diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..abe580317a --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,192 @@ +# CODEOWNERS +# +# How this file is read by GitHub: +# - Last matching pattern wins. Order matters. +# - A trailing slash means "this directory and everything under it". +# - Paths with no rule require no specific reviewer (any maintainer can approve). +# We deliberately leave cross-network e2e and most examples unowned. +# +# Teams: +# @x402-foundation/core — Core protocol, shared infra, CI, docs/specs +# @x402-foundation/site — x402.org website +# @x402-foundation/java — Java SDK +# @x402-foundation/evm — EVM network maintainers +# @x402-foundation/svm — SVM (Solana) network maintainers +# @x402-foundation/stellar — Stellar network maintainers +# @x402-foundation/aptos — Aptos network maintainers +# @x402-foundation/avm — AVM (Avalanche) network maintainers + +# ───────────────────────────────────────────────────────────────────────────── +# 1. Repo-wide meta +# ───────────────────────────────────────────────────────────────────────────── +/LICENSE @x402-foundation/core +/NOTICE @x402-foundation/core +/README.md @x402-foundation/core +/CONTRIBUTING.md @x402-foundation/core +/SECURITY.md @x402-foundation/core +/ROADMAP.md @x402-foundation/core +/PROJECT-IDEAS.md @x402-foundation/core +/.gitignore @x402-foundation/core +/.gitmodules @x402-foundation/core +/.gitbook.yaml @x402-foundation/core +/.vscode/ @x402-foundation/core +/package.json @x402-foundation/core +/package-lock.json @x402-foundation/core +/pnpm-lock.yaml @x402-foundation/core +/static/ @x402-foundation/core + +# ───────────────────────────────────────────────────────────────────────────── +# 2. Specs & docs (network scheme files overridden in section 12) +# ───────────────────────────────────────────────────────────────────────────── +/specs/ @x402-foundation/core +/docs/ @x402-foundation/core + +# ───────────────────────────────────────────────────────────────────────────── +# 3. CI / release infrastructure +# Listed BEFORE network sections so per-network publish workflows override. +# ───────────────────────────────────────────────────────────────────────────── +/.github/ @x402-foundation/core + +# ───────────────────────────────────────────────────────────────────────────── +# 4. TypeScript shared monorepo config +# ───────────────────────────────────────────────────────────────────────────── +/typescript/CONTRIBUTING.md @x402-foundation/core +/typescript/package.json @x402-foundation/core +/typescript/pnpm-workspace.yaml @x402-foundation/core +/typescript/pnpm-lock.yaml @x402-foundation/core +/typescript/turbo.json @x402-foundation/core +/typescript/tsconfig.base.json @x402-foundation/core +/typescript/eslint.config.js @x402-foundation/core +/typescript/.prettierrc @x402-foundation/core +/typescript/.prettierignore @x402-foundation/core +/typescript/.changeset/ @x402-foundation/core + +# ───────────────────────────────────────────────────────────────────────────── +# 5. TypeScript packages — shared / cross-network +# (Per-network mechanism, paywall, and extension subdirs overridden later.) +# ───────────────────────────────────────────────────────────────────────────── +/typescript/packages/core/ @x402-foundation/core +/typescript/packages/http/ @x402-foundation/core +/typescript/packages/extensions/ @x402-foundation/core +/typescript/packages/mcp/ @x402-foundation/core +/typescript/packages/mechanisms/ @x402-foundation/core +/typescript/packages/legacy/ @x402-foundation/core + +# ───────────────────────────────────────────────────────────────────────────── +# 6. Site (x402.org) +# Network partner subdirs overridden in section 12. +# ───────────────────────────────────────────────────────────────────────────── +/typescript/site/ @x402-foundation/site + +# ───────────────────────────────────────────────────────────────────────────── +# 7. Python (shared / cross-network) +# ───────────────────────────────────────────────────────────────────────────── +/python/ @x402-foundation/core +/python/CONTRIBUTING.md @x402-foundation/core +/python/x402/ @x402-foundation/core +/python/x402/http/ @x402-foundation/core +/python/x402/mcp/ @x402-foundation/core +/python/x402/extensions/ @x402-foundation/core +/python/x402/mechanisms/ @x402-foundation/core +/python/x402/tests/ @x402-foundation/core +/python/legacy/ @x402-foundation/core + +# ───────────────────────────────────────────────────────────────────────────── +# 8. Go (shared / cross-network) +# ───────────────────────────────────────────────────────────────────────────── +/go/ @x402-foundation/core +/go/http/ @x402-foundation/core +/go/mcp/ @x402-foundation/core +/go/extensions/ @x402-foundation/core +/go/mechanisms/ @x402-foundation/core +/go/signers/ @x402-foundation/core +/go/types/ @x402-foundation/core +/go/test/ @x402-foundation/core +/go/legacy/ @x402-foundation/core + +# ───────────────────────────────────────────────────────────────────────────── +# 9. Java +# ───────────────────────────────────────────────────────────────────────────── +/java/ @x402-foundation/java +/.github/workflows/java.yml @x402-foundation/java + +# ───────────────────────────────────────────────────────────────────────────── +# 10. Examples (cross-network; no per-network slicing) +# ───────────────────────────────────────────────────────────────────────────── +/examples/ @x402-foundation/core + +# ───────────────────────────────────────────────────────────────────────────── +# 11. Contracts (only EVM exists today; structured for future chains) +# ───────────────────────────────────────────────────────────────────────────── +/contracts/ @x402-foundation/core + +# Note on e2e: intentionally NOT owned in bulk. Most of e2e (echo, gin, hono, +# fastapi, fastify, flask, nethttp, mcp-*, axios, fetch, requests, httpx, +# the facilitators, scripts, templates, mock-facilitator) is cross-network +# infrastructure — anyone closest to the change reviews. Only the per-network +# Next.js API routes have owners (section 12). + +# ╔═══════════════════════════════════════════════════════════════════════════╗ +# ║ 12. Network overrides — placed last so they win last-match precedence. ║ +# ╚═══════════════════════════════════════════════════════════════════════════╝ + +# ── EVM ─────────────────────────────────────────────────────────────────────── +/contracts/evm/ @x402-foundation/evm +/specs/schemes/exact/scheme_exact_evm.md @x402-foundation/evm +/specs/schemes/upto/scheme_upto_evm.md @x402-foundation/evm +/specs/extensions/eip2612_gas_sponsoring.md @x402-foundation/evm +/specs/extensions/erc20_gas_sponsoring.md @x402-foundation/evm +/typescript/packages/mechanisms/evm/ @x402-foundation/evm +/typescript/packages/extensions/src/eip2612-gas-sponsoring/ @x402-foundation/evm +/typescript/packages/extensions/src/erc20-approval-gas-sponsoring/ @x402-foundation/evm +/typescript/packages/http/paywall/src/evm/ @x402-foundation/evm +/go/mechanisms/evm/ @x402-foundation/evm +/go/signers/evm/ @x402-foundation/evm +/go/extensions/eip2612gassponsor/ @x402-foundation/evm +/go/extensions/erc20approvalgassponsor/ @x402-foundation/evm +/go/http/evm_paywall_template.go @x402-foundation/evm +/python/x402/mechanisms/evm/ @x402-foundation/evm +/python/x402/extensions/eip2612_gas_sponsoring/ @x402-foundation/evm +/python/x402/extensions/erc20_approval_gas_sponsoring/ @x402-foundation/evm +/python/x402/http/paywall/evm_paywall_template.py @x402-foundation/evm +/python/x402/tests/unit/mechanisms/evm/ @x402-foundation/evm +/e2e/servers/next/app/api/exact/evm/ @x402-foundation/evm +/e2e/servers/next/app/api/upto/evm/ @x402-foundation/evm +/.github/workflows/publish_npm_scoped_x402_evm.yml @x402-foundation/evm + +# ── SVM (Solana) ────────────────────────────────────────────────────────────── +/specs/schemes/exact/scheme_exact_svm.md @x402-foundation/svm +/typescript/packages/mechanisms/svm/ @x402-foundation/svm +/typescript/packages/http/paywall/src/svm/ @x402-foundation/svm +/typescript/site/app/ecosystem/partners-data/solana-pay-x402/ @x402-foundation/svm +/go/mechanisms/svm/ @x402-foundation/svm +/go/signers/svm/ @x402-foundation/svm +/go/http/svm_paywall_template.go @x402-foundation/svm +/python/x402/mechanisms/svm/ @x402-foundation/svm +/python/x402/http/paywall/svm_paywall_template.py @x402-foundation/svm +/python/x402/tests/unit/mechanisms/svm/ @x402-foundation/svm +/e2e/servers/next/app/api/exact/svm/ @x402-foundation/svm +/.github/workflows/publish_npm_scoped_x402_svm.yml @x402-foundation/svm + +# ── Stellar ─────────────────────────────────────────────────────────────────── +/specs/schemes/exact/scheme_exact_stellar.md @x402-foundation/stellar +/typescript/packages/mechanisms/stellar/ @x402-foundation/stellar +/typescript/site/app/ecosystem/partners-data/stellar/ @x402-foundation/stellar +/typescript/site/app/ecosystem/partners-data/built-on-stellar/ @x402-foundation/stellar +/e2e/servers/next/app/api/exact/stellar/ @x402-foundation/stellar +/.github/workflows/publish_npm_scoped_x402_stellar.yml @x402-foundation/stellar + +# ── Aptos ───────────────────────────────────────────────────────────────────── +/specs/schemes/exact/scheme_exact_aptos.md @x402-foundation/aptos +/typescript/packages/mechanisms/aptos/ @x402-foundation/aptos +/e2e/servers/next/app/api/exact/aptos/ @x402-foundation/aptos +/.github/workflows/publish_npm_scoped_x402_aptos.yml @x402-foundation/aptos + +# ── AVM (Avalanche) — placeholders for upcoming network port ───────────────── +/typescript/packages/mechanisms/avm/ @x402-foundation/avm +/typescript/packages/http/paywall/src/avm/ @x402-foundation/avm +/go/mechanisms/avm/ @x402-foundation/avm +/go/signers/avm/ @x402-foundation/avm +/python/x402/mechanisms/avm/ @x402-foundation/avm +/e2e/servers/next/app/api/exact/avm/ @x402-foundation/avm +/.github/workflows/publish_npm_scoped_x402_avm.yml @x402-foundation/avm diff --git a/.github/workflows/check_format.yml b/.github/workflows/check_format.yml index 79920aac89..f7409e6a07 100644 --- a/.github/workflows/check_format.yml +++ b/.github/workflows/check_format.yml @@ -1,41 +1,47 @@ name: Format on: [pull_request] +permissions: + contents: read + id-token: none + jobs: check-format-typescript: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: + version: 11.1.1 run_install: false - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "22" cache: "pnpm" cache-dependency-path: ./typescript - name: Ensure formatting working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm format:check check-format-examples-typescript: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: + version: 11.1.1 run_install: false - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "22" cache: "pnpm" cache-dependency-path: ./examples/typescript - name: Ensure formatting working-directory: ./examples/typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm format:check diff --git a/.github/workflows/check_go.yml b/.github/workflows/check_go.yml index 46dc15bf88..1eff42f6a0 100644 --- a/.github/workflows/check_go.yml +++ b/.github/workflows/check_go.yml @@ -1,6 +1,10 @@ name: Check Go on: [pull_request] +permissions: + contents: read + id-token: none + jobs: check-format-go: runs-on: ubuntu-latest @@ -8,10 +12,10 @@ jobs: run: working-directory: ./go steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: go-version: "1.24" cache-dependency-path: ./go/go.sum @@ -32,10 +36,10 @@ jobs: run: working-directory: ./go steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: go-version: "1.24" cache-dependency-path: ./go/go.sum @@ -51,10 +55,10 @@ jobs: run: working-directory: ./go steps: - - uses: actions/checkout@v5 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Go - uses: actions/setup-go@v5 + uses: actions/setup-go@40f1582b2485089dde7abd97c1529aa768e1baff # v5.6.0 with: go-version: "1.24" cache-dependency-path: ./go/go.sum diff --git a/.github/workflows/check_lint.yml b/.github/workflows/check_lint.yml index f633f94685..5eca67b1ac 100644 --- a/.github/workflows/check_lint.yml +++ b/.github/workflows/check_lint.yml @@ -1,41 +1,47 @@ name: Lint on: [pull_request] +permissions: + contents: read + id-token: none + jobs: check-lint-typescript: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: + version: 11.1.1 run_install: false - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "22" cache: "pnpm" cache-dependency-path: ./typescript - name: Ensure Linting working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm lint:check check-lint-examples-typescript: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: + version: 11.1.1 run_install: false - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "22" cache: "pnpm" cache-dependency-path: ./examples/typescript - name: Ensure Linting working-directory: ./examples/typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm lint:check \ No newline at end of file diff --git a/.github/workflows/check_package_lock.yml b/.github/workflows/check_package_lock.yml index 9a6a0f6641..62fb7dfee3 100644 --- a/.github/workflows/check_package_lock.yml +++ b/.github/workflows/check_package_lock.yml @@ -1,27 +1,32 @@ name: Package Lock on: [pull_request] +permissions: + contents: read + id-token: none + jobs: check-package-lock-typescript: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: + version: 11.1.1 run_install: false - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "22" cache: "pnpm" cache-dependency-path: ./typescript - name: Check if pnpm-lock.yaml changed working-directory: ./typescript run: | - pnpm install + pnpm install --ignore-scripts if [ -n "$(git diff pnpm-lock.yaml)" ]; then echo "Error: pnpm-lock.yaml was modified after running pnpm install. Please commit the updated pnpm-lock.yaml file." git diff pnpm-lock.yaml @@ -31,23 +36,24 @@ jobs: check-package-lock-examples-typescript: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: + version: 11.1.1 run_install: false - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "22" cache: "pnpm" cache-dependency-path: ./examples/typescript - name: Check if pnpm-lock.yaml changed working-directory: ./examples/typescript run: | - pnpm install + pnpm install --ignore-scripts if [ -n "$(git diff pnpm-lock.yaml)" ]; then echo "Error: pnpm-lock.yaml was modified after running pnpm install. Please commit the updated pnpm-lock.yaml file." git diff pnpm-lock.yaml diff --git a/.github/workflows/check_paywall_template.yml b/.github/workflows/check_paywall_template.yml new file mode 100644 index 0000000000..17d0e31a82 --- /dev/null +++ b/.github/workflows/check_paywall_template.yml @@ -0,0 +1,111 @@ +name: Check Paywall Template + +on: + pull_request: + paths: + - "typescript/packages/http/paywall/**" + - "typescript/packages/mechanisms/evm/**" + - "typescript/pnpm-lock.yaml" + - "python/x402/http/paywall/**" + - "go/http/evm_paywall_template.go" + - "go/http/svm_paywall_template.go" + - "go/http/avm_paywall_template.go" + - ".github/workflows/check_paywall_template.yml" + +permissions: + contents: read + id-token: none + +jobs: + check-paywall-template: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Setup pnpm + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 + with: + version: 11.1.1 + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "24" + cache: "pnpm" + cache-dependency-path: ./typescript + + - name: Install dependencies + working-directory: ./typescript + run: pnpm install --frozen-lockfile --ignore-scripts + + - name: Build workspace dependencies + working-directory: ./typescript + run: pnpm run build:paywall-deps + + - name: Regenerate paywall bundles + working-directory: ./typescript/packages/http/paywall + run: pnpm run build:paywall + + - name: Verify regenerated templates match committed files + run: | + git diff --exit-code -- \ + typescript/packages/http/paywall/src/evm/gen/template.ts \ + typescript/packages/http/paywall/src/svm/gen/template.ts \ + typescript/packages/http/paywall/src/avm/gen/template.ts \ + python/x402/http/paywall/evm_paywall_template.py \ + python/x402/http/paywall/svm_paywall_template.py \ + python/x402/http/paywall/avm_paywall_template.py \ + go/http/evm_paywall_template.go \ + go/http/svm_paywall_template.go \ + go/http/avm_paywall_template.go \ + || { + echo "" + echo "::error::Stale paywall templates: regenerated outputs differ from committed snapshots." + echo "Regenerate exactly as CI does (from \`typescript/\`, deps first):" + echo " cd typescript" + echo " pnpm install --frozen-lockfile --ignore-scripts" + echo " pnpm run build:paywall-deps" + echo " pnpm --filter @x402/paywall run build:paywall" + echo "Then stage and commit the nine template files under typescript/, python/, and go/http/ listed in this workflow." + echo "" + git diff --stat -- \ + typescript/packages/http/paywall/src/evm/gen/template.ts \ + typescript/packages/http/paywall/src/svm/gen/template.ts \ + typescript/packages/http/paywall/src/avm/gen/template.ts \ + python/x402/http/paywall/evm_paywall_template.py \ + python/x402/http/paywall/svm_paywall_template.py \ + python/x402/http/paywall/avm_paywall_template.py \ + go/http/evm_paywall_template.go \ + go/http/svm_paywall_template.go \ + go/http/avm_paywall_template.go + exit 1 + } + + - name: Verify determinism (re-run build, compare to first run) + working-directory: ./typescript/packages/http/paywall + run: | + first_sha=$(sha256sum \ + src/evm/gen/template.ts \ + src/svm/gen/template.ts \ + src/avm/gen/template.ts \ + ../../../../python/x402/http/paywall/evm_paywall_template.py \ + ../../../../python/x402/http/paywall/svm_paywall_template.py \ + ../../../../python/x402/http/paywall/avm_paywall_template.py \ + ../../../../go/http/evm_paywall_template.go \ + ../../../../go/http/svm_paywall_template.go \ + ../../../../go/http/avm_paywall_template.go) + pnpm run build:paywall + second_sha=$(sha256sum \ + src/evm/gen/template.ts \ + src/svm/gen/template.ts \ + src/avm/gen/template.ts \ + ../../../../python/x402/http/paywall/evm_paywall_template.py \ + ../../../../python/x402/http/paywall/svm_paywall_template.py \ + ../../../../python/x402/http/paywall/avm_paywall_template.py \ + ../../../../go/http/evm_paywall_template.go \ + ../../../../go/http/svm_paywall_template.go \ + ../../../../go/http/avm_paywall_template.go) + if [ "$first_sha" != "$second_sha" ]; then + echo "::error::build:paywall is non-deterministic across repeat runs. See x4-23b for context." + diff <(echo "$first_sha") <(echo "$second_sha") + exit 1 + fi diff --git a/.github/workflows/check_python.yml b/.github/workflows/check_python.yml index 79c1beb02b..d9e09cf2b2 100644 --- a/.github/workflows/check_python.yml +++ b/.github/workflows/check_python.yml @@ -1,6 +1,10 @@ name: Check Python on: [pull_request] +permissions: + contents: read + id-token: none + jobs: test-python: runs-on: ubuntu-latest @@ -8,10 +12,10 @@ jobs: run: working-directory: ./python/x402 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2 with: enable-cache: true cache-dependency-glob: "python/x402/uv.lock" @@ -31,10 +35,10 @@ jobs: run: working-directory: ./python/x402 steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Install uv - uses: astral-sh/setup-uv@v5 + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2 with: enable-cache: true cache-dependency-glob: "python/x402/uv.lock" diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml deleted file mode 100644 index 3c0ad6eddc..0000000000 --- a/.github/workflows/e2e_tests.yml +++ /dev/null @@ -1,348 +0,0 @@ -# E2E Test Workflow for x402 Protocol -# -# This workflow runs the full end-to-end test suite which validates the x402 -# payment protocol across multiple languages (TypeScript, Go, Python), -# frameworks, transports (HTTP, MCP), and blockchain networks. -# -# Trigger: Manual only (workflow_dispatch). Select the branch to test from -# the "Use workflow from" dropdown in the GitHub Actions UI. -# -# ============================================================================ -# REQUIRED GITHUB SECRETS -# ============================================================================ -# -# The following secrets must be configured in the repository settings -# (Settings > Secrets and variables > Actions) for this workflow to succeed. -# -# --- Wallet Keys (Required) --- -# -# CLIENT_EVM_PRIVATE_KEY: -# EVM private key for the client wallet that makes payments. -# Must be funded with testnet USDC on Base Sepolia. -# Format: 0x-prefixed hex string (e.g., 0x4df9...) -# -# CLIENT_SVM_PRIVATE_KEY: -# Solana private key for the client wallet that makes payments. -# Must be funded with devnet USDC on Solana Devnet. -# Format: base58 encoded string -# -# FACILITATOR_EVM_PRIVATE_KEY: -# EVM private key for the facilitator wallet that verifies/settles payments. -# Format: 0x-prefixed hex string -# -# FACILITATOR_SVM_PRIVATE_KEY: -# Solana private key for the facilitator wallet that verifies/settles payments. -# Format: base58 encoded string -# -# SERVER_EVM_ADDRESS: -# EVM address where server payments are sent (payee address). -# Format: 0x-prefixed hex address (e.g., 0x122F...) -# -# SERVER_SVM_ADDRESS: -# Solana address where server payments are sent (payee address). -# Format: base58 encoded public key -# -# --- RPC URLs (Optional) --- -# -# These are optional. If not set, the test suite falls back to public defaults. -# Setting custom RPC URLs is recommended for reliability in CI. -# -# BASE_SEPOLIA_RPC_URL: -# Custom RPC URL for Base Sepolia testnet. -# Default: https://sepolia.base.org -# -# SOLANA_DEVNET_RPC_URL: -# Custom RPC URL for Solana Devnet. -# Default: https://api.devnet.solana.com -# -# ============================================================================ - -name: E2E Tests - -on: - workflow_dispatch: - inputs: - branch: - description: "Branch to test (leave empty to use the branch selected above)" - required: false - default: "" - transport: - description: "Transports to test (comma-separated: http,mcp)" - required: false - default: "http" - facilitators: - description: "Facilitators to test (comma-separated: go,typescript,python)" - required: false - default: "go,typescript,python" - servers: - description: "Servers to test (comma-separated: express,hono,gin,flask,fastapi,next)" - required: false - clients: - description: "Clients to test (comma-separated: axios,fetch,go-http,httpx,requests)" - required: false - families: - description: "Protocol families (comma-separated: evm,svm)" - required: false - minimize: - description: "Use coverage-based test minimization (--min)" - type: boolean - default: true - verbose: - description: "Enable verbose logging" - type: boolean - default: true - -permissions: - contents: read - pull-requests: write - -jobs: - e2e-tests: - runs-on: ubuntu-latest - timeout-minutes: 30 - - steps: - # --- Validate Required Secrets --- - # Fail fast before installing anything if secrets are missing. - - - name: Validate required secrets - run: | - MISSING=() - - if [ -z "${{ secrets.CLIENT_EVM_PRIVATE_KEY }}" ]; then MISSING+=("CLIENT_EVM_PRIVATE_KEY"); fi - if [ -z "${{ secrets.CLIENT_SVM_PRIVATE_KEY }}" ]; then MISSING+=("CLIENT_SVM_PRIVATE_KEY"); fi - if [ -z "${{ secrets.FACILITATOR_EVM_PRIVATE_KEY }}" ]; then MISSING+=("FACILITATOR_EVM_PRIVATE_KEY"); fi - if [ -z "${{ secrets.FACILITATOR_SVM_PRIVATE_KEY }}" ]; then MISSING+=("FACILITATOR_SVM_PRIVATE_KEY"); fi - if [ -z "${{ secrets.SERVER_EVM_ADDRESS }}" ]; then MISSING+=("SERVER_EVM_ADDRESS"); fi - if [ -z "${{ secrets.SERVER_SVM_ADDRESS }}" ]; then MISSING+=("SERVER_SVM_ADDRESS"); fi - - if [ ${#MISSING[@]} -gt 0 ]; then - echo "::error::Missing required secrets: ${MISSING[*]}" - echo "" - echo "The following secrets must be configured in Settings > Secrets and variables > Actions:" - for secret in "${MISSING[@]}"; do - echo " - $secret" - done - exit 1 - fi - - echo "All required secrets are present." - - - uses: actions/checkout@v4 - with: - ref: ${{ inputs.branch || github.ref }} - - # --- Language Runtimes --- - - - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda - with: - run_install: false - - - name: Setup Node.js - uses: actions/setup-node@v4 - with: - node-version: "20" - cache: "pnpm" - cache-dependency-path: | - e2e/pnpm-lock.yaml - typescript/pnpm-lock.yaml - - - name: Setup Go - uses: actions/setup-go@v5 - with: - go-version: "1.24" - cache-dependency-path: | - go/go.sum - e2e/**/go.sum - - - name: Setup Python (uv) - uses: astral-sh/setup-uv@v5 - with: - enable-cache: true - - - name: Install Python - run: uv python install 3.13 - - # --- Install Dependencies --- - - - name: Install and build TypeScript SDK - working-directory: ./typescript - run: | - pnpm install --frozen-lockfile - pnpm build - - - name: Install E2E dependencies - working-directory: ./e2e - run: pnpm install --frozen-lockfile - - # --- Build & Setup E2E Components --- - # setup.sh runs install.sh and build.sh for all servers, clients, and - # facilitators (TypeScript, Go, and Python components). - - - name: Setup E2E components - working-directory: ./e2e - run: ./setup.sh -v - - # --- Write Environment File --- - - - name: Create .env file - working-directory: ./e2e - run: | - { - echo "SERVER_EVM_ADDRESS=${{ secrets.SERVER_EVM_ADDRESS }}" - echo "SERVER_SVM_ADDRESS=${{ secrets.SERVER_SVM_ADDRESS }}" - echo "CLIENT_EVM_PRIVATE_KEY=${{ secrets.CLIENT_EVM_PRIVATE_KEY }}" - echo "CLIENT_SVM_PRIVATE_KEY=${{ secrets.CLIENT_SVM_PRIVATE_KEY }}" - echo "FACILITATOR_EVM_PRIVATE_KEY=${{ secrets.FACILITATOR_EVM_PRIVATE_KEY }}" - echo "FACILITATOR_SVM_PRIVATE_KEY=${{ secrets.FACILITATOR_SVM_PRIVATE_KEY }}" - } > .env - - # --- Run E2E Tests --- - # Uses programmatic mode (CLI filter flags) to bypass the interactive - # prompt that `pnpm test` opens by default. Any --flag triggers - # programmatic mode in the test runner (see e2e/src/cli/args.ts). - - - name: Run E2E tests - id: e2e - working-directory: ./e2e - run: | - ARGS="" - - # Apply workflow_dispatch inputs (or defaults) - ARGS="$ARGS --transport=${{ inputs.transport || 'http' }}" - ARGS="$ARGS --facilitators=${{ inputs.facilitators || 'go,python,typescript' }}" - - if [ -n "${{ inputs.servers }}" ]; then - ARGS="$ARGS --servers=${{ inputs.servers }}" - fi - - if [ -n "${{ inputs.clients }}" ]; then - ARGS="$ARGS --clients=${{ inputs.clients }}" - fi - - if [ -n "${{ inputs.families }}" ]; then - ARGS="$ARGS --families=${{ inputs.families }}" - fi - - # Default to --min and -v when inputs are not provided (e.g. push trigger) - MINIMIZE="${{ inputs.minimize }}" - if [ "$MINIMIZE" = "true" ] || [ -z "$MINIMIZE" ]; then - ARGS="$ARGS --min" - fi - - VERBOSE="${{ inputs.verbose }}" - if [ "$VERBOSE" = "true" ]; then - ARGS="$ARGS -v" - fi - - ARGS="$ARGS --parallel" - - ARGS="$ARGS --log-file=e2e-results.log --output-json=e2e-results.json" - - echo "Running: pnpm test $ARGS" - - # Run tests but capture exit code so we can still comment on the PR - set +e - pnpm test $ARGS - TEST_EXIT_CODE=$? - set -e - - echo "test_exit_code=$TEST_EXIT_CODE" >> "$GITHUB_OUTPUT" - exit 0 - - # --- Upload Results --- - - - name: Upload test log - if: always() - uses: actions/upload-artifact@v4 - with: - name: e2e-test-log - path: | - e2e/e2e-results.log - e2e/e2e-results.json - retention-days: 14 - - # --- Comment on PR --- - # Find any open PR for the tested branch, delete previous E2E comments - # from this workflow, and post a new comment with results. - - - name: Comment results on PR - if: always() - env: - GH_TOKEN: ${{ github.token }} - TEST_EXIT_CODE: ${{ steps.e2e.outputs.test_exit_code }} - run: | - BRANCH="${{ inputs.branch || github.ref_name }}" - - # Find open PR for this branch - PR_NUMBER=$(gh pr list --head "$BRANCH" --state open --json number --jq '.[0].number' 2>/dev/null || true) - - if [ -z "$PR_NUMBER" ]; then - echo "No open PR found for branch '$BRANCH', skipping comment." - exit 0 - fi - - echo "Found PR #$PR_NUMBER for branch '$BRANCH'" - - # Delete previous E2E comments from this workflow - COMMENT_IDS=$(gh api "repos/${{ github.repository }}/issues/${PR_NUMBER}/comments" \ - --paginate --jq '.[] | select(.body | contains("")) | .id' 2>/dev/null || true) - - for CID in $COMMENT_IDS; do - echo "Deleting previous E2E comment $CID" - gh api --method DELETE "repos/${{ github.repository }}/issues/comments/$CID" 2>/dev/null || true - done - - # Build comment body from JSON results - COMMENT_BODY=""$'\n' - - if [ -f e2e/e2e-results.json ]; then - TOTAL=$(jq '.summary.total' e2e/e2e-results.json) - PASSED=$(jq '.summary.passed' e2e/e2e-results.json) - FAILED=$(jq '.summary.failed' e2e/e2e-results.json) - NETWORK=$(jq -r '.summary.networkMode' e2e/e2e-results.json) - - if [ "$FAILED" = "0" ]; then - COMMENT_BODY+="## :white_check_mark: E2E Tests Passed"$'\n\n' - else - COMMENT_BODY+="## :x: E2E Tests Failed"$'\n\n' - fi - - COMMENT_BODY+="**Network:** ${NETWORK} | **Total:** ${TOTAL} | **Passed:** ${PASSED} | **Failed:** ${FAILED}"$'\n\n' - - # Failed test details (only shown when there are failures) - FAILED_DETAILS=$(jq -r '.results[] | select(.passed == false) | "| \(.testNumber) | \(.client) | \(.server) | \(.endpoint) | \(.facilitator) | \(.error // "Unknown") |"' e2e/e2e-results.json) - if [ -n "$FAILED_DETAILS" ]; then - COMMENT_BODY+="### Failed Tests"$'\n' - COMMENT_BODY+="| Test | Client | Server | Endpoint | Facilitator | Error |"$'\n' - COMMENT_BODY+="|---|---|---|---|---|---|"$'\n' - COMMENT_BODY+="${FAILED_DETAILS}"$'\n\n' - fi - else - # No JSON output — tests likely crashed before producing results - if [ "$TEST_EXIT_CODE" != "0" ]; then - COMMENT_BODY+="## :x: E2E Tests Failed"$'\n\n' - COMMENT_BODY+="Test runner exited with code ${TEST_EXIT_CODE} before producing results."$'\n' - COMMENT_BODY+="Check the [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details."$'\n' - else - COMMENT_BODY+="## :warning: E2E Tests — No Results"$'\n\n' - COMMENT_BODY+="No structured output was produced. Check the [workflow run](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) for details."$'\n' - fi - fi - - COMMENT_BODY+=$'\n'"Run: [${{ github.run_id }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})"$'\n' - - # Post new comment - gh pr comment "$PR_NUMBER" --body "$COMMENT_BODY" - echo "Posted E2E results comment on PR #$PR_NUMBER" - - # --- Fail the workflow if tests failed --- - - - name: Check test result - if: always() - run: | - if [ "${{ steps.e2e.outputs.test_exit_code }}" != "0" ]; then - echo "E2E tests failed with exit code ${{ steps.e2e.outputs.test_exit_code }}" - exit 1 - fi diff --git a/.github/workflows/java.yml b/.github/workflows/java.yml index 062416ae83..b2a98c6a2a 100644 --- a/.github/workflows/java.yml +++ b/.github/workflows/java.yml @@ -9,21 +9,25 @@ on: - 'java/**' workflow_dispatch: +permissions: + contents: read + id-token: none + jobs: test: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up JDK 17 - uses: actions/setup-java@v4 + uses: actions/setup-java@c1e323688fd81a25caa38c78aa6df2d33d3e20d9 # v4.8.0 with: java-version: '17' distribution: 'temurin' - name: Cache Maven dependencies - uses: actions/cache@v4 + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 with: path: ~/.m2 key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 3df7686fd8..1ba107709f 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -7,10 +7,11 @@ jobs: labeler: permissions: contents: read + id-token: none pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/labeler@v5 + - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 # v5.0.0 with: sync-labels: true diff --git a/.github/workflows/publish_npm_coinbase_x402.yml b/.github/workflows/publish_npm_coinbase_x402.yml index c463b364e3..075229a204 100644 --- a/.github/workflows/publish_npm_coinbase_x402.yml +++ b/.github/workflows/publish_npm_coinbase_x402.yml @@ -5,30 +5,29 @@ on: jobs: publish-npm-coinbase-x402: + if: github.ref == 'refs/heads/@coinbase/x402' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/@coinbase/x402' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "22" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=x402 --filter=@coinbase/x402 run build - name: Publish coinbase-x402 package @@ -40,13 +39,7 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on @coinbase/x402 branch - if [[ "${{ github.ref }}" == "refs/heads/@coinbase/x402" ]]; then - echo "Publishing to NPM (@coinbase/x402 branch)" - pnpm publish --provenance --access public --publish-branch "@coinbase/x402" - else - echo "Dry run only (non-release branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (@coinbase/x402 branch)" + pnpm publish --provenance --access public --publish-branch "@coinbase/x402" env: NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file diff --git a/.github/workflows/publish_npm_scoped_x402_aptos.yml b/.github/workflows/publish_npm_scoped_x402_aptos.yml index 431a404933..b0b5dd2a4c 100644 --- a/.github/workflows/publish_npm_scoped_x402_aptos.yml +++ b/.github/workflows/publish_npm_scoped_x402_aptos.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-aptos: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/aptos run build - name: Publish @x402/aptos package @@ -46,11 +45,5 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_avm.yml b/.github/workflows/publish_npm_scoped_x402_avm.yml new file mode 100644 index 0000000000..51900ca3ce --- /dev/null +++ b/.github/workflows/publish_npm_scoped_x402_avm.yml @@ -0,0 +1,49 @@ +name: Publish @x402/avm package to NPM + +on: + workflow_dispatch: + +jobs: + publish-npm-x402-avm: + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + environment: npm + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Setup pnpm + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 + with: + version: 11.1.1 + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "24" + registry-url: "https://registry.npmjs.org" + + - name: Update npm for OIDC trusted publishing + run: npm install -g npm@11.14.1 --ignore-scripts + + - name: Configure npm for trusted publishing + run: npm config delete always-auth 2>/dev/null || true + + - name: Install and build + working-directory: ./typescript + run: | + pnpm install --frozen-lockfile --ignore-scripts + pnpm -r --filter=@x402/core --filter=@x402/extensions --filter=@x402/avm run build + + - name: Publish @x402/avm package + working-directory: ./typescript/packages/mechanisms/avm + run: | + # Get package information directly + PACKAGE_NAME=$(node -p "require('./package.json').name") + PACKAGE_VERSION=$(node -p "require('./package.json').version") + + echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" + + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_axios.yml b/.github/workflows/publish_npm_scoped_x402_axios.yml index 0c24845c14..a87397f411 100644 --- a/.github/workflows/publish_npm_scoped_x402_axios.yml +++ b/.github/workflows/publish_npm_scoped_x402_axios.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-axios: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/axios run build - name: Publish @x402/axios package @@ -46,12 +45,6 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_core.yml b/.github/workflows/publish_npm_scoped_x402_core.yml index 83c22a779b..73e1b0e03c 100644 --- a/.github/workflows/publish_npm_scoped_x402_core.yml +++ b/.github/workflows/publish_npm_scoped_x402_core.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-core: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 - + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 - - - uses: actions/setup-node@v4 + version: 11.1.1 + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core run build - name: Publish @x402/core package @@ -46,12 +45,6 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_evm.yml b/.github/workflows/publish_npm_scoped_x402_evm.yml index 7b58df182d..751c8c3a80 100644 --- a/.github/workflows/publish_npm_scoped_x402_evm.yml +++ b/.github/workflows/publish_npm_scoped_x402_evm.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-evm: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/extensions --filter=@x402/evm run build - name: Publish @x402/evm package @@ -46,12 +45,6 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_express.yml b/.github/workflows/publish_npm_scoped_x402_express.yml index f50571f9b3..041266092d 100644 --- a/.github/workflows/publish_npm_scoped_x402_express.yml +++ b/.github/workflows/publish_npm_scoped_x402_express.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-express: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/extensions --filter=@x402/express run build - name: Publish @x402/express package @@ -46,12 +45,6 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_extensions.yml b/.github/workflows/publish_npm_scoped_x402_extensions.yml index 1e89d1b805..358d201f8a 100644 --- a/.github/workflows/publish_npm_scoped_x402_extensions.yml +++ b/.github/workflows/publish_npm_scoped_x402_extensions.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-extensions: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/extensions run build - name: Publish @x402/extensions package @@ -46,12 +45,6 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_fastify.yml b/.github/workflows/publish_npm_scoped_x402_fastify.yml index c794464be0..8ea35bcd33 100644 --- a/.github/workflows/publish_npm_scoped_x402_fastify.yml +++ b/.github/workflows/publish_npm_scoped_x402_fastify.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-fastify: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/extensions --filter=@x402/fastify run build - name: Publish @x402/fastify package @@ -46,11 +45,5 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_fetch.yml b/.github/workflows/publish_npm_scoped_x402_fetch.yml index b8f5c1a43c..50df149ae6 100644 --- a/.github/workflows/publish_npm_scoped_x402_fetch.yml +++ b/.github/workflows/publish_npm_scoped_x402_fetch.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-fetch: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/fetch run build - name: Publish @x402/fetch package @@ -46,12 +45,6 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_hedera.yml b/.github/workflows/publish_npm_scoped_x402_hedera.yml new file mode 100644 index 0000000000..2236ae8388 --- /dev/null +++ b/.github/workflows/publish_npm_scoped_x402_hedera.yml @@ -0,0 +1,49 @@ +name: Publish @x402/hedera package to NPM + +on: + workflow_dispatch: + +jobs: + publish-npm-x402-hedera: + if: github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + environment: npm + permissions: + contents: read + id-token: write + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Setup pnpm + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 + with: + version: 11.1.1 + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + with: + node-version: "24" + registry-url: "https://registry.npmjs.org" + + - name: Update npm for OIDC trusted publishing + run: npm install -g npm@11.14.1 --ignore-scripts + + - name: Configure npm for trusted publishing + run: npm config delete always-auth 2>/dev/null || true + + - name: Install and build + working-directory: ./typescript + run: | + pnpm install --frozen-lockfile --ignore-scripts + pnpm -r --filter=@x402/core --filter=@x402/hedera run build + + - name: Publish @x402/hedera package + working-directory: ./typescript/packages/mechanisms/hedera + run: | + # Get package information directly + PACKAGE_NAME=$(node -p "require('./package.json').name") + PACKAGE_VERSION=$(node -p "require('./package.json').version") + + echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" + + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_hono.yml b/.github/workflows/publish_npm_scoped_x402_hono.yml index 8374076e6b..3b5219005f 100644 --- a/.github/workflows/publish_npm_scoped_x402_hono.yml +++ b/.github/workflows/publish_npm_scoped_x402_hono.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-hono: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/extensions --filter=@x402/hono run build - name: Publish @x402/hono package @@ -46,12 +45,6 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_mcp.yml b/.github/workflows/publish_npm_scoped_x402_mcp.yml index fa0ab99d61..473272cbdc 100644 --- a/.github/workflows/publish_npm_scoped_x402_mcp.yml +++ b/.github/workflows/publish_npm_scoped_x402_mcp.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-mcp: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/mcp run build - name: Publish @x402/mcp package @@ -46,25 +45,19 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - - # Check if version is a prerelease (contains -alpha, -beta, -rc, etc.) - if [[ "$PACKAGE_VERSION" =~ -[a-zA-Z] ]]; then - # Extract prerelease tag (e.g., "alpha" from "2.3.0-alpha") - PRERELEASE_TAG=$(echo "$PACKAGE_VERSION" | sed -n 's/.*-\([a-zA-Z][a-zA-Z0-9]*\).*/\1/p') - if [ -z "$PRERELEASE_TAG" ]; then - # Fallback: use "pre" if we can't extract a tag - PRERELEASE_TAG="pre" - fi - echo "Detected prerelease version, publishing with tag: $PRERELEASE_TAG" - pnpm publish --provenance --access public --tag "$PRERELEASE_TAG" - else - echo "Publishing stable version" - pnpm publish --provenance --access public + echo "Publishing to NPM (main branch)" + + # Check if version is a prerelease (contains -alpha, -beta, -rc, etc.) + if [[ "$PACKAGE_VERSION" =~ -[a-zA-Z] ]]; then + # Extract prerelease tag (e.g., "alpha" from "2.3.0-alpha") + PRERELEASE_TAG=$(echo "$PACKAGE_VERSION" | sed -n 's/.*-\([a-zA-Z][a-zA-Z0-9]*\).*/\1/p') + if [ -z "$PRERELEASE_TAG" ]; then + # Fallback: use "pre" if we can't extract a tag + PRERELEASE_TAG="pre" fi + echo "Detected prerelease version, publishing with tag: $PRERELEASE_TAG" + pnpm publish --provenance --access public --tag "$PRERELEASE_TAG" else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks + echo "Publishing stable version" + pnpm publish --provenance --access public fi diff --git a/.github/workflows/publish_npm_scoped_x402_next.yml b/.github/workflows/publish_npm_scoped_x402_next.yml index cf8929b81c..98150077b1 100644 --- a/.github/workflows/publish_npm_scoped_x402_next.yml +++ b/.github/workflows/publish_npm_scoped_x402_next.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-next: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/extensions --filter=@x402/next run build - name: Publish @x402/next package @@ -46,12 +45,6 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_paywall.yml b/.github/workflows/publish_npm_scoped_x402_paywall.yml index e517f42286..7fb3a77523 100644 --- a/.github/workflows/publish_npm_scoped_x402_paywall.yml +++ b/.github/workflows/publish_npm_scoped_x402_paywall.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-paywall: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,8 +33,8 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile - pnpm -r --filter=@x402/core --filter=@x402/extensions --filter=@x402/evm --filter=@x402/svm --filter=@x402/paywall run build + pnpm install --frozen-lockfile --ignore-scripts + pnpm -r --filter=@x402/core --filter=@x402/extensions --filter=@x402/evm --filter=@x402/svm --filter=@x402/avm --filter=@x402/paywall run build - name: Publish @x402/paywall package working-directory: ./typescript/packages/http/paywall @@ -46,12 +45,6 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_stellar.yml b/.github/workflows/publish_npm_scoped_x402_stellar.yml index 92d09e057b..54b000408f 100644 --- a/.github/workflows/publish_npm_scoped_x402_stellar.yml +++ b/.github/workflows/publish_npm_scoped_x402_stellar.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-stellar: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/stellar run build - name: Publish @x402/stellar package @@ -46,11 +45,5 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_scoped_x402_svm.yml b/.github/workflows/publish_npm_scoped_x402_svm.yml index ef1af505bb..28a78c5b9d 100644 --- a/.github/workflows/publish_npm_scoped_x402_svm.yml +++ b/.github/workflows/publish_npm_scoped_x402_svm.yml @@ -5,28 +5,27 @@ on: jobs: publish-npm-x402-svm: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@41ff72655975bd51cab0327fa583b6e92b6d3061 + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript - name: Update npm for OIDC trusted publishing - run: npm install -g npm@latest + run: npm install -g npm@11.14.1 --ignore-scripts - name: Configure npm for trusted publishing run: npm config delete always-auth 2>/dev/null || true @@ -34,7 +33,7 @@ jobs: - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=@x402/core --filter=@x402/svm run build - name: Publish @x402/svm package @@ -46,12 +45,6 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_x402.yml b/.github/workflows/publish_npm_x402.yml index d007f8b52b..4538f62eb0 100644 --- a/.github/workflows/publish_npm_x402.yml +++ b/.github/workflows/publish_npm_x402.yml @@ -5,30 +5,35 @@ on: jobs: publish-npm-x402: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript + + - name: Update npm for OIDC trusted publishing + run: npm install -g npm@11.14.1 --ignore-scripts + + - name: Configure npm for trusted publishing + run: npm config delete always-auth 2>/dev/null || true - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=x402 run build - name: Publish x402 package @@ -40,13 +45,5 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_x402_axios.yml b/.github/workflows/publish_npm_x402_axios.yml index 35bf3ad05c..e247954bae 100644 --- a/.github/workflows/publish_npm_x402_axios.yml +++ b/.github/workflows/publish_npm_x402_axios.yml @@ -5,30 +5,35 @@ on: jobs: publish-npm-x402-axios: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript + + - name: Update npm for OIDC trusted publishing + run: npm install -g npm@11.14.1 --ignore-scripts + + - name: Configure npm for trusted publishing + run: npm config delete always-auth 2>/dev/null || true - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=x402 --filter=x402-axios run build - name: Publish x402-axios package @@ -40,13 +45,5 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public \ No newline at end of file diff --git a/.github/workflows/publish_npm_x402_express.yml b/.github/workflows/publish_npm_x402_express.yml index e395e436d8..59e56b324e 100644 --- a/.github/workflows/publish_npm_x402_express.yml +++ b/.github/workflows/publish_npm_x402_express.yml @@ -5,30 +5,35 @@ on: jobs: publish-npm-x402-express: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript + + - name: Update npm for OIDC trusted publishing + run: npm install -g npm@11.14.1 --ignore-scripts + + - name: Configure npm for trusted publishing + run: npm config delete always-auth 2>/dev/null || true - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=x402 --filter=x402-express run build - name: Publish x402-express package @@ -40,13 +45,5 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public \ No newline at end of file diff --git a/.github/workflows/publish_npm_x402_fetch.yml b/.github/workflows/publish_npm_x402_fetch.yml index c7470dfa3f..93949768ef 100644 --- a/.github/workflows/publish_npm_x402_fetch.yml +++ b/.github/workflows/publish_npm_x402_fetch.yml @@ -5,30 +5,35 @@ on: jobs: publish-npm-x402-fetch: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - version: 10.7.0 + version: 11.1.1 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - node-version: "20" + node-version: "24" registry-url: "https://registry.npmjs.org" - cache: "pnpm" - cache-dependency-path: ./typescript + + - name: Update npm for OIDC trusted publishing + run: npm install -g npm@11.14.1 --ignore-scripts + + - name: Configure npm for trusted publishing + run: npm config delete always-auth 2>/dev/null || true - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=x402 --filter=x402-fetch run build - name: Publish x402-fetch package @@ -40,13 +45,5 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public \ No newline at end of file diff --git a/.github/workflows/publish_npm_x402_hono.yml b/.github/workflows/publish_npm_x402_hono.yml index aac955461b..509597dc77 100644 --- a/.github/workflows/publish_npm_x402_hono.yml +++ b/.github/workflows/publish_npm_x402_hono.yml @@ -5,24 +5,35 @@ on: jobs: publish-npm-x402-hono: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Setup pnpm + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - node-version: "20" - registry-url: "https://registry.npmjs.org" - - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + version: 11.1.1 + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - version: 10.7.0 + node-version: "24" + registry-url: "https://registry.npmjs.org" + + - name: Update npm for OIDC trusted publishing + run: npm install -g npm@11.14.1 --ignore-scripts + + - name: Configure npm for trusted publishing + run: npm config delete always-auth 2>/dev/null || true + - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=x402 --filter=x402-hono run build - name: Publish x402-hono package @@ -34,13 +45,5 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_npm_x402_next.yml b/.github/workflows/publish_npm_x402_next.yml index 7ca52117ac..6ce1439faa 100644 --- a/.github/workflows/publish_npm_x402_next.yml +++ b/.github/workflows/publish_npm_x402_next.yml @@ -5,24 +5,35 @@ on: jobs: publish-npm-x402-next: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest - environment: ${{ github.ref == 'refs/heads/main' && 'npm' || '' }} + environment: npm permissions: contents: read id-token: write steps: - - uses: actions/checkout@v4 - - uses: actions/setup-node@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Setup pnpm + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: - node-version: "20" - registry-url: "https://registry.npmjs.org" - - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + version: 11.1.1 + + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: - version: 10.7.0 + node-version: "24" + registry-url: "https://registry.npmjs.org" + + - name: Update npm for OIDC trusted publishing + run: npm install -g npm@11.14.1 --ignore-scripts + + - name: Configure npm for trusted publishing + run: npm config delete always-auth 2>/dev/null || true + - name: Install and build working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm -r --filter=x402 --filter=x402-next run build - name: Publish x402-next package @@ -34,13 +45,5 @@ jobs: echo "Package: $PACKAGE_NAME@$PACKAGE_VERSION" - # Check if running on main branch - if [[ "${{ github.ref }}" == "refs/heads/main" ]]; then - echo "Publishing to NPM (main branch)" - pnpm publish --provenance --access public - else - echo "Dry run only (non-main branch: ${{ github.ref }})" - pnpm publish --dry-run --no-git-checks - fi - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file + echo "Publishing to NPM (main branch)" + pnpm publish --provenance --access public diff --git a/.github/workflows/publish_pypi_x402.yml b/.github/workflows/publish_pypi_x402.yml index 752d614ced..834853be9b 100644 --- a/.github/workflows/publish_pypi_x402.yml +++ b/.github/workflows/publish_pypi_x402.yml @@ -5,6 +5,7 @@ on: jobs: publish-pypi-x402: + if: github.ref == 'refs/heads/main' runs-on: ubuntu-latest defaults: run: @@ -14,23 +15,21 @@ jobs: url: https://pypi.org/p/x402 permissions: contents: read + id-token: write steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - run: | git config user.name "github-actions[bot]" git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - name: Set up Python 3.10 - uses: actions/setup-python@v4 + uses: actions/setup-python@7f4fc3e22c37d6ff65e88745f38bd3157c663f7c # v4.9.1 with: python-version: "3.10" - name: Install uv - uses: astral-sh/setup-uv@v5 - with: - enable-cache: true - cache-dependency-glob: "uv.lock" + uses: astral-sh/setup-uv@d4b2f3b6ecc6e67c4457f6d3e41ec42d3d0fcb86 # v5.4.2 - name: Install dependencies run: uv sync @@ -42,7 +41,6 @@ jobs: echo "version=$(sed -n 's/^version = "\(.*\)"/\1/p' pyproject.toml)" >> $GITHUB_OUTPUT - name: Publish package - uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc + uses: pypa/gh-action-pypi-publish@76f52bc884231f62b9a034ebfe128415bbaabdfc # v1.12.4 with: packages-dir: python/x402/dist/ - password: ${{ secrets.PYPI_X402_TOKEN }} diff --git a/.github/workflows/unit_tests.yml b/.github/workflows/unit_tests.yml index 35568e4b58..e9493e2211 100644 --- a/.github/workflows/unit_tests.yml +++ b/.github/workflows/unit_tests.yml @@ -1,21 +1,26 @@ name: Run Unit Tests on: [pull_request] +permissions: + contents: read + id-token: none + jobs: test-x402-typescript: runs-on: ubuntu-latest strategy: matrix: - node-version: ["20", "22"] + node-version: ["22", "24"] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Setup pnpm - uses: pnpm/action-setup@a7487c7e89a18df4991f7f222e4898a00d66ddda + uses: pnpm/action-setup@0e279bb959325dab635dd2c09392533439d90093 # v6.0.8 with: + version: 11.1.1 run_install: false - - uses: actions/setup-node@v4 + - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 with: node-version: ${{ matrix.node-version }} cache: "pnpm" @@ -24,5 +29,5 @@ jobs: - name: Install and Test working-directory: ./typescript run: | - pnpm install --frozen-lockfile + pnpm install --frozen-lockfile --ignore-scripts pnpm run test diff --git a/.github/workflows/update-docs.yml b/.github/workflows/update-docs.yml index e0bea7dc32..09b545a642 100644 --- a/.github/workflows/update-docs.yml +++ b/.github/workflows/update-docs.yml @@ -15,11 +15,15 @@ on: - 'go/legacy/**' - 'python/legacy/**' +permissions: + contents: read + id-token: none + jobs: update-docs: runs-on: ubuntu-latest steps: - - uses: actions/github-script@v7 + - uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7.1.0 env: MINTLIFY_API_KEY: ${{ secrets.MINTLIFY_API_KEY }} PROJECT_ID: ${{ secrets.MINTLIFY_PROJECT_ID }} diff --git a/.gitignore b/.gitignore index 91f46e3f18..b961e2e570 100644 --- a/.gitignore +++ b/.gitignore @@ -12,6 +12,7 @@ e2e/facilitators/external-proxies/* !e2e/facilitators/external-proxies/README.md typescript/package-lock.json .pnpm-store/ +cdk.out/ # e2e Go build artifacts (compiled binaries) e2e/clients/go-http/client @@ -27,13 +28,21 @@ e2e/servers/gin/server e2e/servers/nethttp/nethttp e2e/servers/mcp-go/mcp-go e2e/servers/mcp-go/mcp-server +e2e/servers/nethttp/nethttp e2e/legacy/servers/gin/gin # Example build artifacts examples/go/servers/upto/upto +examples/go/clients/batch-settlement/batch-settlement +examples/go/servers/batch-settlement/batch-settlement +examples/go/facilitator/batch-settlement/batch-settlement # Agent artifacts TASK.md .claude/ skills/ REVIEW_PROMPT.md +.omx/ +.omc/ +/demo/ +/contracts/tvm/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 683297dae1..decfb9a708 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,6 +4,7 @@ x402 welcomes contributions of schemes, middleware, new chain support, and more. ## Contents +- [AI-Assisted Contributions](#ai-assisted-contributions) - [Repository Structure](#repository-structure) - [Language-Specific Guides](#language-specific-guides) - [Contributing Workflow](#contributing-workflow) @@ -11,6 +12,66 @@ x402 welcomes contributions of schemes, middleware, new chain support, and more. - [Commit Signing](#commit-signing) - [Getting Help](#getting-help) +## AI-Assisted Contributions + +Using AI tools (LLMs, code assistants, etc.) for contributions is acceptable, given the following: + +- **You must review AI output before requesting review.** Do not open a non-Draft PR until you have personally verified the generated code. AI-generated PRs submitted without human review waste maintainer time and erode trust. +- **Remove verbosity and filler.** AI tools tend to produce verbose documentation, comments, PR descriptions, and commit messages. Strip these down to what is concise, clear, and useful — nothing more. +- **Remove redundant code and tests.** Deduplicate generated code, tests, and explanations. Explicitness and clarity are good; repetition and over-explanation are not. +- **Verify correctness, especially around payment and signature logic.** x402 handles real value transfer. AI tools hallucinate plausible-looking code that may be subtly wrong — incorrect signing flows, wrong chain constants, hallucinated headers that don't match the spec. You are responsible for catching these before submission. +- **Do not batch-generate low-effort PRs.** Submitting multiple narrow, machine-generated PRs in rapid succession is obvious and unhelpful. If AI helps you work faster, use that speed to produce fewer, higher-quality contributions — not more low-quality ones. +- **Disclose significant AI usage.** If the majority of a PR was generated by an AI tool, note this in the PR description. This is not a mark against the PR — it helps reviewers calibrate their review (e.g., checking for hallucinated APIs or fabricated test assertions). + +Contributions that show clear signs of unreviewed AI output (generic filler comments, hallucination, redundant boilerplate, cookie-cutter PR descriptions) may be closed without detailed review. + +### Sample Prompt for AI-Assisted Development + +If you use an AI coding agent (Claude Code, Codex, Cursor, etc.) to work on x402, include the following in your agent's system prompt or project instructions. This ensures the agent's output aligns with x402 contribution standards before you review it. + +```text +You are contributing to x402, an open protocol for internet-native payments. +x402 handles real value transfer — correctness is critical. + +Follow these rules for all code, documentation, and commit messages you produce: + +1. CONCISE OUTPUT ONLY. Do not add filler comments, redundant docstrings, or + verbose explanations. Every line of documentation or commentary must carry + useful information. + +2. NO REDUNDANCY. Do not generate duplicate or near-duplicate code, tests, or + explanations. If logic already exists, use it — do not rewrite it. Three + similar lines are better than an unnecessary abstraction, but three identical + blocks are never acceptable. + +3. VERIFY AGAINST THE SPEC. Before writing payment, signing, or settlement + logic, read the relevant spec in specs/. Do not invent header names, payload + fields, or signing flows. If you are unsure whether a field or constant + exists, search the codebase — do not guess. + +4. MATCH EXISTING PATTERNS. Read the surrounding code before generating new + code. Match the style, naming conventions, error handling, and test patterns + already in use for that SDK (TypeScript, Python, Go, or Java). + +5. DO NOT ADD UNREQUESTED FEATURES. Implement exactly what was asked. Do not + add extra configuration options, feature flags, helper utilities, or + "improvements" beyond the scope of the task. + +6. COMMIT MESSAGES. Use conventional commits (feat:, fix:, docs:, chore:). + Keep the subject line under 72 characters. The body should explain why, not + what — the diff shows what changed. + +7. CHAIN AND TOKEN CONSTANTS. Never hardcode chain IDs, token addresses, or + decimal values from memory. Always reference the constants defined in the + codebase (e.g., mechanisms/evm/constants, mechanisms/svm/constants). + +8. TEST CORRECTNESS. Generated tests must assert meaningful behavior, not just + that "the function doesn't throw." Do not fabricate expected values — derive + them from the spec or existing test fixtures. +``` + +You can place this in a `CLAUDE.md`, `.cursorrules`, `codex-instructions.md`, or equivalent file at the root of your working copy. It is not committed to the repository — it is for your local development workflow. + ## Repository Structure The x402 repository contains implementations in multiple languages plus protocol specifications. @@ -138,12 +199,8 @@ Because different chains have different best practices, a scheme may have a diff ### Adding a Default Asset for an EVM Chain If your chain is EVM-compatible and you want to add a default stablecoin for -dollar-string pricing (`"$0.10"`), you don't need the full 3-PR workflow below. See: - -- [Go: DEFAULT_ASSET.md](go/mechanisms/evm/DEFAULT_ASSET.md) -- [TypeScript: DEFAULT_ASSET.md](typescript/packages/mechanisms/evm/src/exact/server/DEFAULT_ASSET.md) - -These guides include a cross-SDK checklist of every file to update. +dollar-string pricing (`"$0.10"`), you don't need the full 3-PR workflow below. See +[DEFAULT_ASSETS.md](DEFAULT_ASSETS.md) for instructions. ### Adding a New Chain Family @@ -168,7 +225,7 @@ After spec approval, implement in a **single SDK** (TypeScript, Python OR Go). | SDK | Interfaces | |-----|------------| | TypeScript (`@x402/core`) | `SchemeNetworkClient`, `SchemeNetworkServer`, `SchemeNetworkFacilitator` | -| Go (`github.com/coinbase/x402/go`) | `ClientScheme`, `ServerScheme`, `FacilitatorScheme` | +| Go (`github.com/x402-foundation/x402/go`) | `ClientScheme`, `ServerScheme`, `FacilitatorScheme` | | Python (`x402`) | `SchemeNetworkClient`, `SchemeNetworkServer`, `SchemeNetworkFacilitator` | **Required tests:** diff --git a/DEFAULT_ASSETS.md b/DEFAULT_ASSETS.md new file mode 100644 index 0000000000..640055dd19 --- /dev/null +++ b/DEFAULT_ASSETS.md @@ -0,0 +1,110 @@ +# Default Assets for EVM Chains + +When a server uses `price: "$0.10"` syntax (USD string pricing), x402 needs to know which stablecoin to use on that chain. Each SDK maintains a map of chain → default stablecoin. This document explains how to add or update these defaults. + +For chains without a default, servers can use `registerMoneyParser()` or specify prices directly as a `TokenAmount` with `amountInAtomicUnits`. + +## Asset Transfer Methods + +x402 supports two methods for transferring assets on EVM: + +| Method | Use Case | Notes | +|--------|----------|-------| +| **EIP-3009** (default) | Tokens with `transferWithAuthorization` (e.g., USDC) | Simplest — single signature, no approval step | +| **Permit2** | Any ERC-20 token | Universal fallback — requires one-time Permit2 approval | + +If no transfer method is specified, the system defaults to **EIP-3009**. + +For Permit2 tokens, also check whether the token implements EIP-2612 `permit()`: +- **Yes** → set `supportsEip2612: true` so clients can use gasless permits for Permit2 approval +- **No** → omit the field; clients fall back to ERC-20 approval gas sponsoring + +## Adding a New Chain + +### 1. Gather token information + +1. Get the stablecoin's contract address on your chain +2. Read the `name()` and `version()` functions from the token contract (these are the EIP-712 domain values) +3. Check whether the token supports EIP-3009 (`transferWithAuthorization`) +4. If not, check whether it supports EIP-2612 (`permit()`) + +### 2. Update all three SDKs + +Add an entry in each SDK's constants file. All three **must** use the same CAIP-2 key, token address, EIP-712 `name`/`version`, decimals, and transfer method. + +
+TypeScripttypescript/packages/mechanisms/evm/src/shared/defaultAssets.ts + +Add to the `DEFAULT_STABLECOINS` map: + +```typescript +"eip155:YOUR_CHAIN_ID": { + address: "0xYOUR_STABLECOIN_ADDRESS", + name: "Token Name", // EIP-712 domain name + version: "1", // EIP-712 domain version + decimals: 6, + // assetTransferMethod: "permit2", // Only if token lacks EIP-3009 + // supportsEip2612: true, // Only for Permit2 tokens with EIP-2612 +}, +``` +
+ +
+Gogo/mechanisms/evm/constants.go + +Add to the `NetworkConfigs` map: + +```go +"eip155:YOUR_CHAIN_ID": { + ChainID: big.NewInt(YOUR_CHAIN_ID), + DefaultAsset: AssetInfo{ + Address: "0xYOUR_STABLECOIN_ADDRESS", + Name: "Token Name", // EIP-712 domain name + Version: "1", // EIP-712 domain version + Decimals: 6, + // AssetTransferMethod: AssetTransferMethodPermit2, // Only if token lacks EIP-3009 + // SupportsEip2612: true, // Only for Permit2 tokens with EIP-2612 + }, +}, +``` +
+ +
+Pythonpython/x402/mechanisms/evm/constants.py + +Add to the `NETWORK_CONFIGS` dict: + +```python +"eip155:YOUR_CHAIN_ID": NetworkConfig( + chain_id=YOUR_CHAIN_ID, + default_asset=AssetInfo( + address="0xYOUR_STABLECOIN_ADDRESS", + name="Token Name", # EIP-712 domain name + version="1", # EIP-712 domain version + decimals=6, + # asset_transfer_method=AssetTransferMethod.PERMIT2, # Only if token lacks EIP-3009 + # supports_eip2612=True, # Only for Permit2 tokens with EIP-2612 + ), +), +``` +
+ +### 3. Submit a PR + +Include the chain name and rationale for the asset selection. If the chain team has officially endorsed a stablecoin, mention that. + +## Asset Selection Policy + +The default asset is chosen **per chain** based on: + +1. **Chain-endorsed stablecoin** — If the chain has officially selected or endorsed a stablecoin, use it. +2. **No official stance** — We encourage the chain team to make the selection and submit a PR. +3. **Community PRs welcome** — Chain teams and community members may submit PRs, provided the EIP-712 domain parameters are correct and the selection aligns with the chain's ecosystem. + +## Cross-SDK Checklist + +| SDK | File | Map/Dict | +|-----|------|----------| +| **TypeScript** | `typescript/packages/mechanisms/evm/src/shared/defaultAssets.ts` | `DEFAULT_STABLECOINS` | +| **Go** | `go/mechanisms/evm/constants.go` | `NetworkConfigs` | +| **Python** | `python/x402/mechanisms/evm/constants.py` | `NETWORK_CONFIGS` | diff --git a/README.md b/README.md index efcdc0790a..a136e65d83 100644 --- a/README.md +++ b/README.md @@ -16,41 +16,66 @@ app.use( // That's it! See examples/ for full details ``` +## Installation +
-Installation +Typescript + +
-### Typescript +> See all the packages available in the [**Typescript SDK**](./typescript/), including chain implementations of x402, code examples and integration guides. ```shell # All available reference sdks -npm install @x402/core @x402/evm @x402/svm @x402/axios @x402/fetch @x402/express @x402/hono @x402/next @x402/paywall @x402/extensions +npm install @x402/core \ + @x402/evm @x402/svm @x402/stellar @x402/svm \ + @x402/axios @x402/fastify @x402/fetch @x402/express @x402/hono @x402/next @x402/paywall @x402/extensions +``` +```shell # Minimal Fetch client npm install @x402/core @x402/evm @x402/svm @x402/fetch +``` +```shell # Minimal express Server npm install @x402/core @x402/evm @x402/svm @x402/express ``` -### Python +
+ +
+Python + +
+ +> See the [**`python/x402`**](./python/) folder for code examples and integration guides. ```shell pip install x402 ``` -### Go +
+ +
+Go + +
+ +> See the [**`go/`**](./go/) folder for code examples and integration guides. ```shell -go get github.com/coinbase/x402/go +go get github.com/x402-foundation/x402/go ```
+ ## Principles - **Open standard:** x402 is an open standard, freely accessible and usable by anyone. It will never force reliance on a single party. - **HTTP / Transport Native:** x402 is meant to seamlessly complement existing data transportation. It should whenever possible not mandate additional requests outside the scope of a typical client / server flow. -- **Network, token, and currency agnostic:** we welcome contributions that add support for new networks (both crypto and fiat), signing standards, or schemes, so long as they meet our acceptance criteria laid out in [CONTRIBUTING.md](https://github.com/coinbase/x402/blob/main/CONTRIBUTING.md). x402 may extend support to fiat based networks, but will never deprioritize onchain payments in favor of fiat payments. +- **Network, token, and currency agnostic:** we welcome contributions that add support for new networks (both crypto and fiat), signing standards, or schemes, so long as they meet our acceptance criteria laid out in [CONTRIBUTING.md](https://github.com/x402-foundation/x402/blob/main/CONTRIBUTING.md). x402 may extend support to fiat based networks, but will never deprioritize onchain payments in favor of fiat payments. - **Backwards Compatible:** x402 will not deprecate support for any existing networks unless such removal is deemed necessary for the security of the standard. Whenever possible, x402 will aim for backwards compatibility for non-major version changes. - **Trust minimizing:** all payment schemes must not allow for the facilitator or resource server to move funds, other than in accordance with client intentions - **Easy to use:** It is the goal of the x402 community to improve ease of use relative to other forms of payment on the Internet. This means abstracting as many details of crypto as possible away from the client and resource server, and into the facilitator. This means the client/server should not need to think about gas, rpc, etc. @@ -64,11 +89,11 @@ The x402 ecosystem is growing! Check out our [ecosystem page](https://x402.org/e - Ecosystem infrastructure and tooling - Learning and community resources -Want to add your project to the ecosystem? See our [demo site README](https://github.com/coinbase/x402/tree/main/typescript/site#adding-your-project-to-the-ecosystem) for detailed instructions on how to submit your project. +Want to add your project to the ecosystem? See our [demo site README](https://github.com/x402-foundation/x402/tree/main/typescript/site#adding-your-project-to-the-ecosystem) for detailed instructions on how to submit your project. -**Roadmap:** see [ROADMAP.md](https://github.com/coinbase/x402/blob/main/ROADMAP.md) +**Roadmap:** see [ROADMAP.md](https://github.com/x402-foundation/x402/blob/main/ROADMAP.md) -**Documentation:** see [docs/](./docs/) for the GitBook documentation source +**Documentation:** see [`docs/`](./docs/) for the published documentation source (Mintlify). Payment **schemes** include **`exact`**, **`upto`**, and **`batch-settlement`**; specifications live under [`specs/schemes/`](./specs/schemes/). ## Terms: @@ -127,9 +152,9 @@ A scheme is a logical way of moving money. Blockchains allow for a large number of flexible ways to move money. To help facilitate an expanding number of payment use cases, the `x402` protocol is extensible to different ways of settling payments via its `scheme` field. Each payment scheme may have different operational functionality depending on what actions are necessary to fulfill the payment. -For example `exact`, the first scheme shipping as part of the protocol, would have different behavior than `upto`. `exact` transfers a specific amount (ex: pay $1 to read an article), while a theoretical `upto` would transfer up to an amount, based on the resources consumed during a request (ex: generating tokens from an LLM). +For example, **`exact`** transfers a specific amount (for example, pay $1 to read an article). **`upto`** authorizes up to a maximum per request; the seller settles the actual usage, up to that cap. **`batch-settlement`** (EVM) uses escrow and off-chain vouchers so sellers can redeem many small charges onchain in batches instead of settling every HTTP request separately. -See `specs/schemes` for more details on schemes, and see `specs/schemes/exact/scheme_exact_evm.md` to see the first proposed scheme for exact payment on EVM chains. +See `specs/schemes` for full scheme specifications; `specs/schemes/exact/scheme_exact_evm.md` describes **exact** payments on EVM chains. ### Schemes vs Networks diff --git a/TSC.md b/TSC.md new file mode 100644 index 0000000000..2c1634d04f --- /dev/null +++ b/TSC.md @@ -0,0 +1,9 @@ +# Technical Steering Commitee + +The following are the Participating Organizations of the Technical Steering Committee and their Representatives, listed in order of greatest to least seniority: + +|Participating Organization | Representative| +|--------------|---------------| +|Coinbase, Inc. | Erik Reppel | +|Cloudflare, Inc. | Rohin Lohe | +|Stripe, Inc. | Steve Kaliski | diff --git a/docs/AGENTS.md b/docs/AGENTS.md index 5aba8f17a9..579e692dfc 100644 --- a/docs/AGENTS.md +++ b/docs/AGENTS.md @@ -7,6 +7,7 @@ ## Directory Structure - `advanced-concepts/` — Advanced topics (lifecycle hooks, etc.) - `core-concepts/` — Protocol explanations (HTTP 402, client-server, facilitator, wallet) +- `schemes/` — Payment scheme documentation with end-user server/client setup - `extensions/` — x402 extension documentation (Bazaar discovery, and future extensions) - `getting-started/` — Quickstart guides for buyers and sellers (MDX files with tabs) - `guides/` — How-to guides (MCP server, v1→v2 migration) @@ -17,6 +18,7 @@ ## Code-to-Doc Mapping - Changes to `typescript/packages/core/src/` affect Core Concepts docs +- Changes to `typescript/packages/mechanisms/`, `go/mechanisms/`, or `python/x402/mechanisms/` affect Payment Schemes docs and `sdk-features.md` - Changes to `typescript/packages/extensions/src/` affect Extensions docs (Bazaar, etc.) - Changes to `typescript/packages/*/src/` affect SDK references and quickstart guides - Changes to `python/x402/` affect Python SDK references @@ -24,10 +26,13 @@ - Changes to `go/` affect Go SDK references - Changes to `go/extensions/` affect Extensions docs - Changes to facilitator endpoints affect quickstart guides -- Changes to `specs/` may require updates to core-concepts docs +- Changes to `specs/schemes/` may require updates to Payment Schemes docs +- Changes to other `specs/` files may require updates to Core Concepts docs ## Style Guidelines - Use TypeScript for primary code examples (it's the reference SDK) +- For scheme pages, lead with server setup before client setup +- Keep scheme overviews network-agnostic; put network-specific behavior in the relevant scheme page section and link to specs for protocol details - Include error handling in all API examples - Write for developers with 2-5 years experience - Use MDX components (``, ``, ``, ``) for interactive content @@ -40,6 +45,7 @@ - DO: Link to relevant specs in `specs/` for protocol details - DO: Use `` for multi-language code examples - DO: Add frontmatter (title, description) to all pages +- DO: Link scheme pages to relevant server/client examples - DON'T: Duplicate protocol details from `specs/` — link instead - DON'T: Add pages without updating `docs.json` - **Git: Create PRs for review; NEVER commit directly to main** @@ -49,6 +55,7 @@ - `faq.md` — Frequently asked questions - `docs.json` — Navigation and configuration (MUST update when adding pages) - `core-concepts/*.md` — Conceptual documentation +- `schemes/*.mdx` — Payment scheme docs. Keep `overview` network-agnostic; individual scheme pages may include network-specific SDK setup and spec links - `extensions/*.mdx` — Extension documentation (Bazaar, future extensions) - `advanced-concepts/*.mdx` — Advanced topics (lifecycle hooks for custom workflows, etc.) - `getting-started/*.mdx` — Quickstart guides (MDX for tab components) @@ -96,13 +103,17 @@ When triggered by GitHub Actions or other automated workflows: |-------------|---------------------| | `typescript/packages/core/src/*.ts` API changes | Core Concepts, quickstart guides | | `typescript/packages/extensions/src/*.ts` Extensions changes | Extensions docs (Bazaar, etc.) | +| `typescript/packages/mechanisms/**/*.ts` API changes | Payment Schemes docs, SDK Features | | `typescript/packages/*/src/*.ts` API changes | SDK reference, quickstart guides | | `python/x402/*.py` API changes | Python SDK reference | +| `python/x402/mechanisms/**/*.py` API changes | Payment Schemes docs, SDK Features | | `python/x402/extensions/*.py` Extensions changes | Extensions docs | | `go/*.go` API changes | Go SDK reference | +| `go/mechanisms/**/*.go` API changes | Payment Schemes docs, SDK Features | | `go/extensions/*.go` Extensions changes | Extensions docs | | `java/src/**/*.java` API changes | Java SDK reference | -| `specs/*.md` protocol changes | core-concepts docs | +| `specs/schemes/*.md` protocol changes | Payment Schemes docs | +| `specs/*.md` protocol changes | Core Concepts docs | | `specs/extensions/*.md` Extensions changes | Extensions docs (only if SDK implementation exists) | | Comment removal, formatting | NO update needed | | Test file changes | NO update needed | diff --git a/docs/advanced-concepts/lifecycle-hooks.mdx b/docs/advanced-concepts/lifecycle-hooks.mdx index c37bab531e..1f60937327 100644 --- a/docs/advanced-concepts/lifecycle-hooks.mdx +++ b/docs/advanced-concepts/lifecycle-hooks.mdx @@ -11,12 +11,15 @@ Hooks allow you to intercept and modify payment lifecycle events on clients, ser Register hooks on the core resource server for verification and settlement lifecycle events. Use cases include logging payments, recording analytics, implementing custom access control or recovering from transient failures. -* **onBeforeVerify** — Runs before payment verification. Return `{ abort: true, reason }` to reject. -* **onAfterVerify** — Runs after successful verification. +* **onBeforeVerify** — Runs before payment verification. Return `{ abort: true, reason }` to reject, or `{ skip: true, result }` to use a locally produced verification result. +* **onAfterVerify** — Runs after successful verification. Return `{ skipHandler: true, response? }` to settle without invoking the resource handler. * **onVerifyFailure** — Runs on verification failure. Return `{ recovered: true, result }` to override. -* **onBeforeSettle** — Runs before settlement. Return `{ abort: true, reason }` to reject. +* **onBeforeSettle** — Runs before settlement. Return `{ abort: true, reason }` to reject, or `{ skip: true, result }` to use a locally produced settlement result. * **onAfterSettle** — Runs after successful settlement. * **onSettleFailure** — Runs on settlement failure. Return `{ recovered: true, result }` to override. +* **onVerifiedPaymentCanceled** — Runs when a verified payment is not settled because the protected handler throws or returns an error response. + +These server-level hooks run for every payment regardless of which extensions are active. Extensions and schemes can also contribute lifecycle hook adapters that run only when their extension key or scheme/network is used. See [Extensions Overview](/extensions/overview) for extension-level behavior. @@ -70,7 +73,7 @@ Register hooks on the core resource server for verification and settlement lifec ```go - import x402 "github.com/coinbase/x402/go" + import x402 "github.com/x402-foundation/x402/go" server := x402.Newx402ResourceServer(facilitatorClient) @@ -121,8 +124,8 @@ Register hooks for HTTP-specific request handling before payment processing. Use ```go import ( "context" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" ) // Create resource server @@ -155,6 +158,7 @@ Register hooks on the core client for payment payload creation lifecycle events. * **onBeforePaymentCreation** — Runs before creating a payment payload. Return `{ abort: true, reason }` to cancel. * **onAfterPaymentCreation** — Runs after successful payload creation. * **onPaymentCreationFailure** — Runs on failure. Return `{ recovered: true, payload }` to provide fallback. +* **onPaymentResponse** — Runs after a paid request completes. Return `{ recovered: true }` to tell the transport to retry with a fresh payload. @@ -210,7 +214,7 @@ Register hooks on the core client for payment payload creation lifecycle events. ```go - import x402 "github.com/coinbase/x402/go" + import x402 "github.com/x402-foundation/x402/go" client := x402.Newx402Client() @@ -342,7 +346,7 @@ Register hooks on the facilitator for verification and settlement lifecycle even ```go - import x402 "github.com/coinbase/x402/go" + import x402 "github.com/x402-foundation/x402/go" facilitator := x402.Newx402Facilitator() @@ -365,7 +369,7 @@ Register hooks on the facilitator for verification and settlement lifecycle even ## Hook Chaining -All SDKs support method chaining for registering multiple hooks: +Hooks can be chained when registering multiple handlers: diff --git a/docs/core-concepts/client-server.md b/docs/core-concepts/client-server.md index 83c3478a13..3b083bebfd 100644 --- a/docs/core-concepts/client-server.md +++ b/docs/core-concepts/client-server.md @@ -50,7 +50,7 @@ Servers do not need to manage client identities or maintain session state. Verif #### Duplicate Settlement on Solana -If your server settles payments directly on Solana (without delegating to a facilitator), be aware of a race condition: the same signed payment transaction can be submitted multiple times before the first submission is confirmed on-chain. Solana's RPC will return "success" for each submission, since the network deduplicates at the consensus level. A malicious client can exploit this to obtain access to multiple resources while only paying once. +If your server settles payments directly on Solana (without delegating to a facilitator), be aware of a race condition: the same signed payment transaction can be submitted multiple times before the first submission is confirmed onchain. Solana's RPC will return "success" for each submission, since the network deduplicates at the consensus level. A malicious client can exploit this to obtain access to multiple resources while only paying once. To mitigate this, servers that settle Solana payments themselves **must** maintain a short-lived, in-memory cache of transaction payloads currently being settled: @@ -59,7 +59,7 @@ To mitigate this, servers that settle Solana payments themselves **must** mainta 3. If the key is not present, insert it into the cache and proceed with settlement. 4. Evict entries older than 120 seconds (approximately twice the Solana blockhash lifetime). -If you are using a facilitator, the x402 SVM libraries already include built-in duplicate settlement protection via a `SettlementCache`. See the [Exact SVM Scheme Specification](https://github.com/coinbase/x402/blob/main/specs/schemes/exact/scheme_exact_svm.md) for full details. +If you are using a facilitator, the x402 SVM libraries already include built-in duplicate settlement protection via a `SettlementCache`. See the [Exact SVM Scheme Specification](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_svm.md) for full details. ### Communication Flow diff --git a/docs/core-concepts/facilitator.md b/docs/core-concepts/facilitator.md index 4c96cba36f..a598ac07fb 100644 --- a/docs/core-concepts/facilitator.md +++ b/docs/core-concepts/facilitator.md @@ -53,13 +53,13 @@ Multiple facilitators are live in production, supporting various networks includ ### Duplicate Settlement (Solana) -On Solana, a race condition can occur when the same payment transaction is submitted to a facilitator's `/settle` endpoint multiple times before the first submission is confirmed on-chain. Because Solana's RPC returns "success" for duplicate submissions (the network deduplicates at the consensus level), the facilitator may return a successful settlement response for each call. A malicious client could exploit this to access multiple resources while only paying once. +On Solana, a race condition can occur when the same payment transaction is submitted to a facilitator's `/settle` endpoint multiple times before the first submission is confirmed onchain. Because Solana's RPC returns "success" for duplicate submissions (the network deduplicates at the consensus level), the facilitator may return a successful settlement response for each call. A malicious client could exploit this to access multiple resources while only paying once. To mitigate this, the x402 SVM mechanism packages include a built-in `SettlementCache` — a short-lived, in-memory cache that detects and rejects duplicate settlement attempts for the same transaction payload. The cache requires no external storage and entries are automatically evicted after 120 seconds (approximately twice the Solana blockhash lifetime). This protection is enabled by default when using the standard SVM facilitator registration helpers in TypeScript and Python. In Go, a shared `SettlementCache` instance should be passed to both V1 and V2 SVM facilitator schemes during registration. -**If you are a merchant settling payments directly (without a facilitator), you must implement equivalent duplicate detection yourself.** See the [Exact SVM Scheme Specification](https://github.com/coinbase/x402/blob/main/specs/schemes/exact/scheme_exact_svm.md) for the full specification. +**If you are a merchant settling payments directly (without a facilitator), you must implement equivalent duplicate detection yourself.** See the [Exact SVM Scheme Specification](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_svm.md) for the full specification. ### Summary diff --git a/docs/core-concepts/http-402.md b/docs/core-concepts/http-402.md index 9a0a3429fa..dab4cd847f 100644 --- a/docs/core-concepts/http-402.md +++ b/docs/core-concepts/http-402.md @@ -39,6 +39,8 @@ x402 V2 uses three standardized headers for payment communication: All headers contain valid Base64-encoded JSON strings. This encoding ensures compatibility across different HTTP implementations and prevents issues with special characters in JSON payloads. +Whether funds move **onchain** in the same HTTP round trip depends on the **scheme**: **`exact`** and **`upto`** typically settle immediately, while **`batch-settlement`** confirms the payment authorization up front and redeems value **onchain** later according to the network binding (see **[Batch settlement](/schemes/batch-settlement)**). + ### Summary HTTP 402 is the foundation of the x402 protocol, enabling services to declare payment requirements directly within HTTP responses. It: diff --git a/docs/core-concepts/network-and-token-support.mdx b/docs/core-concepts/network-and-token-support.mdx index ffab259f2a..40bd2bca6e 100644 --- a/docs/core-concepts/network-and-token-support.mdx +++ b/docs/core-concepts/network-and-token-support.mdx @@ -3,66 +3,34 @@ title: "Networks & Token Support" description: "This page explains which blockchain networks and tokens are supported by x402, and how to extend support to additional networks." --- -## V2 Network Identifiers (CAIP-2) +## Network Identifiers (CAIP-2) -x402 V2 uses [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) standard network identifiers for unambiguous cross-chain support. This format follows the pattern `namespace:reference`. +x402 uses [CAIP-2](https://chainagnostic.org/CAIPs/caip-2) standard network identifiers (`namespace:reference`) for unambiguous cross-chain support: -### Network Identifier Reference +- **EVM networks**: `eip155:` — any EVM chain is supported (e.g., `eip155:8453` for Base) +- **Solana**: `solana:` (first 32 bytes of the genesis block hash) +- **TON (TVM)**: `tvm:` (e.g., `tvm:-239` for mainnet, `tvm:-3` for testnet) +- **Algorand**: `algorand:` (base64-encoded genesis hash) +- **Stellar**: `stellar:` (`pubnet` or `testnet`) +- **Aptos**: `aptos:` (e.g., `aptos:1` for mainnet) +- **Hedera**: `hedera:` (`mainnet` or `testnet`) -| V1 Name | V2 CAIP-2 ID | Chain ID | Description | -|---------|--------------|----------|-------------| -| `base` | `eip155:8453` | 8453 | Base mainnet | -| `base-sepolia` | `eip155:84532` | 84532 | Base Sepolia testnet | -| `solana` | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | - | Solana mainnet | -| `solana-devnet` | `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` | - | Solana Devnet | -| - | `aptos:1` | 1 | Aptos Mainnet | -| - | `aptos:2` | 2 | Aptos Testnet | -| - | `stellar:pubnet` | - | Stellar Mainnet | -| - | `stellar:testnet` | - | Stellar Testnet | -| `avalanche` | `eip155:43114` | 43114 | Avalanche C-Chain mainnet | -| `avalanche-fuji` | `eip155:43113` | 43113 | Avalanche Fuji testnet | -| `polygon` | `eip155:137` | 137 | Polygon mainnet | -| `polygon-amoy` | `eip155:80002` | 80002 | Polygon Amoy testnet | -| `sei` | `eip155:1329` | 1329 | Sei mainnet | -| `sei-testnet` | `eip155:713715` | 713715 | Sei testnet | -| `skale-base` | `eip155:1187947933` | 1187947933 | SKALE mainnet | -| `skale-base-sepolia` | `eip155:324705682` | 324705682 | SKALE testnet | +## Token Support -### Format Explanation -- **EVM networks**: `eip155:` where chainId is the numeric chain identifier -- **Solana**: `solana:` where genesisHash is the first 32 bytes of the genesis block hash -- **Stellar**: `stellar:` where network is `pubnet` (mainnet) or `testnet` -- **Aptos**: `aptos:` where chainId is the numeric chain identifier +x402 supports tokens on EVM, Solana, TON, Stellar, Aptos, and Hedera networks: -## Overview +| Ecosystem | Supported Tokens | Transfer Method | +|-----------|------------------|-----------------| +| **EVM** | Any ERC-20 token | EIP-3009 or Permit2 | +| **Solana** | Any SPL or Token-2022 token | SPL Transfer | +| **TON (TVM)** | Any TEP-74 jetton (e.g., USDT) | Signed W5R1 internal message | +| **Stellar** | Any Soroban token implementing SEP-41 | `transfer(from, to, amount)` | +| **Aptos** | Any fungible asset | `primary_fungible_store::transfer` | +| **Hedera** | HBAR or any HTS fungible token | Hedera Transfer Transaction | -x402 is designed to work across multiple blockchain networks, with different levels of support depending on the facilitator being used. The protocol itself is network-agnostic, but facilitators need to implement network-specific logic for payment verification and settlement. +Facilitators support **networks**, not specific tokens — any compatible token works on any facilitator that supports that network. -### Supported Facilitators - -Network support in x402 depends on which facilitator you use. For a complete and up-to-date list of available facilitators and their supported networks, see the [x402 Ecosystem](https://www.x402.org/ecosystem?filter=facilitators). - -#### x402.org Facilitator - -* **Supports**: `eip155:84532` (Base Sepolia), `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` (Solana Devnet) -* **Notes**: Recommended for testing and development. This is the default facilitator in the x402 packages and requires no setup. - -#### Production Facilitators - -Multiple production-ready facilitators are available supporting various networks including Base, Solana, Polygon, Avalanche, and more. See the [x402 Ecosystem](https://www.x402.org/ecosystem?filter=facilitators) for available options and their documentation. - -### Token Support - -x402 supports tokens on EVM, Solana, Stellar, and Aptos networks: - -* **EVM**: Any ERC-20 token (via EIP-3009 or Permit2) -* **Solana**: Any SPL or token-2022 token -* **Stellar**: Any Soroban token implementing SEP-41 -* **Aptos**: Any fungible asset using Aptos's native fungible asset framework - -**Important**: Facilitators support networks, not specific tokens — any ERC-20 token works on EVM networks (via EIP-3009 or Permit2), any SPL/token-2022 token works on Solana, any SEP-41 token works on Stellar, and any fungible asset works on Aptos, for the facilitators that support those networks. - -#### EVM: Asset Transfer Methods +### EVM: Asset Transfer Methods x402 supports two asset transfer methods on EVM, selected automatically based on token capabilities: @@ -71,24 +39,22 @@ x402 supports two asset transfer methods on EVM, selected automatically based on | **EIP-3009** | Tokens with `transferWithAuthorization` (e.g., USDC) | Single off-chain signature, simplest flow | | **Permit2** | Any ERC-20 token | Uses Uniswap's [Permit2](https://docs.uniswap.org/contracts/v4/deployments) contract + `x402ExactPermit2Proxy` | -Both methods provide: +Both methods provide gasless transfers (facilitator sponsors gas), signature-based authorization, and secure payments. EIP-3009 is preferred when available (simpler, no approval step). Permit2 serves as the universal fallback. -* **Gasless transfers**: The facilitator sponsors gas for the payment itself. For Permit2, the one-time approval step can also be made gasless via optional [gas sponsoring extensions](/extensions/eip2612-gas-sponsoring) -* **Signature-based authorization**: Users sign transfer authorizations off-chain -* **Secure payments**: Transfers are authorized by cryptographic signatures +**Permit2 approval**: Requires a one-time onchain approval. x402 supports two gas sponsoring extensions that make this step gasless — see [EIP-2612 Gas Sponsoring](/extensions/eip2612-gas-sponsoring) and [ERC-20 Approval Gas Sponsoring](/extensions/erc20-approval-gas-sponsoring). -EIP-3009 is preferred when available (simpler, no approval step). Permit2 serves as the universal fallback, enabling any ERC-20 token to work with x402. +### EVM: Batch settlement (`batch-settlement`) -**Permit2 approval**: Permit2 requires a one-time on-chain approval of the Permit2 contract. x402 supports two gas sponsoring extensions that make this step gasless — see [EIP-2612 Gas Sponsoring](/extensions/eip2612-gas-sponsoring) and [ERC-20 Approval Gas Sponsoring](/extensions/erc20-approval-gas-sponsoring). +For high-frequency or repeated micropayment flows where settling every request onchain is too costly, x402 supports the **`batch-settlement`** scheme on EVM: the buyer deposits once into an escrow contract, signs off-chain vouchers per request, and sellers redeem in batches onchain. Per-request pricing still uses an **up-to** ceiling (`PaymentRequirements.amount`); actual charges can vary per request within that limit—see **[Batch settlement](/schemes/batch-settlement)**. -#### Specifying Payment Amounts +### Specifying Payment Amounts When configuring payment requirements, you have two options: -1. **Price String** (e.g., `"$0.01"`) - The system infers USDC as the token -2. **TokenAmount** - Specify exact atomic units of any ERC-20 token +1. **Price String** (e.g., `"$0.01"`) — The system uses the chain's [default stablecoin](#default-assets-for-dollar-string-pricing). Only works on chains with a configured default. +2. **TokenAmount** — Specify exact `amountInAtomicUnits` + asset address. Works on **any chain** with no configuration needed. -#### Using Custom ERC-20 Tokens +### Using Custom ERC-20 Tokens To use a custom ERC-20 token, you need three key pieces of information: @@ -96,9 +62,7 @@ To use a custom ERC-20 token, you need three key pieces of information: 2. **EIP-712 Name**: The token's name for EIP-712 signatures 3. **EIP-712 Version**: The token's version for EIP-712 signatures -**Finding Token Information on Basescan** - -You can retrieve the required EIP-712 values from any block explorer: +You can retrieve these from any block explorer: 1. **Name**: Read the `name()` function - [Example on Basescan](https://basescan.org/token/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913#readProxyContract#F16) 2. **Version**: Read the `version()` function - [Example on Basescan](https://basescan.org/token/0x833589fcd6edb6e08f4c7c32d4f71b54bda02913#readProxyContract#F24) @@ -114,47 +78,83 @@ These values are used in the `eip712` nested object when configuring TokenAmount } ``` -#### Solana: SPL Tokens & Token 2022 Tokens +## Default Assets for Dollar-String Pricing -On Solana, x402 supports all SPL tokens and Token 2022 tokens. When using facilitators that support Solana or Solana Devnet, payments can be made in any SPL/token-2022 token, including USDC (SPL). No EIP-712 configuration is required on Solana. +When you use `"$0.01"` syntax, x402 needs to know which stablecoin to use. The following chains have pre-configured defaults. For chains not listed, use `registerMoneyParser()` or specify the price directly as a `TokenAmount` with `amountInAtomicUnits`. To contribute a new default asset, see [Contributing a New Default Asset](#contributing-a-new-default-asset) below. -#### Stellar: Soroban Tokens +### EVM -On Stellar, x402 supports all Soroban tokens implementing [SEP-41](https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0041.md). Payments use the `transfer(from, to, amount)` function. The TypeScript SDK supports sponsored transactions where facilitators pay gas fees on behalf of clients. Stellar uses ledger-based expiration (default ~12 ledgers ≈ 60 seconds) instead of timestamps. +| Chain | CAIP-2 | Token Address | EIP-712 Name | Decimals | Transfer Method | +|-------|--------|---------------|--------------|----------|-----------------| +| Base | `eip155:8453` | `0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913` | USD Coin | 6 | EIP-3009 | +| Base Sepolia | `eip155:84532` | `0x036CbD53842c5426634e7929541eC2318f3dCF7e` | USDC | 6 | EIP-3009 | +| Polygon | `eip155:137` | `0x3c499c542cEF5E3811e1192ce70d8cC03d5c3359` | USD Coin | 6 | EIP-3009 | +| Arbitrum One | `eip155:42161` | `0xaf88d065e77c8cC2239327C5EDb3A432268e5831` | USD Coin | 6 | EIP-3009 | +| Arbitrum Sepolia | `eip155:421614` | `0x75faf114eafb1BDbe2F0316DF893fd58CE46AA4d` | USD Coin | 6 | EIP-3009 | +| Monad | `eip155:143` | `0x754704Bc059F8C67012fEd69BC8A327a5aafb603` | USD Coin | 6 | EIP-3009 | +| Stable | `eip155:988` | `0x779Ded0c9e1022225f8E0630b35a9b54bE713736` | USDT0 | 6 | EIP-3009 | +| Stable Testnet | `eip155:2201` | `0x78Cf24370174180738C5B8E352B6D14c83a6c9A9` | USDT0 | 6 | EIP-3009 | +| MegaETH | `eip155:4326` | `0xFAfDdbb3FC7688494971a79cc65DCa3EF82079E7` | MegaUSD | 18 | Permit2 + EIP-2612 | +| Mezo Testnet | `eip155:31611` | `0x118917a40FAf1CD7a13dB0Ef56C86De7973Ac503` | Mezo USD | 18 | Permit2 + EIP-2612 | +| Radius | `eip155:723487` | `0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb` | Stable Coin | 6 | Permit2 + EIP-2612 | +| Radius Testnet | `eip155:72344` | `0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb` | Stable Coin | 6 | Permit2 + EIP-2612 | -#### Aptos: Fungible Assets -On Aptos, x402 supports all fungible assets using Aptos's native fungible asset framework. Payments use the `primary_fungible_store::transfer` function for automatic store creation and management. The TypeScript SDK supports sponsored transactions where facilitators pay gas fees on behalf of clients. -#### Default Tokens +### Solana (SVM) -Each network defines its own default token. When you use a price string (e.g., `"$0.01"`), the system uses the network's configured default. USDC is the default on most EVM networks because it implements EIP-3009 (simplest flow) and is widely available, but other networks may define different defaults. +| Chain | CAIP-2 | Token Mint | Decimals | +|-------|--------|------------|----------| +| Solana Mainnet | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | `EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v` (USDC) | 6 | +| Solana Devnet | `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` | `4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU` (USDC) | 6 | -#### Why EIP-3009 + Permit2? +### TON (TVM) -These two transfer methods together give x402 full ERC-20 coverage on EVM: +| Chain | CAIP-2 | Jetton Minter | Decimals | +|-------|----------|---------------|----------| +| TON Mainnet | `tvm:-239` | `EQCxE6mUtQJKFnGfaROTKOt1lZbDiiX1kCixRv7Nw2Id_sDs` (USDT) | 6 | +| TON Testnet | `tvm:-3` | `kQDNUDJC0iQvJoZp0ml-YteL1NtTXKphU03CTI5v4VtBhGYs` (USDT) | 6 | -1. **Gas abstraction**: Buyers don't need native tokens (ETH, MATIC, etc.) for gas -2. **EIP-3009**: One-step payments with no approval needed — ideal for tokens like USDC -3. **Permit2**: Universal fallback for any ERC-20 token, with optional gas-sponsored approval via [extensions](/extensions/eip2612-gas-sponsoring) +### Algorand (AVM) -### Quick Reference +| Chain | CAIP-2 | ASA ID | Decimals | +|-------|--------|--------|----------| +| Algorand Mainnet | `algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=` | `31566704` (USDC) | 6 | +| Algorand Testnet | `algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=` | `10458941` (USDC) | 6 | -| Facilitator Type | Networks Supported | Production Ready | Requirements | -| ---------------- | ------------------ | ---------------- | ------------ | -| x402.org (Default) | `eip155:84532`, `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` | Testnet only | None | -| [Production Facilitators](https://www.x402.org/ecosystem?filter=facilitators) | Various (Base, Solana, Polygon, Avalanche, etc.) | Yes | Varies | -| Self-hosted | Any EVM network (CAIP-2 format) | Yes | Technical setup | +### Stellar + +| Chain | CAIP-2 | Token Contract | Decimals | +|-------|--------|---------------|----------| +| Stellar Pubnet | `stellar:pubnet` | `CCW67TSZV3SSS2HXMBQ5JFGCKJNXKZM7UQUWUZPUTHXSTZLEO7SJMI75` (USDC) | 7 | +| Stellar Testnet | `stellar:testnet` | `CBIELTK6YBZJU5UP2WWQEUCYKLPU6AUNZ2BQ4WWFEIE3USCIHMXQDAMA` (USDC) | 7 | + +### Aptos + +| Chain | CAIP-2 | Fungible Asset Address | Decimals | +|-------|--------|----------------------|----------| +| Aptos Mainnet | `aptos:1` | `0xbae207659db88bea0cbead6da0ed00aac12edcdda169e591cd41c94180b46f3b` (USDC) | 6 | +| Aptos Testnet | `aptos:2` | `0x69091fbab5f7d635ee7ac5098cf0c1efbe31d68fec0f2cd565e8d168daf52832` (USDC) | 6 | + +### Hedera + +| Chain | CAIP-2 | Token ID | Decimals | +|-------|--------|----------|----------| +| Hedera Mainnet | `hedera:mainnet` | `0.0.456858` (USDC) | 6 | +| Hedera Testnet | `hedera:testnet` | `0.0.429274` (USDC) | 6 | + +HBAR (native token) is also supported using asset ID `0.0.0`, with amounts in tinybars (1 HBAR = 10⁸ tinybars). -**Note**: On EVM networks, facilitators support any ERC-20 token (via EIP-3009 or Permit2); on Solana, facilitators support any SPL/Token-2022 token. +## Adding Support for New Networks -### Adding Support for New Networks +There are two distinct paths, depending on your goal: -x402 V2 uses dynamic network registration - you can support any EVM network without modifying source files. +1. **[Runtime Registration](#runtime-registration)** — use any network in your own server code without modifying the x402 source. No PR required. +2. **[Contributing a New Default Asset](#contributing-a-new-default-asset)** — upstream a chain so it appears in the default-asset tables above and supports `"$0.01"` dollar-string pricing out of the box. Requires a PR updating the TypeScript, Go, and Python SDK registries. -#### V2: Dynamic Registration (Recommended) +### Runtime Registration -In V2, networks are supported through the registration pattern using CAIP-2 identifiers. No source code changes are required: +x402 uses dynamic network registration — you can support any EVM network without modifying source files. @@ -167,9 +167,8 @@ In V2, networks are supported through the registration pattern using CAIP-2 iden }); const server = new x402ResourceServer(facilitatorClient); - server.register("eip155:*", new ExactEvmScheme()); // Registers wildcard support for all EVM chains + server.register("eip155:*", new ExactEvmScheme()); - // Now use any CAIP-2 network identifier in your routes: const routes = { "GET /api/data": { accepts: [{ @@ -185,15 +184,14 @@ In V2, networks are supported through the registration pattern using CAIP-2 iden ```go import ( - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" + x402http "github.com/x402-foundation/x402/go/http" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ URL: "https://your-facilitator.com", }) - // Register EVM scheme - supports any CAIP-2 EVM network schemes := []ginmw.SchemeConfig{ {Network: x402.Network("eip155:43114"), Server: evm.NewExactEvmScheme()}, // Avalanche } @@ -206,23 +204,19 @@ In V2, networks are supported through the registration pattern using CAIP-2 iden from x402.mechanisms.evm.exact import ExactEvmServerScheme from x402.server import x402ResourceServer - # Create facilitator client for your network facilitator = HTTPFacilitatorClient( FacilitatorConfig(url="https://your-facilitator.com") ) - # Create server and register EVM scheme for your network server = x402ResourceServer(facilitator) server.register("eip155:43114", ExactEvmServerScheme()) # Avalanche mainnet - - # Now use any CAIP-2 network identifier in your routes: routes: dict[str, RouteConfig] = { "GET /api/data": RouteConfig( accepts=[ PaymentOption( scheme="exact", price="$0.001", - network="eip155:43114", # Avalanche mainnet + network="eip155:43114", pay_to="0xYourAddress", ), ], @@ -237,7 +231,32 @@ In V2, networks are supported through the registration pattern using CAIP-2 iden - The scheme implementation handles the network automatically - You only need a facilitator that supports your target network (or run your own) -#### Running Your Own Facilitator +### Contributing a New Default Asset + +To add a chain to the [default-asset tables above](#default-assets-for-dollar-string-pricing) so that dollar-string pricing (`"$0.01"`) works out of the box, open a PR against [x402-foundation/x402](https://github.com/x402-foundation/x402). Follow the cross-SDK walkthrough in [DEFAULT_ASSETS.md](https://github.com/x402-foundation/x402/blob/main/DEFAULT_ASSETS.md), which names every file in the TypeScript, Go, and Python registries that must be updated. + +## Facilitators + +Network support in x402 depends on which facilitator you use. For a complete list, see the [x402 Ecosystem](https://www.x402.org/ecosystem?filter=facilitators). + +### x402.org Facilitator + +* **Supports**: `eip155:84532` (Base Sepolia), `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` (Solana Devnet), `stellar:testnet` (Stellar Testnet), `aptos:2` (Aptos Testnet) +* **Notes**: Recommended for testing and development. This is the default facilitator in the x402 packages and requires no setup. + +### Production Facilitators + +Multiple production-ready facilitators are available supporting various networks including Base, Solana, Polygon, Avalanche, and more. See the [x402 Ecosystem](https://www.x402.org/ecosystem?filter=facilitators) for available options. + +### Quick Reference + +| Facilitator Type | Networks Supported | Production Ready | Requirements | +| ---------------- | ------------------ | ---------------- | ------------ | +| x402.org (Default) | `eip155:84532`, `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`, `stellar:testnet`, `aptos:2` | Testnet only | None | +| [Production Facilitators](https://www.x402.org/ecosystem?filter=facilitators) | Various (Base, Solana, Polygon, Avalanche, etc.) | Yes | Varies | +| Self-hosted | Any network | Yes | Technical setup | + +### Running Your Own Facilitator If you need immediate support or want to test before contributing, you can run your own facilitator. @@ -249,33 +268,19 @@ Video Guide: [Adding EVM Chains to x402](https://x.com/jaycoolh/status/192085155 2. A wallet with native tokens for gas sponsorship 3. The x402 facilitator code -### Future Network Support - -The x402 ecosystem is actively expanding network support. Planned additions include: - -* Additional L2 networks -* Additional non-EVM chain support -* Cross-chain payment capabilities - -### Getting Help - -For help with network integration: +## Getting Help * Join the [x402 Discord community](https://discord.gg/cdp) -* Check the [x402 GitHub repository](https://github.com/coinbase/x402) - -### Summary +* Check the [x402 GitHub repository](https://github.com/x402-foundation/x402) -x402's network support is designed to be extensible while maintaining security and reliability. Whether you're using the default Base Sepolia (`eip155:84532`) setup for testing or running your own facilitator for custom networks, the protocol provides flexibility for various use cases. +## Summary Key takeaways: -* Base (`eip155:8453`), Base Sepolia (`eip155:84532`), Solana (`solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp`), and Solana Devnet (`solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1`) have the best out-of-the-box support -* Any EVM network can be supported with a custom facilitator using CAIP-2 format -* Any ERC-20 token works on any facilitator (via EIP-3009 or Permit2) -* Use price strings for USDC or TokenAmount for custom tokens -* Network choice affects gas costs and payment economics -* V2 uses CAIP-2 network identifiers for unambiguous cross-chain support +* **Any EVM chain** is supported via `eip155:` — plus Solana, TON (TVM), Algorand, Stellar, Aptos, and Hedera +* [Default assets](#default-assets-for-dollar-string-pricing) are a convenience for `"$0.01"` dollar-string pricing; explicit `TokenAmount` works on any chain +* Any ERC-20 token works on any EVM facilitator (via EIP-3009 or Permit2) +* CAIP-2 identifiers provide unambiguous cross-chain support Next, explore: diff --git a/docs/docs.json b/docs/docs.json index 90d8e39cb0..269fab39d5 100644 --- a/docs/docs.json +++ b/docs/docs.json @@ -23,7 +23,7 @@ { "anchor": "GitHub", "icon": "github", - "href": "https://github.com/coinbase/x402" + "href": "https://github.com/x402-foundation/x402" }, { "anchor": "Discord", @@ -62,6 +62,15 @@ "core-concepts/network-and-token-support" ] }, + { + "group": "Payment Schemes", + "pages": [ + "schemes/overview", + "schemes/exact", + "schemes/upto", + "schemes/batch-settlement" + ] + }, { "group": "Extensions", "pages": [ diff --git a/docs/extensions/bazaar.mdx b/docs/extensions/bazaar.mdx index e84dbf09bd..7eb4be66ac 100644 --- a/docs/extensions/bazaar.mdx +++ b/docs/extensions/bazaar.mdx @@ -69,20 +69,14 @@ Clients that understand the `bazaar` extension should read the `bazaar` key of t #### List Endpoint -Retrieve all available x402-compatible endpoints and MCP tools: +Retrieve all available x402-compatible endpoints and MCP tools from a facilitator that supports Bazaar discovery: -##### Coinbase ```bash -GET https://api.cdp.coinbase.com/platform/v2/x402/discovery/resources -``` - -##### PayAI -```bash -GET https://facilitator.payai.network/discovery/resources +GET {facilitator_url}/discovery/resources ``` -**Note**: The recommended way to use this endpoint is to use the `useFacilitator` hook as described below. +**Note**: The recommended way to use this endpoint is through the Bazaar facilitator client extension shown below. **Response Schema** @@ -93,29 +87,39 @@ Each resource in the list contains the following fields: "accepts": [ { "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - "description": "", "extra": { "name": "USD Coin", "version": "2" }, - "maxAmountRequired": "200", + "amount": "200", "maxTimeoutSeconds": 60, - "mimeType": "", "network": "eip155:8453", - "outputSchema": { - "input": { - "method": "GET", - "type": "http" - }, - "output": null - }, "payTo": "0xa2477E16dCB42E2AD80f03FE97D7F1a1646cd1c0", - "resource": "https://api.example.com/x402/weather", "scheme": "exact" } ], + "extensions": { + "bazaar": { + "info": { + "input": { + "type": "http", + "method": "GET", + "queryParams": { + "city": "San Francisco" + } + }, + "output": { + "type": "json", + "example": { + "city": "San Francisco", + "weather": "foggy", + "temperature": 60 + } + } + } + } + }, "lastUpdated": "2025-08-09T01:07:04.005Z", - "metadata": {}, "resource": "https://api.example.com/x402/weather", "type": "http", "x402Version": 2 @@ -128,15 +132,15 @@ The `type` field indicates the resource type: - `"http"` - HTTP endpoints (GET, POST, PUT, PATCH, DELETE, HEAD) - `"mcp"` - MCP (Model Context Protocol) tools -For MCP tools, the `outputSchema.input` object will contain: +For MCP tools, the `extensions.bazaar.info.input` object will contain: - `type: "mcp"` - Identifies this as an MCP tool -- `tool` - The MCP tool name (used in `tools/call` requests) +- `toolName` - The MCP tool name (used in `tools/call` requests) - `inputSchema` - JSON Schema for the tool's arguments (follows MCP `Tool.inputSchema` format) - `description` - Human-readable description of the tool (optional) - `transport` - MCP transport protocol: `"streamable-http"` (default) or `"sse"` (optional) - `example` - Example arguments object (optional) -**Note:** For MCP tools, the unique resource identifier is the tuple (`resource`, `input.tool`) since MCP multiplexes multiple tools over a single server endpoint. +**Note:** For MCP tools, the unique resource identifier is the tuple (`resource`, `extensions.bazaar.info.input.toolName`) since MCP multiplexes multiple tools over a single server endpoint. ### Quickstart for Buyers @@ -155,7 +159,8 @@ Fetch the list of available x402 services using the facilitator client: }); const client = withBazaar(facilitatorClient); - const response = await client.extensions.discovery.listResources({ type: "http" }); + // List HTTP services; use type: "mcp" to list MCP tools instead + const response = await client.extensions.bazaar.listResources({ type: "http" }); // Filter services under $0.10 const usdcAsset = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"; @@ -164,7 +169,7 @@ Fetch the list of available x402 services using the facilitator client: const affordableServices = response.items.filter(item => item.accepts.find(paymentRequirements => paymentRequirements.asset === usdcAsset && - Number(paymentRequirements.maxAmountRequired) < maxPrice + Number(paymentRequirements.amount) < maxPrice ) ); ``` @@ -175,10 +180,12 @@ Fetch the list of available x402 services using the facilitator client: import ( "context" + "encoding/json" "fmt" + "strconv" - "github.com/coinbase/x402/go/extensions/bazaar" - x402http "github.com/coinbase/x402/go/http" + "github.com/x402-foundation/x402/go/extensions/bazaar" + x402http "github.com/x402-foundation/x402/go/http" ) func main() { @@ -203,16 +210,22 @@ Fetch the list of available x402 services using the facilitator client: // Filter services under $0.10 usdcAsset := "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" maxPrice := 100000 // $0.10 in USDC atomic units (6 decimals) + type paymentRequirement struct { + Asset string `json:"asset"` + Amount string `json:"amount"` + } for _, item := range response.Items { - for _, paymentReq := range item.Accepts { - // Parse asset and maxAmountRequired from payment requirements - if asset, ok := paymentReq["asset"].(string); ok && asset == usdcAsset { - if maxAmount, ok := paymentReq["maxAmountRequired"].(string); ok { - // Convert and compare price - fmt.Printf("Found service: %s\n", item.Resource) - } + for _, rawPaymentReq := range item.Accepts { + var paymentReq paymentRequirement + if err := json.Unmarshal(rawPaymentReq, &paymentReq); err != nil { + continue + } + amount, err := strconv.ParseInt(paymentReq.Amount, 10, 64) + if err != nil || paymentReq.Asset != usdcAsset || amount >= int64(maxPrice) { + continue } + fmt.Printf("Found service: %s\n", item.Resource) } } } @@ -221,12 +234,17 @@ Fetch the list of available x402 services using the facilitator client: ```python from x402.http import FacilitatorConfig, HTTPFacilitatorClient + from x402.extensions.bazaar import with_bazaar, ListDiscoveryResourcesParams - facilitator = HTTPFacilitatorClient( + facilitator_client = HTTPFacilitatorClient( FacilitatorConfig(url="https://x402.org/facilitator") ) + client = with_bazaar(facilitator_client) - response = await facilitator.list_resources(type="http") + # List HTTP services; use type="mcp" to list MCP tools instead + response = client.extensions.bazaar.list_resources( + ListDiscoveryResourcesParams(type="http") + ) # Filter services under $0.10 usdc_asset = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" @@ -236,12 +254,67 @@ Fetch the list of available x402 services using the facilitator client: item for item in response.items if any( - payment_req.asset == usdc_asset - and int(payment_req.max_amount_required) < max_price - for payment_req in item.accepts + payment_req.get("asset") == usdc_asset + and int(payment_req.get("amount", 0)) < max_price + for payment_req in (item.accepts or []) ) ] ``` + + + + +#### Step 1b: Search for Services + +You can also search for services using a natural-language query. Pagination is facilitator-defined: some facilitators may include top-level `limit` and `cursor`, and others may omit them. + + + + ```typescript + const results = await client.extensions.bazaar.search({ + query: "weather APIs", + type: "http", + }); + + // Some facilitators return a pagination object like the list endpoint + if (results.pagination) { + console.log("Next page cursor:", results.pagination.cursor); + } + + console.log(`Found ${results.resources.length} services`); + ``` + + + + ```go + results, err := client.SearchDiscoveryResources(ctx, &bazaar.SearchDiscoveryResourcesParams{ + Query: "weather APIs", + Type: "http", + }) + if err != nil { + panic(err) + } + + fmt.Printf("Found %d services\n", len(results.Resources)) + if results.Pagination != nil { + fmt.Println("Next cursor:", results.Pagination.Cursor) + } + ``` + + + + ```python + from x402.extensions.bazaar import SearchDiscoveryResourcesParams + + results = client.extensions.bazaar.search( + SearchDiscoveryResourcesParams(query="weather APIs", type="http") + ) + + print(f"Found {len(results.resources)} services") + if results.pagination is not None: + print(f"Next cursor: {results.pagination.cursor}") + ``` + @@ -271,15 +344,17 @@ Once you've found a suitable service, use an x402 client to call it: client ); - // Select the payment method of your choice - const selectedPaymentRequirements = selectedService.accepts[0]; - const inputSchema = selectedPaymentRequirements.outputSchema.input; + // Read the Bazaar call metadata for the selected service + const bazaar = selectedService.extensions?.bazaar as { + info?: { input?: { method?: string; queryParams?: Record } } + } | undefined; + const input = bazaar?.info?.input; // Build the request using the service's schema const response = await api.request({ - method: inputSchema.method, - url: inputSchema.resource, - params: { location: "San Francisco" } // Based on inputSchema + method: input?.method ?? "GET", + url: selectedService.resource, + params: input?.queryParams ?? { city: "San Francisco" } }); console.log("Response data:", response.data); @@ -305,16 +380,16 @@ Once you've found a suitable service, use an x402 client to call it: # Select a service from discovery (from Step 1) selected_service = affordable_services[0] - # Select the payment method of your choice - selected_payment_requirements = selected_service.accepts[0] - input_schema = selected_payment_requirements.output_schema.input + # Read the Bazaar call metadata for the selected service + bazaar = (selected_service.extensions or {}).get("bazaar", {}) + input_info = bazaar.get("info", {}).get("input", {}) # Make the request using httpx client async with x402HttpxClient(client) as http: response = await http.request( - method=input_schema.method, - url=input_schema.resource, - params={"location": "San Francisco"} # Based on input_schema + method=input_info.get("method", "GET"), + url=selected_service.resource, + params=input_info.get("queryParams", {"city": "San Francisco"}) ) await response.aread() print(f"Response data: {response.json()}") @@ -325,6 +400,49 @@ Once you've found a suitable service, use an x402 client to call it: +#### Step 2 (MCP tools): Call a Discovered MCP Tool + +For discovered MCP tools, use the x402 MCP client to call the tool after paying: + + + + ```typescript + import { createx402MCPClient } from "@x402/mcp"; + import { ExactEvmScheme } from "@x402/evm/exact/client"; + import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; + import { privateKeyToAccount } from "viem/accounts"; + + const account = privateKeyToAccount("0xYourPrivateKey"); + + // Discover MCP tools from the Bazaar + const mcpItems = await client.extensions.bazaar.listResources({ type: "mcp" }); + const selectedTool = mcpItems.items[0]; + const bazaar = selectedTool.extensions?.bazaar as { + info?: { input?: { toolName?: string } } + } | undefined; + const toolName = bazaar?.info?.input?.toolName; + if (!toolName) throw new Error("Selected MCP resource is missing a toolName"); + + // Connect the x402 MCP client to the tool's server + const x402Mcp = createx402MCPClient({ + name: "my-mcp-client", + schemes: [{ network: "eip155:8453", scheme: new ExactEvmScheme(account) }], + }); + + // selectedTool.resource is an identifier like mcp://tool/get_weather, not a transport URL + const mcpServerUrl = "https://your-mcp-server.example.com"; + const transport = new SSEClientTransport(new URL(`${mcpServerUrl}/sse`)); + await x402Mcp.connect(transport); + + // Call the paid tool — x402Mcp handles payment automatically + const result = await x402Mcp.callTool(toolName, { city: "San Francisco" }); + console.log("Tool result:", result); + + await x402Mcp.close(); + ``` + + + ### Quickstart for Sellers #### Listing with Bazaar Extension @@ -347,6 +465,85 @@ This means `/users/123`, `/users/456`, and `/users/789` all map to the same cata **Note:** Wildcard segments (`*`) are automatically converted to named parameters (`:var1`, `:var2`, etc.) for catalog normalization. +#### Service Metadata + +Resource servers can publish provider-level metadata on the **`resource` object** of the 402 response. Facilitators use these fields to enrich Bazaar search results with a human-readable name, topical tags, and an icon — no out-of-band admin step required. + +All three fields are optional. Servers that omit them produce byte-identical 402 responses; clients that don't recognize them ignore them. + +| Field | Type | Description | +|-------|------|-------------| +| `serviceName` | string | Human-readable name for the service (≤ 32 printable ASCII characters). | +| `tags` | string[] | Up to 5 short topical tags (each ≤ 32 printable ASCII characters). Used for facilitator-side filtering and search. | +| `iconUrl` | string | Absolute `https://` or `http://` URL to an icon image representing the service (≤ 2048 characters). | + +These fields are set on the `resource` object in your route configuration, alongside `description` and `mimeType`: + + + + ```typescript + const routes = { + "GET /weather": { + price: "$0.001", + network: "eip155:8453", + payTo: "0xYourAddress", + resource: { + url: "https://api.example.com/weather", + description: "Get real-time weather data", + mimeType: "application/json", + serviceName: "Example Weather", + tags: ["weather", "forecast"], + iconUrl: "https://api.example.com/icon.png", + }, + extensions: { bazaar: { ... } }, + }, + }; + ``` + + + ```python + from x402.schemas.payments import ResourceInfo + + routes: dict[str, RouteConfig] = { + "GET /weather": RouteConfig( + accepts=[...], + resource=ResourceInfo( + url="https://api.example.com/weather", + description="Get real-time weather data", + mime_type="application/json", + service_name="Example Weather", + tags=["weather", "forecast"], + icon_url="https://api.example.com/icon.png", + ), + extensions={"bazaar": {...}}, + ), + } + ``` + + + ```go + routes := x402http.RoutesConfig{ + "GET /weather": { + Accepts: x402http.PaymentOptions{{...}}, + Resource: &types.ResourceInfo{ + URL: "https://api.example.com/weather", + Description: "Get real-time weather data", + MimeType: "application/json", + ServiceName: "Example Weather", + Tags: []string{"weather", "forecast"}, + IconURL: "https://api.example.com/icon.png", + }, + Extensions: map[string]interface{}{ + types.BAZAAR: discoveryExtension, + }, + }, + } + ``` + + + +**Validation rules:** Facilitators apply soft-drop rules — a field that fails validation is silently discarded while the rest of the metadata is preserved. `serviceName` and `tags` are restricted to printable ASCII (U+0020–U+007E) so that string-length checks are consistent across TypeScript, Python, and Go. `iconUrl` must be an absolute `http://` or `https://` URL with no IP literals or loopback hostnames (SSRF defense). + #### Adding Metadata To enhance your listing with descriptions and schemas, include them when setting up your x402 middleware. **You should include descriptions for each parameter to make it clear for agents to call your endpoints**: @@ -357,7 +554,7 @@ To enhance your listing with descriptions and schemas, include them when setting import { paymentMiddleware } from "@x402/express"; import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server"; import { ExactEvmScheme } from "@x402/evm/exact/server"; - import { bazaarResourceServerExtension } from "@x402/extensions"; + import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; const facilitatorClient = new HTTPFacilitatorClient({ url: "https://x402.org/facilitator" @@ -367,31 +564,44 @@ To enhance your listing with descriptions and schemas, include them when setting const routes = { "GET /weather": { - price: "$0.001", - network: "eip155:8453", - resource: "0xYourAddress", + accepts: { + scheme: "exact", + price: "$0.001", + network: "eip155:8453", + payTo: "0xYourAddress", + }, description: "Get current weather data for any location", + mimeType: "application/json", extensions: { - bazaar: { - discoverable: true, + ...declareDiscoveryExtension({ + input: { location: "San Francisco" }, inputSchema: { - queryParams: { + properties: { location: { type: "string", - description: "City name or coordinates", - required: true + description: "City name or coordinates" } - } + }, + required: ["location"] }, - outputSchema: { - type: "object", - properties: { - temperature: { type: "number" }, - conditions: { type: "string" }, - humidity: { type: "number" } + output: { + example: { + location: "San Francisco", + temperature: 70, + conditions: "sunny", + humidity: 45 + }, + schema: { + type: "object", + properties: { + location: { type: "string" }, + temperature: { type: "number" }, + conditions: { type: "string" }, + humidity: { type: "number" } + } } } - } + }) } } }; @@ -403,6 +613,7 @@ To enhance your listing with descriptions and schemas, include them when setting ```python from fastapi import FastAPI + from x402.extensions.bazaar import OutputConfig, declare_discovery_extension from x402.http import FacilitatorConfig, HTTPFacilitatorClient, PaymentOption from x402.http.middleware.fastapi import PaymentMiddlewareASGI from x402.http.types import RouteConfig @@ -411,7 +622,6 @@ To enhance your listing with descriptions and schemas, include them when setting app = FastAPI() - # Create facilitator client (CDP mainnet) facilitator = HTTPFacilitatorClient( FacilitatorConfig(url="https://x402.org/facilitator") ) @@ -433,28 +643,35 @@ To enhance your listing with descriptions and schemas, include them when setting ], mime_type="application/json", description="Get current weather data for any location", - extensions={ - "bazaar": { - "discoverable": True, - "inputSchema": { - "queryParams": { - "location": { - "type": "string", - "description": "City name or coordinates", - "required": True, - } + extensions=declare_discovery_extension( + input={"location": "San Francisco"}, + input_schema={ + "properties": { + "location": { + "type": "string", + "description": "City name or coordinates", } }, - "outputSchema": { + "required": ["location"], + }, + output=OutputConfig( + example={ + "location": "San Francisco", + "temperature": 70, + "conditions": "sunny", + "humidity": 45, + }, + schema={ "type": "object", "properties": { + "location": {"type": "string"}, "temperature": {"type": "number"}, "conditions": {"type": "string"}, "humidity": {"type": "number"}, }, }, - } - }, + ), + ), ), } @@ -466,12 +683,12 @@ To enhance your listing with descriptions and schemas, include them when setting package main import ( - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - "github.com/coinbase/x402/go/extensions/types" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + "github.com/x402-foundation/x402/go/extensions/types" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" "github.com/gin-gonic/gin" ) @@ -497,8 +714,16 @@ To enhance your listing with descriptions and schemas, include them when setting }, "", &types.OutputConfig{ + Example: map[string]interface{}{ + "location": "San Francisco", + "temperature": 70, + "conditions": "sunny", + "humidity": 45, + }, Schema: types.JSONSchema{ + "type": "object", "properties": map[string]interface{}{ + "location": map[string]interface{}{"type": "string"}, "temperature": map[string]interface{}{"type": "number"}, "conditions": map[string]interface{}{"type": "string"}, "humidity": map[string]interface{}{"type": "number"}, @@ -547,13 +772,114 @@ To enhance your listing with descriptions and schemas, include them when setting -### Coming Soon +#### Adding Metadata for MCP Tools + +To make paid MCP tools discoverable, pass the discovery extension in your payment wrapper config: + + + + ```typescript + import { createPaymentWrapper } from "@x402/mcp"; + import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; + + const paid = createPaymentWrapper(resourceServer, { + accepts, + resource: { + url: "mcp://tool/get_weather", + description: "Get current weather for a city", + }, + extensions: declareDiscoveryExtension({ + toolName: "get_weather", + description: "Get current weather for a city", + transport: "sse", + inputSchema: { + properties: { city: { type: "string", description: "City name" } }, + required: ["city"], + }, + example: { city: "San Francisco" }, + }), + }); + + mcpServer.tool("get_weather", "Get current weather ($0.001)", { city: z.string() }, + paid(async ({ city }) => ({ content: [{ type: "text", text: JSON.stringify(await fetchWeather(city)) }] })) + ); + ``` + + + ```python + from x402.mcp import create_payment_wrapper + from x402.extensions.bazaar import DeclareMcpDiscoveryConfig, declare_mcp_discovery_extension + + weather_discovery = declare_mcp_discovery_extension( + DeclareMcpDiscoveryConfig( + tool_name="get_weather", + description="Get current weather for a city", + transport="sse", + input_schema={ + "properties": {"city": {"type": "string", "description": "City name"}}, + "required": ["city"], + }, + example={"city": "San Francisco"}, + ) + ) + + weather_wrapper = create_payment_wrapper( + resource_server, + accepts=weather_accepts, + resource=ResourceInfo( + url="mcp://tool/get_weather", + description="Get current weather for a city", + ), + extensions=weather_discovery, + ) -The x402 Bazaar is rapidly evolving, and your feedback helps us prioritize features. + @mcp.tool(name="get_weather", description="Get current weather ($0.001)") + @weather_wrapper + async def get_weather(city: str) -> str: + return json.dumps(await fetch_weather(city)) + ``` + + + ```go + import ( + "github.com/x402-foundation/x402/go/extensions/bazaar" + mcp402 "github.com/x402-foundation/x402/go/mcp" + "github.com/x402-foundation/x402/go/types" + ) + + weatherDiscovery, _ := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "get_weather", + Description: "Get current weather for a city", + Transport: bazaar.TransportSSE, + InputSchema: bazaar.JSONSchema{ + "properties": map[string]interface{}{ + "city": map[string]interface{}{ + "type": "string", + "description": "City name", + }, + }, + "required": []string{"city"}, + }, + Example: map[string]interface{}{"city": "San Francisco"}, + }) + + paymentWrapper := mcp402.NewPaymentWrapper(resourceServer, mcp402.PaymentWrapperConfig{ + Accepts: weatherAccepts, + Resource: &types.ResourceInfo{ + URL: "mcp://tool/get_weather", + Description: "Get current weather for a city", + }, + Extensions: map[string]interface{}{ + bazaar.BAZAAR.Key(): weatherDiscovery, + }, + }) + ``` + + ### Support -* **GitHub**: [github.com/coinbase/x402](https://github.com/coinbase/x402) +* **GitHub**: [github.com/x402-foundation/x402](https://github.com/x402-foundation/x402) * **Discord**: [Join #x402 channel](https://discord.com/invite/cdp) ### FAQ @@ -574,4 +900,4 @@ A: Currently Base (`eip155:8453`), Base Sepolia (`eip155:84532`), Solana (`solan A: No, only x402-compatible endpoints can be listed. See our [Quickstart for Sellers](/getting-started/quickstart-for-sellers) to make your API x402-compatible. **Q: What are MCP tools and how do they work with Bazaar?** -A: MCP (Model Context Protocol) tools are AI-agent-friendly interfaces that can be discovered and paid for through x402. When listing an MCP tool, include `type: "mcp"` in the bazaar extension along with the tool name and input schema. The unique identifier for MCP tools is the combination of the resource URL and tool name, since multiple tools can be served from a single MCP endpoint. +A: MCP (Model Context Protocol) tools are AI-agent-friendly interfaces that can be discovered and paid for through x402. When listing an MCP tool, use the MCP Bazaar discovery helper and include the tool name (`toolName`) and input schema. The unique identifier for MCP tools is the combination of the resource URL and tool name, since multiple tools can be served from a single MCP endpoint. diff --git a/docs/extensions/eip2612-gas-sponsoring.mdx b/docs/extensions/eip2612-gas-sponsoring.mdx index 7d90ad8a9d..3b4390c764 100644 --- a/docs/extensions/eip2612-gas-sponsoring.mdx +++ b/docs/extensions/eip2612-gas-sponsoring.mdx @@ -1,6 +1,6 @@ --- title: "EIP-2612 Gas Sponsoring" -description: "Gasless Permit2 approval for ERC-20 tokens that implement EIP-2612. The facilitator submits the permit on-chain, so the client never pays gas for the approval step." +description: "Gasless Permit2 approval for ERC-20 tokens that implement EIP-2612. The facilitator submits the permit onchain, so the client never pays gas for the approval step." --- The EIP-2612 gas sponsoring extension enables gasless Permit2 approval for tokens that implement the [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) `permit()` function (e.g., USDC). The client signs an off-chain permit authorizing the Permit2 contract, and the facilitator submits it atomically during settlement via `x402ExactPermit2Proxy.settleWithPermit`. @@ -47,7 +47,7 @@ Advertise support for this extension in your route configuration: ```go import ( - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" ) extensions := eip2612gassponsor.DeclareEip2612GasSponsoringExtension() @@ -97,7 +97,7 @@ The `ExactEvmScheme` handles EIP-2612 gas sponsoring automatically. When the ser ```go import ( - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" ) scheme := evm.NewExactEvmScheme(signer) diff --git a/docs/extensions/erc20-approval-gas-sponsoring.mdx b/docs/extensions/erc20-approval-gas-sponsoring.mdx index 63ddbfadcd..8666d8b7ca 100644 --- a/docs/extensions/erc20-approval-gas-sponsoring.mdx +++ b/docs/extensions/erc20-approval-gas-sponsoring.mdx @@ -52,7 +52,7 @@ Advertise support for this extension in your route configuration: ```go import ( - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" ) extensions := erc20approvalgassponsor.DeclareExtension() @@ -105,7 +105,7 @@ The `ExactEvmScheme` handles ERC-20 approval gas sponsoring automatically as a f ```go import ( - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" ) scheme := evm.NewExactEvmScheme(signer) diff --git a/docs/extensions/offer-receipt.mdx b/docs/extensions/offer-receipt.mdx index b7d116e837..11167f9b29 100644 --- a/docs/extensions/offer-receipt.mdx +++ b/docs/extensions/offer-receipt.mdx @@ -9,7 +9,7 @@ The Offer & Receipt extension adds cryptographic proof-of-interaction to x402 pa Signed offers and receipts are portable, verifiable artifacts that any third party can check. They enable: -* **Reputation systems** — Clients can attach receipts to on-chain attestations as proof they actually paid for and received a service. This is the "Verified Purchase" equivalent for the open web. +* **Reputation systems** — Clients can attach receipts to onchain attestations as proof they actually paid for and received a service. This is the "Verified Purchase" equivalent for the open web. * **Dispute resolution** — Offers prove the server committed to specific terms; receipts prove delivery. If either party disputes a transaction, the signed artifacts provide evidence. * **Auditing** — Receipts create a verifiable trail of service delivery without exposing transaction details (the transaction hash is optional). * **Client confidence** — Services with verifiable proof-of-interaction build stronger trust signals, making new clients more likely to use the service. @@ -331,7 +331,7 @@ This is a W3C standard mechanism and is sufficient for many use cases. However, ### Additional Binding Mechanisms -For production services that need stronger guarantees — immutable on-chain attestations, DNS-based verification, temporal anchoring, or key lifecycle management (expiration, rotation, revocation) — ecosystem partners offer additional trust layers on top of `did.json`. See the [Infrastructure & Tooling category](https://www.x402.org/ecosystem?filter=ecosystem-infrastructure) on the ecosystem page for reputation and identity services that integrate with the offer-receipt extension. +For production services that need stronger guarantees — immutable onchain attestations, DNS-based verification, temporal anchoring, or key lifecycle management (expiration, rotation, revocation) — ecosystem partners offer additional trust layers on top of `did.json`. See the [Infrastructure & Tooling category](https://www.x402.org/ecosystem?filter=ecosystem-infrastructure) on the ecosystem page for reputation and identity services that integrate with the offer-receipt extension. ## Client-Side: Extracting Offers and Receipts @@ -413,12 +413,12 @@ Ecosystem partners (see the [Infrastructure & Tooling category](https://www.x402 Complete working examples are available in the x402 repository: -- [Server Example (Express.js)](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/offer-receipt) — Resource server with offer-receipt enabled, showing both EIP-712 and JWS configurations -- [Client Example](https://github.com/coinbase/x402/tree/main/examples/typescript/clients/offer-receipt) — Complete client flow: offer extraction, payment, receipt capture, and verification +- [Server Example (Express.js)](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/offer-receipt) — Resource server with offer-receipt enabled, showing both EIP-712 and JWS configurations +- [Client Example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/offer-receipt) — Complete client flow: offer extraction, payment, receipt capture, and verification ## Further Reading - [Extensions Overview](./overview) — How the x402 extension system works -- [Offer & Receipt Extension Specification](https://github.com/coinbase/x402/blob/main/specs/extensions/extension-offer-and-receipt.md) — Full protocol spec with payload schemas, EIP-712 types, verification rules, and wire format examples -- [@x402/extensions package](https://github.com/coinbase/x402/tree/main/typescript/packages/extensions/src/offer-receipt) — TypeScript implementation source +- [Offer & Receipt Extension Specification](https://github.com/x402-foundation/x402/blob/main/specs/extensions/extension-offer-and-receipt.md) — Full protocol spec with payload schemas, EIP-712 types, verification rules, and wire format examples +- [@x402/extensions package](https://github.com/x402-foundation/x402/tree/main/typescript/packages/extensions/src/offer-receipt) — TypeScript implementation source - [SDK Features](/sdk-features) — Extension support across TypeScript, Go, and Python diff --git a/docs/extensions/overview.mdx b/docs/extensions/overview.mdx index a6f7ea9454..e4d53fe1cd 100644 --- a/docs/extensions/overview.mdx +++ b/docs/extensions/overview.mdx @@ -11,13 +11,14 @@ x402 has two extension points that serve different roles in the payment flow: ### Resource Server Extensions -These run on the resource server (the service accepting payments) and hook into the HTTP payment lifecycle. A `ResourceServerExtension` can intervene at three points: +These run on the resource server (the service accepting payments) and hook into the HTTP payment lifecycle. A `ResourceServerExtension` can intervene at four points: 1. **Declaration** (`enrichDeclaration`) — Called at route registration time. The extension can modify or narrow the route's extension declaration based on transport context (e.g., Bazaar narrows the HTTP method). 2. **402 Response** (`enrichPaymentRequiredResponse`) — Called when the server returns `402 Payment Required`. The extension can add data to the response (e.g., signed offers, discovery metadata). 3. **Settlement Response** (`enrichSettlementResponse`) — Called after successful payment. The extension can add data to the `PAYMENT-RESPONSE` header (e.g., signed receipts, payment identifiers). +4. **Verify/settle lifecycle hooks** (`hooks`) — Scoped verify and settle hooks that run only when the extension is declared on the route. These follow the same pattern as the server-level hooks (`onBeforeVerify`, `onAfterVerify`, `onVerifyFailure`, `onBeforeSettle`, `onAfterSettle`, `onSettleFailure`) but receive the extension's declaration as a first argument. -All three hooks are optional. Most extensions use one or two — not all three. +All four points are optional. Most extensions use one or two — not all. ### Facilitator Extensions @@ -59,6 +60,21 @@ interface ResourceServerExtension { declaration: unknown, context: SettleResultContext, ) => Promise; + + /** + * Verify/settle lifecycle hooks scoped to this extension. + * These run only when the extension is declared on the route (i.e. declaredExtensions[key] is set). + * The extension's declaration is passed as the first argument to each hook. + * Hook contexts are read-only for core protocol fields; use abort/recover return values instead of mutation. + */ + hooks?: { + onBeforeVerify?: (declaration: unknown, context: VerifyContext) => Promise; + onAfterVerify?: (declaration: unknown, context: VerifyResultContext) => Promise; + onVerifyFailure?: (declaration: unknown, context: VerifyFailureContext) => Promise; + onBeforeSettle?: (declaration: unknown, context: SettleContext) => Promise; + onAfterSettle?: (declaration: unknown, context: SettleResultContext) => Promise; + onSettleFailure?: (declaration: unknown, context: SettleFailureContext) => Promise; + }; } ``` @@ -121,10 +137,10 @@ To create your own extension: 1. **Define the extension object** implementing `ResourceServerExtension` 2. **Choose a unique key** — this identifies your extension in route declarations and response payloads -3. **Implement the hooks you need** — `enrichDeclaration`, `enrichPaymentRequiredResponse`, `enrichSettlementResponse` +3. **Implement the hooks you need** — `enrichDeclaration`, `enrichPaymentRequiredResponse`, `enrichSettlementResponse`, and/or `hooks` 4. **Create a declare function** — a helper that returns the route-level configuration for your extension 5. **Register it** on the `x402ResourceServer` via `registerExtension` -6. **Submit a pull request** to [coinbase/x402](https://github.com/coinbase/x402) — extensions must be reviewed and approved by the x402 maintainers before they are included in the SDK +6. **Submit a pull request** to [x402-foundation/x402](https://github.com/x402-foundation/x402) — extensions must be reviewed and approved by the x402 maintainers before they are included in the SDK Here's a minimal example: @@ -143,6 +159,19 @@ const myExtension: ResourceServerExtension = { // Add custom data after successful payment return { settled: true, processedAt: Date.now() }; }, + + hooks: { + // Runs only when this extension is declared on the route + onAfterSettle: async (declaration, context) => { + // declaration is the per-route config for this extension + // context.result, context.requirements, etc. are read-only + await auditLog.record({ + extensionConfig: declaration, + payer: context.result.payer, + transaction: context.result.transaction, + }); + }, + }, }; // Declare helper for route config @@ -151,10 +180,10 @@ function declareMyExtension(config: { customOption: boolean }) { } ``` -The data returned from each hook is included in the response under `extensions["my-extension"]`. +The data returned from `enrichPaymentRequiredResponse` and `enrichSettlementResponse` is included in the response under `extensions["my-extension"]`. The `hooks` callbacks run as part of the server's verify/settle lifecycle but only when the extension is active on the route. ## Further Reading - [x402 SDK Features](/sdk-features) — Extension support across TypeScript, Go, and Python -- [Extension Specs](https://github.com/coinbase/x402/tree/main/specs/extensions) — Protocol-level extension specifications -- [@x402/extensions package](https://github.com/coinbase/x402/tree/main/typescript/packages/extensions) — TypeScript implementation source +- [Extension Specs](https://github.com/x402-foundation/x402/tree/main/specs/extensions) — Protocol-level extension specifications +- [@x402/extensions package](https://github.com/x402-foundation/x402/tree/main/typescript/packages/extensions) — TypeScript implementation source diff --git a/docs/extensions/payment-identifier.mdx b/docs/extensions/payment-identifier.mdx index e5ea85f00e..b62ef06188 100644 --- a/docs/extensions/payment-identifier.mdx +++ b/docs/extensions/payment-identifier.mdx @@ -135,7 +135,7 @@ async with x402HttpxClient(client) as http: Use the `GeneratePaymentID()` utility to create a unique identifier: ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" // Generate with default prefix "pay_" paymentID := paymentidentifier.GeneratePaymentID("") @@ -152,8 +152,8 @@ Hook into the payment flow to add the payment ID before payload creation: ```go import ( - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/paymentidentifier" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/paymentidentifier" ) client := x402.Newx402Client() @@ -412,8 +412,8 @@ Declare the payment-identifier extension in your route configuration: ```go import ( - x402http "github.com/coinbase/x402/go/http" - "github.com/coinbase/x402/go/extensions/paymentidentifier" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/extensions/paymentidentifier" ) // Optional or required payment identifier (pick one) @@ -442,7 +442,7 @@ routes := x402http.RoutesConfig{ Use the `ExtractPaymentIdentifier()` utility to get the payment ID from the payload: ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" // In your handler payload := c.MustGet("x402_payload").(x402.PaymentPayload) @@ -705,7 +705,7 @@ from x402.extensions.payment_identifier import ( Generates a cryptographically secure unique payment identifier. ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" // Generate with default prefix "pay_" paymentID := paymentidentifier.GeneratePaymentID("") @@ -721,7 +721,7 @@ paymentID = paymentidentifier.GeneratePaymentID("order_") Adds a payment identifier to the extensions object. Only modifies extensions if the server declared support for the extension. Pass an empty string to auto-generate an ID. ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" extensions := make(map[string]interface{}) err := paymentidentifier.AppendPaymentIdentifierToExtensions(extensions, "pay_custom_id_1234567890abcdef") @@ -733,7 +733,7 @@ err := paymentidentifier.AppendPaymentIdentifierToExtensions(extensions, "pay_cu Validates a payment identifier format. ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" valid := paymentidentifier.IsValidPaymentID("pay_7d5d747be160e280504c099d984bcfe0") // true valid = paymentidentifier.IsValidPaymentID("invalid") // false (too short) @@ -746,7 +746,7 @@ valid = paymentidentifier.IsValidPaymentID("invalid") // false (too short) Creates a payment-identifier extension declaration for resource servers. ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" // Optional payment ID extension := paymentidentifier.DeclarePaymentIdentifierExtension(false) @@ -760,7 +760,7 @@ extensionRequired := paymentidentifier.DeclarePaymentIdentifierExtension(true) Extracts the payment identifier from a payment payload. ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" paymentID, err := paymentidentifier.ExtractPaymentIdentifier(payload, true) if err != nil { @@ -776,7 +776,7 @@ if paymentID != "" { Validates the payment identifier extension object structure and ID format. ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" extension := payload.Extensions[paymentidentifier.PAYMENT_IDENTIFIER] result := paymentidentifier.ValidatePaymentIdentifier(extension) @@ -789,7 +789,7 @@ if !result.Valid { ### Constants ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" const ( PAYMENT_IDENTIFIER = "payment-identifier" @@ -808,16 +808,16 @@ var PAYMENT_ID_PATTERN = regexp.MustCompile(`^[a-zA-Z0-9_-]+$`) Full working examples are available in the x402 repository: **TypeScript:** -- [TypeScript Client Example](https://github.com/coinbase/x402/tree/main/examples/typescript/clients/payment-identifier) -- [TypeScript Server Example](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/payment-identifier) +- [TypeScript Client Example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/payment-identifier) +- [TypeScript Server Example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/payment-identifier) **Python:** -- [Python Client Example](https://github.com/coinbase/x402/tree/main/examples/python/clients/payment-identifier) -- [Python Server Example](https://github.com/coinbase/x402/tree/main/examples/python/servers/payment-identifier) +- [Python Client Example](https://github.com/x402-foundation/x402/tree/main/examples/python/clients/payment-identifier) +- [Python Server Example](https://github.com/x402-foundation/x402/tree/main/examples/python/servers/payment-identifier) **Go:** -- [Go Client Example](https://github.com/coinbase/x402/tree/main/examples/go/clients/payment-identifier) -- [Go Server Example](https://github.com/coinbase/x402/tree/main/examples/go/servers/payment-identifier) +- [Go Client Example](https://github.com/x402-foundation/x402/tree/main/examples/go/clients/payment-identifier) +- [Go Server Example](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/payment-identifier) ## FAQ diff --git a/docs/extensions/sign-in-with-x.mdx b/docs/extensions/sign-in-with-x.mdx index 0344207164..01957a43e9 100644 --- a/docs/extensions/sign-in-with-x.mdx +++ b/docs/extensions/sign-in-with-x.mdx @@ -437,5 +437,5 @@ The package includes `InMemorySIWxStorage` for development. For production, impl - [CAIP-122 Specification](https://chainagnostic.org/CAIPs/caip-122) - Sign-In-With-X standard - [EIP-4361 (SIWE)](https://eips.ethereum.org/EIPS/eip-4361) - Sign-In With Ethereum - [Sign-In With Solana](https://github.com/phantom/sign-in-with-solana) -- [x402 Core Package](https://github.com/coinbase/x402/tree/main/typescript/packages/core) +- [x402 Core Package](https://github.com/x402-foundation/x402/tree/main/typescript/packages/core) - [Lifecycle Hooks](/advanced-concepts/lifecycle-hooks) - Custom payment flow logic diff --git a/docs/faq.md b/docs/faq.md index 83c80990f8..b943df5e8c 100644 --- a/docs/faq.md +++ b/docs/faq.md @@ -6,16 +6,15 @@ title: "FAQ" #### What _is_ x402 in a single sentence? -x402 is an open‑source protocol that turns the dormant HTTP `402 Payment Required` status code into a fully‑featured, on‑chain payment layer for APIs, websites, and autonomous agents. +x402 is an open‑source protocol that turns the dormant HTTP `402 Payment Required` status code into a fully‑featured, onchain payment layer for APIs, websites, and autonomous agents. **Is x402 a CDP Product?** -_No._ While Coinbase Developer Platform provides tooling and are the creators of the standard, it is an open protocol (Apache-2.0 license) and you don't need any Coinbase products to use it. We look forward to further clarifying this distinction and making x402 a credibly neutral payment standard. +_No._ While Coinbase Developer Platform provides tooling and are the creators of the standard, it is an open protocol (Apache-2.0 license) and a credibly neutral payment standard, and you don't need any Coinbase products to use it. -#### Why not use traditional payment rails or API keys? +#### Why not just use API keys? -Traditional rails require credit‑card networks, user accounts, and multi‑step UI flows.\ -x402 removes those dependencies, enabling programmatic, HTTP-native payments (perfect for AI agents) while dropping fees to near‑zero and settling in \~1 second. +API key registration requires multi-step UI flows to set up accounts, add payment methods, and plug API keys into your agent. x402 removes those dependencies, enabling programmatic, HTTP-native payments (perfect for AI agents) while dropping fees to near‑zero and settling in ~1 second. #### Is x402 only for crypto‑native projects? @@ -27,7 +26,7 @@ No. Any web API or content provider—crypto or web2—can integrate x402 if it Typescript, Python, and Go are reference implementations, but x402 is an **open protocol**. -Nothing prevents you from implementing the spec in Rust, Java, or other languages. If you're interested in building support for your favorite language, please [open an issue](https://github.com/coinbase/x402/issues) and let us know, we'd be happy to help! +Nothing prevents you from implementing the spec in Rust, Java, or other languages. If you're interested in building support for your favorite language, please [open an issue](https://github.com/x402-foundation/x402/issues) and let us know, we'd be happy to help! ### Facilitators @@ -40,7 +39,7 @@ Multiple organizations operate production facilitators. The protocol is **permis #### What stops a malicious facilitator from stealing funds or lying about settlement? -Every x402 `PaymentPayload` is **signed by the buyer** and settled **directly on‑chain**.\ +Every x402 `PaymentPayload` is **signed by the buyer** and settled **directly onchain**.\ A facilitator that tampers with the transaction would fail signature checks and would **not be able to** settle the transaction. ### Pricing & Schemes @@ -51,7 +50,8 @@ There is no single answer, but common patterns are: * **Flat per‑call** (e.g., `$0.001` per request) * **Tiered** (`/basic` vs `/pro` endpoints with different prices) -* **Up‑to** (work in progress): "pay‑up‑to" where the final cost equals usage (tokens, MB, etc.) +* **Up‑to** (`scheme: "upto"`): The client authorizes a maximum amount but is only charged for actual usage (tokens, compute time, bandwidth, etc.). Available on EVM networks in TypeScript, Go, and Python. See the [Seller Quickstart](/getting-started/quickstart-for-sellers#payment-schemes-exact-upto-and-batch-settlement) for setup. +* **Batch settlement** (`scheme: "batch-settlement"`): For many small payments on EVM, the buyer deposits into escrow once and pays with off-chain vouchers; settlement is batched onchain. Still uses a per-request maximum; actual charges can vary within that limit. TypeScript and Go SDKs today; Python planned. See [Batch settlement](/schemes/batch-settlement). #### Can I integrate x402 with a usage / plan manager like Metronome? @@ -68,7 +68,7 @@ Yes. x402 handles the _payment execution_. You can still meter usage, aggregate | Solana | `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` | Any SPL token or Token-2022 token | fee-free | **Mainnet** | | Solana Devnet | `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` | Any SPL token or Token-2022 | fee-free | **Testnet** | -\* Gas paid on chain; many facilitators offer **zero** facilitator fees (see [ecosystem](https://www.x402.org/ecosystem?filter=facilitators) for details). +\* Gas paid onchain; many facilitators offer **zero** facilitator fees (see [ecosystem](https://www.x402.org/ecosystem?filter=facilitators) for details). _Support for additional chains and assets is on the roadmap and community‑driven._ @@ -87,10 +87,10 @@ No. The recommended pattern is: #### How do refunds work? -The current `exact` scheme is a _push payment_—irreversible once executed. Two options: +The **`exact`** scheme is a _push payment_—irreversible once executed. Options: -1. **Business‑logic refunds:** Seller sends a new USDC transfer back to the buyer. -2. **Escrow schemes:** Future spec could add conditional transfers (e.g., HTLCs or hold invoices). +1. **Business‑logic refunds:** Seller sends a new token transfer back to the buyer. +2. **`batch-settlement` on EVM:** Cooperative refunds and timed withdrawals from channel escrow are defined in the scheme—see [Batch settlement](/schemes/batch-settlement). ### Usage by AI Agents @@ -111,21 +111,9 @@ Yes. Programmatic wallets (e.g., **CDP Wallet API**, **viem**, **ethers‑v6** H #### Is there a formal spec or whitepaper? -* **Spec:** [GitHub Specification](https://github.com/coinbase/x402/tree/main/specs) +* **Spec:** [GitHub Specification](https://github.com/x402-foundation/x402/tree/main/specs) * [**Whitepaper**](https://www.x402.org/x402-whitepaper.pdf) -#### How will x402 evolve? - -Tracked in public GitHub issues + community RFCs. Major themes: - -* Multi‑asset support -* Additional schemes (`upto`, `stream`) -* Discovery layer for service search & reputation - -**Why is x402 hosted in the Coinbase GitHub?** - -We acknowledge that the repo is primarily under Coinbase ownership today. This is primarily to leverage our best-in-house security and auditing team to ensure the spec is safe and nobody accidentally creates legally ambiguous payment flows. We intend to eventually transfer ownership of the repo to a steering group or open-source committee. - ### Troubleshooting #### I keep getting `402 Payment Required`, even after attaching `PAYMENT-SIGNATURE`. Why? @@ -143,5 +131,4 @@ We acknowledge that the repo is primarily under Coinbase ownership today. This i ### Still have questions? -• Reach out in the [Discord channel](https://discord.gg/invite/cdp)\ -• Open a GitHub Discussion or Issue in the [x402 repo](https://github.com/coinbase/x402) +• Open a GitHub Discussion or Issue in the [x402 repo](https://github.com/x402-foundation/x402) diff --git a/docs/getting-started/quickstart-for-buyers.mdx b/docs/getting-started/quickstart-for-buyers.mdx index 003524dc8a..600368023d 100644 --- a/docs/getting-started/quickstart-for-buyers.mdx +++ b/docs/getting-started/quickstart-for-buyers.mdx @@ -12,7 +12,7 @@ Before you begin, ensure you have: * A service that requires payment via x402 **Note**\ -There are pre-configured [examples available in the x402 repo](https://github.com/coinbase/x402/tree/main/examples), including examples for [fetch](https://github.com/coinbase/x402/tree/main/examples/typescript/clients/fetch), [Axios](https://github.com/coinbase/x402/tree/main/examples/typescript/clients/axios), [Go](https://github.com/coinbase/x402/tree/main/examples/go/clients), and [MCP](https://github.com/coinbase/x402/tree/main/examples/typescript/clients/mcp). +There are pre-configured [examples available in the x402 repo](https://github.com/x402-foundation/x402/tree/main/examples), including examples for [fetch](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch), [Axios](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/axios), [Go](https://github.com/x402-foundation/x402/tree/main/examples/go/clients), and [MCP](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/mcp). ### 1. Install Dependencies @@ -30,6 +30,9 @@ There are pre-configured [examples available in the x402 repo](https://github.co # For Solana support, also add: npm install @x402/svm + # For Algorand support, also add: + npm install @x402/avm + # For Aptos support, also add: npm install @x402/aptos @@ -41,7 +44,7 @@ There are pre-configured [examples available in the x402 repo](https://github.co Add the x402 Go module to your project: ```bash - go get github.com/coinbase/x402/go + go get github.com/x402-foundation/x402/go ``` @@ -82,7 +85,7 @@ There are pre-configured [examples available in the x402 repo](https://github.co ```go import ( - evmsigners "github.com/coinbase/x402/go/signers/evm" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) // Load private key from environment @@ -138,6 +141,17 @@ const privateKey = new Ed25519PrivateKey(process.env.APTOS_PRIVATE_KEY!); const aptosSigner = Account.fromPrivateKey({ privateKey }); ``` +#### Algorand (AVM) + +Use the `@x402/avm` package to instantiate a signer: + +```typescript +import { toClientAvmSigner } from "@x402/avm"; + +// Create signer from Base64-encoded private key (64-byte: seed + pubkey) +const avmSigner = toClientAvmSigner(process.env.AVM_PRIVATE_KEY!); +``` + #### Stellar Use the Stellar SDK to instantiate a signer: @@ -156,7 +170,7 @@ const stellarSigner = createEd25519Signer( - **@x402/fetch** extends the native `fetch` API to handle 402 responses and payment headers for you. [Full example here](https://github.com/coinbase/x402/tree/main/examples/typescript/clients/fetch) + **@x402/fetch** extends the native `fetch` API to handle 402 responses and payment headers for you. [Full example here](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch) ```typescript import { wrapFetchWithPayment } from "@x402/fetch"; @@ -193,7 +207,7 @@ const stellarSigner = createEd25519Signer( ``` - **@x402/axios** adds a payment interceptor to Axios, so your requests are retried with payment headers automatically. [Full example here](https://github.com/coinbase/x402/tree/main/examples/typescript/clients/axios) + **@x402/axios** adds a payment interceptor to Axios, so your requests are retried with payment headers automatically. [Full example here](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/axios) ```typescript import { x402Client, wrapAxiosWithPayment, x402HTTPClient } from "@x402/axios"; @@ -227,7 +241,7 @@ const stellarSigner = createEd25519Signer( ``` - [Full example here](https://github.com/coinbase/x402/tree/main/examples/go/clients/http) + [Full example here](https://github.com/x402-foundation/x402/tree/main/examples/go/clients/http) ```go package main @@ -240,10 +254,10 @@ const stellarSigner = createEd25519Signer( "os" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) func main() { @@ -290,7 +304,7 @@ const stellarSigner = createEd25519Signer( **httpx** provides async HTTP client support with automatic 402 payment handling. - [Full HTTPX example](https://github.com/coinbase/x402/tree/main/examples/python/clients/httpx) | [Full Requests example](https://github.com/coinbase/x402/tree/main/examples/python/clients/requests) + [Full HTTPX example](https://github.com/x402-foundation/x402/tree/main/examples/python/clients/httpx) | [Full Requests example](https://github.com/x402-foundation/x402/tree/main/examples/python/clients/requests) ```python import asyncio @@ -330,7 +344,7 @@ const stellarSigner = createEd25519Signer( **requests** provides sync HTTP client support with automatic 402 payment handling. - [Full Requests example](https://github.com/coinbase/x402/tree/main/examples/python/clients/requests) + [Full Requests example](https://github.com/x402-foundation/x402/tree/main/examples/python/clients/requests) ```python import os @@ -405,6 +419,12 @@ You can register multiple payment schemes to handle different networks: const aptosSigner = Account.fromPrivateKey({ privateKey: aptosPrivateKey }); client.register("aptos:*", new ExactAptosScheme(aptosSigner)); + // For Algorand support, also add: + import { ExactAvmScheme, toClientAvmSigner } from "@x402/avm"; + + const avmSigner = toClientAvmSigner(process.env.AVM_PRIVATE_KEY!); + client.register("algorand:*", new ExactAvmScheme(avmSigner)); + // For Stellar support, also add: import { ExactStellarScheme, createEd25519Signer } from "@x402/stellar"; @@ -418,12 +438,12 @@ You can register multiple payment schemes to handle different networks: ```go import ( - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" - svmsigners "github.com/coinbase/x402/go/signers/svm" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" + svmsigners "github.com/x402-foundation/x402/go/signers/svm" ) // Create signers @@ -480,6 +500,15 @@ You can register multiple payment schemes to handle different networks: +### Payment Schemes + +The examples above use the simplest fixed-price scheme. If a resource advertises a different scheme in its 402 response, register that scheme for the same network namespace: + +* [`exact`](/schemes/exact): fixed-price payments. +* [`upto`](/schemes/upto): usage-based payments where you authorize a maximum and the seller charges actual usage. +* [`batch-settlement`](/schemes/batch-settlement): high-volume payments where the client deposits into escrow, signs off-chain vouchers, and the seller claims value onchain in batches. + + ### 4. Discover Available Services (Optional) Instead of hardcoding endpoints, you can use the x402 Bazaar to dynamically discover available services. This is especially powerful for building autonomous agents. @@ -532,10 +561,10 @@ try { * Install x402 client packages (`@x402/fetch` or `@x402/axios`) and mechanism packages (`@x402/evm`, `@x402/svm`, `@x402/aptos`) * Create a wallet signer -* Create an `x402Client` and register payment schemes +* Create an `x402Client` and register payment schemes (`exact` for fixed-price, `upto` for usage-based billing, `batch-settlement` for batched EVM micropayments when the server advertises it) * Use the provided wrapper/interceptor to make paid API requests * (Optional) Use the x402 Bazaar to discover services dynamically -* Payment flows are handled automatically for you +* Payment flows are handled automatically for you -- including `upto` where you only pay the actual usage *** @@ -549,6 +578,6 @@ try { * [@x402/fetch on npm](https://www.npmjs.com/package/@x402/fetch) * [@x402/axios on npm](https://www.npmjs.com/package/@x402/axios) * [@x402/evm on npm](https://www.npmjs.com/package/@x402/evm) -* [x402 Go module](https://github.com/coinbase/x402/tree/main/go) +* [x402 Go module](https://github.com/x402-foundation/x402/tree/main/go) For questions or support, join our [Discord](https://discord.gg/cdp). diff --git a/docs/getting-started/quickstart-for-sellers.mdx b/docs/getting-started/quickstart-for-sellers.mdx index 789d6097e8..959a635f97 100644 --- a/docs/getting-started/quickstart-for-sellers.mdx +++ b/docs/getting-started/quickstart-for-sellers.mdx @@ -14,7 +14,7 @@ Before you begin, ensure you have: * An existing API or server **Note**\ -There are pre-configured examples available in the x402 repo for both [Node.js](https://github.com/coinbase/x402/tree/main/examples/typescript/servers) and [Go](https://github.com/coinbase/x402/tree/main/examples/go/servers). There is also an [advanced example](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/advanced) that shows how to use the x402 SDKs to build a more complex payment flow. +There are pre-configured examples available in the x402 repo for both [Node.js](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers) and [Go](https://github.com/x402-foundation/x402/tree/main/examples/go/servers). There is also an [advanced example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/advanced) that shows how to use the x402 SDKs to build a more complex payment flow. ### 1. Install Dependencies @@ -23,35 +23,42 @@ There are pre-configured examples available in the x402 repo for both [Node.js]( Install the [x402 Express middleware package](https://www.npmjs.com/package/@x402/express). ```bash - npm install @x402/express @x402/core @x402/evm @x402/svm + npm install @x402/express @x402/core @x402/evm @x402/svm @x402/avm ``` Install the [x402 Next.js middleware package](https://www.npmjs.com/package/@x402/next). ```bash - npm install @x402/next @x402/core @x402/evm @x402/svm + npm install @x402/next @x402/core @x402/evm @x402/svm @x402/avm ``` Install the [x402 Hono middleware package](https://www.npmjs.com/package/@x402/hono). ```bash - npm install @x402/hono @x402/core @x402/evm @x402/svm + npm install @x402/hono @x402/core @x402/evm @x402/svm @x402/avm ``` Install the [x402 Fastify middleware package](https://www.npmjs.com/package/@x402/fastify). ```bash - npm install @x402/fastify @x402/core @x402/evm @x402/svm + npm install @x402/fastify @x402/core @x402/evm @x402/svm @x402/avm ``` - + + Add the x402 Go module to your project: + + ```bash + go get github.com/x402-foundation/x402/go + ``` + + Add the x402 Go module to your project: ```bash - go get github.com/coinbase/x402/go + go get github.com/x402-foundation/x402/go ``` @@ -87,13 +94,14 @@ Integrate the payment middleware into your application. You will need to provide - Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/express). + Full example in the repo [here](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/express). ```typescript import express from "express"; import { paymentMiddleware, x402ResourceServer } from "@x402/express"; import { ExactEvmScheme } from "@x402/evm/exact/server"; import { ExactSvmScheme } from "@x402/svm/exact/server"; + import { ExactAvmScheme } from "@x402/avm/exact/server"; import { HTTPFacilitatorClient } from "@x402/core/server"; const app = express(); @@ -101,6 +109,7 @@ Integrate the payment middleware into your application. You will need to provide // Your receiving wallet addresses const evmAddress = "0xYourEvmAddress"; const svmAddress = "YourSolanaAddress"; + const avmAddress = "YourAlgorandAddress"; // Create facilitator client (testnet) const facilitatorClient = new HTTPFacilitatorClient({ @@ -124,6 +133,12 @@ Integrate the payment middleware into your application. You will need to provide network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", // Solana Devnet payTo: svmAddress, }, + { + scheme: "exact", + price: "$0.001", + network: "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=", // Algorand Testnet + payTo: avmAddress, + }, ], description: "Weather data", mimeType: "application/json", @@ -131,7 +146,8 @@ Integrate the payment middleware into your application. You will need to provide }, new x402ResourceServer(facilitatorClient) .register("eip155:84532", new ExactEvmScheme()) - .register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme()), + .register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme()) + .register("algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=", new ExactAvmScheme()), ), ); @@ -150,7 +166,7 @@ Integrate the payment middleware into your application. You will need to provide ``` - Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/typescript/fullstack/next). + Full example in the repo [here](https://github.com/x402-foundation/x402/tree/main/examples/typescript/fullstack/next). Next.js offers two approaches: `paymentProxy` for protecting page routes (or multiple routes at once), and `withX402` for wrapping individual API route handlers. The key difference is that `withX402` only settles payment after a successful response (status \< 400), making it the recommended approach for API routes. @@ -248,7 +264,7 @@ Integrate the payment middleware into your application. You will need to provide ``` - Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/hono). + Full example in the repo [here](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/hono). ```typescript import { Hono } from "hono"; @@ -307,7 +323,7 @@ Integrate the payment middleware into your application. You will need to provide ``` - Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/fastify). + Full example in the repo [here](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/fastify). ```typescript import Fastify from "fastify"; @@ -364,7 +380,7 @@ Integrate the payment middleware into your application. You will need to provide ``` - Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/go/servers/gin). + Full example in the repo [here](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/gin). ```go package main @@ -373,11 +389,11 @@ Integrate the payment middleware into your application. You will need to provide "net/http" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" "github.com/gin-gonic/gin" ) @@ -437,7 +453,7 @@ Integrate the payment middleware into your application. You will need to provide ``` - Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/go/servers/nethttp). + Full example in the repo [here](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/nethttp). ```go package main @@ -447,11 +463,11 @@ Integrate the payment middleware into your application. You will need to provide "net/http" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - nethttpmw "github.com/coinbase/x402/go/http/nethttp" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + nethttpmw "github.com/x402-foundation/x402/go/http/nethttp" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) func main() { @@ -515,8 +531,81 @@ Integrate the payment middleware into your application. You will need to provide } ``` + + Full example in the repo [here](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/echo). + + ```go + package main + + import ( + "net/http" + "time" + + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + echomw "github.com/x402-foundation/x402/go/http/echo" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" + "github.com/labstack/echo/v4" + ) + + func main() { + evmAddress := "0xYourEvmAddress" + svmAddress := "YourSolanaAddress" + evmNetwork := x402.Network("eip155:84532") // Base Sepolia + svmNetwork := x402.Network("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1") // Solana Devnet + + e := echo.New() + + // Create facilitator client + facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ + URL: "https://x402.org/facilitator", + }) + + // Apply x402 payment middleware + e.Use(echomw.X402Payment(echomw.Config{ + Routes: x402http.RoutesConfig{ + "GET /weather": { + Accepts: x402http.PaymentOptions{ + { + Scheme: "exact", + Price: "$0.001", + Network: "eip155:84532", + PayTo: evmAddress, + }, + { + Scheme: "exact", + Price: "$0.001", + Network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + PayTo: svmAddress, + }, + }, + Description: "Get weather data for a city", + MimeType: "application/json", + }, + }, + Facilitator: facilitatorClient, + Schemes: []echomw.SchemeConfig{ + {Network: evmNetwork, Server: evm.NewExactEvmScheme()}, + {Network: svmNetwork, Server: svm.NewExactSvmScheme()}, + }, + Timeout: 30 * time.Second, + })) + + // Protected endpoint + e.GET("/weather", func(c echo.Context) error { + return c.JSON(http.StatusOK, map[string]interface{}{ + "weather": "sunny", + "temperature": 70, + }) + }) + + e.Start(":4021") + } + ``` + - Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/python/servers/fastapi). + Full example in the repo [here](https://github.com/x402-foundation/x402/tree/main/examples/python/servers/fastapi). ```python from typing import Any @@ -591,7 +680,7 @@ Integrate the payment middleware into your application. You will need to provide ``` - Full example in the repo [here](https://github.com/coinbase/x402/tree/main/examples/python/servers/flask). + Full example in the repo [here](https://github.com/x402-foundation/x402/tree/main/examples/python/servers/flask). ```python from flask import Flask, jsonify @@ -665,8 +754,8 @@ Integrate the payment middleware into your application. You will need to provide ```typescript interface RouteConfig { accepts: Array<{ - scheme: string; // Payment scheme (e.g., "exact") - price: string; // Price in dollars (e.g., "$0.01") + scheme: string; // Payment scheme: "exact", "upto", or "batch-settlement" + price: string; // For "exact": the fixed price. For "upto" / "batch-settlement": the per-request maximum authorized amount. network: string; // Network in CAIP-2 format (e.g., "eip155:84532" or "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1") payTo: string; // Your wallet address }>; @@ -678,6 +767,237 @@ interface RouteConfig { When a request is made to these routes without payment, your server will respond with the HTTP 402 Payment Required code and payment instructions. +### Payment Schemes: Exact, Upto, and Batch Settlement + +x402 supports several payment schemes that control how charges are calculated: + +**`exact`** (default) — The client pays the exact advertised price. This is the simplest scheme and works across all networks (EVM, SVM, Stellar, Aptos) and all SDKs (TypeScript, Go, Python). Best for fixed-price endpoints where the cost is known upfront. + +**`upto`** — The client authorizes a **maximum** amount, but the server settles **only what was actually used**. This enables usage-based billing where the final charge depends on work performed (LLM token count, compute time, bytes served, etc.). Currently available on EVM networks only (Permit2), in TypeScript, Go, and Python SDKs. + +**`batch-settlement`** — For high-frequency or repeated micropayment traffic, the buyer funds a channel once, signs off-chain vouchers per request, and the seller settles onchain in batches (not every request). Each call still advertises a per-request maximum (`price`); you can charge actual usage up to that cap using the same **`setSettlementOverrides`** pattern as `upto`. See **[Batch settlement](/schemes/batch-settlement)** and the [Payment Schemes overview](/schemes/overview). + +The examples in step 2 above all use the `exact` scheme. To use `upto` instead, there are two key differences: + +1. Set `scheme: "upto"` in your route config, where `price` becomes the **maximum** the client authorizes +2. Call `setSettlementOverrides` in your handler to specify the **actual** amount to charge + + + + Full example in the repo [here](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/upto). + + ```typescript + import express from "express"; + import { paymentMiddleware, setSettlementOverrides, x402ResourceServer } from "@x402/express"; + import { UptoEvmScheme } from "@x402/evm/upto/server"; + import { HTTPFacilitatorClient } from "@x402/core/server"; + + const app = express(); + const evmAddress = "0xYourEvmAddress"; + + const facilitatorClient = new HTTPFacilitatorClient({ + url: "https://x402.org/facilitator" + }); + + const maxPrice = "$0.10"; // Maximum the client authorizes (10 cents) + + app.use( + paymentMiddleware( + { + "GET /api/generate": { + accepts: { + scheme: "upto", + price: maxPrice, + network: "eip155:84532", // Base Sepolia + payTo: evmAddress, + }, + description: "AI text generation — billed by token usage", + mimeType: "application/json", + }, + }, + new x402ResourceServer(facilitatorClient) + .register("eip155:84532", new UptoEvmScheme()), + ), + ); + + app.get("/api/generate", (req, res) => { + // Simulate variable-cost work (LLM tokens, compute time, etc.) + const maxAmountAtomic = 100000; // 10 cents in 6-decimal USDC atomic units + const actualUsage = Math.floor(Math.random() * (maxAmountAtomic + 1)); + + // Settle only the actual usage — the client is never charged more than this + setSettlementOverrides(res, { amount: String(actualUsage) }); + + res.json({ + result: "Here is your generated text...", + usage: { + authorizedMaxAtomic: String(maxAmountAtomic), + actualChargedAtomic: String(actualUsage), + }, + }); + }); + + app.listen(4021, () => { + console.log("Server listening at http://localhost:4021"); + }); + ``` + + + Full example in the repo [here](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/upto). + + ```go + package main + + import ( + "fmt" + "math/rand" + "net/http" + "time" + + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/server" + "github.com/gin-gonic/gin" + ) + + func main() { + evmAddress := "0xYourEvmAddress" + evmNetwork := x402.Network("eip155:84532") // Base Sepolia + + r := gin.Default() + + facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ + URL: "https://x402.org/facilitator", + }) + + maxPrice := "$0.10" // Maximum the client authorizes + + r.Use(ginmw.X402Payment(ginmw.Config{ + Routes: x402http.RoutesConfig{ + "GET /api/generate": { + Accepts: x402http.PaymentOptions{ + { + Scheme: "upto", + Price: maxPrice, + Network: evmNetwork, + PayTo: evmAddress, + }, + }, + Description: "AI text generation - billed by token usage", + MimeType: "application/json", + }, + }, + Facilitator: facilitatorClient, + Schemes: []ginmw.SchemeConfig{ + {Network: evmNetwork, Server: uptoevm.NewUptoEvmScheme()}, + }, + Timeout: 30 * time.Second, + })) + + r.GET("/api/generate", func(c *gin.Context) { + // Simulate variable-cost work (LLM tokens, compute time, etc.) + maxAmountAtomic := 100000 // 10 cents in 6-decimal USDC atomic units + actualUsage := rand.Intn(maxAmountAtomic + 1) + + // Settle only the actual usage + ginmw.SetSettlementOverrides(c, &x402.SettlementOverrides{ + Amount: fmt.Sprintf("%d", actualUsage), + }) + + c.JSON(http.StatusOK, gin.H{ + "result": "Here is your generated text...", + "usage": gin.H{ + "authorizedMaxAtomic": fmt.Sprintf("%d", maxAmountAtomic), + "actualChargedAtomic": fmt.Sprintf("%d", actualUsage), + }, + }) + }) + + r.Run(":4021") + } + ``` + + + ```python + import random + from typing import Any + + from fastapi import FastAPI + from starlette.responses import Response + + from x402.http import FacilitatorConfig, HTTPFacilitatorClient, PaymentOption + from x402.http.middleware.fastapi import PaymentMiddlewareASGI, set_settlement_overrides + from x402.http.types import RouteConfig + from x402.mechanisms.evm.upto import UptoEvmServerScheme + from x402.schemas import Network + from x402.server import x402ResourceServer + + app = FastAPI() + + evm_address = "0xYourEvmAddress" + EVM_NETWORK: Network = "eip155:84532" # Base Sepolia + + facilitator = HTTPFacilitatorClient( + FacilitatorConfig(url="https://x402.org/facilitator") + ) + + server = x402ResourceServer(facilitator) + server.register(EVM_NETWORK, UptoEvmServerScheme()) + + max_price = "$0.10" # Maximum the client authorizes (10 cents) + + routes: dict[str, RouteConfig] = { + "GET /api/generate": RouteConfig( + accepts=[ + PaymentOption( + scheme="upto", + pay_to=evm_address, + price=max_price, + network=EVM_NETWORK, + ), + ], + mime_type="application/json", + description="AI text generation — billed by token usage", + ), + } + + app.add_middleware(PaymentMiddlewareASGI, routes=routes, server=server) + + + @app.get("/api/generate") + async def generate(response: Response) -> dict[str, Any]: + # Simulate variable-cost work (LLM tokens, compute time, etc.) + max_amount_atomic = 100000 # 10 cents in 6-decimal USDC atomic units + actual_usage = random.randint(0, max_amount_atomic) + + # Settle only the actual usage — the client is never charged more than this + set_settlement_overrides(response, {"amount": str(actual_usage)}) + + return { + "result": "Here is your generated text...", + "usage": { + "authorizedMaxAtomic": str(max_amount_atomic), + "actualChargedAtomic": str(actual_usage), + }, + } + + + if __name__ == "__main__": + import uvicorn + uvicorn.run(app, host="0.0.0.0", port=4021) + ``` + + + +The `setSettlementOverrides` amount supports three formats: + +* **Raw atomic units** — e.g., `"1000"` settles exactly 1,000 atomic units of the token (for USDC with 6 decimals, `"1000"` = $0.001) +* **Percentage of authorized maximum** — e.g., `"50%"` settles 50% of `PaymentRequirements.amount`. Supports up to two decimal places (e.g., `"33.33%"`). The result is floored to the nearest atomic unit. +* **Dollar price** — e.g., `"$0.05"` converts a USD-denominated price to atomic units. This format works when you configured your route with `$`-prefixed pricing (e.g., `price: "$0.10"`). Token decimals are determined from the registered scheme. The result is rounded to the nearest atomic unit. + +The resolved amount must always be <= the authorized maximum. If the amount is `"0"`, no onchain transaction occurs and the client is not charged. + ### 3. Test Your Integration To verify: @@ -690,43 +1010,57 @@ To verify: ### 4. Enhance Discovery with Metadata (Recommended) -When using a facilitator that supports the Bazaar extension, your endpoints can be listed in the [x402 Bazaar](/extensions/bazaar), the discovery layer that helps buyers and AI agents find services. To enable discovery: +When using a facilitator that supports the Bazaar extension, your endpoints can be listed in the [x402 Bazaar](/extensions/bazaar), the discovery layer that helps buyers and AI agents find services. + +**For HTTP endpoints**, add the discovery extension to your route config: ```typescript +import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; + { "GET /weather": { - accepts: [ - { - scheme: "exact", - price: "$0.001", - network: "eip155:8453", - payTo: "0xYourAddress", - }, - { - scheme: "exact", - price: "$0.001", - network: "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", // Solana mainnet - payTo: "YourSolanaAddress", - }, - ], + accepts: [{ scheme: "exact", price: "$0.001", network: "eip155:8453", payTo: "0xYourAddress" }], description: "Get real-time weather data including temperature, conditions, and humidity", mimeType: "application/json", extensions: { - bazaar: { - discoverable: true, - category: "weather", - tags: ["forecast", "real-time"], - }, + ...declareDiscoveryExtension({ + input: { city: "San Francisco" }, + inputSchema: { + properties: { city: { type: "string", description: "City name" } }, + required: ["city"], + }, + }), }, }, } ``` +**For MCP tools**, pass the discovery extension in your payment wrapper config: + +```typescript +import { createPaymentWrapper } from "@x402/mcp"; +import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; + +const paid = createPaymentWrapper(resourceServer, { + accepts, + resource: { url: "mcp://tool/get_weather", description: "Get current weather for a city" }, + extensions: declareDiscoveryExtension({ + toolName: "get_weather", + description: "Get current weather for a city", + transport: "sse", + inputSchema: { + properties: { city: { type: "string", description: "City name" } }, + required: ["city"], + }, + }), +}); +``` + Learn more about the discovery layer in the [Bazaar documentation](/extensions/bazaar). ### 5. Error Handling -* If you run into trouble, check out the examples in the [repo](https://github.com/coinbase/x402/tree/main/examples) for more context and full code. +* If you run into trouble, check out the examples in the [repo](https://github.com/x402-foundation/x402/tree/main/examples) for more context and full code. * Run `npm install` or `go mod tidy` to install dependencies --- @@ -748,7 +1082,15 @@ For mainnet, use a production facilitator. See the [x402 Ecosystem](https://www. }); ``` - + + ```go + facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ + URL: "https://api.cdp.coinbase.com/platform/v2/x402", + // URL: "https://facilitator.payai.network", // PayAI Facilitator + }) + ``` + + ```go facilitatorClient := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ URL: "https://api.cdp.coinbase.com/platform/v2/x402", @@ -839,11 +1181,11 @@ For multi-network support, register both EVM and SVM schemes: server.register("solana:*", new ExactSvmScheme()); ``` - + ```go import ( - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) r.Use(ginmw.X402Payment(ginmw.Config{ @@ -855,6 +1197,22 @@ For multi-network support, register both EVM and SVM schemes: })) ``` + + ```go + import ( + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" + ) + + e.Use(echomw.X402Payment(echomw.Config{ + // ... + Schemes: []echomw.SchemeConfig{ + {Network: x402.Network("eip155:8453"), Server: evm.NewExactEvmScheme()}, + {Network: x402.Network("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"), Server: svm.NewExactSvmScheme()}, + }, + })) + ``` + ```python from x402.mechanisms.evm.exact import ExactEvmServerScheme @@ -900,7 +1258,7 @@ See [Network Support](/core-concepts/network-and-token-support) for the full lis ### Next Steps -* Check out the [Advanced Example](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/advanced) for a more complex payment flow +* Check out the [Advanced Example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/advanced) for a more complex payment flow * Explore [Advanced Concepts](/advanced-concepts/lifecycle-hooks) like lifecycle hooks for custom logic before/after verification/settlement * Explore [Extensions](/extensions/bazaar) like Bazaar for service discovery * Get started as a [buyer](/getting-started/quickstart-for-buyers) @@ -913,6 +1271,7 @@ This quickstart covered: * Installing the x402 SDK and relevant middleware * Adding payment middleware to your API and configuring it +* Choosing between `exact` (fixed-price), `upto` (usage-based per settlement), and `batch-settlement` (EVM micropayments with batched redemption) payment schemes * Testing your integration * Deploying to mainnet with CAIP-2 network identifiers diff --git a/docs/guides/mcp-server-with-x402.md b/docs/guides/mcp-server-with-x402.md index 871fe64785..9c93f33801 100644 --- a/docs/guides/mcp-server-with-x402.md +++ b/docs/guides/mcp-server-with-x402.md @@ -19,7 +19,7 @@ This lets you (or your agent) access paid APIs programmatically, with no manual * Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) * pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -* An x402-compatible server to connect to (for this demo, we'll use the [sample express server with weather data](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/express) from the x402 repo, or any external x402 API) +* An x402-compatible server to connect to (for this demo, we'll use the [sample express server with weather data](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/express) from the x402 repo, or any external x402 API) * An Ethereum wallet with USDC (on Base Sepolia or Base Mainnet) and/or a Solana wallet with USDC (on Devnet or Mainnet) * [Claude Desktop with MCP support](https://claude.ai/download) @@ -31,7 +31,7 @@ This lets you (or your agent) access paid APIs programmatically, with no manual ```bash # Clone the x402 repository -git clone https://github.com/coinbase/x402.git +git clone https://github.com/x402-foundation/x402.git cd x402/examples/typescript # Install dependencies and build packages @@ -105,6 +105,10 @@ import axios from "axios"; import { x402Client, wrapAxiosWithPayment } from "@x402/axios"; import { ExactEvmScheme } from "@x402/evm/exact/client"; import { ExactSvmScheme } from "@x402/svm/exact/client"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/client"; +import { toClientEvmSigner } from "@x402/evm"; +import { createPublicClient, http } from "viem"; +import { baseSepolia } from "viem/chains"; import { privateKeyToAccount } from "viem/accounts"; import { createKeyPairSignerFromBytes } from "@solana/kit"; import { base58 } from "@scure/base"; @@ -129,8 +133,16 @@ async function createClient() { // Register EVM scheme if private key is provided if (evmPrivateKey) { - const evmSigner = privateKeyToAccount(evmPrivateKey); - client.register("eip155:*", new ExactEvmScheme(evmSigner)); + const account = privateKeyToAccount(evmPrivateKey); + client.register("eip155:*", new ExactEvmScheme(account)); + const publicClient = createPublicClient({ chain: baseSepolia, transport: http() }); + const batchSigner = toClientEvmSigner(account, publicClient); + client.register( + "eip155:*", + new BatchSettlementEvmScheme(batchSigner, { + depositPolicy: { depositMultiplier: 5 }, + }), + ); } // Register SVM scheme if private key is provided @@ -168,7 +180,7 @@ async function main() { await server.connect(transport); } -main().catch(error => { +main().catch((error) => { console.error(error); process.exit(1); }); @@ -196,11 +208,25 @@ The example supports both EVM (Base, Ethereum) and Solana networks. The x402 cli import { x402Client, wrapAxiosWithPayment } from "@x402/axios"; import { ExactEvmScheme } from "@x402/evm/exact/client"; import { ExactSvmScheme } from "@x402/svm/exact/client"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/client"; +import { toClientEvmSigner } from "@x402/evm"; +import { createPublicClient, http } from "viem"; +import { baseSepolia } from "viem/chains"; +import { privateKeyToAccount } from "viem/accounts"; const client = new x402Client(); -// Register EVM scheme for Base/Ethereum payments -client.register("eip155:*", new ExactEvmScheme(evmSigner)); +const account = privateKeyToAccount(evmPrivateKey); +const publicClient = createPublicClient({ chain: baseSepolia, transport: http() }); + +// Register EVM schemes for Base/Ethereum payments (exact + batch-settlement) +client.register("eip155:*", new ExactEvmScheme(account)); +client.register( + "eip155:*", + new BatchSettlementEvmScheme(toClientEvmSigner(account, publicClient), { + depositPolicy: { depositMultiplier: 5 }, + }), +); // Register SVM scheme for Solana payments client.register("solana:*", new ExactSvmScheme(svmSigner)); @@ -210,9 +236,11 @@ const httpClient = wrapAxiosWithPayment(axios.create({ baseURL }), client); ``` When the server returns a 402 response, the client checks the `network` field in the payment requirements: -- `eip155:*` networks use the EVM scheme +- `eip155:*` networks use the registered EVM schemes (`exact`, `upto`, **`batch-settlement`**, etc.) - `solana:*` networks use the SVM scheme +**Batch settlement:** Paid APIs that advertise **`scheme: "batch-settlement"`** require **`BatchSettlementEvmScheme`** on **`eip155:*`** (in addition to `ExactEvmScheme`). The **Implementation** section and the snippet above register both so tools work against **`exact`** servers and **batch-settlement** APIs. See **[Batch settlement](/schemes/batch-settlement)**. + *** ### Response Handling @@ -304,9 +332,52 @@ The example uses these x402 v2 packages: *** +*** + +### Making Your MCP Tools Discoverable via Bazaar + +If you are building an MCP **server** (not just a client bridge), you can make your paid tools visible in the [x402 Bazaar](/extensions/bazaar) so AI agents and other buyers can discover them without prior knowledge of your server. + +Pass `extensions` in the payment wrapper config with the Bazaar discovery metadata: + +```typescript +import { createPaymentWrapper } from "@x402/mcp"; +import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; + +const paid = createPaymentWrapper(resourceServer, { + accepts, + resource: { + url: "mcp://tool/get_weather", + description: "Get current weather for a city", + }, + // Bazaar discovery metadata — facilitators will catalog this tool + extensions: declareDiscoveryExtension({ + toolName: "get_weather", + description: "Get current weather for a city", + transport: "sse", + inputSchema: { + properties: { city: { type: "string", description: "City name" } }, + required: ["city"], + }, + example: { city: "San Francisco" }, + }), +}); +``` + +When a client pays for the tool, the facilitator extracts the Bazaar extension from the payment payload and indexes the tool in `/discovery/resources` with `type: "mcp"`. Buyers can then discover it by querying a Bazaar-enabled facilitator: + +```typescript +const mcpTools = await client.extensions.bazaar.listResources({ type: "mcp" }); +``` + +See the full [Bazaar documentation](/extensions/bazaar) for details on buyers querying and calling discovered MCP tools. + +*** + ### Next Steps -* [See the full example in the repo](https://github.com/coinbase/x402/tree/main/examples/typescript/clients/mcp) +* [See the full example in the repo](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/mcp) * Try integrating with your own x402-compatible APIs * Extend the MCP server with more tools or custom logic as needed * [Learn about building x402 servers](/getting-started/quickstart-for-sellers) +* [Explore the Bazaar discovery layer](/extensions/bazaar) diff --git a/docs/introduction.md b/docs/introduction.md index 86d16a34c1..5e560d84cb 100644 --- a/docs/introduction.md +++ b/docs/introduction.md @@ -9,7 +9,7 @@ x402 is the open payment standard that enables services to charge for access to With x402, any web service can require payment before serving a response, using crypto-native payments for speed, privacy, and efficiency. -**Want to contribute to our docs?** [The GitBook repo is open to PRs! ](https://github.com/coinbase/x402) Our only ask is that you keep these docs as a neutral resource, with no branded content other than linking out to other resources where appropriate. +**Want to contribute to our docs?** [The documentation source in this repository is open to PRs.](https://github.com/x402-foundation/x402) Our only ask is that you keep these docs as a neutral resource, with no branded content other than linking out to other resources where appropriate. **Note about the docs:** These docs are the credibly neutral source of truth for x402, as x402 is a completely open standard under the Apache-2.0 license. Coinbase Developer Platform is currently sponsoring [AI-powered docs for users here](https://docs.cdp.coinbase.com/x402/welcome), as we migrate to our own AI-powered solution on the main x402.org domain. @@ -19,7 +19,7 @@ x402 offers: - **No fees and minimal friction** x402 as a standard has 0 fees built in. - **Native support for machine-to-machine payments**, enabling seamless use by AI agents -- **Built-in micropayment support**, making it easy to monetize usage-based services +- **Built-in micropayment support**, making it easy to monetize usage-based services (including **[batch settlement](/schemes/batch-settlement)** on EVM for high-volume, batched **onchain** redemption) ### Who is x402 for? @@ -53,6 +53,7 @@ For more detail, see: - [Client / Server](/core-concepts/client-server) - [Facilitator](/core-concepts/facilitator) - [HTTP 402](/core-concepts/http-402) +- [Batch settlement](/schemes/batch-settlement) The goal is to make programmatic commerce accessible, permissionless, and developer-friendly. @@ -63,4 +64,5 @@ Ready to build? Start here: - [Quickstart for Sellers](/getting-started/quickstart-for-sellers) - [Quickstart for Buyers](/getting-started/quickstart-for-buyers) - [Explore Core Concepts](/core-concepts/http-402) +- [Batch settlement](/schemes/batch-settlement) (EVM micropayments / batched redemption) - [Join our community on Discord](https://discord.gg/invite/cdp) diff --git a/docs/schemes/batch-settlement.mdx b/docs/schemes/batch-settlement.mdx new file mode 100644 index 0000000000..aa5ea07dfd --- /dev/null +++ b/docs/schemes/batch-settlement.mdx @@ -0,0 +1,325 @@ +--- +title: "Batch Settlement" +description: "High-throughput EVM payments with escrow, off-chain vouchers, and batched onchain redemption." +--- + +The `batch-settlement` scheme is for high-throughput payments where many requests are authorized individually and redeemed later in batches. The EVM implementation uses stateless unidirectional payment channels: a buyer deposits funds into onchain escrow once, then signs off-chain cumulative vouchers for each request. The seller verifies vouchers quickly and redeems them onchain later in batches. + +Use `batch-settlement` for repeated paid API calls, usage-metered endpoints, and other workloads where many small payments would be too expensive or slow to settle one-by-one. + +### How It Works + +1. **Deposit:** the client opens or tops up a channel by depositing ERC-20 funds into escrow. Deposits use EIP-3009 or Permit2 and are submitted by the facilitator. +2. **Voucher:** each paid request includes a signed cumulative voucher for the channel's total claimable amount. +3. **Verify:** the server verifies the voucher and serves the response without waiting for an onchain transfer. +4. **Claim:** the server's channel manager periodically claims the latest vouchers from many channels in one transaction. +5. **Settle:** claimed funds are swept to the receiver in a separate settle transaction. +6. **Refund:** idle channels can be cooperatively refunded after outstanding vouchers are claimed. + +The route `price` is still a per-request maximum. For dynamic pricing, the server can charge less than that maximum with settlement overrides. + +### Server Setup + +Register the scheme with a resource server, protect routes with `scheme: "batch-settlement"`, configure server-side channel storage, and run a channel manager to claim, settle, and refund channels. + + + + ```typescript + import { HTTPFacilitatorClient } from "@x402/core/server"; + import { BatchSettlementEvmScheme, FileChannelStorage } from "@x402/evm/batch-settlement/server"; + import { paymentMiddleware, setSettlementOverrides, x402ResourceServer } from "@x402/express"; + + const network = "eip155:84532" as const; + const facilitatorClient = new HTTPFacilitatorClient({ url: process.env.FACILITATOR_URL! }); + + const batchScheme = new BatchSettlementEvmScheme(receiverAddress, { + receiverAuthorizerSigner, + withdrawDelay: 86400, + storage: new FileChannelStorage({ directory: "./channels" }), + }); + + const resourceServer = new x402ResourceServer(facilitatorClient) + .register(network, batchScheme); + + const channelManager = batchScheme.createChannelManager(facilitatorClient, network); + channelManager.start({ + claimIntervalSecs: 60, + settleIntervalSecs: 300, + refundIntervalSecs: 3600, + maxClaimsPerBatch: 100, + }); + + app.use(paymentMiddleware({ + "GET /weather": { + accepts: { + scheme: "batch-settlement", + price: "$0.01", + network, + payTo: receiverAddress, + }, + description: "Weather data", + mimeType: "application/json", + }, + }, resourceServer)); + + app.get("/weather", (req, res) => { + setSettlementOverrides(res, { amount: "50%" }); + res.json({ report: { weather: "sunny", temperature: 70 } }); + }); + ``` + + + ```go + cfg := &batchedserver.BatchSettlementEvmSchemeServerConfig{ + ReceiverAuthorizerSigner: receiverAuthorizerSigner, + WithdrawDelay: 86400, + Storage: batchedserver.NewFileChannelStorage(batchsettlement.FileChannelStorageOptions{ + Directory: "./channels", + }), + } + + scheme := batchedserver.NewBatchSettlementEvmScheme(receiverAddress, cfg) + manager := scheme.CreateChannelManager(facilitatorClient, x402.Network("eip155:84532")) + manager.Start(batchedserver.AutoSettlementConfig{ + ClaimIntervalSecs: 60, + SettleIntervalSecs: 300, + RefundIntervalSecs: 3600, + MaxClaimsPerBatch: 100, + }) + + routes := x402http.RoutesConfig{ + "GET /weather": { + Accepts: x402http.PaymentOptions{ + { + Scheme: batchsettlement.SchemeBatched, + Price: "$0.01", + Network: x402.Network("eip155:84532"), + PayTo: receiverAddress, + }, + }, + Description: "Weather data", + MimeType: "application/json", + }, + } + + mux.HandleFunc("GET /weather", func(w http.ResponseWriter, r *http.Request) { + nethttpmw.SetSettlementOverrides(w, &x402.SettlementOverrides{Amount: "50%"}) + _ = json.NewEncoder(w).Encode(map[string]any{ + "report": map[string]any{"weather": "sunny", "temperature": 70}, + }) + }) + ``` + + + +### Server Storage + +Server storage keeps the latest voucher and channel session state that the channel manager uses to claim, settle, and refund later. In-memory storage is useful for local demos, but production servers should configure durable storage so outstanding vouchers survive restarts. + +Use file storage for single-process deployments. For serverless or multi-instance deployments, use Redis/Valkey storage so channel updates are shared atomically across processes. See the [Next.js batch-settlement Redis example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/fullstack/next-batch-settlement-redis) for a full `withX402` setup with `RedisChannelStorage` and cron-based claim/settle routes. + +### Client Setup + +Register `BatchSettlementEvmScheme` for `eip155:*`. The client SDK handles deposits, voucher signing, channel recovery, and corrective 402 resync. + + + + ```typescript + import { x402Client, wrapFetchWithPayment } from "@x402/fetch"; + import { toClientEvmSigner } from "@x402/evm"; + import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/client"; + import { createPublicClient, http } from "viem"; + import { baseSepolia } from "viem/chains"; + import { privateKeyToAccount } from "viem/accounts"; + + const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`); + const publicClient = createPublicClient({ chain: baseSepolia, transport: http() }); + const signer = toClientEvmSigner(account, publicClient); + + const batchScheme = new BatchSettlementEvmScheme(signer, { + depositPolicy: { depositMultiplier: 5 }, + }); + + const client = new x402Client(); + client.register("eip155:*", batchScheme); + + const fetchWithPayment = wrapFetchWithPayment(fetch, client); + const response = await fetchWithPayment("https://api.example.com/weather"); + ``` + + + ```go + import ( + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/ethereum/go-ethereum/ethclient" + batchedclient "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" + ) + + ethClient, err := ethclient.Dial("https://sepolia.base.org") + if err != nil { + log.Fatal(err) + } + + evmSigner, err := evmsigners.NewClientSignerFromPrivateKeyWithClient(os.Getenv("EVM_PRIVATE_KEY"), ethClient) + if err != nil { + log.Fatal(err) + } + + batchScheme := batchedclient.NewBatchSettlementEvmScheme(evmSigner, &batchedclient.BatchSettlementEvmSchemeOptions{ + DepositMultiplier: 5, + }) + + x402Client := x402.Newx402Client(). + Register("eip155:*", batchScheme) + + httpClient := x402http.WrapHTTPClientWithPayment( + http.DefaultClient, + x402http.Newx402HTTPClient(x402Client), + ) + ``` + + + +### Deposit Policy + +The deposit policy controls how much the client deposits when a channel needs funding or top-up. + +| Field | Description | +|-------|-------------| +| `depositMultiplier` / `DepositMultiplier` | Deposits `amount x multiplier` for the advertised per-request maximum. The default is `5`; the minimum is `3`. | +| `depositStrategy` / `DepositStrategy` | Optional callback for caps, dynamic deposits, or opting out of automatic top-up. | + + + + ```typescript + const maxDeposit = 1_000_000n; + + const batchScheme = new BatchSettlementEvmScheme(signer, { + depositPolicy: { depositMultiplier: 5 }, + depositStrategy: ({ depositAmount }) => { + const amount = BigInt(depositAmount); + return amount > maxDeposit ? maxDeposit : undefined; + }, + }); + ``` + + + ```go + batchScheme := batchedclient.NewBatchSettlementEvmScheme(evmSigner, &batchedclient.BatchSettlementEvmSchemeOptions{ + DepositMultiplier: 5, + DepositStrategy: func(_ context.Context, c batchedclient.DepositStrategyContext) (batchedclient.DepositStrategyResult, error) { + capped, _ := new(big.Int).SetString("1000000", 10) + proposed, _ := new(big.Int).SetString(c.DepositAmount, 10) + if proposed.Cmp(capped) > 0 { + return batchedclient.DepositStrategyResult{Amount: capped.String()}, nil + } + return batchedclient.DepositStrategyResult{}, nil + }, + }) + ``` + + + +### Voucher Signer Delegation + +By default, vouchers are signed by the payer key. For higher-throughput clients, especially smart wallets using EIP-1271, delegate voucher signing to a dedicated EOA. The delegated address is committed into the channel as `payerAuthorizer`, which lets the facilitator verify vouchers with ECDSA recovery instead of an onchain smart-wallet signature check. + + + + ```typescript + const voucherSigner = toClientEvmSigner( + privateKeyToAccount(process.env.EVM_VOUCHER_SIGNER_PRIVATE_KEY as `0x${string}`), + ); + + const batchScheme = new BatchSettlementEvmScheme(signer, { + voucherSigner, + }); + ``` + + + ```go + voucherSigner, err := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("EVM_VOUCHER_SIGNER_PRIVATE_KEY")) + if err != nil { + log.Fatal(err) + } + + batchScheme := batchedclient.NewBatchSettlementEvmScheme(evmSigner, &batchedclient.BatchSettlementEvmSchemeOptions{ + VoucherSigner: voucherSigner, + }) + ``` + + + +### Client Persistence and Refunds + +Client channel state is stored in memory by default. Persistent client storage is optional because the SDK can recover channel state through corrective 402 responses and onchain state on the next paid request. Long-lived clients can still persist state to avoid that recovery round trip after restarts. + + + + ```typescript + import { FileClientChannelStorage } from "@x402/evm/batch-settlement/client"; + + const batchScheme = new BatchSettlementEvmScheme(signer, { + storage: new FileClientChannelStorage({ directory: "./channels" }), + }); + + await batchScheme.refund("https://api.example.com/weather"); + await batchScheme.refund("https://api.example.com/weather", { amount: "1000000" }); + ``` + + + ```go + import "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + + batchScheme := batchedclient.NewBatchSettlementEvmScheme(evmSigner, &batchedclient.BatchSettlementEvmSchemeOptions{ + Storage: batchedclient.NewFileClientChannelStorage(batchsettlement.FileChannelStorageOptions{ + Directory: "./channels", + }), + }) + + settle, err := batchScheme.Refund(ctx, "https://api.example.com/weather", &batchedclient.RefundOptions{ + Amount: "1000000", + }) + ``` + + + +### Receiver Authorizer + +Every channel commits to a `receiverAuthorizer`, which signs claim and refund authorizations. + +| Strategy | When to use it | +|----------|----------------| +| Self-managed `receiverAuthorizerSigner` | Recommended for production. Channels survive facilitator changes because any facilitator can relay your signed claims and refunds. | +| Facilitator-delegated authorizer | Simpler to run. If you switch facilitators, claim and refund old channels before opening new ones. | + +### Settlement Policy + +Choose claim, settle, and refund intervals based on throughput and gas cost: + +* Claim often enough that outstanding vouchers are claimed before a payer's timed withdrawal can finalize after `withdrawDelay`. +* Settle less often when gas savings matter more than cash-flow latency. +* Refund idle channels to return unclaimed balance to payers. + +Set `withdrawDelay` greater than your claim cadence plus an operational safety margin. + +### Examples + +* [TypeScript client](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/batch-settlement) +* [TypeScript server](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/batch-settlement) +* [Next.js server + Redis storage](https://github.com/x402-foundation/x402/tree/main/examples/typescript/fullstack/next-batch-settlement-redis) +* [Go client](https://github.com/x402-foundation/x402/tree/main/examples/go/clients/batch-settlement) +* [Go server](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/batch-settlement) + +### Specs + +* [`batch-settlement` spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/batch-settlement/scheme_batch_settlement.md) +* [`batch-settlement` EVM spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/batch-settlement/scheme_batch_settlement_evm.md) + +### See Also + +* [Payment schemes overview](/schemes/overview) +* [Exact](/schemes/exact) +* [Upto](/schemes/upto) diff --git a/docs/schemes/exact.mdx b/docs/schemes/exact.mdx new file mode 100644 index 0000000000..b827ecd69b --- /dev/null +++ b/docs/schemes/exact.mdx @@ -0,0 +1,241 @@ +--- +title: "Exact" +description: "Fixed-price x402 payments where the buyer authorizes exactly the advertised amount." +--- + +The `exact` scheme is a fixed-price payment scheme. The seller advertises one amount, the buyer signs for that exact amount, and the facilitator settles that payment for the request. + +Use `exact` when the final charge is known before the response is generated, such as a fixed-price API call, file download, or gated page. + +### Server Setup + + + + ```typescript + import { HTTPFacilitatorClient } from "@x402/core/server"; + import { paymentMiddleware, x402ResourceServer } from "@x402/express"; + import { ExactEvmScheme } from "@x402/evm/exact/server"; + import { ExactSvmScheme } from "@x402/svm/exact/server"; + + const facilitatorClient = new HTTPFacilitatorClient({ + url: "https://x402.org/facilitator", + }); + + const resourceServer = new x402ResourceServer(facilitatorClient) + .register("eip155:84532", new ExactEvmScheme()) + .register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme()); + + app.use( + paymentMiddleware( + { + "GET /weather": { + accepts: [ + { + scheme: "exact", + price: "$0.001", + network: "eip155:84532", + payTo: "0xYourAddress", + }, + { + scheme: "exact", + price: "$0.001", + network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + payTo: "YourSolanaAddress", + }, + ], + description: "Weather data", + mimeType: "application/json", + }, + }, + resourceServer, + ), + ); + ``` + + + ```go + routes := x402http.RoutesConfig{ + "GET /weather": { + Accepts: x402http.PaymentOptions{ + { + Scheme: "exact", + Price: "$0.001", + Network: "eip155:84532", + PayTo: "0xYourAddress", + }, + { + Scheme: "exact", + Price: "$0.001", + Network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + PayTo: "YourSolanaAddress", + }, + }, + Description: "Weather data", + MimeType: "application/json", + }, + } + + handler := nethttpmw.X402Payment(nethttpmw.Config{ + Routes: routes, + Facilitator: facilitatorClient, + Schemes: []nethttpmw.SchemeConfig{ + {Network: x402.Network("eip155:84532"), Server: exactevm.NewExactEvmScheme()}, + {Network: x402.Network("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"), Server: exactsvm.NewExactSvmScheme()}, + }, + })(mux) + ``` + + + ```python + from fastapi import FastAPI + + from x402.http import FacilitatorConfig, HTTPFacilitatorClient, PaymentOption + from x402.http.middleware.fastapi import PaymentMiddlewareASGI + from x402.http.types import RouteConfig + from x402.mechanisms.evm.exact import ExactEvmServerScheme + from x402.mechanisms.svm.exact import ExactSvmServerScheme + from x402.server import x402ResourceServer + + app = FastAPI() + facilitator = HTTPFacilitatorClient(FacilitatorConfig(url="https://x402.org/facilitator")) + + server = x402ResourceServer(facilitator) + server.register("eip155:84532", ExactEvmServerScheme()) + server.register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", ExactSvmServerScheme()) + + routes = { + "GET /weather": RouteConfig( + accepts=[ + PaymentOption( + scheme="exact", + price="$0.001", + network="eip155:84532", + pay_to="0xYourAddress", + ), + PaymentOption( + scheme="exact", + price="$0.001", + network="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + pay_to="YourSolanaAddress", + ), + ], + description="Weather data", + mime_type="application/json", + ), + } + + app.add_middleware(PaymentMiddlewareASGI, routes=routes, server=server) + ``` + + + +### Client Setup + + + + ```typescript + import { x402Client } from "@x402/core/client"; + import { ExactEvmScheme } from "@x402/evm/exact/client"; + import { ExactSvmScheme } from "@x402/svm/exact/client"; + import { createKeyPairSignerFromBytes } from "@solana/kit"; + import { base58 } from "@scure/base"; + import { privateKeyToAccount } from "viem/accounts"; + + const evmSigner = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`); + const svmSigner = await createKeyPairSignerFromBytes( + base58.decode(process.env.SVM_PRIVATE_KEY!), + ); + + const client = new x402Client(); + client.register("eip155:*", new ExactEvmScheme(evmSigner)); + client.register("solana:*", new ExactSvmScheme(svmSigner)); + ``` + + + ```go + import ( + x402 "github.com/x402-foundation/x402/go" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + exactsvm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" + svmsigners "github.com/x402-foundation/x402/go/signers/svm" + ) + + evmSigner, err := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("EVM_PRIVATE_KEY")) + if err != nil { + log.Fatal(err) + } + + svmSigner, err := svmsigners.NewClientSignerFromPrivateKey(os.Getenv("SVM_PRIVATE_KEY")) + if err != nil { + log.Fatal(err) + } + + x402Client := x402.Newx402Client(). + Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, nil)). + Register("solana:*", exactsvm.NewExactSvmScheme(svmSigner)) + ``` + + + ```python + import os + + from eth_account import Account + + from x402 import x402Client + from x402.mechanisms.evm import EthAccountSigner + from x402.mechanisms.evm.exact.register import register_exact_evm_client + from x402.mechanisms.svm import KeypairSigner + from x402.mechanisms.svm.exact.register import register_exact_svm_client + + client = x402Client() + + account = Account.from_key(os.getenv("EVM_PRIVATE_KEY")) + register_exact_evm_client(client, EthAccountSigner(account)) + + svm_signer = KeypairSigner.from_base58(os.getenv("SVM_PRIVATE_KEY")) + register_exact_svm_client(client, svm_signer) + ``` + + + +### Network Implementations + +The `exact` scheme has network specifications for EVM, SVM, AVM, Stellar, Aptos, Hedera, TON, Cardano, Keeta, and Sui. + +### EVM Transfer Methods + +The EVM implementation supports two transfer methods: + +| Method | Description | +|--------|-------------| +| `eip3009` | Uses token-native `transferWithAuthorization`, commonly for USDC. This is the default when supported. | +| `permit2` | Uses Uniswap Permit2 plus the x402 exact proxy, so it can support ERC-20 tokens without EIP-3009. | + +Permit2 may require a one-time approval. The gas sponsoring extensions can let the facilitator handle that approval path for compatible tokens. + +### Examples + +* [TypeScript server example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/express) +* [TypeScript client example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch) +* [Go server example](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/nethttp) +* [Go client example](https://github.com/x402-foundation/x402/tree/main/examples/go/clients/http) +* [Python server example](https://github.com/x402-foundation/x402/tree/main/examples/python/servers/fastapi) +* [Python client example](https://github.com/x402-foundation/x402/tree/main/examples/python/clients/requests) + +### Specs + +* [`exact` spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact.md) +* [`exact` EVM spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_evm.md) +* [`exact` SVM spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_svm.md) +* [`exact` AVM spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_algo.md) +* [`exact` Stellar spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_stellar.md) +* [`exact` Aptos spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_aptos.md) +* [`exact` Hedera spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_hedera.md) +* [`exact` TON spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_ton.md) + +### See Also + +* [Payment schemes overview](/schemes/overview) +* [Upto](/schemes/upto) +* [Batch settlement](/schemes/batch-settlement) diff --git a/docs/schemes/overview.mdx b/docs/schemes/overview.mdx new file mode 100644 index 0000000000..dd14f9ba67 --- /dev/null +++ b/docs/schemes/overview.mdx @@ -0,0 +1,57 @@ +--- +title: "Payment Schemes" +description: "Choose between exact, upto, and batch-settlement payment schemes in x402." +--- + +Payment schemes define the payment semantics for a resource: `exact` is for fixed-price requests where the buyer authorizes the advertised amount, `upto` is for single-request usage-based billing where the buyer authorizes a maximum and the seller charges actual usage, and `batch-settlement` is for high-volume or repeated micropayments where per-request authorizations are accumulated against a reusable channel. Network implementations define how those semantics are encoded for EVM, SVM, TVM (TON), AVM, Stellar, Aptos, Hedera, and other networks; see [SDK Features](/sdk-features) for current SDK support. + +### Schemes in a 402 Response + +A protected resource advertises one or more payment requirements in its HTTP 402 Payment Required response. The `scheme` names the payment semantics and `network` names the network implementation. + +```json +{ + "x402Version": 2, + "error": "PAYMENT-SIGNATURE header is required", + "resource": { + "url": "https://api.example.com/weather", + "description": "Weather data", + "mimeType": "application/json" + }, + "accepts": [ + { + "scheme": "exact", + "network": "eip155:84532", + "amount": "1000", + "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "payTo": "0xYourEvmAddress", + "maxTimeoutSeconds": 60, + "extra": { + "name": "USDC", + "version": "2" + } + }, + { + "scheme": "exact", + "network": "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + "amount": "1000", + "asset": "So11111111111111111111111111111111111111112", + "payTo": "YourSolanaAddress", + "maxTimeoutSeconds": 60, + "extra": { + "feePayer": "EwWqGE4ZFKLofuestmU4LDdK7XM1N4ALgdZccwYugwGd" + } + } + ] +} +``` + +Servers register scheme implementations for the networks they advertise. Clients register scheme implementations for the networks they can pay on. When the client receives a 402 response, the SDK selects an `accepts` entry whose `scheme` and `network` match a registered implementation. + +### Specs + +For scheme-level payload semantics, see the network-agnostic specifications. Each scheme page links to its currently implemented network specs. + +* [`exact` spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact.md) +* [`upto` spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/upto/scheme_upto.md) +* [`batch-settlement` spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/batch-settlement/scheme_batch_settlement.md) diff --git a/docs/schemes/upto.mdx b/docs/schemes/upto.mdx new file mode 100644 index 0000000000..486f563c2e --- /dev/null +++ b/docs/schemes/upto.mdx @@ -0,0 +1,197 @@ +--- +title: "Upto" +description: "Usage-based x402 payments where the buyer authorizes a maximum and the seller charges actual usage." +--- + +The `upto` scheme lets a seller advertise a maximum price for one request, then settle for the actual amount used. The buyer signs once for the maximum, and the server chooses a final amount that is less than or equal to that maximum. + +Use `upto` for one-request usage metering, such as LLM token generation, bandwidth, compute time, or dynamic data queries. + +### Server Setup + +Set the route `price` to the maximum authorized amount. In the handler, use settlement overrides to charge the actual amount. + + + + ```typescript + import { paymentMiddleware, setSettlementOverrides, x402ResourceServer } from "@x402/express"; + import { UptoEvmScheme } from "@x402/evm/upto/server"; + + const resourceServer = new x402ResourceServer(facilitatorClient) + .register("eip155:84532", new UptoEvmScheme()); + + app.use(paymentMiddleware({ + "GET /api/generate": { + accepts: { + scheme: "upto", + price: "$0.10", + network: "eip155:84532", + payTo: "0xYourAddress", + }, + description: "AI text generation billed by usage", + }, + }, resourceServer)); + + app.get("/api/generate", (req, res) => { + const actualUsage = computeActualCost(); + setSettlementOverrides(res, { amount: String(actualUsage) }); + res.json({ result: "..." }); + }); + ``` + + + ```go + routes := x402http.RoutesConfig{ + "GET /api/generate": { + Accepts: x402http.PaymentOptions{ + { + Scheme: "upto", + Price: "$0.10", + Network: "eip155:84532", + PayTo: "0xYourAddress", + }, + }, + Description: "AI text generation billed by usage", + }, + } + + mux.HandleFunc("GET /api/generate", func(w http.ResponseWriter, r *http.Request) { + actualUsage := computeActualCost() + nethttpmw.SetSettlementOverrides(w, &x402.SettlementOverrides{ + Amount: fmt.Sprintf("%d", actualUsage), + }) + _ = json.NewEncoder(w).Encode(map[string]string{"result": "..."}) + }) + ``` + + + ```python + from fastapi import FastAPI, Response + + from x402.http import FacilitatorConfig, HTTPFacilitatorClient, PaymentOption + from x402.http.middleware.fastapi import PaymentMiddlewareASGI, set_settlement_overrides + from x402.http.types import RouteConfig + from x402.mechanisms.evm.upto import UptoEvmServerScheme + from x402.server import x402ResourceServer + + app = FastAPI() + facilitator = HTTPFacilitatorClient(FacilitatorConfig(url="https://x402.org/facilitator")) + + server = x402ResourceServer(facilitator) + server.register("eip155:84532", UptoEvmServerScheme()) + + routes = { + "GET /api/generate": RouteConfig( + accepts=[ + PaymentOption( + scheme="upto", + price="$0.10", + network="eip155:84532", + pay_to="0xYourAddress", + ) + ], + description="AI text generation billed by usage", + ) + } + + app.add_middleware(PaymentMiddlewareASGI, routes=routes, server=server) + + @app.get("/api/generate") + async def generate(response: Response) -> dict[str, str]: + actual_usage = compute_actual_cost() + set_settlement_overrides(response, {"amount": str(actual_usage)}) + return {"result": "..."} + ``` + + + +### Client Setup + +Register `UptoEvmScheme` alongside `ExactEvmScheme` if your client may call both fixed-price and usage-based EVM resources. + + + + ```typescript + import { x402Client } from "@x402/core/client"; + import { ExactEvmScheme } from "@x402/evm/exact/client"; + import { UptoEvmScheme } from "@x402/evm/upto/client"; + import { privateKeyToAccount } from "viem/accounts"; + + const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`); + + const client = new x402Client(); + client.register("eip155:*", new ExactEvmScheme(signer)); + client.register("eip155:*", new UptoEvmScheme(signer)); + ``` + + + ```go + import ( + x402 "github.com/x402-foundation/x402/go" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" + ) + + evmSigner, err := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("EVM_PRIVATE_KEY")) + if err != nil { + log.Fatal(err) + } + + x402Client := x402.Newx402Client(). + Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, nil)). + Register("eip155:*", uptoevm.NewUptoEvmScheme(evmSigner, nil)) + ``` + + + ```python + import os + + from eth_account import Account + + from x402 import x402Client + from x402.mechanisms.evm import EthAccountSigner + from x402.mechanisms.evm.exact.register import register_exact_evm_client + from x402.mechanisms.evm.upto import UptoEvmScheme + + account = Account.from_key(os.getenv("EVM_PRIVATE_KEY")) + signer = EthAccountSigner(account) + + client = x402Client() + register_exact_evm_client(client, signer) + client.register("eip155:*", UptoEvmScheme(signer)) + ``` + + + +### Settlement Override Formats + +`amount` can be expressed as: + +| Format | Example | Meaning | +|--------|---------|---------| +| Raw atomic units | `"50000"` | Settle exactly 50,000 token base units | +| Percentage | `"50%"` | Settle 50% of the route maximum | +| Dollar price | `"$0.05"` | Convert a dollar-denominated route price to base units | + +Setting the amount to `"0"` means no charge for that request. + +### EVM Implementation + +`upto` uses Permit2 because the settled amount is not known when the buyer signs. The facilitator advertises a `facilitatorAddress` in the payment requirements, and the client binds the authorization to that facilitator. + +### Examples + +* [TypeScript server example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/upto) +* [Go server example](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/upto) + +### Specs + +* [`upto` spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/upto/scheme_upto.md) +* [`upto` EVM spec](https://github.com/x402-foundation/x402/blob/main/specs/schemes/upto/scheme_upto_evm.md) + +### See Also + +* [Payment schemes overview](/schemes/overview) +* [Exact](/schemes/exact) +* [Batch settlement](/schemes/batch-settlement) diff --git a/docs/sdk-features.md b/docs/sdk-features.md index 1d94740a15..77b2a87fb3 100644 --- a/docs/sdk-features.md +++ b/docs/sdk-features.md @@ -19,7 +19,7 @@ This page tracks which features are implemented in each SDK (TypeScript, Go, Pyt | Role | TypeScript | Go | Python | |------|------------|-----|--------| -| Server | Express, Hono, Next.js | Gin, net/http | FastAPI, Flask | +| Server | Express, Hono, Next.js, Fastify | Gin, net/http, Echo | FastAPI, Flask | | Client | Fetch, Axios | net/http | httpx, requests | ## Networks @@ -28,26 +28,35 @@ This page tracks which features are implemented in each SDK (TypeScript, Go, Pyt |---------|------------|-----|--------| | evm (EIP-155) | ✅ | ✅ | ✅ | | svm (Solana) | ✅ | ✅ | ✅ | +| tvm (TON) | ❌ | ❌ | ✅ | +| avm (Algorand) | ✅ | ❌ | ❌ | | stellar | ✅ | ❌ | ❌ | | aptos | ✅ | ❌ | ❌ | +| hedera | ✅ | ❌ | ❌ | ## Mechanisms -| Mechanism | TypeScript | Go | Python | -|-----------|------------|-----|--------| -| exact/evm (EIP-3009) | ✅ | ✅ | ✅ | -| exact/evm (Permit2) | ✅ | ✅ | ✅ | -| exact/svm (SPL) | ✅ | ✅ | ✅ | -| exact/stellar (Soroban) | ✅ | ❌ | ❌ | -| exact/aptos (Fungible Assets) | ✅ | ❌ | ❌ | -| upto/evm (Permit2) | ✅ | ✅ | ❌ | +| Scheme | Network | `assetTransferMethod` | TypeScript | Go | Python | +|--------|---------|------------------------|------------|-----|--------| +| exact | evm | `eip3009` | ✅ | ✅ | ✅ | +| exact | evm | `permit2` | ✅ | ✅ | ✅ | +| exact | svm | - | ✅ | ✅ | ✅ | +| exact | avm | - | ✅ | ❌ | ❌ | +| exact | stellar | - | ✅ | ❌ | ❌ | +| exact | aptos | - | ✅ | ❌ | ❌ | +| exact | hedera | - | ✅ | ❌ | ❌ | +| exact | tvm | - | ❌ | ❌ | ✅ | +| upto | evm | `permit2` | ✅ | ✅ | ✅ | +| batch-settlement | evm | `eip3009` | ✅ | ✅ | ❌ | +| batch-settlement | evm | `permit2` | ✅ | ✅ | ❌ | ## Extensions | Extension | TypeScript | Go | Python | |-----------|------------|-----|--------| | bazaar (server) | ✅ | ✅ | ✅ | -| bazaar (facilitator client) | ✅ | ✅ | ✅ | +| bazaar (facilitator client - list) | ✅ | ✅ | ✅ | +| bazaar (facilitator client - search) | ✅ | ✅ | ✅ | | sign-in-with-x | ✅ | ❌ | ❌ | | payment-identifier | ✅ | ✅ | ✅ | | offer-receipt | ✅ | ❌ | ❌ | @@ -61,6 +70,7 @@ This page tracks which features are implemented in each SDK (TypeScript, Go, Pyt | onBeforePaymentCreation | ✅ | ✅ | ✅ | | onAfterPaymentCreation | ✅ | ✅ | ✅ | | onPaymentCreationFailure | ✅ | ✅ | ✅ | +| onPaymentResponse | ✅ | ✅ | ❌ | | onPaymentRequired (HTTP) | ✅ | ❌ | ❌ | ## Server Hooks @@ -73,6 +83,7 @@ This page tracks which features are implemented in each SDK (TypeScript, Go, Pyt | onBeforeSettle | ✅ | ✅ | ✅ | | onAfterSettle | ✅ | ✅ | ✅ | | onSettleFailure | ✅ | ✅ | ✅ | +| onVerifiedPaymentCanceled | ✅ | ✅ | ❌ | | onProtectedRequest (HTTP) | ✅ | ✅ | ❌ | ## Facilitator Hooks @@ -94,6 +105,21 @@ This page tracks which features are implemented in each SDK (TypeScript, Go, Pyt | enrichPaymentRequiredResponse | ✅ | ❌ | ❌ | | enrichSettlementResponse | ✅ | ❌ | ❌ | +## Hook Adapter Features + +| Feature | TypeScript | Go | Python | +|---------|------------|-----|--------| +| Scheme-level lifecycle hook adapters | ✅ | ✅ | ❌ | +| Extension-level lifecycle hook adapters | ✅ | ✅ | ❌ | + +## MCP (Model Context Protocol) + +| Feature | TypeScript | Go | Python | +|---------|------------|-----|--------| +| MCP server payment wrapper | ✅ | ✅ | ✅ | +| MCP client (auto-pay tools) | ✅ | ✅ | ✅ | +| Bazaar discovery for MCP tools | ✅ | ✅ | ✅ | + ## HTTP Server Features | Feature | TypeScript | Go | Python | diff --git a/e2e/.env-local b/e2e/.env-local index 77e443bb11..4fa9f13ddf 100644 --- a/e2e/.env-local +++ b/e2e/.env-local @@ -1,10 +1,18 @@ # E2E Test Configuration SERVER_EVM_ADDRESS= SERVER_SVM_ADDRESS= +SERVER_AVM_ADDRESS= SERVER_STELLAR_ADDRESS= +SERVER_HEDERA_ADDRESS= CLIENT_EVM_PRIVATE_KEY= CLIENT_SVM_PRIVATE_KEY= +CLIENT_AVM_PRIVATE_KEY= CLIENT_STELLAR_PRIVATE_KEY= +CLIENT_HEDERA_ACCOUNT_ID= +CLIENT_HEDERA_PRIVATE_KEY= FACILITATOR_EVM_PRIVATE_KEY= FACILITATOR_SVM_PRIVATE_KEY= +FACILITATOR_AVM_PRIVATE_KEY= FACILITATOR_STELLAR_PRIVATE_KEY= +FACILITATOR_HEDERA_ACCOUNT_ID= +FACILITATOR_HEDERA_PRIVATE_KEY= diff --git a/e2e/README.md b/e2e/README.md index 9a54295429..bc4f44dfd7 100644 --- a/e2e/README.md +++ b/e2e/README.md @@ -48,11 +48,12 @@ pnpm test ``` Launches an interactive CLI where you can select: -- **Facilitators** - Payment verification/settlement services (Go, TypeScript) +- **Facilitators** - Payment verification/settlement services (Go, TypeScript, Python) - **Servers** - Protected endpoints requiring payment (Express, Gin, Hono, Next.js, FastAPI, Flask, etc.) - **Clients** - Payment-capable HTTP clients (axios, fetch, httpx, requests, etc.) - **Extensions** - Additional features like Bazaar discovery -- **Protocols** - EVM, SVM, and/or Aptos networks +- **Protocols** - EVM, SVM, Aptos, Hedera, Stellar, and/or TVM networks +- **Payment schemes** (when multiple apply) - `exact`, `upto`, or `batch-settlement` Every valid combination of your selections will be tested. For example, selecting 2 facilitators, 3 servers, and 2 clients will generate and run all compatible test scenarios. @@ -114,19 +115,50 @@ Required environment variables (set in `.env` file): CLIENT_EVM_PRIVATE_KEY=0x... # EVM private key for client payments CLIENT_SVM_PRIVATE_KEY=... # Solana private key for client payments CLIENT_APTOS_PRIVATE_KEY=... # Aptos private key for client payments (hex string) +CLIENT_HEDERA_ACCOUNT_ID=0.0.... # Hedera account id for client payments +CLIENT_HEDERA_PRIVATE_KEY=0x... # Hedera ECDSA private key for client payments CLIENT_STELLAR_PRIVATE_KEY=... # Stellar private key for client payments +CLIENT_TVM_PRIVATE_KEY=... # TVM private key for client payments # Server payment addresses SERVER_EVM_ADDRESS=0x... # Where servers receive EVM payments SERVER_SVM_ADDRESS=... # Where servers receive Solana payments SERVER_APTOS_ADDRESS=0x... # Where servers receive Aptos payments +SERVER_HEDERA_ADDRESS=0.0.... # Where servers receive Hedera payments SERVER_STELLAR_ADDRESS=... # Where servers receive Stellar payments +SERVER_TVM_ADDRESS=... # Where servers receive TVM payments # Facilitator wallets (⚠️ TEST WALLETS ONLY — used to fund/drain client between tests) FACILITATOR_EVM_PRIVATE_KEY=0x... # EVM private key for facilitator FACILITATOR_SVM_PRIVATE_KEY=... # Solana private key for facilitator FACILITATOR_APTOS_PRIVATE_KEY=... # Aptos private key for facilitator (hex string) +FACILITATOR_HEDERA_ACCOUNT_ID=0.0... # Hedera fee payer account id for facilitator +FACILITATOR_HEDERA_PRIVATE_KEY=0x... # Hedera ECDSA private key for facilitator FACILITATOR_STELLAR_PRIVATE_KEY=... # Stellar private key for facilitator +FACILITATOR_TVM_PRIVATE_KEY=... # TVM private key for facilitator + +# TVM support +TVM_PROVIDER=tonapi # Optional: toncenter (default) or tonapi +TONAPI_API_KEY=... # Required when TVM_PROVIDER=tonapi +TONAPI_BASE_URL=... # Optional custom TonAPI base URL +TONCENTER_API_KEY=... # Recommended when TVM_PROVIDER=toncenter +``` + +To run Python SDK TVM e2e scenarios through TonAPI instead of Toncenter: + +```bash +cd e2e +TVM_PROVIDER=tonapi \ +TONAPI_API_KEY= \ +pnpm test --testnet --families=tvm --facilitators=python --clients=httpx,requests --servers=fastapi,flask --min -v +``` + +Optional environment variables (batch-settlement scheme): + +```bash +SERVER_EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY=0x... # server-side self-managed claim/refund signer +CLIENT_EVM_VOUCHER_SIGNER_PRIVATE_KEY=0x... # EOA the client uses to sign vouchers +BATCH_SETTLEMENT_RECOVERY=true # test client state-loss recovery scenario (default: true) ``` ### Account Setup Instructions @@ -140,6 +172,12 @@ You need **three separate Stellar accounts** for e2e tests (client, server, faci 3. Get testnet USDC from [Circle Faucet](https://faucet.circle.com/) (select Stellar network). > **Note:** The facilitator account only needs XLM (step 1). Client and server accounts need all three steps. +##### TON testnet funding for TVM e2e and examples + +- **Testnet TON**: use [@testgiver_ton_bot](https://t.me/testgiver_ton_bot) to fund the facilitator and payer wallets with TON for relay fees. The facilitator wallet must hold **at least 1.1 TON** before running tests. +- **Testnet USDT**: the payer wallet also needs testnet USDT. Open the [TON transfer link](https://app.tonkeeper.com/transfer/kQDNUDJC0iQvJoZp0ml-YteL1NtTXKphU03CTI5v4VtBhGYs?amount=49000000&bin=te6cckEBAQEAFgAAKClXdJkAAAAAAAAAAAAAAAAAmJaAhDUekg) or scan the QR code below to get them. The facilitator wallet only needs TON. +- **Note:** the facilitator uses a highload-wallet-v3 account, so the facilitator's wallet address differs from your W5 address — fund the highload-v3 address, not the W5 one derived from the same key. + QR code for the testnet USDT transfer link ## Example Session @@ -153,7 +191,7 @@ $ pnpm test --min ✔ Select servers › express, hono, legacy-express ✔ Select clients › axios, fetch, httpx ✔ Select extensions › bazaar -✔ Select protocol families › EVM, SVM, Aptos, Stellar +✔ Select protocol families › EVM, SVM, Aptos, Hedera, Stellar, TVM 📊 Coverage-Based Minimization Total scenarios: 156 diff --git a/e2e/clients/axios/index.ts b/e2e/clients/axios/index.ts index 31f00ddfca..5b16a67e9f 100644 --- a/e2e/clients/axios/index.ts +++ b/e2e/clients/axios/index.ts @@ -5,15 +5,23 @@ import { createPublicClient, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { base, baseSepolia } from "viem/chains"; import { ExactEvmScheme, type ExactEvmSchemeOptions } from "@x402/evm/exact/client"; -import { UptoEvmScheme as UptoEvmClientScheme, type UptoEvmSchemeOptions } from "@x402/evm/upto/client"; +import { + UptoEvmScheme as UptoEvmClientScheme, + type UptoEvmSchemeOptions, +} from "@x402/evm/upto/client"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/client"; import { ExactEvmSchemeV1 } from "@x402/evm/v1"; import { toClientEvmSigner } from "@x402/evm"; import { ExactSvmScheme } from "@x402/svm/exact/client"; import { ExactSvmSchemeV1 } from "@x402/svm/v1"; import { ExactAptosScheme } from "@x402/aptos/exact/client"; import { Account, Ed25519PrivateKey, PrivateKey, PrivateKeyVariants } from "@aptos-labs/ts-sdk"; +import { createClientHederaSigner, PrivateKey as HederaPrivateKey } from "@x402/hedera"; +import { ExactHederaScheme } from "@x402/hedera/exact/client"; import { ExactStellarScheme } from "@x402/stellar/exact/client"; import { createEd25519Signer, type Ed25519Signer } from "@x402/stellar"; +import { ExactAvmScheme as ExactAvmClientScheme } from "@x402/avm/exact/client"; +import { toClientAvmSigner } from "@x402/avm"; import { base58 } from "@scure/base"; import { createKeyPairSignerFromBytes } from "@solana/kit"; import { x402Client } from "@x402/core/client"; @@ -47,6 +55,23 @@ const uptoSchemeOptions: UptoEvmSchemeOptions | undefined = process.env.EVM_RPC_ ? { rpcUrl: process.env.EVM_RPC_URL } : undefined; +// Batch-settlement scheme uses a per-scenario salt (CHANNEL_SALT) so concurrent +// e2e runs don't collide on the same on-chain channel id. An optional voucher +// signer (EVM_VOUCHER_SIGNER_PRIVATE_KEY) exercises the alt-EOA voucher branch +// while deposits keep using the main client signer. +const channelSalt = process.env.CHANNEL_SALT as `0x${string}` | undefined; +const voucherSignerKey = process.env.EVM_VOUCHER_SIGNER_PRIVATE_KEY as + | `0x${string}` + | undefined; +const voucherSigner = voucherSignerKey + ? toClientEvmSigner(privateKeyToAccount(voucherSignerKey), publicClient) + : undefined; +const batchSettlementOptions = + channelSalt || voucherSigner + ? { ...(channelSalt ? { salt: channelSalt } : {}), ...(voucherSigner ? { voucherSigner } : {}) } + : undefined; +const batchSettlementScheme = new BatchSettlementEvmScheme(evmSigner, batchSettlementOptions); + // Initialize Aptos signer if key is provided let aptosAccount: Account | undefined; if (process.env.APTOS_PRIVATE_KEY) { @@ -58,15 +83,35 @@ if (process.env.APTOS_PRIVATE_KEY) { aptosAccount = Account.fromPrivateKey({ privateKey: aptosPrivateKey }); } +// Initialize Hedera signer if account + key are provided +let hederaClientSigner: ReturnType | undefined; +if (process.env.HEDERA_ACCOUNT_ID && process.env.HEDERA_PRIVATE_KEY) { + hederaClientSigner = createClientHederaSigner( + process.env.HEDERA_ACCOUNT_ID, + HederaPrivateKey.fromStringECDSA(process.env.HEDERA_PRIVATE_KEY), + { + network: process.env.HEDERA_NETWORK || "hedera:testnet", + nodeUrl: process.env.HEDERA_NODE_URL || undefined, + }, + ); +} + // Initialize Stellar signer if key is provided let stellarSigner: Ed25519Signer | undefined; if (process.env.STELLAR_PRIVATE_KEY) { stellarSigner = createEd25519Signer(process.env.STELLAR_PRIVATE_KEY); } +// Initialize AVM signer if key is provided +let avmSigner: ReturnType | undefined; +if (process.env.AVM_PRIVATE_KEY) { + avmSigner = toClientAvmSigner(process.env.AVM_PRIVATE_KEY); +} + const client = new x402Client() .register("eip155:*", new ExactEvmScheme(evmSigner, evmSchemeOptions)) .register("eip155:*", new UptoEvmClientScheme(evmSigner, uptoSchemeOptions)) + .register("eip155:*", batchSettlementScheme) .registerV1("base-sepolia", new ExactEvmSchemeV1(evmSigner)) .registerV1("base", new ExactEvmSchemeV1(evmSigner)) .register("solana:*", new ExactSvmScheme(svmSigner)) @@ -75,50 +120,131 @@ const client = new x402Client() if (aptosAccount) { client.register("aptos:*", new ExactAptosScheme(aptosAccount)); } +if (hederaClientSigner) { + client.register("hedera:*", new ExactHederaScheme(hederaClientSigner)); +} if (stellarSigner) { client.register("stellar:*", new ExactStellarScheme(stellarSigner)); } +if (avmSigner) { + client.register("algorand:*", new ExactAvmClientScheme(avmSigner)); +} const axiosWithPayment = wrapAxiosWithPayment(axios.create(), client); -axiosWithPayment - .get(url) - .then(async (response) => { - const data = response.data; - // Check both v2 (PAYMENT-RESPONSE) and v1 (X-PAYMENT-RESPONSE) headers - const paymentResponse = - response.headers["payment-response"] || response.headers["x-payment-response"]; - - if (!paymentResponse) { - // No payment was required - const result = { - success: true, - data: data, - status_code: response.status, - }; - console.log(JSON.stringify(result)); - process.exit(0); - return; - } - - const decodedPaymentResponse = decodePaymentResponseHeader(paymentResponse); - - const result = { - success: decodedPaymentResponse.success, - data: data, - status_code: response.status, - payment_response: decodedPaymentResponse, - }; +const batchSettlementPhase = process.env.BATCH_SETTLEMENT_PHASE as + | "initial" + | "recovery-refund" + | "full" + | undefined; + +/** + * Issues a single paid request and returns the parsed result. + * + * @returns Structured result with response data and decoded payment-response. + */ +interface RequestResult { + success: boolean; + data: unknown; + status_code: number; + payment_response?: any; +} + +async function issueRequest(): Promise { + const response = await axiosWithPayment.get(url); + const paymentResponseHeader = + response.headers["payment-response"] || response.headers["x-payment-response"]; + + if (!paymentResponseHeader) { + return { success: true, data: response.data, status_code: response.status }; + } + + const decodedPaymentResponse = decodePaymentResponseHeader(paymentResponseHeader); + return { + success: decodedPaymentResponse.success, + data: response.data, + status_code: response.status, + payment_response: decodedPaymentResponse, + }; +} + +function aggregateBatchResult( + phase: "initial" | "recovery-refund" | "full", + results: RequestResult[], + details: Record, +) { + const last = results[results.length - 1]!; + return { + success: results.every(result => result.success), + data: { + batchSettlement: { + phase, + requests: results, + ...details, + }, + }, + status_code: last.status_code, + payment_response: last.payment_response, + }; +} - // Output structured result as JSON for proxy to parse +try { + if (!batchSettlementPhase) { + const result = await issueRequest(); console.log(JSON.stringify(result)); process.exit(0); - }) - .catch((error) => { - console.error(JSON.stringify({ + } + + if (batchSettlementPhase === "initial") { + const deposit = await issueRequest(); + const voucher = await issueRequest(); + console.log(JSON.stringify(aggregateBatchResult("initial", [deposit, voucher], { deposit, voucher }))); + process.exit(0); + } + + if (batchSettlementPhase === "recovery-refund") { + const recoveryVoucher = await issueRequest(); + const refundSettle = await batchSettlementScheme.refund(url); + const refund = { + success: refundSettle.success, + data: { refund: true }, + status_code: 200, + payment_response: refundSettle, + }; + console.log( + JSON.stringify( + aggregateBatchResult("recovery-refund", [recoveryVoucher, refund], { + recoveryVoucher, + refund, + }), + ), + ); + process.exit(0); + } + + if (batchSettlementPhase === "full") { + const deposit = await issueRequest(); + const voucher = await issueRequest(); + const refundSettle = await batchSettlementScheme.refund(url); + const refund = { + success: refundSettle.success, + data: { refund: true }, + status_code: 200, + payment_response: refundSettle, + }; + console.log(JSON.stringify(aggregateBatchResult("full", [deposit, voucher, refund], { deposit, voucher, refund }))); + process.exit(0); + } + + throw new Error(`Unknown BATCH_SETTLEMENT_PHASE: ${batchSettlementPhase}`); +} catch (error: unknown) { + const err = error as { message?: string; response?: { status?: number } }; + console.error( + JSON.stringify({ success: false, - error: error.message || "Request failed", - status_code: error.response?.status || 500, - })); - process.exit(1); - }); + error: err.message || "Request failed", + status_code: err.response?.status || 500, + }), + ); + process.exit(1); +} diff --git a/e2e/clients/axios/package.json b/e2e/clients/axios/package.json index 6c97ae132c..138ab9ca3a 100644 --- a/e2e/clients/axios/package.json +++ b/e2e/clients/axios/package.json @@ -14,17 +14,20 @@ "@scure/base": "^1.2.6", "@solana/kit": "^6.1.0", "@x402/aptos": "workspace:*", + "@x402/avm": "workspace:*", "@x402/axios": "workspace:*", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", + "@x402/hedera": "workspace:*", "@x402/stellar": "workspace:*", "@x402/svm": "workspace:*", "axios": "^1.7.9", "dotenv": "^16.4.7", - "viem": "^2.21.26" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -32,7 +35,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } -} \ No newline at end of file +} diff --git a/e2e/clients/axios/test.config.json b/e2e/clients/axios/test.config.json index ff7b7accbf..52aa785cd9 100644 --- a/e2e/clients/axios/test.config.json +++ b/e2e/clients/axios/test.config.json @@ -5,18 +5,24 @@ "protocolFamilies": [ "evm", "svm", + "avm", "aptos", + "hedera", "stellar" ], "x402Versions": [ 1, 2 ], + "schemes": [ + "exact", + "upto", + "batch-settlement" + ], "evm": { - "transferMethods": [ + "assetTransferMethods": [ "eip3009", - "permit2", - "upto" + "permit2" ] }, "extensions": [ @@ -31,8 +37,17 @@ "ENDPOINT_PATH" ], "optional": [ + "AVM_PRIVATE_KEY", "APTOS_PRIVATE_KEY", - "STELLAR_PRIVATE_KEY" + "HEDERA_ACCOUNT_ID", + "HEDERA_PRIVATE_KEY", + "HEDERA_NETWORK", + "HEDERA_NODE_URL", + "STELLAR_PRIVATE_KEY", + "CHANNEL_SALT", + "BATCH_SETTLEMENT_PHASE", + "BATCH_SETTLEMENT_RECOVERY", + "EVM_VOUCHER_SIGNER_PRIVATE_KEY" ] } } \ No newline at end of file diff --git a/e2e/clients/fetch/index.ts b/e2e/clients/fetch/index.ts index e88320d3d5..da3164a42f 100644 --- a/e2e/clients/fetch/index.ts +++ b/e2e/clients/fetch/index.ts @@ -4,15 +4,23 @@ import { createPublicClient, http } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { base, baseSepolia } from "viem/chains"; import { ExactEvmScheme, type ExactEvmSchemeOptions } from "@x402/evm/exact/client"; -import { UptoEvmScheme as UptoEvmClientScheme, type UptoEvmSchemeOptions } from "@x402/evm/upto/client"; +import { + UptoEvmScheme as UptoEvmClientScheme, + type UptoEvmSchemeOptions, +} from "@x402/evm/upto/client"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/client"; import { ExactEvmSchemeV1 } from "@x402/evm/v1"; import { toClientEvmSigner } from "@x402/evm"; import { ExactSvmScheme } from "@x402/svm/exact/client"; import { ExactSvmSchemeV1 } from "@x402/svm/v1"; import { ExactAptosScheme } from "@x402/aptos/exact/client"; import { Account, Ed25519PrivateKey, PrivateKey, PrivateKeyVariants } from "@aptos-labs/ts-sdk"; +import { createClientHederaSigner, PrivateKey as HederaPrivateKey } from "@x402/hedera"; +import { ExactHederaScheme } from "@x402/hedera/exact/client"; import { ExactStellarScheme } from "@x402/stellar/exact/client"; import { createEd25519Signer, Ed25519Signer } from "@x402/stellar"; +import { ExactAvmScheme as ExactAvmClientScheme } from "@x402/avm/exact/client"; +import { toClientAvmSigner } from "@x402/avm"; import { base58 } from "@scure/base"; import { createKeyPairSignerFromBytes } from "@solana/kit"; import { x402Client, x402HTTPClient } from "@x402/core/client"; @@ -23,7 +31,9 @@ const baseURL = process.env.RESOURCE_SERVER_URL as string; const endpointPath = process.env.ENDPOINT_PATH as string; const url = `${baseURL}${endpointPath}`; const evmAccount = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`); -const svmSigner = await createKeyPairSignerFromBytes(base58.decode(process.env.SVM_PRIVATE_KEY as string)); +const svmSigner = await createKeyPairSignerFromBytes( + base58.decode(process.env.SVM_PRIVATE_KEY as string), +); const evmNetwork = process.env.EVM_NETWORK || "eip155:84532"; const evmRpcUrl = process.env.EVM_RPC_URL; @@ -44,23 +54,63 @@ const uptoSchemeOptions: UptoEvmSchemeOptions | undefined = process.env.EVM_RPC_ ? { rpcUrl: process.env.EVM_RPC_URL } : undefined; +// Batch-settlement scheme uses a per-scenario salt (CHANNEL_SALT) so concurrent +// e2e runs don't collide on the same on-chain channel id. An optional voucher +// signer (EVM_VOUCHER_SIGNER_PRIVATE_KEY) exercises the alt-EOA voucher branch +// while deposits keep using the main client signer. +const channelSalt = process.env.CHANNEL_SALT as `0x${string}` | undefined; +const voucherSignerKey = process.env.EVM_VOUCHER_SIGNER_PRIVATE_KEY as + | `0x${string}` + | undefined; +const voucherSigner = voucherSignerKey + ? toClientEvmSigner(privateKeyToAccount(voucherSignerKey), publicClient) + : undefined; +const batchSettlementOptions = + channelSalt || voucherSigner + ? { ...(channelSalt ? { salt: channelSalt } : {}), ...(voucherSigner ? { voucherSigner } : {}) } + : undefined; +const batchSettlementScheme = new BatchSettlementEvmScheme(evmSigner, batchSettlementOptions); + // Initialize Aptos signer if key is provided let aptosAccount: Account | undefined; if (process.env.APTOS_PRIVATE_KEY) { - const formattedKey = PrivateKey.formatPrivateKey(process.env.APTOS_PRIVATE_KEY, PrivateKeyVariants.Ed25519); + const formattedKey = PrivateKey.formatPrivateKey( + process.env.APTOS_PRIVATE_KEY, + PrivateKeyVariants.Ed25519, + ); const aptosPrivateKey = new Ed25519PrivateKey(formattedKey); aptosAccount = Account.fromPrivateKey({ privateKey: aptosPrivateKey }); } +// Initialize Hedera signer if account + key are provided +let hederaClientSigner: ReturnType | undefined; +if (process.env.HEDERA_ACCOUNT_ID && process.env.HEDERA_PRIVATE_KEY) { + hederaClientSigner = createClientHederaSigner( + process.env.HEDERA_ACCOUNT_ID, + HederaPrivateKey.fromStringECDSA(process.env.HEDERA_PRIVATE_KEY), + { + network: process.env.HEDERA_NETWORK || "hedera:testnet", + nodeUrl: process.env.HEDERA_NODE_URL || undefined, + }, + ); +} + // Initialize Stellar signer if key is provided let stellarSigner: Ed25519Signer | undefined; if (process.env.STELLAR_PRIVATE_KEY) { stellarSigner = createEd25519Signer(process.env.STELLAR_PRIVATE_KEY); } +// Initialize AVM signer if key is provided +let avmSigner: ReturnType | undefined; +if (process.env.AVM_PRIVATE_KEY) { + avmSigner = toClientAvmSigner(process.env.AVM_PRIVATE_KEY); +} + const client = new x402Client() .register("eip155:*", new ExactEvmScheme(evmSigner, evmSchemeOptions)) .register("eip155:*", new UptoEvmClientScheme(evmSigner, uptoSchemeOptions)) + .register("eip155:*", batchSettlementScheme) .registerV1("base-sepolia", new ExactEvmSchemeV1(evmSigner)) .registerV1("base", new ExactEvmSchemeV1(evmSigner)) .register("solana:*", new ExactSvmScheme(svmSigner)) @@ -69,38 +119,119 @@ const client = new x402Client() if (aptosAccount) { client.register("aptos:*", new ExactAptosScheme(aptosAccount)); } +if (hederaClientSigner) { + client.register("hedera:*", new ExactHederaScheme(hederaClientSigner)); +} if (stellarSigner) { client.register("stellar:*", new ExactStellarScheme(stellarSigner)); } +if (avmSigner) { + client.register("algorand:*", new ExactAvmClientScheme(avmSigner)); +} const fetchWithPayment = wrapFetchWithPayment(fetch, client); +const httpClient = new x402HTTPClient(client); -fetchWithPayment(url, { - method: "GET", -}).then(async response => { +const batchSettlementPhase = process.env.BATCH_SETTLEMENT_PHASE as + | "initial" + | "recovery-refund" + | "full" + | undefined; + +/** + * Issues a single paid request and returns the parsed result. + * + * @returns Structured result with response data and decoded payment-response. + */ +interface RequestResult { + success: boolean; + data: unknown; + status_code: number; + payment_response?: any; +} + +async function issueRequest(): Promise { + const response = await fetchWithPayment(url, { method: "GET" }); const data = await response.json(); - const paymentResponse = new x402HTTPClient(client).getPaymentSettleResponse((name) => response.headers.get(name)); + const paymentResponse = httpClient.getPaymentSettleResponse(name => response.headers.get(name)); if (!paymentResponse) { - // No payment was required - const result = { - success: true, - data: data, - status_code: response.status, - }; - console.log(JSON.stringify(result)); - process.exit(0); - return; + return { success: true, data, status_code: response.status }; } - const result = { + return { success: paymentResponse.success, - data: data, + data, status_code: response.status, payment_response: paymentResponse, }; +} + +function aggregateBatchResult( + phase: "initial" | "recovery-refund" | "full", + results: RequestResult[], + details: Record, +) { + const last = results[results.length - 1]!; + return { + success: results.every(result => result.success), + data: { + batchSettlement: { + phase, + requests: results, + ...details, + }, + }, + status_code: last.status_code, + payment_response: last.payment_response, + }; +} - // Output structured result as JSON for proxy to parse +if (!batchSettlementPhase) { + const result = await issueRequest(); console.log(JSON.stringify(result)); process.exit(0); -}); +} + +if (batchSettlementPhase === "initial") { + const deposit = await issueRequest(); + const voucher = await issueRequest(); + console.log(JSON.stringify(aggregateBatchResult("initial", [deposit, voucher], { deposit, voucher }))); + process.exit(0); +} + +if (batchSettlementPhase === "recovery-refund") { + const recoveryVoucher = await issueRequest(); + const refundSettle = await batchSettlementScheme.refund(url); + const refund = { + success: refundSettle.success, + data: { refund: true }, + status_code: 200, + payment_response: refundSettle, + }; + console.log( + JSON.stringify( + aggregateBatchResult("recovery-refund", [recoveryVoucher, refund], { + recoveryVoucher, + refund, + }), + ), + ); + process.exit(0); +} + +if (batchSettlementPhase === "full") { + const deposit = await issueRequest(); + const voucher = await issueRequest(); + const refundSettle = await batchSettlementScheme.refund(url); + const refund = { + success: refundSettle.success, + data: { refund: true }, + status_code: 200, + payment_response: refundSettle, + }; + console.log(JSON.stringify(aggregateBatchResult("full", [deposit, voucher, refund], { deposit, voucher, refund }))); + process.exit(0); +} + +throw new Error(`Unknown BATCH_SETTLEMENT_PHASE: ${batchSettlementPhase}`); diff --git a/e2e/clients/fetch/package.json b/e2e/clients/fetch/package.json index ae2c29cc60..c2faf3baff 100644 --- a/e2e/clients/fetch/package.json +++ b/e2e/clients/fetch/package.json @@ -14,17 +14,19 @@ "@scure/base": "^1.2.6", "@solana/kit": "^6.1.0", "@x402/aptos": "workspace:*", + "@x402/avm": "workspace:*", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", "@x402/fetch": "workspace:*", + "@x402/hedera": "workspace:*", "@x402/stellar": "workspace:*", "@x402/svm": "workspace:*", - "axios": "^1.7.9", "dotenv": "^16.4.7", - "viem": "^2.21.26" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -32,7 +34,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } -} \ No newline at end of file +} diff --git a/e2e/clients/fetch/test.config.json b/e2e/clients/fetch/test.config.json index 42b9be92a8..debd8acf1b 100644 --- a/e2e/clients/fetch/test.config.json +++ b/e2e/clients/fetch/test.config.json @@ -5,18 +5,24 @@ "protocolFamilies": [ "evm", "svm", + "avm", "aptos", + "hedera", "stellar" ], "x402Versions": [ 1, 2 ], + "schemes": [ + "exact", + "upto", + "batch-settlement" + ], "evm": { - "transferMethods": [ + "assetTransferMethods": [ "eip3009", - "permit2", - "upto" + "permit2" ] }, "extensions": [ @@ -31,8 +37,17 @@ "ENDPOINT_PATH" ], "optional": [ + "AVM_PRIVATE_KEY", "APTOS_PRIVATE_KEY", - "STELLAR_PRIVATE_KEY" + "HEDERA_ACCOUNT_ID", + "HEDERA_PRIVATE_KEY", + "HEDERA_NETWORK", + "HEDERA_NODE_URL", + "STELLAR_PRIVATE_KEY", + "CHANNEL_SALT", + "BATCH_SETTLEMENT_PHASE", + "BATCH_SETTLEMENT_RECOVERY", + "EVM_VOUCHER_SIGNER_PRIVATE_KEY" ] } } diff --git a/e2e/clients/go-http/README.md b/e2e/clients/go-http/README.md index 9d4d019f2c..6e06ed6ed8 100644 --- a/e2e/clients/go-http/README.md +++ b/e2e/clients/go-http/README.md @@ -24,12 +24,12 @@ This client demonstrates and tests the Go x402 HTTP client with both EVM and SVM ```go import ( - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - "github.com/coinbase/x402/go/mechanisms/evm" - evmv1 "github.com/coinbase/x402/go/mechanisms/evm/exact/v1" - "github.com/coinbase/x402/go/mechanisms/svm" - svmv1 "github.com/coinbase/x402/go/mechanisms/svm/exact/v1" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/mechanisms/evm" + evmv1 "github.com/x402-foundation/x402/go/mechanisms/evm/exact/v1" + "github.com/x402-foundation/x402/go/mechanisms/svm" + svmv1 "github.com/x402-foundation/x402/go/mechanisms/svm/exact/v1" ) // Create x402 client with direct registration @@ -135,9 +135,9 @@ export SVM_PRIVATE_KEY="..." ## Dependencies -- `github.com/coinbase/x402/go` - Core x402 protocol -- `github.com/coinbase/x402/go/http` - HTTP integration -- `github.com/coinbase/x402/go/mechanisms/evm` - EVM mechanisms -- `github.com/coinbase/x402/go/mechanisms/svm` - SVM mechanisms +- `github.com/x402-foundation/x402/go` - Core x402 protocol +- `github.com/x402-foundation/x402/go/http` - HTTP integration +- `github.com/x402-foundation/x402/go/mechanisms/evm` - EVM mechanisms +- `github.com/x402-foundation/x402/go/mechanisms/svm` - SVM mechanisms - `github.com/ethereum/go-ethereum` - Ethereum Go library - `github.com/gagliardetto/solana-go` - Solana Go library diff --git a/e2e/clients/go-http/go.mod b/e2e/clients/go-http/go.mod index be39d8a56e..29bb103fb8 100644 --- a/e2e/clients/go-http/go.mod +++ b/e2e/clients/go-http/go.mod @@ -1,12 +1,12 @@ -module github.com/coinbase/x402-go/e2e/clients/go-http +module github.com/x402-foundation/x402-go/e2e/clients/go-http go 1.24.0 toolchain go1.24.1 require ( - github.com/coinbase/x402/go v0.0.0 github.com/ethereum/go-ethereum v1.16.7 + github.com/x402-foundation/x402/go v0.0.0 ) require ( @@ -61,4 +61,4 @@ require ( golang.org/x/time v0.14.0 // indirect ) -replace github.com/coinbase/x402/go => ../../../go +replace github.com/x402-foundation/x402/go => ../../../go diff --git a/e2e/clients/go-http/main.go b/e2e/clients/go-http/main.go index 96ef06ab3f..a7cdb8c56b 100644 --- a/e2e/clients/go-http/main.go +++ b/e2e/clients/go-http/main.go @@ -10,19 +10,22 @@ import ( "github.com/ethereum/go-ethereum/ethclient" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - exactevm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - exactevmv1 "github.com/coinbase/x402/go/mechanisms/evm/exact/v1/client" - uptoevm "github.com/coinbase/x402/go/mechanisms/evm/upto/client" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/client" - svmv1 "github.com/coinbase/x402/go/mechanisms/svm/exact/v1/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" - svmsigners "github.com/coinbase/x402/go/signers/svm" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + batchedclient "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/client" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + exactevmv1 "github.com/x402-foundation/x402/go/mechanisms/evm/exact/v1/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/client" + svmv1 "github.com/x402-foundation/x402/go/mechanisms/svm/exact/v1/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" + svmsigners "github.com/x402-foundation/x402/go/signers/svm" ) -// Result structure for e2e test output -type Result struct { +// stepResult is the JSON shape the harness expects per request step. Matches +// the fields produced by `e2e/clients/fetch/index.ts` issueRequest(): +// {success, data, status_code, payment_response}. +type stepResult struct { Success bool `json:"success"` Data interface{} `json:"data,omitempty"` StatusCode int `json:"status_code,omitempty"` @@ -30,8 +33,17 @@ type Result struct { Error string `json:"error,omitempty"` } +// aggregateResult mirrors the TS `aggregateBatchResult()` output so the harness +// validator (`validateBatchPaymentStep` in e2e/test.ts) can read each step via +// `data.batchSettlement.{deposit,voucher,recoveryVoucher,refund}`. +type aggregateResult struct { + Success bool `json:"success"` + Data interface{} `json:"data,omitempty"` + StatusCode int `json:"status_code,omitempty"` + PaymentResponse interface{} `json:"payment_response,omitempty"` +} + func main() { - // Get configuration from environment serverURL := os.Getenv("RESOURCE_SERVER_URL") if serverURL == "" { log.Fatal("RESOURCE_SERVER_URL is required") @@ -44,15 +56,14 @@ func main() { evmPrivateKey := os.Getenv("EVM_PRIVATE_KEY") if evmPrivateKey == "" { - log.Fatal("❌ EVM_PRIVATE_KEY environment variable is required") + log.Fatal("EVM_PRIVATE_KEY environment variable is required") } svmPrivateKey := os.Getenv("SVM_PRIVATE_KEY") if svmPrivateKey == "" { - log.Fatal("❌ SVM_PRIVATE_KEY environment variable is required") + log.Fatal("SVM_PRIVATE_KEY environment variable is required") } - // Connect to EVM RPC for on-chain reads (needed for EIP-2612 extension) evmRpcURL := os.Getenv("EVM_RPC_URL") if evmRpcURL == "" { evmRpcURL = "https://sepolia.base.org" @@ -85,100 +96,202 @@ func main() { uptoConfig = &uptoevm.UptoEvmSchemeConfig{RPCURL: evmRpcURL} } + // Batch-settlement scheme uses a per-scenario salt (CHANNEL_SALT) so concurrent + // e2e runs don't collide on the same on-chain channel id. An optional voucher + // signer (EVM_VOUCHER_SIGNER_PRIVATE_KEY) exercises the alt-EOA voucher branch + // while deposits keep using the main client signer. + batchedCfg := &batchedclient.BatchSettlementEvmSchemeOptions{} + if salt := os.Getenv("CHANNEL_SALT"); salt != "" { + batchedCfg.Salt = salt + } + if voucherKey := os.Getenv("EVM_VOUCHER_SIGNER_PRIVATE_KEY"); voucherKey != "" { + voucherSigner, err := evmsigners.NewClientSignerFromPrivateKeyWithClient(voucherKey, ethClient) + if err != nil { + outputError(fmt.Sprintf("Failed to create voucher signer: %v", err)) + return + } + batchedCfg.VoucherSigner = voucherSigner + } + batchedScheme := batchedclient.NewBatchSettlementEvmScheme(evmSigner, batchedCfg) + x402Client := x402.Newx402Client(). Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, evmConfig)). Register("eip155:*", uptoevm.NewUptoEvmScheme(evmSigner, uptoConfig)). + Register("eip155:*", batchedScheme). Register("solana:*", svm.NewExactSvmScheme(svmSigner)). RegisterV1("base-sepolia", exactevmv1.NewExactEvmSchemeV1(evmSigner)). RegisterV1("base", exactevmv1.NewExactEvmSchemeV1(evmSigner)). RegisterV1("solana-devnet", svmv1.NewExactSvmSchemeV1(svmSigner)). RegisterV1("solana", svmv1.NewExactSvmSchemeV1(svmSigner)) - // Create HTTP client wrapper httpClient := x402http.Newx402HTTPClient(x402Client) - - // Wrap standard HTTP client with payment handling client := x402http.WrapHTTPClientWithPayment(http.DefaultClient, httpClient) - // Make the request url := serverURL + endpointPath ctx := context.Background() - req, err := http.NewRequestWithContext(ctx, "GET", url, nil) - if err != nil { - outputError(fmt.Sprintf("Failed to create request: %v", err)) + // Phased batch-settlement contract — mirrors TS `e2e/clients/fetch/index.ts`. + // When BATCH_SETTLEMENT_PHASE is unset, fall through to the single-request + // branch used by non-batch endpoints. + switch os.Getenv("BATCH_SETTLEMENT_PHASE") { + case "initial": + deposit := issueRequest(ctx, client, httpClient, url) + voucher := issueRequest(ctx, client, httpClient, url) + emit(aggregate("initial", []stepResult{deposit, voucher}, map[string]stepResult{ + "deposit": deposit, + "voucher": voucher, + })) + return + case "recovery-refund": + recoveryVoucher := issueRequest(ctx, client, httpClient, url) + refund := issueRefund(ctx, batchedScheme, url) + emit(aggregate("recovery-refund", []stepResult{recoveryVoucher, refund}, map[string]stepResult{ + "recoveryVoucher": recoveryVoucher, + "refund": refund, + })) + return + case "full": + deposit := issueRequest(ctx, client, httpClient, url) + voucher := issueRequest(ctx, client, httpClient, url) + refund := issueRefund(ctx, batchedScheme, url) + emit(aggregate("full", []stepResult{deposit, voucher, refund}, map[string]stepResult{ + "deposit": deposit, + "voucher": voucher, + "refund": refund, + })) + return + case "": + // Single-request scenario for non-batch endpoints. + emit(toAggregate(issueRequest(ctx, client, httpClient, url))) + return + default: + outputError(fmt.Sprintf("Unknown BATCH_SETTLEMENT_PHASE: %s", os.Getenv("BATCH_SETTLEMENT_PHASE"))) return } +} - // Perform the request (payment will be handled) +// settleResponseExtractor reads PAYMENT-RESPONSE headers and returns a typed SettleResponse. +type settleResponseExtractor interface { + GetPaymentSettleResponse(headers map[string]string) (*x402.SettleResponse, error) +} + +// issueRequest performs a single paid GET, mirroring the TS fetch client's +// issueRequest() so the per-step JSON shape matches what `validateBatchPaymentStep` +// expects. +func issueRequest( + ctx context.Context, + client *http.Client, + httpClient settleResponseExtractor, + url string, +) stepResult { + req, err := http.NewRequestWithContext(ctx, "GET", url, nil) + if err != nil { + return stepResult{Success: false, Error: fmt.Sprintf("Failed to create request: %v", err)} + } resp, err := client.Do(req) if err != nil { - outputError(fmt.Sprintf("Request failed: %v", err)) - return + return stepResult{Success: false, Error: fmt.Sprintf("Request failed: %v", err)} } defer resp.Body.Close() - // Read response body var responseData interface{} if err := json.NewDecoder(resp.Body).Decode(&responseData); err != nil { - outputError(fmt.Sprintf("Failed to decode response: %v", err)) - return + return stepResult{Success: false, Error: fmt.Sprintf("Failed to decode response: %v", err), StatusCode: resp.StatusCode} } - // Extract payment response from headers if present var paymentResponse interface{} - if paymentHeader := resp.Header.Get("PAYMENT-RESPONSE"); paymentHeader != "" { - settleResp, err := httpClient.GetPaymentSettleResponse(map[string]string{ - "PAYMENT-RESPONSE": paymentHeader, - }) - if err == nil { + if header := resp.Header.Get("PAYMENT-RESPONSE"); header != "" { + if settleResp, err := httpClient.GetPaymentSettleResponse(map[string]string{"PAYMENT-RESPONSE": header}); err == nil { paymentResponse = settleResp } - } else if paymentHeader := resp.Header.Get("X-PAYMENT-RESPONSE"); paymentHeader != "" { - settleResp, err := httpClient.GetPaymentSettleResponse(map[string]string{ - "X-PAYMENT-RESPONSE": paymentHeader, - }) - if err == nil { + } else if header := resp.Header.Get("X-PAYMENT-RESPONSE"); header != "" { + if settleResp, err := httpClient.GetPaymentSettleResponse(map[string]string{"X-PAYMENT-RESPONSE": header}); err == nil { paymentResponse = settleResp } } - // Check if payment was successful (if a payment was required) success := true if resp.StatusCode == 402 { - // Payment was required but we got a 402, so payment failed success = false - } else if settleResp, ok := paymentResponse.(*x402.SettleResponse); ok && paymentResponse != nil { - // Payment was attempted, check if it succeeded + } else if settleResp, ok := paymentResponse.(*x402.SettleResponse); ok && settleResp != nil { success = settleResp.Success } - // Output result - result := Result{ + return stepResult{ Success: success, Data: responseData, StatusCode: resp.StatusCode, PaymentResponse: paymentResponse, } +} + +// issueRefund triggers a cooperative refund on the batch-settlement channel, +// mirroring TS `await batchSettlementScheme.refund(url)`. +func issueRefund(ctx context.Context, scheme *batchedclient.BatchSettlementEvmScheme, url string) stepResult { + settle, err := scheme.Refund(ctx, url, &batchedclient.RefundOptions{}) + if err != nil { + return stepResult{ + Success: false, + Error: fmt.Sprintf("Refund failed: %v", err), + StatusCode: 200, + Data: map[string]bool{"refund": true}, + } + } + return stepResult{ + Success: settle.Success, + Data: map[string]bool{"refund": true}, + StatusCode: 200, + PaymentResponse: settle, + } +} + +// aggregate builds the multi-step batchSettlement payload expected by the +// harness validator. Mirrors TS `aggregateBatchResult()`. +func aggregate(phase string, results []stepResult, details map[string]stepResult) aggregateResult { + last := results[len(results)-1] + allOk := true + for _, r := range results { + if !r.Success { + allOk = false + break + } + } + batch := map[string]interface{}{ + "phase": phase, + "requests": results, + } + for k, v := range details { + batch[k] = v + } + return aggregateResult{ + Success: allOk, + Data: map[string]interface{}{"batchSettlement": batch}, + StatusCode: last.StatusCode, + PaymentResponse: last.PaymentResponse, + } +} - outputResult(result) +// toAggregate lifts a single stepResult into the wrapper shape used for +// non-batch (single-request) scenarios. +func toAggregate(s stepResult) aggregateResult { + return aggregateResult{ + Success: s.Success, + Data: s.Data, + StatusCode: s.StatusCode, + PaymentResponse: s.PaymentResponse, + } } -func outputResult(result Result) { +func emit(result aggregateResult) { data, err := json.Marshal(result) if err != nil { log.Fatalf("Failed to marshal result: %v", err) } fmt.Println(string(data)) - os.Exit(0) } func outputError(errorMsg string) { - result := Result{ - Success: false, - Error: errorMsg, - } - data, _ := json.Marshal(result) + data, _ := json.Marshal(stepResult{Success: false, Error: errorMsg}) fmt.Println(string(data)) os.Exit(1) } diff --git a/e2e/clients/go-http/test.config.json b/e2e/clients/go-http/test.config.json index 07d5f8cb4d..77bf197e2e 100644 --- a/e2e/clients/go-http/test.config.json +++ b/e2e/clients/go-http/test.config.json @@ -10,12 +10,15 @@ 1, 2 ], - "schemes": ["exact", "upto"], + "schemes": [ + "exact", + "upto", + "batch-settlement" + ], "evm": { - "transferMethods": [ + "assetTransferMethods": [ "eip3009", - "permit2", - "upto" + "permit2" ] }, "extensions": [ @@ -30,7 +33,10 @@ "ENDPOINT_PATH" ], "optional": [ - "EVM_RPC_URL" + "EVM_RPC_URL", + "CHANNEL_SALT", + "BATCH_SETTLEMENT_PHASE", + "EVM_VOUCHER_SIGNER_PRIVATE_KEY" ] } -} \ No newline at end of file +} diff --git a/e2e/clients/httpx/main.py b/e2e/clients/httpx/main.py index 424f0530ae..5a29d4fd07 100644 --- a/e2e/clients/httpx/main.py +++ b/e2e/clients/httpx/main.py @@ -7,7 +7,11 @@ from dotenv import load_dotenv from eth_account import Account -logging.basicConfig(level=logging.INFO, format="%(name)s %(levelname)s: %(message)s", stream=__import__('sys').stderr) +logging.basicConfig( + level=logging.INFO, + format="%(name)s %(levelname)s: %(message)s", + stream=__import__("sys").stderr, +) logging.getLogger("x402.signers").setLevel(logging.DEBUG) logging.getLogger("x402.permit2").setLevel(logging.DEBUG) @@ -16,8 +20,17 @@ from x402.http.clients import x402_httpx_transport from x402.mechanisms.evm import EthAccountSignerWithRPC from x402.mechanisms.evm.exact import register_exact_evm_client +from x402.mechanisms.evm.upto import UptoEvmClientScheme from x402.mechanisms.svm import KeypairSigner from x402.mechanisms.svm.exact import register_exact_svm_client +from x402.mechanisms.tvm import ( + TVM_MAINNET, + TVM_PROVIDER_TONAPI, + TVM_TESTNET, + WalletV5R1Config, + WalletV5R1MnemonicSigner, +) +from x402.mechanisms.tvm.exact import ExactTvmClientScheme import httpx # Load environment variables @@ -26,7 +39,14 @@ # Get environment variables evm_private_key = os.getenv("EVM_PRIVATE_KEY") svm_private_key = os.getenv("SVM_PRIVATE_KEY") +tvm_private_key = os.getenv("TVM_PRIVATE_KEY") evm_rpc_url = os.getenv("EVM_RPC_URL", "https://sepolia.base.org") +tvm_provider = (os.getenv("TVM_PROVIDER") or "").strip().lower() +toncenter_api_key = os.getenv("TONCENTER_API_KEY") +toncenter_base_url = os.getenv("TONCENTER_BASE_URL") +tonapi_api_key = os.getenv("TONAPI_API_KEY") +tonapi_base_url = os.getenv("TONAPI_BASE_URL") +tvm_network = os.getenv("TVM_NETWORK", TVM_TESTNET) base_url = os.getenv("RESOURCE_SERVER_URL") endpoint_path = os.getenv("ENDPOINT_PATH") @@ -35,10 +55,10 @@ print(json.dumps(error_result)) exit(1) -if not evm_private_key and not svm_private_key: +if not evm_private_key and not svm_private_key and not tvm_private_key: error_result = { "success": False, - "error": "At least one of EVM_PRIVATE_KEY or SVM_PRIVATE_KEY must be set", + "error": "At least one of EVM_PRIVATE_KEY, SVM_PRIVATE_KEY, or TVM_PRIVATE_KEY must be set", } print(json.dumps(error_result)) exit(1) @@ -53,12 +73,31 @@ async def main(): evm_account = Account.from_key(evm_private_key) evm_signer = EthAccountSignerWithRPC(evm_account, rpc_url=evm_rpc_url) register_exact_evm_client(client, evm_signer) + client.register("eip155:*", UptoEvmClientScheme(evm_signer)) # Register SVM exact scheme if private key is available if svm_private_key: svm_signer = KeypairSigner.from_base58(svm_private_key) register_exact_svm_client(client, svm_signer) + if tvm_private_key: + if tvm_network not in {TVM_TESTNET, TVM_MAINNET}: + raise ValueError(f"Unsupported TVM network: {tvm_network}") + tvm_config = WalletV5R1Config.from_private_key(tvm_network, tvm_private_key) + tvm_config.provider = tvm_provider or tvm_config.provider + tvm_config.api_key = ( + tonapi_api_key if tvm_provider == TVM_PROVIDER_TONAPI else toncenter_api_key + ) + tvm_config.provider_base_url = ( + tonapi_base_url + if tvm_provider == TVM_PROVIDER_TONAPI + else toncenter_base_url + ) + client.register( + tvm_network, + ExactTvmClientScheme(WalletV5R1MnemonicSigner(tvm_config)), + ) + # Create httpx client with x402 payment transport and increased timeout # Set timeout to 30 seconds to handle busy servers during test runs timeout = httpx.Timeout(30.0, connect=10.0) diff --git a/e2e/clients/httpx/pyproject.toml b/e2e/clients/httpx/pyproject.toml index 9c8028967e..045c66fdb5 100644 --- a/e2e/clients/httpx/pyproject.toml +++ b/e2e/clients/httpx/pyproject.toml @@ -5,7 +5,7 @@ description = "Python httpx client for x402 e2e tests" requires-python = ">=3.10" dependencies = [ "python-dotenv>=1.0.0", - "x402[httpx,evm,svm,extensions]" + "x402[httpx,evm,svm,tvm,extensions]" ] [build-system] @@ -19,6 +19,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/e2e/clients/httpx/test.config.json b/e2e/clients/httpx/test.config.json index 26fecdf809..c25d790c11 100644 --- a/e2e/clients/httpx/test.config.json +++ b/e2e/clients/httpx/test.config.json @@ -4,14 +4,22 @@ "language": "python", "protocolFamilies": [ "evm", - "svm" + "svm", + "tvm" ], "x402Versions": [ 1, 2 ], + "schemes": [ + "exact", + "upto" + ], "evm": { - "transferMethods": ["eip3009", "permit2"] + "assetTransferMethods": [ + "eip3009", + "permit2" + ] }, "extensions": [ "eip2612GasSponsoring", @@ -26,7 +34,14 @@ "optional": [ "EVM_PRIVATE_KEY", "SVM_PRIVATE_KEY", - "EVM_RPC_URL" + "TVM_PRIVATE_KEY", + "EVM_RPC_URL", + "TVM_NETWORK", + "TVM_PROVIDER", + "TONCENTER_API_KEY", + "TONCENTER_BASE_URL", + "TONAPI_API_KEY", + "TONAPI_BASE_URL" ] } } diff --git a/e2e/clients/httpx/uv.lock b/e2e/clients/httpx/uv.lock index 1d634e6156..c56d23527d 100644 --- a/e2e/clients/httpx/uv.lock +++ b/e2e/clients/httpx/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" [[package]] @@ -280,6 +280,88 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, ] +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.4" @@ -1256,6 +1338,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + [[package]] name = "pycryptodome" version = "3.23.0" @@ -1291,6 +1382,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, ] +[[package]] +name = "pycryptodomex" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -1424,6 +1550,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -1433,6 +1594,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, ] +[[package]] +name = "pytoniq" +version = "0.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytoniq-core" }, + { name = "requests" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/b2/9991a953e4b766918a142fe111f71f12803c6acf65eb30f36eb85ed08f31/pytoniq-0.1.43.tar.gz", hash = "sha256:b4b1c8fed2f9d2f1b6f0ab4b3f1fc5503a0088630d8081f817807ff31e608606", size = 50463, upload-time = "2025-11-30T12:30:41.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/c1/b6e5c739839e0e12bde4563438acd55d39552ea63f6de123724b4b91ac64/pytoniq-0.1.43-py3-none-any.whl", hash = "sha256:922c1721124bf7214e0b7044fba2a439e006367778611c0ce813cbe5b00079d3", size = 56118, upload-time = "2025-11-30T12:30:39.65Z" }, +] + +[[package]] +name = "pytoniq-core" +version = "0.1.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "x25519" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/2c/7afbb9003a3aa72ccfe69711433fe36d2493db2c4acf66dde32f7b55799b/pytoniq_core-0.1.46.tar.gz", hash = "sha256:c8e3cf9ccb1852780a725cd51ba7a66a28122eb39c8b9bb97dcdc5bd02c24734", size = 101236, upload-time = "2025-11-28T10:23:21.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/0e/e27cf7ce1bebb47fb95e1d6deae5c91c6ffcb7851f156990e57079cbe8db/pytoniq_core-0.1.46-py3-none-any.whl", hash = "sha256:0a284c8b68f9fed9d54e4dad871238d844339183bf985a614796360e36e1b95e", size = 91400, upload-time = "2025-11-28T10:23:20.95Z" }, +] + [[package]] name = "pyunormalize" version = "17.0.0" @@ -1734,6 +1926,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + [[package]] name = "solana" version = "0.36.11" @@ -1905,9 +2106,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] +[[package]] +name = "x25519" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/b6/fca895aff0800cdf941f856df0685a5513094163664b904576e3e3ef1460/x25519-0.0.2.tar.gz", hash = "sha256:ed91d0aba7f4f4959ed8b37118c11d94f56d36c38bb6f2e6c20d0438d75b1556", size = 4833, upload-time = "2021-10-24T15:18:38.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d1/66c637eb8e7a9601675bf7f04bb9a3015358a0f49e4c31d29a2b9a9d72d9/x25519-0.0.2-py3-none-any.whl", hash = "sha256:5c0833260a548bea9137a5a1b5c30334b751a59d148a62832df0c9e7b919ce99", size = 4907, upload-time = "2021-10-24T15:18:36.727Z" }, +] + [[package]] name = "x402" -version = "2.5.0" +version = "2.6.0" source = { editable = "../../../python/x402" } dependencies = [ { name = "nest-asyncio" }, @@ -1933,6 +2143,12 @@ svm = [ { name = "solana" }, { name = "solders" }, ] +tvm = [ + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, +] [package.metadata] requires-dist = [ @@ -1943,22 +2159,26 @@ requires-dist = [ { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.115.0" }, { name = "flask", marker = "extra == 'flask'", specifier = ">=3.0.0" }, { name = "httpx", marker = "extra == 'httpx'", specifier = ">=0.28.1" }, + { name = "httpx", marker = "extra == 'tvm'", specifier = ">=0.28.1" }, { name = "jsonschema", marker = "extra == 'extensions'", specifier = ">=4.0.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pynacl", marker = "extra == 'tvm'", specifier = ">=1.5.0" }, + { name = "pytoniq", marker = "extra == 'tvm'", specifier = ">=0.1.39" }, + { name = "pytoniq-core", marker = "extra == 'tvm'", specifier = ">=0.1.36" }, { name = "requests", marker = "extra == 'requests'", specifier = ">=2.31.0" }, { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0" }, { name = "solders", marker = "extra == 'svm'", specifier = ">=0.27.0" }, { name = "starlette", marker = "extra == 'fastapi'", specifier = ">=0.27.0" }, { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "web3", marker = "extra == 'evm'", specifier = ">=7.0.0" }, - { name = "x402", extras = ["evm", "svm"], marker = "extra == 'mechanisms'" }, + { name = "x402", extras = ["evm", "svm", "tvm"], marker = "extra == 'mechanisms'" }, { name = "x402", extras = ["flask", "fastapi"], marker = "extra == 'servers'" }, { name = "x402", extras = ["httpx", "requests"], marker = "extra == 'clients'" }, - { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions"], marker = "extra == 'all'" }, + { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions"], marker = "extra == 'all'" }, ] -provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] +provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] [package.metadata.requires-dev] dev = [ @@ -1974,8 +2194,11 @@ dev = [ { name = "mcp", specifier = ">=1.26.0" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, + { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytest", specifier = ">=7.0.0" }, { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytoniq", specifier = ">=0.1.39" }, + { name = "pytoniq-core", specifier = ">=0.1.36" }, { name = "requests", specifier = ">=2.31.0" }, { name = "ruff", specifier = ">=0.1.0" }, { name = "solana", specifier = ">=0.36.0" }, @@ -1991,13 +2214,13 @@ version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "python-dotenv" }, - { name = "x402", extra = ["evm", "extensions", "httpx", "svm"] }, + { name = "x402", extra = ["evm", "extensions", "httpx", "svm", "tvm"] }, ] [package.metadata] requires-dist = [ { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "x402", extras = ["httpx", "evm", "svm", "extensions"], editable = "../../../python/x402" }, + { name = "x402", extras = ["httpx", "evm", "svm", "tvm", "extensions"], editable = "../../../python/x402" }, ] [[package]] diff --git a/e2e/clients/mcp-go/go.mod b/e2e/clients/mcp-go/go.mod index 3899ac9b0c..e57df0123b 100644 --- a/e2e/clients/mcp-go/go.mod +++ b/e2e/clients/mcp-go/go.mod @@ -1,12 +1,12 @@ -module github.com/coinbase/x402/e2e/clients/mcp-go +module github.com/x402-foundation/x402/e2e/clients/mcp-go go 1.24.0 toolchain go1.24.1 require ( - github.com/coinbase/x402/go v0.0.0 github.com/modelcontextprotocol/go-sdk v1.3.0 + github.com/x402-foundation/x402/go v0.0.0 ) require ( @@ -37,4 +37,4 @@ require ( golang.org/x/sys v0.39.0 // indirect ) -replace github.com/coinbase/x402/go => ../../../go +replace github.com/x402-foundation/x402/go => ../../../go diff --git a/e2e/clients/mcp-go/main.go b/e2e/clients/mcp-go/main.go index 4befd7e31d..ba3dfded98 100644 --- a/e2e/clients/mcp-go/main.go +++ b/e2e/clients/mcp-go/main.go @@ -6,11 +6,11 @@ import ( "fmt" "os" - x402 "github.com/coinbase/x402/go" - mcp402 "github.com/coinbase/x402/go/mcp" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + mcp402 "github.com/x402-foundation/x402/go/mcp" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) // Result structure for e2e test output diff --git a/e2e/clients/mcp-go/test.config.json b/e2e/clients/mcp-go/test.config.json index 74bb183db1..3ae7fbc268 100644 --- a/e2e/clients/mcp-go/test.config.json +++ b/e2e/clients/mcp-go/test.config.json @@ -9,8 +9,14 @@ "x402Versions": [ 2 ], + "schemes": [ + "exact" + ], "evm": { - "transferMethods": ["eip3009", "permit2"] + "assetTransferMethods": [ + "eip3009", + "permit2" + ] }, "environment": { "required": [ diff --git a/e2e/clients/mcp-python/main.py b/e2e/clients/mcp-python/main.py index c2f1950978..f747422786 100644 --- a/e2e/clients/mcp-python/main.py +++ b/e2e/clients/mcp-python/main.py @@ -18,11 +18,15 @@ server_url = os.getenv("RESOURCE_SERVER_URL", "") endpoint_path = os.getenv("ENDPOINT_PATH", "") # tool name, e.g. "get_weather" evm_private_key = os.getenv("EVM_PRIVATE_KEY", "") +tvm_private_key = os.getenv("TVM_PRIVATE_KEY", "") -if not server_url or not endpoint_path or not evm_private_key: +if not server_url or not endpoint_path or not (evm_private_key or tvm_private_key): result = { "success": False, - "error": "Missing required environment variables: RESOURCE_SERVER_URL, ENDPOINT_PATH, EVM_PRIVATE_KEY", + "error": ( + "Missing required environment variables: RESOURCE_SERVER_URL, ENDPOINT_PATH, " + "and one of EVM_PRIVATE_KEY or TVM_PRIVATE_KEY" + ), } print(json.dumps(result)) sys.exit(1) @@ -36,21 +40,48 @@ async def main() -> dict: from x402.mcp import create_x402_mcp_client from x402.mechanisms.evm.exact import register_exact_evm_client from x402.mechanisms.evm.signers import EthAccountSigner - - # Create x402 client with EVM scheme + from x402.mechanisms.tvm import ( + TVM_MAINNET, + TVM_PROVIDER_TONAPI, + TVM_TESTNET, + WalletV5R1Config, + WalletV5R1MnemonicSigner, + ) + from x402.mechanisms.tvm.exact import ExactTvmClientScheme + + # Create x402 client with the configured payment schemes client = x402Client() - account = Account.from_key(evm_private_key) - evm_signer = EthAccountSigner(account) - register_exact_evm_client(client, evm_signer) + if evm_private_key: + account = Account.from_key(evm_private_key) + evm_signer = EthAccountSigner(account) + register_exact_evm_client(client, evm_signer) + + if tvm_private_key: + tvm_network = os.getenv("TVM_NETWORK", TVM_TESTNET) + if tvm_network not in {TVM_TESTNET, TVM_MAINNET}: + raise ValueError(f"Unsupported TVM network: {tvm_network}") + tvm_config = WalletV5R1Config.from_private_key(tvm_network, tvm_private_key) + tvm_provider = (os.getenv("TVM_PROVIDER") or "").strip().lower() + tvm_config.provider = tvm_provider or tvm_config.provider + tvm_config.api_key = ( + os.getenv("TONAPI_API_KEY") + if tvm_provider == TVM_PROVIDER_TONAPI + else os.getenv("TONCENTER_API_KEY") + ) + tvm_config.provider_base_url = ( + os.getenv("TONAPI_BASE_URL") + if tvm_provider == TVM_PROVIDER_TONAPI + else os.getenv("TONCENTER_BASE_URL") + ) + client.register( + tvm_network, + ExactTvmClientScheme(WalletV5R1MnemonicSigner(tvm_config)), + ) try: - async with create_x402_mcp_client( - client, server_url, auto_payment=True - ) as mcp: + async with create_x402_mcp_client(client, server_url, auto_payment=True) as mcp: # Call the paid tool - payment is handled automatically - result = await mcp.call_tool( - endpoint_path, {"city": "San Francisco"} - ) + result = await mcp.call_tool(endpoint_path, {"city": "San Francisco"}) # Extract data from content data = None diff --git a/e2e/clients/mcp-python/pyproject.toml b/e2e/clients/mcp-python/pyproject.toml index b32ad6237a..fc2e9d4755 100644 --- a/e2e/clients/mcp-python/pyproject.toml +++ b/e2e/clients/mcp-python/pyproject.toml @@ -6,7 +6,7 @@ requires-python = ">=3.10" dependencies = [ "python-dotenv>=1.0.0", "mcp>=1.9.0", - "x402[evm,mcp]" + "x402[evm,tvm,mcp]" ] [build-system] @@ -20,6 +20,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/e2e/clients/mcp-python/run.sh b/e2e/clients/mcp-python/run.sh index 31c1f93486..a0337e9257 100755 --- a/e2e/clients/mcp-python/run.sh +++ b/e2e/clients/mcp-python/run.sh @@ -1,4 +1,4 @@ #!/bin/bash # Ensure dependencies are synced before running -uv sync --quiet +uv sync --reinstall-package x402 --quiet uv run python main.py diff --git a/e2e/clients/mcp-python/test.config.json b/e2e/clients/mcp-python/test.config.json index bab065c9bc..e52e260fe8 100644 --- a/e2e/clients/mcp-python/test.config.json +++ b/e2e/clients/mcp-python/test.config.json @@ -4,20 +4,34 @@ "transport": "mcp", "language": "python", "protocolFamilies": [ - "evm" + "evm", + "tvm" ], "x402Versions": [ 2 ], + "schemes": [ + "exact" + ], "evm": { - "transferMethods": ["eip3009"] + "assetTransferMethods": [ + "eip3009" + ] }, "environment": { "required": [ - "EVM_PRIVATE_KEY", "RESOURCE_SERVER_URL", "ENDPOINT_PATH" ], - "optional": [] + "optional": [ + "EVM_PRIVATE_KEY", + "TVM_PRIVATE_KEY", + "TVM_NETWORK", + "TVM_PROVIDER", + "TONCENTER_API_KEY", + "TONCENTER_BASE_URL", + "TONAPI_API_KEY", + "TONAPI_BASE_URL" + ] } } diff --git a/e2e/clients/mcp-python/uv.lock b/e2e/clients/mcp-python/uv.lock index d4768a6ad5..18155417a6 100644 --- a/e2e/clients/mcp-python/uv.lock +++ b/e2e/clients/mcp-python/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" [[package]] @@ -1466,6 +1466,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, ] +[[package]] +name = "pycryptodomex" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -1627,6 +1662,41 @@ crypto = [ { name = "cryptography" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -1645,6 +1715,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" }, ] +[[package]] +name = "pytoniq" +version = "0.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytoniq-core" }, + { name = "requests" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/b2/9991a953e4b766918a142fe111f71f12803c6acf65eb30f36eb85ed08f31/pytoniq-0.1.43.tar.gz", hash = "sha256:b4b1c8fed2f9d2f1b6f0ab4b3f1fc5503a0088630d8081f817807ff31e608606", size = 50463, upload-time = "2025-11-30T12:30:41.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/c1/b6e5c739839e0e12bde4563438acd55d39552ea63f6de123724b4b91ac64/pytoniq-0.1.43-py3-none-any.whl", hash = "sha256:922c1721124bf7214e0b7044fba2a439e006367778611c0ce813cbe5b00079d3", size = 56118, upload-time = "2025-11-30T12:30:39.65Z" }, +] + +[[package]] +name = "pytoniq-core" +version = "0.1.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "x25519" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/2c/7afbb9003a3aa72ccfe69711433fe36d2493db2c4acf66dde32f7b55799b/pytoniq_core-0.1.46.tar.gz", hash = "sha256:c8e3cf9ccb1852780a725cd51ba7a66a28122eb39c8b9bb97dcdc5bd02c24734", size = 101236, upload-time = "2025-11-28T10:23:21.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/0e/e27cf7ce1bebb47fb95e1d6deae5c91c6ffcb7851f156990e57079cbe8db/pytoniq_core-0.1.46-py3-none-any.whl", hash = "sha256:0a284c8b68f9fed9d54e4dad871238d844339183bf985a614796360e36e1b95e", size = 91400, upload-time = "2025-11-28T10:23:20.95Z" }, +] + [[package]] name = "pyunormalize" version = "17.0.0" @@ -1960,6 +2061,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + [[package]] name = "sse-starlette" version = "3.2.0" @@ -2135,9 +2245,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] +[[package]] +name = "x25519" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/b6/fca895aff0800cdf941f856df0685a5513094163664b904576e3e3ef1460/x25519-0.0.2.tar.gz", hash = "sha256:ed91d0aba7f4f4959ed8b37118c11d94f56d36c38bb6f2e6c20d0438d75b1556", size = 4833, upload-time = "2021-10-24T15:18:38.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d1/66c637eb8e7a9601675bf7f04bb9a3015358a0f49e4c31d29a2b9a9d72d9/x25519-0.0.2-py3-none-any.whl", hash = "sha256:5c0833260a548bea9137a5a1b5c30334b751a59d148a62832df0c9e7b919ce99", size = 4907, upload-time = "2021-10-24T15:18:36.727Z" }, +] + [[package]] name = "x402" -version = "2.5.0" +version = "2.8.0" source = { editable = "../../../python/x402" } dependencies = [ { name = "nest-asyncio" }, @@ -2156,6 +2275,12 @@ evm = [ mcp = [ { name = "mcp" }, ] +tvm = [ + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, +] [package.metadata] requires-dist = [ @@ -2166,22 +2291,26 @@ requires-dist = [ { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.115.0" }, { name = "flask", marker = "extra == 'flask'", specifier = ">=3.0.0" }, { name = "httpx", marker = "extra == 'httpx'", specifier = ">=0.28.1" }, + { name = "httpx", marker = "extra == 'tvm'", specifier = ">=0.28.1" }, { name = "jsonschema", marker = "extra == 'extensions'", specifier = ">=4.0.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pynacl", marker = "extra == 'tvm'", specifier = ">=1.5.0" }, + { name = "pytoniq", marker = "extra == 'tvm'", specifier = ">=0.1.39" }, + { name = "pytoniq-core", marker = "extra == 'tvm'", specifier = ">=0.1.36" }, { name = "requests", marker = "extra == 'requests'", specifier = ">=2.31.0" }, { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0" }, { name = "solders", marker = "extra == 'svm'", specifier = ">=0.27.0" }, { name = "starlette", marker = "extra == 'fastapi'", specifier = ">=0.27.0" }, { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "web3", marker = "extra == 'evm'", specifier = ">=7.0.0" }, - { name = "x402", extras = ["evm", "svm"], marker = "extra == 'mechanisms'" }, + { name = "x402", extras = ["evm", "svm", "tvm"], marker = "extra == 'mechanisms'" }, { name = "x402", extras = ["flask", "fastapi"], marker = "extra == 'servers'" }, { name = "x402", extras = ["httpx", "requests"], marker = "extra == 'clients'" }, - { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions"], marker = "extra == 'all'" }, + { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions"], marker = "extra == 'all'" }, ] -provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] +provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] [package.metadata.requires-dev] dev = [ @@ -2197,8 +2326,11 @@ dev = [ { name = "mcp", specifier = ">=1.26.0" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, + { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytest", specifier = ">=7.0.0" }, { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytoniq", specifier = ">=0.1.39" }, + { name = "pytoniq-core", specifier = ">=0.1.36" }, { name = "requests", specifier = ">=2.31.0" }, { name = "ruff", specifier = ">=0.1.0" }, { name = "solana", specifier = ">=0.36.0" }, @@ -2215,14 +2347,14 @@ source = { virtual = "." } dependencies = [ { name = "mcp" }, { name = "python-dotenv" }, - { name = "x402", extra = ["evm", "mcp"] }, + { name = "x402", extra = ["evm", "mcp", "tvm"] }, ] [package.metadata] requires-dist = [ { name = "mcp", specifier = ">=1.9.0" }, { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "x402", extras = ["evm", "mcp"], editable = "../../../python/x402" }, + { name = "x402", extras = ["evm", "tvm", "mcp"], editable = "../../../python/x402" }, ] [[package]] diff --git a/e2e/clients/mcp-typescript/package.json b/e2e/clients/mcp-typescript/package.json index f29b7eeb94..49b2a41408 100644 --- a/e2e/clients/mcp-typescript/package.json +++ b/e2e/clients/mcp-typescript/package.json @@ -11,13 +11,13 @@ }, "dependencies": { "@modelcontextprotocol/sdk": "^1.15.1", - "@x402/core": "workspace:*", "@x402/evm": "workspace:*", "@x402/mcp": "workspace:*", - "viem": "^2.21.26" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -25,7 +25,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/e2e/clients/mcp-typescript/test.config.json b/e2e/clients/mcp-typescript/test.config.json index 5f2b7c7e35..66ff57dd80 100644 --- a/e2e/clients/mcp-typescript/test.config.json +++ b/e2e/clients/mcp-typescript/test.config.json @@ -9,8 +9,14 @@ "x402Versions": [ 2 ], + "schemes": [ + "exact" + ], "evm": { - "transferMethods": ["eip3009", "permit2"] + "assetTransferMethods": [ + "eip3009", + "permit2" + ] }, "environment": { "required": [ diff --git a/e2e/clients/requests/main.py b/e2e/clients/requests/main.py index c5eb3b291d..16f2ab11f6 100644 --- a/e2e/clients/requests/main.py +++ b/e2e/clients/requests/main.py @@ -10,8 +10,17 @@ from x402.http.clients import x402_requests from x402.mechanisms.evm import EthAccountSignerWithRPC from x402.mechanisms.evm.exact import register_exact_evm_client +from x402.mechanisms.evm.upto import UptoEvmClientScheme from x402.mechanisms.svm import KeypairSigner from x402.mechanisms.svm.exact import register_exact_svm_client +from x402.mechanisms.tvm import ( + TVM_MAINNET, + TVM_PROVIDER_TONAPI, + TVM_TESTNET, + WalletV5R1Config, + WalletV5R1MnemonicSigner, +) +from x402.mechanisms.tvm.exact import ExactTvmClientScheme # Load environment variables load_dotenv() @@ -19,7 +28,14 @@ # Get environment variables evm_private_key = os.getenv("EVM_PRIVATE_KEY") svm_private_key = os.getenv("SVM_PRIVATE_KEY") +tvm_private_key = os.getenv("TVM_PRIVATE_KEY") evm_rpc_url = os.getenv("EVM_RPC_URL", "https://sepolia.base.org") +tvm_provider = (os.getenv("TVM_PROVIDER") or "").strip().lower() +toncenter_api_key = os.getenv("TONCENTER_API_KEY") +toncenter_base_url = os.getenv("TONCENTER_BASE_URL") +tonapi_api_key = os.getenv("TONAPI_API_KEY") +tonapi_base_url = os.getenv("TONAPI_BASE_URL") +tvm_network = os.getenv("TVM_NETWORK", TVM_TESTNET) base_url = os.getenv("RESOURCE_SERVER_URL") endpoint_path = os.getenv("ENDPOINT_PATH") @@ -28,10 +44,10 @@ print(json.dumps(error_result)) exit(1) -if not evm_private_key and not svm_private_key: +if not evm_private_key and not svm_private_key and not tvm_private_key: error_result = { "success": False, - "error": "At least one of EVM_PRIVATE_KEY or SVM_PRIVATE_KEY must be set", + "error": "At least one of EVM_PRIVATE_KEY, SVM_PRIVATE_KEY, or TVM_PRIVATE_KEY must be set", } print(json.dumps(error_result)) exit(1) @@ -46,12 +62,31 @@ def main(): evm_account = Account.from_key(evm_private_key) evm_signer = EthAccountSignerWithRPC(evm_account, rpc_url=evm_rpc_url) register_exact_evm_client(client, evm_signer) + client.register("eip155:*", UptoEvmClientScheme(evm_signer)) # Register SVM exact scheme if private key is available if svm_private_key: svm_signer = KeypairSigner.from_base58(svm_private_key) register_exact_svm_client(client, svm_signer) + if tvm_private_key: + if tvm_network not in {TVM_TESTNET, TVM_MAINNET}: + raise ValueError(f"Unsupported TVM network: {tvm_network}") + tvm_config = WalletV5R1Config.from_private_key(tvm_network, tvm_private_key) + tvm_config.provider = tvm_provider or tvm_config.provider + tvm_config.api_key = ( + tonapi_api_key if tvm_provider == TVM_PROVIDER_TONAPI else toncenter_api_key + ) + tvm_config.provider_base_url = ( + tonapi_base_url + if tvm_provider == TVM_PROVIDER_TONAPI + else toncenter_base_url + ) + client.register( + tvm_network, + ExactTvmClientScheme(WalletV5R1MnemonicSigner(tvm_config)), + ) + # Create a session with x402 payment handling session = x402_requests(client) diff --git a/e2e/clients/requests/pyproject.toml b/e2e/clients/requests/pyproject.toml index b4259dcdea..7115ed6027 100644 --- a/e2e/clients/requests/pyproject.toml +++ b/e2e/clients/requests/pyproject.toml @@ -5,7 +5,7 @@ description = "Python requests client for x402 e2e tests" requires-python = ">=3.10" dependencies = [ "python-dotenv>=1.0.0", - "x402[requests,evm,svm,extensions]" + "x402[requests,evm,svm,tvm,extensions]" ] [build-system] @@ -19,6 +19,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/e2e/clients/requests/test.config.json b/e2e/clients/requests/test.config.json index 783ba8467f..362acdbfa8 100644 --- a/e2e/clients/requests/test.config.json +++ b/e2e/clients/requests/test.config.json @@ -4,14 +4,22 @@ "language": "python", "protocolFamilies": [ "evm", - "svm" + "svm", + "tvm" ], "x402Versions": [ 1, 2 ], + "schemes": [ + "exact", + "upto" + ], "evm": { - "transferMethods": ["eip3009", "permit2"] + "assetTransferMethods": [ + "eip3009", + "permit2" + ] }, "extensions": [ "eip2612GasSponsoring", @@ -26,7 +34,14 @@ "optional": [ "EVM_PRIVATE_KEY", "SVM_PRIVATE_KEY", - "EVM_RPC_URL" + "TVM_PRIVATE_KEY", + "EVM_RPC_URL", + "TVM_NETWORK", + "TVM_PROVIDER", + "TONCENTER_API_KEY", + "TONCENTER_BASE_URL", + "TONAPI_API_KEY", + "TONAPI_BASE_URL" ] } } diff --git a/e2e/clients/requests/uv.lock b/e2e/clients/requests/uv.lock index 3fa9f0e1c2..8f20e8cca1 100644 --- a/e2e/clients/requests/uv.lock +++ b/e2e/clients/requests/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" [[package]] @@ -280,6 +280,88 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/70/7d/9bc192684cea499815ff478dfcdc13835ddf401365057044fb721ec6bddb/certifi-2025.11.12-py3-none-any.whl", hash = "sha256:97de8790030bbd5c2d96b7ec782fc2f7820ef8dba6db909ccf95449f2d062d4b", size = 159438, upload-time = "2025-11-12T02:54:49.735Z" }, ] +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.4" @@ -1256,6 +1338,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + [[package]] name = "pycryptodome" version = "3.23.0" @@ -1291,6 +1382,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, ] +[[package]] +name = "pycryptodomex" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -1424,6 +1550,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -1433,6 +1594,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, ] +[[package]] +name = "pytoniq" +version = "0.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytoniq-core" }, + { name = "requests" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/b2/9991a953e4b766918a142fe111f71f12803c6acf65eb30f36eb85ed08f31/pytoniq-0.1.43.tar.gz", hash = "sha256:b4b1c8fed2f9d2f1b6f0ab4b3f1fc5503a0088630d8081f817807ff31e608606", size = 50463, upload-time = "2025-11-30T12:30:41.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/c1/b6e5c739839e0e12bde4563438acd55d39552ea63f6de123724b4b91ac64/pytoniq-0.1.43-py3-none-any.whl", hash = "sha256:922c1721124bf7214e0b7044fba2a439e006367778611c0ce813cbe5b00079d3", size = 56118, upload-time = "2025-11-30T12:30:39.65Z" }, +] + +[[package]] +name = "pytoniq-core" +version = "0.1.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "x25519" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/2c/7afbb9003a3aa72ccfe69711433fe36d2493db2c4acf66dde32f7b55799b/pytoniq_core-0.1.46.tar.gz", hash = "sha256:c8e3cf9ccb1852780a725cd51ba7a66a28122eb39c8b9bb97dcdc5bd02c24734", size = 101236, upload-time = "2025-11-28T10:23:21.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/0e/e27cf7ce1bebb47fb95e1d6deae5c91c6ffcb7851f156990e57079cbe8db/pytoniq_core-0.1.46-py3-none-any.whl", hash = "sha256:0a284c8b68f9fed9d54e4dad871238d844339183bf985a614796360e36e1b95e", size = 91400, upload-time = "2025-11-28T10:23:20.95Z" }, +] + [[package]] name = "pyunormalize" version = "17.0.0" @@ -1734,6 +1926,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + [[package]] name = "solana" version = "0.36.11" @@ -1905,9 +2106,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] +[[package]] +name = "x25519" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/b6/fca895aff0800cdf941f856df0685a5513094163664b904576e3e3ef1460/x25519-0.0.2.tar.gz", hash = "sha256:ed91d0aba7f4f4959ed8b37118c11d94f56d36c38bb6f2e6c20d0438d75b1556", size = 4833, upload-time = "2021-10-24T15:18:38.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d1/66c637eb8e7a9601675bf7f04bb9a3015358a0f49e4c31d29a2b9a9d72d9/x25519-0.0.2-py3-none-any.whl", hash = "sha256:5c0833260a548bea9137a5a1b5c30334b751a59d148a62832df0c9e7b919ce99", size = 4907, upload-time = "2021-10-24T15:18:36.727Z" }, +] + [[package]] name = "x402" -version = "2.5.0" +version = "2.6.0" source = { editable = "../../../python/x402" } dependencies = [ { name = "nest-asyncio" }, @@ -1933,6 +2143,12 @@ svm = [ { name = "solana" }, { name = "solders" }, ] +tvm = [ + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, +] [package.metadata] requires-dist = [ @@ -1943,22 +2159,26 @@ requires-dist = [ { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.115.0" }, { name = "flask", marker = "extra == 'flask'", specifier = ">=3.0.0" }, { name = "httpx", marker = "extra == 'httpx'", specifier = ">=0.28.1" }, + { name = "httpx", marker = "extra == 'tvm'", specifier = ">=0.28.1" }, { name = "jsonschema", marker = "extra == 'extensions'", specifier = ">=4.0.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pynacl", marker = "extra == 'tvm'", specifier = ">=1.5.0" }, + { name = "pytoniq", marker = "extra == 'tvm'", specifier = ">=0.1.39" }, + { name = "pytoniq-core", marker = "extra == 'tvm'", specifier = ">=0.1.36" }, { name = "requests", marker = "extra == 'requests'", specifier = ">=2.31.0" }, { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0" }, { name = "solders", marker = "extra == 'svm'", specifier = ">=0.27.0" }, { name = "starlette", marker = "extra == 'fastapi'", specifier = ">=0.27.0" }, { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "web3", marker = "extra == 'evm'", specifier = ">=7.0.0" }, - { name = "x402", extras = ["evm", "svm"], marker = "extra == 'mechanisms'" }, + { name = "x402", extras = ["evm", "svm", "tvm"], marker = "extra == 'mechanisms'" }, { name = "x402", extras = ["flask", "fastapi"], marker = "extra == 'servers'" }, { name = "x402", extras = ["httpx", "requests"], marker = "extra == 'clients'" }, - { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions"], marker = "extra == 'all'" }, + { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions"], marker = "extra == 'all'" }, ] -provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] +provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] [package.metadata.requires-dev] dev = [ @@ -1974,8 +2194,11 @@ dev = [ { name = "mcp", specifier = ">=1.26.0" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, + { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytest", specifier = ">=7.0.0" }, { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytoniq", specifier = ">=0.1.39" }, + { name = "pytoniq-core", specifier = ">=0.1.36" }, { name = "requests", specifier = ">=2.31.0" }, { name = "ruff", specifier = ">=0.1.0" }, { name = "solana", specifier = ">=0.36.0" }, @@ -1991,13 +2214,13 @@ version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "python-dotenv" }, - { name = "x402", extra = ["evm", "extensions", "requests", "svm"] }, + { name = "x402", extra = ["evm", "extensions", "requests", "svm", "tvm"] }, ] [package.metadata] requires-dist = [ { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "x402", extras = ["requests", "evm", "svm", "extensions"], editable = "../../../python/x402" }, + { name = "x402", extras = ["requests", "evm", "svm", "tvm", "extensions"], editable = "../../../python/x402" }, ] [[package]] diff --git a/e2e/clients/text-client-protocol.txt b/e2e/clients/text-client-protocol.txt index 8b362d0d74..6dd26ad0eb 100644 --- a/e2e/clients/text-client-protocol.txt +++ b/e2e/clients/text-client-protocol.txt @@ -15,13 +15,15 @@ Clients must declare which protocol families they support in their test.config.j Clients must declare which x402 protocol versions they support using the `x402Versions` field: - **x402Versions**: Array of supported x402 protocol versions (e.g., [1, 2]) -## EVM Transfer Method Support -Clients that support the EVM protocol family must declare which transfer methods they support using the `evm.transferMethods` field: -- **eip3009**: EIP-3009 transferWithAuthorization -- **permit2**: Uniswap Permit2 approval-based transfer +## EVM asset transfer method support +Clients that support the EVM protocol family must declare which **asset authorization** paths they implement using **`evm.assetTransferMethods`**: +- **eip3009**: EIP-3009 `transferWithAuthorization` +- **permit2**: Uniswap Permit2 + +Payment **schemes** (exact / upto / batch-settlement) are chosen per server endpoint; the client is matched only on **`assetTransferMethod`**. If the `evm` field is omitted, the client is assumed to only support `["eip3009"]`. -The test suite uses this to skip scenarios where a server endpoint requires a transfer method the client does not support. +The test suite uses this to skip scenarios where a server endpoint requires an asset transfer method the client does not support. Example configuration: ```json @@ -32,7 +34,7 @@ Example configuration: "protocolFamilies": ["evm"], "x402Versions": [1, 2], "evm": { - "transferMethods": ["eip3009", "permit2"] + "assetTransferMethods": ["eip3009", "permit2"] }, "environment": { "required": ["EVM_PRIVATE_KEY", "RESOURCE_SERVER_URL", "ENDPOINT_PATH"], @@ -50,7 +52,7 @@ Multi-protocol client example: "protocolFamilies": ["evm", "svm"], "x402Versions": [1, 2], "evm": { - "transferMethods": ["eip3009", "permit2"] + "assetTransferMethods": ["eip3009", "permit2"] }, "environment": { "required": ["EVM_PRIVATE_KEY", "SVM_PRIVATE_KEY", "RESOURCE_SERVER_URL", "ENDPOINT_PATH"], @@ -68,7 +70,7 @@ Python client example (eip3009 only): "protocolFamilies": ["evm"], "x402Versions": [1, 2], "evm": { - "transferMethods": ["eip3009"] + "assetTransferMethods": ["eip3009"] }, "environment": { "required": ["EVM_PRIVATE_KEY", "RESOURCE_SERVER_URL", "ENDPOINT_PATH"], diff --git a/e2e/extensions/bazaar.ts b/e2e/extensions/bazaar.ts index c402028f1e..0bc1cb4412 100644 --- a/e2e/extensions/bazaar.ts +++ b/e2e/extensions/bazaar.ts @@ -1,12 +1,16 @@ /** * Bazaar Discovery Extension Validation for E2E Tests - * + * * This module validates that the bazaar discovery extension is working correctly * by checking that facilitators have discovered all expected endpoints from servers. */ -import { log, verboseLog, errorLog } from '../src/logger'; -import type { FacilitatorProxy, DiscoveredServer, TestConfig } from '../src/types'; +import { log, verboseLog, errorLog } from "../src/logger"; +import type { + FacilitatorProxy, + DiscoveredServer, + TestConfig, +} from "../src/types"; /** * Discovery resources response structure @@ -22,7 +26,7 @@ interface DiscoveryResourcesResponse { accepts: any[]; discoveryInfo?: any; lastUpdated: string; - metadata?: Record; + extensions?: Record; }>; pagination: { limit: number; @@ -31,6 +35,20 @@ interface DiscoveryResourcesResponse { }; } +/** + * Discovery search response structure + */ +interface DiscoverySearchResponse { + x402Version: number; + resources: Array<{ + resource: string; + type: string; + [key: string]: unknown; + }>; + partialResults?: boolean; + pagination?: { limit: number; cursor: string | null } | null; +} + /** * Expected endpoint that should be discovered */ @@ -40,6 +58,14 @@ interface ExpectedDiscoverableEndpoint { endpointPath: string; method: string; description: string; + /** For MCP tools: expected resource URL is mcp://tool/{toolName} */ + expectedResourceUrl: string; + /** For MCP tools: the tool name expected in discoveryInfo.input.toolName */ + toolName?: string; + /** For MCP tools: expected discoveryInfo.input.transport value. */ + mcpTransport?: "streamable-http" | "sse"; + /** Transport type ('http' or 'mcp') */ + transport: string; } /** @@ -74,14 +100,14 @@ export interface DiscoveryValidationResult { * Check if a server supports the bazaar extension */ function serverSupportsBazaar(serverConfig: TestConfig): boolean { - return serverConfig.extensions?.includes('bazaar') ?? false; + return serverConfig.extensions?.includes("bazaar") ?? false; } /** * Check if a facilitator supports the bazaar extension */ function facilitatorSupportsBazaar(facilitatorConfig: TestConfig): boolean { - return facilitatorConfig.extensions?.includes('bazaar') ?? false; + return facilitatorConfig.extensions?.includes("bazaar") ?? false; } /** @@ -89,38 +115,109 @@ function facilitatorSupportsBazaar(facilitatorConfig: TestConfig): boolean { */ function getDiscoverableEndpoints( server: DiscoveredServer, - serverPort: number + serverPort: number, ): ExpectedDiscoverableEndpoint[] { if (!serverSupportsBazaar(server.config)) { return []; } + const serverTransport = server.config.transport ?? "http"; const serverUrl = `http://localhost:${serverPort}`; const discoverableEndpoints: ExpectedDiscoverableEndpoint[] = []; // Find all payment-required endpoints (these should have discovery info) - const paymentEndpoints = server.config.endpoints?.filter( - endpoint => endpoint.requiresPayment === true - ) || []; + const paymentEndpoints = + server.config.endpoints?.filter( + (endpoint) => endpoint.requiresPayment === true, + ) || []; for (const endpoint of paymentEndpoints) { + const isMcpEndpoint = + serverTransport === "mcp" || endpoint.method === "tool"; + const toolName = endpoint.toolName ?? endpoint.path; + + // MCP resources are identified by mcp://tool/{toolName}; HTTP by server URL + path + const expectedResourceUrl = isMcpEndpoint + ? `mcp://tool/${toolName}` + : `${serverUrl}${endpoint.path}`; + discoverableEndpoints.push({ serverName: server.config.name, serverUrl, endpointPath: endpoint.path, method: endpoint.method, description: endpoint.description, + expectedResourceUrl, + toolName: isMcpEndpoint ? toolName : undefined, + mcpTransport: isMcpEndpoint ? endpoint.mcpTransport : undefined, + transport: isMcpEndpoint ? "mcp" : "http", }); } return discoverableEndpoints; } +/** + * Validate the search endpoint response structure for a facilitator. + * Uses a wildcard query ("") which should match all resources or return an empty set. + */ +async function validateSearchEndpoint( + facilitatorProxy: FacilitatorProxy, + facilitatorName: string, +): Promise<{ valid: boolean; error?: string }> { + const query = "http"; // Generic term likely to match something + const url = `${facilitatorProxy.getUrl()}/discovery/search?query=${encodeURIComponent(query)}`; + verboseLog(` 🔍 Validating search endpoint: ${url}`); + + try { + const response = await fetch(url); + + if (!response.ok) { + return { + valid: false, + error: `Search endpoint returned ${response.status} ${response.statusText}`, + }; + } + + const data = (await response.json()) as DiscoverySearchResponse; + + // Validate required fields + if (typeof data.x402Version !== "number") { + return { valid: false, error: "search response missing x402Version" }; + } + if (!Array.isArray(data.resources)) { + return { valid: false, error: "search response missing resources array" }; + } + if ( + data.pagination !== undefined && + data.pagination !== null && + (typeof data.pagination !== "object" || + typeof data.pagination.limit !== "number") + ) { + return { valid: false, error: "pagination.limit must be number when present" }; + } + if ( + data.partialResults !== undefined && + typeof data.partialResults !== "boolean" + ) { + return { valid: false, error: "partialResults must be boolean when present" }; + } + + verboseLog(` ✅ Search endpoint valid (${data.resources.length} results)`); + return { valid: true }; + } catch (error) { + return { + valid: false, + error: `Search endpoint request failed: ${error instanceof Error ? error.message : String(error)}`, + }; + } +} + /** * Fetch discovered resources from a facilitator */ async function fetchDiscoveredResources( - facilitatorProxy: FacilitatorProxy + facilitatorProxy: FacilitatorProxy, ): Promise { try { const url = `${facilitatorProxy.getUrl()}/discovery/resources?limit=1000`; @@ -129,14 +226,18 @@ async function fetchDiscoveredResources( const response = await fetch(url); if (!response.ok) { - errorLog(` ❌ Failed to fetch discovery resources: ${response.status} ${response.statusText}`); + errorLog( + ` ❌ Failed to fetch discovery resources: ${response.status} ${response.statusText}`, + ); return null; } const data = await response.json(); return data as DiscoveryResourcesResponse; } catch (error) { - errorLog(` ❌ Error fetching discovery resources: ${error instanceof Error ? error.message : String(error)}`); + errorLog( + ` ❌ Error fetching discovery resources: ${error instanceof Error ? error.message : String(error)}`, + ); return null; } } @@ -147,7 +248,7 @@ async function fetchDiscoveredResources( async function validateFacilitatorDiscovery( facilitatorProxy: FacilitatorProxy, facilitatorConfig: TestConfig, - expectedEndpoints: ExpectedDiscoverableEndpoint[] + expectedEndpoints: ExpectedDiscoverableEndpoint[], ): Promise { const facilitatorName = facilitatorConfig.name; const facilitatorUrl = facilitatorProxy.getUrl(); @@ -183,27 +284,74 @@ async function validateFacilitatorDiscovery( missingEndpoints: expectedEndpoints, unexpectedEndpoints: [], success: false, - error: 'Failed to fetch discovery resources', + error: "Failed to fetch discovery resources", }; } - verboseLog(` 📊 Total resources discovered: ${discoveryResponse.items.length}`); + verboseLog( + ` 📊 Total resources discovered: ${discoveryResponse.items.length}`, + ); - // Build set of discovered resource URLs for easy comparison - const discoveredUrls = new Set( - discoveryResponse.items.map(item => item.resource) + // Build map of discovered resource URL → item for easy lookup + const discoveredItemsByUrl = new Map( + discoveryResponse.items.map((item) => [item.resource, item]), ); // Check which expected endpoints were discovered const missingEndpoints: ExpectedDiscoverableEndpoint[] = []; const discoveredEndpoints: string[] = []; + const metadataMismatches: string[] = []; for (const expected of expectedEndpoints) { - const expectedResourceUrl = `${expected.serverUrl}${expected.endpointPath}`; + const { expectedResourceUrl } = expected; + const discoveredItem = discoveredItemsByUrl.get(expectedResourceUrl); - if (discoveredUrls.has(expectedResourceUrl)) { + if (discoveredItem) { discoveredEndpoints.push(expectedResourceUrl); verboseLog(` ✅ Discovered: ${expected.method} ${expectedResourceUrl}`); + + // For MCP resources, additionally verify type and toolName in discoveryInfo + if (expected.transport === "mcp" && expected.toolName) { + const inputType = discoveredItem.discoveryInfo?.input?.type; + const inputToolName = discoveredItem.discoveryInfo?.input?.toolName; + const inputTransport = discoveredItem.discoveryInfo?.input?.transport; + let hasMetadataMismatch = false; + + if (inputType !== "mcp") { + hasMetadataMismatch = true; + verboseLog( + ` ⚠️ MCP resource ${expectedResourceUrl}: expected discoveryInfo.input.type "mcp", got "${inputType}"`, + ); + } + if (inputToolName !== expected.toolName) { + hasMetadataMismatch = true; + verboseLog( + ` ⚠️ MCP resource ${expectedResourceUrl}: expected toolName "${expected.toolName}", got "${inputToolName}"`, + ); + } + if ( + expected.mcpTransport !== undefined && + inputTransport !== expected.mcpTransport + ) { + hasMetadataMismatch = true; + verboseLog( + ` ⚠️ MCP resource ${expectedResourceUrl}: expected transport "${expected.mcpTransport}", got "${inputTransport}"`, + ); + } + if (hasMetadataMismatch) { + metadataMismatches.push(expectedResourceUrl); + } + if ( + inputType === "mcp" && + inputToolName === expected.toolName && + (expected.mcpTransport === undefined || + inputTransport === expected.mcpTransport) + ) { + verboseLog( + ` ✅ MCP discovery metadata verified for tool: ${expected.toolName}`, + ); + } + } } else { missingEndpoints.push(expected); verboseLog(` ❌ Missing: ${expected.method} ${expectedResourceUrl}`); @@ -212,18 +360,28 @@ async function validateFacilitatorDiscovery( // Find any unexpected resources (discovered but not expected) const expectedUrls = new Set( - expectedEndpoints.map(e => `${e.serverUrl}${e.endpointPath}`) + expectedEndpoints.map((e) => e.expectedResourceUrl), ); const unexpectedEndpoints = discoveryResponse.items - .filter(item => !expectedUrls.has(item.resource)) - .map(item => item.resource); + .filter((item) => !expectedUrls.has(item.resource)) + .map((item) => item.resource); if (unexpectedEndpoints.length > 0) { - verboseLog(` ℹ️ Unexpected endpoints discovered: ${unexpectedEndpoints.length}`); - unexpectedEndpoints.forEach(url => verboseLog(` • ${url}`)); + verboseLog( + ` ℹ️ Unexpected endpoints discovered: ${unexpectedEndpoints.length}`, + ); + unexpectedEndpoints.forEach((url) => verboseLog(` • ${url}`)); } - const success = missingEndpoints.length === 0; + if (metadataMismatches.length > 0) { + errorLog( + ` ❌ MCP discovery metadata mismatches: ${metadataMismatches.length}`, + ); + metadataMismatches.forEach((url) => errorLog(` • ${url}`)); + } + + const success = + missingEndpoints.length === 0 && metadataMismatches.length === 0; return { facilitatorName, @@ -239,15 +397,15 @@ async function validateFacilitatorDiscovery( /** * Main discovery validation handler - * + * * Validates that all expected endpoints have been discovered by facilitators - * + * * @param facilitators - Array of facilitator proxies with their configs * @param servers - Array of discovered servers with their configs * @param serverPorts - Map of server name to port number * @param facilitatorServerMap - Optional map tracking which facilitators processed which servers (for minimized test runs) * @returns Validation result - * + * * @example * ```typescript * const result = await handleDiscoveryValidation( @@ -255,7 +413,7 @@ async function validateFacilitatorDiscovery( * servers, * new Map([['express', 4021], ['hono', 4022]]) * ); - * + * * if (!result.success) { * console.error('Discovery validation failed'); * } @@ -265,11 +423,11 @@ export async function handleDiscoveryValidation( facilitators: Array<{ proxy: FacilitatorProxy; config: TestConfig }>, servers: DiscoveredServer[], serverPorts: Map, - facilitatorServerMap?: Map> + facilitatorServerMap?: Map>, ): Promise { - log('\n╔════════════════════════════════════════════════════════╗'); - log('║ Bazaar Discovery Extension Validation ║'); - log('╚════════════════════════════════════════════════════════╝'); + log("\n╔════════════════════════════════════════════════════════╗"); + log("║ Bazaar Discovery Extension Validation ║"); + log("╚════════════════════════════════════════════════════════╝"); // Calculate all expected discoverable endpoints const allExpectedEndpoints: ExpectedDiscoverableEndpoint[] = []; @@ -277,7 +435,9 @@ export async function handleDiscoveryValidation( for (const server of servers) { const serverPort = serverPorts.get(server.config.name); if (!serverPort) { - verboseLog(` ⚠️ No port found for server: ${server.config.name}, skipping`); + verboseLog( + ` ⚠️ No port found for server: ${server.config.name}, skipping`, + ); continue; } @@ -287,9 +447,11 @@ export async function handleDiscoveryValidation( log(`\n📋 Expected Discoverable Endpoints: ${allExpectedEndpoints.length}`); if (allExpectedEndpoints.length > 0) { - verboseLog(''); - allExpectedEndpoints.forEach(endpoint => { - verboseLog(` • ${endpoint.method} ${endpoint.serverUrl}${endpoint.endpointPath} (${endpoint.serverName})`); + verboseLog(""); + allExpectedEndpoints.forEach((endpoint) => { + verboseLog( + ` • ${endpoint.method} ${endpoint.expectedResourceUrl} (${endpoint.serverName})`, + ); }); } @@ -305,19 +467,23 @@ export async function handleDiscoveryValidation( if (facilitatorServerMap) { const processedServers = facilitatorServerMap.get(config.name); if (processedServers && processedServers.size > 0) { - facilitatorExpectedEndpoints = allExpectedEndpoints.filter( - endpoint => processedServers.has(endpoint.serverName) + facilitatorExpectedEndpoints = allExpectedEndpoints.filter((endpoint) => + processedServers.has(endpoint.serverName), ); - verboseLog(`\n 📋 Facilitator ${config.name} processed ${processedServers.size} server(s): ${Array.from(processedServers).join(', ')}`); - verboseLog(` Expected to discover ${facilitatorExpectedEndpoints.length} endpoint(s) from those servers`); + verboseLog( + `\n 📋 Facilitator ${config.name} processed ${processedServers.size} server(s): ${Array.from(processedServers).join(", ")}`, + ); + verboseLog( + ` Expected to discover ${facilitatorExpectedEndpoints.length} endpoint(s) from those servers`, + ); } } const result = await validateFacilitatorDiscovery( proxy, config, - facilitatorExpectedEndpoints + facilitatorExpectedEndpoints, ); facilitatorResults.push(result); @@ -325,18 +491,30 @@ export async function handleDiscoveryValidation( if (facilitatorSupportsBazaar(config)) { facilitatorsChecked++; totalDiscovered += result.totalDiscovered; + + // Also validate the search endpoint structure + const searchResult = await validateSearchEndpoint(proxy, config.name); + if (!searchResult.valid) { + result.success = false; + result.error = result.error + ? `${result.error}; Search endpoint validation failed: ${searchResult.error}` + : `Search endpoint validation failed: ${searchResult.error}`; + errorLog( + ` ❌ Search endpoint validation failed for ${config.name}: ${searchResult.error}`, + ); + } } } // Determine overall success - const allEndpointsDiscovered = facilitatorResults.every(r => r.success); + const allEndpointsDiscovered = facilitatorResults.every((r) => r.success); const hasExpectedEndpoints = allExpectedEndpoints.length > 0; const success = !hasExpectedEndpoints || allEndpointsDiscovered; // Print summary - log('\n═══════════════════════════════════════════════════════'); - log(' Discovery Summary'); - log('═══════════════════════════════════════════════════════'); + log("\n═══════════════════════════════════════════════════════"); + log(" Discovery Summary"); + log("═══════════════════════════════════════════════════════"); log(`Total Facilitators: ${facilitators.length}`); log(`Facilitators with Bazaar: ${facilitatorsChecked}`); log(`Expected Endpoints: ${allExpectedEndpoints.length}`); @@ -344,17 +522,24 @@ export async function handleDiscoveryValidation( // Print per-facilitator results for (const result of facilitatorResults) { - if (!facilitatorSupportsBazaar(facilitators.find(f => f.config.name === result.facilitatorName)!.config)) { + if ( + !facilitatorSupportsBazaar( + facilitators.find((f) => f.config.name === result.facilitatorName)! + .config, + ) + ) { continue; } log(`\n📍 ${result.facilitatorName}:`); - log(` Discovered: ${result.discoveredEndpoints.length}/${result.expectedEndpoints.length}`); + log( + ` Discovered: ${result.discoveredEndpoints.length}/${result.expectedEndpoints.length}`, + ); if (result.missingEndpoints.length > 0) { errorLog(` ❌ Missing: ${result.missingEndpoints.length}`); - result.missingEndpoints.forEach(endpoint => { - errorLog(` • ${endpoint.method} ${endpoint.serverUrl}${endpoint.endpointPath}`); + result.missingEndpoints.forEach((endpoint) => { + errorLog(` • ${endpoint.method} ${endpoint.expectedResourceUrl}`); }); } else if (result.expectedEndpoints.length > 0) { log(` ✅ All expected endpoints discovered`); @@ -362,7 +547,7 @@ export async function handleDiscoveryValidation( if (result.unexpectedEndpoints.length > 0) { verboseLog(` ℹ️ Unexpected: ${result.unexpectedEndpoints.length}`); - result.unexpectedEndpoints.forEach(url => { + result.unexpectedEndpoints.forEach((url) => { verboseLog(` • ${url}`); }); } @@ -372,13 +557,13 @@ export async function handleDiscoveryValidation( } } - log('\n═══════════════════════════════════════════════════════'); + log("\n═══════════════════════════════════════════════════════"); if (success) { - log('✅ Discovery Validation: PASSED'); + log("✅ Discovery Validation: PASSED"); } else { - errorLog('❌ Discovery Validation: FAILED'); + errorLog("❌ Discovery Validation: FAILED"); } - log('═══════════════════════════════════════════════════════\n'); + log("═══════════════════════════════════════════════════════\n"); return { totalFacilitators: facilitators.length, @@ -396,11 +581,14 @@ export async function handleDiscoveryValidation( */ export function shouldRunDiscoveryValidation( facilitators: Array<{ config: TestConfig }>, - servers: DiscoveredServer[] + servers: DiscoveredServer[], ): boolean { - const hasServerWithBazaar = servers.some(s => serverSupportsBazaar(s.config)); - const hasFacilitatorWithBazaar = facilitators.some(f => facilitatorSupportsBazaar(f.config)); + const hasServerWithBazaar = servers.some((s) => + serverSupportsBazaar(s.config), + ); + const hasFacilitatorWithBazaar = facilitators.some((f) => + facilitatorSupportsBazaar(f.config), + ); return hasServerWithBazaar && hasFacilitatorWithBazaar; } - diff --git a/e2e/facilitators/go/README.md b/e2e/facilitators/go/README.md index 40212e4122..62b0964214 100644 --- a/e2e/facilitators/go/README.md +++ b/e2e/facilitators/go/README.md @@ -83,12 +83,12 @@ facilitator := x402.Newx402Facilitator() ```go import ( - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/evm" - evmv1 "github.com/coinbase/x402/go/mechanisms/evm/exact/v1" - "github.com/coinbase/x402/go/mechanisms/svm" - svmv1 "github.com/coinbase/x402/go/mechanisms/svm/exact/v1" - "github.com/coinbase/x402/go/extensions/bazaar" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + evmv1 "github.com/x402-foundation/x402/go/mechanisms/evm/exact/v1" + "github.com/x402-foundation/x402/go/mechanisms/svm" + svmv1 "github.com/x402-foundation/x402/go/mechanisms/svm/exact/v1" + "github.com/x402-foundation/x402/go/extensions/bazaar" ) // Create facilitator @@ -258,9 +258,9 @@ export PORT=4024 ## Dependencies -- `github.com/coinbase/x402/go` - Core facilitator -- `github.com/coinbase/x402/go/mechanisms/evm` - EVM mechanisms -- `github.com/coinbase/x402/go/mechanisms/svm` - SVM mechanisms -- `github.com/coinbase/x402/go/extensions/bazaar` - Bazaar extension +- `github.com/x402-foundation/x402/go` - Core facilitator +- `github.com/x402-foundation/x402/go/mechanisms/evm` - EVM mechanisms +- `github.com/x402-foundation/x402/go/mechanisms/svm` - SVM mechanisms +- `github.com/x402-foundation/x402/go/extensions/bazaar` - Bazaar extension - `github.com/ethereum/go-ethereum` - Ethereum client - `github.com/gagliardetto/solana-go` - Solana client diff --git a/e2e/facilitators/go/batched_authorizer.go b/e2e/facilitators/go/batched_authorizer.go new file mode 100644 index 0000000000..3ede878148 --- /dev/null +++ b/e2e/facilitators/go/batched_authorizer.go @@ -0,0 +1,148 @@ +package main + +import ( + "context" + "crypto/ecdsa" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + evmmech "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +// batchedAuthorizerSigner produces ClaimBatch and Refund EIP-712 signatures +// advertised by the batch-settlement scheme under /supported. Mirrors the TS +// e2e facilitator's authorizerSigner and the example facilitator's +// authorizer.go helper. +type batchedAuthorizerSigner struct { + privateKey *ecdsa.PrivateKey + address common.Address +} + +func newBatchedAuthorizerSigner(privateKeyHex string) (*batchedAuthorizerSigner, error) { + pk, err := crypto.HexToECDSA(strings.TrimPrefix(privateKeyHex, "0x")) + if err != nil { + return nil, fmt.Errorf("parse private key: %w", err) + } + return &batchedAuthorizerSigner{ + privateKey: pk, + address: crypto.PubkeyToAddress(pk.PublicKey), + }, nil +} + +func (a *batchedAuthorizerSigner) Address() string { return a.address.Hex() } + +func (a *batchedAuthorizerSigner) SignClaimBatch(ctx context.Context, claims []batchsettlement.BatchSettlementVoucherClaim, network string) ([]byte, error) { + chainId, err := evmmech.GetEvmChainId(network) + if err != nil { + return nil, err + } + domain := batchsettlement.GetBatchSettlementEip712Domain(chainId) + + allTypes := map[string][]evmmech.TypedDataField{ + "EIP712Domain": eip712DomainFields, + "ClaimBatch": batchsettlement.ClaimBatchTypes["ClaimBatch"], + "ClaimEntry": batchsettlement.ClaimBatchTypes["ClaimEntry"], + } + + entries := make([]map[string]interface{}, len(claims)) + for i, claim := range claims { + channelId, _ := batchsettlement.ComputeChannelId(claim.Voucher.Channel, network) + channelIdBytes, _ := evmmech.HexToBytes(channelId) + maxClaimable, _ := new(big.Int).SetString(claim.Voucher.MaxClaimableAmount, 10) + totalClaimed, _ := new(big.Int).SetString(claim.TotalClaimed, 10) + entries[i] = map[string]interface{}{ + "channelId": channelIdBytes, + "maxClaimableAmount": maxClaimable, + "totalClaimed": totalClaimed, + } + } + return a.signTypedData(domain, allTypes, "ClaimBatch", map[string]interface{}{"claims": entries}) +} + +func (a *batchedAuthorizerSigner) SignRefund(ctx context.Context, channelId string, amount string, nonce string, network string) ([]byte, error) { + chainId, err := evmmech.GetEvmChainId(network) + if err != nil { + return nil, err + } + refundAmount, ok := new(big.Int).SetString(amount, 10) + if !ok { + return nil, fmt.Errorf("invalid refund amount: %s", amount) + } + refundNonce, ok := new(big.Int).SetString(nonce, 10) + if !ok { + return nil, fmt.Errorf("invalid nonce: %s", nonce) + } + channelIdBytes, err := evmmech.HexToBytes(channelId) + if err != nil { + return nil, err + } + + domain := batchsettlement.GetBatchSettlementEip712Domain(chainId) + allTypes := map[string][]evmmech.TypedDataField{ + "EIP712Domain": eip712DomainFields, + "Refund": batchsettlement.RefundTypes["Refund"], + } + message := map[string]interface{}{ + "channelId": channelIdBytes, + "nonce": refundNonce, + "amount": refundAmount, + } + return a.signTypedData(domain, allTypes, "Refund", message) +} + +func (a *batchedAuthorizerSigner) signTypedData( + domain evmmech.TypedDataDomain, + allTypes map[string][]evmmech.TypedDataField, + primaryType string, + message map[string]interface{}, +) ([]byte, error) { + td := apitypes.TypedData{ + Types: apitypes.Types{}, + PrimaryType: primaryType, + Domain: apitypes.TypedDataDomain{ + Name: getStringFromInterface(domain.Name), + Version: getStringFromInterface(domain.Version), + ChainId: (*math.HexOrDecimal256)(getBigIntFromInterface(domain.ChainID)), + VerifyingContract: getStringFromInterface(domain.VerifyingContract), + }, + Message: message, + } + for name, fields := range allTypes { + conv := make([]apitypes.Type, len(fields)) + for i, f := range fields { + conv[i] = apitypes.Type{Name: f.Name, Type: f.Type} + } + td.Types[name] = conv + } + + dataHash, err := td.HashStruct(td.PrimaryType, td.Message) + if err != nil { + return nil, fmt.Errorf("hash struct: %w", err) + } + domainSep, err := td.HashStruct("EIP712Domain", td.Domain.Map()) + if err != nil { + return nil, fmt.Errorf("hash domain: %w", err) + } + digest := crypto.Keccak256(append([]byte{0x19, 0x01}, append(domainSep, dataHash...)...)) + sig, err := crypto.Sign(digest, a.privateKey) + if err != nil { + return nil, fmt.Errorf("sign: %w", err) + } + sig[64] += 27 + return sig, nil +} + +// eip712DomainFields is the canonical EIP-712 domain layout (name + version + +// chainId + verifyingContract) used by every batch-settlement signature. +var eip712DomainFields = []evmmech.TypedDataField{ + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, +} diff --git a/e2e/facilitators/go/bazaar.go b/e2e/facilitators/go/bazaar.go index 45d9e762b7..78692743ac 100644 --- a/e2e/facilitators/go/bazaar.go +++ b/e2e/facilitators/go/bazaar.go @@ -1,12 +1,14 @@ package main import ( + "fmt" "log" + "strings" "sync" "time" - x402 "github.com/coinbase/x402/go" - exttypes "github.com/coinbase/x402/go/extensions/types" + x402 "github.com/x402-foundation/x402/go" + exttypes "github.com/x402-foundation/x402/go/extensions/types" ) type DiscoveredResource struct { @@ -17,7 +19,7 @@ type DiscoveredResource struct { DiscoveryInfo *exttypes.DiscoveryInfo `json:"discoveryInfo,omitempty"` RouteTemplate string `json:"routeTemplate,omitempty"` LastUpdated string `json:"lastUpdated"` - Metadata map[string]interface{} `json:"metadata,omitempty"` + Extensions map[string]interface{} `json:"extensions,omitempty"` } type BazaarCatalog struct { @@ -47,18 +49,26 @@ func (c *BazaarCatalog) CatalogResource( log.Printf(" Route template: %s", routeTemplate) } + // Derive type from discovery info input type + resourceType := "http" + if discoveryInfo != nil { + if _, ok := discoveryInfo.Input.(exttypes.McpInput); ok { + resourceType = "mcp" + } + } + c.mutex.Lock() defer c.mutex.Unlock() c.discoveredResources[resourceURL] = DiscoveredResource{ Resource: resourceURL, - Type: "http", + Type: resourceType, X402Version: x402Version, Accepts: []x402.PaymentRequirements{paymentRequirements}, DiscoveryInfo: discoveryInfo, RouteTemplate: routeTemplate, LastUpdated: time.Now().Format(time.RFC3339), - Metadata: make(map[string]interface{}), + Extensions: make(map[string]interface{}), } } @@ -84,6 +94,36 @@ func (c *BazaarCatalog) GetResources(limit, offset int) ([]DiscoveredResource, i return all[offset:end], total } +// SearchResources performs case-insensitive keyword search across resource URL, +// type, and extension values. +func (c *BazaarCatalog) SearchResources(query, resourceType string, limit int) ([]DiscoveredResource, string) { + c.mutex.RLock() + defer c.mutex.RUnlock() + + needle := strings.ToLower(query) + var results []DiscoveredResource + + for _, r := range c.discoveredResources { + haystack := strings.ToLower(r.Resource + " " + r.Type) + for _, v := range r.Extensions { + haystack += " " + strings.ToLower(fmt.Sprintf("%v", v)) + } + if !strings.Contains(haystack, needle) { + continue + } + if resourceType != "" && r.Type != resourceType { + continue + } + results = append(results, r) + } + + if limit > 0 && len(results) > limit { + results = results[:limit] + } + + return results, query +} + func (c *BazaarCatalog) GetCount() int { c.mutex.RLock() defer c.mutex.RUnlock() diff --git a/e2e/facilitators/go/go.mod b/e2e/facilitators/go/go.mod index 439612494a..28539a5fef 100644 --- a/e2e/facilitators/go/go.mod +++ b/e2e/facilitators/go/go.mod @@ -1,14 +1,14 @@ -module github.com/coinbase/x402-go/e2e/facilitators/go +module github.com/x402-foundation/x402-go/e2e/facilitators/go go 1.24.0 toolchain go1.24.1 require ( - github.com/coinbase/x402/go v0.0.0 github.com/ethereum/go-ethereum v1.16.7 github.com/gagliardetto/solana-go v1.14.0 github.com/gin-gonic/gin v1.11.0 + github.com/x402-foundation/x402/go v0.0.0 ) require ( @@ -88,4 +88,4 @@ require ( google.golang.org/protobuf v1.36.9 // indirect ) -replace github.com/coinbase/x402/go => ../../../go +replace github.com/x402-foundation/x402/go => ../../../go diff --git a/e2e/facilitators/go/main.go b/e2e/facilitators/go/main.go index b9d7ad2f59..f90c6797a0 100644 --- a/e2e/facilitators/go/main.go +++ b/e2e/facilitators/go/main.go @@ -16,19 +16,6 @@ import ( "sync" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" - exttypes "github.com/coinbase/x402/go/extensions/types" - evmmech "github.com/coinbase/x402/go/mechanisms/evm" - exactevm "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - exactevmv1 "github.com/coinbase/x402/go/mechanisms/evm/exact/v1/facilitator" - uptoevm "github.com/coinbase/x402/go/mechanisms/evm/upto/facilitator" - svmmech "github.com/coinbase/x402/go/mechanisms/svm" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/facilitator" - svmv1 "github.com/coinbase/x402/go/mechanisms/svm/exact/v1/facilitator" - x402types "github.com/coinbase/x402/go/types" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -41,6 +28,21 @@ import ( solana "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" "github.com/gin-gonic/gin" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + exttypes "github.com/x402-foundation/x402/go/extensions/types" + evmmech "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + batchedevm "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/facilitator" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + exactevmv1 "github.com/x402-foundation/x402/go/mechanisms/evm/exact/v1/facilitator" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/facilitator" + svmmech "github.com/x402-foundation/x402/go/mechanisms/svm" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/facilitator" + svmv1 "github.com/x402-foundation/x402/go/mechanisms/svm/exact/v1/facilitator" + x402types "github.com/x402-foundation/x402/go/types" ) const ( @@ -143,14 +145,30 @@ func (s *realFacilitatorEvmSigner) VerifyTypedData( typedData.Types[typeName] = typedFields } - // Add EIP712Domain if not present + // Add EIP712Domain type if not present. + // + // Domain fields are conditionally declared based on which TypedDataDomain + // fields are populated. go-ethereum's `apitypes.TypedDataDomain.Map()` + // drops empty Name/Version/VerifyingContract and nil ChainID; if the type + // list still names them, `HashStruct("EIP712Domain", ...)` errors with + // "provided data '' doesn't match type 'string'" (Permit2's no-version + // domain is the canonical case). Mirrors viem's `getTypesForEIP712Domain` + // and the same fix applied to `go/mechanisms/evm/eip712.go`. if _, exists := typedData.Types["EIP712Domain"]; !exists { - typedData.Types["EIP712Domain"] = []apitypes.Type{ - {Name: "name", Type: "string"}, - {Name: "version", Type: "string"}, - {Name: "chainId", Type: "uint256"}, - {Name: "verifyingContract", Type: "address"}, + domainFields := make([]apitypes.Type, 0, 4) + if typedData.Domain.Name != "" { + domainFields = append(domainFields, apitypes.Type{Name: "name", Type: "string"}) } + if typedData.Domain.Version != "" { + domainFields = append(domainFields, apitypes.Type{Name: "version", Type: "string"}) + } + if typedData.Domain.ChainId != nil { + domainFields = append(domainFields, apitypes.Type{Name: "chainId", Type: "uint256"}) + } + if typedData.Domain.VerifyingContract != "" { + domainFields = append(domainFields, apitypes.Type{Name: "verifyingContract", Type: "address"}) + } + typedData.Types["EIP712Domain"] = domainFields } // Hash the data @@ -555,6 +573,18 @@ func hashBytes(data []byte) string { return hex.EncodeToString(hash[:]) } +// isBatchSettlementRequirements reports whether the payment requirements use +// the batch-settlement scheme. Used by the verify-hash cache hooks to exempt +// batch-settlement flows: the resource server rewrites refund and voucher +// payloads between /verify and /settle, so the verify-time payload hash never +// matches the settle-time hash for those flows. Mirrors the TS e2e facilitator. +func isBatchSettlementRequirements(req x402.PaymentRequirementsView) bool { + if req == nil { + return false + } + return req.GetScheme() == batchsettlement.SchemeBatched +} + // Real SVM facilitator signer type realFacilitatorSvmSigner struct { privateKey solana.PrivateKey @@ -847,6 +877,22 @@ func main() { uptoEvmFacilitatorScheme := uptoevm.NewUptoEvmScheme(evmSigner, nil) facilitator.Register([]x402.Network{x402.Network(evmNetwork)}, uptoEvmFacilitatorScheme) + // Register batch-settlement EVM scheme. Mirrors TS: + // `new BatchSettlementEvmScheme(evmSigner, authorizerSigner)` where the + // authorizer key falls back to EVM_PRIVATE_KEY when + // EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY is not set. + authorizerKey := os.Getenv("EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY") + if authorizerKey == "" { + authorizerKey = evmPrivateKey + } + batchedAuthorizer, err := newBatchedAuthorizerSigner(authorizerKey) + if err != nil { + log.Fatalf("Failed to create batch-settlement authorizer: %v", err) + } + log.Printf("EVM Receiver Authorizer (batch-settlement): %s", batchedAuthorizer.Address()) + batchedScheme := batchedevm.NewBatchSettlementEvmScheme(evmSigner, batchedAuthorizer) + facilitator.Register([]x402.Network{x402.Network(evmNetwork)}, batchedScheme) + evmV1Config := &exactevmv1.ExactEvmSchemeV1Config{ DeployERC4337WithEIP6492: true, } @@ -935,7 +981,18 @@ func main() { return nil }). OnBeforeSettle(func(ctx x402.FacilitatorSettleContext) (*x402.FacilitatorBeforeHookResult, error) { - // Hook 3: Validate payment was previously verified + // Hook 3: Validate payment was previously verified. + // + // Batch-settlement is exempt: the resource server's `BeforeSettleHook` + // rewrites refund payloads (adds claims/amount/refundNonce) and rewrites + // voucher commits before /settle, so the payload bytes seen at settle + // time differ from the verify-time bytes. Mirrors the TS e2e fac + // (e2e/facilitators/typescript/index.ts ~548) which skips the cache + // check for `requirements.scheme === "batch-settlement"`. + if isBatchSettlementRequirements(ctx.Requirements) { + return nil, nil + } + paymentHash := hashBytes(ctx.PayloadBytes) verificationMutex.RLock() verificationTimestamp, verified := verifiedPayments[paymentHash] @@ -964,11 +1021,17 @@ func main() { return nil, nil }). OnAfterSettle(func(ctx x402.FacilitatorSettleResultContext) error { - // Hook 4: Clean up verified payment tracking after successful settlement - paymentHash := hashBytes(ctx.PayloadBytes) - verificationMutex.Lock() - delete(verifiedPayments, paymentHash) - verificationMutex.Unlock() + // Hook 4: Clean up verified payment tracking after successful settlement. + // Skip cleanup for batch-settlement: the verify-time entry was keyed by + // a different payload (see OnBeforeSettle comment) so there's nothing + // to delete here, and the cache entry naturally ages out via the 5-min + // TTL check above. Mirrors TS e2e fac. + if !isBatchSettlementRequirements(ctx.Requirements) { + paymentHash := hashBytes(ctx.PayloadBytes) + verificationMutex.Lock() + delete(verifiedPayments, paymentHash) + verificationMutex.Unlock() + } if ctx.Result.Success { log.Printf("✅ Settlement completed: %s", ctx.Result.Transaction) @@ -976,11 +1039,14 @@ func main() { return nil }). OnSettleFailure(func(ctx x402.FacilitatorSettleFailureContext) (*x402.FacilitatorSettleFailureHookResult, error) { - // Hook 5: Clean up verified payment tracking on failure too - paymentHash := hashBytes(ctx.PayloadBytes) - verificationMutex.Lock() - delete(verifiedPayments, paymentHash) - verificationMutex.Unlock() + // Hook 5: Clean up verified payment tracking on failure too. Same + // batch-settlement exemption as OnAfterSettle. + if !isBatchSettlementRequirements(ctx.Requirements) { + paymentHash := hashBytes(ctx.PayloadBytes) + verificationMutex.Lock() + delete(verifiedPayments, paymentHash) + verificationMutex.Unlock() + } log.Printf("❌ Settlement failed: %v", ctx.Error) return nil, nil @@ -1104,7 +1170,7 @@ func main() { items, total := bazaarCatalog.GetResources(limit, offset) c.JSON(http.StatusOK, gin.H{ - "x402Version": 1, + "x402Version": 2, "items": items, "pagination": gin.H{ "limit": limit, @@ -1114,6 +1180,33 @@ func main() { }) }) + // GET /discovery/search - Search discovered resources using keyword matching + router.GET("/discovery/search", func(c *gin.Context) { + query := c.Query("query") + if query == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "query parameter is required"}) + return + } + + resourceType := c.Query("type") + limit := 0 + if limitParam := c.Query("limit"); limitParam != "" { + fmt.Sscanf(limitParam, "%d", &limit) + } + + items, _ := bazaarCatalog.SearchResources(query, resourceType, limit) + if items == nil { + items = []DiscoveredResource{} + } + + c.JSON(http.StatusOK, gin.H{ + "x402Version": 2, + "resources": items, + "partialResults": false, + "pagination": nil, + }) + }) + router.GET("/health", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{ "status": "ok", diff --git a/e2e/facilitators/go/test.config.json b/e2e/facilitators/go/test.config.json index 55ec7fc5f7..92abdb35f6 100644 --- a/e2e/facilitators/go/test.config.json +++ b/e2e/facilitators/go/test.config.json @@ -15,9 +15,16 @@ "eip2612GasSponsoring", "erc20ApprovalGasSponsoring" ], - "schemes": ["exact", "upto"], + "schemes": [ + "exact", + "upto", + "batch-settlement" + ], "evm": { - "transferMethods": ["eip3009", "permit2"] + "assetTransferMethods": [ + "eip3009", + "permit2" + ] }, "environment": { "required": [ @@ -25,6 +32,8 @@ "EVM_PRIVATE_KEY", "SVM_PRIVATE_KEY" ], - "optional": [] + "optional": [ + "EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY" + ] } -} \ No newline at end of file +} diff --git a/e2e/facilitators/python/README.md b/e2e/facilitators/python/README.md index 291e9f85b4..1ae21a1f2d 100644 --- a/e2e/facilitators/python/README.md +++ b/e2e/facilitators/python/README.md @@ -4,7 +4,7 @@ A Python implementation of an x402 facilitator service for end-to-end testing. ## Features -- **Multi-Chain Support**: Handles both EVM (Base Sepolia) and SVM (Solana Devnet) networks +- **Multi-Chain Support**: Handles EVM (Base Sepolia), SVM (Solana Devnet), and TVM (TON testnet/mainnet) networks - **Protocol Versions**: Supports both x402 V1 and V2 protocols - **Bazaar Extension**: Full support for resource discovery and cataloging - **Lifecycle Hooks**: Payment verification tracking and discovery info extraction @@ -39,25 +39,41 @@ uv run uvicorn main:app --port 4022 ## Environment Variables -| Variable | Required | Description | -|----------|----------|-------------| -| `PORT` | No | Server port (default: 4022) | -| `EVM_PRIVATE_KEY` | Yes | Private key for EVM transactions | -| `SVM_PRIVATE_KEY` | Yes | Private key for SVM transactions | -| `EVM_RPC_URL` | No | Custom EVM RPC URL (default: Base Sepolia) | -| `EVM_NETWORK` | No | EVM network identifier | -| `SVM_NETWORK` | No | SVM network identifier | +| Variable | Required | Description | +| -------------------- | ------------- | --------------------------------------------------- | +| `PORT` | No | Server port (default: 4022) | +| `EVM_PRIVATE_KEY` | Conditionally | Private key for EVM transactions | +| `SVM_PRIVATE_KEY` | Conditionally | Private key for SVM transactions | +| `TVM_PRIVATE_KEY` | Conditionally | Private key for the TVM highload facilitator wallet | +| `EVM_RPC_URL` | No | Custom EVM RPC URL (default: Base Sepolia) | +| `EVM_NETWORK` | No | EVM network identifier | +| `SVM_NETWORK` | No | SVM network identifier | +| `TVM_NETWORK` | No | TVM network identifier (default: `tvm:-3`) | +| `TVM_PROVIDER` | No | TVM provider: `toncenter` (default) or `tonapi` | +| `TONCENTER_API_KEY` | No | Toncenter API key for TVM testnet | +| `TONCENTER_BASE_URL` | No | Custom Toncenter base URL for TVM | +| `TONAPI_API_KEY` | No | TonAPI API key when `TVM_PROVIDER=tonapi` | +| `TONAPI_BASE_URL` | No | Custom TonAPI base URL for TVM | + +### TVM funding notes + +To fund the TVM facilitator wallet, request testnet TON from [@testgiver_ton_bot](https://t.me/testgiver_ton_bot). The facilitator wallet only needs TON for relay fees and must hold **at least 1.1 TON** before running tests. + +> **Note:** the facilitator uses a highload-wallet-v3 account, so the facilitator's wallet address differs from your W5 address — fund the highload-v3 address, not the W5 one derived from the same key. + +To get testnet-USDT for the payer wallet, open the [testnet USDT transfer link](https://app.tonkeeper.com/transfer/kQDNUDJC0iQvJoZp0ml-YteL1NtTXKphU03CTI5v4VtBhGYs?amount=49000000&bin=te6cckEBAQEAFgAAKClXdJkAAAAAAAAAAAAAAAAAmJaAhDUekg) or scan the QR code below: +QR code for the testnet USDT transfer link ## Endpoints -| Method | Path | Description | -|--------|------|-------------| -| POST | `/verify` | Verify a payment against requirements | -| POST | `/settle` | Settle a payment on-chain | -| GET | `/supported` | Get supported payment kinds and extensions | -| GET | `/discovery/resources` | List discovered resources (bazaar) | -| GET | `/health` | Health check | -| POST | `/close` | Graceful shutdown | +| Method | Path | Description | +| ------ | ---------------------- | ------------------------------------------ | +| POST | `/verify` | Verify a payment against requirements | +| POST | `/settle` | Settle a payment on-chain | +| GET | `/supported` | Get supported payment kinds and extensions | +| GET | `/discovery/resources` | List discovered resources (bazaar) | +| GET | `/health` | Health check | +| POST | `/close` | Graceful shutdown | ## API Examples @@ -97,6 +113,7 @@ The facilitator uses: - **x402 Python SDK**: Core x402 functionality - **web3.py**: EVM blockchain interactions - **solders**: SVM blockchain interactions +- **pytoniq + Toncenter/TonAPI**: TVM blockchain interactions ## E2E Test Integration @@ -107,4 +124,3 @@ This facilitator is automatically discovered by the e2e test framework via 2. Wait for the "Facilitator listening" log message 3. Run tests through the facilitator 4. Shut down via POST `/close` - diff --git a/e2e/facilitators/python/bazaar.py b/e2e/facilitators/python/bazaar.py index 4c7c466d55..9ae22dda22 100644 --- a/e2e/facilitators/python/bazaar.py +++ b/e2e/facilitators/python/bazaar.py @@ -18,7 +18,7 @@ def __init__( accepts: list[dict[str, Any]], discovery_info: dict[str, Any] | None = None, route_template: str | None = None, - metadata: dict[str, Any] | None = None, + extensions: dict[str, Any] | None = None, ) -> None: self.resource = resource self.type = resource_type @@ -27,7 +27,7 @@ def __init__( self.discovery_info = discovery_info self.route_template = route_template self.last_updated = datetime.now().isoformat() - self.metadata = metadata or {} + self.extensions = extensions or {} def to_dict(self) -> dict[str, Any]: """Convert to dictionary for JSON serialization.""" @@ -37,7 +37,7 @@ def to_dict(self) -> dict[str, Any]: "x402Version": self.x402_version, "accepts": self.accepts, "lastUpdated": self.last_updated, - "metadata": self.metadata, + "extensions": self.extensions, } if self.discovery_info: result["discoveryInfo"] = self.discovery_info @@ -84,7 +84,7 @@ def catalog_resource( accepts=[payment_requirements], discovery_info=discovery_info, route_template=route_template, - metadata={}, + extensions={}, ) def get_resources(self, limit: int = 100, offset: int = 0) -> dict[str, Any]: @@ -111,6 +111,45 @@ def get_resources(self, limit: int = 100, offset: int = 0) -> dict[str, Any]: }, } + def search_resources( + self, + query: str, + resource_type: str | None = None, + limit: int | None = None, + ) -> dict[str, Any]: + """Search resources using case-insensitive keyword matching. + + Matches against the resource URL, type, and extension values. + + Args: + query: The search query string. + resource_type: Optional filter by resource type. + limit: Optional advisory maximum number of results. + + Returns: + Dictionary with x402Version, items, and optional pagination hints. + """ + needle = query.lower() + results = [] + for r in self._resources.values(): + haystack = " ".join( + [r.resource, r.type] + [str(v) for v in r.extensions.values()] + ).lower() + if needle in haystack: + results.append(r) + + if resource_type: + results = [r for r in results if r.type == resource_type] + + items = results[:limit] if limit is not None else results + + return { + "x402Version": 2, + "resources": [r.to_dict() for r in items], + "partialResults": False, + "pagination": None, + } + def get_count(self) -> int: """Get total count of discovered resources.""" return len(self._resources) diff --git a/e2e/facilitators/python/main.py b/e2e/facilitators/python/main.py index 97d55e8f0b..8a98add9e7 100644 --- a/e2e/facilitators/python/main.py +++ b/e2e/facilitators/python/main.py @@ -6,6 +6,7 @@ Supports: - EVM networks (Base Sepolia) via web3.py - SVM networks (Solana Devnet) via solders +- TVM networks (TON testnet/mainnet) via pytoniq + Toncenter/TonAPI - Bazaar discovery extension for resource cataloging - EIP-2612 gas sponsoring extension (gasless Permit2 approval via permit) - ERC-20 approval gas sponsoring extension (gasless Permit2 via signed tx relay) @@ -23,6 +24,7 @@ logging.getLogger("x402.permit2").setLevel(logging.DEBUG) logging.getLogger("x402.signers").setLevel(logging.DEBUG) +from bazaar import BazaarCatalog from dotenv import load_dotenv from fastapi import FastAPI, HTTPException from pydantic import BaseModel @@ -39,10 +41,16 @@ from x402.mechanisms.evm.constants import TX_STATUS_SUCCESS from x402.mechanisms.evm.exact import register_exact_evm_facilitator from x402.mechanisms.evm.types import TransactionReceipt +from x402.mechanisms.evm.upto import UptoEvmFacilitatorScheme from x402.mechanisms.svm import FacilitatorKeypairSigner from x402.mechanisms.svm.exact import register_exact_svm_facilitator - -from bazaar import BazaarCatalog +from x402.mechanisms.tvm import ( + TVM_TESTNET, + TVM_PROVIDER_TONAPI, + HighloadV3Config, + FacilitatorHighloadV3Signer, +) +from x402.mechanisms.tvm.exact import ExactTvmFacilitatorScheme # Load environment variables load_dotenv() @@ -53,27 +61,59 @@ # Initialize bazaar catalog bazaar_catalog = BazaarCatalog() -# Validate required environment variables -if not os.environ.get("EVM_PRIVATE_KEY"): - print("❌ EVM_PRIVATE_KEY environment variable is required") +# Validate that at least one chain is configured +if not any( + [ + os.environ.get("EVM_PRIVATE_KEY"), + os.environ.get("SVM_PRIVATE_KEY"), + os.environ.get("TVM_PRIVATE_KEY"), + ] +): + print( + "❌ At least one of EVM_PRIVATE_KEY, SVM_PRIVATE_KEY, or TVM_PRIVATE_KEY is required" + ) sys.exit(1) -if not os.environ.get("SVM_PRIVATE_KEY"): - print("❌ SVM_PRIVATE_KEY environment variable is required") - sys.exit(1) - -# Initialize the EVM signer from private key -evm_rpc_url = os.environ.get("EVM_RPC_URL") or "https://sepolia.base.org" -evm_signer = FacilitatorWeb3Signer( - private_key=os.environ["EVM_PRIVATE_KEY"], - rpc_url=evm_rpc_url, -) -print(f"EVM Facilitator account: {evm_signer.get_addresses()[0]}") - -# Initialize the SVM signer from private key -svm_keypair = Keypair.from_base58_string(os.environ["SVM_PRIVATE_KEY"]) -svm_signer = FacilitatorKeypairSigner(svm_keypair) -print(f"SVM Facilitator account: {svm_signer.get_addresses()[0]}") +# Network configuration +EVM_NETWORK = os.environ.get("EVM_NETWORK", "eip155:84532") +SVM_NETWORK = os.environ.get("SVM_NETWORK", "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1") +TVM_NETWORK = os.environ.get("TVM_NETWORK", TVM_TESTNET) + +# Initialize the EVM signer from private key when configured +evm_signer = None +if os.environ.get("EVM_PRIVATE_KEY"): + evm_rpc_url = os.environ.get("EVM_RPC_URL") or "https://sepolia.base.org" + evm_signer = FacilitatorWeb3Signer( + private_key=os.environ["EVM_PRIVATE_KEY"], + rpc_url=evm_rpc_url, + ) + print(f"EVM Facilitator account: {evm_signer.get_addresses()[0]}") + +# Initialize the SVM signer from private key when configured +svm_signer = None +if os.environ.get("SVM_PRIVATE_KEY"): + svm_keypair = Keypair.from_base58_string(os.environ["SVM_PRIVATE_KEY"]) + svm_signer = FacilitatorKeypairSigner(svm_keypair) + print(f"SVM Facilitator account: {svm_signer.get_addresses()[0]}") + +# Initialize the TVM signer from private key when configured +tvm_signer = None +if os.environ.get("TVM_PRIVATE_KEY"): + tvm_config = HighloadV3Config.from_private_key(os.environ["TVM_PRIVATE_KEY"]) + tvm_provider = (os.environ.get("TVM_PROVIDER") or "").strip().lower() + tvm_config.provider = tvm_provider or tvm_config.provider + tvm_config.api_key = ( + os.environ.get("TONAPI_API_KEY") + if tvm_provider == TVM_PROVIDER_TONAPI + else os.environ.get("TONCENTER_API_KEY") + ) + tvm_config.provider_base_url = ( + os.environ.get("TONAPI_BASE_URL") + if tvm_provider == TVM_PROVIDER_TONAPI + else os.environ.get("TONCENTER_BASE_URL") + ) + tvm_signer = FacilitatorHighloadV3Signer({TVM_NETWORK: tvm_config}) + print(f"TVM Facilitator account: {tvm_signer.get_addresses()[0]}") class Erc20ApprovalSigner: @@ -95,22 +135,30 @@ def send_transactions(self, transactions: list) -> list[str]: payer_address = w3.eth.account.recover_transaction(tx) # Use the same gas constants as the library's approve tx builder - gas_cost = 70_000 * 1_000_000_000 # ERC20_APPROVE_GAS_LIMIT * DEFAULT_MAX_FEE_PER_GAS + gas_cost = ( + 70_000 * 1_000_000_000 + ) # ERC20_APPROVE_GAS_LIMIT * DEFAULT_MAX_FEE_PER_GAS payer_balance = w3.eth.get_balance(payer_address) if payer_balance < gas_cost: deficit = gas_cost - payer_balance - print(f"⛽ Funding payer {payer_address} with {deficit} wei for gas") + print( + f"⛽ Funding payer {payer_address} with {deficit} wei for gas" + ) fund_tx = { "to": payer_address, "value": deficit, "gas": 21000, "gasPrice": w3.eth.gas_price, - "nonce": w3.eth.get_transaction_count(self._signer._account.address), + "nonce": w3.eth.get_transaction_count( + self._signer._account.address + ), "chainId": w3.eth.chain_id, } signed_fund = self._signer._account.sign_transaction(fund_tx) - fund_hash = w3.eth.send_raw_transaction(signed_fund.raw_transaction).hex() + fund_hash = w3.eth.send_raw_transaction( + signed_fund.raw_transaction + ).hex() fund_receipt = w3.eth.wait_for_transaction_receipt(fund_hash) if fund_receipt["status"] != 1: raise RuntimeError(f"gas_funding_failed: {fund_hash}") @@ -138,7 +186,9 @@ def wait_for_transaction_receipt(self, tx_hash: str) -> TransactionReceipt: return self._signer.wait_for_transaction_receipt(tx_hash) -erc20_approval_signer = Erc20ApprovalSigner(evm_signer) +erc20_approval_signer = ( + Erc20ApprovalSigner(evm_signer) if evm_signer is not None else None +) def _handle_after_verify(ctx: Any) -> None: @@ -183,7 +233,7 @@ def _handle_after_verify(ctx: Any) -> None: print(f" ⚠️ Failed to extract discovery info: {err}") -# Initialize the x402 Facilitator with EVM and SVM support +# Initialize the x402 Facilitator with optional EVM/SVM/TVM support facilitator = ( x402Facilitator() .on_before_verify(lambda ctx: print("Before verify", ctx)) @@ -195,25 +245,38 @@ def _handle_after_verify(ctx: Any) -> None: ) # Register EVM schemes (V1 and V2) -register_exact_evm_facilitator( - facilitator, - evm_signer, - networks="eip155:84532", # Base Sepolia - deploy_erc4337_with_eip6492=True, -) +if evm_signer is not None: + register_exact_evm_facilitator( + facilitator, + evm_signer, + networks=EVM_NETWORK, + deploy_erc4337_with_eip6492=True, + ) + + # Register upto EVM scheme (V2 only) + facilitator.register([EVM_NETWORK], UptoEvmFacilitatorScheme(evm_signer)) # Register SVM schemes (V1 and V2) -register_exact_svm_facilitator( - facilitator, - svm_signer, - networks="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", # Devnet -) +if svm_signer is not None: + register_exact_svm_facilitator( + facilitator, + svm_signer, + networks=SVM_NETWORK, + ) + +# Register TVM schemes (V2) +if tvm_signer is not None: + facilitator.register( + [TVM_NETWORK], + ExactTvmFacilitatorScheme(tvm_signer), + ) # Register gas sponsoring extensions -facilitator.register_extension(EIP2612_GAS_SPONSORING) -facilitator.register_extension( - Erc20ApprovalFacilitatorExtension(signer=erc20_approval_signer) -) +if evm_signer is not None and erc20_approval_signer is not None: + facilitator.register_extension(EIP2612_GAS_SPONSORING) + facilitator.register_extension( + Erc20ApprovalFacilitatorExtension(signer=erc20_approval_signer) + ) # Pydantic models for request/response @@ -266,11 +329,14 @@ async def verify(request: VerifyRequest): response = await facilitator.verify(payload, requirements) if not response.is_valid: - print(f" ❌ Verify rejected: {response.invalid_reason} (payer={response.payer})") + print( + f" ❌ Verify rejected: {response.invalid_reason} (payer={response.payer})" + ) return response.model_dump(by_alias=True, exclude_none=True) except Exception as e: import traceback + print(f"Verify error: {e}") traceback.print_exc() raise HTTPException(status_code=500, detail=str(e)) @@ -335,7 +401,9 @@ async def supported(): response = facilitator.get_supported() return { - "kinds": [k.model_dump(by_alias=True, exclude_none=True) for k in response.kinds], + "kinds": [ + k.model_dump(by_alias=True, exclude_none=True) for k in response.kinds + ], "extensions": response.extensions, "signers": response.signers, } @@ -358,12 +426,31 @@ async def discovery_resources(limit: int = 100, offset: int = 0): raise HTTPException(status_code=500, detail=str(e)) +@app.get("/discovery/search") +async def discovery_search(query: str, type: str | None = None, limit: int | None = None): + """Search discovered resources using keyword matching. + + Args: + query: The search query string (required). + type: Optional filter by resource type. + limit: Optional advisory maximum number of results. + + Returns: + Search response with x402Version, items, and optional pagination hints. + """ + try: + return bazaar_catalog.search_resources(query, type, limit) + except Exception as e: + print(f"Discovery search error: {e}") + raise HTTPException(status_code=500, detail=str(e)) from e + + @app.get("/health") async def health(): """Health check endpoint.""" return { "status": "ok", - "network": "eip155:84532", + "networks": [kind.network for kind in facilitator.get_supported().kinds], "facilitator": "python", "version": "2.0.0", "extensions": facilitator.get_extensions(), @@ -377,6 +464,8 @@ async def close(): import asyncio print("Received shutdown request") + if tvm_signer is not None: + tvm_signer.close() async def shutdown(): await asyncio.sleep(0.1) @@ -389,14 +478,16 @@ async def shutdown(): if __name__ == "__main__": import uvicorn + supported_networks = [kind.network for kind in facilitator.get_supported().kinds] + active_extensions = facilitator.get_extensions() + print(f""" ╔════════════════════════════════════════════════════════╗ ║ x402 Python Facilitator (E2E) ║ ╠════════════════════════════════════════════════════════╣ ║ Server: http://localhost:{PORT} ║ -║ Network: eip155:84532 ║ -║ Address: {evm_signer.get_addresses()[0]} ║ -║ Extensions: bazaar, eip2612, erc20approval ║ +║ Networks: {", ".join(supported_networks[:2])[:36]:<36}║ +║ Extensions: {", ".join(active_extensions)[:36]:<36}║ ║ ║ ║ Endpoints: ║ ║ • POST /verify (verify payment) ║ diff --git a/e2e/facilitators/python/pyproject.toml b/e2e/facilitators/python/pyproject.toml index 635094c70d..3cabc27d83 100644 --- a/e2e/facilitators/python/pyproject.toml +++ b/e2e/facilitators/python/pyproject.toml @@ -4,14 +4,14 @@ version = "0.1.0" description = "Python facilitator for x402 e2e testing" requires-python = ">=3.10" dependencies = [ - "x402[fastapi,evm,svm,extensions]", + "x402[fastapi,evm,svm,tvm,extensions]", "python-dotenv>=1.2.1", "uvicorn[standard]>=0.40.0", ] [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] x402 = { path = "../../../python/x402", editable = true } - diff --git a/e2e/facilitators/python/test.config.json b/e2e/facilitators/python/test.config.json index ab0ea28eb9..9f017b5e35 100644 --- a/e2e/facilitators/python/test.config.json +++ b/e2e/facilitators/python/test.config.json @@ -4,7 +4,8 @@ "language": "python", "protocolFamilies": [ "evm", - "svm" + "svm", + "tvm" ], "x402Versions": [ 1, @@ -15,19 +16,33 @@ "eip2612GasSponsoring", "erc20ApprovalGasSponsoring" ], + "schemes": [ + "exact", + "upto" + ], "evm": { - "transferMethods": ["eip3009", "permit2"] + "assetTransferMethods": [ + "eip3009", + "permit2" + ] }, "environment": { "required": [ - "PORT", - "EVM_PRIVATE_KEY", - "SVM_PRIVATE_KEY" + "PORT" ], "optional": [ "EVM_NETWORK", "SVM_NETWORK", - "EVM_RPC_URL" + "TVM_NETWORK", + "EVM_RPC_URL", + "EVM_PRIVATE_KEY", + "SVM_PRIVATE_KEY", + "TVM_PRIVATE_KEY", + "TVM_PROVIDER", + "TONCENTER_API_KEY", + "TONCENTER_BASE_URL", + "TONAPI_API_KEY", + "TONAPI_BASE_URL" ] } } diff --git a/e2e/facilitators/python/uv.lock b/e2e/facilitators/python/uv.lock index e3a4299b04..3ff88ed2d4 100644 --- a/e2e/facilitators/python/uv.lock +++ b/e2e/facilitators/python/uv.lock @@ -289,6 +289,88 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.4" @@ -1657,6 +1739,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + [[package]] name = "pycryptodome" version = "3.23.0" @@ -1692,6 +1783,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, ] +[[package]] +name = "pycryptodomex" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -1866,6 +1992,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -1884,6 +2045,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/aa/76/03af049af4dcee5d27442f71b6924f01f3efb5d2bd34f23fcd563f2cc5f5/python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090", size = 24541, upload-time = "2025-12-17T09:24:21.153Z" }, ] +[[package]] +name = "pytoniq" +version = "0.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytoniq-core" }, + { name = "requests" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/b2/9991a953e4b766918a142fe111f71f12803c6acf65eb30f36eb85ed08f31/pytoniq-0.1.43.tar.gz", hash = "sha256:b4b1c8fed2f9d2f1b6f0ab4b3f1fc5503a0088630d8081f817807ff31e608606", size = 50463, upload-time = "2025-11-30T12:30:41.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/c1/b6e5c739839e0e12bde4563438acd55d39552ea63f6de123724b4b91ac64/pytoniq-0.1.43-py3-none-any.whl", hash = "sha256:922c1721124bf7214e0b7044fba2a439e006367778611c0ce813cbe5b00079d3", size = 56118, upload-time = "2025-11-30T12:30:39.65Z" }, +] + +[[package]] +name = "pytoniq-core" +version = "0.1.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "x25519" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/2c/7afbb9003a3aa72ccfe69711433fe36d2493db2c4acf66dde32f7b55799b/pytoniq_core-0.1.46.tar.gz", hash = "sha256:c8e3cf9ccb1852780a725cd51ba7a66a28122eb39c8b9bb97dcdc5bd02c24734", size = 101236, upload-time = "2025-11-28T10:23:21.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/0e/e27cf7ce1bebb47fb95e1d6deae5c91c6ffcb7851f156990e57079cbe8db/pytoniq_core-0.1.46-py3-none-any.whl", hash = "sha256:0a284c8b68f9fed9d54e4dad871238d844339183bf985a614796360e36e1b95e", size = 91400, upload-time = "2025-11-28T10:23:20.95Z" }, +] + [[package]] name = "pyunormalize" version = "17.0.0" @@ -2410,6 +2602,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/43/1c586f9f413765201234541857cb82fda076f4b0f7bad4a0ec248da39cf3/sentry_sdk-2.49.0-py2.py3-none-any.whl", hash = "sha256:6ea78499133874445a20fe9c826c9e960070abeb7ae0cdf930314ab16bb97aa0", size = 415693, upload-time = "2026-01-08T09:56:21.872Z" }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + [[package]] name = "shellingham" version = "1.5.4" @@ -2844,9 +3045,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] +[[package]] +name = "x25519" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/b6/fca895aff0800cdf941f856df0685a5513094163664b904576e3e3ef1460/x25519-0.0.2.tar.gz", hash = "sha256:ed91d0aba7f4f4959ed8b37118c11d94f56d36c38bb6f2e6c20d0438d75b1556", size = 4833, upload-time = "2021-10-24T15:18:38.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d1/66c637eb8e7a9601675bf7f04bb9a3015358a0f49e4c31d29a2b9a9d72d9/x25519-0.0.2-py3-none-any.whl", hash = "sha256:5c0833260a548bea9137a5a1b5c30334b751a59d148a62832df0c9e7b919ce99", size = 4907, upload-time = "2021-10-24T15:18:36.727Z" }, +] + [[package]] name = "x402" -version = "2.5.0" +version = "2.6.0" source = { editable = "../../../python/x402" } dependencies = [ { name = "nest-asyncio" }, @@ -2873,6 +3083,12 @@ svm = [ { name = "solana" }, { name = "solders" }, ] +tvm = [ + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, +] [package.metadata] requires-dist = [ @@ -2883,22 +3099,26 @@ requires-dist = [ { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.115.0" }, { name = "flask", marker = "extra == 'flask'", specifier = ">=3.0.0" }, { name = "httpx", marker = "extra == 'httpx'", specifier = ">=0.28.1" }, + { name = "httpx", marker = "extra == 'tvm'", specifier = ">=0.28.1" }, { name = "jsonschema", marker = "extra == 'extensions'", specifier = ">=4.0.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pynacl", marker = "extra == 'tvm'", specifier = ">=1.5.0" }, + { name = "pytoniq", marker = "extra == 'tvm'", specifier = ">=0.1.39" }, + { name = "pytoniq-core", marker = "extra == 'tvm'", specifier = ">=0.1.36" }, { name = "requests", marker = "extra == 'requests'", specifier = ">=2.31.0" }, { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0" }, { name = "solders", marker = "extra == 'svm'", specifier = ">=0.27.0" }, { name = "starlette", marker = "extra == 'fastapi'", specifier = ">=0.27.0" }, { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "web3", marker = "extra == 'evm'", specifier = ">=7.0.0" }, - { name = "x402", extras = ["evm", "svm"], marker = "extra == 'mechanisms'" }, + { name = "x402", extras = ["evm", "svm", "tvm"], marker = "extra == 'mechanisms'" }, { name = "x402", extras = ["flask", "fastapi"], marker = "extra == 'servers'" }, { name = "x402", extras = ["httpx", "requests"], marker = "extra == 'clients'" }, - { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions"], marker = "extra == 'all'" }, + { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions"], marker = "extra == 'all'" }, ] -provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] +provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] [package.metadata.requires-dev] dev = [ @@ -2914,8 +3134,11 @@ dev = [ { name = "mcp", specifier = ">=1.26.0" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, + { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytest", specifier = ">=7.0.0" }, { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytoniq", specifier = ">=0.1.39" }, + { name = "pytoniq-core", specifier = ">=0.1.36" }, { name = "requests", specifier = ">=2.31.0" }, { name = "ruff", specifier = ">=0.1.0" }, { name = "solana", specifier = ">=0.36.0" }, @@ -2932,14 +3155,14 @@ source = { virtual = "." } dependencies = [ { name = "python-dotenv" }, { name = "uvicorn", extra = ["standard"] }, - { name = "x402", extra = ["evm", "extensions", "fastapi", "svm"] }, + { name = "x402", extra = ["evm", "extensions", "fastapi", "svm", "tvm"] }, ] [package.metadata] requires-dist = [ { name = "python-dotenv", specifier = ">=1.2.1" }, { name = "uvicorn", extras = ["standard"], specifier = ">=0.40.0" }, - { name = "x402", extras = ["fastapi", "evm", "svm", "extensions"], editable = "../../../python/x402" }, + { name = "x402", extras = ["fastapi", "evm", "svm", "tvm", "extensions"], editable = "../../../python/x402" }, ] [[package]] diff --git a/e2e/facilitators/text-facilitator-protocol.txt b/e2e/facilitators/text-facilitator-protocol.txt index 1779205ec0..956e73a1c6 100644 --- a/e2e/facilitators/text-facilitator-protocol.txt +++ b/e2e/facilitators/text-facilitator-protocol.txt @@ -20,13 +20,15 @@ Facilitators must declare which x402 protocol versions they support using the `x Facilitators must declare which protocol extensions they support using the `extensions` field: - **extensions**: Array of supported extension names (e.g., ["bazaar"]) -## EVM Transfer Method Support -Facilitators that support the EVM protocol family must declare which transfer methods they support using the `evm.transferMethods` field: -- **eip3009**: EIP-3009 transferWithAuthorization -- **permit2**: Uniswap Permit2 approval-based transfer +## EVM asset transfer method support +Facilitators that support the EVM protocol family must declare which **asset authorization** paths they implement using **`evm.assetTransferMethods`**: +- **eip3009**: EIP-3009 `transferWithAuthorization` +- **permit2**: Uniswap Permit2 + +Payment **schemes** (exact / upto / batch-settlement) are chosen per server endpoint; the facilitator is matched only on **`assetTransferMethod`**. If the `evm` field is omitted, the facilitator is assumed to only support `["eip3009"]`. -The test suite uses this to skip scenarios where a server endpoint requires a transfer method the facilitator does not support. +The test suite uses this to skip scenarios where a server endpoint requires an asset transfer method the facilitator does not support. Example configuration: ```json @@ -38,7 +40,7 @@ Example configuration: "x402Versions": [2], "extensions": ["bazaar"], "evm": { - "transferMethods": ["eip3009", "permit2"] + "assetTransferMethods": ["eip3009", "permit2"] }, "environment": { "required": ["PORT", "EVM_PRIVATE_KEY", "EVM_NETWORK"], @@ -57,7 +59,7 @@ Python facilitator example (eip3009 only): "x402Versions": [2], "extensions": ["bazaar"], "evm": { - "transferMethods": ["eip3009"] + "assetTransferMethods": ["eip3009"] }, "environment": { "required": ["PORT", "EVM_PRIVATE_KEY", "SVM_PRIVATE_KEY", "APTOS_PRIVATE_KEY"], diff --git a/e2e/facilitators/typescript/README.md b/e2e/facilitators/typescript/README.md index a87bbcade5..608aa7009b 100644 --- a/e2e/facilitators/typescript/README.md +++ b/e2e/facilitators/typescript/README.md @@ -1,6 +1,6 @@ # E2E Test Facilitator: TypeScript -This facilitator demonstrates and tests the TypeScript x402 facilitator implementation with EVM, SVM, and optional Stellar payment verification and settlement. +This facilitator demonstrates and tests the TypeScript x402 facilitator implementation with EVM, SVM, optional Aptos, optional Hedera, and optional Stellar payment verification and settlement. ## What It Tests @@ -9,7 +9,7 @@ This facilitator demonstrates and tests the TypeScript x402 facilitator implemen - ✅ **V1 Protocol** - Legacy x402 facilitator protocol - ✅ **Payment Verification** - Validates payment payloads off-chain - ✅ **Payment Settlement** - Executes transactions on-chain -- ✅ **Multi-chain Support** - EVM, SVM, and (optional) Stellar mechanisms +- ✅ **Multi-chain Support** - EVM, SVM, and optional Aptos/Hedera/Stellar mechanisms - ✅ **HTTP API** - Express.js server exposing facilitator endpoints ### Facilitator Endpoints @@ -171,8 +171,12 @@ pnpm start ### Optional - `STELLAR_PRIVATE_KEY` - Stellar private key (S... format) - enables Stellar support +- `HEDERA_ACCOUNT_ID` - Hedera fee payer account id - enables Hedera support with `HEDERA_PRIVATE_KEY` +- `HEDERA_PRIVATE_KEY` - Hedera ECDSA private key (0x-prefixed or DER-encoded) - `EVM_NETWORK` - EVM network (default: eip155:84532) - `SVM_NETWORK` - SVM network (default: solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1) +- `HEDERA_NETWORK` - Hedera network (default: hedera:testnet) +- `HEDERA_NODE_URL` - Optional custom Hedera node URL - `STELLAR_NETWORK` - Stellar network (default: stellar:testnet) ## Package Dependencies diff --git a/e2e/facilitators/typescript/bazaar.ts b/e2e/facilitators/typescript/bazaar.ts index c9b8cefaba..f98ddc6c73 100644 --- a/e2e/facilitators/typescript/bazaar.ts +++ b/e2e/facilitators/typescript/bazaar.ts @@ -3,13 +3,13 @@ import type { PaymentRequirements } from "@x402/core/types"; export interface DiscoveredResource { resource: string; - type: "http"; + type: "http" | "mcp"; x402Version: number; accepts: PaymentRequirements[]; discoveryInfo?: DiscoveryInfo; routeTemplate?: string; lastUpdated: string; - metadata?: Record; + extensions?: Record; } export class BazaarCatalog { @@ -32,13 +32,13 @@ export class BazaarCatalog { this.discoveredResources.set(resourceUrl, { resource: resourceUrl, - type: "http", + type: discoveryInfo.input.type, x402Version, accepts: [paymentRequirements], discoveryInfo, routeTemplate, lastUpdated: new Date().toISOString(), - metadata: {}, + extensions: {}, }); } @@ -48,7 +48,7 @@ export class BazaarCatalog { const items = allResources.slice(offset, offset + limit); return { - x402Version: 1, + x402Version: 2, items, pagination: { limit, @@ -58,8 +58,38 @@ export class BazaarCatalog { }; } + /** + * Search resources using case-insensitive keyword matching against resource URL, + * type, and extension values. + */ + searchResources(query: string, type?: string, limit?: number) { + const needle = query.toLowerCase(); + let results = Array.from(this.discoveredResources.values()).filter((r) => { + const haystack = [ + r.resource, + r.type, + ...Object.values(r.extensions ?? {}), + ] + .join(" ") + .toLowerCase(); + return haystack.includes(needle); + }); + + if (type) { + results = results.filter((r) => r.type === type); + } + + const items = limit !== undefined ? results.slice(0, limit) : results; + + return { + x402Version: 2, + resources: items, + partialResults: false, + pagination: null, + }; + } + getCount(): number { return this.discoveredResources.size; } } - diff --git a/e2e/facilitators/typescript/index.ts b/e2e/facilitators/typescript/index.ts index ad3a406bfa..e714cbeb1c 100644 --- a/e2e/facilitators/typescript/index.ts +++ b/e2e/facilitators/typescript/index.ts @@ -21,6 +21,8 @@ import { base58 } from "@scure/base"; import { createKeyPairSignerFromBytes } from "@solana/kit"; import { toFacilitatorAptosSigner } from "@x402/aptos"; import { ExactAptosScheme } from "@x402/aptos/exact/facilitator"; +import { toFacilitatorAvmSigner } from "@x402/avm"; +import { ExactAvmScheme } from "@x402/avm/exact/facilitator"; import { x402Facilitator } from "@x402/core/facilitator"; import { Network, @@ -29,7 +31,8 @@ import { SettleResponse, VerifyResponse, } from "@x402/core/types"; -import { toFacilitatorEvmSigner } from "@x402/evm"; +import { type AuthorizerSigner, toFacilitatorEvmSigner } from "@x402/evm"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/facilitator"; import { ExactEvmScheme } from "@x402/evm/exact/facilitator"; import { UptoEvmScheme } from "@x402/evm/upto/facilitator"; import { ExactEvmSchemeV1 } from "@x402/evm/exact/v1/facilitator"; @@ -39,16 +42,37 @@ import { EIP2612_GAS_SPONSORING, createErc20ApprovalGasSponsoringExtension, } from "@x402/extensions"; +import { + AccountId, + Client as HederaClient, + PrivateKey as HederaPrivateKey, + createHederaClient, + createHederaPreflightTransfer, + createHederaSignAndSubmitTransaction, + toFacilitatorHederaSigner, +} from "@x402/hedera"; +import { ExactHederaScheme } from "@x402/hedera/exact/facilitator"; import { toFacilitatorSvmSigner } from "@x402/svm"; import { ExactSvmScheme } from "@x402/svm/exact/facilitator"; import { ExactSvmSchemeV1 } from "@x402/svm/exact/v1/facilitator"; import { NETWORKS as SVM_V1_NETWORKS } from "@x402/svm/v1"; -import { createEd25519Signer, type FacilitatorStellarSigner } from "@x402/stellar"; +import { + createEd25519Signer, + type FacilitatorStellarSigner, +} from "@x402/stellar"; import { ExactStellarScheme } from "@x402/stellar/exact/facilitator"; import crypto from "crypto"; import dotenv from "dotenv"; import express from "express"; -import { createWalletClient, http, publicActions, Chain, parseTransaction, recoverTransactionAddress } from "viem"; +import { + createWalletClient, + http, + nonceManager, + publicActions, + Chain, + parseTransaction, + recoverTransactionAddress, +} from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { baseSepolia, base } from "viem/chains"; import { BazaarCatalog } from "./bazaar.js"; @@ -61,10 +85,16 @@ const EVM_NETWORK = process.env.EVM_NETWORK || "eip155:84532"; const SVM_NETWORK = process.env.SVM_NETWORK || "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"; const APTOS_NETWORK = process.env.APTOS_NETWORK || "aptos:2"; +const AVM_NETWORK = + process.env.AVM_NETWORK || + "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="; +const HEDERA_NETWORK = process.env.HEDERA_NETWORK || "hedera:testnet"; const STELLAR_NETWORK = process.env.STELLAR_NETWORK || "stellar:testnet"; const EVM_RPC_URL = process.env.EVM_RPC_URL; const SVM_RPC_URL = process.env.SVM_RPC_URL; +const AVM_RPC_URL = process.env.AVM_RPC_URL; const APTOS_RPC_URL = process.env.APTOS_RPC_URL; +const HEDERA_NODE_URL = process.env.HEDERA_NODE_URL; const STELLAR_RPC_URL = process.env.STELLAR_RPC_URL; // Map CAIP-2 network IDs to viem chains @@ -81,10 +111,14 @@ function getEvmChain(network: string): Chain { console.log(`🌐 EVM Network: ${EVM_NETWORK}`); console.log(`🌐 SVM Network: ${SVM_NETWORK}`); console.log(`🌐 Aptos Network: ${APTOS_NETWORK}`); +console.log(`🌐 AVM Network: ${AVM_NETWORK}`); +console.log(`🌐 Hedera Network: ${HEDERA_NETWORK}`); console.log(`🌐 Stellar Network: ${STELLAR_NETWORK}`); if (EVM_RPC_URL) console.log(`🌐 EVM RPC URL: ${EVM_RPC_URL}`); if (SVM_RPC_URL) console.log(`🌐 SVM RPC URL: ${SVM_RPC_URL}`); +if (AVM_RPC_URL) console.log(`🌐 AVM RPC URL: ${AVM_RPC_URL}`); if (APTOS_RPC_URL) console.log(`🌐 Aptos RPC URL: ${APTOS_RPC_URL}`); +if (HEDERA_NODE_URL) console.log(`🌐 Hedera Node URL: ${HEDERA_NODE_URL}`); if (STELLAR_RPC_URL) console.log(`🌐 Stellar RPC URL: ${STELLAR_RPC_URL}`); // Validate required environment variables @@ -101,9 +135,25 @@ if (!process.env.SVM_PRIVATE_KEY) { // Initialize the EVM account from private key const evmAccount = privateKeyToAccount( process.env.EVM_PRIVATE_KEY as `0x${string}`, + { nonceManager }, ); console.info(`EVM Facilitator account: ${evmAccount.address}`); +// Dedicated receiver authorizer for the batch-settlement scheme (falls back to EVM_PRIVATE_KEY) +const receiverAuthorizerPrivateKey = + process.env.EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY ?? process.env.EVM_PRIVATE_KEY; +const authorizerAccount = privateKeyToAccount( + receiverAuthorizerPrivateKey as `0x${string}`, +); +const authorizerSigner: AuthorizerSigner = { + address: authorizerAccount.address, + signTypedData: (params) => + authorizerAccount.signTypedData( + params as Parameters[0], + ), +}; +console.info(`EVM Receiver Authorizer: ${authorizerSigner.address}`); + // Initialize the SVM account from private key const svmAccount = await createKeyPairSignerFromBytes( base58.decode(process.env.SVM_PRIVATE_KEY as string), @@ -124,10 +174,45 @@ if (process.env.APTOS_PRIVATE_KEY) { ); } +// Initialize the AVM signer from private key (optional) +let avmSigner: ReturnType | undefined; +if (process.env.AVM_PRIVATE_KEY) { + avmSigner = toFacilitatorAvmSigner(process.env.AVM_PRIVATE_KEY as string); + console.info(`AVM Facilitator account: ${avmSigner.getAddresses()[0]}`); +} + +// Initialize the Hedera signer from account + private key (optional) +let hederaSigner: ReturnType | undefined; +if (process.env.HEDERA_ACCOUNT_ID && process.env.HEDERA_PRIVATE_KEY) { + const hederaAccountId = process.env.HEDERA_ACCOUNT_ID; + const hederaKey = HederaPrivateKey.fromStringECDSA( + process.env.HEDERA_PRIVATE_KEY, + ); + + const buildHederaClient = (network: string): HederaClient => { + const client = createHederaClient(network, HEDERA_NODE_URL); + client.setOperator(AccountId.fromString(hederaAccountId), hederaKey); + return client; + }; + + hederaSigner = toFacilitatorHederaSigner({ + getAddresses: () => [hederaAccountId], + signAndSubmitTransaction: createHederaSignAndSubmitTransaction( + buildHederaClient, + hederaKey, + ), + preflightTransfer: createHederaPreflightTransfer(buildHederaClient), + }); + console.info(`Hedera Facilitator account: ${hederaAccountId}`); +} + // Initialize the Stellar signer from private key (optional) let stellarSigner: FacilitatorStellarSigner | undefined; if (process.env.STELLAR_PRIVATE_KEY) { - stellarSigner = createEd25519Signer(process.env.STELLAR_PRIVATE_KEY as string, STELLAR_NETWORK as Network); + stellarSigner = createEd25519Signer( + process.env.STELLAR_PRIVATE_KEY as string, + STELLAR_NETWORK as Network, + ); console.info(`Stellar Facilitator account: ${stellarSigner.address}`); } @@ -139,7 +224,7 @@ const viemClient = createWalletClient({ transport: http(EVM_RPC_URL), }).extend(publicActions); -// Initialize the x402 Facilitator with EVM, SVM, and Aptos support +// Initialize the x402 Facilitator with EVM, SVM, Aptos, and optional Hedera support const evmSigner = toFacilitatorEvmSigner({ address: evmAccount.address, @@ -191,9 +276,9 @@ const svmSigner = toFacilitatorSvmSigner( // Pass custom RPC URL if provided const aptosSigner = aptosAccount ? toFacilitatorAptosSigner( - aptosAccount, - APTOS_RPC_URL ? { defaultRpcUrl: APTOS_RPC_URL } : undefined, - ) + aptosAccount, + APTOS_RPC_URL ? { defaultRpcUrl: APTOS_RPC_URL } : undefined, + ) : undefined; const verifiedPayments = new Map(); @@ -206,43 +291,170 @@ function createPaymentHash(paymentPayload: PaymentPayload): string { .digest("hex"); } +function isBatchSettlementScheme(requirements: PaymentRequirements): boolean { + return requirements.scheme === "batch-settlement"; +} + +// For batch-settlement payloads the action lives at payload.payload.type +// (deposit / voucher) or payload.payload.settleAction (claimWithSignature / +// settle / refundWithSignature). Used by onAfterSettle to detect deposits. +function extractPayloadAction(paymentPayload: PaymentPayload): string { + const inner = paymentPayload.payload as Record | undefined; + if (!inner || typeof inner !== "object") { + return "n/a"; + } + if (typeof inner.type === "string") { + return inner.type; + } + if (typeof inner.settleAction === "string") { + return inner.settleAction; + } + return "n/a"; +} + +// Minimal ABI fragment for reading channel state from the BatchSettlement contract +const BATCH_SETTLEMENT_ADDRESS = "0x4020e07E964De72a79367828c9C6140fcaE00003" as const; +const channelsAbi = [ + { + type: "function", + name: "channels", + stateMutability: "view", + inputs: [{ name: "channelId", type: "bytes32" }], + outputs: [ + { name: "balance", type: "uint256" }, + { name: "totalClaimed", type: "uint256" }, + ], + }, +] as const; + +async function readChannelBalance(channelId: `0x${string}`): Promise { + const result = (await viemClient.readContract({ + address: BATCH_SETTLEMENT_ADDRESS, + abi: channelsAbi, + functionName: "channels", + args: [channelId], + })) as readonly [bigint, bigint]; + return result[0]; +} + +// Avoid stale state after a deposit is mined +async function waitForChannelDepositConfirmed( + channelId: `0x${string}`, + expectedMinBalance: bigint, + options: { initialDelayMs?: number; maxDelayMs?: number; timeoutMs?: number } = {}, +): Promise { + const initialDelayMs = options.initialDelayMs ?? 250; + const maxDelayMs = options.maxDelayMs ?? 4_000; + const timeoutMs = options.timeoutMs ?? 30_000; + + const startedAt = Date.now(); + let delayMs = initialDelayMs; + let attempt = 0; + let lastBalance = 0n; + + while (Date.now() - startedAt < timeoutMs) { + attempt += 1; + try { + lastBalance = await readChannelBalance(channelId); + } catch (err) { + console.warn( + `⏳ deposit confirm: read failed on attempt ${attempt} for channel ${channelId}: ${err instanceof Error ? err.message : String(err)}`, + ); + } + + if (lastBalance >= expectedMinBalance) { + console.log( + `⏳ deposit confirm: channel ${channelId} balance=${lastBalance} (>= ${expectedMinBalance}) after ${attempt} attempt(s) in ${Date.now() - startedAt}ms`, + ); + return; + } + + await new Promise((resolve) => setTimeout(resolve, delayMs)); + delayMs = Math.min(delayMs * 2, maxDelayMs); + } + + throw new Error( + `deposit_confirm_timeout: channel ${channelId} balance=${lastBalance} (< ${expectedMinBalance}) after ${attempt} attempt(s) in ${Date.now() - startedAt}ms`, + ); +} + +async function waitForBatchSettlementDepositConfirmed( + extra: Record | undefined, +): Promise { + const channelId = typeof extra?.channelId === "string" ? (extra.channelId as `0x${string}`) : undefined; + const balanceStr = typeof extra?.balance === "string" ? extra.balance : undefined; + + if (!channelId || !balanceStr) { + console.warn( + "⏳ deposit confirm: settle response missing channelId/balance, skipping on-chain wait", + ); + return; + } + + let expectedMinBalance: bigint; + try { + expectedMinBalance = BigInt(balanceStr); + } catch { + console.warn(`⏳ deposit confirm: unparseable balance ${balanceStr}, skipping wait`); + return; + } + + if (expectedMinBalance === 0n) { + return; + } + + try { + await waitForChannelDepositConfirmed(channelId, expectedMinBalance); + } catch (err) { + console.error( + `⏳ deposit confirm: ${err instanceof Error ? err.message : String(err)} — proceeding anyway`, + ); + } +} + const facilitator = new x402Facilitator(); -// Register EVM, SVM, and Aptos schemes (v2 + v1) +// Register EVM, SVM, Aptos, and Hedera schemes (v2 + v1 where applicable) facilitator .register(EVM_NETWORK as Network, new ExactEvmScheme(evmSigner)) .register(EVM_NETWORK as Network, new UptoEvmScheme(evmSigner)) + .register( + EVM_NETWORK as Network, + new BatchSettlementEvmScheme(evmSigner, authorizerSigner), + ) .registerV1(EVM_V1_NETWORKS as Network[], new ExactEvmSchemeV1(evmSigner)) .register(SVM_NETWORK as Network, new ExactSvmScheme(svmSigner)) .registerV1(SVM_V1_NETWORKS as Network[], new ExactSvmSchemeV1(svmSigner)); +if (avmSigner) { + facilitator.register(AVM_NETWORK as Network, new ExactAvmScheme(avmSigner)); +} if (aptosSigner) { facilitator.register( APTOS_NETWORK as Network, new ExactAptosScheme(aptosSigner), ); } +if (hederaSigner) { + facilitator.register( + HEDERA_NETWORK as Network, + new ExactHederaScheme(hederaSigner), + ); +} if (stellarSigner) { - facilitator.register(STELLAR_NETWORK as Network, new ExactStellarScheme([stellarSigner])); + facilitator.register( + STELLAR_NETWORK as Network, + new ExactStellarScheme([stellarSigner]), + ); } -const PERMIT2_ADDRESS = "0x000000000022D473030F116dDEE9F6B43aC78BA3" as const; -const erc20AllowanceAbi = [ - { - inputs: [ - { name: "owner", type: "address" }, - { name: "spender", type: "address" }, - ], - name: "allowance", - outputs: [{ name: "", type: "uint256" }], - stateMutability: "view", - type: "function", - }, -] as const; const erc20ApprovalSigner = { ...evmSigner, sendTransactions: async ( - transactions: (`0x${string}` | { to: `0x${string}`; data: `0x${string}`; gas?: bigint })[], + transactions: ( + | `0x${string}` + | { to: `0x${string}`; data: `0x${string}`; gas?: bigint } + )[], ): Promise<`0x${string}`[]> => { const hashes: `0x${string}`[] = []; for (const tx of transactions) { @@ -250,28 +462,38 @@ const erc20ApprovalSigner = { if (typeof tx === "string") { // Parse the raw tx to extract sender and gas params for potential gas funding const parsed = parseTransaction(tx); - const payerAddress = await recoverTransactionAddress({ serializedTransaction: tx }); + const payerAddress = await recoverTransactionAddress({ + serializedTransaction: tx, + }); const gas = parsed.gas ?? 70_000n; const maxFeePerGas = parsed.maxFeePerGas ?? 1_000_000_000n; const gasCost = gas * maxFeePerGas; // Check if the payer has enough ETH for gas - const payerBalance = await viemClient.getBalance({ address: payerAddress }); + const payerBalance = await viemClient.getBalance({ + address: payerAddress, + }); if (payerBalance < gasCost) { const deficit = gasCost - payerBalance; - console.log(`⛽ Funding payer ${payerAddress} with ${deficit} wei for gas`); + console.log( + `⛽ Funding payer ${payerAddress} with ${deficit} wei for gas`, + ); const fundHash = await viemClient.sendTransaction({ to: payerAddress, value: deficit, }); - const fundReceipt = await viemClient.waitForTransactionReceipt({ hash: fundHash }); + const fundReceipt = await viemClient.waitForTransactionReceipt({ + hash: fundHash, + }); if (fundReceipt.status !== "success") { throw new Error(`gas_funding_failed: ${fundHash}`); } console.log(`⛽ Gas funding confirmed: ${fundHash}`); } - hash = await viemClient.sendRawTransaction({ serializedTransaction: tx }); + hash = await viemClient.sendRawTransaction({ + serializedTransaction: tx, + }); } else { hash = await viemClient.sendTransaction(tx); } @@ -288,7 +510,9 @@ const erc20ApprovalSigner = { facilitator .registerExtension(BAZAAR) .registerExtension(EIP2612_GAS_SPONSORING) - .registerExtension(createErc20ApprovalGasSponsoringExtension(erc20ApprovalSigner)) + .registerExtension( + createErc20ApprovalGasSponsoringExtension(erc20ApprovalSigner), + ) // Lifecycle hooks for payment tracking and discovery .onAfterVerify(async (context) => { // Hook 1: Track verified payment for verify→settle flow validation @@ -301,23 +525,39 @@ facilitator context.paymentPayload, context.requirements, ); - if (discovered && "method" in discovered && discovered.method) { + if (discovered) { + const action = + "method" in discovered ? discovered.method : discovered.toolName; + if (!action) { + return; + } + let resourceUrl = discovered.resourceUrl; + if ( + discovered.discoveryInfo.input.type === "mcp" && + "toolName" in discovered && + discovered.toolName && + (!resourceUrl || resourceUrl.startsWith("null/")) + ) { + resourceUrl = `mcp://tool/${discovered.toolName}`; + } bazaarCatalog.catalogResource( - discovered.resourceUrl, - discovered.method, + resourceUrl, + action, discovered.x402Version, discovered.discoveryInfo, context.requirements, discovered.routeTemplate, ); - console.log( - `📦 Discovered resource: ${discovered.method} ${discovered.resourceUrl}`, - ); + console.log(`📦 Discovered resource: ${action} ${resourceUrl}`); } } }) .onBeforeSettle(async (context) => { // Hook 3: Validate payment was previously verified + if (isBatchSettlementScheme(context.requirements)) { + return; + } + const paymentHash = createPaymentHash(context.paymentPayload); const verificationTimestamp = verifiedPayments.get(paymentHash); @@ -340,17 +580,30 @@ facilitator }) .onAfterSettle(async (context) => { // Hook 4: Clean up verified payment tracking after settlement - const paymentHash = createPaymentHash(context.paymentPayload); - verifiedPayments.delete(paymentHash); + if (!isBatchSettlementScheme(context.requirements)) { + const paymentHash = createPaymentHash(context.paymentPayload); + verifiedPayments.delete(paymentHash); + } if (context.result.success) { console.log(`✅ Settlement completed: ${context.result.transaction}`); } + + // For batch-settlement deposits, wait for the deposit to be confirmed onchain + if ( + isBatchSettlementScheme(context.requirements) && + context.result.success && + extractPayloadAction(context.paymentPayload) === "deposit" + ) { + await waitForBatchSettlementDepositConfirmed(context.result.extra); + } }) .onSettleFailure(async (context) => { // Hook 5: Clean up on settlement failure too - const paymentHash = createPaymentHash(context.paymentPayload); - verifiedPayments.delete(paymentHash); + if (!isBatchSettlementScheme(context.requirements)) { + const paymentHash = createPaymentHash(context.paymentPayload); + verifiedPayments.delete(paymentHash); + } console.error(`❌ Settlement failed: ${context.error.message}`); }); @@ -474,6 +727,27 @@ app.get("/discovery/resources", (req, res) => { } }); +app.get("/discovery/search", (req, res) => { + try { + const query = req.query.query as string; + if (!query) { + return res.status(400).json({ error: "query parameter is required" }); + } + const type = req.query.type as string | undefined; + const limit = req.query.limit + ? parseInt(req.query.limit as string) + : undefined; + + const response = bazaarCatalog.searchResources(query, type, limit); + res.json(response); + } catch (error) { + console.error("Discovery search error:", error); + res.status(500).json({ + error: error instanceof Error ? error.message : "Unknown error", + }); + } +}); + /** * GET /health * Health check endpoint @@ -483,7 +757,9 @@ app.get("/health", (req, res) => { status: "ok", evmNetwork: EVM_NETWORK, svmNetwork: SVM_NETWORK, + avmNetwork: avmSigner ? AVM_NETWORK : "(not configured)", aptosNetwork: aptosAccount ? APTOS_NETWORK : "(not configured)", + hederaNetwork: hederaSigner ? HEDERA_NETWORK : "(not configured)", stellarNetwork: stellarSigner ? STELLAR_NETWORK : "(not configured)", facilitator: "typescript", version: "2.0.0", @@ -515,9 +791,13 @@ app.listen(parseInt(PORT), () => { ║ Server: http://localhost:${PORT} ║ ║ EVM Network: ${EVM_NETWORK} ║ ║ SVM Network: ${SVM_NETWORK} ║ +║ AVM Network: ${AVM_NETWORK} ║ ║ Aptos Network: ${APTOS_NETWORK} ║ +║ Hedera Network: ${HEDERA_NETWORK} ║ ║ EVM Address: ${evmAccount.address} ║ +║ AVM Address: ${avmSigner ? avmSigner.getAddresses()[0] : "(not configured)"} ║ Aptos Address: ${aptosAccount ? aptosAccount.accountAddress.toStringLong().slice(0, 20) + "..." : "(not configured)"} +║ Hedera Address: ${process.env.HEDERA_ACCOUNT_ID || "(not configured)"} ║ ║ Stellar Address: ${stellarSigner ? stellarSigner.address : "(not configured)"} ║ ║ Extensions: bazaar ║ ║ ║ diff --git a/e2e/facilitators/typescript/package.json b/e2e/facilitators/typescript/package.json index b3e6922b0a..fc800b23b6 100644 --- a/e2e/facilitators/typescript/package.json +++ b/e2e/facilitators/typescript/package.json @@ -16,21 +16,23 @@ "@scure/base": "^1.2.6", "@solana/kit": "^6.1.0", "@x402/aptos": "workspace:*", + "@x402/avm": "workspace:*", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", "@x402/extensions": "workspace:*", + "@x402/hedera": "workspace:*", "@x402/stellar": "workspace:*", "@x402/svm": "workspace:*", "dotenv": "^16.4.5", "express": "^4.19.2", - "viem": "^2.21.54" + "viem": "^2.48.11" }, "devDependencies": { "@types/express": "^4.17.21", - "@types/node": "^22.10.1", - "eslint": "^9.15.0", - "prettier": "^3.3.3", - "tsx": "^4.19.2", - "typescript": "^5.7.2" + "@types/node": "^22.13.4", + "eslint": "^9.24.0", + "prettier": "3.5.2", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } -} \ No newline at end of file +} diff --git a/e2e/facilitators/typescript/test.config.json b/e2e/facilitators/typescript/test.config.json index d4a6137e50..6d2fbca7c0 100644 --- a/e2e/facilitators/typescript/test.config.json +++ b/e2e/facilitators/typescript/test.config.json @@ -5,20 +5,30 @@ "protocolFamilies": [ "evm", "svm", + "avm", "aptos", + "hedera", "stellar" ], "x402Versions": [ 1, 2 ], + "schemes": [ + "exact", + "upto", + "batch-settlement" + ], "extensions": [ "bazaar", "eip2612GasSponsoring", "erc20ApprovalGasSponsoring" ], "evm": { - "transferMethods": ["eip3009", "permit2", "upto"] + "assetTransferMethods": [ + "eip3009", + "permit2" + ] }, "environment": { "required": [ @@ -27,12 +37,19 @@ "SVM_PRIVATE_KEY" ], "optional": [ + "AVM_PRIVATE_KEY", "APTOS_PRIVATE_KEY", + "HEDERA_ACCOUNT_ID", + "HEDERA_PRIVATE_KEY", "STELLAR_PRIVATE_KEY", "EVM_NETWORK", "SVM_NETWORK", + "AVM_NETWORK", "APTOS_NETWORK", - "STELLAR_NETWORK" + "HEDERA_NETWORK", + "HEDERA_NODE_URL", + "STELLAR_NETWORK", + "EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY" ] } } diff --git a/e2e/legacy/clients/axios/package.json b/e2e/legacy/clients/axios/package.json index 0d50932e7a..090a94270f 100644 --- a/e2e/legacy/clients/axios/package.json +++ b/e2e/legacy/clients/axios/package.json @@ -12,11 +12,12 @@ "dependencies": { "axios": "^1.7.9", "dotenv": "^16.5.0", - "viem": "^2.21.26", + "viem": "^2.48.11", "x402-axios": "workspace:*" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -24,7 +25,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } -} \ No newline at end of file +} diff --git a/e2e/legacy/clients/fetch/package.json b/e2e/legacy/clients/fetch/package.json index f079ea58fe..6483ec4231 100644 --- a/e2e/legacy/clients/fetch/package.json +++ b/e2e/legacy/clients/fetch/package.json @@ -10,13 +10,13 @@ "lint:check": "eslint . --ext .ts" }, "dependencies": { - "axios": "^1.7.9", "dotenv": "^16.4.7", - "viem": "^2.21.26", + "viem": "^2.48.11", "x402-fetch": "workspace:*" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "eslint": "^9.24.0", "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", @@ -24,7 +24,7 @@ "@typescript-eslint/parser": "^8.29.1", "eslint-plugin-import": "^2.31.0", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/e2e/legacy/clients/httpx/pyproject.toml b/e2e/legacy/clients/httpx/pyproject.toml index 1e6d4a3d0e..4edd26699e 100644 --- a/e2e/legacy/clients/httpx/pyproject.toml +++ b/e2e/legacy/clients/httpx/pyproject.toml @@ -21,6 +21,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/e2e/legacy/clients/requests/pyproject.toml b/e2e/legacy/clients/requests/pyproject.toml index ce8b798e5b..2dcde153a0 100644 --- a/e2e/legacy/clients/requests/pyproject.toml +++ b/e2e/legacy/clients/requests/pyproject.toml @@ -21,6 +21,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/e2e/legacy/servers/express/package.json b/e2e/legacy/servers/express/package.json index 514c255887..5108d684c1 100644 --- a/e2e/legacy/servers/express/package.json +++ b/e2e/legacy/servers/express/package.json @@ -17,6 +17,7 @@ "devDependencies": { "@eslint/js": "^9.24.0", "@types/express": "^5.0.1", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -24,8 +25,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } -} \ No newline at end of file +} diff --git a/e2e/legacy/servers/fastapi/pyproject.toml b/e2e/legacy/servers/fastapi/pyproject.toml index a963eadb99..3128cc268f 100644 --- a/e2e/legacy/servers/fastapi/pyproject.toml +++ b/e2e/legacy/servers/fastapi/pyproject.toml @@ -22,6 +22,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/e2e/legacy/servers/flask/pyproject.toml b/e2e/legacy/servers/flask/pyproject.toml index 50b9c2319b..5dff378fbd 100644 --- a/e2e/legacy/servers/flask/pyproject.toml +++ b/e2e/legacy/servers/flask/pyproject.toml @@ -21,6 +21,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/e2e/legacy/servers/gin/go.mod b/e2e/legacy/servers/gin/go.mod index 5c21953dec..4e1f3d0b5b 100644 --- a/e2e/legacy/servers/gin/go.mod +++ b/e2e/legacy/servers/gin/go.mod @@ -1,9 +1,9 @@ -module github.com/coinbase/x402/e2e/servers/gin +module github.com/x402-foundation/x402/e2e/servers/gin go 1.23.3 require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/gin-gonic/gin v1.10.0 github.com/joho/godotenv v1.5.1 ) @@ -39,4 +39,4 @@ require ( gopkg.in/yaml.v3 v3.0.1 // indirect ) -replace github.com/coinbase/x402/go => ../../../../go/legacy +replace github.com/x402-foundation/x402/go => ../../../../go/legacy diff --git a/e2e/legacy/servers/gin/main.go b/e2e/legacy/servers/gin/main.go index a3630f0221..a7ae87a3c5 100644 --- a/e2e/legacy/servers/gin/main.go +++ b/e2e/legacy/servers/gin/main.go @@ -9,10 +9,10 @@ import ( "syscall" "time" - x402gin "github.com/coinbase/x402/go/pkg/gin" - "github.com/coinbase/x402/go/pkg/types" "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402gin "github.com/x402-foundation/x402/go/pkg/gin" + "github.com/x402-foundation/x402/go/pkg/types" ) var shutdownRequested bool diff --git a/e2e/legacy/servers/hono/package.json b/e2e/legacy/servers/hono/package.json index 4f0cefc631..a87c734f92 100644 --- a/e2e/legacy/servers/hono/package.json +++ b/e2e/legacy/servers/hono/package.json @@ -16,9 +16,10 @@ "x402-hono": "workspace:*" }, "devDependencies": { - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0", + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "@types/node": "^22.13.4", + "typescript": "^5.7.3", "@eslint/js": "^9.24.0", "eslint": "^9.24.0", "eslint-plugin-jsdoc": "^50.6.9", diff --git a/e2e/legacy/servers/next/package.json b/e2e/legacy/servers/next/package.json index fe51d112e0..2c77fabb7a 100644 --- a/e2e/legacy/servers/next/package.json +++ b/e2e/legacy/servers/next/package.json @@ -13,17 +13,16 @@ "lint:check": "eslint . --ext .ts" }, "dependencies": { - "@heroicons/react": "^2.2.0", "next": "^15.5.9", "react": "19.2.3", "react-dom": "19.2.3", - "viem": "^2.21.26", + "viem": "^2.48.11", "x402-next": "workspace:*" }, "devDependencies": { "@eslint/js": "^9.24.0", "@svgr/webpack": "^8.1.0", - "@types/node": "^20", + "@types/node": "^22.13.4", "@types/react": "^19", "@types/react-dom": "^19", "@typescript-eslint/eslint-plugin": "^8.29.1", @@ -39,6 +38,6 @@ "prettier": "3.5.2", "stream-browserify": "^3.0.0", "tailwindcss": "^3.4.1", - "typescript": "^5" + "typescript": "^5.7.3" } } \ No newline at end of file diff --git a/e2e/package.json b/e2e/package.json index bdeb660fce..00a5b7ff86 100644 --- a/e2e/package.json +++ b/e2e/package.json @@ -2,6 +2,7 @@ "name": "x402-e2e", "version": "1.0.0", "description": "End-to-end tests for X402 protocol", + "packageManager": "pnpm@11.1.1", "main": "dist/test.js", "scripts": { "test": "tsx test.ts", @@ -16,20 +17,18 @@ "permit2:revoke": "tsx scripts/permit2-approval.ts revoke" }, "dependencies": { - "axios": "^1.6.0", "dotenv": "^17.0.1", - "express": "^4.18.0", "prompts": "^2.4.2", - "tsx": "^4.20.3", - "viem": "^2.0.0" + "tsx": "^4.21.0", + "viem": "^2.48.11" }, "devDependencies": { "@types/express": "^4.17.0", - "@types/node": "^20.0.0", + "@types/node": "^22.13.4", "@types/prompts": "^2.4.9", - "typescript": "^5.0.0" + "typescript": "^5.7.3" }, "engines": { - "node": ">=18.0.0" + "node": ">=22.0.0" } -} \ No newline at end of file +} diff --git a/e2e/pnpm-lock.yaml b/e2e/pnpm-lock.yaml index 40353cd865..8111735b0b 100644 --- a/e2e/pnpm-lock.yaml +++ b/e2e/pnpm-lock.yaml @@ -8,36 +8,30 @@ importers: .: dependencies: - axios: - specifier: ^1.6.0 - version: 1.10.0 dotenv: specifier: ^17.0.1 version: 17.0.1 - express: - specifier: ^4.18.0 - version: 4.21.2 prompts: specifier: ^2.4.2 version: 2.4.2 tsx: - specifier: ^4.20.3 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 viem: - specifier: ^2.0.0 - version: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) devDependencies: '@types/express': specifier: ^4.17.0 version: 4.17.23 '@types/node': - specifier: ^20.0.0 - version: 20.19.4 + specifier: ^22.13.4 + version: 22.16.0 '@types/prompts': specifier: ^2.4.9 version: 2.4.9 typescript: - specifier: ^5.0.0 + specifier: ^5.7.3 version: 5.8.3 ../typescript/packages/core: @@ -75,22 +69,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/extensions: dependencies: @@ -100,6 +94,9 @@ importers: '@scure/base': specifier: ^1.2.6 version: 1.2.6 + '@signinwithethereum/siwe': + specifier: ^4.1.0 + version: 4.1.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) '@x402/core': specifier: workspace:~ version: link:../core @@ -109,15 +106,12 @@ importers: jose: specifier: ^5.9.6 version: 5.10.0 - siwe: - specifier: ^2.3.2 - version: 2.3.2(ethers@6.16.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) tweetnacl: specifier: ^1.0.3 version: 1.0.3 viem: - specifier: ^2.43.5 - version: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) zod: specifier: ^3.24.2 version: 3.25.71 @@ -151,34 +145,28 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/http/axios: dependencies: '@x402/core': specifier: workspace:~ version: link:../../core - axios: - specifier: ^1.7.9 - version: 1.12.2 - zod: - specifier: ^3.24.2 - version: 3.25.71 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -192,6 +180,9 @@ importers: '@typescript-eslint/parser': specifier: ^8.29.1 version: 8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) + axios: + specifier: ^1.7.9 + version: 1.12.2 eslint: specifier: ^9.24.0 version: 9.38.0(jiti@1.21.7) @@ -209,22 +200,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/http/express: dependencies: @@ -237,12 +228,6 @@ importers: '@x402/paywall': specifier: workspace:^ version: link:../paywall - viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - zod: - specifier: ^3.24.2 - version: 3.25.71 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -279,22 +264,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/http/fastify: dependencies: @@ -305,7 +290,7 @@ importers: specifier: workspace:~ version: link:../../extensions '@x402/paywall': - specifier: workspace:* + specifier: workspace:^ version: link:../paywall devDependencies: '@eslint/js': @@ -340,34 +325,28 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/http/fetch: dependencies: '@x402/core': specifier: workspace:~ version: link:../../core - viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - zod: - specifier: ^3.24.2 - version: 3.25.71 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -398,22 +377,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/http/hono: dependencies: @@ -426,9 +405,6 @@ importers: '@x402/paywall': specifier: workspace:^ version: link:../paywall - zod: - specifier: ^3.24.2 - version: 3.25.71 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -462,22 +438,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/http/next: dependencies: @@ -491,11 +467,8 @@ importers: specifier: workspace:^ version: link:../paywall next: - specifier: ^16.0.10 - version: 16.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - zod: - specifier: ^3.24.2 - version: 3.25.71 + specifier: '>=16.0.10 <16.1.0' + version: 16.0.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3) devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -526,25 +499,34 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/http/paywall: dependencies: + '@algorandfoundation/algokit-utils': + specifier: 10.0.0-alpha.46 + version: 10.0.0-alpha.46 + '@blockshake/defly-connect': + specifier: ^1.2.1 + version: 1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@perawallet/connect': + specifier: ^1.4.2 + version: 1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@scure/base': specifier: ^1.2.6 version: 1.2.6 @@ -562,19 +544,22 @@ importers: version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10) '@solana/transaction-confirmation': specifier: ^2.1.1 - version: 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/wallet-standard-features': specifier: ^1.3.0 version: 1.3.0 '@tanstack/react-query': specifier: ^5.90.7 version: 5.90.8(react@19.2.0) + '@txnlab/use-wallet': + specifier: ^4.3.1 + version: 4.6.0(@blockshake/defly-connect@1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@perawallet/connect@1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@walletconnect/sign-client@2.23.9(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(algosdk@3.5.2)(lute-connect@1.7.0) '@wagmi/connectors': specifier: ^5.8.1 - version: 5.11.2(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71) + version: 5.11.2(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)))(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(zod@4.1.12))(zod@4.1.12) '@wagmi/core': specifier: ^2.17.1 - version: 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + version: 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) '@wallet-standard/app': specifier: ^1.1.0 version: 1.1.0 @@ -584,22 +569,25 @@ importers: '@wallet-standard/features': specifier: ^1.1.0 version: 1.1.0 + '@walletconnect/sign-client': + specifier: ^2.23.1 + version: 2.23.9(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) '@x402/core': specifier: workspace:~ version: link:../../core + lute-connect: + specifier: ^1.6.3 + version: 1.7.0 viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) wagmi: specifier: ^2.17.1 - version: 2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71) - zod: - specifier: ^3.24.2 - version: 3.25.71 + version: 2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(zod@4.1.12) devDependencies: '@craftamap/esbuild-plugin-html': specifier: ^0.9.0 - version: 0.9.0(bufferutil@4.0.9)(esbuild@0.25.5)(utf-8-validate@5.0.10) + version: 0.9.0(bufferutil@4.0.9)(esbuild@0.27.7)(utf-8-validate@5.0.10) '@eslint/js': specifier: ^9.24.0 version: 9.38.0 @@ -618,6 +606,9 @@ importers: '@typescript-eslint/parser': specifier: ^8.29.1 version: 8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) + '@x402/avm': + specifier: workspace:~ + version: link:../../mechanisms/avm '@x402/evm': specifier: workspace:~ version: link:../../mechanisms/evm @@ -628,8 +619,8 @@ importers: specifier: ^6.0.3 version: 6.0.3 esbuild: - specifier: ^0.25.4 - version: 0.25.5 + specifier: ^0.27.2 + version: 0.27.7 eslint: specifier: ^9.24.0 version: 9.38.0(jiti@1.21.7) @@ -653,22 +644,22 @@ importers: version: 19.2.0(react@19.2.0) tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/legacy/x402: dependencies: @@ -703,11 +694,11 @@ importers: specifier: ^1.1.0 version: 1.1.0 viem: - specifier: ^2.21.26 - version: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) wagmi: specifier: ^2.15.6 - version: 2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71) + version: 2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71) zod: specifier: ^3.24.2 version: 3.25.71 @@ -717,7 +708,7 @@ importers: version: 0.38.19(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(bufferutil@4.0.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.71) '@craftamap/esbuild-plugin-html': specifier: ^0.9.0 - version: 0.9.0(bufferutil@4.0.9)(esbuild@0.25.5)(utf-8-validate@5.0.10) + version: 0.9.0(bufferutil@4.0.9)(esbuild@0.27.7)(utf-8-validate@5.0.10) '@eslint/js': specifier: ^9.24.0 version: 9.38.0 @@ -738,16 +729,16 @@ importers: version: 8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) '@wagmi/connectors': specifier: ^5.8.1 - version: 5.11.2(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71) + version: 5.11.2(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71) '@wagmi/core': specifier: ^2.17.1 - version: 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + version: 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) buffer: specifier: ^6.0.3 version: 6.0.3 esbuild: - specifier: ^0.25.4 - version: 0.25.5 + specifier: ^0.27.2 + version: 0.27.7 eslint: specifier: ^9.24.0 version: 9.38.0(jiti@1.21.7) @@ -771,22 +762,22 @@ importers: version: 19.2.1(react@19.2.1) tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/legacy/x402-axios: dependencies: @@ -794,8 +785,8 @@ importers: specifier: ^1.7.9 version: 1.10.0 viem: - specifier: ^2.21.26 - version: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) x402: specifier: workspace:^ version: link:../x402 @@ -832,22 +823,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/legacy/x402-express: dependencies: @@ -861,8 +852,8 @@ importers: specifier: ^4.18.2 version: 4.21.2 viem: - specifier: ^2.21.26 - version: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) x402: specifier: workspace:^ version: link:../x402 @@ -902,28 +893,28 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/legacy/x402-fetch: dependencies: viem: - specifier: ^2.21.26 - version: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) x402: specifier: workspace:^ version: link:../x402 @@ -960,37 +951,37 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/legacy/x402-hono: dependencies: '@coinbase/cdp-sdk': specifier: ^1.22.0 - version: 1.38.4(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 1.38.4(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/kit': specifier: ^5.0.0 - version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) hono: specifier: ^4.7.1 version: 4.10.2 viem: - specifier: ^2.21.26 - version: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) x402: specifier: workspace:^ version: link:../x402 @@ -1027,22 +1018,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/legacy/x402-next: dependencies: @@ -1056,8 +1047,8 @@ importers: specifier: '>=15.5.9 || >=16.0.10' version: 16.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) viem: - specifier: ^2.21.26 - version: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) x402: specifier: workspace:^ version: link:../x402 @@ -1094,22 +1085,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/mcp: dependencies: @@ -1158,25 +1149,25 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 viem: - specifier: ^2.27.2 - version: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/mechanisms/aptos: dependencies: @@ -1184,7 +1175,7 @@ importers: specifier: ^5.2.1 version: 5.2.1(got@11.8.6) '@x402/core': - specifier: workspace:* + specifier: workspace:~ version: link:../../core devDependencies: '@eslint/js': @@ -1216,22 +1207,77 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 + typescript: + specifier: ^5.7.3 + version: 5.8.3 + vite: + specifier: ^6.2.6 + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) + vitest: + specifier: ^3.0.5 + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) + + ../typescript/packages/mechanisms/avm: + dependencies: + '@algorandfoundation/algokit-utils': + specifier: 10.0.0-alpha.46 + version: 10.0.0-alpha.46 + '@x402/core': + specifier: workspace:~ + version: link:../../core + devDependencies: + '@eslint/js': + specifier: ^9.24.0 + version: 9.38.0 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 + '@typescript-eslint/eslint-plugin': + specifier: ^8.29.1 + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) + '@typescript-eslint/parser': + specifier: ^8.29.1 + version: 8.48.0(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) + eslint: + specifier: ^9.24.0 + version: 9.38.0(jiti@1.21.7) + eslint-plugin-import: + specifier: ^2.31.0 + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0(jiti@1.21.7)) + eslint-plugin-jsdoc: + specifier: ^50.6.9 + version: 50.8.0(eslint@9.38.0(jiti@1.21.7)) + eslint-plugin-prettier: + specifier: ^5.2.6 + version: 5.5.4(eslint@9.38.0(jiti@1.21.7))(prettier@3.5.2) + prettier: + specifier: 3.5.2 + version: 3.5.2 + tsup: + specifier: ^8.4.0 + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) + tsx: + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/mechanisms/evm: dependencies: @@ -1239,8 +1285,8 @@ importers: specifier: workspace:~ version: link:../../core viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) zod: specifier: ^3.24.2 version: 3.25.71 @@ -1274,22 +1320,77 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 + typescript: + specifier: ^5.7.3 + version: 5.8.3 + vite: + specifier: ^6.2.6 + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) + vitest: + specifier: ^3.0.5 + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) + + ../typescript/packages/mechanisms/hedera: + dependencies: + '@hiero-ledger/sdk': + specifier: 2.80.0 + version: 2.80.0(bn.js@5.2.1)(react-native@0.85.2(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)) + '@x402/core': + specifier: workspace:* + version: link:../../core + devDependencies: + '@eslint/js': + specifier: ^9.24.0 + version: 9.38.0 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 + '@typescript-eslint/eslint-plugin': + specifier: ^8.29.1 + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) + '@typescript-eslint/parser': + specifier: ^8.29.1 + version: 8.48.0(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) + eslint: + specifier: ^9.24.0 + version: 9.38.0(jiti@1.21.7) + eslint-plugin-import: + specifier: ^2.31.0 + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.38.0(jiti@1.21.7)) + eslint-plugin-jsdoc: + specifier: ^50.6.9 + version: 50.8.0(eslint@9.38.0(jiti@1.21.7)) + eslint-plugin-prettier: + specifier: ^5.2.6 + version: 5.5.4(eslint@9.38.0(jiti@1.21.7))(prettier@3.5.2) + prettier: + specifier: 3.5.2 + version: 3.5.2 + tsup: + specifier: ^8.4.0 + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) + tsx: + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/mechanisms/stellar: dependencies: @@ -1297,7 +1398,7 @@ importers: specifier: ^14.6.1 version: 14.6.1 '@x402/core': - specifier: workspace:* + specifier: workspace:~ version: link:../../core devDependencies: '@eslint/js': @@ -1329,22 +1430,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../typescript/packages/mechanisms/svm: dependencies: @@ -1396,22 +1497,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1) + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.8.3 vite: specifier: ^6.2.6 - version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + version: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + version: 5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) clients/axios: dependencies: @@ -1427,6 +1528,9 @@ importers: '@x402/aptos': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/aptos + '@x402/avm': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/avm '@x402/axios': specifier: workspace:* version: link:../../../typescript/packages/http/axios @@ -1436,6 +1540,9 @@ importers: '@x402/evm': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/evm + '@x402/hedera': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/hedera '@x402/stellar': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/stellar @@ -1449,12 +1556,15 @@ importers: specifier: ^16.4.7 version: 16.6.1 viem: - specifier: ^2.21.26 - version: 2.38.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.38.0 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -1477,10 +1587,10 @@ importers: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 + specifier: ^5.7.3 version: 5.8.3 clients/fetch: @@ -1497,6 +1607,9 @@ importers: '@x402/aptos': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/aptos + '@x402/avm': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/avm '@x402/core': specifier: workspace:* version: link:../../../typescript/packages/core @@ -1506,25 +1619,28 @@ importers: '@x402/fetch': specifier: workspace:* version: link:../../../typescript/packages/http/fetch + '@x402/hedera': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/hedera '@x402/stellar': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/stellar '@x402/svm': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/svm - axios: - specifier: ^1.7.9 - version: 1.10.0 dotenv: specifier: ^16.4.7 version: 16.6.1 viem: - specifier: ^2.21.26 - version: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.38.0 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -1547,10 +1663,10 @@ importers: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 + specifier: ^5.7.3 version: 5.8.3 clients/mcp-typescript: @@ -1558,9 +1674,6 @@ importers: '@modelcontextprotocol/sdk': specifier: ^1.15.1 version: 1.25.3(hono@4.10.2)(zod@4.1.12) - '@x402/core': - specifier: workspace:* - version: link:../../../typescript/packages/core '@x402/evm': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/evm @@ -1568,12 +1681,15 @@ importers: specifier: workspace:* version: link:../../../typescript/packages/mcp viem: - specifier: ^2.21.26 - version: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.38.0 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -1596,10 +1712,10 @@ importers: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 + specifier: ^5.7.3 version: 5.8.3 facilitators/typescript: @@ -1616,6 +1732,9 @@ importers: '@x402/aptos': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/aptos + '@x402/avm': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/avm '@x402/core': specifier: workspace:* version: link:../../../typescript/packages/core @@ -1625,6 +1744,9 @@ importers: '@x402/extensions': specifier: workspace:* version: link:../../../typescript/packages/extensions + '@x402/hedera': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/hedera '@x402/stellar': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/stellar @@ -1638,26 +1760,26 @@ importers: specifier: ^4.19.2 version: 4.21.2 viem: - specifier: ^2.21.54 - version: 2.38.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) devDependencies: '@types/express': specifier: ^4.17.21 version: 4.17.23 '@types/node': - specifier: ^22.10.1 + specifier: ^22.13.4 version: 22.16.0 eslint: - specifier: ^9.15.0 + specifier: ^9.24.0 version: 9.38.0(jiti@1.21.7) prettier: - specifier: ^3.3.3 + specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.19.2 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.7.2 + specifier: ^5.7.3 version: 5.8.3 legacy/clients/axios: @@ -1669,8 +1791,8 @@ importers: specifier: ^16.5.0 version: 16.6.1 viem: - specifier: ^2.21.26 - version: 2.38.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) x402-axios: specifier: workspace:* version: link:../../../../typescript/packages/legacy/x402-axios @@ -1678,6 +1800,9 @@ importers: '@eslint/js': specifier: ^9.24.0 version: 9.38.0 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -1700,23 +1825,20 @@ importers: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 + specifier: ^5.7.3 version: 5.8.3 legacy/clients/fetch: dependencies: - axios: - specifier: ^1.7.9 - version: 1.12.2 dotenv: specifier: ^16.4.7 version: 16.6.1 viem: - specifier: ^2.21.26 - version: 2.38.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) x402-fetch: specifier: workspace:* version: link:../../../../typescript/packages/legacy/x402-fetch @@ -1724,6 +1846,9 @@ importers: '@eslint/js': specifier: ^9.24.0 version: 9.38.0 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -1746,10 +1871,10 @@ importers: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 + specifier: ^5.7.3 version: 5.8.3 legacy/servers/express: @@ -1770,6 +1895,9 @@ importers: '@types/express': specifier: ^5.0.1 version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -1792,13 +1920,13 @@ importers: specifier: 3.5.2 version: 3.5.2 tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.8.3) + specifier: ^8.4.0 + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 + specifier: ^5.7.3 version: 5.8.3 legacy/servers/hono: @@ -1819,6 +1947,9 @@ importers: '@eslint/js': specifier: ^9.24.0 version: 9.38.0 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -1841,20 +1972,17 @@ importers: specifier: 3.5.2 version: 3.5.2 tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.8.3) + specifier: ^8.4.0 + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 + specifier: ^5.7.3 version: 5.8.3 legacy/servers/next: dependencies: - '@heroicons/react': - specifier: ^2.2.0 - version: 2.2.0(react@19.2.3) next: specifier: ^15.5.9 version: 15.5.9(@babel/core@7.28.4)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -1865,8 +1993,8 @@ importers: specifier: 19.2.3 version: 19.2.3(react@19.2.3) viem: - specifier: ^2.21.26 - version: 2.38.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) x402-next: specifier: workspace:* version: link:../../../../typescript/packages/legacy/x402-next @@ -1878,8 +2006,8 @@ importers: specifier: ^8.1.0 version: 8.1.0(typescript@5.8.3) '@types/node': - specifier: ^20 - version: 20.19.4 + specifier: ^22.13.4 + version: 22.16.0 '@types/react': specifier: ^19 version: 19.2.2 @@ -1924,9 +2052,9 @@ importers: version: 3.0.0 tailwindcss: specifier: ^3.4.1 - version: 3.4.18(tsx@4.20.3)(yaml@2.8.1) + version: 3.4.18(tsx@4.21.0)(yaml@2.8.1) typescript: - specifier: ^5 + specifier: ^5.7.3 version: 5.8.3 servers/express: @@ -1934,6 +2062,9 @@ importers: '@x402/aptos': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/aptos + '@x402/avm': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/avm '@x402/core': specifier: workspace:* version: link:../../../typescript/packages/core @@ -1946,6 +2077,9 @@ importers: '@x402/extensions': specifier: workspace:* version: link:../../../typescript/packages/extensions + '@x402/hedera': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/hedera '@x402/stellar': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/stellar @@ -1965,6 +2099,9 @@ importers: '@types/express': specifier: ^5.0.1 version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -1987,13 +2124,13 @@ importers: specifier: 3.5.2 version: 3.5.2 tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.8.3) + specifier: ^8.4.0 + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 + specifier: ^5.7.3 version: 5.8.3 servers/fastify: @@ -2001,6 +2138,9 @@ importers: '@x402/aptos': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/aptos + '@x402/avm': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/avm '@x402/core': specifier: workspace:* version: link:../../../typescript/packages/core @@ -2013,6 +2153,9 @@ importers: '@x402/fastify': specifier: workspace:* version: link:../../../typescript/packages/http/fastify + '@x402/hedera': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/hedera '@x402/stellar': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/stellar @@ -2029,6 +2172,9 @@ importers: '@eslint/js': specifier: ^9.24.0 version: 9.38.0 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -2051,13 +2197,13 @@ importers: specifier: 3.5.2 version: 3.5.2 tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.8.3) + specifier: ^8.4.0 + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 + specifier: ^5.7.3 version: 5.8.3 servers/hono: @@ -2068,6 +2214,9 @@ importers: '@x402/aptos': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/aptos + '@x402/avm': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/avm '@x402/core': specifier: workspace:* version: link:../../../typescript/packages/core @@ -2077,6 +2226,9 @@ importers: '@x402/extensions': specifier: workspace:* version: link:../../../typescript/packages/extensions + '@x402/hedera': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/hedera '@x402/hono': specifier: workspace:* version: link:../../../typescript/packages/http/hono @@ -2099,6 +2251,9 @@ importers: '@types/express': specifier: ^5.0.1 version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 version: 8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -2121,13 +2276,13 @@ importers: specifier: 3.5.2 version: 3.5.2 tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.8.3) + specifier: ^8.4.0 + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 + specifier: ^5.7.3 version: 5.8.3 servers/mcp-typescript: @@ -2141,6 +2296,9 @@ importers: '@x402/evm': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/evm + '@x402/extensions': + specifier: workspace:* + version: link:../../../typescript/packages/extensions '@x402/mcp': specifier: workspace:* version: link:../../../typescript/packages/mcp @@ -2157,6 +2315,9 @@ importers: '@types/express': specifier: ^5.0.1 version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.16.0 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -2179,23 +2340,23 @@ importers: specifier: 3.5.2 version: 3.5.2 tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.8.3) + specifier: ^8.4.0 + version: 8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.3 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 + specifier: ^5.7.3 version: 5.8.3 servers/next: dependencies: - '@heroicons/react': - specifier: ^2.2.0 - version: 2.2.0(react@19.2.3) '@x402/aptos': specifier: workspace:* version: link:../../../typescript/packages/mechanisms/aptos + '@x402/avm': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/avm '@x402/core': specifier: workspace:* version: link:../../../typescript/packages/core @@ -2205,6 +2366,9 @@ importers: '@x402/extensions': specifier: workspace:* version: link:../../../typescript/packages/extensions + '@x402/hedera': + specifier: workspace:* + version: link:../../../typescript/packages/mechanisms/hedera '@x402/next': specifier: workspace:* version: link:../../../typescript/packages/http/next @@ -2216,7 +2380,7 @@ importers: version: link:../../../typescript/packages/mechanisms/svm next: specifier: ^16.0.10 - version: 16.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + version: 16.0.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3) react: specifier: ^19.2.3 version: 19.2.3 @@ -2224,15 +2388,15 @@ importers: specifier: ^19.2.3 version: 19.2.3(react@19.2.3) viem: - specifier: ^2.21.26 - version: 2.38.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.38.0 '@types/node': - specifier: ^20 - version: 20.19.4 + specifier: ^22.13.4 + version: 22.16.0 '@types/react': specifier: ^19 version: 19.2.2 @@ -2277,19 +2441,23 @@ importers: version: 3.0.0 tailwindcss: specifier: ^3.4.1 - version: 3.4.18(tsx@4.20.3)(yaml@2.8.1) + version: 3.4.18(tsx@4.21.0)(yaml@2.8.1) typescript: - specifier: ^5 + specifier: ^5.7.3 version: 5.8.3 packages: - '@adraffy/ens-normalize@1.10.1': - resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} - '@adraffy/ens-normalize@1.11.0': resolution: {integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==} + '@algorandfoundation/algokit-utils@10.0.0-alpha.46': + resolution: {integrity: sha512-Lx56ET6RmrDCFGwx6qyIr7YRX3Q3MyKgqkNeumLkFHXVkqMnXnK1aLeEbV59EOK8UHQ5UPJofSj1zvRMm9Du7w==} + engines: {node: '>=20.0'} + + '@algorandfoundation/xhd-wallet-api@2.0.0-canary.1': + resolution: {integrity: sha512-U6rSWMO6FKDLvMxWtfKyW5ctqSy2NrONWTU/jOA+BX0SGru0GPXsxwzFdcPa5w+X055V/xVVsr8eA3xA+m/5jA==} + '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} engines: {node: '>=10'} @@ -2315,6 +2483,10 @@ packages: resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.28.4': resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} engines: {node: '>=6.9.0'} @@ -2327,6 +2499,10 @@ packages: resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -2402,6 +2578,10 @@ packages: resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -2419,6 +2599,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1': resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==} engines: {node: '>=6.9.0'} @@ -2858,17 +3043,34 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.4': + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.28.4': resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + '@babel/types@7.28.4': resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + '@base-org/account@1.1.1': resolution: {integrity: sha512-IfVJPrDPhHfqXRDb89472hXkpvJuQQR7FDI9isLPHEqSYt/45whIoBxSPgZ0ssTt379VhQo4+87PWI1DoLSfAQ==} + '@blockshake/defly-connect@1.2.1': + resolution: {integrity: sha512-T9wAjPTFdc8iRiDzTqmeBRCIroWLgXmqZHwnpzuchjYZXXqbnj+zge+HS7UaNunpxGVjDUNK1ah7OR6hEqtJoQ==} + peerDependencies: + algosdk: ^3.0.0 + '@coinbase/cdp-sdk@1.38.4': resolution: {integrity: sha512-xVvfluaGt0NxNmjElP3C1yI6KnsGwihabdXj+qNtjjsSmd/Ha2V3gAiCyNrrYOqIORn4mpC2jgu2fUFEDaMpaw==} @@ -2937,23 +3139,17 @@ packages: resolution: {integrity: sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==} engines: {node: '>=18'} - '@esbuild/aix-ppc64@0.19.12': - resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - '@esbuild/aix-ppc64@0.25.5': resolution: {integrity: sha512-9o3TMmpmftaCMepOdA5k/yDw8SfInyzWWTjYTFCX3kPSDJMROQTb8jg+h9Cnwnmm1vOzvxN7gIfB5V2ewpjtGA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.19.12': - resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] '@esbuild/android-arm64@0.25.5': resolution: {integrity: sha512-VGzGhj4lJO+TVGV1v8ntCZWJktV7SGCs3Pn1GRWI1SBFtRALoomm8k5E9Pmwg3HOAal2VDc2F9+PM/rEY6oIDg==} @@ -2961,10 +3157,10 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm@0.19.12': - resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} - engines: {node: '>=12'} - cpu: [arm] + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] os: [android] '@esbuild/android-arm@0.25.5': @@ -2973,10 +3169,10 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-x64@0.19.12': - resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] os: [android] '@esbuild/android-x64@0.25.5': @@ -2985,11 +3181,11 @@ packages: cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.19.12': - resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] '@esbuild/darwin-arm64@0.25.5': resolution: {integrity: sha512-GtaBgammVvdF7aPIgH2jxMDdivezgFu6iKpmT+48+F8Hhg5J/sfnDieg0aeG/jfSvkYQU2/pceFPDKlqZzwnfQ==} @@ -2997,10 +3193,10 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.19.12': - resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] os: [darwin] '@esbuild/darwin-x64@0.25.5': @@ -3009,11 +3205,11 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.19.12': - resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] '@esbuild/freebsd-arm64@0.25.5': resolution: {integrity: sha512-nk4tGP3JThz4La38Uy/gzyXtpkPW8zSAmoUhK9xKKXdBCzKODMc2adkB2+8om9BDYugz+uGV7sLmpTYzvmz6Sw==} @@ -3021,10 +3217,10 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.19.12': - resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] os: [freebsd] '@esbuild/freebsd-x64@0.25.5': @@ -3033,11 +3229,11 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.19.12': - resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] '@esbuild/linux-arm64@0.25.5': resolution: {integrity: sha512-Z9kfb1v6ZlGbWj8EJk9T6czVEjjq2ntSYLY2cw6pAZl4oKtfgQuS4HOq41M/BcoLPzrUbNd+R4BXFyH//nHxVg==} @@ -3045,10 +3241,10 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.19.12': - resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} - engines: {node: '>=12'} - cpu: [arm] + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] os: [linux] '@esbuild/linux-arm@0.25.5': @@ -3057,10 +3253,10 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.19.12': - resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} - engines: {node: '>=12'} - cpu: [ia32] + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] os: [linux] '@esbuild/linux-ia32@0.25.5': @@ -3069,10 +3265,10 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.19.12': - resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} - engines: {node: '>=12'} - cpu: [loong64] + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] os: [linux] '@esbuild/linux-loong64@0.25.5': @@ -3081,10 +3277,10 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.19.12': - resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} - engines: {node: '>=12'} - cpu: [mips64el] + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] os: [linux] '@esbuild/linux-mips64el@0.25.5': @@ -3093,10 +3289,10 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.19.12': - resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} - engines: {node: '>=12'} - cpu: [ppc64] + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] os: [linux] '@esbuild/linux-ppc64@0.25.5': @@ -3105,10 +3301,10 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.19.12': - resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} - engines: {node: '>=12'} - cpu: [riscv64] + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] os: [linux] '@esbuild/linux-riscv64@0.25.5': @@ -3117,10 +3313,10 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.19.12': - resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} - engines: {node: '>=12'} - cpu: [s390x] + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] os: [linux] '@esbuild/linux-s390x@0.25.5': @@ -3129,10 +3325,10 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.19.12': - resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] os: [linux] '@esbuild/linux-x64@0.25.5': @@ -3141,16 +3337,22 @@ packages: cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.5': resolution: {integrity: sha512-pwHtMP9viAy1oHPvgxtOv+OkduK5ugofNTVDilIzBLpoWAM16r7b/mxBvfpuQDpRQFMfuVr5aLcn4yveGvBZvw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.19.12': - resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] os: [netbsd] '@esbuild/netbsd-x64@0.25.5': @@ -3159,16 +3361,22 @@ packages: cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.5': resolution: {integrity: sha512-7A208+uQKgTxHd0G0uqZO8UjK2R0DDb4fDmERtARjSHWxqMTye4Erz4zZafx7Di9Cv+lNHYuncAkiGFySoD+Mw==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.19.12': - resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] os: [openbsd] '@esbuild/openbsd-x64@0.25.5': @@ -3177,11 +3385,17 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/sunos-x64@0.19.12': - resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} - engines: {node: '>=12'} + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} cpu: [x64] - os: [sunos] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] '@esbuild/sunos-x64@0.25.5': resolution: {integrity: sha512-l+azKShMy7FxzY0Rj4RCt5VD/q8mG/e+mDivgspo+yL8zW7qEwctQ6YqKX34DTEleFAvCIUviCFX1SDZRSyMQA==} @@ -3189,11 +3403,11 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.19.12': - resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] '@esbuild/win32-arm64@0.25.5': resolution: {integrity: sha512-O2S7SNZzdcFG7eFKgvwUEZ2VG9D/sn/eIiz8XRZ1Q/DO5a3s76Xv0mdBzVM5j5R639lXQmPmSo0iRpHqUUrsxw==} @@ -3201,10 +3415,10 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.19.12': - resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} - engines: {node: '>=12'} - cpu: [ia32] + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] os: [win32] '@esbuild/win32-ia32@0.25.5': @@ -3213,10 +3427,10 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.19.12': - resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} - engines: {node: '>=12'} - cpu: [x64] + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] os: [win32] '@esbuild/win32-x64@0.25.5': @@ -3225,6 +3439,12 @@ packages: cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -3279,6 +3499,63 @@ packages: resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} engines: {node: '>=14'} + '@ethersproject/abi@5.8.0': + resolution: {integrity: sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==} + + '@ethersproject/abstract-provider@5.8.0': + resolution: {integrity: sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==} + + '@ethersproject/abstract-signer@5.8.0': + resolution: {integrity: sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==} + + '@ethersproject/address@5.8.0': + resolution: {integrity: sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==} + + '@ethersproject/base64@5.8.0': + resolution: {integrity: sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==} + + '@ethersproject/bignumber@5.8.0': + resolution: {integrity: sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==} + + '@ethersproject/bytes@5.8.0': + resolution: {integrity: sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==} + + '@ethersproject/constants@5.8.0': + resolution: {integrity: sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==} + + '@ethersproject/hash@5.8.0': + resolution: {integrity: sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==} + + '@ethersproject/keccak256@5.8.0': + resolution: {integrity: sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==} + + '@ethersproject/logger@5.8.0': + resolution: {integrity: sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==} + + '@ethersproject/networks@5.8.0': + resolution: {integrity: sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==} + + '@ethersproject/properties@5.8.0': + resolution: {integrity: sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==} + + '@ethersproject/rlp@5.8.0': + resolution: {integrity: sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==} + + '@ethersproject/signing-key@5.8.0': + resolution: {integrity: sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==} + + '@ethersproject/strings@5.8.0': + resolution: {integrity: sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==} + + '@ethersproject/transactions@5.8.0': + resolution: {integrity: sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==} + + '@ethersproject/web@5.8.0': + resolution: {integrity: sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==} + + '@evanhahn/lottie-web-light@5.8.1': + resolution: {integrity: sha512-U0G1tt3/UEYnyCNNslWPi1dB7X1xQ9aoSip+B3GTKO/Bns8yz/p39vBkRSN9d25nkbHuCsbjky2coQftj5YVKw==} + '@farcaster/frame-sdk@0.1.12': resolution: {integrity: sha512-qlikvkxsrsvKGutr3PM3Yvsuni2Fku15aPagrCyHZWbYAJrZ4mRJM6u9S8eLAXMMnYd9gJ9yor6COYgmZMBOgQ==} engines: {node: '>=22.11.0'} @@ -3334,10 +3611,39 @@ packages: peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@heroicons/react@2.2.0': - resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==} + '@grpc/grpc-js@1.12.6': + resolution: {integrity: sha512-JXUj6PI0oqqzTGvKtzOkxtpsyPRNsrmhh41TtIz/zEB6J+AUiZZ0dxWzcMwO9Ns5rmSPuMdghlTbUuqIM48d3Q==} + engines: {node: '>=12.10.0'} + + '@grpc/proto-loader@0.7.15': + resolution: {integrity: sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==} + engines: {node: '>=6'} + hasBin: true + + '@hiero-ledger/cryptography@1.16.0-beta.3': + resolution: {integrity: sha512-7+R/HKGq6LiqUZ1agn52sQS6J3+VXBWvqIMUCIU1EVdbEPQDPoVPJYEd7dDreBCLIcjBRcHVjDc9wbi+ar2rsA==} + engines: {node: '>=12.0.0'} + peerDependencies: + expo-crypto: '*' + peerDependenciesMeta: + expo-crypto: + optional: true + + '@hiero-ledger/proto@2.26.0-beta.3': + resolution: {integrity: sha512-2UhTKX2RbL2LC8XcgetFa4iS5d8cELY/8PmFolj750z4CoQu2YOchZTqNTdI431qR9uAx3aBVSf+mx/YBYIUNA==} + engines: {node: '>=10.0.0'} + peerDependencies: + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + debug: 4.4.1 + protobufjs: 7.5.4 + strip-ansi: 7.1.2 + + '@hiero-ledger/sdk@2.80.0': + resolution: {integrity: sha512-9FHNPduWl27eNI2Gns0O6GJTqcEJ11lBTML84A7D8albCErVXaUVsnRrASafH+Xfq1dqK5dwsNHRwu8WtM3zVQ==} + engines: {node: '>=18.0.0'} peerDependencies: - react: '>= 16 || ^19.0.0-rc' + bn.js: 5.2.1 '@hono/node-server@1.19.5': resolution: {integrity: sha512-iBuhh+uaaggeAuf+TftcjZyWh2GEgZcVGXkNtskLVoWaXhnJtC5HLHrU8W1KHDoucqO1MswwglmkWLFyiDn4WQ==} @@ -3397,78 +3703,92 @@ packages: resolution: {integrity: sha512-I4RxkXU90cpufazhGPyVujYwfIm9Nk1QDEmiIsaPwdnm013F7RIceaCc87kAH+oUB1ezqEvC6ga4m7MSlqsJvQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.3': resolution: {integrity: sha512-x1uE93lyP6wEwGvgAIV0gP6zmaL/a0tGzJs/BIDDG0zeBhMnuUPm7ptxGhUbcGs4okDJrk4nxgrmxpib9g6HpA==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.3': resolution: {integrity: sha512-Y2T7IsQvJLMCBM+pmPbM3bKT/yYJvVtLJGfCs4Sp95SjvnFIjynbjzsa7dY1fRJX45FTSfDksbTp6AGWudiyCg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.3': resolution: {integrity: sha512-RgWrs/gVU7f+K7P+KeHFaBAJlNkD1nIZuVXdQv6S+fNA6syCcoboNjsV2Pou7zNlVdNQoQUpQTk8SWDHUA3y/w==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.3': resolution: {integrity: sha512-3JU7LmR85K6bBiRzSUc/Ff9JBVIFVvq6bomKE0e63UXGeRw2HPVEjoJke1Yx+iU4rL7/7kUjES4dZ/81Qjhyxg==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.3': resolution: {integrity: sha512-F9q83RZ8yaCwENw1GieztSfj5msz7GGykG/BA+MOUefvER69K/ubgFHNeSyUu64amHIYKGDs4sRCMzXVj8sEyw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.3': resolution: {integrity: sha512-U5PUY5jbc45ANM6tSJpsgqmBF/VsL6LnxJmIf11kB7J5DctHgqm0SkuXzVWtIY90GnJxKnC/JT251TDnk1fu/g==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.4': resolution: {integrity: sha512-YXU1F/mN/Wu786tl72CyJjP/Ngl8mGHN1hST4BGl+hiW5jhCnV2uRVTNOcaYPs73NeT/H8Upm3y9582JVuZHrQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.4': resolution: {integrity: sha512-Xyam4mlqM0KkTHYVSuc6wXRmM7LGN0P12li03jAnZ3EJWZqj83+hi8Y9UxZUbxsgsK1qOEwg7O0Bc0LjqQVtxA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.4': resolution: {integrity: sha512-F4PDtF4Cy8L8hXA2p3TO6s4aDt93v+LKmpcYFLAVdkkD3hSxZzee0rh6/+94FpAynsuMpLX5h+LRsSG3rIciUQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.4': resolution: {integrity: sha512-qVrZKE9Bsnzy+myf7lFKvng6bQzhNUAYcVORq2P7bDlvmF6u2sCmK2KyEQEBdYk+u3T01pVsPrkj943T1aJAsw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.4': resolution: {integrity: sha512-ZfGtcp2xS51iG79c6Vhw9CWqQC8l2Ot8dygxoDoIQPTat/Ov3qAa8qpxSrtAEAJW+UjTXc4yxCjNfxm4h6Xm2A==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.4': resolution: {integrity: sha512-8hDVvW9eu4yHWnjaOOR8kHVrew1iIX+MUgwxSuH2XyYeNRtLUe4VNioSqbNkB7ZYQJj9rUTT4PyRscyk2PXFKA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.4': resolution: {integrity: sha512-lU0aA5L8QTlfKjpDCEFOZsTYGn3AEiO6db8W5aQDxj0nQkVrZWmN3ZP9sYKWJdtq3PWPhUNlqehWyXpYDcI9Sg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.4': resolution: {integrity: sha512-33QL6ZO/qpRyG7woB/HUALz28WnTMI2W1jgX3Nu2bypqLIKx/QKMILLJzJjI+SIbvXdG9fUnmrxR7vbi1sTBeA==} @@ -3497,6 +3817,18 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/ttlcache@1.4.1': + resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} + engines: {node: '>=12'} + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -3507,12 +3839,21 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + '@js-sdsl/ordered-map@4.4.2': + resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + + '@likecoin/qr-code-styling@1.6.6': + resolution: {integrity: sha512-RbGK/+20bJhFZR70r8MeDvfyz3W7U5zXpykSTYOYxZGyo6wC+Y4QnbUpL+YdAtzT2ZIFeCNOcRs2W2FNrKPoaA==} + '@lit-labs/ssr-dom-shim@1.4.0': resolution: {integrity: sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==} @@ -3609,12 +3950,19 @@ packages: '@cfworker/json-schema': optional: true + '@msgpack/msgpack@3.1.3': + resolution: {integrity: sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==} + engines: {node: '>= 18'} + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} '@next/env@15.5.9': resolution: {integrity: sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==} + '@next/env@16.0.10': + resolution: {integrity: sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==} + '@next/env@16.1.1': resolution: {integrity: sha512-3oxyM97Sr2PqiVyMyrZUtrtM3jqqFxOQJVuKclDsgj/L728iZt/GyslkN4NwarledZATCenbk4Offjk1hQmaAA==} @@ -3630,6 +3978,12 @@ packages: cpu: [arm64] os: [darwin] + '@next/swc-darwin-arm64@16.0.10': + resolution: {integrity: sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + '@next/swc-darwin-arm64@16.1.1': resolution: {integrity: sha512-JS3m42ifsVSJjSTzh27nW+Igfha3NdBOFScr9C80hHGrWx55pTrVL23RJbqir7k7/15SKlrLHhh/MQzqBBYrQA==} engines: {node: '>= 10'} @@ -3642,6 +3996,12 @@ packages: cpu: [x64] os: [darwin] + '@next/swc-darwin-x64@16.0.10': + resolution: {integrity: sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + '@next/swc-darwin-x64@16.1.1': resolution: {integrity: sha512-hbyKtrDGUkgkyQi1m1IyD3q4I/3m9ngr+V93z4oKHrPcmxwNL5iMWORvLSGAf2YujL+6HxgVvZuCYZfLfb4bGw==} engines: {node: '>= 10'} @@ -3653,48 +4013,84 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] + + '@next/swc-linux-arm64-gnu@16.0.10': + resolution: {integrity: sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] '@next/swc-linux-arm64-gnu@16.1.1': resolution: {integrity: sha512-/fvHet+EYckFvRLQ0jPHJCUI5/B56+2DpI1xDSvi80r/3Ez+Eaa2Yq4tJcRTaB1kqj/HrYKn8Yplm9bNoMJpwQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@15.5.7': resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] + + '@next/swc-linux-arm64-musl@16.0.10': + resolution: {integrity: sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] '@next/swc-linux-arm64-musl@16.1.1': resolution: {integrity: sha512-MFHrgL4TXNQbBPzkKKur4Fb5ICEJa87HM7fczFs2+HWblM7mMLdco3dvyTI+QmLBU9xgns/EeeINSZD6Ar+oLg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@15.5.7': resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] + + '@next/swc-linux-x64-gnu@16.0.10': + resolution: {integrity: sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] '@next/swc-linux-x64-gnu@16.1.1': resolution: {integrity: sha512-20bYDfgOQAPUkkKBnyP9PTuHiJGM7HzNBbuqmD0jiFVZ0aOldz+VnJhbxzjcSabYsnNjMPsE0cyzEudpYxsrUQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@15.5.7': resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] + + '@next/swc-linux-x64-musl@16.0.10': + resolution: {integrity: sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] '@next/swc-linux-x64-musl@16.1.1': resolution: {integrity: sha512-9pRbK3M4asAHQRkwaXwu601oPZHghuSC8IXNENgbBSyImHv/zY4K5udBusgdHkvJ/Tcr96jJwQYOll0qU8+fPA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@15.5.7': resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} @@ -3702,6 +4098,12 @@ packages: cpu: [arm64] os: [win32] + '@next/swc-win32-arm64-msvc@16.0.10': + resolution: {integrity: sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + '@next/swc-win32-arm64-msvc@16.1.1': resolution: {integrity: sha512-bdfQkggaLgnmYrFkSQfsHfOhk/mCYmjnrbRCGgkMcoOBZ4n+TRRSLmT/CU5SATzlBJ9TpioUyBW/vWFXTqQRiA==} engines: {node: '>= 10'} @@ -3714,12 +4116,22 @@ packages: cpu: [x64] os: [win32] + '@next/swc-win32-x64-msvc@16.0.10': + resolution: {integrity: sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + '@next/swc-win32-x64-msvc@16.1.1': resolution: {integrity: sha512-Ncwbw2WJ57Al5OX0k4chM68DKhEPlrXBaSXDCi2kPi5f4d8b3ejr3RRJGfKBLrn2YJL5ezNS7w2TZLHSti8CMw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] + '@noble/ciphers@1.2.0': + resolution: {integrity: sha512-YGdEUzYEd+82jeaVbSKKVp1jFZb8LwaNMIIzHFkihGvYdd/KKAr7KaJHdEdSYGredE3ssSravXIa0Jxg28Sv5w==} + engines: {node: ^14.21.3 || >=16} + '@noble/ciphers@1.2.1': resolution: {integrity: sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==} engines: {node: ^14.21.3 || >=16} @@ -3728,8 +4140,9 @@ packages: resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} engines: {node: ^14.21.3 || >=16} - '@noble/curves@1.2.0': - resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} + '@noble/ciphers@2.1.1': + resolution: {integrity: sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw==} + engines: {node: '>= 20.19.0'} '@noble/curves@1.4.2': resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} @@ -3746,17 +4159,16 @@ packages: resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} engines: {node: ^14.21.3 || >=16} - '@noble/curves@1.9.2': - resolution: {integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==} - engines: {node: ^14.21.3 || >=16} - '@noble/curves@1.9.7': resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} engines: {node: ^14.21.3 || >=16} - '@noble/hashes@1.3.2': - resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} - engines: {node: '>= 16'} + '@noble/curves@2.0.1': + resolution: {integrity: sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==} + engines: {node: '>= 20.19.0'} + + '@noble/ed25519@3.0.1': + resolution: {integrity: sha512-t/T8LuK0ym8ALQudCCQCtrRdMSxBnRgHXw+wg+YsSlE6d+on7sX3flqlSJ2mOs9xEuchM36kj9SuX5MG7pXQMA==} '@noble/hashes@1.4.0': resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} @@ -3774,6 +4186,10 @@ packages: resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} + '@noble/hashes@2.0.1': + resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} + engines: {node: '>= 20.19.0'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -3794,6 +4210,11 @@ packages: resolution: {integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==} deprecated: 'The package is now available as "qr": npm install qr' + '@perawallet/connect@1.5.2': + resolution: {integrity: sha512-Lq4nLaQBisZUkBIWirhRn4b9MjrKWvlMxfrU6On5al/14E5mm3dlnwGHhpJ88IGlnGs7JyL625LVMgUK1TOTrg==} + peerDependencies: + algosdk: ^3.5.2 + '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} @@ -3805,6 +4226,92 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + + '@react-native/assets-registry@0.85.2': + resolution: {integrity: sha512-kauC/oPaxklU4Y+u9gBfCBJm51qX6WBZq4xx0USCdimtp+G8+554kpygfSWIjoqCJa2o06bWxBEjesiuCv+LzA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/codegen@0.85.2': + resolution: {integrity: sha512-XCginmxh0//++EXVOEJHBVZxHla294FzLCFF6jXwAUjvXVhqyIKyxhABfz+r4OOmaiuWk4Rtd4arqdAzeHeprg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@babel/core': '*' + + '@react-native/community-cli-plugin@0.85.2': + resolution: {integrity: sha512-3KLgSg1kHvBpr93zMaQhvfYTgnCw7yZRED+3J4dMcYjfSjtD0Wf8SofU6uBmAw9JaVYvP43lpdwUpI4p0+ABsg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@react-native-community/cli': '*' + '@react-native/metro-config': 0.85.2 + peerDependenciesMeta: + '@react-native-community/cli': + optional: true + '@react-native/metro-config': + optional: true + + '@react-native/debugger-frontend@0.85.2': + resolution: {integrity: sha512-j+0b9H5f5hGTLQxHIhJU/b/W6ijuxJF+ZTLHB0se2kzUBNxFKd7DkIc6753qk3CJdiv55vxG3XDgmlpbHxOpmA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/debugger-shell@0.85.2': + resolution: {integrity: sha512-r5BkhqPMfg3LmaZS5zadHmBNVH5h4bhSpv4BEPGfK4gat9HABAMzUzybi+2wpgU3SoHxnyKGdExEJvoqVcjeRg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/dev-middleware@0.85.2': + resolution: {integrity: sha512-3J+NaDUg+QEfDeLAUzgaWhpaxEg78g+KwbydlDCewh2G6WnHpsty8XooruxNHzyAsqVWywZMrzmbn78Ctc1O9Q==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/gradle-plugin@0.85.2': + resolution: {integrity: sha512-YXBOLeAqFrv7XwUeBPTKZeOV1FIxn4AW7UAEitScf3ibC8bu8+6NpJu4HWgbNQHg7vDbbTZVbcOl8EwGxsSq2w==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/js-polyfills@0.85.2': + resolution: {integrity: sha512-esGEAmKVM40DV/yVmNljCKZTIeUo7qXqc+Hwffkv3TG+b3E24xyFovHrbP98gGxZr2ZsEyx+2sKLdXF5asY5nw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/normalize-colors@0.85.2': + resolution: {integrity: sha512-svuOLtjbFGXDdHsriHXuND5FgHg7XlkOXCbH/8+X4t76YLH6qSTffSIQQrKLDL5mn4EFU+Oh/PNO0/FfpnTOTg==} + + '@react-native/virtualized-lists@0.85.2': + resolution: {integrity: sha512-wmVKpAlcr+UB0L5SpbrV865EdleUP7I5+X+48e1aRsQK8q+wsTRBXeUwWVip/1l+HZwlZFeO8iOILJ16VRu0Cw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@types/react': ^19.2.0 + react: '*' + react-native: 0.85.2 + peerDependenciesMeta: + '@types/react': + optional: true + '@reown/appkit-common@1.7.8': resolution: {integrity: sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==} @@ -3868,56 +4375,67 @@ packages: resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.52.5': resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.52.5': resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.52.5': resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loong64-gnu@4.52.5': resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.52.5': resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.52.5': resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.52.5': resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.52.5': resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.52.5': resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.52.5': resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openharmony-arm64@4.52.5': resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} @@ -3984,6 +4502,23 @@ packages: '@scure/bip39@1.6.0': resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} + '@signinwithethereum/siwe-parser@4.1.0': + resolution: {integrity: sha512-aS+bU5QpTQgMpC6HjQHuKJpltUrkyGUVNuhuBLARa39wF1B+m05/4bgnf2qrEcgQONfU36A2Nbn3ibmwhHkc2Q==} + + '@signinwithethereum/siwe@4.1.0': + resolution: {integrity: sha512-NT56M82i+A2uBU++F9PSBvEYPcjUV3BdClRVojWt3cbe7WizIVH1wi2qKJJR570RLHZvr8q1gUf0E90WymlMeA==} + peerDependencies: + ethers: ^5.7.0 || ^6.13.0 + viem: ^2.7.0 + peerDependenciesMeta: + ethers: + optional: true + viem: + optional: true + + '@sinclair/typebox@0.27.10': + resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} + '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -5283,23 +5818,8 @@ packages: '@solana/web3.js@1.98.4': resolution: {integrity: sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==} - '@spruceid/siwe-parser@2.1.2': - resolution: {integrity: sha512-d/r3S1LwJyMaRAKQ0awmo9whfXeE88Qt00vRj91q5uv5ATtWIQEGJ67Yr5eSZw5zp1/fZCXZYuEckt8lSkereQ==} - - '@stablelib/binary@1.0.1': - resolution: {integrity: sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==} - - '@stablelib/int@1.0.1': - resolution: {integrity: sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==} - - '@stablelib/random@1.0.2': - resolution: {integrity: sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==} - - '@stablelib/wipe@1.0.1': - resolution: {integrity: sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==} - - '@stellar/js-xdr@3.1.2': - resolution: {integrity: sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==} + '@stellar/js-xdr@3.1.2': + resolution: {integrity: sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==} '@stellar/stellar-base@14.1.0': resolution: {integrity: sha512-A8kFli6QGy22SRF45IjgPAJfUNGjnI+R7g4DF5NZYVsD1kGf7B4ITyc4OPclLV9tqNI4/lXxafGEw0JEUbHixw==} @@ -5406,10 +5926,49 @@ packages: peerDependencies: react: ^18 || ^19 + '@tanstack/store@0.8.0': + resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + '@trysound/sax@0.2.0': resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} + '@txnlab/use-wallet@4.6.0': + resolution: {integrity: sha512-niAookAa8cpkrZsGDwQUaeLTODSd5gxSiUHaiPDiHiF/4oGKx/X/KJOFwAA/8iXOI8CTe60fbwEiKRXNIa1RvQ==} + peerDependencies: + '@agoralabs-sh/avm-web-provider': ^1.7.0 + '@blockshake/defly-connect': ^1.2.1 + '@perawallet/connect': ^1.4.1 + '@walletconnect/modal': ^2.7.0 + '@walletconnect/sign-client': ^2.23.4 + '@web3auth/base': ^9.0.0 + '@web3auth/base-provider': ^9.0.0 + '@web3auth/modal': ^9.0.0 + '@web3auth/single-factor-auth': ^9.0.0 + algosdk: ^3.0.0 + lute-connect: ^1.6.3 + peerDependenciesMeta: + '@agoralabs-sh/avm-web-provider': + optional: true + '@blockshake/defly-connect': + optional: true + '@perawallet/connect': + optional: true + '@walletconnect/modal': + optional: true + '@walletconnect/sign-client': + optional: true + '@web3auth/base': + optional: true + '@web3auth/base-provider': + optional: true + '@web3auth/modal': + optional: true + '@web3auth/single-factor-auth': + optional: true + lute-connect: + optional: true + '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} @@ -5452,6 +6011,15 @@ packages: '@types/http-errors@2.0.5': resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -5473,15 +6041,9 @@ packages: '@types/node@12.20.55': resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - '@types/node@20.19.4': - resolution: {integrity: sha512-OP+We5WV8Xnbuvw0zC2m4qfB/BJvjyCwtNjhHdJxV1639SGSKrLmJkc3fMnp2Qy8nJyHp8RO6umxELN/dS1/EA==} - '@types/node@22.16.0': resolution: {integrity: sha512-B2egV9wALML1JCpv3VQoQ+yesQKAmNMBIAY7OteVrikcOcAkWm+dGL6qpeCktPjAv6N1JLnhbNiqS35UpFyBsQ==} - '@types/node@22.7.5': - resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} - '@types/prompts@2.4.9': resolution: {integrity: sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA==} @@ -5520,6 +6082,12 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + '@typescript-eslint/eslint-plugin@8.46.2': resolution: {integrity: sha512-ZGBMToy857/NIPaaCucIUQgqueOiq7HeAKkhlvqVV4lm089zUFW6ikRySx2v+cAhKeUCPuWVHeimyk6Dw1iY3w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -5677,41 +6245,49 @@ packages: resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.11.1': resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} cpu: [arm64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} cpu: [riscv64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} cpu: [s390x] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.11.1': resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} cpu: [x64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.11.1': resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} cpu: [x64] os: [linux] + libc: [musl] '@unrs/resolver-binding-wasm32-wasi@1.11.1': resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} @@ -5806,6 +6382,16 @@ packages: resolution: {integrity: sha512-hiEivWNztx73s+7iLxsuD1sOJ28xtRix58W7Xnz4XzzA/pF0+aicnWgjOdA10doVDEDZdUuZCIIqG96SFNlDUg==} engines: {node: '>=16'} + '@walletconnect/browser-utils@1.8.0': + resolution: {integrity: sha512-Wcqqx+wjxIo9fv6eBUFHPsW1y/bGWWRboni5dfD8PtOmrihrEpOCmvRJe4rfl7xgJW8Ea9UqKEaq0bIRLHlK4A==} + + '@walletconnect/client@1.8.0': + resolution: {integrity: sha512-svyBQ14NHx6Cs2j4TpkQaBI/2AF4+LXz64FojTjMtV4VMMhl81jSO1vNeg+yYhQzvjcGH/GpSwixjyCW0xFBOQ==} + deprecated: 'WalletConnect''s v1 SDKs are now deprecated. Please upgrade to a v2 SDK. For details see: https://docs.walletconnect.com/' + + '@walletconnect/core@1.8.0': + resolution: {integrity: sha512-aFTHvEEbXcZ8XdWBw6rpQDte41Rxwnuk3SgTD8/iKGSRTni50gI9S3YEzMj05jozSiOBxQci4pJDMVhIUMtarw==} + '@walletconnect/core@2.21.0': resolution: {integrity: sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==} engines: {node: '>=18'} @@ -5814,6 +6400,16 @@ packages: resolution: {integrity: sha512-Tp4MHJYcdWD846PH//2r+Mu4wz1/ZU/fr9av1UWFiaYQ2t2TPLDiZxjLw54AAEpMqlEHemwCgiRiAmjR1NDdTQ==} engines: {node: '>=18'} + '@walletconnect/core@2.23.9': + resolution: {integrity: sha512-ws4WG8LeagUo2ERRo02HryXRcpwIRmCQ3pHLW5gWbVReLXXIpgk6ZAfID3fEGHevIwwnHSGww+nNhNpdXyiq0g==} + engines: {node: '>=18.20.8'} + + '@walletconnect/crypto@1.1.0': + resolution: {integrity: sha512-yZO8BBTQt7BcaemjDgwN56OmSv0OO4QjIpvtfj5OxZfL6IQZQWHOhwC6pJg+BmZPbDlJlWFqFuCZRtiPwRmsoA==} + + '@walletconnect/encoding@1.0.2': + resolution: {integrity: sha512-CrwSBrjqJ7rpGQcTL3kU+Ief+Bcuu9PH6JLOb+wM6NITX1GTxR/MfNwnQfhLKK6xpRAyj2/nM04OOH6wS8Imag==} + '@walletconnect/environment@1.0.1': resolution: {integrity: sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==} @@ -5826,6 +6422,9 @@ packages: '@walletconnect/heartbeat@1.2.2': resolution: {integrity: sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==} + '@walletconnect/iso-crypto@1.8.0': + resolution: {integrity: sha512-pWy19KCyitpfXb70hA73r9FcvklS+FvO9QUIttp3c2mfW8frxgYeRXfxLRCIQTkaYueRKvdqPjbyhPLam508XQ==} + '@walletconnect/jsonrpc-http-connection@1.0.8': resolution: {integrity: sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==} @@ -5852,45 +6451,81 @@ packages: '@walletconnect/logger@2.1.2': resolution: {integrity: sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==} + '@walletconnect/logger@3.0.2': + resolution: {integrity: sha512-7wR3wAwJTOmX4gbcUZcFMov8fjftY05+5cO/d4cpDD8wDzJ+cIlKdYOXaXfxHLSYeDazMXIsxMYjHYVDfkx+nA==} + + '@walletconnect/randombytes@1.1.0': + resolution: {integrity: sha512-X+LO/9ClnXX2Q/1+u83qMnohVaxC4qsXByM/gMSwGMrUObxEiqEWS+b9Upg9oNl6mTr85dTCRF8W17KVcKKXQw==} + '@walletconnect/relay-api@1.0.11': resolution: {integrity: sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==} '@walletconnect/relay-auth@1.1.0': resolution: {integrity: sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==} + '@walletconnect/safe-json@1.0.0': + resolution: {integrity: sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg==} + '@walletconnect/safe-json@1.0.2': resolution: {integrity: sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==} '@walletconnect/sign-client@2.21.0': resolution: {integrity: sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' '@walletconnect/sign-client@2.21.1': resolution: {integrity: sha512-QaXzmPsMnKGV6tc4UcdnQVNOz4zyXgarvdIQibJ4L3EmLat73r5ZVl4c0cCOcoaV7rgM9Wbphgu5E/7jNcd3Zg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' + + '@walletconnect/sign-client@2.23.9': + resolution: {integrity: sha512-Xj+hw4E6mGRyhCdVOT/RMgnG+up/Y3v0ho5PlkVozvXWeVSqHNh9DmjLuU97a7OACoGd/oHBF6g3NVqD7MgCMQ==} + + '@walletconnect/socket-transport@1.8.0': + resolution: {integrity: sha512-5DyIyWrzHXTcVp0Vd93zJ5XMW61iDM6bcWT4p8DTRfFsOtW46JquruMhxOLeCOieM4D73kcr3U7WtyR4JUsGuQ==} '@walletconnect/time@1.0.2': resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} + '@walletconnect/types@1.8.0': + resolution: {integrity: sha512-Cn+3I0V0vT9ghMuzh1KzZvCkiAxTq+1TR2eSqw5E5AVWfmCtECFkVZBP6uUJZ8YjwLqXheI+rnjqPy7sVM4Fyg==} + deprecated: 'WalletConnect''s v1 SDKs are now deprecated. Please upgrade to a v2 SDK. For details see: https://docs.walletconnect.com/' + '@walletconnect/types@2.21.0': resolution: {integrity: sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==} '@walletconnect/types@2.21.1': resolution: {integrity: sha512-UeefNadqP6IyfwWC1Yi7ux+ljbP2R66PLfDrDm8izmvlPmYlqRerJWJvYO4t0Vvr9wrG4Ko7E0c4M7FaPKT/sQ==} + '@walletconnect/types@2.23.9': + resolution: {integrity: sha512-IUl1PpD/Dig8IE2OZ9XtjbPohEyOZJ73xs92EDUzoIyzRtfm36g2D340pY3iu3AAdLv1yFiaZafB8Hf8RFze8A==} + '@walletconnect/universal-provider@2.21.0': resolution: {integrity: sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==} '@walletconnect/universal-provider@2.21.1': resolution: {integrity: sha512-Wjx9G8gUHVMnYfxtasC9poGm8QMiPCpXpbbLFT+iPoQskDDly8BwueWnqKs4Mx2SdIAWAwuXeZ5ojk5qQOxJJg==} + '@walletconnect/utils@1.8.0': + resolution: {integrity: sha512-zExzp8Mj1YiAIBfKNm5u622oNw44WOESzo6hj+Q3apSMIb0Jph9X3GDIdbZmvVZsNPxWDL7uodKgZcCInZv2vA==} + '@walletconnect/utils@2.21.0': resolution: {integrity: sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==} '@walletconnect/utils@2.21.1': resolution: {integrity: sha512-VPZvTcrNQCkbGOjFRbC24mm/pzbRMUq2DSQoiHlhh0X1U7ZhuIrzVtAoKsrzu6rqjz0EEtGxCr3K1TGRqDG4NA==} + '@walletconnect/utils@2.23.9': + resolution: {integrity: sha512-C5TltCs8UPypNiteYnKSv8+ZDK2EjVDyXCxN6kA9bkA+j6KGsNIV7l9MUA8WBAvE5Gi5EcBdhD3R9Hpo/1HHqQ==} + + '@walletconnect/window-getters@1.0.0': + resolution: {integrity: sha512-xB0SQsLaleIYIkSsl43vm8EwETpBzJ2gnzk7e0wMF3ktqiTGS6TFHxcprMl5R44KKh4tCcHCJwolMCaDSwtAaA==} + '@walletconnect/window-getters@1.0.1': resolution: {integrity: sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==} + '@walletconnect/window-metadata@1.0.0': + resolution: {integrity: sha512-9eFvmJxIKCC3YWOL97SgRkKhlyGXkrHwamfechmqszbypFspaSk+t2jQXAEU7YClHF6Qjw5eYOmy1//zFi9/GA==} + '@walletconnect/window-metadata@1.0.1': resolution: {integrity: sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==} @@ -5916,17 +6551,6 @@ packages: zod: optional: true - abitype@1.1.0: - resolution: {integrity: sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - abitype@1.2.3: resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} peerDependencies: @@ -5938,6 +6562,10 @@ packages: zod: optional: true + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} @@ -5959,9 +6587,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - aes-js@4.0.0-beta.5: - resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} - agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -5984,6 +6609,21 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + algo-msgpack-with-bigint@2.1.1: + resolution: {integrity: sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==} + engines: {node: '>= 10'} + + algorand-msgpack@1.1.0: + resolution: {integrity: sha512-08k7pBQnkaUB5p+jL7f1TRaUIlTSDE0cesFu1mD7llLao+1cAhtvvZmGE3OnisTd0xOn118QMw74SRqddqaYvw==} + engines: {node: '>= 14'} + + algosdk@3.5.2: + resolution: {integrity: sha512-frhGtZl1JvfrLRKmMvUm880wj4OiWsWo2FhbreNWh7pdFsKuWPj60fV682wt/CYefLI70iwHavPOwGBkTVt0VA==} + engines: {node: '>=18.0.0'} + + anser@1.4.10: + resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -5996,6 +6636,10 @@ packages: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.3: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} @@ -6035,10 +6679,6 @@ packages: resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} - array.prototype.findlast@1.2.5: resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} engines: {node: '>= 0.4'} @@ -6063,9 +6703,16 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + asn1.js@4.10.1: resolution: {integrity: sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==} + asn1js@3.0.6: + resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==} + engines: {node: '>=12.0.0'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -6131,6 +6778,9 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-syntax-hermes-parser@0.33.3: + resolution: {integrity: sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -6154,6 +6804,9 @@ packages: big.js@6.2.2: resolution: {integrity: sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==} + bignumber.js@9.1.1: + resolution: {integrity: sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==} + bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} @@ -6161,9 +6814,18 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + + bn.js@4.11.8: + resolution: {integrity: sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==} + bn.js@4.12.2: resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==} + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + bn.js@5.2.2: resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} @@ -6181,6 +6843,9 @@ packages: borsh@0.7.0: resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + bowser@2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + bowser@2.12.1: resolution: {integrity: sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==} @@ -6225,6 +6890,12 @@ packages: bs58@6.0.0: resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer-xor@1.0.3: resolution: {integrity: sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==} @@ -6232,15 +6903,9 @@ packages: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} bufferutil@4.0.9: - resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==} + resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==, tarball: https://artifactory.cbhq.net:8081/artifactory/api/npm/cb-npm-master/bufferutil/-/bufferutil-4.0.9.tgz} engines: {node: '>=6.14.2'} - bundle-require@4.2.1: - resolution: {integrity: sha512-7Q/6vkyYAwOmQNRw75x+4yRtZCZJXUDmHHlFdkiV0wgv/reNjtJwpu1jPJ0w2kbEpIM0uoKI3S4/f39dU7AjSA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} - peerDependencies: - esbuild: '>=0.17' - bundle-require@5.1.0: resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6321,6 +6986,21 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chrome-launcher@0.15.2: + resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} + engines: {node: '>=12.13.0'} + hasBin: true + + chromium-edge-launcher@0.3.0: + resolution: {integrity: sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==} + + ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + cipher-base@1.0.7: resolution: {integrity: sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==} engines: {node: '>= 0.10'} @@ -6331,6 +7011,10 @@ packages: cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clone-response@1.0.3: resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} @@ -6349,6 +7033,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -6397,6 +7084,10 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} + consola@3.4.2: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} @@ -6487,6 +7178,9 @@ packages: resolution: {integrity: sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==} engines: {node: '>= 0.10'} + crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} @@ -6541,6 +7235,9 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} @@ -6569,6 +7266,15 @@ packages: supports-color: optional: true + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -6650,6 +7356,9 @@ packages: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-browser@5.2.0: + resolution: {integrity: sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA==} + detect-browser@5.3.0: resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==} @@ -6666,10 +7375,6 @@ packages: dijkstrajs@1.0.3: resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} - dlv@1.1.3: resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} @@ -6762,6 +7467,9 @@ packages: error-ex@1.3.4: resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + es-abstract@1.24.0: resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} engines: {node: '>= 0.4'} @@ -6800,22 +7508,25 @@ packages: es-toolkit@1.33.0: resolution: {integrity: sha512-X13Q/ZSc+vsO1q600bvNK4bxgXMkHcf//RxCmYDaRY5DAcT+eoXjY5hoAPGMdRnWQjvyLEcyauG3b6hz76LNqg==} + es-toolkit@1.44.0: + resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==} + es6-promise@4.2.8: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} es6-promisify@5.0.0: resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} - esbuild@0.19.12: - resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} - engines: {node: '>=12'} - hasBin: true - esbuild@0.25.5: resolution: {integrity: sha512-P8OtKZRv/5J5hhz0cUAdu/cLuPIKXpQl1R9pZtvmHWQvrAUVd0UNIPT4IB4W3rNOqVO0rlqHmCIbSwxh/c9yUQ==} engines: {node: '>=18'} hasBin: true + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -7002,9 +7713,9 @@ packages: ethereum-cryptography@2.2.1: resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} - ethers@6.16.0: - resolution: {integrity: sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==} - engines: {node: '>=14.0.0'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} eventemitter2@6.4.9: resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} @@ -7031,14 +7742,13 @@ packages: evp_bytestokey@1.0.3: resolution: {integrity: sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==} - execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} - expect-type@1.2.2: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + express-rate-limit@7.5.1: resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} engines: {node: '>= 16'} @@ -7061,6 +7771,12 @@ packages: resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} engines: {node: '> 0.1.90'} + fast-base64-decode@1.0.0: + resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==} + + fast-copy@3.0.2: + resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + fast-decode-uri-component@1.0.1: resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} @@ -7112,6 +7828,14 @@ packages: fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fb-dotslash@0.5.8: + resolution: {integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==} + engines: {node: '>=20'} + hasBin: true + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -7136,6 +7860,10 @@ packages: resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} engines: {node: '>=0.10.0'} + finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + finalhandler@1.3.1: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} @@ -7166,6 +7894,9 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flow-enums-runtime@0.0.6: + resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + follow-redirects@1.15.9: resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} engines: {node: '>=4.0'} @@ -7183,6 +7914,10 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + forge-light@1.1.4: + resolution: {integrity: sha512-Nr0xdu93LJawgBZVU/tC+A+4pbKqigdY5PRBz8CXNm4e5saAZIqU2Qe9+nVFtVO5TWCHSgvI0LaZZuatgE5J1g==} + engines: {node: '>= 6.13.0'} + form-data@4.0.3: resolution: {integrity: sha512-qsITQPfmvMOSAdeyZ+12I1c+CKSstAFAwu+97zrnWAbIr5u8wfsExUzCesVLC8NgHuRUqNN4Zy6UPWUTRGslcA==} engines: {node: '>= 6'} @@ -7242,10 +7977,6 @@ packages: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} - get-symbol-description@1.1.0: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} @@ -7263,6 +7994,7 @@ packages: glob@10.4.5: resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true globals@14.0.0: @@ -7277,10 +8009,6 @@ packages: resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} engines: {node: '>= 0.4'} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} - globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} @@ -7292,6 +8020,9 @@ packages: resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} engines: {node: '>=10.19.0'} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} @@ -7345,12 +8076,33 @@ packages: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + + hermes-compiler@250829098.0.10: + resolution: {integrity: sha512-TcRlZ0/TlyfJqquRFAWoyElVNnkdYRi/sEp4/Qy8/GYxjg8j2cS9D4MjuaQ+qimkmLN7AmO+44IznRf06mAr0w==} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + hermes-estree@0.33.3: + resolution: {integrity: sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==} + + hermes-estree@0.35.0: + resolution: {integrity: sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==} + hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + hermes-parser@0.33.3: + resolution: {integrity: sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==} + + hermes-parser@0.35.0: + resolution: {integrity: sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==} + + hi-base32@0.5.1: + resolution: {integrity: sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==} + hmac-drbg@1.0.1: resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} @@ -7385,10 +8137,6 @@ packages: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} - humanize-ms@1.2.1: resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} @@ -7421,6 +8169,11 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} + image-size@1.2.1: + resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} + engines: {node: '>=16.x'} + hasBin: true + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -7436,6 +8189,9 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} @@ -7496,6 +8252,11 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -7574,6 +8335,9 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -7586,6 +8350,10 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -7622,6 +8390,22 @@ packages: engines: {node: '>=8'} hasBin: true + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jiti@1.21.7: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true @@ -7636,9 +8420,24 @@ packages: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} + js-base64@3.7.4: + resolution: {integrity: sha512-wpM/wi20Tl+3ifTyi0RdDckS4YTD4Lf953mBRrpG8547T7hInHNPEj8+ck4gB8VDcGyeAWFK++Wb/fU1BeavKQ==} + + js-base64@3.7.7: + resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + js-base64@3.7.8: resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} + js-sha256@0.9.0: + resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==} + + js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + + js-sha512@0.8.0: + resolution: {integrity: sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -7649,6 +8448,9 @@ packages: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true + jsc-safe-url@0.2.4: + resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==} + jsdoc-type-pratt-parser@4.1.0: resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} engines: {node: '>=12.0.0'} @@ -7667,6 +8469,9 @@ packages: engines: {node: '>=6'} hasBin: true + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -7736,6 +8541,10 @@ packages: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} engines: {node: '>=0.10'} + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -7743,6 +8552,9 @@ packages: light-my-request@6.6.0: resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} + lighthouse-logger@1.4.2: + resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} + lilconfig@3.1.3: resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} engines: {node: '>=14'} @@ -7771,6 +8583,9 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} @@ -7780,13 +8595,22 @@ packages: lodash.sortby@4.7.0: resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + long@5.3.1: + resolution: {integrity: sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + lottie-web@5.13.0: + resolution: {integrity: sha512-+gfBXl6sxXMPe8tKQm7qzLnUy5DUPJPKIyRHwtpCpyUEYjHYRJC/5gjUvdkuO2c3JllrPtHXH5UJJK8LRYl5yQ==} + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} @@ -7803,9 +8627,18 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lute-connect@1.7.0: + resolution: {integrity: sha512-/eXb2/c/xltKyVEVWchd1QZB6F0fvgXwVIqXDQWeJ9unPo0kMMbtuLkeb1v4Kr1lffxX8uGnb+8kAMYjczUASg==} + magic-string@0.30.19: resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + marky@1.3.0: + resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -7830,6 +8663,9 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} + memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} + merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} @@ -7848,6 +8684,64 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} + metro-babel-transformer@0.84.3: + resolution: {integrity: sha512-svAA+yMLpeMiGcz/jKJs4oHpIGEx4nBqNEJ5AGj4CYIg1efvK+A0TjR6tgIuc6tKO5e8JmN/1lglpN2+f3/z/w==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-cache-key@0.84.3: + resolution: {integrity: sha512-TnSL1Fdvrw+2glTdBSRmA5TL8l/i16ECjsrUdf3E5HncA+sNx8KcwDG8r+3ct1UhfYcusJypzZqTN55FZZcwGg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-cache@0.84.3: + resolution: {integrity: sha512-0QElxwLaHqLZf+Xqio8QrjVbuXP/8sJfQBGSPiITlKDVXrVLefuzYVSH9Sj+QL6lrPj2gYZd/iwQh1yZuVKnLA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-config@0.84.3: + resolution: {integrity: sha512-JmCzZWOETR+O22q8oPBWyQppx3roU9EbkbGzD8Gf1jukQ4b5T1fTzqqHruu6K4sTiNq5zVQySmKF6bp4kVARew==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-core@0.84.3: + resolution: {integrity: sha512-cc0pvAa80ai1nDmqqz0P59a+0ZqCZ/YHU/3jEekZL6spFnYDfX8iDLdn9FR6kX+67rmzKxHNrbrSRFLX2AYocw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-file-map@0.84.3: + resolution: {integrity: sha512-1cL4m4Jv1yRUt9RJExZQLfccscdlMNOcRG6LHLtmJhf3BG9j3MujPVc7CIpKYdFl+KUl+sdjge6oO3+meKCHQA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-minify-terser@0.84.3: + resolution: {integrity: sha512-3ofrG2OQyJbO9RNhCfOcl8QU7EE2WrSsnN5dFkuZaJO5+4Imujr9bUXmspeNlXRsOVk0F/rVRbEFH98lFSCkBQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-resolver@0.84.3: + resolution: {integrity: sha512-pjEzGDtoM8DTHAIPK/9u9ZxszEiuRohYUVImWvgbnB91V4gqYJpQcoEYUugf2NIm1lrX5HNu0OvNqWmPBnGYjA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-runtime@0.84.3: + resolution: {integrity: sha512-o7HLRfMyVk9N2dUZ9VjQfB6xxUItL9Pi9WcqxURE7MEKOH6wbGt9/E92YdYLluTOtkzYAEVfdC6h6lcxqA+hMQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-source-map@0.84.3: + resolution: {integrity: sha512-jS48CeSzw78M8y6VE0f9uy3lVmfbOS677j2VCxnlmlYmnahcXuC6IhoN9K6LynNvos9517yUadcfgioju38xYQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-symbolicate@0.84.3: + resolution: {integrity: sha512-J9Tpo8NCycYrozRvBIUyOwGAu4xkawOsAppmTscFiaegK0WvuDGwIM53GbzVSnytCHjVAF0io5GQxpkrKTuc7g==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + + metro-transform-plugins@0.84.3: + resolution: {integrity: sha512-8S3baq2XhBaafHEH5Q8sJW6tmzsEJk80qKc3RU/nZV1MsnYq94RdjTUR6AyKjQd6Rfsk1BtBxhtiNnk7mgslCg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-transform-worker@0.84.3: + resolution: {integrity: sha512-Wjba7PyYktNRsHbPmkx2J2UX32rAzcDXjCu49zPHeF/viJlYJhwRaNePQcHaCRqQ+kmgQT4ThprsnJfDj71ZMA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro@0.84.3: + resolution: {integrity: sha512-1h3lbVrE6hGf1e/764HfhPGg/bGrWMJDDh7G2rc4gFYZboVuI40BlG/y+UhtbhQDNlO/csMvrcnK0YrTlHUVew==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + micro-ftch@0.3.1: resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} @@ -7880,10 +8774,6 @@ packages: engines: {node: '>=4'} hasBin: true - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - mimic-response@1.0.1: resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} engines: {node: '>=4'} @@ -7920,6 +8810,11 @@ packages: typescript: optional: true + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} @@ -7980,6 +8875,27 @@ packages: sass: optional: true + next@16.0.10: + resolution: {integrity: sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==} + engines: {node: '>=20.9.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true + next@16.1.1: resolution: {integrity: sha512-QI+T7xrxt1pF6SQ/JYFz95ro/mg/1Znk5vBebsWwbpejj1T0A23hO7GYEaVac9QUOT2BIMiuzm0L99ooq7k0/w==} engines: {node: '>=20.9.0'} @@ -8023,6 +8939,9 @@ packages: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + node-mock-http@1.0.3: resolution: {integrity: sha512-jN8dK25fsfnMrVsEhluUTPkBFY+6ybu7jSB1n+ri/vOGjJxU8J9CZhpSGkHXSkFjtUhbmoncG/YG9ta5Ludqog==} @@ -8037,16 +8956,19 @@ packages: resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} engines: {node: '>=10'} - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} - nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nullthrows@1.1.1: + resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} + nwsapi@2.2.22: resolution: {integrity: sha512-ujSMe1OWVn55euT1ihwCI1ZcAaAU3nxUiDwfDQldc51ZXaB9m2AyOn6/jh1BLe2t/G8xd6uKG1UBF2aZJeg2SQ==} + ob1@0.84.3: + resolution: {integrity: sha512-J7554Ef8bzmKaDY365Afq6PF+qtdnY/d5PKUQFrsKlZHV/N3OGZewVrvDrQDyX5V5NJjTpcAKtlrFZcDr+HvpQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + obj-multiplex@1.0.0: resolution: {integrity: sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA==} @@ -8096,6 +9018,10 @@ packages: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} + on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -8103,9 +9029,9 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} + open@7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} openapi-fetch@0.13.8: resolution: {integrity: sha512-yJ4QKRyNxE44baQ9mY5+r/kAzZ8yXMemtNAOFwOzRXJscdjSxxzWSNlyBAr+o5JjkUw9Lc3W7OIoca0cY3PYnQ==} @@ -8121,8 +9047,8 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} - ox@0.11.3: - resolution: {integrity: sha512-1bWYGk/xZel3xro3l8WGg6eq4YEKlaqvyMtVhfMFpbJzK2F6rj4EDRtqDCWVEJMkzcmEi9uW2QxsqELokOlarw==} + ox@0.14.20: + resolution: {integrity: sha512-rby38C3nDn8eQkf29Zgw4hkCZJ64Qqi0zRPWL8ENUQ7JVuoITqrVtwWQgM/He19SCMUEc7hS/Sjw0jIOSLJhOw==} peerDependencies: typescript: '>=5.4.0' peerDependenciesMeta: @@ -8153,14 +9079,6 @@ packages: typescript: optional: true - ox@0.8.1: - resolution: {integrity: sha512-e+z5epnzV+Zuz91YYujecW8cF01mzmrUtWotJ0oEPym/G82uccs7q0WDHTYL3eiONbTUEvcZrptAKLgTBD3u2A==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - ox@0.9.12: resolution: {integrity: sha512-esyA5WXfFhlxpgzoVIEreRaasqqv95sjFpk3L4Me4RWk8bgBDe+J4wO3RZ5ikYmJ2Bbjyv+jKgxyaOzX6JpHPA==} peerDependencies: @@ -8169,8 +9087,8 @@ packages: typescript: optional: true - ox@0.9.6: - resolution: {integrity: sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg==} + ox@0.9.3: + resolution: {integrity: sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg==} peerDependencies: typescript: '>=5.4.0' peerDependenciesMeta: @@ -8291,15 +9209,30 @@ packages: pino-abstract-transport@0.5.0: resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==} + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + pino-abstract-transport@3.0.0: resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} + pino-pretty@13.0.0: + resolution: {integrity: sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==} + hasBin: true + pino-std-serializers@4.0.0: resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==} pino-std-serializers@7.1.0: resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + pino@10.0.0: + resolution: {integrity: sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA==} + hasBin: true + + pino@10.1.0: + resolution: {integrity: sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==} + hasBin: true + pino@10.3.1: resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} hasBin: true @@ -8366,18 +9299,6 @@ packages: peerDependencies: postcss: ^8.4.21 - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - postcss-load-config@6.0.1: resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} engines: {node: '>= 18'} @@ -8436,6 +9357,10 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -8448,6 +9373,9 @@ packages: process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + promise@8.3.0: + resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + prompts@2.4.2: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} @@ -8455,6 +9383,10 @@ packages: prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + protobufjs@7.5.4: + resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + engines: {node: '>=12.0.0'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -8475,6 +9407,19 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.5: + resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} + engines: {node: '>=16.0.0'} + + qr-code-styling@1.6.0-rc.1: + resolution: {integrity: sha512-ModRIiW6oUnsP18QzrRYZSc/CFKFKIdj7pUs57AEVH20ajlglRpN3HukjHk0UbNMTlKGuaYl7Gt6/O5Gg2NU2Q==} + + qrcode-generator@1.5.2: + resolution: {integrity: sha512-pItrW0Z9HnDBnFmgiNrY1uxRdri32Uh9EjNYLPVC2zZ3ZRIIEqBoDgm4DkvDwNNDHTK7FNkmr8zAa77BYc9xNw==} + qrcode@1.5.3: resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} engines: {node: '>=10.13.0'} @@ -8493,6 +9438,10 @@ packages: resolution: {integrity: sha512-4EK3+xJl8Ts67nLYNwqw/dsFVnCf+qR7RgXSK9jEEm9unao3njwMDdmsdvoKBKHzxd7tCYz5e5M+SnMjdtXGQQ==} engines: {node: '>=0.6'} + query-string@6.13.5: + resolution: {integrity: sha512-svk3xg9qHR39P3JlHuD7g3nRnyay5mHbrPctEBDUxUkHRifPHXJDhBUycdCC0NBjXoDf44Gb+IsOZL1Uwn8M/Q==} + engines: {node: '>=6'} + query-string@7.1.3: resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} engines: {node: '>=6'} @@ -8500,6 +9449,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} @@ -8528,6 +9480,9 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} + react-devtools-core@6.1.5: + resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} + react-dom@19.2.0: resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} peerDependencies: @@ -8546,11 +9501,37 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react@19.2.0: - resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} - engines: {node: '>=0.10.0'} + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - react@19.2.1: + react-native-get-random-values@1.11.0: + resolution: {integrity: sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ==} + peerDependencies: + react-native: '>=0.56' + + react-native@0.85.2: + resolution: {integrity: sha512-GFWEPwLYirfj5X8gMtXOWtqX0cqUEURRHETZfFk37VCa4++izrKvGvv24anvuyulXV87NAhVkfNw93rLg3HByw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + peerDependencies: + '@react-native/jest-preset': 0.85.2 + '@types/react': ^19.1.1 + react: ^19.2.3 + peerDependenciesMeta: + '@react-native/jest-preset': + optional: true + '@types/react': + optional: true + + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + + react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + engines: {node: '>=0.10.0'} + + react@19.2.1: resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==} engines: {node: '>=0.10.0'} @@ -8595,6 +9576,9 @@ packages: regenerate@1.4.2: resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} @@ -8655,6 +9639,9 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfc4648@1.5.3: + resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==} + rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} @@ -8716,6 +9703,9 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + secure-json-parse@4.1.0: resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} @@ -8736,6 +9726,10 @@ packages: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} + serialize-error@2.1.0: + resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} + engines: {node: '>=0.10.0'} + serve-static@1.16.2: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} @@ -8782,6 +9776,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -8801,9 +9799,6 @@ packages: siginfo@2.0.0: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -8811,14 +9806,8 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - siwe@2.3.2: - resolution: {integrity: sha512-aSf+6+Latyttbj5nMu6GF3doMfv2UYj83hhwZgUF20ky6fTS83uVhkQABdIVnEuS8y1bBdk7p6ltb9SmlhTTlA==} - peerDependencies: - ethers: ^5.6.8 || ^6.0.8 - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} - engines: {node: '>=8'} + slow-redact@0.3.2: + resolution: {integrity: sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw==} snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} @@ -8841,11 +9830,25 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} deprecated: The work that was done in this beta branch won't be included in future versions + spark-md5@3.0.2: + resolution: {integrity: sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==} + spdx-exceptions@2.5.0: resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} @@ -8869,6 +9872,17 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + + stacktrace-parser@0.1.11: + resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} + engines: {node: '>=6'} + + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} @@ -8949,10 +9963,6 @@ packages: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} - strip-json-comments@3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -8990,6 +10000,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -9017,6 +10031,11 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + terser@5.46.2: + resolution: {integrity: sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==} + engines: {node: '>=10'} + hasBin: true + text-encoding-utf-8@1.0.2: resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} @@ -9030,10 +10049,16 @@ packages: thread-stream@0.15.2: resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==} + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + thread-stream@4.0.0: resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} engines: {node: '>=20'} + throat@5.0.0: + resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -9063,6 +10088,9 @@ packages: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + to-buffer@1.2.2: resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} engines: {node: '>= 0.4'} @@ -9125,29 +10153,9 @@ packages: tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.7.0: - resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - tsup@7.3.0: - resolution: {integrity: sha512-Ja1eaSRrE+QarmATlNO5fse2aOACYMBX+IZRKy1T+gpyH+jXgRrl5l4nHIQJQ1DoDgEjHDTw8cpE085UdBZuWQ==} - engines: {node: '>=18'} - deprecated: Breaking node 16 - hasBin: true - peerDependencies: - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.5.0' - peerDependenciesMeta: - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true - tsup@8.5.0: resolution: {integrity: sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==} engines: {node: '>=18'} @@ -9167,11 +10175,14 @@ packages: typescript: optional: true - tsx@4.20.3: - resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==} + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} hasBin: true + tweetnacl-ts@1.0.3: + resolution: {integrity: sha512-C5I/dWf6xjAXaCDlf84T4HvozU/8ycAlq5WRllF1hAeeq5390tfXD+bNas5bhEV0HMSOx8bsQYpLjPl8wfnEeQ==} + tweetnacl@1.0.3: resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} @@ -9179,6 +10190,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -9203,6 +10218,9 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + typescript-eslint@8.48.0: resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -9221,6 +10239,9 @@ packages: uint8arrays@3.1.0: resolution: {integrity: sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==} + uint8arrays@3.1.1: + resolution: {integrity: sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -9228,15 +10249,9 @@ packages: uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici-types@7.22.0: resolution: {integrity: sha512-RKZvifiL60xdsIuC80UY0dq8Z7DbJUV8/l2hOVbyZAxBzEeQU4Z58+4ZzJ6WN2Lidi9KzT5EbiGX+PI/UGYuRw==} @@ -9348,9 +10363,12 @@ packages: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 utf-8-validate@5.0.10: - resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} + resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==, tarball: https://artifactory.cbhq.net:8081/artifactory/api/npm/cb-npm-master/utf-8-validate/-/utf-8-validate-5.0.10.tgz} engines: {node: '>=6.14.2'} + utf8@3.0.0: + resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -9369,9 +10387,6 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - valid-url@1.0.9: - resolution: {integrity: sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==} - valtio@1.13.2: resolution: {integrity: sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==} engines: {node: '>=12.20.0'} @@ -9396,32 +10411,8 @@ packages: typescript: optional: true - viem@2.31.6: - resolution: {integrity: sha512-2PPbXL/8bHQxUzaLFDk4R6WHifTcXxAqMC8/j6RBgXl/OexQ1HU8r9OukwfDTqrFoHtWWiYz5fktHATy7+U9nQ==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - - viem@2.38.3: - resolution: {integrity: sha512-By2TutLv07iNHHtWqHHzjGipevYsfGqT7KQbGEmqLco1qTJxKnvBbSviqiu6/v/9REV6Q/FpmIxf2Z7/l5AbcQ==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - - viem@2.40.3: - resolution: {integrity: sha512-feYfEpbgjRkZYQpwcgxqkWzjxHI5LSDAjcGetHHwDRuX9BRQHUdV8ohrCosCYpdEhus/RknD3/bOd4qLYVPPuA==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - - viem@2.45.1: - resolution: {integrity: sha512-LN6Pp7vSfv50LgwhkfSbIXftAM5J89lP9x8TeDa8QM7o41IxlHrDh0F9X+FfnCWtsz11pEVV5sn+yBUoOHNqYA==} + viem@2.48.11: + resolution: {integrity: sha512-+WZ5E0dBS6GtKb+1wEk5DeYRRRW42+pFnXCo67Ydodf42sBwO+hu3wnQy66lc4MKmHz+llPVdbyehYr9oTE2iw==} peerDependencies: typescript: '>=5.0.4' peerDependenciesMeta: @@ -9509,6 +10500,12 @@ packages: jsdom: optional: true + vlq@1.0.1: + resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + + vlq@2.0.4: + resolution: {integrity: sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==} + w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} @@ -9524,6 +10521,9 @@ packages: typescript: optional: true + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + webextension-polyfill@0.10.0: resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==} @@ -9541,6 +10541,9 @@ packages: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} + whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + whatwg-mimetype@4.0.0: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} @@ -9615,20 +10618,20 @@ packages: utf-8-validate: optional: true - ws@8.17.1: - resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} - engines: {node: '>=10.0.0'} + ws@7.5.3: + resolution: {integrity: sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==} + engines: {node: '>=8.3.0'} peerDependencies: bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' + utf-8-validate: ^5.0.2 peerDependenciesMeta: bufferutil: optional: true utf-8-validate: optional: true - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -9639,8 +10642,8 @@ packages: utf-8-validate: optional: true - ws@8.18.2: - resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==} + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -9693,6 +10696,10 @@ packages: y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -9705,10 +10712,18 @@ packages: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + yargs@15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} engines: {node: '>=8'} + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -9789,10 +10804,31 @@ packages: snapshots: - '@adraffy/ens-normalize@1.10.1': {} - '@adraffy/ens-normalize@1.11.0': {} + '@algorandfoundation/algokit-utils@10.0.0-alpha.46': + dependencies: + '@algorandfoundation/xhd-wallet-api': 2.0.0-canary.1 + '@noble/curves': 2.0.1 + '@noble/ed25519': 3.0.1 + '@noble/hashes': 2.0.1 + algorand-msgpack: 1.1.0 + buffer: 6.0.3 + dotenv: 16.6.1 + hi-base32: 0.5.1 + json-bigint: 1.0.0 + tweetnacl: 1.0.3 + vlq: 2.0.4 + + '@algorandfoundation/xhd-wallet-api@2.0.0-canary.1': + dependencies: + '@noble/ciphers': 2.1.1 + '@noble/curves': 2.0.1 + '@noble/hashes': 2.0.1 + ajv: 8.17.1 + algo-msgpack-with-bigint: 2.1.1 + bn.js: 5.2.2 + '@alloc/quick-lru@5.2.0': {} '@aptos-labs/aptos-cli@1.1.1': @@ -9832,6 +10868,12 @@ snapshots: js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/compat-data@7.28.4': {} '@babel/core@7.28.4': @@ -9862,6 +10904,14 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.27.3': dependencies: '@babel/types': 7.28.4 @@ -9965,6 +11015,8 @@ snapshots: '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.27.1': {} '@babel/helper-wrap-function@7.28.3': @@ -9984,6 +11036,10 @@ snapshots: dependencies: '@babel/types': 7.28.4 + '@babel/parser@7.29.2': + dependencies: + '@babel/types': 7.29.0 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 @@ -10541,6 +11597,12 @@ snapshots: '@babel/parser': 7.28.4 '@babel/types': 7.28.4 + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@babel/traverse@7.28.4': dependencies: '@babel/code-frame': 7.27.1 @@ -10553,20 +11615,37 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@babel/types@7.28.4': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@base-org/account@1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@3.25.71)': + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@base-org/account@1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@noble/hashes': 1.4.0 clsx: 1.2.1 eventemitter3: 5.0.1 idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.8.3)(zod@3.25.71) + ox: 0.6.9(typescript@5.8.3)(zod@4.1.12) preact: 10.24.2 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) zustand: 5.0.3(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.4.0(react@19.2.0)) transitivePeerDependencies: - '@types/react' @@ -10586,7 +11665,7 @@ snapshots: idb-keyval: 6.2.1 ox: 0.6.9(typescript@5.8.3)(zod@3.25.71) preact: 10.24.2 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) zustand: 5.0.3(@types/react@19.2.2)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) transitivePeerDependencies: - '@types/react' @@ -10598,28 +11677,18 @@ snapshots: - utf-8-validate - zod - '@coinbase/cdp-sdk@1.38.4(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@blockshake/defly-connect@1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: - '@solana-program/system': 0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token': 0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - abitype: 1.0.6(typescript@5.8.3)(zod@3.25.71) - axios: 1.13.4 - axios-retry: 4.5.0(axios@1.13.4) - jose: 6.1.3 - md5: 2.3.0 - uncrypto: 0.1.3 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - zod: 3.25.71 + '@likecoin/qr-code-styling': 1.6.6 + '@walletconnect/client': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/types': 1.8.0 + algosdk: 3.5.2 + bowser: 2.11.0 + buffer: 6.0.3 + lottie-web: 5.13.0 transitivePeerDependencies: - bufferutil - - debug - - encoding - - fastestsmallesttextencoderdecoder - - typescript - utf-8-validate - - ws '@coinbase/cdp-sdk@1.38.4(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: @@ -10633,7 +11702,7 @@ snapshots: jose: 6.1.3 md5: 2.3.0 uncrypto: 0.1.3 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) zod: 3.25.71 transitivePeerDependencies: - bufferutil @@ -10647,9 +11716,9 @@ snapshots: '@coinbase/onchainkit@0.38.19(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(bufferutil@4.0.9)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.71)': dependencies: '@farcaster/frame-sdk': 0.1.12(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@farcaster/miniapp-wagmi-connector': 1.1.0(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@farcaster/miniapp-wagmi-connector': 1.1.0(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) '@tanstack/react-query': 5.90.8(react@19.2.1) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) clsx: 2.1.1 graphql: 16.11.0 graphql-request: 6.1.0(graphql@16.11.0) @@ -10657,8 +11726,8 @@ snapshots: react: 19.2.1 react-dom: 19.2.1(react@19.2.1) tailwind-merge: 2.6.0 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - wagmi: 2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + wagmi: 2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -10705,15 +11774,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@coinbase/wallet-sdk@4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@3.25.71)': + '@coinbase/wallet-sdk@4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: '@noble/hashes': 1.4.0 clsx: 1.2.1 eventemitter3: 5.0.1 idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.8.3)(zod@3.25.71) + ox: 0.6.9(typescript@5.8.3)(zod@4.1.12) preact: 10.24.2 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) zustand: 5.0.3(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.4.0(react@19.2.0)) transitivePeerDependencies: - '@types/react' @@ -10733,7 +11802,7 @@ snapshots: idb-keyval: 6.2.1 ox: 0.6.9(typescript@5.8.3)(zod@3.25.71) preact: 10.24.2 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) zustand: 5.0.3(@types/react@19.2.2)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) transitivePeerDependencies: - '@types/react' @@ -10745,9 +11814,9 @@ snapshots: - utf-8-validate - zod - '@craftamap/esbuild-plugin-html@0.9.0(bufferutil@4.0.9)(esbuild@0.25.5)(utf-8-validate@5.0.10)': + '@craftamap/esbuild-plugin-html@0.9.0(bufferutil@4.0.9)(esbuild@0.27.7)(utf-8-validate@5.0.10)': dependencies: - esbuild: 0.25.5 + esbuild: 0.27.7 jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) lodash: 4.17.21 transitivePeerDependencies: @@ -10804,150 +11873,159 @@ snapshots: esquery: 1.6.0 jsdoc-type-pratt-parser: 4.1.0 - '@esbuild/aix-ppc64@0.19.12': - optional: true - '@esbuild/aix-ppc64@0.25.5': optional: true - '@esbuild/android-arm64@0.19.12': + '@esbuild/aix-ppc64@0.27.7': optional: true '@esbuild/android-arm64@0.25.5': optional: true - '@esbuild/android-arm@0.19.12': + '@esbuild/android-arm64@0.27.7': optional: true '@esbuild/android-arm@0.25.5': optional: true - '@esbuild/android-x64@0.19.12': + '@esbuild/android-arm@0.27.7': optional: true '@esbuild/android-x64@0.25.5': optional: true - '@esbuild/darwin-arm64@0.19.12': + '@esbuild/android-x64@0.27.7': optional: true '@esbuild/darwin-arm64@0.25.5': optional: true - '@esbuild/darwin-x64@0.19.12': + '@esbuild/darwin-arm64@0.27.7': optional: true '@esbuild/darwin-x64@0.25.5': optional: true - '@esbuild/freebsd-arm64@0.19.12': + '@esbuild/darwin-x64@0.27.7': optional: true '@esbuild/freebsd-arm64@0.25.5': optional: true - '@esbuild/freebsd-x64@0.19.12': + '@esbuild/freebsd-arm64@0.27.7': optional: true '@esbuild/freebsd-x64@0.25.5': optional: true - '@esbuild/linux-arm64@0.19.12': + '@esbuild/freebsd-x64@0.27.7': optional: true '@esbuild/linux-arm64@0.25.5': optional: true - '@esbuild/linux-arm@0.19.12': + '@esbuild/linux-arm64@0.27.7': optional: true '@esbuild/linux-arm@0.25.5': optional: true - '@esbuild/linux-ia32@0.19.12': + '@esbuild/linux-arm@0.27.7': optional: true '@esbuild/linux-ia32@0.25.5': optional: true - '@esbuild/linux-loong64@0.19.12': + '@esbuild/linux-ia32@0.27.7': optional: true '@esbuild/linux-loong64@0.25.5': optional: true - '@esbuild/linux-mips64el@0.19.12': + '@esbuild/linux-loong64@0.27.7': optional: true '@esbuild/linux-mips64el@0.25.5': optional: true - '@esbuild/linux-ppc64@0.19.12': + '@esbuild/linux-mips64el@0.27.7': optional: true '@esbuild/linux-ppc64@0.25.5': optional: true - '@esbuild/linux-riscv64@0.19.12': + '@esbuild/linux-ppc64@0.27.7': optional: true '@esbuild/linux-riscv64@0.25.5': optional: true - '@esbuild/linux-s390x@0.19.12': + '@esbuild/linux-riscv64@0.27.7': optional: true '@esbuild/linux-s390x@0.25.5': optional: true - '@esbuild/linux-x64@0.19.12': + '@esbuild/linux-s390x@0.27.7': optional: true '@esbuild/linux-x64@0.25.5': optional: true + '@esbuild/linux-x64@0.27.7': + optional: true + '@esbuild/netbsd-arm64@0.25.5': optional: true - '@esbuild/netbsd-x64@0.19.12': + '@esbuild/netbsd-arm64@0.27.7': optional: true '@esbuild/netbsd-x64@0.25.5': optional: true + '@esbuild/netbsd-x64@0.27.7': + optional: true + '@esbuild/openbsd-arm64@0.25.5': optional: true - '@esbuild/openbsd-x64@0.19.12': + '@esbuild/openbsd-arm64@0.27.7': optional: true '@esbuild/openbsd-x64@0.25.5': optional: true - '@esbuild/sunos-x64@0.19.12': + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': optional: true '@esbuild/sunos-x64@0.25.5': optional: true - '@esbuild/win32-arm64@0.19.12': + '@esbuild/sunos-x64@0.27.7': optional: true '@esbuild/win32-arm64@0.25.5': optional: true - '@esbuild/win32-ia32@0.19.12': + '@esbuild/win32-arm64@0.27.7': optional: true '@esbuild/win32-ia32@0.25.5': optional: true - '@esbuild/win32-x64@0.19.12': + '@esbuild/win32-ia32@0.27.7': optional: true '@esbuild/win32-x64@0.25.5': optional: true + '@esbuild/win32-x64@0.27.7': + optional: true + '@eslint-community/eslint-utils@4.9.0(eslint@9.38.0(jiti@1.21.7))': dependencies: eslint: 9.38.0(jiti@1.21.7) @@ -11014,6 +12092,131 @@ snapshots: ethereum-cryptography: 2.2.1 micro-ftch: 0.3.1 + '@ethersproject/abi@5.8.0': + dependencies: + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/abstract-provider@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/web': 5.8.0 + + '@ethersproject/abstract-signer@5.8.0': + dependencies: + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + + '@ethersproject/address@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/rlp': 5.8.0 + + '@ethersproject/base64@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + + '@ethersproject/bignumber@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + bn.js: 5.2.2 + + '@ethersproject/bytes@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/constants@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + + '@ethersproject/hash@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/keccak256@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + js-sha3: 0.8.0 + + '@ethersproject/logger@5.8.0': {} + + '@ethersproject/networks@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/properties@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/rlp@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/signing-key@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + bn.js: 5.2.2 + elliptic: 6.6.1 + hash.js: 1.1.7 + + '@ethersproject/strings@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/transactions@5.8.0': + dependencies: + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + + '@ethersproject/web@5.8.0': + dependencies: + '@ethersproject/base64': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@evanhahn/lottie-web-light@5.8.1': {} + '@farcaster/frame-sdk@0.1.12(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': dependencies: '@farcaster/miniapp-sdk': 0.2.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) @@ -11053,11 +12256,11 @@ snapshots: - utf-8-validate - zod - '@farcaster/miniapp-wagmi-connector@1.1.0(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))': + '@farcaster/miniapp-wagmi-connector@1.1.0(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))': dependencies: '@farcaster/miniapp-sdk': 0.2.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) '@farcaster/quick-auth@0.0.6(typescript@5.8.3)': dependencies: @@ -11094,37 +12297,96 @@ snapshots: '@fastify/forwarded': 3.0.1 ipaddr.js: 2.3.0 - '@gemini-wallet/core@0.2.0(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))': + '@gemini-wallet/core@0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))': dependencies: '@metamask/rpc-errors': 7.0.2 eventemitter3: 5.0.1 - viem: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) transitivePeerDependencies: - supports-color - '@gemini-wallet/core@0.2.0(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))': + '@gemini-wallet/core@0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))': dependencies: '@metamask/rpc-errors': 7.0.2 eventemitter3: 5.0.1 - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) transitivePeerDependencies: - supports-color - '@gemini-wallet/core@0.2.0(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))': + '@graphql-typed-document-node/core@3.2.0(graphql@16.11.0)': dependencies: - '@metamask/rpc-errors': 7.0.2 - eventemitter3: 5.0.1 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + graphql: 16.11.0 + + '@grpc/grpc-js@1.12.6': + dependencies: + '@grpc/proto-loader': 0.7.15 + '@js-sdsl/ordered-map': 4.4.2 + + '@grpc/proto-loader@0.7.15': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.1 + protobufjs: 7.5.4 + yargs: 17.7.2 + + '@hiero-ledger/cryptography@1.16.0-beta.3(react-native@0.85.2(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))': + dependencies: + '@noble/curves': 1.8.1 + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + asn1js: 3.0.6 + bignumber.js: 9.1.1 + bn.js: 5.2.1 + buffer: 6.0.3 + crypto-js: 4.2.0 + debug: 4.4.1 + forge-light: 1.1.4 + js-base64: 3.7.7 + react-native-get-random-values: 1.11.0(react-native@0.85.2(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)) + spark-md5: 3.0.2 + strip-ansi: 7.1.2 + tweetnacl: 1.0.3 + utf8: 3.0.0 transitivePeerDependencies: + - react-native - supports-color - '@graphql-typed-document-node/core@3.2.0(graphql@16.11.0)': + '@hiero-ledger/proto@2.26.0-beta.3(ansi-regex@6.2.2)(ansi-styles@6.2.3)(debug@4.4.1)(protobufjs@7.5.4)(strip-ansi@7.1.2)': dependencies: - graphql: 16.11.0 + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + debug: 4.4.1 + long: 5.3.1 + protobufjs: 7.5.4 + strip-ansi: 7.1.2 - '@heroicons/react@2.2.0(react@19.2.3)': + '@hiero-ledger/sdk@2.80.0(bn.js@5.2.1)(react-native@0.85.2(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))': dependencies: - react: 19.2.3 + '@ethersproject/abi': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@grpc/grpc-js': 1.12.6 + '@hiero-ledger/cryptography': 1.16.0-beta.3(react-native@0.85.2(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)) + '@hiero-ledger/proto': 2.26.0-beta.3(ansi-regex@6.2.2)(ansi-styles@6.2.3)(debug@4.4.1)(protobufjs@7.5.4)(strip-ansi@7.1.2) + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + bignumber.js: 9.1.1 + bn.js: 5.2.1 + crypto-js: 4.2.0 + debug: 4.4.1 + js-base64: 3.7.4 + long: 5.3.1 + pino: 10.1.0 + pino-pretty: 13.0.0 + protobufjs: 7.5.4 + rfc4648: 1.5.3 + strip-ansi: 7.1.2 + utf8: 3.0.0 + transitivePeerDependencies: + - expo-crypto + - react-native + - supports-color '@hono/node-server@1.19.5(hono@4.10.2)': dependencies: @@ -11243,6 +12505,21 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/ttlcache@1.4.1': {} + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.10 + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.16.0 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -11255,6 +12532,11 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': @@ -11262,6 +12544,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@js-sdsl/ordered-map@4.4.2': {} + + '@likecoin/qr-code-styling@1.6.6': + dependencies: + qrcode-generator: 1.5.2 + '@lit-labs/ssr-dom-shim@1.4.0': {} '@lit/reactive-element@2.1.1': @@ -11497,6 +12785,8 @@ snapshots: - hono - supports-color + '@msgpack/msgpack@3.1.3': {} + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.6.0 @@ -11506,6 +12796,8 @@ snapshots: '@next/env@15.5.9': {} + '@next/env@16.0.10': {} + '@next/env@16.1.1': {} '@next/eslint-plugin-next@15.1.9': @@ -11519,58 +12811,82 @@ snapshots: '@next/swc-darwin-arm64@15.5.7': optional: true + '@next/swc-darwin-arm64@16.0.10': + optional: true + '@next/swc-darwin-arm64@16.1.1': optional: true '@next/swc-darwin-x64@15.5.7': optional: true - '@next/swc-darwin-x64@16.1.1': + '@next/swc-darwin-x64@16.0.10': + optional: true + + '@next/swc-darwin-x64@16.1.1': optional: true '@next/swc-linux-arm64-gnu@15.5.7': optional: true + '@next/swc-linux-arm64-gnu@16.0.10': + optional: true + '@next/swc-linux-arm64-gnu@16.1.1': optional: true '@next/swc-linux-arm64-musl@15.5.7': optional: true + '@next/swc-linux-arm64-musl@16.0.10': + optional: true + '@next/swc-linux-arm64-musl@16.1.1': optional: true '@next/swc-linux-x64-gnu@15.5.7': optional: true + '@next/swc-linux-x64-gnu@16.0.10': + optional: true + '@next/swc-linux-x64-gnu@16.1.1': optional: true '@next/swc-linux-x64-musl@15.5.7': optional: true + '@next/swc-linux-x64-musl@16.0.10': + optional: true + '@next/swc-linux-x64-musl@16.1.1': optional: true '@next/swc-win32-arm64-msvc@15.5.7': optional: true + '@next/swc-win32-arm64-msvc@16.0.10': + optional: true + '@next/swc-win32-arm64-msvc@16.1.1': optional: true '@next/swc-win32-x64-msvc@15.5.7': optional: true + '@next/swc-win32-x64-msvc@16.0.10': + optional: true + '@next/swc-win32-x64-msvc@16.1.1': optional: true + '@noble/ciphers@1.2.0': {} + '@noble/ciphers@1.2.1': {} '@noble/ciphers@1.3.0': {} - '@noble/curves@1.2.0': - dependencies: - '@noble/hashes': 1.3.2 + '@noble/ciphers@2.1.1': {} '@noble/curves@1.4.2': dependencies: @@ -11588,15 +12904,15 @@ snapshots: dependencies: '@noble/hashes': 1.8.0 - '@noble/curves@1.9.2': + '@noble/curves@1.9.7': dependencies: '@noble/hashes': 1.8.0 - '@noble/curves@1.9.7': + '@noble/curves@2.0.1': dependencies: - '@noble/hashes': 1.8.0 + '@noble/hashes': 2.0.1 - '@noble/hashes@1.3.2': {} + '@noble/ed25519@3.0.1': {} '@noble/hashes@1.4.0': {} @@ -11606,6 +12922,8 @@ snapshots: '@noble/hashes@1.8.0': {} + '@noble/hashes@2.0.1': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -11622,6 +12940,20 @@ snapshots: '@paulmillr/qr@0.2.1': {} + '@perawallet/connect@1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@evanhahn/lottie-web-light': 5.8.1 + '@walletconnect/client': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/types': 1.8.0 + algosdk: 3.5.2 + bowser: 2.11.0 + buffer: 6.0.3 + qr-code-styling: 1.6.0-rc.1 + tweetnacl-ts: 1.0.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@pinojs/redact@0.4.0': {} '@pkgjs/parseargs@0.11.0': @@ -11629,11 +12961,104 @@ snapshots: '@pkgr/core@0.2.9': {} + '@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': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 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': {} + + '@react-native/assets-registry@0.85.2': {} + + '@react-native/codegen@0.85.2(@babel/core@7.28.4)': + dependencies: + '@babel/core': 7.28.4 + '@babel/parser': 7.29.2 + hermes-parser: 0.33.3 + invariant: 2.2.4 + nullthrows: 1.1.1 + tinyglobby: 0.2.15 + yargs: 17.7.2 + + '@react-native/community-cli-plugin@0.85.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@react-native/dev-middleware': 0.85.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + debug: 4.4.3 + invariant: 2.2.4 + metro: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-config: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-core: 0.84.3 + semver: 7.7.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/debugger-frontend@0.85.2': {} + + '@react-native/debugger-shell@0.85.2': + dependencies: + cross-spawn: 7.0.6 + debug: 4.4.3 + fb-dotslash: 0.5.8 + transitivePeerDependencies: + - supports-color + + '@react-native/dev-middleware@0.85.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.85.2 + '@react-native/debugger-shell': 0.85.2 + chrome-launcher: 0.15.2 + chromium-edge-launcher: 0.3.0 + connect: 3.7.0 + debug: 4.4.3 + invariant: 2.2.4 + nullthrows: 1.1.1 + open: 7.4.2 + serve-static: 1.16.2 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/gradle-plugin@0.85.2': {} + + '@react-native/js-polyfills@0.85.2': {} + + '@react-native/normalize-colors@0.85.2': {} + + '@react-native/virtualized-lists@0.85.2(@types/react@19.2.2)(react-native@0.85.2(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.2.3 + react-native: 0.85.2(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10) + optionalDependencies: + '@types/react': 19.2.2 + '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.22.4)': dependencies: big.js: 6.2.2 dayjs: 1.11.13 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.22.4) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.22.4) transitivePeerDependencies: - bufferutil - typescript @@ -11644,20 +13069,31 @@ snapshots: dependencies: big.js: 6.2.2 dayjs: 1.11.13 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) transitivePeerDependencies: - bufferutil - typescript - utf-8-validate - zod - '@reown/appkit-controllers@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': + '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@reown/appkit-controllers@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) valtio: 1.13.2(@types/react@19.2.2)(react@19.2.0) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11692,7 +13128,7 @@ snapshots: '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) valtio: 1.13.2(@types/react@19.2.2)(react@19.2.1) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11721,12 +13157,12 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-pay@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': + '@reown/appkit-pay@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@reown/appkit-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@reown/appkit-utils': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@3.25.71) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@4.1.12) lit: 3.3.0 valtio: 1.13.2(@types/react@19.2.2)(react@19.2.0) transitivePeerDependencies: @@ -11797,12 +13233,12 @@ snapshots: dependencies: buffer: 6.0.3 - '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@3.25.71)': + '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@4.1.12)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@reown/appkit-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@reown/appkit-utils': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@3.25.71) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@4.1.12) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) lit: 3.3.0 transitivePeerDependencies: @@ -11871,10 +13307,10 @@ snapshots: - valtio - zod - '@reown/appkit-ui@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': + '@reown/appkit-ui@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) lit: 3.3.0 qrcode: 1.5.3 @@ -11941,16 +13377,16 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@3.25.71)': + '@reown/appkit-utils@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@4.1.12)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) '@reown/appkit-polyfills': 1.7.8 '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) valtio: 1.13.2(@types/react@19.2.2)(react@19.2.0) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11988,7 +13424,7 @@ snapshots: '@walletconnect/logger': 2.1.2 '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) valtio: 1.13.2(@types/react@19.2.2)(react@19.2.1) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -12028,21 +13464,21 @@ snapshots: - typescript - utf-8-validate - '@reown/appkit@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': + '@reown/appkit@1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@reown/appkit-pay': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@reown/appkit-pay': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@3.25.71) - '@reown/appkit-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@reown/appkit-utils': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@3.25.71) + '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@4.1.12) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0))(zod@4.1.12) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) '@walletconnect/types': 2.21.0 - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) bs58: 6.0.0 valtio: 1.13.2(@types/react@19.2.2)(react@19.2.0) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -12085,7 +13521,7 @@ snapshots: '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) bs58: 6.0.0 valtio: 1.13.2(@types/react@19.2.2)(react@19.2.1) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -12194,10 +13630,30 @@ snapshots: - utf-8-validate - zod + '@safe-global/safe-apps-provider@0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + events: 3.3.0 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': dependencies: '@safe-global/safe-gateway-typescript-sdk': 3.23.1 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@safe-global/safe-gateway-typescript-sdk': 3.23.1 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) transitivePeerDependencies: - bufferutil - typescript @@ -12243,6 +13699,19 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 + '@signinwithethereum/siwe-parser@4.1.0': + dependencies: + '@noble/hashes': 1.8.0 + apg-js: 4.4.0 + + '@signinwithethereum/siwe@4.1.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))': + dependencies: + '@signinwithethereum/siwe-parser': 4.1.0 + optionalDependencies: + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + + '@sinclair/typebox@0.27.10': {} + '@sindresorhus/is@4.6.0': {} '@socket.io/component-emitter@3.1.2': {} @@ -12259,10 +13728,6 @@ snapshots: dependencies: '@solana/kit': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@solana-program/system@0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': - dependencies: - '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/system@0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -12286,10 +13751,6 @@ snapshots: dependencies: '@solana/kit': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@solana-program/token@0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': - dependencies: - '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/token@0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -12822,32 +14283,6 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/accounts': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/codecs': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/errors': 3.0.3(typescript@5.8.3) - '@solana/functional': 3.0.3(typescript@5.8.3) - '@solana/instruction-plans': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/instructions': 3.0.3(typescript@5.8.3) - '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/programs': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-parsed-types': 3.0.3(typescript@5.8.3) - '@solana/rpc-spec-types': 3.0.3(typescript@5.8.3) - '@solana/rpc-subscriptions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/signers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/sysvars': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/transaction-confirmation': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - ws - '@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/accounts': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) @@ -12874,32 +14309,6 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/accounts': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/codecs': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/errors': 5.0.0(typescript@5.8.3) - '@solana/functional': 5.0.0(typescript@5.8.3) - '@solana/instruction-plans': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/instructions': 5.0.0(typescript@5.8.3) - '@solana/keys': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/programs': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-parsed-types': 5.0.0(typescript@5.8.3) - '@solana/rpc-spec-types': 5.0.0(typescript@5.8.3) - '@solana/rpc-subscriptions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/signers': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/sysvars': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/transaction-confirmation': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/transaction-messages': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/transactions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - ws - '@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/accounts': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) @@ -13397,23 +14806,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-channel-websocket@2.3.0(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions-channel-websocket@2.3.0(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.3.0(typescript@5.8.3) '@solana/functional': 2.3.0(typescript@5.8.3) '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.8.3) '@solana/subscribable': 2.3.0(typescript@5.8.3) typescript: 5.8.3 - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - - '@solana/rpc-subscriptions-channel-websocket@3.0.3(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/errors': 3.0.3(typescript@5.8.3) - '@solana/functional': 3.0.3(typescript@5.8.3) - '@solana/rpc-subscriptions-spec': 3.0.3(typescript@5.8.3) - '@solana/subscribable': 3.0.3(typescript@5.8.3) - typescript: 5.8.3 - ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@solana/rpc-subscriptions-channel-websocket@3.0.3(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: @@ -13424,15 +14824,6 @@ snapshots: typescript: 5.8.3 ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@solana/rpc-subscriptions-channel-websocket@5.0.0(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/errors': 5.0.0(typescript@5.8.3) - '@solana/functional': 5.0.0(typescript@5.8.3) - '@solana/rpc-subscriptions-spec': 5.0.0(typescript@5.8.3) - '@solana/subscribable': 5.0.0(typescript@5.8.3) - typescript: 5.8.3 - ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@solana/rpc-subscriptions-channel-websocket@5.0.0(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 5.0.0(typescript@5.8.3) @@ -13449,7 +14840,7 @@ snapshots: '@solana/rpc-subscriptions-spec': 5.3.0(typescript@5.8.3) '@solana/subscribable': 5.3.0(typescript@5.8.3) typescript: 5.8.3 - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) transitivePeerDependencies: - bufferutil - utf-8-validate @@ -13508,7 +14899,7 @@ snapshots: optionalDependencies: typescript: 5.8.3 - '@solana/rpc-subscriptions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.3.0(typescript@5.8.3) '@solana/fast-stable-stringify': 2.3.0(typescript@5.8.3) @@ -13516,7 +14907,7 @@ snapshots: '@solana/promises': 2.3.0(typescript@5.8.3) '@solana/rpc-spec-types': 2.3.0(typescript@5.8.3) '@solana/rpc-subscriptions-api': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-subscriptions-channel-websocket': 2.3.0(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-channel-websocket': 2.3.0(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.8.3) '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) @@ -13526,24 +14917,6 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/rpc-subscriptions@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/errors': 3.0.3(typescript@5.8.3) - '@solana/fast-stable-stringify': 3.0.3(typescript@5.8.3) - '@solana/functional': 3.0.3(typescript@5.8.3) - '@solana/promises': 3.0.3(typescript@5.8.3) - '@solana/rpc-spec-types': 3.0.3(typescript@5.8.3) - '@solana/rpc-subscriptions-api': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-subscriptions-channel-websocket': 3.0.3(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-subscriptions-spec': 3.0.3(typescript@5.8.3) - '@solana/rpc-transformers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/subscribable': 3.0.3(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - ws - '@solana/rpc-subscriptions@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 3.0.3(typescript@5.8.3) @@ -13562,24 +14935,6 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/rpc-subscriptions@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/errors': 5.0.0(typescript@5.8.3) - '@solana/fast-stable-stringify': 5.0.0(typescript@5.8.3) - '@solana/functional': 5.0.0(typescript@5.8.3) - '@solana/promises': 5.0.0(typescript@5.8.3) - '@solana/rpc-spec-types': 5.0.0(typescript@5.8.3) - '@solana/rpc-subscriptions-api': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-subscriptions-channel-websocket': 5.0.0(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-subscriptions-spec': 5.0.0(typescript@5.8.3) - '@solana/rpc-transformers': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/subscribable': 5.0.0(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - ws - '@solana/rpc-subscriptions@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 5.0.0(typescript@5.8.3) @@ -13699,7 +15054,7 @@ snapshots: '@solana/rpc-spec': 2.3.0(typescript@5.8.3) '@solana/rpc-spec-types': 2.3.0(typescript@5.8.3) typescript: 5.8.3 - undici-types: 7.16.0 + undici-types: 7.22.0 '@solana/rpc-transport-http@3.0.3(typescript@5.8.3)': dependencies: @@ -13715,7 +15070,7 @@ snapshots: '@solana/rpc-spec': 5.0.0(typescript@5.8.3) '@solana/rpc-spec-types': 5.0.0(typescript@5.8.3) typescript: 5.8.3 - undici-types: 7.16.0 + undici-types: 7.22.0 '@solana/rpc-transport-http@5.3.0(typescript@5.8.3)': dependencies: @@ -13723,7 +15078,7 @@ snapshots: '@solana/rpc-spec': 5.3.0(typescript@5.8.3) '@solana/rpc-spec-types': 5.3.0(typescript@5.8.3) typescript: 5.8.3 - undici-types: 7.16.0 + undici-types: 7.22.0 '@solana/rpc-transport-http@6.1.0(typescript@5.8.3)': dependencies: @@ -13997,7 +15352,7 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-confirmation@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/transaction-confirmation@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) @@ -14005,7 +15360,7 @@ snapshots: '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/promises': 2.3.0(typescript@5.8.3) '@solana/rpc': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) @@ -14014,23 +15369,6 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/transaction-confirmation@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/errors': 3.0.3(typescript@5.8.3) - '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/promises': 3.0.3(typescript@5.8.3) - '@solana/rpc': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-subscriptions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - ws - '@solana/transaction-confirmation@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) @@ -14048,23 +15386,6 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/transaction-confirmation@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/errors': 5.0.0(typescript@5.8.3) - '@solana/keys': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/promises': 5.0.0(typescript@5.8.3) - '@solana/rpc': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/rpc-subscriptions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/transaction-messages': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/transactions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - ws - '@solana/transaction-confirmation@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) @@ -14314,29 +15635,9 @@ snapshots: - typescript - utf-8-validate - '@spruceid/siwe-parser@2.1.2': - dependencies: - '@noble/hashes': 1.8.0 - apg-js: 4.4.0 - uri-js: 4.4.1 - valid-url: 1.0.9 - - '@stablelib/binary@1.0.1': - dependencies: - '@stablelib/int': 1.0.1 - - '@stablelib/int@1.0.1': {} - - '@stablelib/random@1.0.2': - dependencies: - '@stablelib/binary': 1.0.1 - '@stablelib/wipe': 1.0.1 - - '@stablelib/wipe@1.0.1': {} - - '@stellar/js-xdr@3.1.2': {} - - '@stellar/stellar-base@14.1.0': + '@stellar/js-xdr@3.1.2': {} + + '@stellar/stellar-base@14.1.0': dependencies: '@noble/curves': 1.9.7 '@stellar/js-xdr': 3.1.2 @@ -14476,8 +15777,20 @@ snapshots: '@tanstack/query-core': 5.90.8 react: 19.2.1 + '@tanstack/store@0.8.0': {} + '@trysound/sax@0.2.0': {} + '@txnlab/use-wallet@4.6.0(@blockshake/defly-connect@1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@perawallet/connect@1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@walletconnect/sign-client@2.23.9(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(algosdk@3.5.2)(lute-connect@1.7.0)': + dependencies: + '@tanstack/store': 0.8.0 + algosdk: 3.5.2 + optionalDependencies: + '@blockshake/defly-connect': 1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@perawallet/connect': 1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/sign-client': 2.23.9(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + lute-connect: 1.7.0 + '@tybys/wasm-util@0.10.1': dependencies: tslib: 2.8.1 @@ -14543,6 +15856,16 @@ snapshots: '@types/http-errors@2.0.5': {} + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -14559,18 +15882,10 @@ snapshots: '@types/node@12.20.55': {} - '@types/node@20.19.4': - dependencies: - undici-types: 6.21.0 - '@types/node@22.16.0': dependencies: undici-types: 6.21.0 - '@types/node@22.7.5': - dependencies: - undici-types: 6.19.8 - '@types/prompts@2.4.9': dependencies: '@types/node': 22.16.0 @@ -14615,6 +15930,12 @@ snapshots: dependencies: '@types/node': 22.16.0 + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + '@typescript-eslint/eslint-plugin@8.46.2(@typescript-eslint/parser@8.46.2(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3)': dependencies: '@eslint-community/regexpp': 4.12.2 @@ -14867,13 +16188,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1))': + '@vitest/mocker@3.2.4(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 magic-string: 0.30.19 optionalDependencies: - vite: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + vite: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -14901,19 +16222,19 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 - '@wagmi/connectors@5.11.2(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71)': + '@wagmi/connectors@5.11.2(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)))(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(zod@4.1.12))(zod@4.1.12)': dependencies: - '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@3.25.71) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@3.25.71) - '@gemini-wallet/core': 0.2.0(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@4.1.12) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@4.1.12) + '@gemini-wallet/core': 0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.19(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71)) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + porto: 0.2.19(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)))(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(zod@4.1.12)) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -14948,66 +16269,19 @@ snapshots: - wagmi - zod - '@wagmi/connectors@5.11.2(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71)': + '@wagmi/connectors@5.11.2(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71)': dependencies: '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.71) '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.71) - '@gemini-wallet/core': 0.2.0(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@gemini-wallet/core': 0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.19(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71)) - viem: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - immer - - ioredis - - react - - supports-color - - uploadthing - - use-sync-external-store - - utf-8-validate - - wagmi - - zod - - '@wagmi/connectors@6.1.0(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71)': - dependencies: - '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@3.25.71) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@3.25.71) - '@gemini-wallet/core': 0.2.0(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) - '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.19(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71)) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + porto: 0.2.19(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71)) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -15042,19 +16316,19 @@ snapshots: - wagmi - zod - '@wagmi/connectors@6.1.0(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71)': + '@wagmi/connectors@6.1.0(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)))(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(zod@4.1.12))(zod@4.1.12)': dependencies: - '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.71) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.71) - '@gemini-wallet/core': 0.2.0(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@4.1.12) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(zod@4.1.12) + '@gemini-wallet/core': 0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.19(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71)) - viem: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + porto: 0.2.19(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)))(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(zod@4.1.12)) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -15089,19 +16363,19 @@ snapshots: - wagmi - zod - '@wagmi/connectors@6.1.0(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71)': + '@wagmi/connectors@6.1.0(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71)': dependencies: '@base-org/account': 1.1.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.71) '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.71) - '@gemini-wallet/core': 0.2.0(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@gemini-wallet/core': 0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.19(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71)) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + porto: 0.2.19(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71)) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -15136,11 +16410,11 @@ snapshots: - wagmi - zod - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))': + '@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))': dependencies: eventemitter3: 5.0.1 mipd: 0.0.7(typescript@5.8.3) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) zustand: 5.0.0(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.4.0(react@19.2.0)) optionalDependencies: '@tanstack/query-core': 5.90.8 @@ -15151,26 +16425,11 @@ snapshots: - react - use-sync-external-store - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.8.3) - viem: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - zustand: 5.0.0(@types/react@19.2.2)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) - optionalDependencies: - '@tanstack/query-core': 5.90.8 - typescript: 5.8.3 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))': + '@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))': dependencies: eventemitter3: 5.0.1 mipd: 0.0.7(typescript@5.8.3) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) zustand: 5.0.0(@types/react@19.2.2)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) optionalDependencies: '@tanstack/query-core': 5.90.8 @@ -15191,6 +16450,33 @@ snapshots: dependencies: '@wallet-standard/base': 1.1.0 + '@walletconnect/browser-utils@1.8.0': + dependencies: + '@walletconnect/safe-json': 1.0.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/window-getters': 1.0.0 + '@walletconnect/window-metadata': 1.0.0 + detect-browser: 5.2.0 + + '@walletconnect/client@1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@walletconnect/core': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/iso-crypto': 1.8.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@walletconnect/core@1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@walletconnect/socket-transport': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@walletconnect/core@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': dependencies: '@walletconnect/heartbeat': 1.2.2 @@ -15235,6 +16521,50 @@ snapshots: - utf-8-validate - zod + '@walletconnect/core@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.33.0 + events: 3.3.0 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + '@walletconnect/core@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': dependencies: '@walletconnect/heartbeat': 1.2.2 @@ -15279,22 +16609,125 @@ snapshots: - utf-8-validate - zod + '@walletconnect/core@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.33.0 + events: 3.3.0 + uint8arrays: 3.1.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/core@2.23.9(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.23.9 + '@walletconnect/utils': 2.23.9(typescript@5.8.3)(zod@4.1.12) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.44.0 + events: 3.3.0 + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/crypto@1.1.0': + dependencies: + '@noble/ciphers': 1.2.0 + '@noble/hashes': 1.7.0 + '@walletconnect/encoding': 1.0.2 + '@walletconnect/environment': 1.0.1 + '@walletconnect/randombytes': 1.1.0 + tslib: 1.14.1 + + '@walletconnect/encoding@1.0.2': + dependencies: + is-typedarray: 1.0.0 + tslib: 1.14.1 + typedarray-to-buffer: 3.1.5 + '@walletconnect/environment@1.0.1': dependencies: tslib: 1.14.1 - '@walletconnect/ethereum-provider@2.21.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': + '@walletconnect/ethereum-provider@2.21.1(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: - '@reown/appkit': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@reown/appkit': 1.7.8(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) '@walletconnect/jsonrpc-http-connection': 1.0.8 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) '@walletconnect/types': 2.21.1 - '@walletconnect/universal-provider': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@walletconnect/universal-provider': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -15376,6 +16809,12 @@ snapshots: '@walletconnect/time': 1.0.2 events: 3.3.0 + '@walletconnect/iso-crypto@1.8.0': + dependencies: + '@walletconnect/crypto': 1.1.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + '@walletconnect/jsonrpc-http-connection@1.0.8': dependencies: '@walletconnect/jsonrpc-utils': 1.0.8 @@ -15442,6 +16881,18 @@ snapshots: '@walletconnect/safe-json': 1.0.2 pino: 7.11.0 + '@walletconnect/logger@3.0.2': + dependencies: + '@walletconnect/safe-json': 1.0.2 + pino: 10.0.0 + + '@walletconnect/randombytes@1.1.0': + dependencies: + '@noble/hashes': 1.7.0 + '@walletconnect/encoding': 1.0.2 + '@walletconnect/environment': 1.0.1 + tslib: 1.14.1 + '@walletconnect/relay-api@1.0.11': dependencies: '@walletconnect/jsonrpc-types': 1.0.4 @@ -15452,7 +16903,9 @@ snapshots: '@noble/hashes': 1.7.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - uint8arrays: 3.1.0 + uint8arrays: 3.1.1 + + '@walletconnect/safe-json@1.0.0': {} '@walletconnect/safe-json@1.0.2': dependencies: @@ -15494,16 +16947,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': + '@walletconnect/sign-client@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': dependencies: - '@walletconnect/core': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@walletconnect/core': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/logger': 2.1.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1 - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -15530,11 +16983,130 @@ snapshots: - utf-8-validate - zod - '@walletconnect/time@1.0.2': + '@walletconnect/sign-client@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': dependencies: - tslib: 1.14.1 - - '@walletconnect/types@2.21.0': + '@walletconnect/core': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/sign-client@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@walletconnect/core': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/sign-client@2.23.9(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@walletconnect/core': 2.23.9(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 3.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.23.9 + '@walletconnect/utils': 2.23.9(typescript@5.8.3)(zod@4.1.12) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/socket-transport@1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + ws: 7.5.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@walletconnect/time@1.0.2': + dependencies: + tslib: 1.14.1 + + '@walletconnect/types@1.8.0': {} + + '@walletconnect/types@2.21.0': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 @@ -15592,6 +17164,35 @@ snapshots: - ioredis - uploadthing + '@walletconnect/types@2.23.9': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + '@walletconnect/universal-provider@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': dependencies: '@walletconnect/events': 1.0.1 @@ -15632,6 +17233,46 @@ snapshots: - utf-8-validate - zod + '@walletconnect/universal-provider@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + es-toolkit: 1.33.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + '@walletconnect/universal-provider@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': dependencies: '@walletconnect/events': 1.0.1 @@ -15672,6 +17313,56 @@ snapshots: - utf-8-validate - zod + '@walletconnect/universal-provider@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + es-toolkit: 1.33.0 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/utils@1.8.0': + dependencies: + '@walletconnect/browser-utils': 1.8.0 + '@walletconnect/encoding': 1.0.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/types': 1.8.0 + bn.js: 4.11.8 + js-sha3: 0.8.0 + query-string: 6.13.5 + '@walletconnect/utils@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': dependencies: '@noble/ciphers': 1.2.1 @@ -15716,6 +17407,50 @@ snapshots: - utf-8-validate - zod + '@walletconnect/utils@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@noble/ciphers': 1.2.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + '@walletconnect/utils@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)': dependencies: '@noble/ciphers': 1.2.1 @@ -15760,10 +17495,104 @@ snapshots: - utf-8-validate - zod + '@walletconnect/utils@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)': + dependencies: + '@noble/ciphers': 1.2.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/utils@2.23.9(typescript@5.8.3)(zod@4.1.12)': + dependencies: + '@msgpack/msgpack': 3.1.3 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.23.9 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + blakejs: 1.2.1 + detect-browser: 5.3.0 + ox: 0.9.3(typescript@5.8.3)(zod@4.1.12) + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - typescript + - uploadthing + - zod + + '@walletconnect/window-getters@1.0.0': {} + '@walletconnect/window-getters@1.0.1': dependencies: tslib: 1.14.1 + '@walletconnect/window-metadata@1.0.0': + dependencies: + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata@1.0.1': dependencies: '@walletconnect/window-getters': 1.0.1 @@ -15779,12 +17608,7 @@ snapshots: typescript: 5.8.3 zod: 3.25.71 - abitype@1.1.0(typescript@5.8.3)(zod@3.25.71): - optionalDependencies: - typescript: 5.8.3 - zod: 3.25.71 - - abitype@1.1.0(typescript@5.8.3)(zod@4.1.12): + abitype@1.0.8(typescript@5.8.3)(zod@4.1.12): optionalDependencies: typescript: 5.8.3 zod: 4.1.12 @@ -15804,6 +17628,10 @@ snapshots: typescript: 5.8.3 zod: 4.1.12 + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + abstract-logging@2.0.1: {} accepts@1.3.8: @@ -15822,8 +17650,6 @@ snapshots: acorn@8.15.0: {} - aes-js@4.0.0-beta.5: {} - agent-base@7.1.4: {} agentkeepalive@4.6.0: @@ -15848,6 +17674,23 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + algo-msgpack-with-bigint@2.1.1: {} + + algorand-msgpack@1.1.0: {} + + algosdk@3.5.2: + dependencies: + algorand-msgpack: 1.1.0 + hi-base32: 0.5.1 + js-sha256: 0.9.0 + js-sha3: 0.8.0 + js-sha512: 0.8.0 + json-bigint: 1.0.0 + tweetnacl: 1.0.3 + vlq: 2.0.4 + + anser@1.4.10: {} + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -15856,6 +17699,8 @@ snapshots: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.3: {} any-promise@1.3.0: {} @@ -15893,8 +17738,6 @@ snapshots: is-string: 1.1.1 math-intrinsics: 1.1.0 - array-union@2.1.0: {} - array.prototype.findlast@1.2.5: dependencies: call-bind: 1.0.8 @@ -15946,12 +17789,20 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + asap@2.0.6: {} + asn1.js@4.10.1: dependencies: bn.js: 4.12.2 inherits: 2.0.4 minimalistic-assert: 1.0.1 + asn1js@3.0.6: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + assertion-error@2.0.1: {} ast-types-flow@0.0.8: {} @@ -16032,6 +17883,10 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-syntax-hermes-parser@0.33.3: + dependencies: + hermes-parser: 0.33.3 + balanced-match@1.0.2: {} base-x@3.0.11: @@ -16048,12 +17903,20 @@ snapshots: big.js@6.2.2: {} + bignumber.js@9.1.1: {} + bignumber.js@9.3.1: {} binary-extensions@2.3.0: {} + blakejs@1.2.1: {} + + bn.js@4.11.8: {} + bn.js@4.12.2: {} + bn.js@5.2.1: {} + bn.js@5.2.2: {} body-parser@1.20.3: @@ -16095,6 +17958,8 @@ snapshots: bs58: 4.0.1 text-encoding-utf-8: 1.0.2 + bowser@2.11.0: {} + bowser@2.12.1: {} brace-expansion@1.1.12: @@ -16168,6 +18033,12 @@ snapshots: dependencies: base-x: 5.0.1 + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + buffer-xor@1.0.3: {} buffer@6.0.3: @@ -16179,11 +18050,6 @@ snapshots: dependencies: node-gyp-build: 4.8.4 - bundle-require@4.2.1(esbuild@0.19.12): - dependencies: - esbuild: 0.19.12 - load-tsconfig: 0.2.5 - bundle-require@5.1.0(esbuild@0.25.5): dependencies: esbuild: 0.25.5 @@ -16267,6 +18133,29 @@ snapshots: dependencies: readdirp: 4.1.2 + chrome-launcher@0.15.2: + dependencies: + '@types/node': 22.16.0 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + transitivePeerDependencies: + - supports-color + + chromium-edge-launcher@0.3.0: + dependencies: + '@types/node': 22.16.0 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + mkdirp: 1.0.4 + transitivePeerDependencies: + - supports-color + + ci-info@2.0.0: {} + + ci-info@3.9.0: {} + cipher-base@1.0.7: dependencies: inherits: 2.0.4 @@ -16281,6 +18170,12 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 6.2.0 + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clone-response@1.0.3: dependencies: mimic-response: 1.0.1 @@ -16295,6 +18190,8 @@ snapshots: color-name@1.1.4: {} + colorette@2.0.20: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -16323,6 +18220,15 @@ snapshots: confbox@0.1.8: {} + connect@3.7.0: + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color + consola@3.4.2: {} content-disposition@0.5.4: @@ -16428,6 +18334,8 @@ snapshots: randombytes: 2.1.0 randomfill: 1.0.4 + crypto-js@4.2.0: {} + css-select@5.2.2: dependencies: boolbase: 1.0.0 @@ -16490,6 +18398,8 @@ snapshots: dependencies: '@babel/runtime': 7.28.4 + dateformat@4.6.3: {} + dayjs@1.11.13: {} debug@2.6.9: @@ -16504,6 +18414,10 @@ snapshots: dependencies: ms: 2.1.2 + debug@4.4.1: + dependencies: + ms: 2.1.3 + debug@4.4.3: dependencies: ms: 2.1.3 @@ -16565,6 +18479,8 @@ snapshots: destroy@1.2.0: {} + detect-browser@5.2.0: {} + detect-browser@5.3.0: {} detect-libc@2.1.2: @@ -16580,10 +18496,6 @@ snapshots: dijkstrajs@1.0.3: {} - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - dlv@1.1.3: {} doctrine@2.1.0: @@ -16689,6 +18601,10 @@ snapshots: dependencies: is-arrayish: 0.2.1 + error-stack-parser@2.1.4: + dependencies: + stackframe: 1.3.4 + es-abstract@1.24.0: dependencies: array-buffer-byte-length: 1.0.2 @@ -16794,38 +18710,14 @@ snapshots: es-toolkit@1.33.0: {} + es-toolkit@1.44.0: {} + es6-promise@4.2.8: {} es6-promisify@5.0.0: dependencies: es6-promise: 4.2.8 - esbuild@0.19.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.19.12 - '@esbuild/android-arm': 0.19.12 - '@esbuild/android-arm64': 0.19.12 - '@esbuild/android-x64': 0.19.12 - '@esbuild/darwin-arm64': 0.19.12 - '@esbuild/darwin-x64': 0.19.12 - '@esbuild/freebsd-arm64': 0.19.12 - '@esbuild/freebsd-x64': 0.19.12 - '@esbuild/linux-arm': 0.19.12 - '@esbuild/linux-arm64': 0.19.12 - '@esbuild/linux-ia32': 0.19.12 - '@esbuild/linux-loong64': 0.19.12 - '@esbuild/linux-mips64el': 0.19.12 - '@esbuild/linux-ppc64': 0.19.12 - '@esbuild/linux-riscv64': 0.19.12 - '@esbuild/linux-s390x': 0.19.12 - '@esbuild/linux-x64': 0.19.12 - '@esbuild/netbsd-x64': 0.19.12 - '@esbuild/openbsd-x64': 0.19.12 - '@esbuild/sunos-x64': 0.19.12 - '@esbuild/win32-arm64': 0.19.12 - '@esbuild/win32-ia32': 0.19.12 - '@esbuild/win32-x64': 0.19.12 - esbuild@0.25.5: optionalDependencies: '@esbuild/aix-ppc64': 0.25.5 @@ -16854,6 +18746,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.5 '@esbuild/win32-x64': 0.25.5 + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + escalade@3.2.0: {} escape-html@1.0.3: {} @@ -17190,18 +19111,7 @@ snapshots: '@scure/bip32': 1.4.0 '@scure/bip39': 1.3.0 - ethers@6.16.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): - dependencies: - '@adraffy/ens-normalize': 1.10.1 - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@types/node': 22.7.5 - aes-js: 4.0.0-beta.5 - tslib: 2.7.0 - ws: 8.17.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - bufferutil - - utf-8-validate + event-target-shim@5.0.1: {} eventemitter2@6.4.9: {} @@ -17222,20 +19132,10 @@ snapshots: md5.js: 1.3.5 safe-buffer: 5.2.1 - execa@5.1.1: - dependencies: - cross-spawn: 7.0.6 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - expect-type@1.2.2: {} + exponential-backoff@3.1.3: {} + express-rate-limit@7.5.1(express@5.2.1): dependencies: express: 5.2.1 @@ -17316,6 +19216,10 @@ snapshots: eyes@0.1.8: {} + fast-base64-decode@1.0.0: {} + + fast-copy@3.0.2: {} + fast-decode-uri-component@1.0.1: {} fast-deep-equal@3.1.3: {} @@ -17387,6 +19291,12 @@ snapshots: dependencies: reusify: 1.1.0 + fb-dotslash@0.5.8: {} + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -17405,6 +19315,18 @@ snapshots: filter-obj@1.1.0: {} + finalhandler@1.1.2: + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + finalhandler@1.3.1: dependencies: debug: 2.6.9 @@ -17457,6 +19379,8 @@ snapshots: flatted@3.3.3: {} + flow-enums-runtime@0.0.6: {} + follow-redirects@1.15.9: {} for-each@0.3.5: @@ -17468,6 +19392,8 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + forge-light@1.1.4: {} + form-data@4.0.3: dependencies: asynckit: 0.4.0 @@ -17534,8 +19460,6 @@ snapshots: dependencies: pump: 3.0.3 - get-stream@6.0.1: {} - get-symbol-description@1.1.0: dependencies: call-bound: 1.0.4 @@ -17572,15 +19496,6 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - globrex@0.1.2: {} gopd@1.2.0: {} @@ -17599,6 +19514,8 @@ snapshots: p-cancelable: 2.1.1 responselike: 2.0.1 + graceful-fs@4.2.11: {} + graphemer@1.4.0: {} graphql-request@6.1.0(graphql@16.11.0): @@ -17662,12 +19579,30 @@ snapshots: dependencies: function-bind: 1.1.2 + help-me@5.0.0: {} + + hermes-compiler@250829098.0.10: {} + hermes-estree@0.25.1: {} + hermes-estree@0.33.3: {} + + hermes-estree@0.35.0: {} + hermes-parser@0.25.1: dependencies: hermes-estree: 0.25.1 + hermes-parser@0.33.3: + dependencies: + hermes-estree: 0.33.3 + + hermes-parser@0.35.0: + dependencies: + hermes-estree: 0.35.0 + + hi-base32@0.5.1: {} + hmac-drbg@1.0.1: dependencies: hash.js: 1.1.7 @@ -17717,8 +19652,6 @@ snapshots: transitivePeerDependencies: - supports-color - human-signals@2.1.0: {} - humanize-ms@1.2.1: dependencies: ms: 2.1.3 @@ -17745,6 +19678,10 @@ snapshots: ignore@7.0.5: {} + image-size@1.2.1: + dependencies: + queue: 6.0.2 + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -17760,6 +19697,10 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + ipaddr.js@1.9.1: {} ipaddr.js@2.3.0: {} @@ -17823,6 +19764,8 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-docker@2.2.1: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -17892,6 +19835,8 @@ snapshots: dependencies: which-typed-array: 1.1.19 + is-typedarray@1.0.0: {} + is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -17903,6 +19848,10 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + isarray@1.0.0: {} isarray@2.0.5: {} @@ -17917,10 +19866,6 @@ snapshots: dependencies: ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - isows@1.0.7(ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)): - dependencies: - ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) - isows@1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)): dependencies: ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -17958,6 +19903,33 @@ snapshots: - bufferutil - utf-8-validate + jest-get-type@29.6.3: {} + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.16.0 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-worker@29.7.0: + dependencies: + '@types/node': 22.16.0 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + jiti@1.21.7: {} jose@5.10.0: {} @@ -17966,8 +19938,18 @@ snapshots: joycon@3.1.1: {} + js-base64@3.7.4: {} + + js-base64@3.7.7: {} + js-base64@3.7.8: {} + js-sha256@0.9.0: {} + + js-sha3@0.8.0: {} + + js-sha512@0.8.0: {} + js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -17976,6 +19958,8 @@ snapshots: dependencies: argparse: 2.0.1 + jsc-safe-url@0.2.4: {} + jsdoc-type-pratt-parser@4.1.0: {} jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): @@ -17998,7 +19982,7 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) xml-name-validator: 5.0.0 transitivePeerDependencies: - bufferutil @@ -18007,6 +19991,10 @@ snapshots: jsesc@3.1.0: {} + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + json-buffer@3.0.1: {} json-parse-even-better-errors@2.3.1: {} @@ -18067,6 +20055,8 @@ snapshots: dependencies: language-subtag-registry: 0.3.23 + leven@3.1.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -18078,6 +20068,13 @@ snapshots: process-warning: 4.0.1 set-cookie-parser: 2.7.2 + lighthouse-logger@1.4.2: + dependencies: + debug: 2.6.9 + marky: 1.3.0 + transitivePeerDependencies: + - supports-color + lilconfig@3.1.3: {} lines-and-columns@1.2.4: {} @@ -18108,18 +20105,26 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.camelcase@4.3.0: {} + lodash.debounce@4.0.8: {} lodash.merge@4.6.2: {} lodash.sortby@4.7.0: {} + lodash.throttle@4.1.1: {} + lodash@4.17.21: {} + long@5.3.1: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 + lottie-web@5.13.0: {} + loupe@3.2.1: {} lower-case@2.0.2: @@ -18134,10 +20139,18 @@ snapshots: dependencies: yallist: 3.1.1 + lute-connect@1.7.0: {} + magic-string@0.30.19: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + marky@1.3.0: {} + math-intrinsics@1.1.0: {} md5.js@1.3.5: @@ -18160,6 +20173,8 @@ snapshots: media-typer@1.1.0: {} + memoize-one@5.2.1: {} + merge-descriptors@1.0.3: {} merge-descriptors@2.0.0: {} @@ -18170,6 +20185,181 @@ snapshots: methods@1.1.2: {} + metro-babel-transformer@0.84.3: + dependencies: + '@babel/core': 7.28.4 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.35.0 + metro-cache-key: 0.84.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-cache-key@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-cache@0.84.3: + dependencies: + exponential-backoff: 3.1.3 + flow-enums-runtime: 0.0.6 + https-proxy-agent: 7.0.6 + metro-core: 0.84.3 + transitivePeerDependencies: + - supports-color + + metro-config@0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + connect: 3.7.0 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-cache: 0.84.3 + metro-core: 0.84.3 + metro-runtime: 0.84.3 + yaml: 2.8.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro-core@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.84.3 + + metro-file-map@0.84.3: + dependencies: + debug: 4.4.3 + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + nullthrows: 1.1.1 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color + + metro-minify-terser@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + terser: 5.46.2 + + metro-resolver@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-runtime@0.84.3: + dependencies: + '@babel/runtime': 7.28.4 + flow-enums-runtime: 0.0.6 + + metro-source-map@0.84.3: + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.84.3 + nullthrows: 1.1.1 + ob1: 0.84.3 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-symbolicate@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.84.3 + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-transform-plugins@0.84.3: + dependencies: + '@babel/core': 7.28.4 + '@babel/generator': 7.29.1 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-transform-worker@0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + '@babel/core': 7.28.4 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + metro: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-babel-transformer: 0.84.3 + metro-cache: 0.84.3 + metro-cache-key: 0.84.3 + metro-minify-terser: 0.84.3 + metro-source-map: 0.84.3 + metro-transform-plugins: 0.84.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro@0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/core': 7.28.4 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + accepts: 2.0.0 + chalk: 4.1.2 + ci-info: 2.0.0 + connect: 3.7.0 + debug: 4.4.3 + error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + hermes-parser: 0.35.0 + image-size: 1.2.1 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.84.3 + metro-cache: 0.84.3 + metro-cache-key: 0.84.3 + metro-config: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-core: 0.84.3 + metro-file-map: 0.84.3 + metro-resolver: 0.84.3 + metro-runtime: 0.84.3 + metro-source-map: 0.84.3 + metro-symbolicate: 0.84.3 + metro-transform-plugins: 0.84.3 + metro-transform-worker: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + mime-types: 3.0.2 + nullthrows: 1.1.1 + serialize-error: 2.1.0 + source-map: 0.5.7 + throat: 5.0.0 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + micro-ftch@0.3.1: {} micromatch@4.0.8: @@ -18196,8 +20386,6 @@ snapshots: mime@1.6.0: {} - mimic-fn@2.1.0: {} - mimic-response@1.0.1: {} mimic-response@3.1.0: {} @@ -18222,6 +20410,8 @@ snapshots: optionalDependencies: typescript: 5.8.3 + mkdirp@1.0.4: {} + mlly@1.8.0: dependencies: acorn: 8.15.0 @@ -18276,6 +20466,29 @@ snapshots: - '@babel/core' - babel-plugin-macros + next@16.0.10(react-dom@19.2.3(react@19.2.3))(react@19.2.3): + dependencies: + '@next/env': 16.0.10 + '@swc/helpers': 0.5.15 + caniuse-lite: 1.0.30001751 + postcss: 8.4.31 + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + styled-jsx: 5.1.6(@babel/core@7.28.4)(react@19.2.3) + optionalDependencies: + '@next/swc-darwin-arm64': 16.0.10 + '@next/swc-darwin-x64': 16.0.10 + '@next/swc-linux-arm64-gnu': 16.0.10 + '@next/swc-linux-arm64-musl': 16.0.10 + '@next/swc-linux-x64-gnu': 16.0.10 + '@next/swc-linux-x64-musl': 16.0.10 + '@next/swc-win32-arm64-msvc': 16.0.10 + '@next/swc-win32-x64-msvc': 16.0.10 + sharp: 0.34.4 + transitivePeerDependencies: + - '@babel/core' + - babel-plugin-macros + next@16.1.1(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@next/env': 16.1.1 @@ -18315,6 +20528,8 @@ snapshots: node-gyp-build@4.8.4: {} + node-int64@0.4.0: {} + node-mock-http@1.0.3: {} node-releases@2.0.26: {} @@ -18323,16 +20538,18 @@ snapshots: normalize-url@6.1.0: {} - npm-run-path@4.0.1: - dependencies: - path-key: 3.1.1 - nth-check@2.1.1: dependencies: boolbase: 1.0.0 + nullthrows@1.1.1: {} + nwsapi@2.2.22: {} + ob1@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + obj-multiplex@1.0.0: dependencies: end-of-stream: 1.4.5 @@ -18393,6 +20610,10 @@ snapshots: on-exit-leak-free@2.1.2: {} + on-finished@2.3.0: + dependencies: + ee-first: 1.1.1 + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -18401,9 +20622,10 @@ snapshots: dependencies: wrappy: 1.0.2 - onetime@5.1.2: + open@7.4.2: dependencies: - mimic-fn: 2.1.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 openapi-fetch@0.13.8: dependencies: @@ -18426,7 +20648,7 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - ox@0.11.3(typescript@5.8.3)(zod@3.22.4): + ox@0.14.20(typescript@5.8.3)(zod@3.22.4): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/ciphers': 1.3.0 @@ -18441,7 +20663,7 @@ snapshots: transitivePeerDependencies: - zod - ox@0.11.3(typescript@5.8.3)(zod@3.25.71): + ox@0.14.20(typescript@5.8.3)(zod@3.25.71): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/ciphers': 1.3.0 @@ -18456,7 +20678,7 @@ snapshots: transitivePeerDependencies: - zod - ox@0.11.3(typescript@5.8.3)(zod@4.1.12): + ox@0.14.20(typescript@5.8.3)(zod@4.1.12): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/ciphers': 1.3.0 @@ -18499,24 +20721,23 @@ snapshots: transitivePeerDependencies: - zod - ox@0.6.9(typescript@5.8.3)(zod@3.25.71): + ox@0.6.7(typescript@5.8.3)(zod@4.1.12): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.8.3)(zod@3.25.71) + abitype: 1.2.3(typescript@5.8.3)(zod@4.1.12) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: - zod - ox@0.8.1(typescript@5.8.3)(zod@3.25.71): + ox@0.6.9(typescript@5.8.3)(zod@3.25.71): dependencies: '@adraffy/ens-normalize': 1.11.0 - '@noble/ciphers': 1.3.0 '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 @@ -18528,11 +20749,10 @@ snapshots: transitivePeerDependencies: - zod - ox@0.9.12(typescript@5.8.3)(zod@4.1.12): + ox@0.6.9(typescript@5.8.3)(zod@4.1.12): dependencies: '@adraffy/ens-normalize': 1.11.0 - '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.1 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 @@ -18543,7 +20763,7 @@ snapshots: transitivePeerDependencies: - zod - ox@0.9.6(typescript@5.8.3)(zod@3.25.71): + ox@0.9.12(typescript@5.8.3)(zod@4.1.12): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/ciphers': 1.3.0 @@ -18551,14 +20771,14 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.8.3)(zod@3.25.71) + abitype: 1.2.3(typescript@5.8.3)(zod@4.1.12) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: - zod - ox@0.9.6(typescript@5.8.3)(zod@4.1.12): + ox@0.9.3(typescript@5.8.3)(zod@4.1.12): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/ciphers': 1.3.0 @@ -18673,14 +20893,62 @@ snapshots: duplexify: 4.1.3 split2: 4.2.0 + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + pino-abstract-transport@3.0.0: dependencies: split2: 4.2.0 + pino-pretty@13.0.0: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pump: 3.0.3 + secure-json-parse: 2.7.0 + sonic-boom: 4.2.1 + strip-json-comments: 3.1.1 + pino-std-serializers@4.0.0: {} pino-std-serializers@7.1.0: {} + pino@10.0.0: + dependencies: + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + slow-redact: 0.3.2 + sonic-boom: 4.2.1 + thread-stream: 3.1.0 + + pino@10.1.0: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 3.1.0 + pino@10.3.1: dependencies: '@pinojs/redact': 0.4.0 @@ -18723,61 +20991,41 @@ snapshots: pony-cause@2.1.11: {} - porto@0.2.19(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71)): + porto@0.2.19(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)))(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(zod@4.1.12)): dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) hono: 4.10.2 idb-keyval: 6.2.2 mipd: 0.0.7(typescript@5.8.3) ox: 0.9.12(typescript@5.8.3)(zod@4.1.12) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) zod: 4.1.12 zustand: 5.0.8(@types/react@19.2.2)(react@19.2.0)(use-sync-external-store@1.4.0(react@19.2.0)) optionalDependencies: '@tanstack/react-query': 5.90.8(react@19.2.0) react: 19.2.0 typescript: 5.8.3 - wagmi: 2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71) - transitivePeerDependencies: - - '@types/react' - - immer - - use-sync-external-store - - porto@0.2.19(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71)): - dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) - hono: 4.10.2 - idb-keyval: 6.2.2 - mipd: 0.0.7(typescript@5.8.3) - ox: 0.9.12(typescript@5.8.3)(zod@4.1.12) - viem: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - zod: 4.1.12 - zustand: 5.0.8(@types/react@19.2.2)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) - optionalDependencies: - '@tanstack/react-query': 5.90.8(react@19.2.1) - react: 19.2.1 - typescript: 5.8.3 - wagmi: 2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71) + wagmi: 2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(zod@4.1.12) transitivePeerDependencies: - '@types/react' - immer - use-sync-external-store - porto@0.2.19(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71)): + porto@0.2.19(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71)): dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) hono: 4.10.2 idb-keyval: 6.2.2 mipd: 0.0.7(typescript@5.8.3) ox: 0.9.12(typescript@5.8.3)(zod@4.1.12) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) zod: 4.1.12 zustand: 5.0.8(@types/react@19.2.2)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) optionalDependencies: '@tanstack/react-query': 5.90.8(react@19.2.1) react: 19.2.1 typescript: 5.8.3 - wagmi: 2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71) + wagmi: 2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71) transitivePeerDependencies: - '@types/react' - immer @@ -18799,20 +21047,13 @@ snapshots: camelcase-css: 2.0.1 postcss: 8.5.6 - postcss-load-config@4.0.2(postcss@8.5.6): - dependencies: - lilconfig: 3.1.3 - yaml: 2.8.1 - optionalDependencies: - postcss: 8.5.6 - - postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(yaml@2.8.1): + postcss-load-config@6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.1): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 1.21.7 postcss: 8.5.6 - tsx: 4.20.3 + tsx: 4.21.0 yaml: 2.8.1 postcss-nested@6.2.0(postcss@8.5.6): @@ -18851,6 +21092,12 @@ snapshots: prettier@3.5.2: {} + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + process-nextick-args@2.0.1: {} process-warning@1.0.0: {} @@ -18859,6 +21106,10 @@ snapshots: process-warning@5.0.0: {} + promise@8.3.0: + dependencies: + asap: 2.0.6 + prompts@2.4.2: dependencies: kleur: 3.0.3 @@ -18870,6 +21121,21 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + protobufjs@7.5.4: + 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': 22.16.0 + long: 5.3.1 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -18895,6 +21161,18 @@ snapshots: punycode@2.3.1: {} + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.5: {} + + qr-code-styling@1.6.0-rc.1: + dependencies: + qrcode-generator: 1.5.2 + + qrcode-generator@1.5.2: {} + qrcode@1.5.3: dependencies: dijkstrajs: 1.0.3 @@ -18916,6 +21194,12 @@ snapshots: dependencies: side-channel: 1.1.0 + query-string@6.13.5: + dependencies: + decode-uri-component: 0.2.2 + split-on-first: 1.1.0 + strict-uri-encode: 2.0.0 + query-string@7.1.3: dependencies: decode-uri-component: 0.2.2 @@ -18925,6 +21209,10 @@ snapshots: queue-microtask@1.2.3: {} + queue@6.0.2: + dependencies: + inherits: 2.0.4 + quick-format-unescaped@4.0.4: {} quick-lru@5.1.1: {} @@ -18956,6 +21244,14 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 + react-devtools-core@6.1.5(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + shell-quote: 1.8.3 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + react-dom@19.2.0(react@19.2.0): dependencies: react: 19.2.0 @@ -18973,6 +21269,60 @@ snapshots: react-is@16.13.1: {} + react-is@18.3.1: {} + + react-native-get-random-values@1.11.0(react-native@0.85.2(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)): + dependencies: + fast-base64-decode: 1.0.0 + react-native: 0.85.2(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10) + + react-native@0.85.2(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10): + dependencies: + '@react-native/assets-registry': 0.85.2 + '@react-native/codegen': 0.85.2(@babel/core@7.28.4) + '@react-native/community-cli-plugin': 0.85.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@react-native/gradle-plugin': 0.85.2 + '@react-native/js-polyfills': 0.85.2 + '@react-native/normalize-colors': 0.85.2 + '@react-native/virtualized-lists': 0.85.2(@types/react@19.2.2)(react-native@0.85.2(@babel/core@7.28.4)(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + babel-plugin-syntax-hermes-parser: 0.33.3 + base64-js: 1.5.1 + commander: 12.1.0 + flow-enums-runtime: 0.0.6 + hermes-compiler: 250829098.0.10 + invariant: 2.2.4 + memoize-one: 5.2.1 + metro-runtime: 0.84.3 + metro-source-map: 0.84.3 + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 + react: 19.2.3 + react-devtools-core: 6.1.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) + react-refresh: 0.14.2 + regenerator-runtime: 0.13.11 + scheduler: 0.27.0 + semver: 7.7.3 + stacktrace-parser: 0.1.11 + tinyglobby: 0.2.15 + whatwg-fetch: 3.6.20 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + yargs: 17.7.2 + optionalDependencies: + '@types/react': 19.2.2 + transitivePeerDependencies: + - '@babel/core' + - '@react-native-community/cli' + - '@react-native/metro-config' + - bufferutil + - supports-color + - utf-8-validate + + react-refresh@0.14.2: {} + react@19.2.0: {} react@19.2.1: {} @@ -19026,6 +21376,8 @@ snapshots: regenerate@1.4.2: {} + regenerator-runtime@0.13.11: {} + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.8 @@ -19084,6 +21436,8 @@ snapshots: reusify@1.1.0: {} + rfc4648@1.5.3: {} + rfdc@1.4.1: {} ripemd160@2.0.3: @@ -19185,6 +21539,8 @@ snapshots: scheduler@0.27.0: {} + secure-json-parse@2.7.0: {} + secure-json-parse@4.1.0: {} semver@6.3.1: {} @@ -19225,6 +21581,8 @@ snapshots: transitivePeerDependencies: - supports-color + serialize-error@2.1.0: {} + serve-static@1.16.2: dependencies: encodeurl: 2.0.0 @@ -19313,6 +21671,8 @@ snapshots: shebang-regex@3.0.0: {} + shell-quote@1.8.3: {} + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -19343,21 +21703,11 @@ snapshots: siginfo@2.0.0: {} - signal-exit@3.0.7: {} - signal-exit@4.1.0: {} sisteransi@1.0.5: {} - siwe@2.3.2(ethers@6.16.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)): - dependencies: - '@spruceid/siwe-parser': 2.1.2 - '@stablelib/random': 1.0.2 - ethers: 6.16.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - uri-js: 4.4.1 - valid-url: 1.0.9 - - slash@3.0.0: {} + slow-redact@0.3.2: {} snake-case@3.0.4: dependencies: @@ -19392,10 +21742,21 @@ snapshots: source-map-js@1.2.1: {} + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.5.7: {} + + source-map@0.6.1: {} + source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 + spark-md5@3.0.2: {} + spdx-exceptions@2.5.0: {} spdx-expression-parse@4.0.0: @@ -19413,6 +21774,14 @@ snapshots: stackback@0.0.2: {} + stackframe@1.3.4: {} + + stacktrace-parser@0.1.11: + dependencies: + type-fest: 0.7.1 + + statuses@1.5.0: {} + statuses@2.0.1: {} statuses@2.0.2: {} @@ -19519,8 +21888,6 @@ snapshots: strip-bom@3.0.0: {} - strip-final-newline@2.0.0: {} - strip-json-comments@3.1.1: {} strip-literal@3.1.0: @@ -19552,6 +21919,10 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} svg-parser@2.0.4: {} @@ -19574,7 +21945,7 @@ snapshots: tailwind-merge@2.6.0: {} - tailwindcss@3.4.18(tsx@4.20.3)(yaml@2.8.1): + tailwindcss@3.4.18(tsx@4.21.0)(yaml@2.8.1): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -19593,7 +21964,7 @@ snapshots: postcss: 8.5.6 postcss-import: 15.1.0(postcss@8.5.6) postcss-js: 4.1.0(postcss@8.5.6) - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(yaml@2.8.1) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.1) postcss-nested: 6.2.0(postcss@8.5.6) postcss-selector-parser: 6.1.2 resolve: 1.22.11 @@ -19602,6 +21973,13 @@ snapshots: - tsx - yaml + terser@5.46.2: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + text-encoding-utf-8@1.0.2: {} thenify-all@1.6.0: @@ -19616,10 +21994,16 @@ snapshots: dependencies: real-require: 0.1.0 + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + thread-stream@4.0.0: dependencies: real-require: 0.2.0 + throat@5.0.0: {} + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -19641,6 +22025,8 @@ snapshots: dependencies: tldts-core: 6.1.86 + tmpl@1.0.5: {} + to-buffer@1.2.2: dependencies: isarray: 2.0.5 @@ -19692,34 +22078,9 @@ snapshots: tslib@1.14.1: {} - tslib@2.7.0: {} - tslib@2.8.1: {} - tsup@7.3.0(postcss@8.5.6)(typescript@5.8.3): - dependencies: - bundle-require: 4.2.1(esbuild@0.19.12) - cac: 6.7.14 - chokidar: 3.6.0 - debug: 4.4.3 - esbuild: 0.19.12 - execa: 5.1.1 - globby: 11.1.0 - joycon: 3.1.1 - postcss-load-config: 4.0.2(postcss@8.5.6) - resolve-from: 5.0.0 - rollup: 4.52.5 - source-map: 0.8.0-beta.0 - sucrase: 3.35.0 - tree-kill: 1.2.2 - optionalDependencies: - postcss: 8.5.6 - typescript: 5.8.3 - transitivePeerDependencies: - - supports-color - - ts-node - - tsup@8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(typescript@5.8.3)(yaml@2.8.1): + tsup@8.5.0(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.8.3)(yaml@2.8.1): dependencies: bundle-require: 5.1.0(esbuild@0.25.5) cac: 6.7.14 @@ -19730,7 +22091,7 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.20.3)(yaml@2.8.1) + postcss-load-config: 6.0.1(jiti@1.21.7)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.1) resolve-from: 5.0.0 rollup: 4.52.5 source-map: 0.8.0-beta.0 @@ -19747,19 +22108,25 @@ snapshots: - tsx - yaml - tsx@4.20.3: + tsx@4.21.0: dependencies: - esbuild: 0.25.5 + esbuild: 0.27.7 get-tsconfig: 4.10.1 optionalDependencies: fsevents: 2.3.3 + tweetnacl-ts@1.0.3: + dependencies: + tslib: 1.14.1 + tweetnacl@1.0.3: {} type-check@0.4.0: dependencies: prelude-ls: 1.2.1 + type-fest@0.7.1: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0 @@ -19804,6 +22171,10 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typedarray-to-buffer@3.1.5: + dependencies: + is-typedarray: 1.0.0 + typescript-eslint@8.48.0(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3): dependencies: '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3))(eslint@9.38.0(jiti@1.21.7))(typescript@5.8.3) @@ -19823,6 +22194,10 @@ snapshots: dependencies: multiformats: 9.9.0 + uint8arrays@3.1.1: + dependencies: + multiformats: 9.9.0 + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -19832,12 +22207,8 @@ snapshots: uncrypto@0.1.3: {} - undici-types@6.19.8: {} - undici-types@6.21.0: {} - undici-types@7.16.0: {} - undici-types@7.22.0: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -19922,6 +22293,8 @@ snapshots: dependencies: node-gyp-build: 4.8.4 + utf8@3.0.0: {} + util-deprecate@1.0.2: {} util@0.12.5: @@ -19938,8 +22311,6 @@ snapshots: uuid@9.0.1: {} - valid-url@1.0.9: {} - valtio@1.13.2(@types/react@19.2.2)(react@19.2.0): dependencies: derive-valtio: 0.1.0(valtio@1.13.2(@types/react@19.2.2)(react@19.2.0)) @@ -19977,67 +22348,16 @@ snapshots: - utf-8-validate - zod - viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71): - dependencies: - '@noble/curves': 1.9.2 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.0.8(typescript@5.8.3)(zod@3.25.71) - isows: 1.0.7(ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.8.1(typescript@5.8.3)(zod@3.25.71) - ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - - viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71): - dependencies: - '@noble/curves': 1.9.1 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.8.3)(zod@3.25.71) - isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.9.6(typescript@5.8.3)(zod@3.25.71) - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - - viem@2.38.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12): - dependencies: - '@noble/curves': 1.9.1 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.8.3)(zod@4.1.12) - isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.9.6(typescript@5.8.3)(zod@4.1.12) - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - - viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71): + viem@2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12): dependencies: - '@noble/curves': 1.9.1 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.8.3)(zod@3.25.71) - isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.9.6(typescript@5.8.3)(zod@3.25.71) - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@scure/bip32': 1.6.2 + '@scure/bip39': 1.5.4 + abitype: 1.0.8(typescript@5.8.3)(zod@4.1.12) + isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + ox: 0.6.7(typescript@5.8.3)(zod@4.1.12) + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -20045,7 +22365,7 @@ snapshots: - utf-8-validate - zod - viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.22.4): + viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.22.4): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 @@ -20053,7 +22373,7 @@ snapshots: '@scure/bip39': 1.6.0 abitype: 1.2.3(typescript@5.8.3)(zod@3.22.4) isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.11.3(typescript@5.8.3)(zod@3.22.4) + ox: 0.14.20(typescript@5.8.3)(zod@3.22.4) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.8.3 @@ -20062,7 +22382,7 @@ snapshots: - utf-8-validate - zod - viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71): + viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 @@ -20070,7 +22390,7 @@ snapshots: '@scure/bip39': 1.6.0 abitype: 1.2.3(typescript@5.8.3)(zod@3.25.71) isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.11.3(typescript@5.8.3)(zod@3.25.71) + ox: 0.14.20(typescript@5.8.3)(zod@3.25.71) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.8.3 @@ -20079,7 +22399,7 @@ snapshots: - utf-8-validate - zod - viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12): + viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 @@ -20087,7 +22407,7 @@ snapshots: '@scure/bip39': 1.6.0 abitype: 1.2.3(typescript@5.8.3)(zod@4.1.12) isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.11.3(typescript@5.8.3)(zod@4.1.12) + ox: 0.14.20(typescript@5.8.3)(zod@4.1.12) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.8.3 @@ -20096,13 +22416,13 @@ snapshots: - utf-8-validate - zod - vite-node@3.2.4(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1): + vite-node@3.2.4(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1): dependencies: cac: 6.7.14 debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + vite: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - jiti @@ -20117,18 +22437,18 @@ snapshots: - tsx - yaml - vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)): + vite-tsconfig-paths@5.1.4(typescript@5.8.3)(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)): dependencies: debug: 4.4.3 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.8.3) optionalDependencies: - vite: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + vite: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color - typescript - vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1): + vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1): dependencies: esbuild: 0.25.5 fdir: 6.5.0(picomatch@4.0.3) @@ -20140,14 +22460,15 @@ snapshots: '@types/node': 22.16.0 fsevents: 2.3.3 jiti: 1.21.7 - tsx: 4.20.3 + terser: 5.46.2 + tsx: 4.21.0 yaml: 2.8.1 - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(tsx@4.20.3)(yaml@2.8.1): + vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.16.0)(jiti@1.21.7)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1)) + '@vitest/mocker': 3.2.4(vite@6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 @@ -20165,8 +22486,8 @@ snapshots: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) - vite-node: 3.2.4(@types/node@22.16.0)(jiti@1.21.7)(tsx@4.20.3)(yaml@2.8.1) + vite: 6.4.1(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@22.16.0)(jiti@1.21.7)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: '@types/debug': 4.1.12 @@ -20186,18 +22507,22 @@ snapshots: - tsx - yaml + vlq@1.0.1: {} + + vlq@2.0.4: {} + w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 - wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71): + wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(zod@4.1.12): dependencies: '@tanstack/react-query': 5.90.8(react@19.2.0) - '@wagmi/connectors': 6.1.0(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@wagmi/connectors': 6.1.0(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)))(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.0))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.0)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12))(zod@4.1.12))(zod@4.1.12) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.0)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.0))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12)) react: 19.2.0 use-sync-external-store: 1.4.0(react@19.2.0) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@4.1.12) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -20229,14 +22554,14 @@ snapshots: - utf-8-validate - zod - wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71): + wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71): dependencies: '@tanstack/react-query': 5.90.8(react@19.2.1) - '@wagmi/connectors': 6.1.0(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) + '@wagmi/connectors': 6.1.0(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) react: 19.2.1 use-sync-external-store: 1.4.0(react@19.2.1) - viem: 2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) optionalDependencies: typescript: 5.8.3 transitivePeerDependencies: @@ -20268,44 +22593,9 @@ snapshots: - utf-8-validate - zod - wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71): + walker@1.0.8: dependencies: - '@tanstack/react-query': 5.90.8(react@19.2.1) - '@wagmi/connectors': 6.1.0(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(wagmi@2.18.2(@tanstack/query-core@5.90.8)(@tanstack/react-query@5.90.8(react@19.2.1))(@types/react@19.2.2)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.31.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71))(zod@3.25.71))(zod@3.25.71) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.8)(@types/react@19.2.2)(react@19.2.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71)) - react: 19.2.1 - use-sync-external-store: 1.4.0(react@19.2.1) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.71) - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/functions' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - immer - - ioredis - - supports-color - - uploadthing - - utf-8-validate - - zod + makeerror: 1.0.12 webextension-polyfill@0.10.0: {} @@ -20319,6 +22609,8 @@ snapshots: dependencies: iconv-lite: 0.6.3 + whatwg-fetch@3.6.20: {} + whatwg-mimetype@4.0.0: {} whatwg-url@14.2.0: @@ -20416,17 +22708,17 @@ snapshots: bufferutil: 4.0.9 utf-8-validate: 5.0.10 - ws@8.17.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): + ws@7.5.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 - ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): + ws@8.17.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 - ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10): + ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 @@ -20451,6 +22743,8 @@ snapshots: y18n@4.0.3: {} + y18n@5.0.8: {} + yallist@3.1.1: {} yaml@2.8.1: {} @@ -20460,6 +22754,8 @@ snapshots: camelcase: 5.3.1 decamelize: 1.2.0 + yargs-parser@21.1.1: {} + yargs@15.4.1: dependencies: cliui: 6.0.0 @@ -20474,6 +22770,16 @@ snapshots: y18n: 4.0.3 yargs-parser: 18.1.3 + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yocto-queue@0.1.0: {} zod-to-json-schema@3.25.1(zod@3.25.71): diff --git a/e2e/pnpm-workspace.yaml b/e2e/pnpm-workspace.yaml index 190cf9d2ab..59b71e7236 100644 --- a/e2e/pnpm-workspace.yaml +++ b/e2e/pnpm-workspace.yaml @@ -11,3 +11,13 @@ packages: - "../typescript/packages/http/*" - "../typescript/packages/mechanisms/*" - "../typescript/packages/legacy/*" +minimumReleaseAge: 4320 # Only install package versions that have been published for at least 3 days. +minimumReleaseAgeStrict: true +allowBuilds: + bufferutil: true + esbuild: true + keccak: true + protobufjs: true + sharp: true + unrs-resolver: true + utf-8-validate: true diff --git a/e2e/servers/echo/README.md b/e2e/servers/echo/README.md index 0a1fae0ee0..c8a30c6e73 100644 --- a/e2e/servers/echo/README.md +++ b/e2e/servers/echo/README.md @@ -22,12 +22,12 @@ This server demonstrates and tests the x402 Echo middleware with both EVM and SV ```go import ( - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - echomw "github.com/coinbase/x402/go/http/echo" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" - "github.com/coinbase/x402/go/extensions/bazaar" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + echomw "github.com/x402-foundation/x402/go/http/echo" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" + "github.com/x402-foundation/x402/go/extensions/bazaar" "github.com/labstack/echo/v4" ) @@ -173,12 +173,12 @@ Content-Type: application/json ## Dependencies -- `github.com/coinbase/x402/go` - Core x402 -- `github.com/coinbase/x402/go/http` - HTTP integration -- `github.com/coinbase/x402/go/http/echo` - Echo middleware -- `github.com/coinbase/x402/go/mechanisms/evm` - EVM server -- `github.com/coinbase/x402/go/mechanisms/svm` - SVM server -- `github.com/coinbase/x402/go/extensions/bazaar` - Discovery extension +- `github.com/x402-foundation/x402/go` - Core x402 +- `github.com/x402-foundation/x402/go/http` - HTTP integration +- `github.com/x402-foundation/x402/go/http/echo` - Echo middleware +- `github.com/x402-foundation/x402/go/mechanisms/evm` - EVM server +- `github.com/x402-foundation/x402/go/mechanisms/svm` - SVM server +- `github.com/x402-foundation/x402/go/extensions/bazaar` - Discovery extension - `github.com/labstack/echo/v4` - HTTP framework ## Implementation Highlights diff --git a/e2e/servers/echo/go.mod b/e2e/servers/echo/go.mod index dc75cd9323..aef42e2a51 100644 --- a/e2e/servers/echo/go.mod +++ b/e2e/servers/echo/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/e2e/servers/echo +module github.com/x402-foundation/x402/e2e/servers/echo go 1.24.0 toolchain go1.24.1 require ( - github.com/coinbase/x402/go v0.0.0 github.com/joho/godotenv v1.5.1 github.com/labstack/echo/v4 v4.15.1 + github.com/x402-foundation/x402/go v0.0.0 ) require ( @@ -70,4 +70,4 @@ require ( golang.org/x/time v0.14.0 // indirect ) -replace github.com/coinbase/x402/go => ../../../go +replace github.com/x402-foundation/x402/go => ../../../go diff --git a/e2e/servers/echo/main.go b/e2e/servers/echo/main.go index 0269f74880..a93d2431f7 100644 --- a/e2e/servers/echo/main.go +++ b/e2e/servers/echo/main.go @@ -8,18 +8,18 @@ import ( "syscall" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" - "github.com/coinbase/x402/go/extensions/types" - x402http "github.com/coinbase/x402/go/http" - echomw "github.com/coinbase/x402/go/http/echo" - exactevm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - uptoevm "github.com/coinbase/x402/go/mechanisms/evm/upto/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" "github.com/joho/godotenv" "github.com/labstack/echo/v4" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/extensions/types" + x402http "github.com/x402-foundation/x402/go/http" + echomw "github.com/x402-foundation/x402/go/http/echo" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) var shutdownRequested bool diff --git a/e2e/servers/echo/test.config.json b/e2e/servers/echo/test.config.json index 74682bc629..7e55cdd639 100644 --- a/e2e/servers/echo/test.config.json +++ b/e2e/servers/echo/test.config.json @@ -16,7 +16,8 @@ "description": "Protected endpoint requiring EIP-3009 payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" }, { "path": "/exact/evm/permit2", @@ -24,8 +25,11 @@ "description": "Protected endpoint requiring Permit2 payment (standard settle, no gas sponsoring)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "permit2Direct": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/exact/evm/permit2-eip2612GasSponsoring", @@ -33,8 +37,11 @@ "description": "Protected endpoint requiring Permit2 payment with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "coldstart": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2-erc20ApprovalGasSponsoring", @@ -42,9 +49,14 @@ "description": "Protected endpoint requiring Permit2 payment with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/upto/evm/permit2", @@ -52,8 +64,11 @@ "description": "Protected endpoint requiring upto Permit2 payment (usage-based settlement)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "permit2Direct": true + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/exact/svm", diff --git a/e2e/servers/express/index.ts b/e2e/servers/express/index.ts index 90591c19c9..ad1915b305 100644 --- a/e2e/servers/express/index.ts +++ b/e2e/servers/express/index.ts @@ -1,10 +1,13 @@ import express from "express"; import { paymentMiddleware, setSettlementOverrides } from "@x402/express"; import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server"; +import { ExactAvmScheme } from "@x402/avm/exact/server"; import { ExactEvmScheme } from "@x402/evm/exact/server"; import { UptoEvmScheme } from "@x402/evm/upto/server"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/server"; import { ExactSvmScheme } from "@x402/svm/exact/server"; import { ExactAptosScheme } from "@x402/aptos/exact/server"; +import { ExactHederaScheme } from "@x402/hedera/exact/server"; import { ExactStellarScheme } from "@x402/stellar/exact/server"; import { bazaarResourceServerExtension, declareDiscoveryExtension } from "@x402/extensions/bazaar"; import { @@ -12,6 +15,7 @@ import { declareErc20ApprovalGasSponsoringExtension, } from "@x402/extensions"; import dotenv from "dotenv"; +import { privateKeyToAccount } from "viem/accounts"; dotenv.config(); @@ -23,16 +27,22 @@ dotenv.config(); */ const PORT = process.env.PORT || "4021"; +const AVM_NETWORK = (process.env.AVM_NETWORK || "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=") as `${string}:${string}`; const EVM_NETWORK = (process.env.EVM_NETWORK || "eip155:84532") as `${string}:${string}`; const SVM_NETWORK = (process.env.SVM_NETWORK || "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1") as `${string}:${string}`; const APTOS_NETWORK = (process.env.APTOS_NETWORK || "aptos:2") as `${string}:${string}`; +const HEDERA_NETWORK = (process.env.HEDERA_NETWORK || "hedera:testnet") as `${string}:${string}`; const STELLAR_NETWORK = (process.env.STELLAR_NETWORK || "stellar:testnet") as `${string}:${string}`; const EVM_PAYEE_ADDRESS = process.env.EVM_PAYEE_ADDRESS as `0x${string}`; const SVM_PAYEE_ADDRESS = process.env.SVM_PAYEE_ADDRESS as string; const EVM_PERMIT2_ASSET = process.env.EVM_PERMIT2_ASSET as `0x${string}`; +const AVM_PAYEE_ADDRESS = process.env.AVM_PAYEE_ADDRESS as string; const APTOS_PAYEE_ADDRESS = process.env.APTOS_PAYEE_ADDRESS as string; +const HEDERA_PAYEE_ADDRESS = process.env.HEDERA_PAYEE_ADDRESS as string | undefined; const STELLAR_PAYEE_ADDRESS = process.env.STELLAR_PAYEE_ADDRESS as string | undefined; +const HEDERA_ASSET = process.env.HEDERA_ASSET ?? "0.0.0"; // 0.0.0 = HBAR or 0.0.429274 for USDC testnet +const HEDERA_AMOUNT = process.env.HEDERA_AMOUNT ?? "100000"; // price in smallest units (tinybars or token decimals), defaults to 0.001 HBAR or 0.1 USDC const facilitatorUrl = process.env.FACILITATOR_URL; if (!EVM_PAYEE_ADDRESS) { @@ -64,12 +74,33 @@ if (mockFacilitatorUrl) { const server = new x402ResourceServer(facilitatorClients); // Register server schemes +if (AVM_PAYEE_ADDRESS) { + server.register("algorand:*", new ExactAvmScheme()); +} server.register("eip155:*", new ExactEvmScheme()); server.register("eip155:*", new UptoEvmScheme()); + +// Register batch-settlement scheme for the EVM payee. +// e2e flow does NOT use ChannelManager — settle actions are handled inline. +const receiverAuthorizerPrivateKey = process.env.EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY as + | `0x${string}` + | undefined; +const receiverAuthorizerSigner = receiverAuthorizerPrivateKey + ? privateKeyToAccount(receiverAuthorizerPrivateKey) + : undefined; +server.register( + "eip155:*", + new BatchSettlementEvmScheme(EVM_PAYEE_ADDRESS, { + ...(receiverAuthorizerSigner ? { receiverAuthorizerSigner } : {}), + }), +); server.register("solana:*", new ExactSvmScheme()); if (APTOS_PAYEE_ADDRESS) { server.register("aptos:*", new ExactAptosScheme()); } +if (HEDERA_PAYEE_ADDRESS) { + server.register("hedera:*", new ExactHederaScheme()); +} if (STELLAR_PAYEE_ADDRESS) { server.register("stellar:*", new ExactStellarScheme()); } @@ -82,6 +113,20 @@ console.log( ); console.log(`Using remote facilitator at: ${facilitatorUrl}`); +/** + * Pre-middleware guard for optional AVM endpoint + * Returns 501 Not Implemented if AVM is not configured + */ +app.get("/exact/avm", (req, res, next) => { + if (!AVM_PAYEE_ADDRESS) { + return res.status(501).json({ + error: "AVM payments not configured", + message: "AVM_PAYEE_ADDRESS environment variable is not set", + }); + } + next(); +}); + /** * Pre-middleware guard for optional Aptos endpoint * Returns 501 Not Implemented if Aptos is not configured @@ -96,6 +141,20 @@ app.get("/exact/aptos", (req, res, next) => { next(); }); +/** + * Pre-middleware guard for optional Hedera endpoint + * Returns 501 Not Implemented if Hedera is not configured + */ +app.get("/exact/hedera", (req, res, next) => { + if (!HEDERA_PAYEE_ADDRESS) { + return res.status(501).json({ + error: "Hedera payments not configured", + message: "HEDERA_PAYEE_ADDRESS environment variable is not set", + }); + } + next(); +}); + /** * Pre-middleware guard for optional Stellar endpoint * Returns 501 Not Implemented if Stellar is not configured @@ -120,6 +179,88 @@ app.use( paymentMiddleware( { // Route-specific payment configuration + ...(AVM_PAYEE_ADDRESS + ? { + "GET /exact/avm": { + accepts: { + payTo: AVM_PAYEE_ADDRESS, + scheme: "exact", + price: "$0.001", + network: AVM_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected endpoint accessed successfully", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, + }, + required: ["message", "timestamp"], + }, + }, + }), + }, + }, + } + : {}), + "GET /batch-settlement/evm/eip3009": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + price: "$0.001", + network: EVM_NETWORK, + }, + }, + "GET /batch-settlement/evm/permit2": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: { + amount: "1000", + asset: EVM_PERMIT2_ASSET, + extra: { + assetTransferMethod: "permit2", + name: EVM_NETWORK == "eip155:84532" ? "USDC" : "USD Coin", + version: "2", + }, + }, + }, + }, + "GET /batch-settlement/evm/permit2-eip2612GasSponsoring": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: "$0.001", + extra: { assetTransferMethod: "permit2" }, + }, + extensions: { + ...declareEip2612GasSponsoringExtension(), + }, + }, + "GET /batch-settlement/evm/permit2-erc20ApprovalGasSponsoring": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: { + amount: "1000", + asset: EVM_PERMIT2_ASSET, + extra: { + assetTransferMethod: "permit2", + }, + }, + }, + extensions: { + ...declareErc20ApprovalGasSponsoringExtension(), + }, + }, "GET /exact/evm/eip3009": { accepts: { payTo: EVM_PAYEE_ADDRESS, @@ -199,6 +340,38 @@ app.use( }, } : {}), + ...(HEDERA_PAYEE_ADDRESS + ? { + "GET /exact/hedera": { + accepts: { + payTo: HEDERA_PAYEE_ADDRESS, + scheme: "exact", + price: { + amount: HEDERA_AMOUNT, + asset: HEDERA_ASSET, + }, + network: HEDERA_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected Hedera endpoint accessed successfully", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, + }, + required: ["message", "timestamp"], + }, + }, + }), + }, + }, + } + : {}), // Permit2 endpoint for ERC-20 approval gas sponsoring (no EIP-2612) "GET /exact/evm/permit2-erc20ApprovalGasSponsoring": { accepts: { @@ -375,6 +548,55 @@ app.use( ), ); +/** + * Protected AVM endpoint - requires payment to access + * + * This endpoint demonstrates a resource protected by x402 payment middleware for AVM. + * Clients must provide a valid payment signature to access this endpoint. + * Note: 501 check is handled by pre-middleware guard above. + */ +app.get("/exact/avm", (req, res) => { + res.json({ + message: "Protected endpoint accessed successfully", + timestamp: new Date().toISOString(), + }); +}); + +/** + * Protected batch-settlement endpoint — exercised by repeated voucher requests + * over a single payment channel followed by an optional cooperative refund. + */ +app.get("/batch-settlement/evm/eip3009", (req, res) => { + res.json({ + message: "Batch-settlement endpoint accessed successfully", + timestamp: new Date().toISOString(), + }); +}); + +app.get("/batch-settlement/evm/permit2", (req, res) => { + res.json({ + message: "Batch-settlement Permit2 endpoint accessed successfully", + timestamp: new Date().toISOString(), + method: "batch-settlement-permit2", + }); +}); + +app.get("/batch-settlement/evm/permit2-eip2612GasSponsoring", (req, res) => { + res.json({ + message: "Batch-settlement Permit2 EIP-2612 endpoint accessed successfully", + timestamp: new Date().toISOString(), + method: "batch-settlement-permit2-eip2612", + }); +}); + +app.get("/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", (req, res) => { + res.json({ + message: "Batch-settlement Permit2 ERC-20 approval endpoint accessed successfully", + timestamp: new Date().toISOString(), + method: "batch-settlement-permit2-erc20-approval", + }); +}); + /** * Protected endpoint - requires payment to access * @@ -415,6 +637,20 @@ app.get("/exact/aptos", (req, res) => { }); }); +/** + * Protected Hedera endpoint - requires payment to access + * + * This endpoint demonstrates a resource protected by x402 payment middleware for Hedera. + * Clients must provide a valid payment signature to access this endpoint. + * Note: 501 check is handled by pre-middleware guard above. + */ +app.get("/exact/hedera", (req, res) => { + res.json({ + message: "Protected Hedera endpoint accessed successfully", + timestamp: new Date().toISOString(), + }); +}); + /** * Protected Permit2 ERC-20 endpoint - requires payment via Permit2 flow with ERC-20 approval * @@ -536,22 +772,32 @@ app.listen(parseInt(PORT), () => { ║ x402 Express E2E Test Server ║ ╠════════════════════════════════════════════════════════╣ ║ Server: http://localhost:${PORT} ║ +║ AVM Network: ${AVM_NETWORK} ║ ║ EVM Network: ${EVM_NETWORK} ║ ║ SVM Network: ${SVM_NETWORK} ║ ║ Aptos Network: ${APTOS_NETWORK} ║ +║ Hedera Network: ${HEDERA_NETWORK} ║ ║ Stellar Network: ${STELLAR_NETWORK}║ +║ AVM Payee: ${AVM_PAYEE_ADDRESS || "(not configured)"} ║ EVM Payee: ${EVM_PAYEE_ADDRESS} ║ ║ SVM Payee: ${SVM_PAYEE_ADDRESS} ║ ║ Aptos Payee: ${APTOS_PAYEE_ADDRESS || "(not configured)"} +║ Hedera Payee: ${HEDERA_PAYEE_ADDRESS || "(not configured)"} ║ Stellar Payee: ${STELLAR_PAYEE_ADDRESS || "(not configured)"} ║ ║ ║ Endpoints: ║ +║ • GET /exact/avm (AVM) ║ ║ • GET /exact/evm/eip3009 (EVM EIP-3009) ║ +║ • GET /batch-settlement/evm/eip3009 (Batch-settlement) ║ +║ • GET /batch-settlement/evm/permit2 (Batch Permit2) ║ +║ • GET /batch-settlement/evm/permit2-eip2612GasSponsoring ║ +║ • GET /batch-settlement/evm/permit2-erc20ApprovalGasSponsoring ║ ║ • GET /exact/evm/permit2 (Permit2) ║ ║ • GET /exact/evm/permit2-eip2612GasSponsoring ║ ║ • GET /exact/evm/permit2-erc20ApprovalGasSponsoring ║ ║ • GET /exact/svm (SVM) ║ ║ • GET /exact/aptos (Aptos) ║ +║ • GET /exact/hedera (Hedera) ║ ║ • GET /exact/stellar (Stellar) ║ ║ • GET /health (no payment required) ║ ║ • POST /close (shutdown server) ║ diff --git a/e2e/servers/express/package.json b/e2e/servers/express/package.json index 4756535ea6..f9bcf45814 100644 --- a/e2e/servers/express/package.json +++ b/e2e/servers/express/package.json @@ -11,9 +11,11 @@ }, "dependencies": { "@x402/aptos": "workspace:*", + "@x402/avm": "workspace:*", "@x402/core": "workspace:*", "@x402/express": "workspace:*", "@x402/evm": "workspace:*", + "@x402/hedera": "workspace:*", "@x402/extensions": "workspace:*", "@x402/stellar": "workspace:*", "@x402/svm": "workspace:*", @@ -23,6 +25,7 @@ "devDependencies": { "@eslint/js": "^9.24.0", "@types/express": "^5.0.1", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -30,8 +33,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/e2e/servers/express/test.config.json b/e2e/servers/express/test.config.json index 188ab91bbf..c46e6a6f33 100644 --- a/e2e/servers/express/test.config.json +++ b/e2e/servers/express/test.config.json @@ -3,16 +3,75 @@ "type": "server", "language": "typescript", "x402Version": 2, - "extensions": ["bazaar", "eip2612GasSponsoring", "erc20ApprovalGasSponsoring"], - + "extensions": [ + "bazaar", + "eip2612GasSponsoring", + "erc20ApprovalGasSponsoring" + ], "endpoints": [ + { + "path": "/exact/avm", + "method": "GET", + "description": "Protected endpoint requiring payment on AVM network", + "requiresPayment": true, + "protocolFamily": "avm" + }, { "path": "/exact/evm/eip3009", "method": "GET", "description": "Protected endpoint requiring EIP-3009 payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" + }, + { + "path": "/batch-settlement/evm/eip3009", + "method": "GET", + "description": "Protected endpoint exercised by deposit + voucher + recovery voucher + cooperative refund", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "eip3009" + }, + { + "path": "/batch-settlement/evm/permit2", + "method": "GET", + "description": "Batch-settlement Permit2 direct endpoint (pre-approved Permit2)", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } + }, + { + "path": "/batch-settlement/evm/permit2-eip2612GasSponsoring", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with EIP-2612 gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } + }, + { + "path": "/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with ERC-20 approval gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2", @@ -20,8 +79,11 @@ "description": "Protected endpoint requiring Permit2 payment (standard settle, no gas sponsoring)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "permit2Direct": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/exact/evm/permit2-eip2612GasSponsoring", @@ -29,8 +91,11 @@ "description": "Protected endpoint requiring Permit2 payment with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "coldstart": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2-erc20ApprovalGasSponsoring", @@ -38,9 +103,14 @@ "description": "Protected endpoint requiring Permit2 payment with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/upto/evm/permit2", @@ -48,8 +118,11 @@ "description": "Protected endpoint requiring Upto Permit2 payment (standard settle, no gas sponsoring)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "permit2Direct": true + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/upto/evm/permit2-eip2612GasSponsoring", @@ -57,8 +130,11 @@ "description": "Protected endpoint requiring Upto Permit2 payment with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "coldstart": true + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/upto/evm/permit2-erc20ApprovalGasSponsoring", @@ -66,9 +142,14 @@ "description": "Protected endpoint requiring Upto Permit2 payment with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/svm", @@ -84,6 +165,13 @@ "requiresPayment": true, "protocolFamily": "aptos" }, + { + "path": "/exact/hedera", + "method": "GET", + "description": "Protected endpoint requiring payment on Hedera network", + "requiresPayment": true, + "protocolFamily": "hedera" + }, { "path": "/exact/stellar", "method": "GET", @@ -105,7 +193,18 @@ } ], "environment": { - "required": ["PORT", "EVM_PAYEE_ADDRESS", "SVM_PAYEE_ADDRESS", "FACILITATOR_URL"], - "optional": ["APTOS_PAYEE_ADDRESS", "STELLAR_PAYEE_ADDRESS"] + "required": [ + "PORT", + "EVM_PAYEE_ADDRESS", + "SVM_PAYEE_ADDRESS", + "FACILITATOR_URL" + ], + "optional": [ + "AVM_PAYEE_ADDRESS", + "APTOS_PAYEE_ADDRESS", + "HEDERA_PAYEE_ADDRESS", + "STELLAR_PAYEE_ADDRESS", + "EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY" + ] } -} +} \ No newline at end of file diff --git a/e2e/servers/fastapi/main.py b/e2e/servers/fastapi/main.py index 1cfce7bedf..cb29c28f36 100644 --- a/e2e/servers/fastapi/main.py +++ b/e2e/servers/fastapi/main.py @@ -8,21 +8,27 @@ from dotenv import load_dotenv from fastapi import FastAPI, HTTPException +from fastapi import Response as FastAPIResponse # Import from new x402 package from x402 import x402ResourceServer from x402.http import FacilitatorConfig, HTTPFacilitatorClient -from x402.http.middleware.fastapi import payment_middleware +from x402.http.middleware.fastapi import payment_middleware, set_settlement_overrides from x402.mechanisms.evm.exact import ( register_exact_evm_server, ) +from x402.mechanisms.evm.upto import UptoEvmServerScheme from x402.mechanisms.svm.exact import register_exact_svm_server +from x402.mechanisms.tvm import TVM_TESTNET +from x402.mechanisms.tvm.exact import ExactTvmServerScheme from x402.extensions.bazaar import ( bazaar_resource_server_extension, declare_discovery_extension, OutputConfig, ) -from x402.extensions.eip2612_gas_sponsoring import declare_eip2612_gas_sponsoring_extension +from x402.extensions.eip2612_gas_sponsoring import ( + declare_eip2612_gas_sponsoring_extension, +) from x402.extensions.erc20_approval_gas_sponsoring import ( declare_erc20_approval_gas_sponsoring_extension, ) @@ -33,18 +39,18 @@ # Get configuration from environment EVM_ADDRESS = os.getenv("EVM_PAYEE_ADDRESS") SVM_ADDRESS = os.getenv("SVM_PAYEE_ADDRESS") +TVM_ADDRESS = os.getenv("TVM_PAYEE_ADDRESS") PORT = int(os.getenv("PORT", "4021")) FACILITATOR_URL = os.getenv("FACILITATOR_URL") EVM_PERMIT2_ASSET = os.getenv( "EVM_PERMIT2_ASSET", "0x036CbD53842c5426634e7929541eC2318f3dCF7e" ) +TVM_NETWORK = os.getenv("TVM_NETWORK", TVM_TESTNET) -if not EVM_ADDRESS: - print("Error: Missing required environment variable EVM_PAYEE_ADDRESS") - sys.exit(1) - -if not SVM_ADDRESS: - print("Error: Missing required environment variable SVM_PAYEE_ADDRESS") +if not any([EVM_ADDRESS, SVM_ADDRESS, TVM_ADDRESS]): + print( + "Error: At least one of EVM_PAYEE_ADDRESS, SVM_PAYEE_ADDRESS, or TVM_PAYEE_ADDRESS is required" + ) sys.exit(1) # Network configurations (CAIP-2 format) @@ -67,7 +73,9 @@ # Register EVM and SVM exact schemes register_exact_evm_server(server, EVM_NETWORK) +server.register(EVM_NETWORK, UptoEvmServerScheme()) register_exact_svm_server(server, SVM_NETWORK) +server.register(TVM_NETWORK, ExactTvmServerScheme()) # Register Bazaar discovery extension server.register_extension(bazaar_resource_server_extension) @@ -124,6 +132,31 @@ ), }, }, + "GET /exact/tvm": { + "accepts": { + "scheme": "exact", + "payTo": TVM_ADDRESS, + "price": "$0.001", + "network": TVM_NETWORK, + }, + "extensions": { + **declare_discovery_extension( + output=OutputConfig( + example={ + "message": "Access granted to TVM protected resource", + "timestamp": "2024-01-01T00:00:00Z", + }, + schema={ + "properties": { + "message": {"type": "string"}, + "timestamp": {"type": "string"}, + }, + "required": ["message", "timestamp"], + }, + ) + ), + }, + }, "GET /exact/evm/permit2-eip2612GasSponsoring": { "accepts": { "scheme": "exact", @@ -175,6 +208,83 @@ **declare_erc20_approval_gas_sponsoring_extension(), }, }, + "GET /upto/evm/permit2": { + "accepts": { + "scheme": "upto", + "payTo": EVM_ADDRESS, + "network": EVM_NETWORK, + "price": { + "amount": "2000", + "asset": EVM_PERMIT2_ASSET, + "extra": { + "assetTransferMethod": "permit2", + "name": "USDC", + "version": "2", + }, + }, + }, + "extensions": { + **declare_discovery_extension( + output=OutputConfig( + example={ + "message": "Upto endpoint accessed successfully", + "timestamp": "2024-01-01T00:00:00Z", + "method": "upto-permit2", + }, + schema={ + "properties": { + "message": {"type": "string"}, + "timestamp": {"type": "string"}, + "method": {"type": "string"}, + }, + "required": ["message", "timestamp"], + }, + ) + ), + }, + }, + "GET /upto/evm/permit2-eip2612GasSponsoring": { + "accepts": { + "scheme": "upto", + "payTo": EVM_ADDRESS, + "network": EVM_NETWORK, + "price": { + "amount": "2000", + "asset": EVM_PERMIT2_ASSET, + "extra": { + "assetTransferMethod": "permit2", + "name": "USDC", + "version": "2", + }, + }, + }, + "extensions": { + **declare_eip2612_gas_sponsoring_extension(), + }, + }, + "GET /upto/evm/permit2-erc20ApprovalGasSponsoring": { + "accepts": { + "scheme": "upto", + "payTo": EVM_ADDRESS, + "network": EVM_NETWORK, + "price": { + "amount": "2000", + "asset": EVM_PERMIT2_ASSET, + "extra": { + "assetTransferMethod": "permit2", + }, + }, + }, + "extensions": { + **declare_erc20_approval_gas_sponsoring_extension(), + }, + }, +} + +routes = { + route: requirements + for route, requirements in routes.items() + if requirements["accepts"].get("payTo") } @@ -212,6 +322,18 @@ async def protected_svm_endpoint() -> Dict[str, Any]: } +@app.get("/exact/tvm") +async def protected_tvm_endpoint() -> Dict[str, Any]: + """Protected endpoint that requires TVM payment.""" + if shutdown_requested: + raise HTTPException(status_code=503, detail="Server shutting down") + + return { + "message": "Access granted to TVM protected resource", + "timestamp": "2024-01-01T00:00:00Z", + } + + @app.get("/exact/evm/permit2-eip2612GasSponsoring") async def protected_permit2_endpoint() -> Dict[str, Any]: """Protected endpoint that requires Permit2 payment.""" @@ -238,6 +360,45 @@ async def protected_permit2_erc20_endpoint() -> Dict[str, Any]: } +@app.get("/upto/evm/permit2") +async def protected_upto_permit2_endpoint(response: FastAPIResponse): + """Protected endpoint that requires upto Permit2 payment.""" + if shutdown_requested: + raise HTTPException(status_code=503, detail="Server shutting down") + set_settlement_overrides(response, {"amount": "1000"}) + return { + "message": "Upto endpoint accessed successfully", + "timestamp": "2024-01-01T00:00:00Z", + "method": "upto-permit2", + } + + +@app.get("/upto/evm/permit2-eip2612GasSponsoring") +async def protected_upto_permit2_eip2612_endpoint(response: FastAPIResponse): + """Protected endpoint that requires upto Permit2 payment with EIP-2612 gas sponsoring.""" + if shutdown_requested: + raise HTTPException(status_code=503, detail="Server shutting down") + set_settlement_overrides(response, {"amount": "1000"}) + return { + "message": "Upto Permit2 EIP-2612 endpoint accessed successfully", + "timestamp": "2024-01-01T00:00:00Z", + "method": "upto-permit2-eip2612", + } + + +@app.get("/upto/evm/permit2-erc20ApprovalGasSponsoring") +async def protected_upto_permit2_erc20_endpoint(response: FastAPIResponse): + """Protected endpoint that requires upto Permit2 payment with ERC-20 approval gas sponsoring.""" + if shutdown_requested: + raise HTTPException(status_code=503, detail="Server shutting down") + set_settlement_overrides(response, {"amount": "1000"}) + return { + "message": "Upto Permit2 ERC-20 approval endpoint accessed successfully", + "timestamp": "2024-01-01T00:00:00Z", + "method": "upto-permit2-erc20-approval", + } + + @app.get("/health") async def health_check() -> Dict[str, Any]: """Health check endpoint.""" diff --git a/e2e/servers/fastapi/pyproject.toml b/e2e/servers/fastapi/pyproject.toml index 5490bdf288..dc084c8e55 100644 --- a/e2e/servers/fastapi/pyproject.toml +++ b/e2e/servers/fastapi/pyproject.toml @@ -6,7 +6,7 @@ requires-python = ">=3.10" dependencies = [ "uvicorn>=0.24.0", "python-dotenv>=1.0.0", - "x402[evm,svm,fastapi,extensions]" + "x402[evm,svm,tvm,fastapi,extensions]" ] [build-system] @@ -20,6 +20,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/e2e/servers/fastapi/test.config.json b/e2e/servers/fastapi/test.config.json index 98be7db4af..53284e95b7 100644 --- a/e2e/servers/fastapi/test.config.json +++ b/e2e/servers/fastapi/test.config.json @@ -8,7 +8,16 @@ "eip2612GasSponsoring", "erc20ApprovalGasSponsoring" ], - "evm": { "transferMethods": ["eip3009", "permit2"] }, + "schemes": [ + "exact", + "upto" + ], + "evm": { + "assetTransferMethods": [ + "eip3009", + "permit2" + ] + }, "description": "Python FastAPI server with x402 v2 payment middleware", "endpoints": [ { @@ -17,7 +26,8 @@ "description": "Protected endpoint requiring EIP-3009 payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" }, { "path": "/exact/svm", @@ -26,15 +36,27 @@ "requiresPayment": true, "protocolFamily": "svm" }, + { + "path": "/exact/tvm", + "method": "GET", + "description": "Protected endpoint requiring TVM payment", + "requiresPayment": true, + "protocolFamily": "tvm" + }, { "path": "/exact/evm/permit2-eip2612GasSponsoring", "method": "GET", "description": "Protected endpoint requiring Permit2 payment with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "extensions": ["eip2612GasSponsoring"], - "coldstart": true + "extensions": [ + "eip2612GasSponsoring" + ], + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2-erc20ApprovalGasSponsoring", @@ -42,9 +64,53 @@ "description": "Protected endpoint requiring Permit2 payment with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } + }, + { + "path": "/upto/evm/permit2", + "method": "GET", + "description": "Protected endpoint requiring upto Permit2 payment (partial settlement)", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } + }, + { + "path": "/upto/evm/permit2-eip2612GasSponsoring", + "method": "GET", + "description": "Protected endpoint requiring upto Permit2 payment with EIP-2612 gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } + }, + { + "path": "/upto/evm/permit2-erc20ApprovalGasSponsoring", + "method": "GET", + "description": "Protected endpoint requiring upto Permit2 payment with ERC-20 approval gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/health", @@ -60,14 +126,15 @@ } ], "environment": { - "required": [ - "EVM_PAYEE_ADDRESS", - "SVM_PAYEE_ADDRESS" - ], + "required": [], "optional": [ + "EVM_PAYEE_ADDRESS", + "SVM_PAYEE_ADDRESS", + "TVM_PAYEE_ADDRESS", "PORT", "FACILITATOR_URL", - "EVM_PERMIT2_ASSET" + "EVM_PERMIT2_ASSET", + "TVM_NETWORK" ] } } diff --git a/e2e/servers/fastapi/uv.lock b/e2e/servers/fastapi/uv.lock index d3fe5a45b0..2ee40f391e 100644 --- a/e2e/servers/fastapi/uv.lock +++ b/e2e/servers/fastapi/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" [[package]] @@ -289,6 +289,88 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.4" @@ -1657,6 +1739,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + [[package]] name = "pycryptodome" version = "3.23.0" @@ -1692,6 +1783,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, ] +[[package]] +name = "pycryptodomex" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -1866,6 +1992,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -1884,6 +2045,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/aa/76/03af049af4dcee5d27442f71b6924f01f3efb5d2bd34f23fcd563f2cc5f5/python_multipart-0.0.21-py3-none-any.whl", hash = "sha256:cf7a6713e01c87aa35387f4774e812c4361150938d20d232800f75ffcf266090", size = 24541, upload-time = "2025-12-17T09:24:21.153Z" }, ] +[[package]] +name = "pytoniq" +version = "0.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytoniq-core" }, + { name = "requests" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/b2/9991a953e4b766918a142fe111f71f12803c6acf65eb30f36eb85ed08f31/pytoniq-0.1.43.tar.gz", hash = "sha256:b4b1c8fed2f9d2f1b6f0ab4b3f1fc5503a0088630d8081f817807ff31e608606", size = 50463, upload-time = "2025-11-30T12:30:41.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/c1/b6e5c739839e0e12bde4563438acd55d39552ea63f6de123724b4b91ac64/pytoniq-0.1.43-py3-none-any.whl", hash = "sha256:922c1721124bf7214e0b7044fba2a439e006367778611c0ce813cbe5b00079d3", size = 56118, upload-time = "2025-11-30T12:30:39.65Z" }, +] + +[[package]] +name = "pytoniq-core" +version = "0.1.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "x25519" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/2c/7afbb9003a3aa72ccfe69711433fe36d2493db2c4acf66dde32f7b55799b/pytoniq_core-0.1.46.tar.gz", hash = "sha256:c8e3cf9ccb1852780a725cd51ba7a66a28122eb39c8b9bb97dcdc5bd02c24734", size = 101236, upload-time = "2025-11-28T10:23:21.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/0e/e27cf7ce1bebb47fb95e1d6deae5c91c6ffcb7851f156990e57079cbe8db/pytoniq_core-0.1.46-py3-none-any.whl", hash = "sha256:0a284c8b68f9fed9d54e4dad871238d844339183bf985a614796360e36e1b95e", size = 91400, upload-time = "2025-11-28T10:23:20.95Z" }, +] + [[package]] name = "pyunormalize" version = "17.0.0" @@ -2410,6 +2602,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/43/1c586f9f413765201234541857cb82fda076f4b0f7bad4a0ec248da39cf3/sentry_sdk-2.49.0-py2.py3-none-any.whl", hash = "sha256:6ea78499133874445a20fe9c826c9e960070abeb7ae0cdf930314ab16bb97aa0", size = 415693, upload-time = "2026-01-08T09:56:21.872Z" }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + [[package]] name = "shellingham" version = "1.5.4" @@ -2839,9 +3040,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] +[[package]] +name = "x25519" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/b6/fca895aff0800cdf941f856df0685a5513094163664b904576e3e3ef1460/x25519-0.0.2.tar.gz", hash = "sha256:ed91d0aba7f4f4959ed8b37118c11d94f56d36c38bb6f2e6c20d0438d75b1556", size = 4833, upload-time = "2021-10-24T15:18:38.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d1/66c637eb8e7a9601675bf7f04bb9a3015358a0f49e4c31d29a2b9a9d72d9/x25519-0.0.2-py3-none-any.whl", hash = "sha256:5c0833260a548bea9137a5a1b5c30334b751a59d148a62832df0c9e7b919ce99", size = 4907, upload-time = "2021-10-24T15:18:36.727Z" }, +] + [[package]] name = "x402" -version = "2.5.0" +version = "2.6.0" source = { editable = "../../../python/x402" } dependencies = [ { name = "nest-asyncio" }, @@ -2868,6 +3078,12 @@ svm = [ { name = "solana" }, { name = "solders" }, ] +tvm = [ + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, +] [package.metadata] requires-dist = [ @@ -2878,22 +3094,26 @@ requires-dist = [ { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.115.0" }, { name = "flask", marker = "extra == 'flask'", specifier = ">=3.0.0" }, { name = "httpx", marker = "extra == 'httpx'", specifier = ">=0.28.1" }, + { name = "httpx", marker = "extra == 'tvm'", specifier = ">=0.28.1" }, { name = "jsonschema", marker = "extra == 'extensions'", specifier = ">=4.0.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pynacl", marker = "extra == 'tvm'", specifier = ">=1.5.0" }, + { name = "pytoniq", marker = "extra == 'tvm'", specifier = ">=0.1.39" }, + { name = "pytoniq-core", marker = "extra == 'tvm'", specifier = ">=0.1.36" }, { name = "requests", marker = "extra == 'requests'", specifier = ">=2.31.0" }, { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0" }, { name = "solders", marker = "extra == 'svm'", specifier = ">=0.27.0" }, { name = "starlette", marker = "extra == 'fastapi'", specifier = ">=0.27.0" }, { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "web3", marker = "extra == 'evm'", specifier = ">=7.0.0" }, - { name = "x402", extras = ["evm", "svm"], marker = "extra == 'mechanisms'" }, + { name = "x402", extras = ["evm", "svm", "tvm"], marker = "extra == 'mechanisms'" }, { name = "x402", extras = ["flask", "fastapi"], marker = "extra == 'servers'" }, { name = "x402", extras = ["httpx", "requests"], marker = "extra == 'clients'" }, - { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions"], marker = "extra == 'all'" }, + { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions"], marker = "extra == 'all'" }, ] -provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] +provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] [package.metadata.requires-dev] dev = [ @@ -2909,8 +3129,11 @@ dev = [ { name = "mcp", specifier = ">=1.26.0" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, + { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytest", specifier = ">=7.0.0" }, { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytoniq", specifier = ">=0.1.39" }, + { name = "pytoniq-core", specifier = ">=0.1.36" }, { name = "requests", specifier = ">=2.31.0" }, { name = "ruff", specifier = ">=0.1.0" }, { name = "solana", specifier = ">=0.36.0" }, @@ -2927,14 +3150,14 @@ source = { virtual = "." } dependencies = [ { name = "python-dotenv" }, { name = "uvicorn" }, - { name = "x402", extra = ["evm", "extensions", "fastapi", "svm"] }, + { name = "x402", extra = ["evm", "extensions", "fastapi", "svm", "tvm"] }, ] [package.metadata] requires-dist = [ { name = "python-dotenv", specifier = ">=1.0.0" }, { name = "uvicorn", specifier = ">=0.24.0" }, - { name = "x402", extras = ["evm", "svm", "fastapi", "extensions"], editable = "../../../python/x402" }, + { name = "x402", extras = ["evm", "svm", "tvm", "fastapi", "extensions"], editable = "../../../python/x402" }, ] [[package]] diff --git a/e2e/servers/fastify/index.ts b/e2e/servers/fastify/index.ts index 4ba0718ed2..0b9863a9c7 100644 --- a/e2e/servers/fastify/index.ts +++ b/e2e/servers/fastify/index.ts @@ -3,15 +3,19 @@ import { paymentMiddleware, setSettlementOverrides } from "@x402/fastify"; import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server"; import { ExactEvmScheme } from "@x402/evm/exact/server"; import { UptoEvmScheme } from "@x402/evm/upto/server"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/server"; import { ExactSvmScheme } from "@x402/svm/exact/server"; import { ExactAptosScheme } from "@x402/aptos/exact/server"; +import { ExactHederaScheme } from "@x402/hedera/exact/server"; import { ExactStellarScheme } from "@x402/stellar/exact/server"; +import { ExactAvmScheme } from "@x402/avm/exact/server"; import { bazaarResourceServerExtension, declareDiscoveryExtension } from "@x402/extensions/bazaar"; import { declareEip2612GasSponsoringExtension, declareErc20ApprovalGasSponsoringExtension, } from "@x402/extensions"; import dotenv from "dotenv"; +import { privateKeyToAccount } from "viem/accounts"; dotenv.config(); @@ -27,12 +31,18 @@ const EVM_NETWORK = (process.env.EVM_NETWORK || "eip155:84532") as `${string}:${ const SVM_NETWORK = (process.env.SVM_NETWORK || "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1") as `${string}:${string}`; const APTOS_NETWORK = (process.env.APTOS_NETWORK || "aptos:2") as `${string}:${string}`; +const HEDERA_NETWORK = (process.env.HEDERA_NETWORK || "hedera:testnet") as `${string}:${string}`; +const AVM_NETWORK = (process.env.AVM_NETWORK || "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=") as `${string}:${string}`; const STELLAR_NETWORK = (process.env.STELLAR_NETWORK || "stellar:testnet") as `${string}:${string}`; const EVM_PAYEE_ADDRESS = process.env.EVM_PAYEE_ADDRESS as `0x${string}`; const SVM_PAYEE_ADDRESS = process.env.SVM_PAYEE_ADDRESS as string; const EVM_PERMIT2_ASSET = process.env.EVM_PERMIT2_ASSET as `0x${string}`; +const AVM_PAYEE_ADDRESS = process.env.AVM_PAYEE_ADDRESS as string; const APTOS_PAYEE_ADDRESS = process.env.APTOS_PAYEE_ADDRESS as string; +const HEDERA_PAYEE_ADDRESS = process.env.HEDERA_PAYEE_ADDRESS as string | undefined; const STELLAR_PAYEE_ADDRESS = process.env.STELLAR_PAYEE_ADDRESS as string | undefined; +const HEDERA_ASSET = process.env.HEDERA_ASSET ?? "0.0.0"; // 0.0.0 = HBAR or 0.0.429274 for USDC testnet +const HEDERA_AMOUNT = process.env.HEDERA_AMOUNT ?? "100000"; // price in smallest units (tinybars or token decimals), defaults to 0.001 HBAR or 0.1 USDC const facilitatorUrl = process.env.FACILITATOR_URL; if (!EVM_PAYEE_ADDRESS) { @@ -60,12 +70,33 @@ const facilitatorClient = new HTTPFacilitatorClient({ url: facilitatorUrl }); const server = new x402ResourceServer(facilitatorClient); // Register server schemes +if (AVM_PAYEE_ADDRESS) { + server.register("algorand:*", new ExactAvmScheme()); +} server.register("eip155:*", new ExactEvmScheme()); server.register("eip155:*", new UptoEvmScheme()); + +// Register batch-settlement scheme for the EVM payee. +// e2e flow does NOT use ChannelManager — settle actions are handled inline. +const receiverAuthorizerPrivateKey = process.env.EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY as + | `0x${string}` + | undefined; +const receiverAuthorizerSigner = receiverAuthorizerPrivateKey + ? privateKeyToAccount(receiverAuthorizerPrivateKey) + : undefined; +server.register( + "eip155:*", + new BatchSettlementEvmScheme(EVM_PAYEE_ADDRESS, { + ...(receiverAuthorizerSigner ? { receiverAuthorizerSigner } : {}), + }), +); server.register("solana:*", new ExactSvmScheme()); if (APTOS_PAYEE_ADDRESS) { server.register("aptos:*", new ExactAptosScheme()); } +if (HEDERA_PAYEE_ADDRESS) { + server.register("hedera:*", new ExactHederaScheme()); +} if (STELLAR_PAYEE_ADDRESS) { server.register("stellar:*", new ExactStellarScheme()); } @@ -84,12 +115,24 @@ console.log(`Using remote facilitator at: ${facilitatorUrl}`); */ app.addHook("onRequest", async (request, reply) => { const path = request.url.split("?")[0]; + if (path === "/exact/avm" && !AVM_PAYEE_ADDRESS) { + return reply.status(501).send({ + error: "AVM payments not configured", + message: "AVM_PAYEE_ADDRESS environment variable is not set", + }); + } if (path === "/exact/aptos" && !APTOS_PAYEE_ADDRESS) { return reply.status(501).send({ error: "Aptos payments not configured", message: "APTOS_PAYEE_ADDRESS environment variable is not set", }); } + if (path === "/exact/hedera" && !HEDERA_PAYEE_ADDRESS) { + return reply.status(501).send({ + error: "Hedera payments not configured", + message: "HEDERA_PAYEE_ADDRESS environment variable is not set", + }); + } if (path.startsWith("/exact/stellar") && !STELLAR_PAYEE_ADDRESS) { return reply.status(501).send({ error: "Stellar payments not configured", @@ -108,6 +151,88 @@ paymentMiddleware( app, { // Route-specific payment configuration + ...(AVM_PAYEE_ADDRESS + ? { + "GET /exact/avm": { + accepts: { + payTo: AVM_PAYEE_ADDRESS, + scheme: "exact", + price: "$0.001", + network: AVM_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected endpoint accessed successfully", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, + }, + required: ["message", "timestamp"], + }, + }, + }), + }, + }, + } + : {}), + "GET /batch-settlement/evm/eip3009": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + price: "$0.001", + network: EVM_NETWORK, + }, + }, + "GET /batch-settlement/evm/permit2": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: { + amount: "1000", + asset: EVM_PERMIT2_ASSET, + extra: { + assetTransferMethod: "permit2", + name: EVM_NETWORK == "eip155:84532" ? "USDC" : "USD Coin", + version: "2", + }, + }, + }, + }, + "GET /batch-settlement/evm/permit2-eip2612GasSponsoring": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: "$0.001", + extra: { assetTransferMethod: "permit2" }, + }, + extensions: { + ...declareEip2612GasSponsoringExtension(), + }, + }, + "GET /batch-settlement/evm/permit2-erc20ApprovalGasSponsoring": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: { + amount: "1000", + asset: EVM_PERMIT2_ASSET, + extra: { + assetTransferMethod: "permit2", + }, + }, + }, + extensions: { + ...declareErc20ApprovalGasSponsoringExtension(), + }, + }, "GET /exact/evm/eip3009": { accepts: { payTo: EVM_PAYEE_ADDRESS, @@ -158,20 +283,23 @@ paymentMiddleware( }), }, }, - ...(APTOS_PAYEE_ADDRESS + ...(HEDERA_PAYEE_ADDRESS ? { - "GET /exact/aptos": { + "GET /exact/hedera": { accepts: { - payTo: APTOS_PAYEE_ADDRESS, - scheme: "exact", - price: "$0.001", - network: APTOS_NETWORK, + payTo: HEDERA_PAYEE_ADDRESS, + scheme: "exact" as const, + price: { + amount: HEDERA_AMOUNT, + asset: HEDERA_ASSET, + }, + network: HEDERA_NETWORK, }, extensions: { ...declareDiscoveryExtension({ output: { example: { - message: "Protected endpoint accessed successfully", + message: "Protected Hedera endpoint accessed successfully", timestamp: "2024-01-01T00:00:00Z", }, schema: { @@ -187,6 +315,35 @@ paymentMiddleware( }, } : {}), + ...(APTOS_PAYEE_ADDRESS + ? { + "GET /exact/aptos": { + accepts: { + payTo: APTOS_PAYEE_ADDRESS, + scheme: "exact", + price: "$0.001", + network: APTOS_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected endpoint accessed successfully", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, + }, + required: ["message", "timestamp"], + }, + }, + }), + }, + }, + } + : {}), // Permit2 standard/direct endpoint - no gas sponsoring, client must pre-approve Permit2 "GET /exact/evm/permit2": { accepts: { @@ -328,37 +485,72 @@ paymentMiddleware( }, ...(STELLAR_PAYEE_ADDRESS ? { - "GET /exact/stellar": { - accepts: { - payTo: STELLAR_PAYEE_ADDRESS!, - scheme: "exact", - price: "$0.001", - network: STELLAR_NETWORK, - }, - extensions: { - ...declareDiscoveryExtension({ - output: { - example: { - message: "Protected Stellar endpoint accessed successfully", - timestamp: "2024-01-01T00:00:00Z", - }, - schema: { - properties: { - message: { type: "string" }, - timestamp: { type: "string" }, - }, - required: ["message", "timestamp"], + "GET /exact/stellar": { + accepts: { + payTo: STELLAR_PAYEE_ADDRESS!, + scheme: "exact", + price: "$0.001", + network: STELLAR_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected Stellar endpoint accessed successfully", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, }, + required: ["message", "timestamp"], }, - }), - }, + }, + }), }, - } + }, + } : {}), }, server, // Pass pre-configured server instance ); +/** + * Protected batch-settlement endpoint — exercised by repeated voucher requests + * over a single payment channel followed by an optional cooperative refund. + */ +app.get("/batch-settlement/evm/eip3009", async () => { + return { + message: "Batch-settlement endpoint accessed successfully", + timestamp: new Date().toISOString(), + }; +}); + +app.get("/batch-settlement/evm/permit2", async () => { + return { + message: "Batch-settlement Permit2 endpoint accessed successfully", + timestamp: new Date().toISOString(), + method: "batch-settlement-permit2", + }; +}); + +app.get("/batch-settlement/evm/permit2-eip2612GasSponsoring", async () => { + return { + message: "Batch-settlement Permit2 EIP-2612 endpoint accessed successfully", + timestamp: new Date().toISOString(), + method: "batch-settlement-permit2-eip2612", + }; +}); + +app.get("/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", async () => { + return { + message: "Batch-settlement Permit2 ERC-20 approval endpoint accessed successfully", + timestamp: new Date().toISOString(), + method: "batch-settlement-permit2-erc20-approval", + }; +}); + /** * Protected endpoint - requires payment to access * @@ -385,6 +577,20 @@ app.get("/exact/svm", async () => { }; }); +/** + * Protected AVM endpoint - requires payment to access + * + * This endpoint demonstrates a resource protected by x402 payment middleware for AVM. + * Clients must provide a valid payment signature to access this endpoint. + * Note: 501 check is handled by pre-middleware guard above. + */ +app.get("/exact/avm", async () => { + return { + message: "Protected endpoint accessed successfully", + timestamp: new Date().toISOString(), + }; +}); + /** * Protected Aptos endpoint - requires payment to access * @@ -479,6 +685,15 @@ app.get("/upto/evm/permit2-erc20ApprovalGasSponsoring", async (_request, reply) * Clients must provide a valid payment signature to access this endpoint. * Note: 501 check is handled by pre-middleware guard above. */ +if (HEDERA_PAYEE_ADDRESS) { + app.get("/exact/hedera", async () => { + return { + message: "Protected Hedera endpoint accessed successfully", + timestamp: new Date().toISOString(), + }; + }); +} + if (STELLAR_PAYEE_ADDRESS) { app.get("/exact/stellar", async () => { return { @@ -528,22 +743,28 @@ app.listen({ port: parseInt(PORT) }, (err, address) => { ║ x402 Fastify E2E Test Server ║ ╠════════════════════════════════════════════════════════╣ ║ Server: ${address} ║ +║ AVM Network: ${AVM_NETWORK} ║ ║ EVM Network: ${EVM_NETWORK} ║ ║ SVM Network: ${SVM_NETWORK} ║ ║ Aptos Network: ${APTOS_NETWORK} ║ +║ Hedera Network: ${HEDERA_NETWORK} ║ ║ Stellar Network: ${STELLAR_NETWORK}║ +║ AVM Payee: ${AVM_PAYEE_ADDRESS || "(not configured)"} ║ EVM Payee: ${EVM_PAYEE_ADDRESS} ║ ║ SVM Payee: ${SVM_PAYEE_ADDRESS} ║ ║ Aptos Payee: ${APTOS_PAYEE_ADDRESS || "(not configured)"} +║ Hedera Payee: ${HEDERA_PAYEE_ADDRESS || "(not configured)"} ║ Stellar Payee: ${STELLAR_PAYEE_ADDRESS || "(not configured)"} ║ ║ ║ Endpoints: ║ +║ • GET /exact/avm (AVM) ║ ║ • GET /exact/evm/eip3009 (EVM EIP-3009) ║ ║ • GET /exact/evm/permit2 (Permit2) ║ ║ • GET /exact/evm/permit2-eip2612GasSponsoring ║ ║ • GET /exact/evm/permit2-erc20ApprovalGasSponsoring ║ ║ • GET /exact/svm (SVM) ║ ║ • GET /exact/aptos (Aptos) ║ +║ • GET /exact/hedera (Hedera) ║ ║ • GET /exact/stellar (Stellar) ║ ║ • GET /health (no payment required) ║ ║ • POST /close (shutdown server) ║ diff --git a/e2e/servers/fastify/package.json b/e2e/servers/fastify/package.json index 690c1727e1..102b0e0f53 100644 --- a/e2e/servers/fastify/package.json +++ b/e2e/servers/fastify/package.json @@ -11,10 +11,12 @@ }, "dependencies": { "@x402/aptos": "workspace:*", + "@x402/avm": "workspace:*", "@x402/core": "workspace:*", "@x402/fastify": "workspace:*", "@x402/evm": "workspace:*", "@x402/extensions": "workspace:*", + "@x402/hedera": "workspace:*", "@x402/stellar": "workspace:*", "@x402/svm": "workspace:*", "dotenv": "^16.6.1", @@ -22,6 +24,7 @@ }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -29,8 +32,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/e2e/servers/fastify/test.config.json b/e2e/servers/fastify/test.config.json index 5575e3681b..3473e02ed7 100644 --- a/e2e/servers/fastify/test.config.json +++ b/e2e/servers/fastify/test.config.json @@ -3,16 +3,75 @@ "type": "server", "language": "typescript", "x402Version": 2, - "extensions": ["bazaar", "eip2612GasSponsoring", "erc20ApprovalGasSponsoring"], - + "extensions": [ + "bazaar", + "eip2612GasSponsoring", + "erc20ApprovalGasSponsoring" + ], "endpoints": [ + { + "path": "/exact/avm", + "method": "GET", + "description": "Protected endpoint requiring payment on AVM network", + "requiresPayment": true, + "protocolFamily": "avm" + }, { "path": "/exact/evm/eip3009", "method": "GET", "description": "Protected endpoint requiring EIP-3009 payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" + }, + { + "path": "/batch-settlement/evm/eip3009", + "method": "GET", + "description": "Protected endpoint exercised by deposit + voucher + recovery voucher + cooperative refund", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "eip3009" + }, + { + "path": "/batch-settlement/evm/permit2", + "method": "GET", + "description": "Batch-settlement Permit2 direct endpoint (pre-approved Permit2)", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } + }, + { + "path": "/batch-settlement/evm/permit2-eip2612GasSponsoring", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with EIP-2612 gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } + }, + { + "path": "/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with ERC-20 approval gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2", @@ -20,8 +79,11 @@ "description": "Protected endpoint requiring Permit2 payment (standard settle, no gas sponsoring)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "permit2Direct": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/exact/evm/permit2-eip2612GasSponsoring", @@ -29,8 +91,11 @@ "description": "Protected endpoint requiring Permit2 payment with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "coldstart": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2-erc20ApprovalGasSponsoring", @@ -38,9 +103,14 @@ "description": "Protected endpoint requiring Permit2 payment with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/upto/evm/permit2", @@ -48,8 +118,11 @@ "description": "Protected endpoint requiring upto Permit2 payment (direct, client must pre-approve)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "permit2Direct": true + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/upto/evm/permit2-eip2612GasSponsoring", @@ -57,7 +130,11 @@ "description": "Protected endpoint requiring upto Permit2 payment with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto" + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/upto/evm/permit2-erc20ApprovalGasSponsoring", @@ -65,8 +142,14 @@ "description": "Protected endpoint requiring upto Permit2 payment with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "extensions": ["erc20ApprovalGasSponsoring"] + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/svm", @@ -82,6 +165,13 @@ "requiresPayment": true, "protocolFamily": "aptos" }, + { + "path": "/exact/hedera", + "method": "GET", + "description": "Protected endpoint requiring payment on Hedera network", + "requiresPayment": true, + "protocolFamily": "hedera" + }, { "path": "/exact/stellar", "method": "GET", @@ -103,7 +193,18 @@ } ], "environment": { - "required": ["PORT", "EVM_PAYEE_ADDRESS", "SVM_PAYEE_ADDRESS", "FACILITATOR_URL"], - "optional": ["APTOS_PAYEE_ADDRESS", "STELLAR_PAYEE_ADDRESS"] + "required": [ + "PORT", + "EVM_PAYEE_ADDRESS", + "SVM_PAYEE_ADDRESS", + "FACILITATOR_URL" + ], + "optional": [ + "AVM_PAYEE_ADDRESS", + "APTOS_PAYEE_ADDRESS", + "HEDERA_PAYEE_ADDRESS", + "STELLAR_PAYEE_ADDRESS", + "EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY" + ] } } diff --git a/e2e/servers/flask/main.py b/e2e/servers/flask/main.py index 6657dbe4ab..65c922343e 100644 --- a/e2e/servers/flask/main.py +++ b/e2e/servers/flask/main.py @@ -11,15 +11,20 @@ # Import from new x402 package (sync variants for Flask) from x402 import x402ResourceServerSync from x402.http import FacilitatorConfig, HTTPFacilitatorClientSync -from x402.http.middleware.flask import PaymentMiddleware +from x402.http.middleware.flask import PaymentMiddleware, set_settlement_overrides from x402.mechanisms.evm.exact import register_exact_evm_server +from x402.mechanisms.evm.upto import UptoEvmServerScheme from x402.mechanisms.svm.exact import register_exact_svm_server +from x402.mechanisms.tvm import TVM_TESTNET +from x402.mechanisms.tvm.exact import ExactTvmServerScheme from x402.extensions.bazaar import ( bazaar_resource_server_extension, declare_discovery_extension, OutputConfig, ) -from x402.extensions.eip2612_gas_sponsoring import declare_eip2612_gas_sponsoring_extension +from x402.extensions.eip2612_gas_sponsoring import ( + declare_eip2612_gas_sponsoring_extension, +) from x402.extensions.erc20_approval_gas_sponsoring import ( declare_erc20_approval_gas_sponsoring_extension, ) @@ -34,18 +39,18 @@ # Get configuration from environment EVM_ADDRESS = os.getenv("EVM_PAYEE_ADDRESS") SVM_ADDRESS = os.getenv("SVM_PAYEE_ADDRESS") +TVM_ADDRESS = os.getenv("TVM_PAYEE_ADDRESS") PORT = int(os.getenv("PORT", "4021")) FACILITATOR_URL = os.getenv("FACILITATOR_URL") EVM_PERMIT2_ASSET = os.getenv( "EVM_PERMIT2_ASSET", "0x036CbD53842c5426634e7929541eC2318f3dCF7e" ) +TVM_NETWORK = os.getenv("TVM_NETWORK", TVM_TESTNET) -if not EVM_ADDRESS: - print("Error: Missing required environment variable EVM_PAYEE_ADDRESS") - sys.exit(1) - -if not SVM_ADDRESS: - print("Error: Missing required environment variable SVM_PAYEE_ADDRESS") +if not any([EVM_ADDRESS, SVM_ADDRESS, TVM_ADDRESS]): + print( + "Error: At least one of EVM_PAYEE_ADDRESS, SVM_PAYEE_ADDRESS, or TVM_PAYEE_ADDRESS is required" + ) sys.exit(1) # Network configurations (CAIP-2 format) @@ -68,7 +73,9 @@ # Register EVM and SVM exact schemes register_exact_evm_server(server, EVM_NETWORK) +server.register(EVM_NETWORK, UptoEvmServerScheme()) register_exact_svm_server(server, SVM_NETWORK) +server.register(TVM_NETWORK, ExactTvmServerScheme()) # Register Bazaar discovery extension server.register_extension(bazaar_resource_server_extension) @@ -127,6 +134,31 @@ ), }, }, + "GET /exact/tvm": { + "accepts": { + "scheme": "exact", + "payTo": TVM_ADDRESS, + "price": "$0.001", + "network": TVM_NETWORK, + }, + "extensions": { + **declare_discovery_extension( + output=OutputConfig( + example={ + "message": "Access granted to TVM protected resource", + "timestamp": "2024-01-01T00:00:00Z", + }, + schema={ + "properties": { + "message": {"type": "string"}, + "timestamp": {"type": "string"}, + }, + "required": ["message", "timestamp"], + }, + ) + ), + }, + }, "GET /exact/evm/permit2-eip2612GasSponsoring": { "accepts": { "scheme": "exact", @@ -178,6 +210,83 @@ **declare_erc20_approval_gas_sponsoring_extension(), }, }, + "GET /upto/evm/permit2": { + "accepts": { + "scheme": "upto", + "payTo": EVM_ADDRESS, + "network": EVM_NETWORK, + "price": { + "amount": "2000", + "asset": EVM_PERMIT2_ASSET, + "extra": { + "assetTransferMethod": "permit2", + "name": "USDC", + "version": "2", + }, + }, + }, + "extensions": { + **declare_discovery_extension( + output=OutputConfig( + example={ + "message": "Upto endpoint accessed successfully", + "timestamp": "2024-01-01T00:00:00Z", + "method": "upto-permit2", + }, + schema={ + "properties": { + "message": {"type": "string"}, + "timestamp": {"type": "string"}, + "method": {"type": "string"}, + }, + "required": ["message", "timestamp"], + }, + ) + ), + }, + }, + "GET /upto/evm/permit2-eip2612GasSponsoring": { + "accepts": { + "scheme": "upto", + "payTo": EVM_ADDRESS, + "network": EVM_NETWORK, + "price": { + "amount": "2000", + "asset": EVM_PERMIT2_ASSET, + "extra": { + "assetTransferMethod": "permit2", + "name": "USDC", + "version": "2", + }, + }, + }, + "extensions": { + **declare_eip2612_gas_sponsoring_extension(), + }, + }, + "GET /upto/evm/permit2-erc20ApprovalGasSponsoring": { + "accepts": { + "scheme": "upto", + "payTo": EVM_ADDRESS, + "network": EVM_NETWORK, + "price": { + "amount": "2000", + "asset": EVM_PERMIT2_ASSET, + "extra": { + "assetTransferMethod": "permit2", + }, + }, + }, + "extensions": { + **declare_erc20_approval_gas_sponsoring_extension(), + }, + }, +} + +routes = { + route: requirements + for route, requirements in routes.items() + if requirements["accepts"].get("payTo") } # Apply payment middleware @@ -216,6 +325,20 @@ def protected_svm_endpoint(): ) +@app.route("/exact/tvm") +def protected_tvm_endpoint(): + """Protected endpoint that requires TVM payment.""" + if shutdown_requested: + return jsonify({"error": "Server shutting down"}), 503 + + return jsonify( + { + "message": "Access granted to TVM protected resource", + "timestamp": "2024-01-01T00:00:00Z", + } + ) + + @app.route("/exact/evm/permit2-eip2612GasSponsoring") def protected_permit2_endpoint(): """Protected endpoint that requires Permit2 payment.""" @@ -244,6 +367,54 @@ def protected_permit2_erc20_endpoint(): ) +@app.route("/upto/evm/permit2") +def protected_upto_permit2_endpoint(): + """Protected endpoint that requires upto Permit2 payment.""" + if shutdown_requested: + return jsonify({"error": "Server shutting down"}), 503 + resp = jsonify( + { + "message": "Upto endpoint accessed successfully", + "timestamp": "2024-01-01T00:00:00Z", + "method": "upto-permit2", + } + ) + set_settlement_overrides(resp, {"amount": "1000"}) + return resp + + +@app.route("/upto/evm/permit2-eip2612GasSponsoring") +def protected_upto_permit2_eip2612_endpoint(): + """Protected endpoint that requires upto Permit2 payment with EIP-2612 gas sponsoring.""" + if shutdown_requested: + return jsonify({"error": "Server shutting down"}), 503 + resp = jsonify( + { + "message": "Upto Permit2 EIP-2612 endpoint accessed successfully", + "timestamp": "2024-01-01T00:00:00Z", + "method": "upto-permit2-eip2612", + } + ) + set_settlement_overrides(resp, {"amount": "1000"}) + return resp + + +@app.route("/upto/evm/permit2-erc20ApprovalGasSponsoring") +def protected_upto_permit2_erc20_endpoint(): + """Protected endpoint that requires upto Permit2 payment with ERC-20 approval gas sponsoring.""" + if shutdown_requested: + return jsonify({"error": "Server shutting down"}), 503 + resp = jsonify( + { + "message": "Upto Permit2 ERC-20 approval endpoint accessed successfully", + "timestamp": "2024-01-01T00:00:00Z", + "method": "upto-permit2-erc20-approval", + } + ) + set_settlement_overrides(resp, {"amount": "1000"}) + return resp + + @app.route("/health") def health_check(): """Health check endpoint.""" diff --git a/e2e/servers/flask/pyproject.toml b/e2e/servers/flask/pyproject.toml index 4d6228e66f..4605fe5e55 100644 --- a/e2e/servers/flask/pyproject.toml +++ b/e2e/servers/flask/pyproject.toml @@ -5,7 +5,7 @@ description = "Python Flask server for x402 e2e tests" requires-python = ">=3.10" dependencies = [ "python-dotenv>=1.0.0", - "x402[flask,evm,svm,extensions]" + "x402[flask,evm,svm,tvm,extensions]" ] [build-system] @@ -19,6 +19,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/e2e/servers/flask/test.config.json b/e2e/servers/flask/test.config.json index 3ba02fea37..a1b661169c 100644 --- a/e2e/servers/flask/test.config.json +++ b/e2e/servers/flask/test.config.json @@ -8,7 +8,16 @@ "eip2612GasSponsoring", "erc20ApprovalGasSponsoring" ], - "evm": { "transferMethods": ["eip3009", "permit2"] }, + "schemes": [ + "exact", + "upto" + ], + "evm": { + "assetTransferMethods": [ + "eip3009", + "permit2" + ] + }, "description": "Python Flask server with x402 v2 payment middleware", "endpoints": [ { @@ -17,7 +26,8 @@ "description": "Protected endpoint requiring EIP-3009 payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" }, { "path": "/exact/svm", @@ -26,15 +36,27 @@ "requiresPayment": true, "protocolFamily": "svm" }, + { + "path": "/exact/tvm", + "method": "GET", + "description": "Protected endpoint requiring TVM payment", + "requiresPayment": true, + "protocolFamily": "tvm" + }, { "path": "/exact/evm/permit2-eip2612GasSponsoring", "method": "GET", "description": "Protected endpoint requiring Permit2 payment with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "extensions": ["eip2612GasSponsoring"], - "coldstart": true + "extensions": [ + "eip2612GasSponsoring" + ], + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2-erc20ApprovalGasSponsoring", @@ -42,9 +64,53 @@ "description": "Protected endpoint requiring Permit2 payment with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } + }, + { + "path": "/upto/evm/permit2", + "method": "GET", + "description": "Protected endpoint requiring upto Permit2 payment (partial settlement)", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } + }, + { + "path": "/upto/evm/permit2-eip2612GasSponsoring", + "method": "GET", + "description": "Protected endpoint requiring upto Permit2 payment with EIP-2612 gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } + }, + { + "path": "/upto/evm/permit2-erc20ApprovalGasSponsoring", + "method": "GET", + "description": "Protected endpoint requiring upto Permit2 payment with ERC-20 approval gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/health", @@ -60,14 +126,15 @@ } ], "environment": { - "required": [ - "EVM_PAYEE_ADDRESS", - "SVM_PAYEE_ADDRESS" - ], + "required": [], "optional": [ + "EVM_PAYEE_ADDRESS", + "SVM_PAYEE_ADDRESS", + "TVM_PAYEE_ADDRESS", "PORT", "FACILITATOR_URL", - "EVM_PERMIT2_ASSET" + "EVM_PERMIT2_ASSET", + "TVM_NETWORK" ] } } diff --git a/e2e/servers/flask/uv.lock b/e2e/servers/flask/uv.lock index bec13acc9d..fb2f2f57fe 100644 --- a/e2e/servers/flask/uv.lock +++ b/e2e/servers/flask/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" [[package]] @@ -289,6 +289,88 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.4" @@ -1409,6 +1491,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + [[package]] name = "pycryptodome" version = "3.23.0" @@ -1444,6 +1535,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, ] +[[package]] +name = "pycryptodomex" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -1577,6 +1703,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -1586,6 +1747,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, ] +[[package]] +name = "pytoniq" +version = "0.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytoniq-core" }, + { name = "requests" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/b2/9991a953e4b766918a142fe111f71f12803c6acf65eb30f36eb85ed08f31/pytoniq-0.1.43.tar.gz", hash = "sha256:b4b1c8fed2f9d2f1b6f0ab4b3f1fc5503a0088630d8081f817807ff31e608606", size = 50463, upload-time = "2025-11-30T12:30:41.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/c1/b6e5c739839e0e12bde4563438acd55d39552ea63f6de123724b4b91ac64/pytoniq-0.1.43-py3-none-any.whl", hash = "sha256:922c1721124bf7214e0b7044fba2a439e006367778611c0ce813cbe5b00079d3", size = 56118, upload-time = "2025-11-30T12:30:39.65Z" }, +] + +[[package]] +name = "pytoniq-core" +version = "0.1.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "x25519" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/2c/7afbb9003a3aa72ccfe69711433fe36d2493db2c4acf66dde32f7b55799b/pytoniq_core-0.1.46.tar.gz", hash = "sha256:c8e3cf9ccb1852780a725cd51ba7a66a28122eb39c8b9bb97dcdc5bd02c24734", size = 101236, upload-time = "2025-11-28T10:23:21.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/0e/e27cf7ce1bebb47fb95e1d6deae5c91c6ffcb7851f156990e57079cbe8db/pytoniq_core-0.1.46-py3-none-any.whl", hash = "sha256:0a284c8b68f9fed9d54e4dad871238d844339183bf985a614796360e36e1b95e", size = 91400, upload-time = "2025-11-28T10:23:20.95Z" }, +] + [[package]] name = "pyunormalize" version = "17.0.0" @@ -1887,6 +2079,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + [[package]] name = "solana" version = "0.36.11" @@ -2070,9 +2271,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2f/f9/9e082990c2585c744734f85bec79b5dae5df9c974ffee58fe421652c8e91/werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", size = 224960, upload-time = "2025-11-29T02:15:21.13Z" }, ] +[[package]] +name = "x25519" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/b6/fca895aff0800cdf941f856df0685a5513094163664b904576e3e3ef1460/x25519-0.0.2.tar.gz", hash = "sha256:ed91d0aba7f4f4959ed8b37118c11d94f56d36c38bb6f2e6c20d0438d75b1556", size = 4833, upload-time = "2021-10-24T15:18:38.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d1/66c637eb8e7a9601675bf7f04bb9a3015358a0f49e4c31d29a2b9a9d72d9/x25519-0.0.2-py3-none-any.whl", hash = "sha256:5c0833260a548bea9137a5a1b5c30334b751a59d148a62832df0c9e7b919ce99", size = 4907, upload-time = "2021-10-24T15:18:36.727Z" }, +] + [[package]] name = "x402" -version = "2.5.0" +version = "2.6.0" source = { editable = "../../../python/x402" } dependencies = [ { name = "nest-asyncio" }, @@ -2098,6 +2308,12 @@ svm = [ { name = "solana" }, { name = "solders" }, ] +tvm = [ + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, +] [package.metadata] requires-dist = [ @@ -2108,22 +2324,26 @@ requires-dist = [ { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.115.0" }, { name = "flask", marker = "extra == 'flask'", specifier = ">=3.0.0" }, { name = "httpx", marker = "extra == 'httpx'", specifier = ">=0.28.1" }, + { name = "httpx", marker = "extra == 'tvm'", specifier = ">=0.28.1" }, { name = "jsonschema", marker = "extra == 'extensions'", specifier = ">=4.0.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pynacl", marker = "extra == 'tvm'", specifier = ">=1.5.0" }, + { name = "pytoniq", marker = "extra == 'tvm'", specifier = ">=0.1.39" }, + { name = "pytoniq-core", marker = "extra == 'tvm'", specifier = ">=0.1.36" }, { name = "requests", marker = "extra == 'requests'", specifier = ">=2.31.0" }, { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0" }, { name = "solders", marker = "extra == 'svm'", specifier = ">=0.27.0" }, { name = "starlette", marker = "extra == 'fastapi'", specifier = ">=0.27.0" }, { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "web3", marker = "extra == 'evm'", specifier = ">=7.0.0" }, - { name = "x402", extras = ["evm", "svm"], marker = "extra == 'mechanisms'" }, + { name = "x402", extras = ["evm", "svm", "tvm"], marker = "extra == 'mechanisms'" }, { name = "x402", extras = ["flask", "fastapi"], marker = "extra == 'servers'" }, { name = "x402", extras = ["httpx", "requests"], marker = "extra == 'clients'" }, - { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions"], marker = "extra == 'all'" }, + { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions"], marker = "extra == 'all'" }, ] -provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] +provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] [package.metadata.requires-dev] dev = [ @@ -2139,8 +2359,11 @@ dev = [ { name = "mcp", specifier = ">=1.26.0" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, + { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytest", specifier = ">=7.0.0" }, { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytoniq", specifier = ">=0.1.39" }, + { name = "pytoniq-core", specifier = ">=0.1.36" }, { name = "requests", specifier = ">=2.31.0" }, { name = "ruff", specifier = ">=0.1.0" }, { name = "solana", specifier = ">=0.36.0" }, @@ -2156,13 +2379,13 @@ version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "python-dotenv" }, - { name = "x402", extra = ["evm", "extensions", "flask", "svm"] }, + { name = "x402", extra = ["evm", "extensions", "flask", "svm", "tvm"] }, ] [package.metadata] requires-dist = [ { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "x402", extras = ["flask", "evm", "svm", "extensions"], editable = "../../../python/x402" }, + { name = "x402", extras = ["flask", "evm", "svm", "tvm", "extensions"], editable = "../../../python/x402" }, ] [[package]] diff --git a/e2e/servers/gin/README.md b/e2e/servers/gin/README.md index efdacab907..643d5e2fe7 100644 --- a/e2e/servers/gin/README.md +++ b/e2e/servers/gin/README.md @@ -23,12 +23,12 @@ This server demonstrates and tests the x402 Gin middleware with both EVM and SVM ```go import ( ginfw "github.com/gin-gonic/gin" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" - "github.com/coinbase/x402/go/extensions/bazaar" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" + "github.com/x402-foundation/x402/go/extensions/bazaar" ) // Create Gin router @@ -173,12 +173,12 @@ Content-Type: application/json ## Dependencies -- `github.com/coinbase/x402/go` - Core x402 -- `github.com/coinbase/x402/go/http` - HTTP integration -- `github.com/coinbase/x402/go/http/gin` - Gin middleware -- `github.com/coinbase/x402/go/mechanisms/evm` - EVM server -- `github.com/coinbase/x402/go/mechanisms/svm` - SVM server -- `github.com/coinbase/x402/go/extensions/bazaar` - Discovery extension +- `github.com/x402-foundation/x402/go` - Core x402 +- `github.com/x402-foundation/x402/go/http` - HTTP integration +- `github.com/x402-foundation/x402/go/http/gin` - Gin middleware +- `github.com/x402-foundation/x402/go/mechanisms/evm` - EVM server +- `github.com/x402-foundation/x402/go/mechanisms/svm` - SVM server +- `github.com/x402-foundation/x402/go/extensions/bazaar` - Discovery extension - `github.com/gin-gonic/gin` - HTTP framework ## Implementation Highlights diff --git a/e2e/servers/gin/batched_authorizer.go b/e2e/servers/gin/batched_authorizer.go new file mode 100644 index 0000000000..307f3f0bf3 --- /dev/null +++ b/e2e/servers/gin/batched_authorizer.go @@ -0,0 +1,127 @@ +package main + +import ( + "context" + "crypto/ecdsa" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + "github.com/x402-foundation/x402/go/mechanisms/evm" +) + +// batchedAuthorizerSigner implements server.AuthorizerSigner using a local +// ECDSA key. Mirrors the nethttp e2e server's `batched_authorizer.go`. Used +// when the e2e harness opts into self-managed receiver authorization via +// EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY. +type batchedAuthorizerSigner struct { + privateKey *ecdsa.PrivateKey + address common.Address +} + +func newBatchedAuthorizerSigner(privateKeyHex string) (*batchedAuthorizerSigner, error) { + pk, err := crypto.HexToECDSA(strings.TrimPrefix(privateKeyHex, "0x")) + if err != nil { + return nil, fmt.Errorf("parse private key: %w", err) + } + return &batchedAuthorizerSigner{ + privateKey: pk, + address: crypto.PubkeyToAddress(pk.PublicKey), + }, nil +} + +func (s *batchedAuthorizerSigner) Address() string { return s.address.Hex() } + +func (s *batchedAuthorizerSigner) SignTypedData( + _ context.Context, + domain evm.TypedDataDomain, + types map[string][]evm.TypedDataField, + primaryType string, + message map[string]interface{}, +) ([]byte, error) { + td := apitypes.TypedData{ + Types: apitypes.Types{}, + PrimaryType: primaryType, + Domain: apitypes.TypedDataDomain{ + Name: toStr(domain.Name), + Version: toStr(domain.Version), + ChainId: (*math.HexOrDecimal256)(toBig(domain.ChainID)), + VerifyingContract: toStr(domain.VerifyingContract), + }, + Message: message, + } + for name, fields := range types { + conv := make([]apitypes.Type, len(fields)) + for i, f := range fields { + conv[i] = apitypes.Type{Name: f.Name, Type: f.Type} + } + td.Types[name] = conv + } + // Conditional EIP712Domain field declaration: matches the populated + // domain values so HashStruct doesn't fail with "" when fields like + // `version` are intentionally omitted (Permit2 uses no version, though + // the batch-settlement EIP-712 domain itself has both name and version + // so this branch is mostly defensive parity with the SDK and nethttp). + if _, ok := td.Types["EIP712Domain"]; !ok { + domainFields := make([]apitypes.Type, 0, 4) + if td.Domain.Name != "" { + domainFields = append(domainFields, apitypes.Type{Name: "name", Type: "string"}) + } + if td.Domain.Version != "" { + domainFields = append(domainFields, apitypes.Type{Name: "version", Type: "string"}) + } + if td.Domain.ChainId != nil { + domainFields = append(domainFields, apitypes.Type{Name: "chainId", Type: "uint256"}) + } + if td.Domain.VerifyingContract != "" { + domainFields = append(domainFields, apitypes.Type{Name: "verifyingContract", Type: "address"}) + } + td.Types["EIP712Domain"] = domainFields + } + dataHash, err := td.HashStruct(td.PrimaryType, td.Message) + if err != nil { + return nil, fmt.Errorf("hash struct: %w", err) + } + domainSep, err := td.HashStruct("EIP712Domain", td.Domain.Map()) + if err != nil { + return nil, fmt.Errorf("hash domain: %w", err) + } + digest := crypto.Keccak256(append([]byte{0x19, 0x01}, append(domainSep, dataHash...)...)) + sig, err := crypto.Sign(digest, s.privateKey) + if err != nil { + return nil, fmt.Errorf("sign: %w", err) + } + sig[64] += 27 + return sig, nil +} + +func toStr(v interface{}) string { + switch s := v.(type) { + case string: + return s + case *string: + if s != nil { + return *s + } + } + return "" +} + +func toBig(v interface{}) *big.Int { + switch n := v.(type) { + case *big.Int: + return n + case int64: + return big.NewInt(n) + case string: + b, ok := new(big.Int).SetString(n, 10) + if ok { + return b + } + } + return big.NewInt(0) +} diff --git a/e2e/servers/gin/go.mod b/e2e/servers/gin/go.mod index 393edfdb4f..8ae9286c05 100644 --- a/e2e/servers/gin/go.mod +++ b/e2e/servers/gin/go.mod @@ -1,13 +1,14 @@ -module github.com/coinbase/x402/e2e/servers/gin +module github.com/x402-foundation/x402/e2e/servers/gin go 1.24.0 toolchain go1.24.1 require ( - github.com/coinbase/x402/go v0.0.0 + github.com/ethereum/go-ethereum v1.16.7 github.com/gin-gonic/gin v1.11.0 github.com/joho/godotenv v1.5.1 + github.com/x402-foundation/x402/go v0.0.0 ) require ( @@ -28,7 +29,6 @@ require ( github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect - github.com/ethereum/go-ethereum v1.16.7 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/fatih/color v1.16.0 // indirect github.com/gabriel-vasile/mimetype v1.4.8 // indirect @@ -88,4 +88,4 @@ require ( google.golang.org/protobuf v1.36.9 // indirect ) -replace github.com/coinbase/x402/go => ../../../go +replace github.com/x402-foundation/x402/go => ../../../go diff --git a/e2e/servers/gin/main.go b/e2e/servers/gin/main.go index a52a7bc234..a32575e6e4 100644 --- a/e2e/servers/gin/main.go +++ b/e2e/servers/gin/main.go @@ -8,18 +8,20 @@ import ( "syscall" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" - "github.com/coinbase/x402/go/extensions/types" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - exactevm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - uptoevm "github.com/coinbase/x402/go/mechanisms/evm/upto/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" ginfw "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/extensions/types" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + batchedserver "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/server" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) var shutdownRequested bool @@ -114,6 +116,25 @@ func main() { fmt.Printf("Warning: Failed to create bazaar extension: %v\n", err) } + // Batch-settlement scheme registration. Mirrors the nethttp e2e server: + // the harness drives deposit + voucher + recovery + refund inline via + // BATCH_SETTLEMENT_PHASE; the server only needs to register the scheme + // and respond once payment is verified. Optional self-managed receiver + // authorizer is wired through EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY. + batchedCfg := &batchedserver.BatchSettlementEvmSchemeServerConfig{} + if authKey := os.Getenv("EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY"); authKey != "" { + auth, err := newBatchedAuthorizerSigner(authKey) + if err != nil { + fmt.Printf("Failed to parse EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY: %v\n", err) + os.Exit(1) + } + batchedCfg.ReceiverAuthorizerSigner = auth + fmt.Printf("Batch-settlement receiver authorizer (self-managed): %s\n", auth.Address()) + } else { + fmt.Println("Batch-settlement receiver authorizer: facilitator-delegated") + } + batchedScheme := batchedserver.NewBatchSettlementEvmScheme(evmPayeeAddress, batchedCfg) + routes := x402http.RoutesConfig{ "GET /exact/evm/eip3009": { Accepts: x402http.PaymentOptions{ @@ -128,6 +149,69 @@ func main() { types.BAZAAR.Key(): discoveryExtension, }, }, + // Batch-settlement endpoints. Mirror nethttp's batch-settlement routes: + // the harness drives deposit + voucher + recovery + refund inline via + // BATCH_SETTLEMENT_PHASE; the server only needs to register the scheme + // and respond once payment is verified. + "GET /batch-settlement/evm/eip3009": { + Accepts: x402http.PaymentOptions{ + { + Scheme: batchsettlement.SchemeBatched, + PayTo: evmPayeeAddress, + Price: "$0.001", + Network: evmNetwork, + }, + }, + }, + "GET /batch-settlement/evm/permit2": { + Accepts: x402http.PaymentOptions{ + { + Scheme: batchsettlement.SchemeBatched, + PayTo: evmPayeeAddress, + Network: evmNetwork, + Price: map[string]interface{}{ + "amount": "1000", + "asset": evmPermit2Asset, + "extra": map[string]interface{}{ + "assetTransferMethod": "permit2", + "name": "USDC", + "version": "2", + }, + }, + }, + }, + }, + "GET /batch-settlement/evm/permit2-eip2612GasSponsoring": { + Accepts: x402http.PaymentOptions{ + { + Scheme: batchsettlement.SchemeBatched, + PayTo: evmPayeeAddress, + Network: evmNetwork, + Price: "$0.001", + Extra: map[string]interface{}{ + "assetTransferMethod": "permit2", + }, + }, + }, + Extensions: eip2612gassponsor.DeclareEip2612GasSponsoringExtension(), + }, + "GET /batch-settlement/evm/permit2-erc20ApprovalGasSponsoring": { + Accepts: x402http.PaymentOptions{ + { + Scheme: batchsettlement.SchemeBatched, + PayTo: evmPayeeAddress, + Network: evmNetwork, + Price: map[string]interface{}{ + "amount": "1000", + "asset": evmPermit2Asset, + "extra": map[string]interface{}{ + "assetTransferMethod": "permit2", + }, + }, + }, + }, + Extensions: erc20approvalgassponsor.DeclareExtension(), + }, "GET /exact/svm": { Accepts: x402http.PaymentOptions{ { @@ -259,6 +343,7 @@ func main() { Schemes: []ginmw.SchemeConfig{ {Network: evmNetwork, Server: exactevm.NewExactEvmScheme()}, {Network: evmNetwork, Server: uptoevm.NewUptoEvmScheme()}, + {Network: evmNetwork, Server: batchedScheme}, {Network: svmNetwork, Server: svm.NewExactSvmScheme()}, }, SyncFacilitatorOnStart: true, @@ -375,6 +460,27 @@ func main() { }) }) + // Batch-settlement endpoints. Mirror nethttp's `batchHandler`: the harness + // drives deposit + voucher + recovery + refund inline via BATCH_SETTLEMENT_PHASE; + // the server just acknowledges once payment is verified. + batchHandler := func(method string) ginfw.HandlerFunc { + return func(c *ginfw.Context) { + if shutdownRequested { + c.JSON(http.StatusServiceUnavailable, ginfw.H{"error": "Server shutting down"}) + return + } + c.JSON(http.StatusOK, ginfw.H{ + "message": "Batch-settlement endpoint accessed successfully", + "timestamp": time.Now().Format(time.RFC3339), + "method": method, + }) + } + } + r.GET("/batch-settlement/evm/eip3009", batchHandler("batch-settlement-eip3009")) + r.GET("/batch-settlement/evm/permit2", batchHandler("batch-settlement-permit2")) + r.GET("/batch-settlement/evm/permit2-eip2612GasSponsoring", batchHandler("batch-settlement-permit2-eip2612")) + r.GET("/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", batchHandler("batch-settlement-permit2-erc20-approval")) + // Upto Permit2 endpoint - settles with partial amount r.GET("/upto/evm/permit2", func(c *ginfw.Context) { if shutdownRequested { @@ -451,6 +557,10 @@ func main() { ║ ║ ║ Endpoints: ║ ║ • GET /exact/evm/eip3009 (EVM EIP-3009) ║ +║ • GET /batch-settlement/evm/eip3009 (Batch-settlement) ║ +║ • GET /batch-settlement/evm/permit2 (Batch Permit2) ║ +║ • GET /batch-settlement/evm/permit2-eip2612GasSponsoring ║ +║ • GET /batch-settlement/evm/permit2-erc20ApprovalGasSponsoring ║ ║ • GET /exact/evm/permit2 (Permit2) ║ ║ • GET /exact/evm/permit2-eip2612GasSponsoring ║ ║ • GET /exact/evm/permit2-erc20ApprovalGasSponsoring ║ diff --git a/e2e/servers/gin/run.sh b/e2e/servers/gin/run.sh index 2532f0affa..168b1acfb4 100755 --- a/e2e/servers/gin/run.sh +++ b/e2e/servers/gin/run.sh @@ -1,3 +1,5 @@ #!/bin/bash -go run main.go - +# `go run .` compiles the whole package (main.go + batched_authorizer.go), +# whereas `go run main.go` would only compile main.go and miss helper files +# in the same package, causing `undefined: newBatchedAuthorizerSigner` errors. +go run . diff --git a/e2e/servers/gin/test.config.json b/e2e/servers/gin/test.config.json index 5e434fbfc3..1021d7b0a7 100644 --- a/e2e/servers/gin/test.config.json +++ b/e2e/servers/gin/test.config.json @@ -8,6 +8,12 @@ "eip2612GasSponsoring", "erc20ApprovalGasSponsoring" ], + "evm": { + "assetTransferMethods": [ + "eip3009", + "permit2" + ] + }, "description": "Go Gin server with x402 v2 payment middleware", "endpoints": [ { @@ -16,7 +22,56 @@ "description": "Protected endpoint requiring EIP-3009 payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" + }, + { + "path": "/batch-settlement/evm/eip3009", + "method": "GET", + "description": "Protected endpoint exercised by deposit + voucher + recovery voucher + cooperative refund", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "eip3009" + }, + { + "path": "/batch-settlement/evm/permit2", + "method": "GET", + "description": "Batch-settlement Permit2 direct endpoint (pre-approved Permit2)", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } + }, + { + "path": "/batch-settlement/evm/permit2-eip2612GasSponsoring", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with EIP-2612 gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } + }, + { + "path": "/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with ERC-20 approval gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2", @@ -24,8 +79,11 @@ "description": "Protected endpoint requiring Permit2 payment (standard settle, no gas sponsoring)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "permit2Direct": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/exact/evm/permit2-eip2612GasSponsoring", @@ -33,8 +91,11 @@ "description": "Protected endpoint requiring Permit2 payment with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "coldstart": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2-erc20ApprovalGasSponsoring", @@ -42,9 +103,14 @@ "description": "Protected endpoint requiring Permit2 payment with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/upto/evm/permit2", @@ -52,8 +118,11 @@ "description": "Protected endpoint requiring upto Permit2 payment (usage-based settlement)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "permit2Direct": true + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/exact/svm", @@ -82,6 +151,8 @@ "SVM_PAYEE_ADDRESS", "FACILITATOR_URL" ], - "optional": [] + "optional": [ + "EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY" + ] } } diff --git a/e2e/servers/hono/index.ts b/e2e/servers/hono/index.ts index 9536d6b30f..8a31c20004 100644 --- a/e2e/servers/hono/index.ts +++ b/e2e/servers/hono/index.ts @@ -4,15 +4,19 @@ import { paymentMiddleware, setSettlementOverrides } from "@x402/hono"; import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server"; import { ExactEvmScheme } from "@x402/evm/exact/server"; import { UptoEvmScheme } from "@x402/evm/upto/server"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/server"; import { ExactSvmScheme } from "@x402/svm/exact/server"; import { ExactAptosScheme } from "@x402/aptos/exact/server"; +import { ExactHederaScheme } from "@x402/hedera/exact/server"; import { ExactStellarScheme } from "@x402/stellar/exact/server"; +import { ExactAvmScheme } from "@x402/avm/exact/server"; import { bazaarResourceServerExtension, declareDiscoveryExtension } from "@x402/extensions/bazaar"; import { declareEip2612GasSponsoringExtension, declareErc20ApprovalGasSponsoringExtension, } from "@x402/extensions"; import dotenv from "dotenv"; +import { privateKeyToAccount } from "viem/accounts"; dotenv.config(); @@ -28,11 +32,17 @@ const EVM_NETWORK = (process.env.EVM_NETWORK || "eip155:84532") as `${string}:${ const SVM_NETWORK = (process.env.SVM_NETWORK || "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1") as `${string}:${string}`; const APTOS_NETWORK = (process.env.APTOS_NETWORK || "aptos:2") as `${string}:${string}`; +const HEDERA_NETWORK = (process.env.HEDERA_NETWORK || "hedera:testnet") as `${string}:${string}`; +const AVM_NETWORK = (process.env.AVM_NETWORK || "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=") as `${string}:${string}`; const STELLAR_NETWORK = (process.env.STELLAR_NETWORK || "stellar:testnet") as `${string}:${string}`; const EVM_PAYEE_ADDRESS = process.env.EVM_PAYEE_ADDRESS as `0x${string}`; const SVM_PAYEE_ADDRESS = process.env.SVM_PAYEE_ADDRESS as string; const APTOS_PAYEE_ADDRESS = process.env.APTOS_PAYEE_ADDRESS as string; +const HEDERA_PAYEE_ADDRESS = process.env.HEDERA_PAYEE_ADDRESS as string | undefined; +const AVM_PAYEE_ADDRESS = process.env.AVM_PAYEE_ADDRESS as string; const STELLAR_PAYEE_ADDRESS = process.env.STELLAR_PAYEE_ADDRESS as string | undefined; +const HEDERA_ASSET = process.env.HEDERA_ASSET ?? "0.0.0"; // 0.0.0 = HBAR or 0.0.429274 for USDC testnet +const HEDERA_AMOUNT = process.env.HEDERA_AMOUNT ?? "100000"; // price in smallest units (tinybars or token decimals), defaults to 0.001 HBAR or 0.1 USDC const EVM_PERMIT2_ASSET = process.env.EVM_PERMIT2_ASSET as `0x${string}`; const facilitatorUrl = process.env.FACILITATOR_URL; @@ -65,12 +75,33 @@ if (mockFacilitatorUrl) { const x402Server = new x402ResourceServer(facilitatorClients); // Register server schemes +if (AVM_PAYEE_ADDRESS) { + x402Server.register("algorand:*", new ExactAvmScheme()); +} x402Server.register("eip155:*", new ExactEvmScheme()); x402Server.register("eip155:*", new UptoEvmScheme()); + +// Register batch-settlement scheme for the EVM payee. +// e2e flow does NOT use ChannelManager — settle actions are handled inline. +const receiverAuthorizerPrivateKey = process.env.EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY as + | `0x${string}` + | undefined; +const receiverAuthorizerSigner = receiverAuthorizerPrivateKey + ? privateKeyToAccount(receiverAuthorizerPrivateKey) + : undefined; +x402Server.register( + "eip155:*", + new BatchSettlementEvmScheme(EVM_PAYEE_ADDRESS, { + ...(receiverAuthorizerSigner ? { receiverAuthorizerSigner } : {}), + }), +); x402Server.register("solana:*", new ExactSvmScheme()); if (APTOS_PAYEE_ADDRESS) { x402Server.register("aptos:*", new ExactAptosScheme()); } +if (HEDERA_PAYEE_ADDRESS) { + x402Server.register("hedera:*", new ExactHederaScheme()); +} if (STELLAR_PAYEE_ADDRESS) { x402Server.register("stellar:*", new ExactStellarScheme()); } @@ -83,6 +114,23 @@ console.log( ); console.log(`Using remote facilitator at: ${facilitatorUrl}`); +/** + * Pre-middleware guard for optional AVM endpoint + * Returns 501 Not Implemented if AVM is not configured + */ +app.use("/exact/avm", async (c, next) => { + if (!AVM_PAYEE_ADDRESS) { + return c.json( + { + error: "AVM payments not configured", + message: "AVM_PAYEE_ADDRESS environment variable is not set", + }, + 501, + ); + } + await next(); +}); + /** * Pre-middleware guard for optional Aptos endpoint * Returns 501 Not Implemented if Aptos is not configured @@ -100,6 +148,23 @@ app.use("/exact/aptos", async (c, next) => { await next(); }); +/** + * Pre-middleware guard for optional Hedera endpoint + * Returns 501 Not Implemented if Hedera is not configured + */ +app.use("/exact/hedera", async (c, next) => { + if (!HEDERA_PAYEE_ADDRESS) { + return c.json( + { + error: "Hedera payments not configured", + message: "HEDERA_PAYEE_ADDRESS environment variable is not set", + }, + 501, + ); + } + await next(); +}); + /** * Pre-middleware guard for optional Stellar endpoint * Returns 501 Not Implemented if Stellar is not configured @@ -125,6 +190,88 @@ app.use( paymentMiddleware( { // Route-specific payment configuration + ...(AVM_PAYEE_ADDRESS + ? { + "GET /exact/avm": { + accepts: { + payTo: AVM_PAYEE_ADDRESS, + scheme: "exact", + price: "$0.001", + network: AVM_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected endpoint accessed successfully", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, + }, + required: ["message", "timestamp"], + }, + }, + }), + }, + }, + } + : {}), + "GET /batch-settlement/evm/eip3009": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + price: "$0.001", + network: EVM_NETWORK, + }, + }, + "GET /batch-settlement/evm/permit2": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: { + amount: "1000", + asset: EVM_PERMIT2_ASSET, + extra: { + assetTransferMethod: "permit2", + name: EVM_NETWORK == "eip155:84532" ? "USDC" : "USD Coin", + version: "2", + }, + }, + }, + }, + "GET /batch-settlement/evm/permit2-eip2612GasSponsoring": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: "$0.001", + extra: { assetTransferMethod: "permit2" }, + }, + extensions: { + ...declareEip2612GasSponsoringExtension(), + }, + }, + "GET /batch-settlement/evm/permit2-erc20ApprovalGasSponsoring": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: { + amount: "1000", + asset: EVM_PERMIT2_ASSET, + extra: { + assetTransferMethod: "permit2", + }, + }, + }, + extensions: { + ...declareErc20ApprovalGasSponsoringExtension(), + }, + }, "GET /exact/evm/eip3009": { accepts: { payTo: EVM_PAYEE_ADDRESS, @@ -204,6 +351,38 @@ app.use( }, } : {}), + ...(HEDERA_PAYEE_ADDRESS + ? { + "GET /exact/hedera": { + accepts: { + payTo: HEDERA_PAYEE_ADDRESS, + scheme: "exact", + price: { + amount: HEDERA_AMOUNT, + asset: HEDERA_ASSET, + }, + network: HEDERA_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected Hedera endpoint accessed successfully", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, + }, + required: ["message", "timestamp"], + }, + }, + }), + }, + }, + } + : {}), "GET /exact/evm/permit2": { accepts: { payTo: EVM_PAYEE_ADDRESS, @@ -378,6 +557,41 @@ app.use( ), ); +/** + * Protected batch-settlement endpoint — exercised by repeated voucher requests + * over a single payment channel followed by an optional cooperative refund. + */ +app.get("/batch-settlement/evm/eip3009", c => { + return c.json({ + message: "Batch-settlement endpoint accessed successfully", + timestamp: new Date().toISOString(), + }); +}); + +app.get("/batch-settlement/evm/permit2", c => { + return c.json({ + message: "Batch-settlement Permit2 endpoint accessed successfully", + timestamp: new Date().toISOString(), + method: "batch-settlement-permit2", + }); +}); + +app.get("/batch-settlement/evm/permit2-eip2612GasSponsoring", c => { + return c.json({ + message: "Batch-settlement Permit2 EIP-2612 endpoint accessed successfully", + timestamp: new Date().toISOString(), + method: "batch-settlement-permit2-eip2612", + }); +}); + +app.get("/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", c => { + return c.json({ + message: "Batch-settlement Permit2 ERC-20 approval endpoint accessed successfully", + timestamp: new Date().toISOString(), + method: "batch-settlement-permit2-erc20-approval", + }); +}); + /** * Protected endpoint - requires payment to access * @@ -404,6 +618,20 @@ app.get("/exact/svm", c => { }); }); +/** + * Protected AVM endpoint - requires payment to access + * + * This endpoint demonstrates a resource protected by x402 payment middleware for AVM. + * Clients must provide a valid payment signature to access this endpoint. + * Note: 501 check is handled by pre-middleware guard above. + */ +app.get("/exact/avm", c => { + return c.json({ + message: "Protected endpoint accessed successfully", + timestamp: new Date().toISOString(), + }); +}); + /** * Protected Aptos endpoint - requires payment to access * @@ -418,6 +646,19 @@ app.get("/exact/aptos", c => { }); }); +/** + * Protected Hedera endpoint - requires payment to access + * + * This endpoint demonstrates a resource protected by x402 payment middleware for Hedera. + * Note: 501 check is handled by pre-middleware guard above. + */ +app.get("/exact/hedera", c => { + return c.json({ + message: "Protected Hedera endpoint accessed successfully", + timestamp: new Date().toISOString(), + }); +}); + /** * Protected Permit2 endpoint - standard settle (no gas sponsoring) */ @@ -547,22 +788,28 @@ console.log(` ║ x402 Hono E2E Test Server ║ ╠════════════════════════════════════════════════════════╣ ║ Server: http://localhost:${PORT} ║ +║ AVM Network: ${AVM_NETWORK} ║ ║ EVM Network: ${EVM_NETWORK} ║ ║ SVM Network: ${SVM_NETWORK} ║ ║ Aptos Network: ${APTOS_NETWORK} ║ +║ Hedera Network: ${HEDERA_NETWORK} ║ ║ Stellar Network: ${STELLAR_NETWORK} ║ +║ AVM Payee: ${AVM_PAYEE_ADDRESS || "(not configured)"} ║ EVM Payee: ${EVM_PAYEE_ADDRESS} ║ ║ SVM Payee: ${SVM_PAYEE_ADDRESS} ║ ║ Aptos Payee: ${APTOS_PAYEE_ADDRESS || "(not configured)"} +║ Hedera Payee: ${HEDERA_PAYEE_ADDRESS || "(not configured)"} ║ Stellar Payee: ${STELLAR_PAYEE_ADDRESS || "(not configured)"} ║ ║ ║ Endpoints: ║ +║ • GET /exact/avm (AVM) ║ ║ • GET /exact/evm/eip3009 (EVM EIP-3009) ║ ║ • GET /exact/evm/permit2 (Permit2) ║ ║ • GET /exact/evm/permit2-eip2612GasSponsoring ║ ║ • GET /exact/evm/permit2-erc20ApprovalGasSponsoring ║ ║ • GET /exact/svm (SVM) ║ ║ • GET /exact/aptos (Aptos) ║ +║ • GET /exact/hedera (Hedera) ║ ║ • GET /exact/stellar (Stellar) ║ ║ • GET /health (no payment required) ║ ║ • POST /close (shutdown server) ║ diff --git a/e2e/servers/hono/package.json b/e2e/servers/hono/package.json index ba14bf7e2d..2f3f65d849 100644 --- a/e2e/servers/hono/package.json +++ b/e2e/servers/hono/package.json @@ -12,8 +12,10 @@ "dependencies": { "@hono/node-server": "^1.14.0", "@x402/aptos": "workspace:*", + "@x402/avm": "workspace:*", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", + "@x402/hedera": "workspace:*", "@x402/extensions": "workspace:*", "@x402/hono": "workspace:*", "@x402/stellar": "workspace:*", @@ -24,6 +26,7 @@ "devDependencies": { "@eslint/js": "^9.24.0", "@types/express": "^5.0.1", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -31,8 +34,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/e2e/servers/hono/test.config.json b/e2e/servers/hono/test.config.json index c014288c77..ecc20da640 100644 --- a/e2e/servers/hono/test.config.json +++ b/e2e/servers/hono/test.config.json @@ -3,16 +3,75 @@ "type": "server", "language": "typescript", "x402Version": 2, - "extensions": ["bazaar", "eip2612GasSponsoring", "erc20ApprovalGasSponsoring"], - + "extensions": [ + "bazaar", + "eip2612GasSponsoring", + "erc20ApprovalGasSponsoring" + ], "endpoints": [ + { + "path": "/exact/avm", + "method": "GET", + "description": "Protected endpoint requiring payment on AVM network", + "requiresPayment": true, + "protocolFamily": "avm" + }, { "path": "/exact/evm/eip3009", "method": "GET", "description": "Protected endpoint requiring EIP-3009 payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" + }, + { + "path": "/batch-settlement/evm/eip3009", + "method": "GET", + "description": "Protected endpoint exercised by deposit + voucher + recovery voucher + cooperative refund", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "eip3009" + }, + { + "path": "/batch-settlement/evm/permit2", + "method": "GET", + "description": "Batch-settlement Permit2 direct endpoint (pre-approved Permit2)", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } + }, + { + "path": "/batch-settlement/evm/permit2-eip2612GasSponsoring", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with EIP-2612 gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } + }, + { + "path": "/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with ERC-20 approval gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2", @@ -20,8 +79,11 @@ "description": "Protected endpoint requiring Permit2 payment (standard settle, no gas sponsoring)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "permit2Direct": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/exact/evm/permit2-eip2612GasSponsoring", @@ -29,8 +91,11 @@ "description": "Protected endpoint requiring Permit2 payment with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "coldstart": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2-erc20ApprovalGasSponsoring", @@ -38,9 +103,14 @@ "description": "Protected endpoint requiring Permit2 payment with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/upto/evm/permit2", @@ -48,8 +118,11 @@ "description": "Protected endpoint requiring upto Permit2 payment (direct, client must pre-approve)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "permit2Direct": true + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/upto/evm/permit2-eip2612GasSponsoring", @@ -57,8 +130,11 @@ "description": "Protected endpoint requiring Upto Permit2 payment with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "coldstart": true + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/upto/evm/permit2-erc20ApprovalGasSponsoring", @@ -66,9 +142,14 @@ "description": "Protected endpoint requiring Upto Permit2 payment with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/svm", @@ -84,6 +165,13 @@ "requiresPayment": true, "protocolFamily": "aptos" }, + { + "path": "/exact/hedera", + "method": "GET", + "description": "Protected endpoint requiring payment on Hedera network", + "requiresPayment": true, + "protocolFamily": "hedera" + }, { "path": "/exact/stellar", "method": "GET", @@ -105,7 +193,18 @@ } ], "environment": { - "required": ["PORT", "EVM_PAYEE_ADDRESS", "SVM_PAYEE_ADDRESS", "FACILITATOR_URL"], - "optional": ["APTOS_PAYEE_ADDRESS", "STELLAR_PAYEE_ADDRESS"] + "required": [ + "PORT", + "EVM_PAYEE_ADDRESS", + "SVM_PAYEE_ADDRESS", + "FACILITATOR_URL" + ], + "optional": [ + "AVM_PAYEE_ADDRESS", + "APTOS_PAYEE_ADDRESS", + "HEDERA_PAYEE_ADDRESS", + "STELLAR_PAYEE_ADDRESS", + "EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY" + ] } -} +} \ No newline at end of file diff --git a/e2e/servers/mcp-go/go.mod b/e2e/servers/mcp-go/go.mod index 9fc72ccfb4..306944e9c5 100644 --- a/e2e/servers/mcp-go/go.mod +++ b/e2e/servers/mcp-go/go.mod @@ -1,27 +1,38 @@ -module github.com/coinbase/x402/e2e/servers/mcp-go +module github.com/x402-foundation/x402/e2e/servers/mcp-go go 1.24.0 toolchain go1.24.1 require ( - github.com/coinbase/x402/go v0.0.0 github.com/modelcontextprotocol/go-sdk v1.3.0 + github.com/x402-foundation/x402/go v0.0.0 ) require ( + github.com/Microsoft/go-winio v0.6.2 // indirect github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect github.com/bits-and-blooms/bitset v1.20.0 // indirect github.com/consensys/gnark-crypto v0.18.0 // indirect github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect github.com/ethereum/go-ethereum v1.16.7 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect github.com/google/jsonschema-go v0.4.2 // indirect + github.com/gorilla/websocket v1.4.2 // indirect github.com/holiman/uint256 v1.3.2 // indirect + github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect github.com/yosida95/uritemplate/v3 v3.0.2 // indirect golang.org/x/crypto v0.46.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect @@ -29,4 +40,4 @@ require ( golang.org/x/sys v0.39.0 // indirect ) -replace github.com/coinbase/x402/go => ../../../go +replace github.com/x402-foundation/x402/go => ../../../go diff --git a/e2e/servers/mcp-go/go.sum b/e2e/servers/mcp-go/go.sum index 44cd6d3944..7a08d9d417 100644 --- a/e2e/servers/mcp-go/go.sum +++ b/e2e/servers/mcp-go/go.sum @@ -1,17 +1,46 @@ +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU= github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= +github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= +github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= @@ -20,18 +49,29 @@ github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8= github.com/ethereum/go-ethereum v1.16.7 h1:qeM4TvbrWK0UC0tgkZ7NiRsmBGwsjqc64BHo20U59UQ= github.com/ethereum/go-ethereum v1.16.7/go.mod h1:Fs6QebQbavneQTYcA39PEKv2+zIjX7rPUZ14DER46wk= github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang-jwt/jwt/v5 v5.2.2 h1:Rl4B7itRWVtYIHFrSNd7vhTiz9UpLdi6gZhZ3wEeDy8= github.com/golang-jwt/jwt/v5 v5.2.2/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= @@ -42,56 +82,130 @@ github.com/google/jsonschema-go v0.4.2 h1:tmrUohrwoLZZS/P3x7ex0WAVknEkBZM46iALbc github.com/google/jsonschema-go v0.4.2/go.mod h1:r5quNTdLOYEz95Ru18zA0ydNbBuYoo9tgaYcxEYhJVE= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= github.com/modelcontextprotocol/go-sdk v1.3.0 h1:gMfZkv3DzQF5q/DcQePo5rahEY+sguyPfXDfNBcT0Zs= github.com/modelcontextprotocol/go-sdk v1.3.0/go.mod h1:AnQ//Qc6+4nIyyrB4cxBU7UW9VibK4iOZBeyP/rF1IE= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= +github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= +github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM= +github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw= github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= github.com/yosida95/uritemplate/v3 v3.0.2 h1:Ed3Oyj9yrmi9087+NczuL5BwkIc4wvTb5zIM+UJPGz4= github.com/yosida95/uritemplate/v3 v3.0.2/go.mod h1:ILOh0sOhIJR3+L/8afwt/kE++YT040gmv5BQTMR2HP4= golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/oauth2 v0.30.0 h1:dnDm7JmhM45NNpd8FDDeLhK6FwqbOf4MLCM9zb1BOHI= golang.org/x/oauth2 v0.30.0/go.mod h1:B++QgG3ZKulg6sRPGD/mqlHQs5rB3Ml9erfeDY7xKlU= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/e2e/servers/mcp-go/main.go b/e2e/servers/mcp-go/main.go index 4f05392672..e7a057a69e 100644 --- a/e2e/servers/mcp-go/main.go +++ b/e2e/servers/mcp-go/main.go @@ -9,12 +9,13 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - mcp402 "github.com/coinbase/x402/go/mcp" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - "github.com/coinbase/x402/go/types" "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + x402http "github.com/x402-foundation/x402/go/http" + mcp402 "github.com/x402-foundation/x402/go/mcp" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + "github.com/x402-foundation/x402/go/types" ) // getWeatherData simulates fetching weather data for a city. @@ -96,6 +97,29 @@ func main() { os.Exit(1) } + // Declare bazaar MCP discovery extension for weather tool + weatherInputSchema := map[string]any{ + "type": "object", + "properties": map[string]any{ + "city": map[string]any{ + "type": "string", + "description": "The city name to get weather for", + }, + }, + "required": []string{"city"}, + } + bazaarExtension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "get_weather", + Description: "Get current weather for a city. Requires payment of $0.001.", + Transport: bazaar.TransportSSE, + InputSchema: weatherInputSchema, + Example: map[string]any{"city": "San Francisco"}, + }) + if err != nil { + fmt.Printf("❌ Failed to declare bazaar extension: %v\n", err) + os.Exit(1) + } + // Create payment wrapper using the x402 MCP SDK paymentWrapper := mcp402.NewPaymentWrapper(resourceServer, mcp402.PaymentWrapperConfig{ Accepts: weatherAccepts, @@ -104,6 +128,9 @@ func main() { Description: "Get current weather for a city", MimeType: "application/json", }, + Extensions: map[string]interface{}{ + bazaar.BAZAAR.Key(): bazaarExtension, + }, }) // Create MCP server using the official SDK diff --git a/e2e/servers/mcp-go/test.config.json b/e2e/servers/mcp-go/test.config.json index b95a6681bf..c82a7a7308 100644 --- a/e2e/servers/mcp-go/test.config.json +++ b/e2e/servers/mcp-go/test.config.json @@ -4,14 +4,20 @@ "transport": "mcp", "language": "go", "x402Version": 2, + "extensions": [ + "bazaar" + ], "endpoints": [ { "path": "get_weather", "method": "tool", + "toolName": "get_weather", + "mcpTransport": "sse", "description": "Paid weather tool via MCP transport", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" }, { "path": "/health", diff --git a/e2e/servers/mcp-python/main.py b/e2e/servers/mcp-python/main.py index c27d2f80fd..773808404f 100644 --- a/e2e/servers/mcp-python/main.py +++ b/e2e/servers/mcp-python/main.py @@ -16,10 +16,12 @@ PORT = int(os.getenv("PORT", "4022")) EVM_NETWORK = os.getenv("EVM_NETWORK", "eip155:84532") EVM_PAYEE_ADDRESS = os.getenv("EVM_PAYEE_ADDRESS", "") +TVM_NETWORK = os.getenv("TVM_NETWORK", "tvm:-3") +TVM_PAYEE_ADDRESS = os.getenv("TVM_PAYEE_ADDRESS", "") FACILITATOR_URL = os.getenv("FACILITATOR_URL", "") -if not EVM_PAYEE_ADDRESS: - print("EVM_PAYEE_ADDRESS environment variable is required") +if not EVM_PAYEE_ADDRESS and not TVM_PAYEE_ADDRESS: + print("At least one of EVM_PAYEE_ADDRESS or TVM_PAYEE_ADDRESS is required") exit(1) if not FACILITATOR_URL: @@ -40,9 +42,11 @@ def main() -> None: from mcp.server.fastmcp import FastMCP from x402 import ResourceConfig, ResourceInfo, x402ResourceServer + from x402.extensions.bazaar import DeclareMcpDiscoveryConfig, declare_mcp_discovery_extension from x402.http import FacilitatorConfig, HTTPFacilitatorClient from x402.mcp import create_payment_wrapper from x402.mechanisms.evm.exact import register_exact_evm_server + from x402.mechanisms.tvm.exact import ExactTvmServerScheme # Create FastMCP server mcp = FastMCP("x402 MCP E2E Server") @@ -50,19 +54,51 @@ def main() -> None: # Set up x402 resource server facilitator_client = HTTPFacilitatorClient(FacilitatorConfig(url=FACILITATOR_URL)) resource_server = x402ResourceServer(facilitator_client) - register_exact_evm_server(resource_server, EVM_NETWORK) + if EVM_PAYEE_ADDRESS: + register_exact_evm_server(resource_server, EVM_NETWORK) + if TVM_PAYEE_ADDRESS: + resource_server.register(TVM_NETWORK, ExactTvmServerScheme()) # Initialize (fetches supported kinds from facilitator) resource_server.initialize() - # Build payment requirements for the weather tool - weather_config = ResourceConfig( - scheme="exact", - network=EVM_NETWORK, - pay_to=EVM_PAYEE_ADDRESS, - price="$0.001", + weather_accepts = [] + if EVM_PAYEE_ADDRESS: + weather_accepts.extend( + resource_server.build_payment_requirements( + ResourceConfig( + scheme="exact", + network=EVM_NETWORK, + pay_to=EVM_PAYEE_ADDRESS, + price="$0.001", + ) + ) + ) + if TVM_PAYEE_ADDRESS: + weather_accepts.extend( + resource_server.build_payment_requirements( + ResourceConfig( + scheme="exact", + network=TVM_NETWORK, + pay_to=TVM_PAYEE_ADDRESS, + price="$0.001", + ) + ) + ) + + # Declare Bazaar discovery metadata for the weather tool + weather_discovery = declare_mcp_discovery_extension( + DeclareMcpDiscoveryConfig( + tool_name="get_weather", + description="Get current weather for a city", + transport="sse", + input_schema={ + "properties": {"city": {"type": "string", "description": "City name"}}, + "required": ["city"], + }, + example={"city": "San Francisco"}, + ) ) - weather_accepts = resource_server.build_payment_requirements(weather_config) # Create payment wrapper for the weather tool weather_wrapper = create_payment_wrapper( @@ -73,6 +109,7 @@ def main() -> None: description="Get current weather for a city", mime_type="application/json", ), + extensions=weather_discovery, ) @mcp.tool( @@ -96,7 +133,18 @@ def ping() -> str: async def health(request): return JSONResponse( - {"status": "ok", "tools": ["get_weather (paid: $0.001)", "ping (free)"]} + { + "status": "ok", + "tools": ["get_weather (paid: $0.001)", "ping (free)"], + "protocols": [ + protocol + for protocol, enabled in { + "evm": bool(EVM_PAYEE_ADDRESS), + "tvm": bool(TVM_PAYEE_ADDRESS), + }.items() + if enabled + ], + } ) async def close(request): @@ -128,6 +176,10 @@ def shutdown(): print(f"Server listening on port {PORT}") print(f"SSE endpoint: http://localhost:{PORT}/sse") print(f"Health: http://localhost:{PORT}/health") + if EVM_PAYEE_ADDRESS: + print(f"EVM payments enabled on {EVM_NETWORK}") + if TVM_PAYEE_ADDRESS: + print(f"TVM payments enabled on {TVM_NETWORK}") uvicorn.run(app, host="0.0.0.0", port=PORT, log_level="warning") diff --git a/e2e/servers/mcp-python/pyproject.toml b/e2e/servers/mcp-python/pyproject.toml index 41a0e1705d..26e07a31f1 100644 --- a/e2e/servers/mcp-python/pyproject.toml +++ b/e2e/servers/mcp-python/pyproject.toml @@ -8,7 +8,7 @@ dependencies = [ "mcp>=1.9.0", "uvicorn>=0.24.0", "starlette>=0.27.0", - "x402[evm,mcp]" + "x402[evm,tvm,mcp]" ] [build-system] @@ -22,6 +22,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/e2e/servers/mcp-python/run.sh b/e2e/servers/mcp-python/run.sh index 31c1f93486..a0337e9257 100755 --- a/e2e/servers/mcp-python/run.sh +++ b/e2e/servers/mcp-python/run.sh @@ -1,4 +1,4 @@ #!/bin/bash # Ensure dependencies are synced before running -uv sync --quiet +uv sync --reinstall-package x402 --quiet uv run python main.py diff --git a/e2e/servers/mcp-python/test.config.json b/e2e/servers/mcp-python/test.config.json index 665cb46119..2cad089837 100644 --- a/e2e/servers/mcp-python/test.config.json +++ b/e2e/servers/mcp-python/test.config.json @@ -4,14 +4,27 @@ "transport": "mcp", "language": "python", "x402Version": 2, + "extensions": [ + "bazaar" + ], "endpoints": [ { "path": "get_weather", "method": "tool", + "toolName": "get_weather", + "mcpTransport": "sse", "description": "Paid weather tool via MCP transport", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" + }, + { + "path": "get_weather", + "method": "tool", + "description": "Paid weather tool via MCP transport", + "requiresPayment": true, + "protocolFamily": "tvm" }, { "path": "/health", @@ -29,9 +42,13 @@ "environment": { "required": [ "PORT", - "EVM_PAYEE_ADDRESS", "FACILITATOR_URL" ], - "optional": [] + "optional": [ + "EVM_PAYEE_ADDRESS", + "EVM_NETWORK", + "TVM_PAYEE_ADDRESS", + "TVM_NETWORK" + ] } } diff --git a/e2e/servers/mcp-python/uv.lock b/e2e/servers/mcp-python/uv.lock index 77e4c907b6..b6905a030a 100644 --- a/e2e/servers/mcp-python/uv.lock +++ b/e2e/servers/mcp-python/uv.lock @@ -1,5 +1,5 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" [[package]] @@ -1466,6 +1466,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, ] +[[package]] +name = "pycryptodomex" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -1627,6 +1662,41 @@ crypto = [ { name = "cryptography" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -1645,6 +1715,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" }, ] +[[package]] +name = "pytoniq" +version = "0.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytoniq-core" }, + { name = "requests" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/b2/9991a953e4b766918a142fe111f71f12803c6acf65eb30f36eb85ed08f31/pytoniq-0.1.43.tar.gz", hash = "sha256:b4b1c8fed2f9d2f1b6f0ab4b3f1fc5503a0088630d8081f817807ff31e608606", size = 50463, upload-time = "2025-11-30T12:30:41.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/c1/b6e5c739839e0e12bde4563438acd55d39552ea63f6de123724b4b91ac64/pytoniq-0.1.43-py3-none-any.whl", hash = "sha256:922c1721124bf7214e0b7044fba2a439e006367778611c0ce813cbe5b00079d3", size = 56118, upload-time = "2025-11-30T12:30:39.65Z" }, +] + +[[package]] +name = "pytoniq-core" +version = "0.1.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "x25519" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/2c/7afbb9003a3aa72ccfe69711433fe36d2493db2c4acf66dde32f7b55799b/pytoniq_core-0.1.46.tar.gz", hash = "sha256:c8e3cf9ccb1852780a725cd51ba7a66a28122eb39c8b9bb97dcdc5bd02c24734", size = 101236, upload-time = "2025-11-28T10:23:21.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/0e/e27cf7ce1bebb47fb95e1d6deae5c91c6ffcb7851f156990e57079cbe8db/pytoniq_core-0.1.46-py3-none-any.whl", hash = "sha256:0a284c8b68f9fed9d54e4dad871238d844339183bf985a614796360e36e1b95e", size = 91400, upload-time = "2025-11-28T10:23:20.95Z" }, +] + [[package]] name = "pyunormalize" version = "17.0.0" @@ -1960,6 +2061,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/b7/b95708304cd49b7b6f82fdd039f1748b66ec2b21d6a45180910802f1abf1/rpds_py-0.30.0-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:ac37f9f516c51e5753f27dfdef11a88330f04de2d564be3991384b2f3535d02e", size = 562191, upload-time = "2025-11-30T20:24:36.853Z" }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + [[package]] name = "sse-starlette" version = "3.2.0" @@ -2135,9 +2245,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] +[[package]] +name = "x25519" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/b6/fca895aff0800cdf941f856df0685a5513094163664b904576e3e3ef1460/x25519-0.0.2.tar.gz", hash = "sha256:ed91d0aba7f4f4959ed8b37118c11d94f56d36c38bb6f2e6c20d0438d75b1556", size = 4833, upload-time = "2021-10-24T15:18:38.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d1/66c637eb8e7a9601675bf7f04bb9a3015358a0f49e4c31d29a2b9a9d72d9/x25519-0.0.2-py3-none-any.whl", hash = "sha256:5c0833260a548bea9137a5a1b5c30334b751a59d148a62832df0c9e7b919ce99", size = 4907, upload-time = "2021-10-24T15:18:36.727Z" }, +] + [[package]] name = "x402" -version = "2.5.0" +version = "2.8.0" source = { editable = "../../../python/x402" } dependencies = [ { name = "nest-asyncio" }, @@ -2156,6 +2275,12 @@ evm = [ mcp = [ { name = "mcp" }, ] +tvm = [ + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, +] [package.metadata] requires-dist = [ @@ -2166,22 +2291,26 @@ requires-dist = [ { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.115.0" }, { name = "flask", marker = "extra == 'flask'", specifier = ">=3.0.0" }, { name = "httpx", marker = "extra == 'httpx'", specifier = ">=0.28.1" }, + { name = "httpx", marker = "extra == 'tvm'", specifier = ">=0.28.1" }, { name = "jsonschema", marker = "extra == 'extensions'", specifier = ">=4.0.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pynacl", marker = "extra == 'tvm'", specifier = ">=1.5.0" }, + { name = "pytoniq", marker = "extra == 'tvm'", specifier = ">=0.1.39" }, + { name = "pytoniq-core", marker = "extra == 'tvm'", specifier = ">=0.1.36" }, { name = "requests", marker = "extra == 'requests'", specifier = ">=2.31.0" }, { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0" }, { name = "solders", marker = "extra == 'svm'", specifier = ">=0.27.0" }, { name = "starlette", marker = "extra == 'fastapi'", specifier = ">=0.27.0" }, { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "web3", marker = "extra == 'evm'", specifier = ">=7.0.0" }, - { name = "x402", extras = ["evm", "svm"], marker = "extra == 'mechanisms'" }, + { name = "x402", extras = ["evm", "svm", "tvm"], marker = "extra == 'mechanisms'" }, { name = "x402", extras = ["flask", "fastapi"], marker = "extra == 'servers'" }, { name = "x402", extras = ["httpx", "requests"], marker = "extra == 'clients'" }, - { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions"], marker = "extra == 'all'" }, + { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions"], marker = "extra == 'all'" }, ] -provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] +provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] [package.metadata.requires-dev] dev = [ @@ -2197,8 +2326,11 @@ dev = [ { name = "mcp", specifier = ">=1.26.0" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, + { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytest", specifier = ">=7.0.0" }, { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytoniq", specifier = ">=0.1.39" }, + { name = "pytoniq-core", specifier = ">=0.1.36" }, { name = "requests", specifier = ">=2.31.0" }, { name = "ruff", specifier = ">=0.1.0" }, { name = "solana", specifier = ">=0.36.0" }, @@ -2217,7 +2349,7 @@ dependencies = [ { name = "python-dotenv" }, { name = "starlette" }, { name = "uvicorn" }, - { name = "x402", extra = ["evm", "mcp"] }, + { name = "x402", extra = ["evm", "mcp", "tvm"] }, ] [package.metadata] @@ -2226,7 +2358,7 @@ requires-dist = [ { name = "python-dotenv", specifier = ">=1.0.0" }, { name = "starlette", specifier = ">=0.27.0" }, { name = "uvicorn", specifier = ">=0.24.0" }, - { name = "x402", extras = ["evm", "mcp"], editable = "../../../python/x402" }, + { name = "x402", extras = ["evm", "tvm", "mcp"], editable = "../../../python/x402" }, ] [[package]] diff --git a/e2e/servers/mcp-typescript/index.ts b/e2e/servers/mcp-typescript/index.ts index 6275a4f408..25b7b080b3 100644 --- a/e2e/servers/mcp-typescript/index.ts +++ b/e2e/servers/mcp-typescript/index.ts @@ -10,6 +10,7 @@ import { SSEServerTransport } from "@modelcontextprotocol/sdk/server/sse.js"; import { ExactEvmScheme } from "@x402/evm/exact/server"; import { createPaymentWrapper, x402ResourceServer } from "@x402/mcp"; import { HTTPFacilitatorClient } from "@x402/core/server"; +import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; import express from "express"; import { z } from "zod"; @@ -60,12 +61,28 @@ async function main(): Promise { extra: { name: "USDC", version: "2" }, }); - // Step 4: Create payment wrapper + // Step 4: Declare bazaar discovery extension for the weather tool + const weatherExtensions = declareDiscoveryExtension({ + toolName: "get_weather", + description: "Get current weather for a city. Requires payment of $0.001.", + transport: "sse", + inputSchema: { + type: "object", + properties: { + city: { type: "string", description: "The city name to get weather for" }, + }, + required: ["city"], + }, + }); + + // Step 5: Create payment wrapper with extensions const paidWeather = createPaymentWrapper(resourceServer, { accepts: weatherAccepts, + resource: { url: "mcp://tool/get_weather", description: "Get current weather for a city" }, + extensions: weatherExtensions, }); - // Step 5: Register tools + // Step 6: Register tools mcpServer.tool( "get_weather", "Get current weather for a city. Requires payment of $0.001.", diff --git a/e2e/servers/mcp-typescript/package.json b/e2e/servers/mcp-typescript/package.json index 67e35a8d31..60c6f1014e 100644 --- a/e2e/servers/mcp-typescript/package.json +++ b/e2e/servers/mcp-typescript/package.json @@ -13,6 +13,7 @@ "@modelcontextprotocol/sdk": "^1.15.1", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", + "@x402/extensions": "workspace:*", "@x402/mcp": "workspace:*", "express": "^4.18.2", "zod": "^3.24.4" @@ -20,6 +21,7 @@ "devDependencies": { "@eslint/js": "^9.24.0", "@types/express": "^5.0.1", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -27,8 +29,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/e2e/servers/mcp-typescript/test.config.json b/e2e/servers/mcp-typescript/test.config.json index f6d96954cf..5b83d8b598 100644 --- a/e2e/servers/mcp-typescript/test.config.json +++ b/e2e/servers/mcp-typescript/test.config.json @@ -4,14 +4,20 @@ "transport": "mcp", "language": "typescript", "x402Version": 2, + "extensions": [ + "bazaar" + ], "endpoints": [ { "path": "get_weather", "method": "tool", + "toolName": "get_weather", + "mcpTransport": "sse", "description": "Paid weather tool via MCP transport", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" }, { "path": "/health", diff --git a/e2e/servers/nethttp/README.md b/e2e/servers/nethttp/README.md index a5b9e3667f..3ae45a673c 100644 --- a/e2e/servers/nethttp/README.md +++ b/e2e/servers/nethttp/README.md @@ -23,12 +23,12 @@ This server demonstrates and tests the x402 net/http middleware with both EVM an ```go import ( "net/http" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - nethttpmw "github.com/coinbase/x402/go/http/nethttp" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" - "github.com/coinbase/x402/go/extensions/bazaar" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + nethttpmw "github.com/x402-foundation/x402/go/http/nethttp" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" + "github.com/x402-foundation/x402/go/extensions/bazaar" ) // Create ServeMux @@ -175,12 +175,12 @@ Content-Type: application/json ## Dependencies -- `github.com/coinbase/x402/go` - Core x402 -- `github.com/coinbase/x402/go/http` - HTTP integration -- `github.com/coinbase/x402/go/http/nethttp` - net/http middleware -- `github.com/coinbase/x402/go/mechanisms/evm` - EVM server -- `github.com/coinbase/x402/go/mechanisms/svm` - SVM server -- `github.com/coinbase/x402/go/extensions/bazaar` - Discovery extension +- `github.com/x402-foundation/x402/go` - Core x402 +- `github.com/x402-foundation/x402/go/http` - HTTP integration +- `github.com/x402-foundation/x402/go/http/nethttp` - net/http middleware +- `github.com/x402-foundation/x402/go/mechanisms/evm` - EVM server +- `github.com/x402-foundation/x402/go/mechanisms/svm` - SVM server +- `github.com/x402-foundation/x402/go/extensions/bazaar` - Discovery extension ## Implementation Highlights diff --git a/e2e/servers/nethttp/batched_authorizer.go b/e2e/servers/nethttp/batched_authorizer.go new file mode 100644 index 0000000000..53e0f5ecb4 --- /dev/null +++ b/e2e/servers/nethttp/batched_authorizer.go @@ -0,0 +1,114 @@ +package main + +import ( + "context" + "crypto/ecdsa" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + "github.com/x402-foundation/x402/go/mechanisms/evm" +) + +// batchedAuthorizerSigner implements server.AuthorizerSigner using a local +// ECDSA key. Mirrors the example server's `signer.go`. Used when the e2e +// harness opts into self-managed receiver authorization via +// EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY. +type batchedAuthorizerSigner struct { + privateKey *ecdsa.PrivateKey + address common.Address +} + +func newBatchedAuthorizerSigner(privateKeyHex string) (*batchedAuthorizerSigner, error) { + pk, err := crypto.HexToECDSA(strings.TrimPrefix(privateKeyHex, "0x")) + if err != nil { + return nil, fmt.Errorf("parse private key: %w", err) + } + return &batchedAuthorizerSigner{ + privateKey: pk, + address: crypto.PubkeyToAddress(pk.PublicKey), + }, nil +} + +func (s *batchedAuthorizerSigner) Address() string { return s.address.Hex() } + +func (s *batchedAuthorizerSigner) SignTypedData( + _ context.Context, + domain evm.TypedDataDomain, + types map[string][]evm.TypedDataField, + primaryType string, + message map[string]interface{}, +) ([]byte, error) { + td := apitypes.TypedData{ + Types: apitypes.Types{}, + PrimaryType: primaryType, + Domain: apitypes.TypedDataDomain{ + Name: toStr(domain.Name), + Version: toStr(domain.Version), + ChainId: (*math.HexOrDecimal256)(toBig(domain.ChainID)), + VerifyingContract: toStr(domain.VerifyingContract), + }, + Message: message, + } + for name, fields := range types { + conv := make([]apitypes.Type, len(fields)) + for i, f := range fields { + conv[i] = apitypes.Type{Name: f.Name, Type: f.Type} + } + td.Types[name] = conv + } + if _, ok := td.Types["EIP712Domain"]; !ok { + td.Types["EIP712Domain"] = []apitypes.Type{ + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + } + } + dataHash, err := td.HashStruct(td.PrimaryType, td.Message) + if err != nil { + return nil, fmt.Errorf("hash struct: %w", err) + } + domainSep, err := td.HashStruct("EIP712Domain", td.Domain.Map()) + if err != nil { + return nil, fmt.Errorf("hash domain: %w", err) + } + digest := crypto.Keccak256(append([]byte{0x19, 0x01}, append(domainSep, dataHash...)...)) + sig, err := crypto.Sign(digest, s.privateKey) + if err != nil { + return nil, fmt.Errorf("sign: %w", err) + } + sig[64] += 27 + return sig, nil +} + +func toStr(v interface{}) string { + switch s := v.(type) { + case string: + return s + case *string: + if s != nil { + return *s + } + } + return "" +} + +func toBig(v interface{}) *big.Int { + switch n := v.(type) { + case *big.Int: + return n + case int64: + return big.NewInt(n) + case string: + b, ok := new(big.Int).SetString(n, 10) + if ok { + return b + } + } + return big.NewInt(0) +} diff --git a/e2e/servers/nethttp/go.mod b/e2e/servers/nethttp/go.mod index acc801d29a..6988a87326 100644 --- a/e2e/servers/nethttp/go.mod +++ b/e2e/servers/nethttp/go.mod @@ -1,12 +1,13 @@ -module github.com/coinbase/x402/e2e/servers/nethttp +module github.com/x402-foundation/x402/e2e/servers/nethttp go 1.24.0 toolchain go1.24.1 require ( - github.com/coinbase/x402/go v0.0.0 + github.com/ethereum/go-ethereum v1.16.7 github.com/joho/godotenv v1.5.1 + github.com/x402-foundation/x402/go v0.0.0 ) require ( @@ -24,7 +25,6 @@ require ( github.com/deckarep/golang-set/v2 v2.6.0 // indirect github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect - github.com/ethereum/go-ethereum v1.16.7 // indirect github.com/ethereum/go-verkle v0.2.2 // indirect github.com/fatih/color v1.16.0 // indirect github.com/gagliardetto/binary v0.8.0 // indirect @@ -64,4 +64,4 @@ require ( golang.org/x/time v0.14.0 // indirect ) -replace github.com/coinbase/x402/go => ../../../go +replace github.com/x402-foundation/x402/go => ../../../go diff --git a/e2e/servers/nethttp/main.go b/e2e/servers/nethttp/main.go index f3d13206e4..9a29f73dd4 100644 --- a/e2e/servers/nethttp/main.go +++ b/e2e/servers/nethttp/main.go @@ -9,17 +9,19 @@ import ( "syscall" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" - "github.com/coinbase/x402/go/extensions/types" - x402http "github.com/coinbase/x402/go/http" - nethttpmw "github.com/coinbase/x402/go/http/nethttp" - exactevm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - uptoevm "github.com/coinbase/x402/go/mechanisms/evm/upto/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/extensions/types" + x402http "github.com/x402-foundation/x402/go/http" + nethttpmw "github.com/x402-foundation/x402/go/http/nethttp" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + batchedserver "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/server" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) var shutdownRequested bool @@ -114,6 +116,24 @@ func main() { fmt.Printf("Warning: Failed to create bazaar extension: %v\n", err) } + // Batch-settlement scheme registration. Mirrors the TS express e2e server + // (no ChannelManager — settle actions are driven inline by the harness's + // BATCH_SETTLEMENT_PHASE flow). Optional self-managed receiver authorizer + // is wired through EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY. + batchedCfg := &batchedserver.BatchSettlementEvmSchemeServerConfig{} + if authKey := os.Getenv("EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY"); authKey != "" { + auth, err := newBatchedAuthorizerSigner(authKey) + if err != nil { + fmt.Printf("Failed to parse EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY: %v\n", err) + os.Exit(1) + } + batchedCfg.ReceiverAuthorizerSigner = auth + fmt.Printf("Batch-settlement receiver authorizer (self-managed): %s\n", auth.Address()) + } else { + fmt.Println("Batch-settlement receiver authorizer: facilitator-delegated") + } + batchedScheme := batchedserver.NewBatchSettlementEvmScheme(evmPayeeAddress, batchedCfg) + routes := x402http.RoutesConfig{ "GET /exact/evm/eip3009": { Accepts: x402http.PaymentOptions{ @@ -128,6 +148,65 @@ func main() { types.BAZAAR.Key(): discoveryExtension, }, }, + "GET /batch-settlement/evm/eip3009": { + Accepts: x402http.PaymentOptions{ + { + Scheme: batchsettlement.SchemeBatched, + PayTo: evmPayeeAddress, + Price: "$0.001", + Network: evmNetwork, + }, + }, + }, + "GET /batch-settlement/evm/permit2": { + Accepts: x402http.PaymentOptions{ + { + Scheme: batchsettlement.SchemeBatched, + PayTo: evmPayeeAddress, + Network: evmNetwork, + Price: map[string]interface{}{ + "amount": "1000", + "asset": evmPermit2Asset, + "extra": map[string]interface{}{ + "assetTransferMethod": "permit2", + "name": "USDC", + "version": "2", + }, + }, + }, + }, + }, + "GET /batch-settlement/evm/permit2-eip2612GasSponsoring": { + Accepts: x402http.PaymentOptions{ + { + Scheme: batchsettlement.SchemeBatched, + PayTo: evmPayeeAddress, + Network: evmNetwork, + Price: "$0.001", + Extra: map[string]interface{}{ + "assetTransferMethod": "permit2", + }, + }, + }, + Extensions: eip2612gassponsor.DeclareEip2612GasSponsoringExtension(), + }, + "GET /batch-settlement/evm/permit2-erc20ApprovalGasSponsoring": { + Accepts: x402http.PaymentOptions{ + { + Scheme: batchsettlement.SchemeBatched, + PayTo: evmPayeeAddress, + Network: evmNetwork, + Price: map[string]interface{}{ + "amount": "1000", + "asset": evmPermit2Asset, + "extra": map[string]interface{}{ + "assetTransferMethod": "permit2", + }, + }, + }, + }, + Extensions: erc20approvalgassponsor.DeclareExtension(), + }, "GET /exact/svm": { Accepts: x402http.PaymentOptions{ { @@ -347,6 +426,28 @@ func main() { }) }) + // Batch-settlement endpoints. Mirror express's batch-settlement routes: + // the harness drives deposit + voucher + recovery + refund inline via + // BATCH_SETTLEMENT_PHASE; the server only needs to register the scheme + // and respond once payment is verified. + batchHandler := func(method string) http.HandlerFunc { + return func(w http.ResponseWriter, r *http.Request) { + if shutdownRequested { + writeJSON(w, http.StatusServiceUnavailable, map[string]interface{}{"error": "Server shutting down"}) + return + } + writeJSON(w, http.StatusOK, map[string]interface{}{ + "message": "Batch-settlement endpoint accessed successfully", + "timestamp": time.Now().Format(time.RFC3339), + "method": method, + }) + } + } + mux.HandleFunc("GET /batch-settlement/evm/eip3009", batchHandler("batch-settlement-eip3009")) + mux.HandleFunc("GET /batch-settlement/evm/permit2", batchHandler("batch-settlement-permit2")) + mux.HandleFunc("GET /batch-settlement/evm/permit2-eip2612GasSponsoring", batchHandler("batch-settlement-permit2-eip2612")) + mux.HandleFunc("GET /batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", batchHandler("batch-settlement-permit2-erc20-approval")) + // Health check endpoint - no payment required mux.HandleFunc("GET /health", func(w http.ResponseWriter, r *http.Request) { writeJSON(w, http.StatusOK, map[string]interface{}{ @@ -382,6 +483,7 @@ func main() { Schemes: []nethttpmw.SchemeConfig{ {Network: evmNetwork, Server: exactevm.NewExactEvmScheme()}, {Network: evmNetwork, Server: uptoevm.NewUptoEvmScheme()}, + {Network: evmNetwork, Server: batchedScheme}, {Network: svmNetwork, Server: svm.NewExactSvmScheme()}, }, SyncFacilitatorOnStart: true, diff --git a/e2e/servers/nethttp/run.sh b/e2e/servers/nethttp/run.sh index 5f2f5f8501..168b1acfb4 100755 --- a/e2e/servers/nethttp/run.sh +++ b/e2e/servers/nethttp/run.sh @@ -1,2 +1,5 @@ #!/bin/bash -go run main.go +# `go run .` compiles the whole package (main.go + batched_authorizer.go), +# whereas `go run main.go` would only compile main.go and miss helper files +# in the same package, causing `undefined: newBatchedAuthorizerSigner` errors. +go run . diff --git a/e2e/servers/nethttp/test.config.json b/e2e/servers/nethttp/test.config.json index a77eb5bbb6..ddd11ae8ae 100644 --- a/e2e/servers/nethttp/test.config.json +++ b/e2e/servers/nethttp/test.config.json @@ -8,7 +8,12 @@ "eip2612GasSponsoring", "erc20ApprovalGasSponsoring" ], - "evm": { "transferMethods": ["eip3009", "permit2"] }, + "evm": { + "assetTransferMethods": [ + "eip3009", + "permit2" + ] + }, "description": "Go net/http server with x402 v2 payment middleware", "endpoints": [ { @@ -17,7 +22,56 @@ "description": "Protected endpoint requiring EIP-3009 payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" + }, + { + "path": "/batch-settlement/evm/eip3009", + "method": "GET", + "description": "Protected endpoint exercised by deposit + voucher + recovery voucher + cooperative refund", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "eip3009" + }, + { + "path": "/batch-settlement/evm/permit2", + "method": "GET", + "description": "Batch-settlement Permit2 direct endpoint (pre-approved Permit2)", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } + }, + { + "path": "/batch-settlement/evm/permit2-eip2612GasSponsoring", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with EIP-2612 gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } + }, + { + "path": "/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with ERC-20 approval gas sponsoring", + "requiresPayment": true, + "protocolFamily": "evm", + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2", @@ -25,8 +79,11 @@ "description": "Protected endpoint requiring Permit2 payment (standard settle, no gas sponsoring)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "permit2Direct": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/exact/evm/permit2-eip2612GasSponsoring", @@ -34,8 +91,11 @@ "description": "Protected endpoint requiring Permit2 payment with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "coldstart": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/exact/evm/permit2-erc20ApprovalGasSponsoring", @@ -43,9 +103,14 @@ "description": "Protected endpoint requiring Permit2 payment with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/upto/evm/permit2", @@ -53,8 +118,11 @@ "description": "Protected endpoint requiring upto Permit2 payment (usage-based settlement)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "permit2Direct": true + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/exact/svm", @@ -83,6 +151,8 @@ "SVM_PAYEE_ADDRESS", "FACILITATOR_URL" ], - "optional": [] + "optional": [ + "EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY" + ] } } diff --git a/e2e/servers/next/.env-local b/e2e/servers/next/.env-local index 4fb43f9906..69a9bab09b 100644 --- a/e2e/servers/next/.env-local +++ b/e2e/servers/next/.env-local @@ -1,5 +1,6 @@ PORT=3000 EVM_PAYEE_ADDRESS= SVM_PAYEE_ADDRESS= +HEDERA_PAYEE_ADDRESS= STELLAR_PAYEE_ADDRESS= FACILITATOR_URL=http://localhost:4000 diff --git a/e2e/servers/next/app/api/batch-settlement/evm/eip3009/withx402/route.ts b/e2e/servers/next/app/api/batch-settlement/evm/eip3009/withx402/route.ts new file mode 100644 index 0000000000..cebac6c6b5 --- /dev/null +++ b/e2e/servers/next/app/api/batch-settlement/evm/eip3009/withx402/route.ts @@ -0,0 +1,26 @@ +import { NextRequest, NextResponse } from "next/server"; +import { withX402 } from "@x402/next"; +import { server, EVM_PAYEE_ADDRESS, EVM_NETWORK } from "@/proxy"; + +const handler = async (_: NextRequest) => { + return NextResponse.json({ + message: "Batch-settlement endpoint accessed successfully (withX402)", + timestamp: new Date().toISOString(), + }); +}; + +/** + * Protected batch-settlement EVM endpoint using the withX402 wrapper. + */ +export const GET = withX402( + handler, + { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + price: "$0.001", + network: EVM_NETWORK, + }, + }, + server, +); diff --git a/e2e/servers/next/app/api/exact/avm/route.ts b/e2e/servers/next/app/api/exact/avm/route.ts new file mode 100644 index 0000000000..f8ffd88256 --- /dev/null +++ b/e2e/servers/next/app/api/exact/avm/route.ts @@ -0,0 +1,13 @@ +import { NextResponse } from "next/server"; + +/** + * AVM endpoint requiring payment (proxy middleware) + */ +export const runtime = "nodejs"; + +export async function GET() { + return NextResponse.json({ + message: "Protected endpoint accessed successfully", + timestamp: new Date().toISOString(), + }); +} diff --git a/e2e/servers/next/app/api/exact/evm/eip3009/withx402/route.ts b/e2e/servers/next/app/api/exact/evm/eip3009/withx402/route.ts index 5edb0c1e1d..6ba4116d56 100644 --- a/e2e/servers/next/app/api/exact/evm/eip3009/withx402/route.ts +++ b/e2e/servers/next/app/api/exact/evm/eip3009/withx402/route.ts @@ -1,7 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { withX402 } from "@x402/next"; import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; -import { server, EVM_PAYEE_ADDRESS, EVM_NETWORK } from "../../../proxy"; +import { server, EVM_PAYEE_ADDRESS, EVM_NETWORK } from "@/proxy"; /** * Handler for the protected endpoint diff --git a/e2e/servers/next/app/api/exact/hedera/route.ts b/e2e/servers/next/app/api/exact/hedera/route.ts new file mode 100644 index 0000000000..af620721a9 --- /dev/null +++ b/e2e/servers/next/app/api/exact/hedera/route.ts @@ -0,0 +1,13 @@ +import { NextResponse } from "next/server"; + +/** + * Hedera endpoint requiring payment (proxy middleware) + */ +export const runtime = "nodejs"; + +export async function GET() { + return NextResponse.json({ + message: "Protected Hedera endpoint accessed successfully", + timestamp: new Date().toISOString(), + }); +} diff --git a/e2e/servers/next/app/api/exact/hedera/withx402/route.ts b/e2e/servers/next/app/api/exact/hedera/withx402/route.ts new file mode 100644 index 0000000000..6a06b23a8c --- /dev/null +++ b/e2e/servers/next/app/api/exact/hedera/withx402/route.ts @@ -0,0 +1,64 @@ +import { NextRequest, NextResponse } from "next/server"; +import { withX402 } from "@x402/next"; +import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; +import { + server, + HEDERA_PAYEE_ADDRESS, + HEDERA_NETWORK, + HEDERA_ASSET, + HEDERA_AMOUNT, +} from "@/proxy"; + +/** + * Handler for the protected endpoint + */ +const handler = async (_: NextRequest) => { + return NextResponse.json({ + message: "Protected Hedera endpoint accessed successfully (withX402)", + timestamp: new Date().toISOString(), + }); +}; + +/** + * Protected Hedera endpoint using withX402 wrapper + * Only exported if HEDERA_PAYEE_ADDRESS is configured + */ +export const GET = HEDERA_PAYEE_ADDRESS + ? withX402( + handler, + { + accepts: { + payTo: HEDERA_PAYEE_ADDRESS, + scheme: "exact", + price: { + amount: HEDERA_AMOUNT, + asset: HEDERA_ASSET, + }, + network: HEDERA_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected Hedera endpoint accessed successfully (withX402)", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, + }, + required: ["message", "timestamp"], + }, + }, + }), + }, + }, + server, + ) + : async () => { + return NextResponse.json( + { error: "Hedera not configured" }, + { status: 503 }, + ); + }; diff --git a/e2e/servers/next/app/api/exact/stellar/withx402/route.ts b/e2e/servers/next/app/api/exact/stellar/withx402/route.ts index 7082891b44..c82e759f80 100644 --- a/e2e/servers/next/app/api/exact/stellar/withx402/route.ts +++ b/e2e/servers/next/app/api/exact/stellar/withx402/route.ts @@ -1,7 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { withX402 } from "@x402/next"; import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; -import { server, STELLAR_PAYEE_ADDRESS, STELLAR_NETWORK } from "../../../proxy"; +import { server, STELLAR_PAYEE_ADDRESS, STELLAR_NETWORK } from "@/proxy"; /** * Handler for the protected endpoint @@ -19,37 +19,37 @@ const handler = async (_: NextRequest) => { */ export const GET = STELLAR_PAYEE_ADDRESS ? withX402( - handler, - { - accepts: { - payTo: STELLAR_PAYEE_ADDRESS, - scheme: "exact", - price: "$0.001", - network: STELLAR_NETWORK, - }, - extensions: { - ...declareDiscoveryExtension({ - output: { - example: { - message: "Protected Stellar endpoint accessed successfully (withX402)", - timestamp: "2024-01-01T00:00:00Z", - }, - schema: { - properties: { - message: { type: "string" }, - timestamp: { type: "string" }, - }, - required: ["message", "timestamp"], + handler, + { + accepts: { + payTo: STELLAR_PAYEE_ADDRESS, + scheme: "exact", + price: "$0.001", + network: STELLAR_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected Stellar endpoint accessed successfully (withX402)", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, }, + required: ["message", "timestamp"], }, - }), - }, + }, + }), }, - server, - ) + }, + server, + ) : async () => { - return NextResponse.json( - { error: "Stellar not configured" }, - { status: 503 }, - ); - }; + return NextResponse.json( + { error: "Stellar not configured" }, + { status: 503 }, + ); + }; diff --git a/e2e/servers/next/app/api/exact/svm/withx402/route.ts b/e2e/servers/next/app/api/exact/svm/withx402/route.ts index ea63bc43c2..d41d420d17 100644 --- a/e2e/servers/next/app/api/exact/svm/withx402/route.ts +++ b/e2e/servers/next/app/api/exact/svm/withx402/route.ts @@ -1,7 +1,7 @@ import { NextRequest, NextResponse } from "next/server"; import { withX402 } from "@x402/next"; import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; -import { server, SVM_PAYEE_ADDRESS, SVM_NETWORK } from "../../../proxy"; +import { server, SVM_PAYEE_ADDRESS, SVM_NETWORK } from "@/proxy"; /** * Handler for the protected endpoint diff --git a/e2e/servers/next/app/page.tsx b/e2e/servers/next/app/page.tsx index 34fc13970b..525ee5e445 100644 --- a/e2e/servers/next/app/page.tsx +++ b/e2e/servers/next/app/page.tsx @@ -1,5 +1,5 @@ import Link from 'next/link'; -import WordmarkCondensed from './assets/x402_wordmark_light.svg'; +import wordmarkCondensed from './assets/x402_wordmark_light.svg'; export default function Home() { return ( @@ -9,7 +9,7 @@ export default function Home() {
- + x402

Fullstack demo powered by Next.js diff --git a/e2e/servers/next/package.json b/e2e/servers/next/package.json index e709f385b2..a756e8652b 100644 --- a/e2e/servers/next/package.json +++ b/e2e/servers/next/package.json @@ -14,21 +14,22 @@ }, "dependencies": { "@x402/aptos": "workspace:*", + "@x402/avm": "workspace:*", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", + "@x402/hedera": "workspace:*", "@x402/extensions": "workspace:*", "@x402/next": "workspace:*", "@x402/stellar": "workspace:*", "@x402/svm": "workspace:*", - "@heroicons/react": "^2.2.0", "next": "^16.0.10", "react": "^19.2.3", "react-dom": "^19.2.3", - "viem": "^2.21.26" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", - "@types/node": "^20", + "@types/node": "^22.13.4", "@types/react": "^19", "@types/react-dom": "^19", "@typescript-eslint/eslint-plugin": "^8.29.1", @@ -44,6 +45,6 @@ "prettier": "3.5.2", "stream-browserify": "^3.0.0", "tailwindcss": "^3.4.1", - "typescript": "^5" + "typescript": "^5.7.3" } } diff --git a/e2e/servers/next/proxy.ts b/e2e/servers/next/proxy.ts index 8f5f877dd9..0f16f53857 100644 --- a/e2e/servers/next/proxy.ts +++ b/e2e/servers/next/proxy.ts @@ -2,9 +2,13 @@ import { paymentProxy } from "@x402/next"; import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server"; import { ExactEvmScheme } from "@x402/evm/exact/server"; import { UptoEvmScheme } from "@x402/evm/upto/server"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/server"; +import { privateKeyToAccount } from "viem/accounts"; import { ExactSvmScheme } from "@x402/svm/exact/server"; import { ExactAptosScheme } from "@x402/aptos/exact/server"; +import { ExactHederaScheme } from "@x402/hedera/exact/server"; import { ExactStellarScheme } from "@x402/stellar/exact/server"; +import { ExactAvmScheme } from "@x402/avm/exact/server"; import { bazaarResourceServerExtension, declareDiscoveryExtension } from "@x402/extensions/bazaar"; import { declareEip2612GasSponsoringExtension, @@ -13,12 +17,18 @@ import { export const EVM_PAYEE_ADDRESS = process.env.EVM_PAYEE_ADDRESS as `0x${string}`; export const SVM_PAYEE_ADDRESS = process.env.SVM_PAYEE_ADDRESS as string; +export const AVM_PAYEE_ADDRESS = process.env.AVM_PAYEE_ADDRESS as string; export const APTOS_PAYEE_ADDRESS = process.env.APTOS_PAYEE_ADDRESS as string; +export const HEDERA_PAYEE_ADDRESS = process.env.HEDERA_PAYEE_ADDRESS as string | undefined; export const STELLAR_PAYEE_ADDRESS = process.env.STELLAR_PAYEE_ADDRESS as string | undefined; export const EVM_NETWORK = (process.env.EVM_NETWORK || "eip155:84532") as `${string}:${string}`; export const SVM_NETWORK = (process.env.SVM_NETWORK || "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1") as `${string}:${string}`; +export const AVM_NETWORK = (process.env.AVM_NETWORK || "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=") as `${string}:${string}`; export const APTOS_NETWORK = (process.env.APTOS_NETWORK || "aptos:2") as `${string}:${string}`; +export const HEDERA_NETWORK = (process.env.HEDERA_NETWORK || "hedera:testnet") as `${string}:${string}`; +export const HEDERA_ASSET = process.env.HEDERA_ASSET ?? "0.0.0"; // 0.0.0 = HBAR or 0.0.429274 for USDC testnet +export const HEDERA_AMOUNT = process.env.HEDERA_AMOUNT ?? "100000"; // price in smallest units (tinybars or token decimals), defaults to 0.001 HBAR or 0.1 USDC export const STELLAR_NETWORK = (process.env.STELLAR_NETWORK || "stellar:testnet") as `${string}:${string}`; const EVM_PERMIT2_ASSET = process.env.EVM_PERMIT2_ASSET as `0x${string}`; @@ -40,12 +50,33 @@ if (mockFacilitatorUrl) { export const server = new x402ResourceServer(facilitatorClients); // Register server schemes +if (AVM_PAYEE_ADDRESS) { + server.register("algorand:*", new ExactAvmScheme()); +} server.register("eip155:*", new ExactEvmScheme()); server.register("eip155:*", new UptoEvmScheme()); + +// Register batch-settlement scheme for the EVM payee. +// e2e flow does NOT use ChannelManager — settle actions are handled inline. +const receiverAuthorizerPrivateKey = process.env.EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY as + | `0x${string}` + | undefined; +const receiverAuthorizerSigner = receiverAuthorizerPrivateKey + ? privateKeyToAccount(receiverAuthorizerPrivateKey) + : undefined; +server.register( + "eip155:*", + new BatchSettlementEvmScheme(EVM_PAYEE_ADDRESS, { + ...(receiverAuthorizerSigner ? { receiverAuthorizerSigner } : {}), + }), +); server.register("solana:*", new ExactSvmScheme()); if (APTOS_PAYEE_ADDRESS) { server.register("aptos:*", new ExactAptosScheme()); } +if (HEDERA_PAYEE_ADDRESS) { + server.register("hedera:*", new ExactHederaScheme()); +} if (STELLAR_PAYEE_ADDRESS) { server.register("stellar:*", new ExactStellarScheme()); } @@ -57,6 +88,59 @@ console.log(`Using remote facilitator at: ${facilitatorUrl}`); export const proxy = paymentProxy( { + "/api/batch-settlement/evm/eip3009/proxy": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + price: "$0.001", + network: EVM_NETWORK, + }, + }, + "/api/batch-settlement/evm/permit2/proxy": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: { + amount: "1000", + asset: EVM_PERMIT2_ASSET, + extra: { + assetTransferMethod: "permit2", + name: EVM_NETWORK == "eip155:84532" ? "USDC" : "USD Coin", + version: "2", + }, + }, + }, + }, + "/api/batch-settlement/evm/permit2-eip2612GasSponsoring/proxy": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: "$0.001", + extra: { assetTransferMethod: "permit2" }, + }, + extensions: { + ...declareEip2612GasSponsoringExtension(), + }, + }, + "/api/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring/proxy": { + accepts: { + payTo: EVM_PAYEE_ADDRESS, + scheme: "batch-settlement", + network: EVM_NETWORK, + price: { + amount: "1000", + asset: EVM_PERMIT2_ASSET, + extra: { + assetTransferMethod: "permit2", + }, + }, + }, + extensions: { + ...declareErc20ApprovalGasSponsoringExtension(), + }, + }, "/api/exact/evm/eip3009/proxy": { accepts: { payTo: EVM_PAYEE_ADDRESS, @@ -107,20 +191,81 @@ export const proxy = paymentProxy( }), }, }, + ...(AVM_PAYEE_ADDRESS + ? { + "/api/exact/avm": { + accepts: { + payTo: AVM_PAYEE_ADDRESS, + scheme: "exact", + price: "$0.001", + network: AVM_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected endpoint accessed successfully", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, + }, + required: ["message", "timestamp"], + }, + }, + }), + }, + }, + } + : {}), ...(APTOS_PAYEE_ADDRESS ? { - "/api/exact/aptos": { + "/api/exact/aptos": { + accepts: { + payTo: APTOS_PAYEE_ADDRESS, + scheme: "exact", + price: "$0.001", + network: APTOS_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected endpoint accessed successfully", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, + }, + required: ["message", "timestamp"], + }, + }, + }), + }, + }, + } + : {}), + ...(HEDERA_PAYEE_ADDRESS + ? { + "/api/exact/hedera": { accepts: { - payTo: APTOS_PAYEE_ADDRESS, + payTo: HEDERA_PAYEE_ADDRESS, scheme: "exact", - price: "$0.001", - network: APTOS_NETWORK, + price: { + amount: HEDERA_AMOUNT, + asset: HEDERA_ASSET, + }, + network: HEDERA_NETWORK, }, extensions: { ...declareDiscoveryExtension({ output: { example: { - message: "Protected endpoint accessed successfully", + message: "Protected Hedera endpoint accessed successfully", timestamp: "2024-01-01T00:00:00Z", }, schema: { @@ -138,32 +283,32 @@ export const proxy = paymentProxy( : {}), ...(STELLAR_PAYEE_ADDRESS ? { - "/api/exact/stellar": { - accepts: { - payTo: STELLAR_PAYEE_ADDRESS, - scheme: "exact", - price: "$0.001", - network: STELLAR_NETWORK, - }, - extensions: { - ...declareDiscoveryExtension({ - output: { - example: { - message: "Protected endpoint accessed successfully", - timestamp: "2024-01-01T00:00:00Z", - }, - schema: { - properties: { - message: { type: "string" }, - timestamp: { type: "string" }, - }, - required: ["message", "timestamp"], + "/api/exact/stellar": { + accepts: { + payTo: STELLAR_PAYEE_ADDRESS, + scheme: "exact", + price: "$0.001", + network: STELLAR_NETWORK, + }, + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + message: "Protected endpoint accessed successfully", + timestamp: "2024-01-01T00:00:00Z", + }, + schema: { + properties: { + message: { type: "string" }, + timestamp: { type: "string" }, }, + required: ["message", "timestamp"], }, - }), - }, + }, + }), }, - } + }, + } : {}), "/api/exact/evm/permit2/proxy": { accepts: { @@ -304,7 +449,9 @@ export const config = { matcher: [ "/api/exact/evm/eip3009/proxy", "/api/exact/svm", + "/api/exact/avm", "/api/exact/aptos", + "/api/exact/hedera", "/api/exact/stellar", "/api/exact/evm/permit2/proxy", "/api/exact/evm/permit2-eip2612GasSponsoring/proxy", @@ -312,5 +459,9 @@ export const config = { "/api/upto/evm/permit2", "/api/upto/evm/permit2-eip2612GasSponsoring", "/api/upto/evm/permit2-erc20ApprovalGasSponsoring", + "/api/batch-settlement/evm/eip3009/proxy", + "/api/batch-settlement/evm/permit2/proxy", + "/api/batch-settlement/evm/permit2-eip2612GasSponsoring/proxy", + "/api/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring/proxy", ], }; diff --git a/e2e/servers/next/test.config.json b/e2e/servers/next/test.config.json index be5db0dc67..bd9507ad08 100644 --- a/e2e/servers/next/test.config.json +++ b/e2e/servers/next/test.config.json @@ -3,8 +3,11 @@ "type": "server", "language": "typescript", "x402Version": 2, - "extensions": ["bazaar", "eip2612GasSponsoring", "erc20ApprovalGasSponsoring"], - + "extensions": [ + "bazaar", + "eip2612GasSponsoring", + "erc20ApprovalGasSponsoring" + ], "endpoints": [ { "path": "/api/exact/evm/eip3009/proxy", @@ -12,7 +15,8 @@ "description": "EVM EIP-3009 endpoint using proxy middleware", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" }, { "path": "/api/exact/evm/permit2/proxy", @@ -20,8 +24,11 @@ "description": "EVM Permit2 direct endpoint (standard settle, no gas sponsoring)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "permit2Direct": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/api/exact/evm/permit2-eip2612GasSponsoring/proxy", @@ -29,8 +36,11 @@ "description": "EVM Permit2 endpoint with EIP-2612 gas sponsoring using proxy middleware", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "coldstart": true + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/api/exact/evm/permit2-erc20ApprovalGasSponsoring/proxy", @@ -38,9 +48,14 @@ "description": "EVM Permit2 endpoint with ERC-20 approval gas sponsoring using proxy middleware", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/api/upto/evm/permit2", @@ -48,8 +63,11 @@ "description": "Protected Upto Permit2 endpoint (direct, client must pre-approve)", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "permit2Direct": true + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/api/upto/evm/permit2-eip2612GasSponsoring", @@ -57,8 +75,11 @@ "description": "Protected Upto Permit2 endpoint with EIP-2612 gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "coldstart": true + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/api/upto/evm/permit2-erc20ApprovalGasSponsoring", @@ -66,9 +87,14 @@ "description": "Protected Upto Permit2 endpoint with ERC-20 approval gas sponsoring", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "upto", - "extensions": ["erc20ApprovalGasSponsoring"], - "coldstart": true + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "upto", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } }, { "path": "/api/exact/svm", @@ -77,6 +103,13 @@ "requiresPayment": true, "protocolFamily": "svm" }, + { + "path": "/api/exact/avm", + "method": "GET", + "description": "AVM endpoint using proxy middleware", + "requiresPayment": true, + "protocolFamily": "avm" + }, { "path": "/api/exact/aptos", "method": "GET", @@ -84,6 +117,13 @@ "requiresPayment": true, "protocolFamily": "aptos" }, + { + "path": "/api/exact/hedera", + "method": "GET", + "description": "Hedera endpoint using proxy middleware", + "requiresPayment": true, + "protocolFamily": "hedera" + }, { "path": "/api/exact/stellar", "method": "GET", @@ -97,7 +137,65 @@ "description": "EVM EIP-3009 endpoint using withX402 wrapper", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" + }, + { + "path": "/api/batch-settlement/evm/eip3009/proxy", + "method": "GET", + "description": "Batch-settlement EVM endpoint (proxy middleware): deposit + voucher + recovery voucher + cooperative refund", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "eip3009" + }, + { + "path": "/api/batch-settlement/evm/permit2/proxy", + "method": "GET", + "description": "Batch-settlement Permit2 direct endpoint (proxy middleware, pre-approved Permit2)", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } + }, + { + "path": "/api/batch-settlement/evm/permit2-eip2612GasSponsoring/proxy", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with EIP-2612 gas sponsoring using proxy middleware", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } + }, + { + "path": "/api/batch-settlement/evm/permit2-erc20ApprovalGasSponsoring/proxy", + "method": "GET", + "description": "Batch-settlement Permit2 endpoint with ERC-20 approval gas sponsoring using proxy middleware", + "requiresPayment": true, + "protocolFamily": "evm", + "extensions": [ + "erc20ApprovalGasSponsoring" + ], + "scheme": "batch-settlement", + "assetTransferMethod": "permit2", + "schemeOptions": { + "coldstart": true + } + }, + { + "path": "/api/batch-settlement/evm/eip3009/withx402", + "method": "GET", + "description": "Batch-settlement EVM endpoint (withX402 wrapper): deposit + voucher + recovery voucher + cooperative refund", + "requiresPayment": true, + "protocolFamily": "evm", + "scheme": "batch-settlement", + "assetTransferMethod": "eip3009" }, { "path": "/api/exact/svm/withx402", @@ -106,6 +204,13 @@ "requiresPayment": true, "protocolFamily": "svm" }, + { + "path": "/api/exact/hedera/withx402", + "method": "GET", + "description": "Hedera endpoint using withX402 wrapper", + "requiresPayment": true, + "protocolFamily": "hedera" + }, { "path": "/api/exact/stellar/withx402", "method": "GET", @@ -127,7 +232,18 @@ } ], "environment": { - "required": ["PORT", "EVM_PAYEE_ADDRESS", "SVM_PAYEE_ADDRESS", "FACILITATOR_URL"], - "optional": ["APTOS_PAYEE_ADDRESS", "STELLAR_PAYEE_ADDRESS"] + "required": [ + "PORT", + "EVM_PAYEE_ADDRESS", + "SVM_PAYEE_ADDRESS", + "FACILITATOR_URL" + ], + "optional": [ + "AVM_PAYEE_ADDRESS", + "APTOS_PAYEE_ADDRESS", + "HEDERA_PAYEE_ADDRESS", + "STELLAR_PAYEE_ADDRESS", + "EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY" + ] } } diff --git a/e2e/servers/next/types/svg.d.ts b/e2e/servers/next/types/svg.d.ts index 12f38a6048..d2bae43c0f 100644 --- a/e2e/servers/next/types/svg.d.ts +++ b/e2e/servers/next/types/svg.d.ts @@ -1,5 +1,8 @@ declare module "*.svg" { - import React from "react"; - const SVG: React.FC>; - export default SVG; + const content: { + src: string; + height: number; + width: number; + }; + export default content; } diff --git a/e2e/servers/text-server-protocol.txt b/e2e/servers/text-server-protocol.txt index 956e573b0c..af4d20706a 100644 --- a/e2e/servers/text-server-protocol.txt +++ b/e2e/servers/text-server-protocol.txt @@ -21,17 +21,18 @@ Servers may declare which protocol extensions they support using the `extensions ## Coldstart Tests Some endpoints require special pre-test state setup before they can be exercised (e.g., revoking a Permit2 approval so that the gas-sponsoring extension path is triggered). This setup is expensive: it involves funding the client wallet, submitting on-chain transactions, and draining ETH back. -Endpoints that require this setup declare `"coldstart": true` in their test config. The test runner treats the **first** test for a given endpoint path within a combo as the "coldstart" test — it performs the full setup. Subsequent tests for the same endpoint path within the same combo skip the setup and run directly, exercising the "warm" (already-approved) code path. +Endpoints that require this setup set **`"coldstart": true`** inside **`schemeOptions`** on that endpoint. The test runner treats the **first** test for a given endpoint path within a combo as the "coldstart" test — it performs the full setup. Subsequent tests for the same endpoint path within the same combo skip the setup and run directly, exercising the "warm" (already-approved) code path. -All explicit gas sponsorship extension endpoints (EIP-2612 and ERC-20 approval) should have `coldstart` enabled, as they must succeed without the user having gas or approval ahead of time. +All explicit gas sponsorship extension endpoints (EIP-2612 and ERC-20 approval) should have **`coldstart`** enabled under **`schemeOptions`**, as they must succeed without the user having gas or approval ahead of time. -## EVM Transfer Method -For EVM endpoints, servers must declare the `transferMethod` used for the payment transfer: -- **eip3009**: EIP-3009 transferWithAuthorization (default if omitted) -- **permit2**: Uniswap Permit2 approval-based transfer +## EVM scheme and asset transfer method +For EVM paid endpoints, servers must declare: +- **`scheme`**: Payment scheme — **`exact`** (single settle), **`upto`** (usage-based settle), or **`batch-settlement`** (deposit + vouchers + refund). If omitted, the harness defaults to **`exact`**. +- **`assetTransferMethod`**: **`eip3009`** vs **`permit2`**. If omitted: **`upto`** endpoints default to **`permit2`** (no EIP-3009 path); **`exact`** and **`batch-settlement`** default to **`eip3009`**. +- **`schemeOptions`** (optional): Harness knobs as **`SchemeOptions`** — **`Permit2SchemeOptions`** (`permit2Direct`, `coldstart`) for exact/upto and the same optional Permit2 knobs for batch-settlement. +- **`BATCH_SETTLEMENT_RECOVERY`** (optional env): Defaults to enabled. Set to `false`, `0`, `no`, or `off` to run batch-settlement as deposit + voucher + refund without a fresh client process recovery step. -The `transferMethod` field is only applicable to endpoints with `"protocolFamily": "evm"`. -The test suite uses this field to ensure the client and facilitator both support the required transfer method before generating a test scenario. +These fields apply only when `"protocolFamily": "evm"`. Discovery matches **`assetTransferMethod`** against each client/facilitator’s `evm.assetTransferMethods`; **`scheme`** is used for filters such as `--schemes=`. Example configuration: ```json @@ -48,7 +49,8 @@ Example configuration: "description": "Protected endpoint requiring EIP-3009 payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" }, { "path": "/protected-permit2", @@ -56,7 +58,11 @@ Example configuration: "description": "Protected endpoint requiring Permit2 payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "permit2" + "scheme": "exact", + "assetTransferMethod": "permit2", + "schemeOptions": { + "permit2Direct": true + } }, { "path": "/health", @@ -82,7 +88,8 @@ Multi-protocol server example: "description": "Protected endpoint requiring EVM payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" }, { "path": "/svm-protected", diff --git a/e2e/src/cli/args.ts b/e2e/src/cli/args.ts index ec6332ff71..847f1bfcec 100644 --- a/e2e/src/cli/args.ts +++ b/e2e/src/cli/args.ts @@ -44,6 +44,7 @@ export function parseArgs(): ParsedArgs { arg.startsWith('--extensions=') || arg.startsWith('--versions=') || arg.startsWith('--families=') || + arg.startsWith('--schemes=') || arg.startsWith('--endpoints=') ); @@ -94,6 +95,7 @@ export function parseArgs(): ParsedArgs { const extensions = parseListArg(args, '--extensions'); const versions = parseListArg(args, '--versions')?.map(v => parseInt(v)); const families = parseListArg(args, '--families'); + const schemes = parseListArg(args, '--schemes'); const endpoints = parseListArg(args, '--endpoints'); return { @@ -109,6 +111,7 @@ export function parseArgs(): ParsedArgs { extensions, versions, protocolFamilies: families, + schemes, endpoints, }, showHelp: false, @@ -135,8 +138,8 @@ export function printHelp(): void { console.log(' pnpm test -v Interactive with verbose logging'); console.log(''); console.log('Network Selection:'); - console.log(' --testnet Use testnet networks (Base Sepolia + Solana Devnet)'); - console.log(' --mainnet Use mainnet networks (Base + Solana) ⚠️ Real funds!'); + console.log(' --testnet Use testnet networks'); + console.log(' --mainnet Use mainnet networks ⚠️ Real funds!'); console.log(' (If not specified, will prompt in interactive mode)'); console.log(''); console.log('Programmatic Mode (for CI/workflows):'); @@ -146,7 +149,8 @@ export function printHelp(): void { console.log(' --clients= Comma-separated client names'); console.log(' --extensions= Comma-separated extensions (e.g., bazaar)'); console.log(' --versions= Comma-separated version numbers (e.g., 1,2)'); - console.log(' --families= Comma-separated protocol families (e.g., evm,svm)'); + console.log(' --families= Comma-separated protocol families (e.g., evm,svm,hedera,tvm)'); + console.log(' --schemes= Payment schemes: exact, upto, batch-settlement'); console.log(' --endpoints= Comma-separated endpoint paths or regex patterns (auto-anchored)'); console.log(''); console.log('Options:'); @@ -168,6 +172,7 @@ export function printHelp(): void { console.log(' pnpm test --mainnet --facilitators=go --servers=express # Mainnet programmatic'); console.log(" pnpm test --testnet --endpoints='/protected' # Exact path match"); console.log(" pnpm test --testnet --endpoints='/protected-permit2.*' # Regex: all permit2 routes"); + console.log(' pnpm test --testnet --schemes=exact,batch-settlement # Only those payment schemes'); console.log(' pnpm test --testnet --min --parallel -v # Parallel mode'); console.log(' pnpm test --testnet --min --parallel --concurrency=2 -v # Limited concurrency'); console.log(''); diff --git a/e2e/src/cli/filters.ts b/e2e/src/cli/filters.ts index bf300f3cd9..c60261d5fa 100644 --- a/e2e/src/cli/filters.ts +++ b/e2e/src/cli/filters.ts @@ -1,4 +1,23 @@ -import { TestScenario } from '../types'; +import { TestScenario, endpointPaymentScheme } from '../types'; + +/** x402 payment scheme for filtering (non-EVM counts as exact). */ +export type PaymentSchemeKind = 'exact' | 'upto' | 'batch-settlement'; + +/** + * Classify a scenario's payment scheme for filtering (`endpoint.scheme`, default `exact` on EVM). + */ +export function getScenarioPaymentScheme(scenario: TestScenario): PaymentSchemeKind { + if (scenario.protocolFamily !== 'evm') { + return 'exact'; + } + return endpointPaymentScheme(scenario.endpoint) ?? 'exact'; +} + +export function getUniquePaymentSchemes(scenarios: TestScenario[]): PaymentSchemeKind[] { + const set = new Set(); + scenarios.forEach(s => set.add(getScenarioPaymentScheme(s))); + return Array.from(set).sort(); +} export interface TestFilters { transports?: string[]; @@ -8,6 +27,7 @@ export interface TestFilters { extensions?: string[]; // For test output control (doesn't filter scenarios) versions?: number[]; protocolFamilies?: string[]; + schemes?: string[]; endpoints?: string[]; // Regex patterns to filter by endpoint path } @@ -65,6 +85,15 @@ export function filterScenarios( } } + // Payment scheme filter + if (filters.schemes && filters.schemes.length > 0) { + const normalized = filters.schemes.map(s => s.trim().toLowerCase()); + const kind = getScenarioPaymentScheme(scenario); + if (!normalized.includes(kind)) { + return false; + } + } + // Endpoint filter — each entry is treated as a regex pattern. // Patterns are auto-anchored (^...$) so that "/protected" matches only // that exact path. To match a prefix, use "/protected.*"; for a substring diff --git a/e2e/src/cli/interactive.ts b/e2e/src/cli/interactive.ts index db4eab771e..27c77dbe67 100644 --- a/e2e/src/cli/interactive.ts +++ b/e2e/src/cli/interactive.ts @@ -1,6 +1,14 @@ import prompts from 'prompts'; import { DiscoveredClient, DiscoveredServer, DiscoveredFacilitator, TestScenario } from '../types'; -import { TestFilters, getUniqueVersions, getUniqueProtocolFamilies } from './filters'; +import { + TestFilters, + filterScenarios, + getUniqueVersions, + getUniqueProtocolFamilies, + getUniquePaymentSchemes, + getScenarioPaymentScheme, + PaymentSchemeKind, +} from './filters'; import { log } from '../logger'; import { NetworkMode, getNetworkModeDescription } from '../networks/networks'; @@ -280,7 +288,44 @@ export async function runInteractiveMode( selectedFamilies = availableFamilies; } - // Question 8: Endpoint filter (optional free-text, comma-separated regex patterns) + // Question 8 (CONDITIONAL): Payment scheme — exact vs upto vs batch-settlement (EVM transfer semantics) + const scenariosForScheme = filterScenarios(preliminaryScenarios, { + versions: selectedVersions, + protocolFamilies: selectedFamilies, + }); + const availableSchemes = getUniquePaymentSchemes(scenariosForScheme); + let selectedSchemes: string[] | undefined; + + if (availableSchemes.length > 1) { + const schemeChoices = availableSchemes.map((k: PaymentSchemeKind) => { + const count = scenariosForScheme.filter(s => getScenarioPaymentScheme(s) === k).length; + return { + title: `${k} (${count} scenarios)`, + value: k, + selected: true, + }; + }); + + const schemesResponse = await prompts({ + type: 'multiselect', + name: 'schemes', + message: 'Select payment schemes', + choices: schemeChoices, + min: 1, + hint: 'exact = eip3009/permit2-style; upto = usage-based; batch-settlement = voucher channel', + instructions: false, + }); + + if (!schemesResponse.schemes || schemesResponse.schemes.length === 0) { + return null; + } + + selectedSchemes = schemesResponse.schemes; + } else if (availableSchemes.length === 1) { + selectedSchemes = availableSchemes; + } + + // Question 9: Endpoint filter (optional free-text, comma-separated regex patterns) const endpointsResponse = await prompts({ type: 'text', name: 'endpoints', @@ -297,7 +342,7 @@ export async function runInteractiveMode( ? (endpointsResponse.endpoints as string).split(',').map((p: string) => p.trim()).filter((p: string) => p.length > 0) : undefined; - // Question 9: Select network mode (testnet/mainnet) - LAST question + // Question 10: Select network mode (testnet/mainnet) - LAST question // Skip if preselected via CLI flag let networkMode: NetworkMode; @@ -346,6 +391,7 @@ export async function runInteractiveMode( extensions: selectedExtensions, versions: selectedVersions, protocolFamilies: selectedFamilies, + schemes: selectedSchemes, endpoints: selectedEndpoints, networkMode, }; diff --git a/e2e/src/clients/generic-client.ts b/e2e/src/clients/generic-client.ts index aff2ed44a0..6772d8fec0 100644 --- a/e2e/src/clients/generic-client.ts +++ b/e2e/src/clients/generic-client.ts @@ -18,17 +18,55 @@ export class GenericClientProxy extends BaseProxy implements ClientProxy { async call(config: ClientConfig): Promise { try { - const runConfig: RunConfig = { - env: { - EVM_PRIVATE_KEY: config.evmPrivateKey, - SVM_PRIVATE_KEY: config.svmPrivateKey, - APTOS_PRIVATE_KEY: config.aptosPrivateKey, - STELLAR_PRIVATE_KEY: config.stellarPrivateKey, - RESOURCE_SERVER_URL: config.serverUrl, - ENDPOINT_PATH: config.endpointPath, - EVM_NETWORK: config.evmNetwork, - EVM_RPC_URL: config.evmRpcUrl, + const baseEnv: Record = { + EVM_PRIVATE_KEY: config.evmPrivateKey, + SVM_PRIVATE_KEY: config.svmPrivateKey, + AVM_PRIVATE_KEY: config.avmPrivateKey, + APTOS_PRIVATE_KEY: config.aptosPrivateKey, + HEDERA_ACCOUNT_ID: config.hederaAccountId, + HEDERA_PRIVATE_KEY: config.hederaPrivateKey, + STELLAR_PRIVATE_KEY: config.stellarPrivateKey, + TVM_PRIVATE_KEY: config.tvmPrivateKey, + RESOURCE_SERVER_URL: config.serverUrl, + ENDPOINT_PATH: config.endpointPath, + EVM_NETWORK: config.evmNetwork, + EVM_RPC_URL: config.evmRpcUrl, + HEDERA_NETWORK: config.hederaNetwork, + HEDERA_NODE_URL: config.hederaNodeUrl, + TVM_NETWORK: config.tvmNetwork, + TVM_PROVIDER: process.env.TVM_PROVIDER || '', + TONCENTER_BASE_URL: process.env.TONCENTER_BASE_URL || config.tvmRpcUrl, + TONAPI_API_KEY: process.env.TONAPI_API_KEY || '', + TONAPI_BASE_URL: process.env.TONAPI_BASE_URL || '', + ...(config.batchSettlement + ? { + CHANNEL_SALT: config.batchSettlement.channelSalt, + BATCH_SETTLEMENT_PHASE: config.batchSettlement.phase, + ...(config.batchSettlement.voucherSignerPrivateKey + ? { EVM_VOUCHER_SIGNER_PRIVATE_KEY: config.batchSettlement.voucherSignerPrivateKey } + : {}), + } + : {}), + }; + + const clientConfig = this.loadConfig(); + if (clientConfig?.environment?.required) { + for (const envVar of clientConfig.environment.required) { + if (process.env[envVar] && !baseEnv[envVar]) { + baseEnv[envVar] = process.env[envVar]!; + } + } + } + if (clientConfig?.environment?.optional) { + for (const envVar of clientConfig.environment.optional) { + if (process.env[envVar] && !baseEnv[envVar]) { + baseEnv[envVar] = process.env[envVar]!; + } } + } + + const runConfig: RunConfig = { + env: baseEnv }; // For clients, we run the process and wait for it to complete @@ -71,4 +109,20 @@ export class GenericClientProxy extends BaseProxy implements ClientProxy { async forceStop(): Promise { await this.stopProcess(); } -} \ No newline at end of file + + private loadConfig(): any { + try { + const { readFileSync, existsSync } = require('fs'); + const { join } = require('path'); + const configPath = join(this.directory, 'test.config.json'); + + if (existsSync(configPath)) { + const configContent = readFileSync(configPath, 'utf-8'); + return JSON.parse(configContent); + } + } catch { + // Fall back to the explicitly provided env set when config loading fails. + } + return null; + } +} diff --git a/e2e/src/discovery.ts b/e2e/src/discovery.ts index 46ea72118b..9e200b5673 100644 --- a/e2e/src/discovery.ts +++ b/e2e/src/discovery.ts @@ -10,7 +10,9 @@ import { DiscoveredClient, DiscoveredFacilitator, TestScenario, - ProtocolFamily + ProtocolFamily, + endpointAssetTransferMethod, + endpointPaymentScheme, } from './types'; export class TestDiscovery { @@ -258,31 +260,45 @@ export class TestDiscovery { for (const endpoint of testableEndpoints) { const endpointProtocolFamily = endpoint.protocolFamily || 'evm'; + const endpointScheme = endpointPaymentScheme(endpoint); // Only create scenarios where client supports endpoint's protocol family if (!clientProtocolFamilies.includes(endpointProtocolFamily)) { continue; } - // For EVM endpoints, check transfer method compatibility with client + // For EVM endpoints, check the client supports the endpoint's + // payment scheme and asset transfer method. Both `schemes` and + // `evm.assetTransferMethods` must be declared explicitly on the + // client config — there is no implicit default. if (endpointProtocolFamily === 'evm') { - const endpointTransferMethod = endpoint.transferMethod || 'eip3009'; - const clientTransferMethods = client.config.evm?.transferMethods || ['eip3009']; - if (!clientTransferMethods.includes(endpointTransferMethod)) { - verboseLog(` ⚠️ Skipping ${client.name} ↔ ${server.name} ${endpoint.path}: Transfer method mismatch (client supports [${clientTransferMethods.join(', ')}], endpoint requires ${endpointTransferMethod})`); + const clientSchemes = client.config.schemes ?? []; + if (endpointScheme && !clientSchemes.includes(endpointScheme)) { + verboseLog(` ⚠️ Skipping ${client.name} ↔ ${server.name} ${endpoint.path}: Payment scheme mismatch (client supports [${clientSchemes.join(', ')}], endpoint requires ${endpointScheme})`); + continue; + } + const endpointAtm = endpointAssetTransferMethod(endpoint)!; + const clientAssetMethods = client.config.evm?.assetTransferMethods ?? []; + if (!clientAssetMethods.includes(endpointAtm)) { + verboseLog(` ⚠️ Skipping ${client.name} ↔ ${server.name} ${endpoint.path}: Asset transfer method mismatch (client supports [${clientAssetMethods.join(', ')}], endpoint requires ${endpointAtm})`); continue; } } - // Find facilitators that support this protocol family and version + // Find facilitators that support this protocol family, version, + // payment scheme, and asset transfer method. Facilitators must + // declare `schemes` and `evm.assetTransferMethods` explicitly. const matchingFacilitators = facilitators.filter(f => { const supportsProtocol = f.config.protocolFamilies?.includes(endpointProtocolFamily); const supportsVersion = f.config.x402Versions?.includes(serverVersion); - // For EVM, also check transfer method support if (endpointProtocolFamily === 'evm') { - const endpointTransferMethod = endpoint.transferMethod || 'eip3009'; - const facilTransferMethods = f.config.evm?.transferMethods || ['eip3009']; - if (!facilTransferMethods.includes(endpointTransferMethod)) return false; + const endpointAtm = endpointAssetTransferMethod(endpoint)!; + const facilAssetMethods = f.config.evm?.assetTransferMethods ?? []; + if (!facilAssetMethods.includes(endpointAtm)) return false; + if (endpointScheme) { + const facilSchemes = f.config.schemes ?? []; + if (!facilSchemes.includes(endpointScheme)) return false; + } } return supportsProtocol && supportsVersion; }); @@ -333,8 +349,8 @@ export class TestDiscovery { const protocolFamilies = client.config.protocolFamilies || ['evm']; const versions = client.config.x402Versions || [1]; const transport = client.config.transport || 'http'; - const evmTransferMethods = client.config.evm?.transferMethods || ['eip3009']; - const evmInfo = protocolFamilies.includes('evm') ? ` evm:${evmTransferMethods.join(',')}` : ''; + const evmAssetMethods = client.config.evm?.assetTransferMethods || ['eip3009']; + const evmInfo = protocolFamilies.includes('evm') ? ` evm:${evmAssetMethods.join(',')}` : ''; const extInfo = client.config.extensions ? ` {${client.config.extensions.join(', ')}}` : ''; verboseLog(` - ${client.name} (${client.config.language}) [${transport}] v[${versions.join(', ')}] [${protocolFamilies.join(', ')}]${evmInfo}${extInfo}`); }); @@ -347,8 +363,8 @@ export class TestDiscovery { regularFacilitators.forEach(facilitator => { const protocolFamilies = facilitator.config.protocolFamilies || ['evm']; const versions = facilitator.config.x402Versions || [2]; - const evmTransferMethods = facilitator.config.evm?.transferMethods || ['eip3009']; - const evmInfo = protocolFamilies.includes('evm') ? ` evm:${evmTransferMethods.join(',')}` : ''; + const evmAssetMethods = facilitator.config.evm?.assetTransferMethods || ['eip3009']; + const evmInfo = protocolFamilies.includes('evm') ? ` evm:${evmAssetMethods.join(',')}` : ''; verboseLog(` - ${facilitator.name} (${facilitator.config.language}) v[${versions.join(', ')}] [${protocolFamilies.join(', ')}]${evmInfo}`); }); @@ -357,8 +373,8 @@ export class TestDiscovery { externalFacilitators.forEach(facilitator => { const protocolFamilies = facilitator.config.protocolFamilies || ['evm']; const versions = facilitator.config.x402Versions || [2]; - const evmTransferMethods = facilitator.config.evm?.transferMethods || ['eip3009']; - const evmInfo = protocolFamilies.includes('evm') ? ` evm:${evmTransferMethods.join(',')}` : ''; + const evmAssetMethods = facilitator.config.evm?.assetTransferMethods || ['eip3009']; + const evmInfo = protocolFamilies.includes('evm') ? ` evm:${evmAssetMethods.join(',')}` : ''; verboseLog(` - ${facilitator.name} (${facilitator.config.language}) v[${versions.join(', ')}] [${protocolFamilies.join(', ')}]${evmInfo}`); }); } diff --git a/e2e/src/facilitators/facilitator-manager.ts b/e2e/src/facilitators/facilitator-manager.ts index e54be2da78..bb8e52e4f7 100644 --- a/e2e/src/facilitators/facilitator-manager.ts +++ b/e2e/src/facilitators/facilitator-manager.ts @@ -35,8 +35,12 @@ export class FacilitatorManager { port: this.port, evmPrivateKey: process.env.FACILITATOR_EVM_PRIVATE_KEY, svmPrivateKey: process.env.FACILITATOR_SVM_PRIVATE_KEY, + avmPrivateKey: process.env.FACILITATOR_AVM_PRIVATE_KEY, aptosPrivateKey: process.env.FACILITATOR_APTOS_PRIVATE_KEY, + hederaAccountId: process.env.FACILITATOR_HEDERA_ACCOUNT_ID, + hederaPrivateKey: process.env.FACILITATOR_HEDERA_PRIVATE_KEY, stellarPrivateKey: process.env.FACILITATOR_STELLAR_PRIVATE_KEY, + tvmPrivateKey: process.env.FACILITATOR_TVM_PRIVATE_KEY, networks, }); diff --git a/e2e/src/facilitators/generic-facilitator.ts b/e2e/src/facilitators/generic-facilitator.ts index 672f758a8a..58ed01d228 100644 --- a/e2e/src/facilitators/generic-facilitator.ts +++ b/e2e/src/facilitators/generic-facilitator.ts @@ -53,8 +53,12 @@ export interface FacilitatorConfig { port: number; evmPrivateKey?: string; svmPrivateKey?: string; + avmPrivateKey?: string; aptosPrivateKey?: string; + hederaAccountId?: string; + hederaPrivateKey?: string; stellarPrivateKey?: string; + tvmPrivateKey?: string; networks: NetworkSet; } @@ -114,18 +118,31 @@ export class GenericFacilitatorProxy extends BaseProxy implements FacilitatorPro PORT: config.port.toString(), EVM_PRIVATE_KEY: config.evmPrivateKey || '', SVM_PRIVATE_KEY: config.svmPrivateKey || '', + AVM_PRIVATE_KEY: config.avmPrivateKey || '', APTOS_PRIVATE_KEY: config.aptosPrivateKey || '', + HEDERA_ACCOUNT_ID: config.hederaAccountId || '', + HEDERA_PRIVATE_KEY: config.hederaPrivateKey || '', STELLAR_PRIVATE_KEY: config.stellarPrivateKey || '', + TVM_PRIVATE_KEY: config.tvmPrivateKey || '', // Network configs from NetworkSet EVM_NETWORK: config.networks.evm.caip2, EVM_RPC_URL: config.networks.evm.rpcUrl, SVM_NETWORK: config.networks.svm.caip2, SVM_RPC_URL: config.networks.svm.rpcUrl, + AVM_NETWORK: config.networks.avm.caip2, + AVM_RPC_URL: config.networks.avm.rpcUrl, APTOS_NETWORK: config.networks.aptos.caip2, APTOS_RPC_URL: config.networks.aptos.rpcUrl, + HEDERA_NETWORK: config.networks.hedera.caip2, + HEDERA_NODE_URL: config.networks.hedera.rpcUrl, STELLAR_NETWORK: config.networks.stellar.caip2, STELLAR_RPC_URL: config.networks.stellar.rpcUrl, + TVM_NETWORK: config.networks.tvm.caip2, + TVM_PROVIDER: process.env.TVM_PROVIDER || '', + TONCENTER_BASE_URL: process.env.TONCENTER_BASE_URL || config.networks.tvm.rpcUrl, + TONAPI_API_KEY: process.env.TONAPI_API_KEY || '', + TONAPI_BASE_URL: process.env.TONAPI_BASE_URL || '', }; // Pass through any additional environment variables required by the facilitator diff --git a/e2e/src/networks/networks.ts b/e2e/src/networks/networks.ts index 5d8441a1b6..472151990d 100644 --- a/e2e/src/networks/networks.ts +++ b/e2e/src/networks/networks.ts @@ -6,7 +6,7 @@ */ export type NetworkMode = 'testnet' | 'mainnet'; -export type ProtocolFamily = 'evm' | 'svm' | 'aptos' | 'stellar'; +export type ProtocolFamily = 'evm' | 'svm' | 'avm' | 'aptos' | 'hedera' | 'stellar' | 'tvm'; export type NetworkConfig = { name: string; @@ -18,8 +18,11 @@ export type NetworkConfig = { export type NetworkSet = { evm: NetworkConfig; svm: NetworkConfig; + avm: NetworkConfig; aptos: NetworkConfig; + hedera: NetworkConfig; stellar: NetworkConfig; + tvm: NetworkConfig; }; /** @@ -38,16 +41,31 @@ const NETWORK_SETS: Record = { caip2: 'solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1', rpcUrl: process.env.SOLANA_DEVNET_RPC_URL || 'https://api.devnet.solana.com', }, + avm: { + name: 'Algorand Testnet', + caip2: 'algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=', + rpcUrl: process.env.AVM_TESTNET_RPC_URL || 'https://testnet-api.4160.nodely.dev', + }, aptos: { name: 'Aptos Testnet', caip2: 'aptos:2', rpcUrl: process.env.APTOS_TESTNET_RPC_URL || 'https://fullnode.testnet.aptoslabs.com/v1', }, + hedera: { + name: 'Hedera Testnet', + caip2: 'hedera:testnet', + rpcUrl: process.env.HEDERA_TESTNET_NODE_URL || '', + }, stellar: { name: 'Stellar Testnet', caip2: 'stellar:testnet', rpcUrl: process.env.STELLAR_TESTNET_RPC_URL || 'https://soroban-testnet.stellar.org', }, + tvm: { + name: 'TON Testnet', + caip2: 'tvm:-3', + rpcUrl: process.env.TONCENTER_TESTNET_BASE_URL || 'https://testnet.toncenter.com', + }, }, mainnet: { evm: { @@ -61,16 +79,31 @@ const NETWORK_SETS: Record = { caip2: 'solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp', rpcUrl: process.env.SOLANA_RPC_URL || 'https://api.mainnet-beta.solana.com', }, + avm: { + name: 'Algorand Mainnet', + caip2: 'algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=', + rpcUrl: process.env.AVM_RPC_URL || 'https://mainnet-api.4160.nodely.dev', + }, aptos: { name: 'Aptos', caip2: 'aptos:1', rpcUrl: process.env.APTOS_RPC_URL || 'https://fullnode.mainnet.aptoslabs.com/v1', }, + hedera: { + name: 'Hedera Mainnet', + caip2: 'hedera:mainnet', + rpcUrl: process.env.HEDERA_NODE_URL || '', + }, stellar: { name: 'Stellar Pubnet', caip2: 'stellar:pubnet', rpcUrl: process.env.STELLAR_RPC_URL || 'https://mainnet.sorobanrpc.com', }, + tvm: { + name: 'TON Mainnet', + caip2: 'tvm:-239', + rpcUrl: process.env.TONCENTER_MAINNET_BASE_URL || 'https://toncenter.com', + }, }, }; @@ -78,17 +111,34 @@ const NETWORK_SETS: Record = { * Get the network set for a given mode * * @param mode - 'testnet' or 'mainnet' - * @returns NetworkSet containing EVM, SVM, and Aptos network configs + * @returns NetworkSet containing configured protocol network configs */ export function getNetworkSet(mode: NetworkMode): NetworkSet { return NETWORK_SETS[mode]; } +/** + * Permit2-priced routes read `process.env.EVM_PERMIT2_ASSET` in server processes. + * Use the same resolution here and when spawning resource servers (`generic-server`) + * so cold-start revoke/approve targets the token those routes bill. + * + * Precedence: non-empty `EVM_PERMIT2_ASSET`, then `networks.evm.permit2Asset`. + * When the env var is unset, defaults are Base Sepolia USDC (`eip155:84532`) and + * Base mainnet USDC (`eip155:8453`) from {@link NETWORK_SETS}. + */ +export function resolveEvmPermit2Asset(networks: NetworkSet): string { + const fromEnv = process.env.EVM_PERMIT2_ASSET?.trim(); + if (fromEnv) { + return fromEnv; + } + return (networks.evm.permit2Asset ?? '').trim(); +} + /** * Get network config for a protocol family in a given mode * * @param mode - 'testnet' or 'mainnet' - * @param protocolFamily - 'evm', 'svm', 'aptos', or 'stellar' + * @param protocolFamily - 'evm', 'svm', 'avm', 'aptos', 'hedera', 'stellar', or 'tvm' * @returns NetworkConfig for the specified protocol */ export function getNetworkForProtocol( @@ -106,6 +156,6 @@ export function getNetworkForProtocol( */ export function getNetworkModeDescription(mode: NetworkMode): string { const set = NETWORK_SETS[mode]; - const networks = [set.evm.name, set.svm.name, set.aptos.name, set.stellar.name]; + const networks = [set.evm.name, set.svm.name, set.avm.name, set.aptos.name, set.hedera.name, set.stellar.name, set.tvm.name]; return networks.join(' + '); } diff --git a/e2e/src/proxy-base.ts b/e2e/src/proxy-base.ts index b7312e2762..fcc3f908bc 100644 --- a/e2e/src/proxy-base.ts +++ b/e2e/src/proxy-base.ts @@ -1,5 +1,5 @@ import { spawn, ChildProcess } from 'child_process'; -import { readFileSync, existsSync } from 'fs'; +import { existsSync } from 'fs'; import { join } from 'path'; import { log, verboseLog, errorLog } from './logger'; @@ -35,33 +35,7 @@ export abstract class BaseProxy { throw new Error(`run.sh not found in ${this.directory}`); } - const runShContent = readFileSync(runShPath, 'utf-8'); - - // Parse the run.sh file to extract the command - // Look for lines that start with commands like pnpm, npm, node, python, etc. - const lines = runShContent.split('\n'); - - for (const line of lines) { - const trimmed = line.trim(); - - // Skip comments and empty lines - if (trimmed.startsWith('#') || trimmed === '') continue; - - // Look for command patterns - if (trimmed.startsWith('pnpm ') || - trimmed.startsWith('npm ') || - trimmed.startsWith('node ') || - trimmed.startsWith('python ') || - trimmed.startsWith('uv run ') || - trimmed.startsWith('go run ')) { - - // Split the command into parts - const parts = trimmed.split(' '); - return parts; - } - } - - throw new Error(`No valid command found in ${runShPath}`); + return ['bash', 'run.sh']; } protected async startProcess(config: RunConfig): Promise { @@ -218,4 +192,4 @@ export abstract class BaseProxy { }); }); } -} \ No newline at end of file +} diff --git a/e2e/src/sampling.ts b/e2e/src/sampling.ts index 0c8dfb8441..dc719b4f41 100644 --- a/e2e/src/sampling.ts +++ b/e2e/src/sampling.ts @@ -1,4 +1,4 @@ -import { TestScenario } from './types'; +import { TestScenario, endpointAssetTransferMethod, endpointPaymentScheme } from './types'; import { log, verboseLog } from './logger'; /** @@ -31,13 +31,22 @@ export class CoverageTracker { /** * Generate a coverage key for an endpoint - * Format: "server-name-endpoint-path-protocolFamily-transferMethod-vVersion" - * + * Format: "server-name-endpoint-path-protocolFamily-scheme-assetMethod-vVersion" + * * This ensures each unique endpoint on a server is tested separately, - * including different EVM transfer methods (eip3009 vs permit2). + * including different EVM schemes and asset transfer methods. */ - private getEndpointCoverageKey(serverName: string, endpointPath: string, protocolFamily: string, version: number, transferMethod?: string): string { - const method = protocolFamily === 'evm' ? (transferMethod || 'eip3009') : ''; + private getEndpointCoverageKey( + serverName: string, + endpointPath: string, + protocolFamily: string, + version: number, + scenario: TestScenario, + ): string { + const method = + protocolFamily === 'evm' + ? `${endpointPaymentScheme(scenario.endpoint) ?? 'exact'}-${endpointAssetTransferMethod(scenario.endpoint) ?? 'eip3009'}` + : ''; return `${serverName}-${endpointPath}-${protocolFamily}${method ? `-${method}` : ''}-v${version}`; } @@ -77,7 +86,7 @@ export class CoverageTracker { scenario.endpoint.path, protocolFamily, version, - scenario.endpoint.transferMethod + scenario, ); // Check if ANY component hasn't been covered yet @@ -125,7 +134,7 @@ export class CoverageTracker { scenario.endpoint.path, protocolFamily, version, - scenario.endpoint.transferMethod + scenario, ); this.clientsCovered.add(clientKey); diff --git a/e2e/src/servers/generic-server.ts b/e2e/src/servers/generic-server.ts index f769dbed0d..3d1d63ca0b 100644 --- a/e2e/src/servers/generic-server.ts +++ b/e2e/src/servers/generic-server.ts @@ -1,6 +1,7 @@ import { BaseProxy, RunConfig } from '../proxy-base'; import { ServerProxy, ServerConfig } from '../types'; import { verboseLog, errorLog } from '../logger'; +import { resolveEvmPermit2Asset } from '../networks/networks'; export interface ProtectedResponse { message: string; @@ -73,8 +74,8 @@ export class GenericServerProxy extends BaseProxy implements ServerProxy { verboseLog(` 📂 Server directory: ${this.directory}, isV1: ${isV1Server}`); // For legacy servers, translate CAIP-2 to v1 network names - let evmNetwork = config.networks.evm.caip2; - let svmNetwork = config.networks.svm.caip2; + let evmNetwork: string = config.networks.evm.caip2; + let svmNetwork: string = config.networks.svm.caip2; if (isV1Server) { evmNetwork = translateNetworkForV1(config.networks.evm.caip2); @@ -92,26 +93,52 @@ export class GenericServerProxy extends BaseProxy implements ServerProxy { EVM_NETWORK: evmNetwork, EVM_RPC_URL: config.networks.evm.rpcUrl, EVM_PAYEE_ADDRESS: config.evmPayTo, - EVM_PERMIT2_ASSET: config.networks.evm.permit2Asset || '', + EVM_PERMIT2_ASSET: resolveEvmPermit2Asset(config.networks), // SVM network config SVM_NETWORK: svmNetwork, SVM_RPC_URL: config.networks.svm.rpcUrl, SVM_PAYEE_ADDRESS: config.svmPayTo, + // AVM network config + AVM_NETWORK: config.networks.avm.caip2, + AVM_RPC_URL: config.networks.avm.rpcUrl, + AVM_PAYEE_ADDRESS: config.avmPayTo, + // Aptos network config APTOS_NETWORK: config.networks.aptos.caip2, APTOS_RPC_URL: config.networks.aptos.rpcUrl, APTOS_PAYEE_ADDRESS: config.aptosPayTo, + // Hedera network config. HEDERA_ASSET / HEDERA_AMOUNT are only + // forwarded when set by the caller; the resource servers apply their + // own HBAR defaults (0.0.0 / 100000 tinybars) when absent, so passing + // an empty string here would clobber those defaults. + HEDERA_NETWORK: config.networks.hedera.caip2, + HEDERA_NODE_URL: config.networks.hedera.rpcUrl, + HEDERA_PAYEE_ADDRESS: config.hederaPayTo, + ...(config.hederaAsset !== undefined ? { HEDERA_ASSET: config.hederaAsset } : {}), + ...(config.hederaAmount !== undefined ? { HEDERA_AMOUNT: config.hederaAmount } : {}), + // Stellar network config STELLAR_NETWORK: config.networks.stellar.caip2, STELLAR_RPC_URL: config.networks.stellar.rpcUrl, STELLAR_PAYEE_ADDRESS: config.stellarPayTo, + // TVM network config + TVM_NETWORK: config.networks.tvm.caip2, + TVM_PAYEE_ADDRESS: config.tvmPayTo, + // Facilitator FACILITATOR_URL: config.facilitatorUrl || '', MOCK_FACILITATOR_URL: config.mockFacilitatorUrl || '', + + ...(config.batchSettlement + ? { + EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY: + config.batchSettlement.receiverAuthorizerPrivateKey, + } + : {}), } }; diff --git a/e2e/src/types.ts b/e2e/src/types.ts index 841f200c39..f3a3698a9d 100644 --- a/e2e/src/types.ts +++ b/e2e/src/types.ts @@ -1,8 +1,51 @@ import type { NetworkSet } from './networks/networks'; -export type ProtocolFamily = 'evm' | 'svm' | 'aptos' | 'stellar'; +export type ProtocolFamily = 'evm' | 'svm' | 'avm' | 'aptos' | 'hedera' | 'stellar' | 'tvm'; export type Transport = 'http' | 'mcp'; -export type TransferMethod = 'eip3009' | 'permit2' | 'upto'; +export type PaymentScheme = 'exact' | 'upto' | 'batch-settlement'; +export type AssetTransferMethod = 'eip3009' | 'permit2'; + +/** + * Resolved asset transfer for an EVM endpoint. + */ +export function endpointAssetTransferMethod(endpoint: TestEndpoint): AssetTransferMethod | undefined { + const family = endpoint.protocolFamily ?? 'evm'; + if (family !== 'evm') { + return undefined; + } + if (endpoint.assetTransferMethod != null) { + return endpoint.assetTransferMethod; + } + const scheme = endpoint.scheme ?? 'exact'; + return scheme === 'upto' ? 'permit2' : 'eip3009'; +} + +/** + * Resolved payment scheme for an EVM endpoint. + * Defaults to `exact` when omitted (non-batch endpoints). + */ +export function endpointPaymentScheme(endpoint: TestEndpoint): PaymentScheme | undefined { + const family = endpoint.protocolFamily ?? 'evm'; + if (family !== 'evm') { + return undefined; + } + return endpoint.scheme ?? 'exact'; +} + +/** Harness knobs for exact / upto endpoints (Permit2 settle paths). */ +export interface Permit2SchemeOptions { + permit2Direct?: boolean; + coldstart?: boolean; +} + +/** Harness knobs for batch-settlement endpoints. */ +export type BatchSettlementSchemeOptions = Permit2SchemeOptions; + +export type SchemeOptions = Permit2SchemeOptions | BatchSettlementSchemeOptions; + +export function endpointUsesBatchSettlement(endpoint: TestEndpoint): boolean { + return endpoint.scheme === 'batch-settlement'; +} export interface ClientResult { success: boolean; @@ -12,26 +55,59 @@ export interface ClientResult { error?: string; } +/** Scheme-specific configs for a batch-settlement scenario. */ +export type BatchSettlementPhase = 'initial' | 'recovery-refund' | 'full'; + +export interface BatchSettlementClientConfig { + /** Per-scenario unique salt that derives the onchain channel id (avoids collisions across runs). */ + channelSalt: string; + /** Fixed e2e phase to run for this one-shot client process. */ + phase: BatchSettlementPhase; + /** Optional alternate EOA used to sign vouchers (deposits still use the main client signer). */ + voucherSignerPrivateKey?: string; +} + +/** Scheme-specific knobs the harness forwards to a server for a batch-settlement scenario. */ +export interface BatchSettlementServerConfig { + /** Optional EOA private key the server uses as a self-managed receiver authorizer. */ + receiverAuthorizerPrivateKey: string; +} + export interface ClientConfig { evmPrivateKey: string; svmPrivateKey: string; + avmPrivateKey: string; aptosPrivateKey: string; + hederaAccountId: string; + hederaPrivateKey: string; stellarPrivateKey: string; + tvmPrivateKey: string; serverUrl: string; endpointPath: string; evmNetwork: string; evmRpcUrl: string; + hederaNetwork: string; + hederaNodeUrl: string; + tvmNetwork: string; + tvmRpcUrl: string; + batchSettlement?: BatchSettlementClientConfig; } export interface ServerConfig { port: number; evmPayTo: string; svmPayTo: string; + avmPayTo: string; aptosPayTo: string; + hederaPayTo: string; + hederaAsset?: string; + hederaAmount?: string; stellarPayTo: string; + tvmPayTo: string; networks: NetworkSet; facilitatorUrl?: string; mockFacilitatorUrl?: string; + batchSettlement?: BatchSettlementServerConfig; } export interface ServerProxy { @@ -52,12 +128,14 @@ export interface TestEndpoint { description: string; requiresPayment?: boolean; protocolFamily?: ProtocolFamily; - transferMethod?: TransferMethod; + scheme?: PaymentScheme; + assetTransferMethod?: AssetTransferMethod; + schemeOptions?: SchemeOptions; extensions?: string[]; - /** True for Permit2 standard/direct settle - requires pre-approval (approve before test, not revoke) */ - permit2Direct?: boolean; - /** True for endpoints that require Permit2 revocation + fund/drain state setup before the first test (coldstart). */ - coldstart?: boolean; + /** For MCP tools: the tool name used in tools/call. Defaults to path if not specified. */ + toolName?: string; + /** For MCP tools: expected MCP wire transport for discovery metadata. */ + mcpTransport?: 'streamable-http' | 'sse'; health?: boolean; close?: boolean; } @@ -71,8 +149,14 @@ export interface TestConfig { x402Version?: number; x402Versions?: number[]; extensions?: string[]; + /** + * Payment schemes the component supports. Required on clients and + * facilitators that participate in EVM scenarios; the discovery filter + * skips pairings whose endpoint scheme is not in this list. + */ + schemes?: PaymentScheme[]; evm?: { - transferMethods: TransferMethod[]; + assetTransferMethods?: AssetTransferMethod[]; }; endpoints?: TestEndpoint[]; supportedMethods?: string[]; diff --git a/e2e/templates/server-ts/package.json b/e2e/templates/server-ts/package.json index 19ffe028f1..9b4d627c7e 100644 --- a/e2e/templates/server-ts/package.json +++ b/e2e/templates/server-ts/package.json @@ -9,12 +9,9 @@ "lint": "eslint . --ext .ts --fix", "lint:check": "eslint . --ext .ts" }, - "dependencies": { - "@x402/core": "workspace:*", - "dotenv": "^16.6.1" - }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -22,8 +19,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } -} \ No newline at end of file +} diff --git a/e2e/templates/server-ts/test.config.json b/e2e/templates/server-ts/test.config.json index 2747fb1714..f47ffdd804 100644 --- a/e2e/templates/server-ts/test.config.json +++ b/e2e/templates/server-ts/test.config.json @@ -13,7 +13,8 @@ "description": "Protected endpoint requiring payment", "requiresPayment": true, "protocolFamily": "evm", - "transferMethod": "eip3009" + "scheme": "exact", + "assetTransferMethod": "eip3009" }, { "path": "/health", @@ -36,4 +37,4 @@ ], "optional": [] } -} \ No newline at end of file +} diff --git a/e2e/templates/server/test.config.json b/e2e/templates/server/test.config.json index 33e32ba1da..7472a982bc 100644 --- a/e2e/templates/server/test.config.json +++ b/e2e/templates/server/test.config.json @@ -15,7 +15,8 @@ "description": "", "requiresPayment": true, "protocolFamily": "", - "transferMethod": " (EVM only)" + "scheme": " (EVM paid endpoints)", + "assetTransferMethod": "" }, { "path": "/health", @@ -39,4 +40,4 @@ ], "optional": [] } -} \ No newline at end of file +} diff --git a/e2e/test.ts b/e2e/test.ts index 4349597506..f278753bfd 100644 --- a/e2e/test.ts +++ b/e2e/test.ts @@ -2,34 +2,42 @@ import { config } from 'dotenv'; import { spawn, execSync, ChildProcess } from 'child_process'; import { writeFileSync } from 'fs'; import { join } from 'path'; -import { createWalletClient, createPublicClient, http, parseEther, formatEther } from 'viem'; +import { createWalletClient, createPublicClient, http, parseEther, formatEther, toHex } from 'viem'; import { privateKeyToAccount } from 'viem/accounts'; import { base, baseSepolia } from 'viem/chains'; import { TestDiscovery } from './src/discovery'; -import { ClientConfig, ScenarioResult, ServerConfig, TestScenario } from './src/types'; +import { ClientConfig, ScenarioResult, ServerConfig, TestScenario, endpointAssetTransferMethod, endpointPaymentScheme, endpointUsesBatchSettlement } from './src/types'; import { config as loggerConfig, log, verboseLog, errorLog, close as closeLogger, createComboLogger } from './src/logger'; import { handleDiscoveryValidation, shouldRunDiscoveryValidation } from './extensions/bazaar'; import { parseArgs, printHelp } from './src/cli/args'; import { runInteractiveMode } from './src/cli/interactive'; import { filterScenarios, TestFilters, shouldShowExtensionOutput } from './src/cli/filters'; import { minimizeScenarios } from './src/sampling'; -import { getNetworkSet, NetworkMode, NetworkSet, getNetworkModeDescription } from './src/networks/networks'; +import { getNetworkSet, NetworkMode, getNetworkModeDescription, resolveEvmPermit2Asset } from './src/networks/networks'; import { GenericServerProxy } from './src/servers/generic-server'; import { Semaphore, FacilitatorLock } from './src/concurrency'; import { FacilitatorManager } from './src/facilitators/facilitator-manager'; import { waitForHealth } from './src/health'; -// Base Sepolia token addresses used by permit2 E2E tests -const USDC_BASE_SEPOLIA = '0x036CbD53842c5426634e7929541eC2318f3dCF7e'; -const MOCK_ERC20_BASE_SEPOLIA = '0xeED520980fC7C7B4eB379B96d61CEdea2423005a'; +/** + * Generates a fresh 32-byte hex salt for a batch-settlement test scenario so + * concurrent runs don't collide on the same on-chain channel id. + * + * @returns Hex-encoded 32-byte salt prefixed with `0x`. + */ +function generateChannelSalt(): `0x${string}` { + const bytes = new Uint8Array(32); + crypto.getRandomValues(bytes); + return toHex(bytes); +} /** * Approve Permit2 so that the standard/direct settle path can be exercised. - * Grants unlimited Permit2 allowance for the given token (or USDC by default). + * Grants unlimited Permit2 allowance for the given token (permit2-approval script default if omitted). */ async function approvePermit2Approval(tokenAddress?: string): Promise { return new Promise((resolve) => { - const label = tokenAddress ? `token ${tokenAddress}` : 'USDC (default)'; + const label = tokenAddress ? `token ${tokenAddress}` : '(script default token)'; verboseLog(` 🔓 Approving Permit2 for ${label}...`); const args = ['scripts/permit2-approval.ts', 'approve']; @@ -75,12 +83,11 @@ async function approvePermit2Approval(tokenAddress?: string): Promise { /** * Revoke Permit2 approval so that gas sponsoring extensions are exercised. - * Sets the Permit2 allowance to 0 for the given token (or USDC by default), - * forcing the client into the EIP-2612 or ERC-20 approval extension path. + * Sets the Permit2 allowance to 0 for the given token (permit2-approval script default if omitted). */ async function revokePermit2Approval(tokenAddress?: string): Promise { return new Promise((resolve) => { - const label = tokenAddress ? `token ${tokenAddress}` : 'USDC (default)'; + const label = tokenAddress ? `token ${tokenAddress}` : '(script default token)'; verboseLog(` 🔓 Revoking Permit2 approval for ${label}...`); const args = ['scripts/permit2-approval.ts', 'revoke']; @@ -239,12 +246,37 @@ async function drainClientETH(): Promise { } verboseLog(` 💸 Draining ${formatEther(sendAmount)} ETH from client back to facilitator...`); - const hash = await clientWallet.sendTransaction({ - to: facilitatorAccount.address, - value: sendAmount, - }); - verboseLog(` ✅ Drained client ETH (tx: ${hash})`); - return true; + // Retry on nonce/replacement errors: the revoke tx may still be pending on + // some RPC nodes so the pending nonce can be stale. A short delay + explicit + // pending-nonce fetch resolves it the same way fundClientForRevoke does. + let lastErr: Error | null = null; + for (let attempt = 0; attempt < 3; attempt++) { + if (attempt > 0) await new Promise(r => setTimeout(r, 1000)); + try { + const nonce = await publicClient.getTransactionCount({ + address: clientAccount.address, + blockTag: 'pending', + }); + const hash = await clientWallet.sendTransaction({ + to: facilitatorAccount.address, + value: sendAmount, + nonce, + }); + verboseLog(` ✅ Drained client ETH (tx: ${hash})`); + return true; + } catch (err) { + lastErr = err instanceof Error ? err : new Error(String(err)); + const isNonceError = + lastErr.message.toLowerCase().includes('nonce') || + lastErr.message.toLowerCase().includes('replacement') || + lastErr.message.toLowerCase().includes('underpriced'); + if (!isNonceError) break; + } + } + const errLines = lastErr!.message.split('\n'); + errorLog(` ❌ Failed to drain client ETH: ${errLines[0].trim()}`); + if (errLines.length > 1) verboseLog(errLines.slice(1).join('\n')); + return false; } catch (err) { errorLog(` ❌ Failed to drain client ETH: ${err instanceof Error ? err.message : err}`); return false; @@ -270,6 +302,24 @@ async function startServer( ); } +/** + * Returns true when the settle response omits the on-chain transaction hash + * because the request was settled off-chain (e.g. a batch-settlement voucher + * recorded by the receiver but not yet claimed). + * + * @param paymentResponse - Decoded payment-response payload from the server. + * @returns Whether to skip the transaction-hash presence assertion. + */ +function isOffchainSettleResponse(paymentResponse: any): boolean { + if (!paymentResponse) return false; + const extra = paymentResponse.extra ?? {}; + const channelState = extra.channelState ?? {}; + const isBatchSettlement = + (typeof extra.channelId === 'string' && extra.channelId.length > 0) || + (typeof channelState.channelId === 'string' && channelState.channelId.length > 0); + return isBatchSettlement; +} + async function runClientTest( client: any, callConfig: ClientConfig @@ -284,7 +334,6 @@ async function runClientTest( bufferLog(` 📞 Running client: ${JSON.stringify(callConfig, null, 2)}`); const result = await client.call(callConfig); bufferLog(` 📊 Client result: ${JSON.stringify(result, null, 2)}`); - // Check if the client execution succeeded if (!result.success) { return { @@ -322,8 +371,10 @@ async function runClientTest( }; } - // Payment should have a transaction hash - if (!paymentResponse.transaction) { + // Payment should have a transaction hash, except for off-chain settle + // responses (e.g. batch-settlement vouchers that the server records but + // does not yet claim on-chain). + if (!paymentResponse.transaction && !isOffchainSettleResponse(paymentResponse)) { return { success: false, error: 'Payment succeeded but no transaction hash returned', @@ -367,6 +418,61 @@ async function runClientTest( } } +type ClientTestResult = ScenarioResult & { verboseLogs?: string[] }; + +function getBatchStep(result: ClientTestResult, step: string): any { + return (result.data as any)?.batchSettlement?.[step]; +} + +function validateBatchPaymentStep( + result: ClientTestResult, + step: string, + label: string, + requireTransaction: boolean, +): string | undefined { + const stepResult = getBatchStep(result, step); + if (!stepResult) { + return `Batch-settlement ${label} result missing`; + } + + if (!stepResult.success) { + const reason = stepResult.payment_response?.errorReason || stepResult.error || 'unknown error'; + return `Batch-settlement ${label} failed: ${reason}`; + } + + const paymentResponse = stepResult.payment_response; + if (!paymentResponse) { + return `Batch-settlement ${label} missing payment response`; + } + + if (!paymentResponse.success) { + return `Batch-settlement ${label} payment failed: ${paymentResponse.errorReason || 'unknown error'}`; + } + + if (paymentResponse.errorReason) { + return `Batch-settlement ${label} payment has error reason: ${paymentResponse.errorReason}`; + } + + if (requireTransaction && !paymentResponse.transaction) { + return `Batch-settlement ${label} succeeded but no transaction hash returned`; + } + + if (!requireTransaction && !paymentResponse.transaction && !isOffchainSettleResponse(paymentResponse)) { + return `Batch-settlement ${label} succeeded but no transaction hash or channel state returned`; + } + + return undefined; +} + +function mergeVerboseLogs(...results: ClientTestResult[]): string[] { + return results.flatMap(result => result.verboseLogs ?? []); +} + +function envFlagDefaultTrue(value: string | undefined): boolean { + if (value === undefined) return true; + return !['0', 'false', 'no', 'off'].includes(value.toLowerCase()); +} + async function runTest() { // Show help if requested if (parsedArgs.showHelp) { @@ -383,16 +489,28 @@ async function runTest() { // Load configuration from environment const serverEvmAddress = process.env.SERVER_EVM_ADDRESS; const serverSvmAddress = process.env.SERVER_SVM_ADDRESS; + const serverAvmAddress = process.env.SERVER_AVM_ADDRESS; const serverAptosAddress = process.env.SERVER_APTOS_ADDRESS; + const serverHederaAddress = process.env.SERVER_HEDERA_ADDRESS; const serverStellarAddress = process.env.SERVER_STELLAR_ADDRESS; + const serverTvmAddress = process.env.SERVER_TVM_ADDRESS; const clientEvmPrivateKey = process.env.CLIENT_EVM_PRIVATE_KEY; const clientSvmPrivateKey = process.env.CLIENT_SVM_PRIVATE_KEY; + const clientAvmPrivateKey = process.env.CLIENT_AVM_PRIVATE_KEY; const clientAptosPrivateKey = process.env.CLIENT_APTOS_PRIVATE_KEY; + const clientHederaAccountId = process.env.CLIENT_HEDERA_ACCOUNT_ID; + const clientHederaPrivateKey = process.env.CLIENT_HEDERA_PRIVATE_KEY; const clientStellarPrivateKey = process.env.CLIENT_STELLAR_PRIVATE_KEY; + const clientTvmPrivateKey = process.env.CLIENT_TVM_PRIVATE_KEY; const facilitatorEvmPrivateKey = process.env.FACILITATOR_EVM_PRIVATE_KEY; const facilitatorSvmPrivateKey = process.env.FACILITATOR_SVM_PRIVATE_KEY; + const facilitatorAvmPrivateKey = process.env.FACILITATOR_AVM_PRIVATE_KEY; const facilitatorAptosPrivateKey = process.env.FACILITATOR_APTOS_PRIVATE_KEY; + const facilitatorHederaAccountId = process.env.FACILITATOR_HEDERA_ACCOUNT_ID; + const facilitatorHederaPrivateKey = process.env.FACILITATOR_HEDERA_PRIVATE_KEY; const facilitatorStellarPrivateKey = process.env.FACILITATOR_STELLAR_PRIVATE_KEY; + const facilitatorTvmPrivateKey = process.env.FACILITATOR_TVM_PRIVATE_KEY; + const batchSettlementRecovery = envFlagDefaultTrue(process.env.BATCH_SETTLEMENT_RECOVERY); if (!serverEvmAddress || !serverSvmAddress || !clientEvmPrivateKey || !clientSvmPrivateKey || !facilitatorEvmPrivateKey || !facilitatorSvmPrivateKey) { errorLog('❌ Missing required environment variables:'); errorLog(' SERVER_EVM_ADDRESS, SERVER_SVM_ADDRESS, CLIENT_EVM_PRIVATE_KEY, CLIENT_SVM_PRIVATE_KEY, FACILITATOR_EVM_PRIVATE_KEY, and FACILITATOR_SVM_PRIVATE_KEY must be set'); @@ -464,12 +582,22 @@ async function runTest() { // Get network configuration based on selected mode const networks = getNetworkSet(networkMode); + const evmPermit2Asset = resolveEvmPermit2Asset(networks); + + const permit2AssetSource = process.env.EVM_PERMIT2_ASSET?.trim() + ? 'EVM_PERMIT2_ASSET' + : networks.evm.permit2Asset + ? 'network default' + : 'unset'; log(`\n🌐 Network Mode: ${networkMode.toUpperCase()}`); log(` EVM: ${networks.evm.name} (${networks.evm.caip2})`); + log(` EVM Permit2 asset: ${evmPermit2Asset || '(missing)'} (${permit2AssetSource})`); log(` SVM: ${networks.svm.name} (${networks.svm.caip2})`); log(` APTOS: ${networks.aptos.name} (${networks.aptos.caip2})`); + log(` HEDERA: ${networks.hedera.name} (${networks.hedera.caip2})`); log(` STELLAR: ${networks.stellar.name} (${networks.stellar.caip2})`); + log(` TVM: ${networks.tvm.name} (${networks.tvm.caip2})`); if (networkMode === 'mainnet') { log('\n⚠️ WARNING: Running on MAINNET - real funds will be used!'); @@ -485,6 +613,34 @@ async function runTest() { return; } + const requiredEnvByFamily: Record> = { + evm: [ + ['SERVER_EVM_ADDRESS', serverEvmAddress], + ['CLIENT_EVM_PRIVATE_KEY', clientEvmPrivateKey], + ['FACILITATOR_EVM_PRIVATE_KEY', facilitatorEvmPrivateKey], + ], + svm: [ + ['SERVER_SVM_ADDRESS', serverSvmAddress], + ['CLIENT_SVM_PRIVATE_KEY', clientSvmPrivateKey], + ['FACILITATOR_SVM_PRIVATE_KEY', facilitatorSvmPrivateKey], + ], + aptos: [ + ['SERVER_APTOS_ADDRESS', serverAptosAddress], + ['CLIENT_APTOS_PRIVATE_KEY', clientAptosPrivateKey], + ['FACILITATOR_APTOS_PRIVATE_KEY', facilitatorAptosPrivateKey], + ], + stellar: [ + ['SERVER_STELLAR_ADDRESS', serverStellarAddress], + ['CLIENT_STELLAR_PRIVATE_KEY', clientStellarPrivateKey], + ['FACILITATOR_STELLAR_PRIVATE_KEY', facilitatorStellarPrivateKey], + ], + tvm: [ + ['SERVER_TVM_ADDRESS', serverTvmAddress], + ['CLIENT_TVM_PRIVATE_KEY', clientTvmPrivateKey], + ['FACILITATOR_TVM_PRIVATE_KEY', facilitatorTvmPrivateKey], + ], + }; + // Apply coverage-based minimization if --min flag is set if (parsedArgs.minimize) { filteredScenarios = minimizeScenarios(filteredScenarios); @@ -498,6 +654,22 @@ async function runTest() { log(`\n✅ ${filteredScenarios.length} scenarios selected`); } + const selectedProtocolFamilies = new Set(filteredScenarios.map(scenario => scenario.protocolFamily)); + const missingRequiredEnv = new Set(); + for (const family of selectedProtocolFamilies) { + for (const [name, value] of requiredEnvByFamily[family] || []) { + if (!value) { + missingRequiredEnv.add(name); + } + } + } + + if (missingRequiredEnv.size > 0) { + errorLog('❌ Missing required environment variables for selected protocol families:'); + Array.from(missingRequiredEnv).forEach(name => errorLog(` ${name}`)); + process.exit(1); + } + if (selectedExtensions && selectedExtensions.length > 0) { log(`🎁 Extensions enabled: ${selectedExtensions.join(', ')}`); } @@ -506,37 +678,108 @@ async function runTest() { // Branch coverage assertions for EVM scenarios const evmScenarios = filteredScenarios.filter(s => s.protocolFamily === 'evm'); if (evmScenarios.length > 0) { - const hasEip3009 = evmScenarios.some(s => (s.endpoint.transferMethod || 'eip3009') === 'eip3009'); - const hasPermit2 = evmScenarios.some(s => s.endpoint.transferMethod === 'permit2'); - const hasPermit2Direct = evmScenarios.some(s => s.endpoint.transferMethod === 'permit2' && s.endpoint.permit2Direct === true); - const hasPermit2Eip2612 = evmScenarios.some(s => s.endpoint.transferMethod === 'permit2' && !s.endpoint.extensions?.includes('erc20ApprovalGasSponsoring') && !s.endpoint.permit2Direct); - const hasPermit2Erc20 = evmScenarios.some(s => s.endpoint.transferMethod === 'permit2' && s.endpoint.extensions?.includes('erc20ApprovalGasSponsoring')); + const hasExactEip3009 = evmScenarios.some( + s => endpointPaymentScheme(s.endpoint) === 'exact' && endpointAssetTransferMethod(s.endpoint) === 'eip3009', + ); + const hasExactPermit2 = evmScenarios.some( + s => endpointPaymentScheme(s.endpoint) === 'exact' && endpointAssetTransferMethod(s.endpoint) === 'permit2', + ); + const hasPermit2Direct = evmScenarios.some( + s => + endpointPaymentScheme(s.endpoint) === 'exact' && + endpointAssetTransferMethod(s.endpoint) === 'permit2' && + s.endpoint.schemeOptions?.permit2Direct === true, + ); + const hasPermit2Eip2612 = evmScenarios.some( + s => + endpointPaymentScheme(s.endpoint) === 'exact' && + endpointAssetTransferMethod(s.endpoint) === 'permit2' && + !s.endpoint.extensions?.includes('erc20ApprovalGasSponsoring') && + s.endpoint.schemeOptions?.permit2Direct !== true, + ); + const hasPermit2Erc20 = evmScenarios.some( + s => + endpointPaymentScheme(s.endpoint) === 'exact' && + endpointAssetTransferMethod(s.endpoint) === 'permit2' && + s.endpoint.extensions?.includes('erc20ApprovalGasSponsoring'), + ); + + const hasUpto = evmScenarios.some(s => endpointPaymentScheme(s.endpoint) === 'upto'); + const hasUptoDirect = evmScenarios.some( + s => + endpointPaymentScheme(s.endpoint) === 'upto' && s.endpoint.schemeOptions?.permit2Direct === true, + ); + const hasUptoEip2612 = evmScenarios.some( + s => + endpointPaymentScheme(s.endpoint) === 'upto' && + !s.endpoint.extensions?.includes('erc20ApprovalGasSponsoring') && + s.endpoint.schemeOptions?.permit2Direct !== true, + ); + const hasUptoErc20 = evmScenarios.some( + s => + endpointPaymentScheme(s.endpoint) === 'upto' && + s.endpoint.extensions?.includes('erc20ApprovalGasSponsoring'), + ); - const hasUpto = evmScenarios.some(s => s.endpoint.transferMethod === 'upto'); - const hasUptoDirect = evmScenarios.some(s => s.endpoint.transferMethod === 'upto' && s.endpoint.permit2Direct === true); - const hasUptoEip2612 = evmScenarios.some(s => s.endpoint.transferMethod === 'upto' && !s.endpoint.extensions?.includes('erc20ApprovalGasSponsoring') && !s.endpoint.permit2Direct); - const hasUptoErc20 = evmScenarios.some(s => s.endpoint.transferMethod === 'upto' && s.endpoint.extensions?.includes('erc20ApprovalGasSponsoring')); + const hasBatchSettlementEip3009 = evmScenarios.some( + s => + endpointPaymentScheme(s.endpoint) === 'batch-settlement' && + endpointAssetTransferMethod(s.endpoint) === 'eip3009', + ); + const hasBatchSettlementPermit2 = evmScenarios.some( + s => + endpointPaymentScheme(s.endpoint) === 'batch-settlement' && + endpointAssetTransferMethod(s.endpoint) === 'permit2', + ); + const hasBatchSettlementPermit2Direct = evmScenarios.some( + s => + endpointPaymentScheme(s.endpoint) === 'batch-settlement' && + endpointAssetTransferMethod(s.endpoint) === 'permit2' && + s.endpoint.schemeOptions?.permit2Direct === true, + ); + const hasBatchSettlementPermit2Eip2612 = evmScenarios.some( + s => + endpointPaymentScheme(s.endpoint) === 'batch-settlement' && + endpointAssetTransferMethod(s.endpoint) === 'permit2' && + !s.endpoint.extensions?.includes('erc20ApprovalGasSponsoring') && + s.endpoint.schemeOptions?.permit2Direct !== true, + ); + const hasBatchSettlementPermit2Erc20 = evmScenarios.some( + s => + endpointPaymentScheme(s.endpoint) === 'batch-settlement' && + endpointAssetTransferMethod(s.endpoint) === 'permit2' && + s.endpoint.extensions?.includes('erc20ApprovalGasSponsoring'), + ); log('🔍 EVM Branch Coverage Check:'); - log(` EIP-3009 route: ${hasEip3009 ? '✅' : '❌ MISSING'}`); - log(` Permit2 route: ${hasPermit2 ? '✅' : '❌ MISSING'}`); - log(` Permit2+direct settle: ${hasPermit2Direct ? '✅' : '⚠️ not found'}`); - log(` Permit2+EIP2612 route: ${hasPermit2Eip2612 ? '✅' : '⚠️ not found (may be covered by permit2 route if eip2612 extension enabled)'}`); - log(` Permit2+ERC20 route: ${hasPermit2Erc20 ? '✅' : '⚠️ not found'}`); - log(` Upto route: ${hasUpto ? '✅' : '⚠️ not found'}`); - log(` Upto+direct settle: ${hasUptoDirect ? '✅' : '⚠️ not found'}`); - log(` Upto+EIP2612 route: ${hasUptoEip2612 ? '✅' : '⚠️ not found'}`); - log(` Upto+ERC20 route: ${hasUptoErc20 ? '✅' : '⚠️ not found'}`); + log(` Exact EIP-3009 route: ${hasExactEip3009 ? '✅' : '⚠️ not found'}`); + log(` Exact Permit2 route: ${hasExactPermit2 ? '✅' : '⚠️ not found'}`); + log(` Exact Permit2+direct settle: ${hasPermit2Direct ? '✅' : '⚠️ not found'}`); + log(` Exact Permit2+EIP2612 route: ${hasPermit2Eip2612 ? '✅' : '⚠️ not found (may be covered by permit2 route if eip2612 extension enabled)'}`); + log(` Exact Permit2+ERC20 route: ${hasPermit2Erc20 ? '✅' : '⚠️ not found'}`); + log(` Upto route: ${hasUpto ? '✅' : '⚠️ not found'}`); + log(` Upto+direct settle: ${hasUptoDirect ? '✅' : '⚠️ not found'}`); + log(` Upto+EIP2612 route: ${hasUptoEip2612 ? '✅' : '⚠️ not found'}`); + log(` Upto+ERC20 route: ${hasUptoErc20 ? '✅' : '⚠️ not found'}`); + log(` Batch-settlement EIP-3009: ${hasBatchSettlementEip3009 ? '✅' : '⚠️ not found'}`); + log(` Batch-settlement Permit2: ${hasBatchSettlementPermit2 ? '✅' : '⚠️ not found'}`); + log(` Batch-settlement+direct: ${hasBatchSettlementPermit2Direct ? '✅' : '⚠️ not found'}`); + log(` Batch-settlement+EIP2612: ${hasBatchSettlementPermit2Eip2612 ? '✅' : '⚠️ not found'}`); + log(` Batch-settlement+ERC20: ${hasBatchSettlementPermit2Erc20 ? '✅' : '⚠️ not found'}`); log(''); } // Auto-detect Permit2 scenarios (upto uses Permit2 under the hood) - const hasPermit2Scenarios = filteredScenarios.some( - (s) => s.endpoint.transferMethod === 'permit2' || s.endpoint.transferMethod === 'upto' - ); + const hasPermit2Scenarios = filteredScenarios.some(s => endpointAssetTransferMethod(s.endpoint) === 'permit2'); if (hasPermit2Scenarios) { log('🔐 Permit2 scenarios detected — revoke before gas-sponsored tests, approve before permit2-direct tests'); + if (!evmPermit2Asset) { + errorLog( + '❌ Permit2 scenarios need a token address: set EVM_PERMIT2_ASSET or networks.evm.permit2Asset for this mode.', + ); + process.exit(1); + } } // Collect unique facilitators and servers @@ -560,15 +803,25 @@ async function runTest() { 'EVM_PRIVATE_KEY', 'SVM_PRIVATE_KEY', 'APTOS_PRIVATE_KEY', + 'HEDERA_ACCOUNT_ID', + 'HEDERA_PRIVATE_KEY', 'STELLAR_PRIVATE_KEY', + 'TVM_PRIVATE_KEY', 'EVM_NETWORK', 'SVM_NETWORK', 'APTOS_NETWORK', + 'HEDERA_NETWORK', 'STELLAR_NETWORK', + 'TVM_NETWORK', 'EVM_RPC_URL', 'SVM_RPC_URL', 'APTOS_RPC_URL', + 'HEDERA_NODE_URL', 'STELLAR_RPC_URL', + 'TONCENTER_BASE_URL', + 'TVM_PROVIDER', + 'TONAPI_API_KEY', + 'TONAPI_BASE_URL', ]); for (const [facilitatorName, facilitator] of uniqueFacilitators) { @@ -622,6 +875,8 @@ async function runTest() { passed: boolean; error?: string; transaction?: string; + depositTransaction?: string; + refundTransaction?: string; network?: string; } @@ -711,6 +966,7 @@ async function runTest() { SVM_NETWORK: networks.svm.caip2, APTOS_NETWORK: networks.aptos.caip2, STELLAR_NETWORK: networks.stellar.caip2, + TVM_NETWORK: networks.tvm.caip2, }, stdio: 'pipe', }, @@ -765,20 +1021,178 @@ async function runTest() { const facilitatorLabel = scenario.facilitator ? ` via ${scenario.facilitator.name}` : ''; const testName = `${scenario.client.name} → ${scenario.server.name} → ${scenario.endpoint.path}${facilitatorLabel}`; - const clientConfig: ClientConfig = { + const isBatchSettlement = endpointUsesBatchSettlement(scenario.endpoint); + const voucherSignerPrivateKey = process.env.CLIENT_EVM_VOUCHER_SIGNER_PRIVATE_KEY; + const baseClientConfig: ClientConfig = { evmPrivateKey: clientEvmPrivateKey!, svmPrivateKey: clientSvmPrivateKey!, + avmPrivateKey: clientAvmPrivateKey || '', aptosPrivateKey: clientAptosPrivateKey || '', + hederaAccountId: clientHederaAccountId || '', + hederaPrivateKey: clientHederaPrivateKey || '', stellarPrivateKey: clientStellarPrivateKey || '', + tvmPrivateKey: clientTvmPrivateKey || '', serverUrl: `http://localhost:${port}`, endpointPath: scenario.endpoint.path, evmNetwork: networks.evm.caip2, evmRpcUrl: networks.evm.rpcUrl, + hederaNetwork: networks.hedera.caip2, + hederaNodeUrl: networks.hedera.rpcUrl, + tvmNetwork: networks.tvm.caip2, + tvmRpcUrl: networks.tvm.rpcUrl, }; try { cLog.log(`🧪 Test #${localTestNumber}: ${testName}`); - const result = await runClientTest(scenario.client.proxy, clientConfig); + + if (isBatchSettlement) { + const channelSalt = generateChannelSalt(); + const batchBase = { + channelSalt, + ...(voucherSignerPrivateKey ? { voucherSignerPrivateKey } : {}), + }; + + if (!batchSettlementRecovery) { + const fullResult = await runClientTest(scenario.client.proxy, { + ...baseClientConfig, + batchSettlement: { ...batchBase, phase: 'full' }, + }); + const fullError = fullResult.success + ? validateBatchPaymentStep(fullResult, 'deposit', 'deposit', true) || + validateBatchPaymentStep(fullResult, 'voucher', 'voucher', false) || + validateBatchPaymentStep(fullResult, 'refund', 'refund', true) + : fullResult.error || 'Batch-settlement client phase failed'; + + const depositTransaction = getBatchStep(fullResult, 'deposit')?.payment_response?.transaction; + const refundTransaction = getBatchStep(fullResult, 'refund')?.payment_response?.transaction; + const network = + getBatchStep(fullResult, 'refund')?.payment_response?.network || + getBatchStep(fullResult, 'deposit')?.payment_response?.network || + fullResult.payment_response?.network; + + const detailedResult: DetailedTestResult = { + testNumber: localTestNumber, + client: scenario.client.name, + server: scenario.server.name, + endpoint: scenario.endpoint.path, + facilitator: scenario.facilitator?.name || 'none', + protocolFamily: scenario.protocolFamily, + passed: !fullError, + error: fullError, + transaction: refundTransaction || depositTransaction, + depositTransaction, + refundTransaction, + network, + }; + + if (fullError) { + cLog.log(` ❌ Test failed: ${fullError}`); + const verboseLogs = fullResult.verboseLogs ?? []; + if (verboseLogs.length > 0) { + cLog.log(` 🔍 Verbose logs:`); + verboseLogs.forEach(logLine => cLog.log(logLine)); + } + cLog.verboseLog(` 🔍 Error details: ${JSON.stringify(fullResult, null, 2)}`); + } else { + cLog.log(` ✅ Test passed`); + } + + return detailedResult; + } + + const initialResult = await runClientTest(scenario.client.proxy, { + ...baseClientConfig, + batchSettlement: { ...batchBase, phase: 'initial' }, + }); + const initialError = initialResult.success + ? validateBatchPaymentStep(initialResult, 'deposit', 'deposit', true) || + validateBatchPaymentStep(initialResult, 'voucher', 'voucher', false) + : initialResult.error || 'Initial batch-settlement client phase failed'; + + if (initialError) { + const detailedResult: DetailedTestResult = { + testNumber: localTestNumber, + client: scenario.client.name, + server: scenario.server.name, + endpoint: scenario.endpoint.path, + facilitator: scenario.facilitator?.name || 'none', + protocolFamily: scenario.protocolFamily, + passed: false, + error: initialError, + depositTransaction: getBatchStep(initialResult, 'deposit')?.payment_response?.transaction, + network: initialResult.payment_response?.network, + }; + cLog.log(` ❌ Test failed: ${initialError}`); + const verboseLogs = initialResult.verboseLogs ?? []; + if (verboseLogs.length > 0) { + cLog.log(` 🔍 Verbose logs:`); + verboseLogs.forEach(logLine => cLog.log(logLine)); + } + cLog.verboseLog(` 🔍 Error details: ${JSON.stringify(initialResult, null, 2)}`); + return detailedResult; + } + + const recoveryResult = await runClientTest(scenario.client.proxy, { + ...baseClientConfig, + batchSettlement: { ...batchBase, phase: 'recovery-refund' }, + }); + const recoveryError = recoveryResult.success + ? validateBatchPaymentStep(recoveryResult, 'recoveryVoucher', 'recovery voucher', false) || + validateBatchPaymentStep(recoveryResult, 'refund', 'refund', true) + : recoveryResult.error || 'Recovery/refund batch-settlement client phase failed'; + + const depositTransaction = getBatchStep(initialResult, 'deposit')?.payment_response?.transaction; + const refundTransaction = getBatchStep(recoveryResult, 'refund')?.payment_response?.transaction; + const network = + getBatchStep(recoveryResult, 'refund')?.payment_response?.network || + getBatchStep(initialResult, 'deposit')?.payment_response?.network || + recoveryResult.payment_response?.network || + initialResult.payment_response?.network; + + if (recoveryError) { + const detailedResult: DetailedTestResult = { + testNumber: localTestNumber, + client: scenario.client.name, + server: scenario.server.name, + endpoint: scenario.endpoint.path, + facilitator: scenario.facilitator?.name || 'none', + protocolFamily: scenario.protocolFamily, + passed: false, + error: recoveryError, + transaction: refundTransaction || depositTransaction, + depositTransaction, + refundTransaction, + network, + }; + cLog.log(` ❌ Test failed: ${recoveryError}`); + const verboseLogs = mergeVerboseLogs(initialResult, recoveryResult); + if (verboseLogs.length > 0) { + cLog.log(` 🔍 Verbose logs:`); + verboseLogs.forEach(logLine => cLog.log(logLine)); + } + cLog.verboseLog(` 🔍 Error details: ${JSON.stringify({ initialResult, recoveryResult }, null, 2)}`); + return detailedResult; + } + + const detailedResult: DetailedTestResult = { + testNumber: localTestNumber, + client: scenario.client.name, + server: scenario.server.name, + endpoint: scenario.endpoint.path, + facilitator: scenario.facilitator?.name || 'none', + protocolFamily: scenario.protocolFamily, + passed: true, + transaction: refundTransaction || depositTransaction, + depositTransaction, + refundTransaction, + network, + }; + + cLog.log(` ✅ Test passed`); + return detailedResult; + } + + const result = await runClientTest(scenario.client.proxy, baseClientConfig); const detailedResult: DetailedTestResult = { testNumber: localTestNumber, @@ -850,18 +1264,40 @@ async function runTest() { cLog.log(`🚀 Starting server: ${serverName} (port ${port}) with facilitator: ${facilitatorName || 'none'}`); const facilitatorConfig = facilitatorName ? uniqueFacilitators.get(facilitatorName)?.config : undefined; + const facilitatorSupportsAvm = facilitatorConfig?.protocolFamilies?.includes('avm') ?? false; const facilitatorSupportsAptos = facilitatorConfig?.protocolFamilies?.includes('aptos') ?? false; + const facilitatorSupportsHedera = facilitatorConfig?.protocolFamilies?.includes('hedera') ?? false; const facilitatorSupportsStellar = facilitatorConfig?.protocolFamilies?.includes('stellar') ?? false; const serverConfig: ServerConfig = { port, evmPayTo: serverEvmAddress!, svmPayTo: serverSvmAddress!, + avmPayTo: facilitatorSupportsAvm ? (serverAvmAddress || '') : '', aptosPayTo: facilitatorSupportsAptos ? (serverAptosAddress || '') : '', + hederaPayTo: + facilitatorSupportsHedera && + facilitatorHederaAccountId && + facilitatorHederaPrivateKey + ? (serverHederaAddress || '') + : '', + hederaAsset: process.env.HEDERA_ASSET, + hederaAmount: process.env.HEDERA_AMOUNT, stellarPayTo: facilitatorSupportsStellar ? (serverStellarAddress || '') : '', + tvmPayTo: serverTvmAddress || '', networks, facilitatorUrl, mockFacilitatorUrl, + // Forward the optional receiver-authorizer EOA key so the server can + // self-manage batch-settlement claim/refund signatures when set. + ...(process.env.SERVER_EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY + ? { + batchSettlement: { + receiverAuthorizerPrivateKey: + process.env.SERVER_EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY, + }, + } + : {}), }; const started = await startServer(serverProxy, serverConfig); @@ -890,22 +1326,25 @@ async function runTest() { const tn = nextTestNumber(); const isEvm = scenario.protocolFamily === 'evm'; - if (scenario.endpoint.permit2Direct) { - await approvePermit2Approval(USDC_BASE_SEPOLIA); - } else if (scenario.endpoint.coldstart) { - const endpointKey = scenario.endpoint.path; + if (scenario.endpoint.schemeOptions?.permit2Direct === true) { + await approvePermit2Approval(evmPermit2Asset); + } else if (scenario.endpoint.schemeOptions?.coldstart === true) { + // Key on (client, path) so each client independently runs its own + // fund → revoke → drain cycle. Without the client name, the second + // client in a combo silently skips the coldstart and inherits + // whatever wallet state the first client left behind. + const endpointKey = `${scenario.client.name}::${scenario.endpoint.path}`; if (!coldStartedEndpoints.has(endpointKey)) { coldStartedEndpoints.add(endpointKey); - const token = - scenario.endpoint.extensions?.includes('erc20ApprovalGasSponsoring') - ? MOCK_ERC20_BASE_SEPOLIA - : USDC_BASE_SEPOLIA; await fundClientForRevoke(); // Give fund tx 1s to propagate before submitting revoke (from client wallet) await new Promise(resolve => setTimeout(resolve, 1000)); - await revokePermit2Approval(token); - // Give revoke tx 1s to propagate before drain reads pending balance - await new Promise(resolve => setTimeout(resolve, 1000)); + await revokePermit2Approval(evmPermit2Asset); + // Give revoke tx 2s to propagate before drain reads pending nonce. + // Load-balanced RPCs can return a stale pending nonce if queried + // immediately after the revoke submission, causing the drain to + // collide with the revoke's nonce ("replacement transaction underpriced"). + await new Promise(resolve => setTimeout(resolve, 2000)); await drainClientETH(); // Wait for RPC nonce propagation across load-balanced nodes before the // test client (which may use a separate RPC connection) queries the nonce. @@ -913,6 +1352,8 @@ async function runTest() { } } + const isAvm = scenario.protocolFamily === 'avm'; + if (isEvm && facilitatorName && evmLock) { const releaseLock = await evmLock.acquire(facilitatorName); try { @@ -923,6 +1364,16 @@ async function runTest() { } } else { results.push(await runSingleTest(scenario, port, tn, cLog)); + if (isAvm) { + // Pause between AVM tests to avoid 403 rate limiting on free public Algorand nodes + await new Promise(resolve => setTimeout(resolve, 8000)); + } else if (isEvm) { + // Brief pause between sequential EVM tests so the facilitator wallet's + // settlement tx has time to propagate before the next cold-start setup + // sends from the same account (fundClientForRevoke). Without this, + // the two can collide on the same nonce on load-balanced RPCs. + await new Promise(resolve => setTimeout(resolve, 1500)); + } } } } finally { @@ -969,15 +1420,17 @@ async function runTest() { } // Run discovery validation if bazaar extension is enabled + let discoveryFailed = false; const showBazaarOutput = shouldShowExtensionOutput('bazaar', selectedExtensions); if (showBazaarOutput && shouldRunDiscoveryValidation(facilitatorsWithConfig, serversArray)) { log('\n🔍 Running Bazaar Discovery Validation...\n'); - await handleDiscoveryValidation( + const discoveryResult = await handleDiscoveryValidation( facilitatorsWithConfig, serversArray, discoveryServerPorts, facilitatorServerMap ); + discoveryFailed = !discoveryResult.success; } // Clean up facilitators (servers already stopped in test loop for both modes) @@ -1025,7 +1478,13 @@ async function runTest() { if (test.network) { log(` Network: ${test.network}`); } - if (test.transaction) { + if (test.depositTransaction) { + log(` Deposit Tx: ${test.depositTransaction}`); + } + if (test.refundTransaction) { + log(` Refund Tx: ${test.refundTransaction}`); + } + if (test.transaction && !test.depositTransaction && !test.refundTransaction) { log(` Tx: ${test.transaction}`); } }); @@ -1149,7 +1608,7 @@ async function runTest() { // Close logger closeLogger(); - if (failed > 0) { + if (failed > 0 || discoveryFailed) { process.exit(1); } } diff --git a/examples/go/clients/advanced/README.md b/examples/go/clients/advanced/README.md index 43f3967788..0ff8248a4d 100644 --- a/examples/go/clients/advanced/README.md +++ b/examples/go/clients/advanced/README.md @@ -61,10 +61,10 @@ Register custom logic at different payment stages for observability and control: ```go import ( - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) signer, _ := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("EVM_PRIVATE_KEY")) diff --git a/examples/go/clients/advanced/all_networks.go b/examples/go/clients/advanced/all_networks.go index 229b102536..57eebcd96e 100644 --- a/examples/go/clients/advanced/all_networks.go +++ b/examples/go/clients/advanced/all_networks.go @@ -8,12 +8,13 @@ import ( "net/http" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" - svmsigners "github.com/coinbase/x402/go/signers/svm" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + exactsvm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" + svmsigners "github.com/x402-foundation/x402/go/signers/svm" ) /** @@ -38,8 +39,9 @@ func runAllNetworksExample(ctx context.Context, evmPrivateKey, svmPrivateKey, ur if err != nil { return fmt.Errorf("failed to create EVM signer: %w", err) } - client.Register("eip155:*", evm.NewExactEvmScheme(evmSigner, nil)) - fmt.Printf("✅ Registered EVM networks (eip155:*)\n") + client.Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, nil)) + client.Register("eip155:*", uptoevm.NewUptoEvmScheme(evmSigner, nil)) + fmt.Printf("✅ Registered EVM networks (eip155:*) — exact + upto\n") } // Register SVM scheme if private key is provided @@ -48,7 +50,7 @@ func runAllNetworksExample(ctx context.Context, evmPrivateKey, svmPrivateKey, ur if err != nil { return fmt.Errorf("failed to create SVM signer: %w", err) } - client.Register("solana:*", svm.NewExactSvmScheme(svmSigner)) + client.Register("solana:*", exactsvm.NewExactSvmScheme(svmSigner)) fmt.Printf("✅ Registered SVM networks (solana:*)\n") } diff --git a/examples/go/clients/advanced/custom_transport.go b/examples/go/clients/advanced/custom_transport.go index 2206722bdd..d831dc1297 100644 --- a/examples/go/clients/advanced/custom_transport.go +++ b/examples/go/clients/advanced/custom_transport.go @@ -6,10 +6,11 @@ import ( "net/http" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) /** @@ -90,7 +91,8 @@ func runCustomTransportExample(ctx context.Context, evmPrivateKey, url string) e // Create x402 client client := x402.Newx402Client(). - Register("eip155:*", evm.NewExactEvmScheme(evmSigner, nil)) + Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, nil)). + Register("eip155:*", uptoevm.NewUptoEvmScheme(evmSigner, nil)) httpClient := x402http.Newx402HTTPClient(client) @@ -141,4 +143,3 @@ func runCustomTransportExample(ctx context.Context, evmPrivateKey, url string) e printPaymentDetails(resp.Header) return nil } - diff --git a/examples/go/clients/advanced/error_recovery.go b/examples/go/clients/advanced/error_recovery.go index 8b65d2599e..d5a8217dc3 100644 --- a/examples/go/clients/advanced/error_recovery.go +++ b/examples/go/clients/advanced/error_recovery.go @@ -5,10 +5,11 @@ import ( "fmt" "net/http" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) /** @@ -38,7 +39,8 @@ func runErrorRecoveryExample(ctx context.Context, evmPrivateKey, url string) err // Create x402 client with comprehensive error handling client := x402.Newx402Client(). - Register("eip155:*", evm.NewExactEvmScheme(evmSigner, nil)) + Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, nil)). + Register("eip155:*", uptoevm.NewUptoEvmScheme(evmSigner, nil)) // Recovery counter recoveryAttempts := 0 @@ -166,4 +168,3 @@ func contains(msg string, keywords ...string) bool { } return false } - diff --git a/examples/go/clients/advanced/go.mod b/examples/go/clients/advanced/go.mod index bd19708d9e..eb9e870b32 100644 --- a/examples/go/clients/advanced/go.mod +++ b/examples/go/clients/advanced/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/clients/advanced +module github.com/x402-foundation/x402/examples/go/clients/advanced go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/joho/godotenv v1.5.1 ) diff --git a/examples/go/clients/advanced/hooks.go b/examples/go/clients/advanced/hooks.go index 0a3bad969e..a0f49cc6d0 100644 --- a/examples/go/clients/advanced/hooks.go +++ b/examples/go/clients/advanced/hooks.go @@ -5,10 +5,11 @@ import ( "fmt" "net/http" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) /** @@ -38,7 +39,8 @@ func runHooksExample(ctx context.Context, evmPrivateKey, url string) error { // Create client with scheme registration client := x402.Newx402Client(). - Register("eip155:*", evm.NewExactEvmScheme(evmSigner, nil)) + Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, nil)). + Register("eip155:*", uptoevm.NewUptoEvmScheme(evmSigner, nil)) // Register lifecycle hooks @@ -113,4 +115,3 @@ func runHooksExample(ctx context.Context, evmPrivateKey, url string) error { printPaymentDetails(resp.Header) return nil } - diff --git a/examples/go/clients/advanced/multi_network_priority.go b/examples/go/clients/advanced/multi_network_priority.go index be2145585f..8cbe8251d9 100644 --- a/examples/go/clients/advanced/multi_network_priority.go +++ b/examples/go/clients/advanced/multi_network_priority.go @@ -5,10 +5,11 @@ import ( "fmt" "net/http" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) /** @@ -33,9 +34,9 @@ func runMultiNetworkPriorityExample(ctx context.Context, evmPrivateKey, url stri // In a real scenario, you might have different signers for different networks // For demo purposes, we'll use the same signer but show the pattern - mainnetSigner := primarySigner // Would be different in production - testnetSigner := primarySigner // Would be different in production - baseSigner := primarySigner // Would be different in production + mainnetSigner := primarySigner // Would be different in production + testnetSigner := primarySigner // Would be different in production + baseSigner := primarySigner // Would be different in production fmt.Println("📝 Registering networks with priority:") fmt.Println(" 1. Specific networks (highest priority)") @@ -46,25 +47,29 @@ func runMultiNetworkPriorityExample(ctx context.Context, evmPrivateKey, url stri // More specific registrations take precedence over wildcards client := x402.Newx402Client() - // Level 1: Specific networks (highest priority) + // Level 1: Specific networks (highest priority) — exact + upto fmt.Println("✅ Registering Ethereum Mainnet (eip155:1) with mainnet signer") - client.Register("eip155:1", evm.NewExactEvmScheme(mainnetSigner, nil)) + client.Register("eip155:1", exactevm.NewExactEvmScheme(mainnetSigner, nil)) + client.Register("eip155:1", uptoevm.NewUptoEvmScheme(mainnetSigner, nil)) fmt.Println("✅ Registering Base Mainnet (eip155:8453) with base signer") - client.Register("eip155:8453", evm.NewExactEvmScheme(baseSigner, nil)) + client.Register("eip155:8453", exactevm.NewExactEvmScheme(baseSigner, nil)) + client.Register("eip155:8453", uptoevm.NewUptoEvmScheme(baseSigner, nil)) fmt.Println("✅ Registering Base Sepolia (eip155:84532) with testnet signer") - client.Register("eip155:84532", evm.NewExactEvmScheme(testnetSigner, nil)) + client.Register("eip155:84532", exactevm.NewExactEvmScheme(testnetSigner, nil)) + client.Register("eip155:84532", uptoevm.NewUptoEvmScheme(testnetSigner, nil)) // Level 2: Wildcard for all other EVM networks (fallback) fmt.Println("✅ Registering all other EVM networks (eip155:*) with primary signer\n") - client.Register("eip155:*", evm.NewExactEvmScheme(primarySigner, nil)) + client.Register("eip155:*", exactevm.NewExactEvmScheme(primarySigner, nil)) + client.Register("eip155:*", uptoevm.NewUptoEvmScheme(primarySigner, nil)) // Add logging to show which network is being used client.OnBeforePaymentCreation(func(ctx x402.PaymentCreationContext) (*x402.BeforePaymentCreationHookResult, error) { fmt.Printf("💰 Creating payment for network: %s\n", ctx.SelectedRequirements.GetNetwork()) fmt.Printf(" Scheme: %s\n", ctx.SelectedRequirements.GetScheme()) - + // Show which signer would be used based on network var signerType string switch ctx.SelectedRequirements.GetNetwork() { @@ -117,4 +122,3 @@ func runMultiNetworkPriorityExample(ctx context.Context, evmPrivateKey, url stri printPaymentDetails(resp.Header) return nil } - diff --git a/examples/go/clients/batch-settlement/.env-example b/examples/go/clients/batch-settlement/.env-example new file mode 100644 index 0000000000..f84e0b3fd8 --- /dev/null +++ b/examples/go/clients/batch-settlement/.env-example @@ -0,0 +1,25 @@ +EVM_PRIVATE_KEY=0x... + +# Optional: dedicated voucher-signing EOA (faster verification, recommended for smart wallets) +EVM_VOUCHER_SIGNER_PRIVATE_KEY= + +# RPC endpoint used to read channel state when local storage is empty (cold-start +# recovery so the client picks up an existing channel's totalClaimed instead of +# signing a fresh voucher that the facilitator would reject). +EVM_RPC_URL=https://sepolia.base.org + +RESOURCE_SERVER_URL=http://localhost:4021 +ENDPOINT_PATH=/weather + +# 32-byte hex; differentiates channels with the same payer/payee/token tuple +CHANNEL_SALT=0x0000000000000000000000000000000000000000000000000000000000000000 + +# Optional: persist session state across runs +STORAGE_DIR= + +NUMBER_OF_REQUESTS=3 + +# After the request loop completes, request a cooperative refund. +REFUND_AFTER_REQUESTS=false +# Optional partial refund amount (base units). Empty drains the remaining channel balance. +REFUND_AMOUNT= diff --git a/examples/go/clients/batch-settlement/README.md b/examples/go/clients/batch-settlement/README.md new file mode 100644 index 0000000000..11c1c012e8 --- /dev/null +++ b/examples/go/clients/batch-settlement/README.md @@ -0,0 +1,58 @@ +# Batch-Settlement Client (Go) + +Sequential batch-settlement payment client. Opens a payment channel on the first request (deposit) and pays subsequent requests with off-chain vouchers that update the cumulative claimable amount. + +## Run + +```bash +cp .env-example .env +# fill in EVM_PRIVATE_KEY (and optionally EVM_VOUCHER_SIGNER_PRIVATE_KEY, STORAGE_DIR) + +go run . +``` + +The companion server is in `examples/go/servers/batch-settlement` and the facilitator is in `examples/go/facilitator/batch-settlement`. + +## Voucher Signer Delegation + +By default, vouchers are signed by the same key as the payer (`EVM_PRIVATE_KEY`). Set `EVM_VOUCHER_SIGNER_PRIVATE_KEY` to delegate voucher signing to a dedicated EOA — its address is committed into the channel as the `payerAuthorizer`. + +Use this when: + +- The payer key should only sign deposit authorizations. +- The payer is a smart wallet (EIP-1271). Delegating to an EOA voucher signer lets the facilitator verify vouchers with ECDSA recovery instead of an onchain `isValidSignature` call. + +## Deposit policy + +The default per-request deposit is `payment amount × DEPOSIT_MULTIPLIER` (default `5`). For app-specific deposit decisions (caps, dynamic adjustments, opting out), pass a `DepositStrategy` callback to `BatchSettlementEvmSchemeOptions`: + +```go +cfg := &batchedclient.BatchSettlementEvmSchemeOptions{ + DepositMultiplier: 5, + DepositStrategy: func(_ context.Context, c batchedclient.DepositStrategyContext) (batchedclient.DepositStrategyResult, error) { + // Cap deposits at 1_000_000 base units. + capped, _ := new(big.Int).SetString("1000000", 10) + proposed, _ := new(big.Int).SetString(c.DepositAmount, 10) + if proposed.Cmp(capped) > 0 { + return batchedclient.DepositStrategyResult{Amount: capped.String()}, nil + } + return batchedclient.DepositStrategyResult{}, nil // use computed + }, +} +``` + +## Environment + +| Variable | Required | Description | +|---------------------------------------|----------|-------------| +| `EVM_PRIVATE_KEY` | yes | Payer private key (0x-prefixed hex) | +| `EVM_VOUCHER_SIGNER_PRIVATE_KEY` | no | Dedicated voucher-signing EOA (committed as `payerAuthorizer`) | +| `EVM_RPC_URL` | no | RPC endpoint used for cold-start onchain recovery (default `https://sepolia.base.org`) | +| `RESOURCE_SERVER_URL` | no | Server base URL (default `http://localhost:4021`) | +| `ENDPOINT_PATH` | no | Path on the server (default `/weather`) | +| `CHANNEL_SALT` | no | 32-byte hex salt; change to open a fresh channel (default `0x00…00`) | +| `DEPOSIT_MULTIPLIER` | no | Per-request deposit is payment amount × this multiplier (must be integer ≥ 3; default `5`) | +| `STORAGE_DIR` | no | If set, persists session state under `${STORAGE_DIR}/client/` | +| `NUMBER_OF_REQUESTS` | no | How many paid requests to issue (default `3`) | +| `REFUND_AFTER_REQUESTS` | no | If `"true"`, request a cooperative refund after the request loop completes | +| `REFUND_AMOUNT` | no | Partial refund amount in base units; empty drains the remaining channel balance | diff --git a/examples/go/clients/batch-settlement/go.mod b/examples/go/clients/batch-settlement/go.mod new file mode 100644 index 0000000000..0a8f738887 --- /dev/null +++ b/examples/go/clients/batch-settlement/go.mod @@ -0,0 +1,37 @@ +module github.com/x402-foundation/x402/examples/go/clients/batch-settlement + +go 1.24.0 + +toolchain go1.24.1 + +replace github.com/x402-foundation/x402/go => ../../../../go + +require ( + github.com/ethereum/go-ethereum v1.16.7 + github.com/joho/godotenv v1.5.1 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect + github.com/bits-and-blooms/bitset v1.20.0 // indirect + github.com/consensys/gnark-crypto v0.18.0 // indirect + github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect + github.com/ethereum/go-verkle v0.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/holiman/uint256 v1.3.2 // indirect + github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect + github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect +) diff --git a/examples/go/clients/batch-settlement/go.sum b/examples/go/clients/batch-settlement/go.sum new file mode 100644 index 0000000000..ff25b651d2 --- /dev/null +++ b/examples/go/clients/batch-settlement/go.sum @@ -0,0 +1,197 @@ +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= +github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= +github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= +github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= +github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= +github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= +github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= +github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= +github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8= +github.com/ethereum/go-ethereum v1.16.7 h1:qeM4TvbrWK0UC0tgkZ7NiRsmBGwsjqc64BHo20U59UQ= +github.com/ethereum/go-ethereum v1.16.7/go.mod h1:Fs6QebQbavneQTYcA39PEKv2+zIjX7rPUZ14DER46wk= +github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= +github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= +github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= +github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= +github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= +github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= +github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM= +github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw= +github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/go/clients/batch-settlement/main.go b/examples/go/clients/batch-settlement/main.go new file mode 100644 index 0000000000..0f8d755f63 --- /dev/null +++ b/examples/go/clients/batch-settlement/main.go @@ -0,0 +1,196 @@ +package main + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "net/http" + "os" + "strconv" + "time" + + "github.com/ethereum/go-ethereum/ethclient" + "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + batchedclient "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" +) + +// Sequential batch-settlement client demo. Sends N requests against the same +// channel; the first request opens a deposit, subsequent requests are pure +// off-chain vouchers. +func main() { + _ = godotenv.Load() + + evmPrivateKey := os.Getenv("EVM_PRIVATE_KEY") + if evmPrivateKey == "" { + fmt.Println("EVM_PRIVATE_KEY environment variable is required") + os.Exit(1) + } + + baseURL := envOr("RESOURCE_SERVER_URL", "http://localhost:4021") + endpointPath := envOr("ENDPOINT_PATH", "/weather") + url := baseURL + endpointPath + + rpcURL := envOr("EVM_RPC_URL", "https://sepolia.base.org") + channelSalt := envOr("CHANNEL_SALT", batchedclient.DefaultSalt) + storageDir := os.Getenv("STORAGE_DIR") + numberOfRequests := atoiOr("NUMBER_OF_REQUESTS", 3) + depositMultiplier := atoiOr("DEPOSIT_MULTIPLIER", batchedclient.DefaultDepositMultiplier) + refundAfterRequests := os.Getenv("REFUND_AFTER_REQUESTS") == "true" + refundAmount := os.Getenv("REFUND_AMOUNT") + + // Dial an RPC client so the signer can read onchain channel state when + // local storage is cold. Without this, a fresh client run against a channel + // that already has onchain totalClaimed would sign vouchers with a stale + // cumulative base and the facilitator would reject them. + ethClient, err := ethclient.Dial(rpcURL) + if err != nil { + fmt.Printf("Failed to dial EVM RPC %s: %v\n", rpcURL, err) + os.Exit(1) + } + defer ethClient.Close() + + signer, err := evmsigners.NewClientSignerFromPrivateKeyWithClient(evmPrivateKey, ethClient) + if err != nil { + fmt.Printf("Failed to create signer: %v\n", err) + os.Exit(1) + } + + cfg := &batchedclient.BatchSettlementEvmSchemeOptions{ + DepositMultiplier: depositMultiplier, + Salt: channelSalt, + } + + // Optional dedicated voucher-signing key. + if voucherKey := os.Getenv("EVM_VOUCHER_SIGNER_PRIVATE_KEY"); voucherKey != "" { + voucherSigner, err := evmsigners.NewClientSignerFromPrivateKey(voucherKey) + if err != nil { + fmt.Printf("Failed to create voucher signer: %v\n", err) + os.Exit(1) + } + cfg.VoucherSigner = voucherSigner + } + + if storageDir != "" { + cfg.Storage = batchedclient.NewFileClientChannelStorage(batchsettlement.FileChannelStorageOptions{ + Directory: storageDir, + }) + } + + scheme := batchedclient.NewBatchSettlementEvmScheme(signer, cfg) + + x402Client := x402.Newx402Client() + x402Client.Register("eip155:*", scheme) + + httpClient := x402http.WrapHTTPClientWithPayment(http.DefaultClient, x402http.Newx402HTTPClient(x402Client)) + + fmt.Printf("Base URL: %s, endpoint: %s\n", baseURL, endpointPath) + fmt.Printf("payer: %s\n", signer.Address()) + if cfg.VoucherSigner != nil { + fmt.Printf("payerAuthorizer: %s\n\n", cfg.VoucherSigner.Address()) + } else { + fmt.Printf("payerAuthorizer: %s\n\n", signer.Address()) + } + + for i := 0; i < numberOfRequests; i++ { + t0 := time.Now() + + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + req, _ := http.NewRequestWithContext(ctx, "GET", url, nil) + resp, err := httpClient.Do(req) + cancel() + if err != nil { + fmt.Printf("Request %d failed: %v\n", i+1, err) + os.Exit(1) + } + + fmt.Printf("Request %d — %s\n", i+1, resp.Status) + body, errBody := readJSON(resp) + if errBody != nil { + fmt.Printf(" body: \n", errBody) + } else { + fmt.Printf("Request %d — RESPONSE\n%s\n", i+1, indent(body)) + } + + if settle, _ := extractSettleResponse(resp); settle != nil { + fmt.Println(indent(settle)) + } else if resp.StatusCode != http.StatusOK { + fmt.Printf(" no PAYMENT-RESPONSE (%s) — payment did not settle\n", resp.Status) + } + + _ = resp.Body.Close() + fmt.Printf("Request %d — completed in %.3fs\n\n", i+1, time.Since(t0).Seconds()) + } + + if refundAfterRequests { + if refundAmount != "" { + fmt.Printf("REQUESTING PARTIAL REFUND of %s base units\n", refundAmount) + } else { + fmt.Println("REQUESTING FULL REFUND of remaining channel balance") + } + opts := &batchedclient.RefundOptions{} + if refundAmount != "" { + opts.Amount = refundAmount + } + refundCtx, refundCancel := context.WithTimeout(context.Background(), 60*time.Second) + settle, err := scheme.Refund(refundCtx, url, opts) + refundCancel() + if err != nil { + fmt.Printf("Refund failed: %v\n", err) + os.Exit(1) + } + fmt.Println(indent(settle)) + } +} + +func envOr(key, def string) string { + if v := os.Getenv(key); v != "" { + return v + } + return def +} + +func atoiOr(key string, def int) int { + if v := os.Getenv(key); v != "" { + if n, err := strconv.Atoi(v); err == nil { + return n + } + } + return def +} + +func readJSON(resp *http.Response) (interface{}, error) { + var out interface{} + if err := json.NewDecoder(resp.Body).Decode(&out); err != nil { + return nil, err + } + return out, nil +} + +func extractSettleResponse(resp *http.Response) (*x402.SettleResponse, error) { + header := resp.Header.Get("PAYMENT-RESPONSE") + if header == "" { + header = resp.Header.Get("X-PAYMENT-RESPONSE") + } + if header == "" { + return nil, nil + } + decoded, err := base64.StdEncoding.DecodeString(header) + if err != nil { + return nil, err + } + var out x402.SettleResponse + if err := json.Unmarshal(decoded, &out); err != nil { + return nil, err + } + return &out, nil +} + +func indent(v interface{}) string { + b, _ := json.MarshalIndent(v, " ", " ") + return " " + string(b) +} diff --git a/examples/go/clients/custom/README.md b/examples/go/clients/custom/README.md index 0e1b8f060c..f84bb69982 100644 --- a/examples/go/clients/custom/README.md +++ b/examples/go/clients/custom/README.md @@ -73,9 +73,9 @@ go run . ```go import ( - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" + x402 "github.com/x402-foundation/x402/go" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) evmSigner, _ := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("EVM_PRIVATE_KEY")) diff --git a/examples/go/clients/custom/go.mod b/examples/go/clients/custom/go.mod index f02b539d57..0df1bea0f6 100644 --- a/examples/go/clients/custom/go.mod +++ b/examples/go/clients/custom/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/clients/custom +module github.com/x402-foundation/x402/examples/go/clients/custom go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/joho/godotenv v1.5.1 ) diff --git a/examples/go/clients/custom/main.go b/examples/go/clients/custom/main.go index fa1e0dd370..b87c76cb4b 100644 --- a/examples/go/clients/custom/main.go +++ b/examples/go/clients/custom/main.go @@ -11,11 +11,12 @@ import ( "strings" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" + "github.com/x402-foundation/x402/go/types" ) /** @@ -70,7 +71,8 @@ func main() { } x402Client := x402.Newx402Client(). - Register("eip155:*", evm.NewExactEvmScheme(evmSigner, nil)) + Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, nil)). + Register("eip155:*", uptoevm.NewUptoEvmScheme(evmSigner, nil)) // Make the request with custom payment handling fmt.Println("🔧 Using custom payment implementation (no wrapper)\n") @@ -241,7 +243,7 @@ func makeRequestWithPayment(ctx context.Context, x402Client *x402.X402Client, ur // Encode payment as base64 and add to header encodedPayment := base64.StdEncoding.EncodeToString(payloadBytes) - + // Create new request with payment header retryReq, err := http.NewRequestWithContext(ctx, "GET", url, nil) if err != nil { @@ -399,4 +401,3 @@ func extractSettlementResponse(headerValue string) (x402.SettleResponse, error) return settleResp, nil } - diff --git a/examples/go/clients/http/README.md b/examples/go/clients/http/README.md index a4d065771c..4977ea22ae 100644 --- a/examples/go/clients/http/README.md +++ b/examples/go/clients/http/README.md @@ -25,6 +25,9 @@ Required environment variables: - `SVM_PRIVATE_KEY` - Solana private key for SVM payments (optional) - `SERVER_URL` - Server endpoint (defaults to `http://localhost:4021/weather`) +Optional environment variables: +- `EVM_RPC_URL` - JSON-RPC endpoint for on-chain reads. Enables gas sponsoring extensions (EIP-2612 and ERC-20 approval). Example: `https://sepolia.base.org` + **⚠️ Security Warning:** Never use mainnet keys in `.env` files! Use testnet keys only. 3. Run the client: @@ -54,10 +57,10 @@ go run . mechanism-helper-registration ```go import ( - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) // Create signer diff --git a/examples/go/clients/http/builder_pattern.go b/examples/go/clients/http/builder_pattern.go index 1256006bdc..b134d09907 100644 --- a/examples/go/clients/http/builder_pattern.go +++ b/examples/go/clients/http/builder_pattern.go @@ -1,11 +1,12 @@ package main import ( - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" - svmsigners "github.com/coinbase/x402/go/signers/svm" + x402 "github.com/x402-foundation/x402/go" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + exactsvm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" + svmsigners "github.com/x402-foundation/x402/go/signers/svm" ) /** @@ -18,23 +19,30 @@ import ( * which signers and schemes. */ -func createBuilderPatternClient(evmPrivateKey, svmPrivateKey string) (*x402.X402Client, error) { +func createBuilderPatternClient(evmPrivateKey, svmPrivateKey, evmRpcURL string) (*x402.X402Client, error) { // Create signers from private keys evmSigner, err := evmsigners.NewClientSignerFromPrivateKey(evmPrivateKey) if err != nil { return nil, err } + // Optional RPC config enables gas sponsoring extensions (EIP-2612 / ERC-20 approval) + var rpcConfig *exactevm.ExactEvmSchemeConfig + if evmRpcURL != "" { + rpcConfig = &exactevm.ExactEvmSchemeConfig{RPCURL: evmRpcURL} + } + // Create client and register schemes using builder pattern client := x402.Newx402Client() - // Register EVM scheme for all EVM networks - client.Register("eip155:*", evm.NewExactEvmScheme(evmSigner, nil)) + // Register EVM schemes for all EVM networks + client.Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, rpcConfig)) + client.Register("eip155:*", uptoevm.NewUptoEvmScheme(evmSigner, rpcConfig)) // You can also register specific networks for fine-grained control // For example, use a different signer for Ethereum mainnet: // ethereumSigner := evmsigners.NewClientSignerFromPrivateKey(ethereumKey) - // client.Register("eip155:1", evm.NewExactEvmScheme(ethereumSigner, nil)) + // client.Register("eip155:1", exactevm.NewExactEvmScheme(ethereumSigner, nil)) // Register SVM scheme if key is provided if svmPrivateKey != "" { @@ -44,13 +52,12 @@ func createBuilderPatternClient(evmPrivateKey, svmPrivateKey string) (*x402.X402 } // Register for all Solana networks - client.Register("solana:*", svm.NewExactSvmScheme(svmSigner)) + client.Register("solana:*", exactsvm.NewExactSvmScheme(svmSigner)) // Could also register specific networks: - // client.Register("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", svm.NewExactSvmScheme(solanaMainnetSigner)) - // client.Register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", svm.NewExactSvmScheme(solanaDevnetSigner)) + // client.Register("solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp", exactsvm.NewExactSvmScheme(solanaMainnetSigner)) + // client.Register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", exactsvm.NewExactSvmScheme(solanaDevnetSigner)) } return client, nil } - diff --git a/examples/go/clients/http/go.mod b/examples/go/clients/http/go.mod index 3136c3064e..b2c98c3be6 100644 --- a/examples/go/clients/http/go.mod +++ b/examples/go/clients/http/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/clients/http +module github.com/x402-foundation/x402/examples/go/clients/http go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/joho/godotenv v1.5.1 ) diff --git a/examples/go/clients/http/main.go b/examples/go/clients/http/main.go index 5adbbad5f1..e595e6d6e9 100644 --- a/examples/go/clients/http/main.go +++ b/examples/go/clients/http/main.go @@ -8,8 +8,8 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" ) /** @@ -48,6 +48,7 @@ func main() { } svmPrivateKey := os.Getenv("SVM_PRIVATE_KEY") + evmRpcURL := os.Getenv("EVM_RPC_URL") url := os.Getenv("SERVER_URL") if url == "" { @@ -60,9 +61,9 @@ func main() { switch pattern { case "builder-pattern": - client, err = createBuilderPatternClient(evmPrivateKey, svmPrivateKey) + client, err = createBuilderPatternClient(evmPrivateKey, svmPrivateKey, evmRpcURL) case "mechanism-helper-registration": - client, err = createMechanismHelperRegistrationClient(evmPrivateKey, svmPrivateKey) + client, err = createMechanismHelperRegistrationClient(evmPrivateKey, svmPrivateKey, evmRpcURL) default: fmt.Printf("❌ Unknown pattern: %s\n", pattern) fmt.Println("Available patterns: builder-pattern, mechanism-helper-registration") @@ -135,4 +136,3 @@ func makeRequest(client *x402.X402Client, url string) error { return nil } - diff --git a/examples/go/clients/http/mechanism_helper_registration.go b/examples/go/clients/http/mechanism_helper_registration.go index d2fa8cee9c..92618ba3d8 100644 --- a/examples/go/clients/http/mechanism_helper_registration.go +++ b/examples/go/clients/http/mechanism_helper_registration.go @@ -1,11 +1,12 @@ package main import ( - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" - svmsigners "github.com/coinbase/x402/go/signers/svm" + x402 "github.com/x402-foundation/x402/go" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + exactsvm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" + svmsigners "github.com/x402-foundation/x402/go/signers/svm" ) /** @@ -18,20 +19,25 @@ import ( * all networks of a particular type with the same signer. */ -func createMechanismHelperRegistrationClient(evmPrivateKey, svmPrivateKey string) (*x402.X402Client, error) { +func createMechanismHelperRegistrationClient(evmPrivateKey, svmPrivateKey, evmRpcURL string) (*x402.X402Client, error) { // Create signers from private keys evmSigner, err := evmsigners.NewClientSignerFromPrivateKey(evmPrivateKey) if err != nil { return nil, err } + // Optional RPC config enables gas sponsoring extensions (EIP-2612 / ERC-20 approval) + var rpcConfig *exactevm.ExactEvmSchemeConfig + if evmRpcURL != "" { + rpcConfig = &exactevm.ExactEvmSchemeConfig{RPCURL: evmRpcURL} + } + // Start with a new client client := x402.Newx402Client() - // Register EVM scheme for all EVM networks using wildcard - // This registers: - // - eip155:* (all EVM networks in v2) - client.Register("eip155:*", evm.NewExactEvmScheme(evmSigner, nil)) + // Register EVM schemes for all EVM networks using wildcard + client.Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, rpcConfig)) + client.Register("eip155:*", uptoevm.NewUptoEvmScheme(evmSigner, rpcConfig)) // Register SVM scheme if key is provided if svmPrivateKey != "" { @@ -43,14 +49,13 @@ func createMechanismHelperRegistrationClient(evmPrivateKey, svmPrivateKey string // Register for all Solana networks using wildcard // This registers: // - solana:* (all Solana networks in v2) - client.Register("solana:*", svm.NewExactSvmScheme(svmSigner)) + client.Register("solana:*", exactsvm.NewExactSvmScheme(svmSigner)) } // The fluent API allows chaining for clean code: // client := x402.Newx402Client(). - // Register("eip155:*", evm.NewExactEvmScheme(evmSigner, nil)). - // Register("solana:*", svm.NewExactSvmScheme(svmSigner)) + // Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, nil)). + // Register("solana:*", exactsvm.NewExactSvmScheme(svmSigner)) return client, nil } - diff --git a/examples/go/clients/http/utils.go b/examples/go/clients/http/utils.go index 6a004f8ae1..1adb2afe2e 100644 --- a/examples/go/clients/http/utils.go +++ b/examples/go/clients/http/utils.go @@ -5,8 +5,8 @@ import ( "encoding/json" "net/http" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" ) // wrapHTTPClient wraps a standard HTTP client with x402 payment handling @@ -45,4 +45,3 @@ func extractPaymentResponse(headers http.Header) (*x402.SettleResponse, error) { return &settleResp, nil } - diff --git a/examples/go/clients/mcp-chatbot/go.mod b/examples/go/clients/mcp-chatbot/go.mod index 07a9305197..618f0db44a 100644 --- a/examples/go/clients/mcp-chatbot/go.mod +++ b/examples/go/clients/mcp-chatbot/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/clients/mcp-chatbot +module github.com/x402-foundation/x402/examples/go/clients/mcp-chatbot go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/joho/godotenv v1.5.1 github.com/modelcontextprotocol/go-sdk v1.3.0 github.com/sashabaranov/go-openai v1.38.1 diff --git a/examples/go/clients/mcp-chatbot/main.go b/examples/go/clients/mcp-chatbot/main.go index 4ecfaa5322..9ecde426c9 100644 --- a/examples/go/clients/mcp-chatbot/main.go +++ b/examples/go/clients/mcp-chatbot/main.go @@ -21,13 +21,14 @@ import ( "os" "strings" - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - "github.com/coinbase/x402/go/mcp" - evmsigners "github.com/coinbase/x402/go/signers/evm" "github.com/joho/godotenv" mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp" openai "github.com/sashabaranov/go-openai" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mcp" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) // ============================================================================ @@ -105,7 +106,8 @@ func run() error { // Create x402 payment client and wrap session paymentClient := x402.Newx402Client() - paymentClient.Register("eip155:84532", evm.NewExactEvmScheme(evmSigner, nil)) + paymentClient.Register("eip155:84532", exactevm.NewExactEvmScheme(evmSigner, nil)) + paymentClient.Register("eip155:84532", uptoevm.NewUptoEvmScheme(evmSigner, nil)) x402Mcp := mcp.NewX402MCPClient(clientSession, paymentClient, mcp.Options{ AutoPayment: mcp.BoolPtr(true), OnPaymentRequested: func(context mcp.PaymentRequiredContext) (bool, error) { diff --git a/examples/go/clients/mcp/advanced.go b/examples/go/clients/mcp/advanced.go index 5855bc0583..079f749c9b 100644 --- a/examples/go/clients/mcp/advanced.go +++ b/examples/go/clients/mcp/advanced.go @@ -5,12 +5,13 @@ import ( "fmt" "os" - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" - "github.com/coinbase/x402/go/mcp" "github.com/joho/godotenv" mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mcp" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) // MCP Client with x402 Payment Support - Advanced Example @@ -81,7 +82,8 @@ func runAdvanced() error { // Step 2: Create x402 payment client manually paymentClient := x402.Newx402Client() - paymentClient.Register("eip155:84532", evm.NewExactEvmScheme(evmSigner, nil)) + paymentClient.Register("eip155:84532", exactevm.NewExactEvmScheme(evmSigner, nil)) + paymentClient.Register("eip155:84532", uptoevm.NewUptoEvmScheme(evmSigner, nil)) // Step 3: Compose into X402MCPClient with session x402Mcp := mcp.NewX402MCPClient(clientSession, paymentClient, mcp.Options{ diff --git a/examples/go/clients/mcp/go.mod b/examples/go/clients/mcp/go.mod index 3f605472d7..f07a1a6fff 100644 --- a/examples/go/clients/mcp/go.mod +++ b/examples/go/clients/mcp/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/clients/mcp +module github.com/x402-foundation/x402/examples/go/clients/mcp go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/joho/godotenv v1.5.1 github.com/modelcontextprotocol/go-sdk v1.3.0 ) diff --git a/examples/go/clients/mcp/simple.go b/examples/go/clients/mcp/simple.go index 1fc19d0530..cc91ee242a 100644 --- a/examples/go/clients/mcp/simple.go +++ b/examples/go/clients/mcp/simple.go @@ -5,12 +5,13 @@ import ( "fmt" "os" - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" - "github.com/coinbase/x402/go/mcp" "github.com/joho/godotenv" mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mcp" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) // MCP Client with x402 Payment Support - Simple Example @@ -73,7 +74,8 @@ func runSimple() error { // Create x402 payment client and wrap session paymentClient := x402.Newx402Client() - paymentClient.Register("eip155:84532", evm.NewExactEvmScheme(evmSigner, nil)) + paymentClient.Register("eip155:84532", exactevm.NewExactEvmScheme(evmSigner, nil)) + paymentClient.Register("eip155:84532", uptoevm.NewUptoEvmScheme(evmSigner, nil)) x402Mcp := mcp.NewX402MCPClient(clientSession, paymentClient, mcp.Options{ AutoPayment: mcp.BoolPtr(true), OnPaymentRequested: func(context mcp.PaymentRequiredContext) (bool, error) { diff --git a/examples/go/clients/payment-identifier/README.md b/examples/go/clients/payment-identifier/README.md index 3bd5851360..5a224dab8b 100644 --- a/examples/go/clients/payment-identifier/README.md +++ b/examples/go/clients/payment-identifier/README.md @@ -48,7 +48,7 @@ go run main.go ### Generating a Payment ID ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" // Generate with default prefix "pay_" id := paymentidentifier.GeneratePaymentID("") diff --git a/examples/go/clients/payment-identifier/go.mod b/examples/go/clients/payment-identifier/go.mod index 41a8179505..39203cdb21 100644 --- a/examples/go/clients/payment-identifier/go.mod +++ b/examples/go/clients/payment-identifier/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/clients/payment-identifier +module github.com/x402-foundation/x402/examples/go/clients/payment-identifier go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/joho/godotenv v1.5.1 ) diff --git a/examples/go/clients/payment-identifier/main.go b/examples/go/clients/payment-identifier/main.go index 5cc78af831..bc3babb97a 100644 --- a/examples/go/clients/payment-identifier/main.go +++ b/examples/go/clients/payment-identifier/main.go @@ -11,12 +11,13 @@ import ( "strings" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/paymentidentifier" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/paymentidentifier" + x402http "github.com/x402-foundation/x402/go/http" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) /** @@ -44,9 +45,9 @@ import ( // It then caches the resulting PAYMENT-SIGNATURE header so that subsequent // requests replay the exact same signed payload — a true retry. type PaymentIdentifierTransport struct { - Inner http.RoundTripper - PaymentID string - cachedPaymentHeader string // PAYMENT-SIGNATURE from the first successful attempt + Inner http.RoundTripper + PaymentID string + cachedPaymentHeader string // PAYMENT-SIGNATURE from the first successful attempt } func (t *PaymentIdentifierTransport) RoundTrip(req *http.Request) (*http.Response, error) { @@ -145,7 +146,8 @@ func main() { // Create client with scheme registration client := x402.Newx402Client(). - Register("eip155:*", evm.NewExactEvmScheme(evmSigner, nil)) + Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, nil)). + Register("eip155:*", uptoevm.NewUptoEvmScheme(evmSigner, nil)) // Generate a unique payment ID for this session paymentID := paymentidentifier.GeneratePaymentID("") diff --git a/examples/go/facilitator/advanced/README.md b/examples/go/facilitator/advanced/README.md index a0633b6679..332b3d74bd 100644 --- a/examples/go/facilitator/advanced/README.md +++ b/examples/go/facilitator/advanced/README.md @@ -238,9 +238,9 @@ Register additional schemes for other networks: ```go import ( - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/facilitator" + x402 "github.com/x402-foundation/x402/go" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/facilitator" ) facilitator := x402.Newx402Facilitator() @@ -260,7 +260,7 @@ facilitator.Register([]x402.Network{"solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"}, Extract and validate payment identifiers for deduplication: ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" // In verification hook, extract and track payment ID facilitator.OnAfterVerify(func(ctx x402.FacilitatorVerifyResultContext) error { @@ -296,6 +296,12 @@ if existing, found := store.Get(paymentID); found && existing.Status == "settled } ``` +For production use, bind the payment ID to a normalized fingerprint of the +settlement request, such as network, scheme, asset, amount, payer, payee, and +the application operation ID when available. If the same payment ID is replayed +with a different fingerprint, reject it with a conflict instead of returning a +cached transaction or settling a different payment. + **Use case:** Prevent duplicate settlements, provide exactly-once semantics, track payment lifecycle. ### Lifecycle Hooks diff --git a/examples/go/facilitator/advanced/all_networks.go b/examples/go/facilitator/advanced/all_networks.go index 6b658c2ab8..6fcee3ceea 100644 --- a/examples/go/facilitator/advanced/all_networks.go +++ b/examples/go/facilitator/advanced/all_networks.go @@ -7,10 +7,11 @@ import ( "net/http" "time" - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/facilitator" "github.com/gin-gonic/gin" + x402 "github.com/x402-foundation/x402/go" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/facilitator" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/facilitator" ) /** @@ -60,6 +61,7 @@ func runAllNetworksExample(evmPrivateKey, svmPrivateKey string) error { DeployERC4337WithEIP6492: true, } facilitator.Register([]x402.Network{evmNetwork}, evm.NewExactEvmScheme(evmSigner, evmConfig)) + facilitator.Register([]x402.Network{evmNetwork}, uptoevm.NewUptoEvmScheme(evmSigner, nil)) } // Register SVM scheme if signer is available (only explicitly specified networks) diff --git a/examples/go/facilitator/advanced/bazaar.go b/examples/go/facilitator/advanced/bazaar.go index afd1c8524f..0bb98945ff 100644 --- a/examples/go/facilitator/advanced/bazaar.go +++ b/examples/go/facilitator/advanced/bazaar.go @@ -2,18 +2,21 @@ package main import ( "context" + "encoding/base64" "encoding/json" "fmt" "net/http" + "strings" "sync" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - exttypes "github.com/coinbase/x402/go/extensions/types" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/facilitator" "github.com/gin-gonic/gin" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + exttypes "github.com/x402-foundation/x402/go/extensions/types" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/facilitator" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/facilitator" ) /** @@ -41,6 +44,23 @@ type BazaarCatalog struct { mutex sync.RWMutex } +const extensionResponsesHeader = "EXTENSION-RESPONSES" + +func setExtensionResponsesHeader(c *gin.Context) { + extensionResponses := map[string]map[string]string{ + "bazaar": { + "status": "success", + }, + } + + body, err := json.Marshal(extensionResponses) + if err != nil { + return + } + + c.Header(extensionResponsesHeader, base64.StdEncoding.EncodeToString(body)) +} + func NewBazaarCatalog() *BazaarCatalog { return &BazaarCatalog{ resources: make(map[string]DiscoveredResource), @@ -63,6 +83,33 @@ func (c *BazaarCatalog) GetAll() []DiscoveredResource { return result } +// Search performs case-insensitive keyword matching across resource URL, type, +// and metadata values. Pagination is not supported for in-memory keyword search. +func (c *BazaarCatalog) Search(query, resourceType string, limit int) []DiscoveredResource { + c.mutex.RLock() + defer c.mutex.RUnlock() + + needle := strings.ToLower(query) + var results []DiscoveredResource + + for _, r := range c.resources { + haystack := strings.ToLower(r.Resource + " " + r.Type + " " + r.Description) + if !strings.Contains(haystack, needle) { + continue + } + if resourceType != "" && r.Type != resourceType { + continue + } + results = append(results, r) + } + + if limit > 0 && len(results) > limit { + results = results[:limit] + } + + return results +} + func runBazaarExample(evmPrivateKey, svmPrivateKey string) error { // Network configuration evmNetwork := x402.Network("eip155:84532") // Base Sepolia @@ -96,6 +143,7 @@ func runBazaarExample(evmPrivateKey, svmPrivateKey string) error { DeployERC4337WithEIP6492: true, } facilitator.Register([]x402.Network{evmNetwork}, evm.NewExactEvmScheme(evmSigner, evmConfig)) + facilitator.Register([]x402.Network{evmNetwork}, uptoevm.NewUptoEvmScheme(evmSigner, nil)) } // Register SVM scheme if signer is available @@ -159,7 +207,7 @@ func runBazaarExample(evmPrivateKey, svmPrivateKey string) error { c.JSON(http.StatusOK, supported) }) - // Discovery endpoint + // Discovery list endpoint r.GET("/discovery/resources", func(c *gin.Context) { resources := catalog.GetAll() c.JSON(http.StatusOK, gin.H{ @@ -173,6 +221,32 @@ func runBazaarExample(evmPrivateKey, svmPrivateKey string) error { }) }) + // Discovery search endpoint + r.GET("/discovery/search", func(c *gin.Context) { + query := c.Query("query") + if query == "" { + c.JSON(http.StatusBadRequest, gin.H{"error": "query parameter is required"}) + return + } + resourceType := c.Query("type") + limit := 0 + if limitParam := c.Query("limit"); limitParam != "" { + fmt.Sscanf(limitParam, "%d", &limit) + } + + items := catalog.Search(query, resourceType, limit) + if items == nil { + items = []DiscoveredResource{} + } + + c.JSON(http.StatusOK, gin.H{ + "x402Version": 2, + "resources": items, + "partialResults": false, + "pagination": nil, + }) + }) + // Health endpoint r.GET("/health", func(c *gin.Context) { c.JSON(http.StatusOK, gin.H{"status": "ok"}) @@ -199,6 +273,7 @@ func runBazaarExample(evmPrivateKey, svmPrivateKey string) error { return } + setExtensionResponsesHeader(c) c.JSON(http.StatusOK, result) }) @@ -223,6 +298,7 @@ func runBazaarExample(evmPrivateKey, svmPrivateKey string) error { return } + setExtensionResponsesHeader(c) c.JSON(http.StatusOK, result) }) diff --git a/examples/go/facilitator/advanced/gas_extensions.go b/examples/go/facilitator/advanced/gas_extensions.go new file mode 100644 index 0000000000..c40c32ddb9 --- /dev/null +++ b/examples/go/facilitator/advanced/gas_extensions.go @@ -0,0 +1,124 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "time" + + "github.com/gin-gonic/gin" + x402 "github.com/x402-foundation/x402/go" + eip2612gassponsor "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/facilitator" +) + +/** + * Gas extensions facilitator example (exact + upto) + * + * Registers `exact` and `upto` on Base Sepolia and advertises both Permit2 gas-sponsoring + * extensions: EIP-2612 and ERC-20 approve (tokens without EIP-2612). + * + * Requires EVM_PRIVATE_KEY with Base Sepolia ETH for settlement and for broadcasting + * client-supplied approval transactions when those extensions are used. + */ + +func runGasExtensionsExample(evmPrivateKey string) error { + evmNetwork := x402.Network("eip155:84532") + + evmSigner, err := newFacilitatorEvmSigner(evmPrivateKey, DefaultEvmRPC) + if err != nil { + return fmt.Errorf("failed to create EVM signer: %w", err) + } + + facilitator := x402.Newx402Facilitator() + + evmConfig := &evm.ExactEvmSchemeConfig{ + DeployERC4337WithEIP6492: true, + } + facilitator.Register([]x402.Network{evmNetwork}, evm.NewExactEvmScheme(evmSigner, evmConfig)) + facilitator.Register([]x402.Network{evmNetwork}, uptoevm.NewUptoEvmScheme(evmSigner, nil)) + + facilitator.RegisterExtension(eip2612gassponsor.EIP2612GasSponsoring) + facilitator.RegisterExtension(&erc20approvalgassponsor.Erc20ApprovalFacilitatorExtension{ + Signer: newErc20ApprovalGasSponsorSigner(evmSigner), + }) + + facilitator.OnAfterVerify(func(ctx x402.FacilitatorVerifyResultContext) error { + fmt.Printf("✅ Payment verified\n") + return nil + }) + + facilitator.OnAfterSettle(func(ctx x402.FacilitatorSettleResultContext) error { + fmt.Printf("🎉 Payment settled: %s\n", ctx.Result.Transaction) + return nil + }) + + gin.SetMode(gin.ReleaseMode) + r := gin.New() + r.Use(gin.Recovery()) + + r.GET("/supported", func(c *gin.Context) { + supported := facilitator.GetSupported() + c.JSON(http.StatusOK, supported) + }) + + r.GET("/health", func(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{"status": "ok"}) + }) + + r.POST("/verify", func(c *gin.Context) { + ctx, cancel := context.WithTimeout(c.Request.Context(), 30*time.Second) + defer cancel() + + var reqBody struct { + PaymentPayload json.RawMessage `json:"paymentPayload"` + PaymentRequirements json.RawMessage `json:"paymentRequirements"` + } + + if err := c.BindJSON(&reqBody); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) + return + } + + result, err := facilitator.Verify(ctx, reqBody.PaymentPayload, reqBody.PaymentRequirements) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, result) + }) + + r.POST("/settle", func(c *gin.Context) { + ctx, cancel := context.WithTimeout(c.Request.Context(), 60*time.Second) + defer cancel() + + var reqBody struct { + PaymentPayload json.RawMessage `json:"paymentPayload"` + PaymentRequirements json.RawMessage `json:"paymentRequirements"` + } + + if err := c.BindJSON(&reqBody); err != nil { + c.JSON(http.StatusBadRequest, gin.H{"error": "Invalid request body"}) + return + } + + result, err := facilitator.Settle(ctx, reqBody.PaymentPayload, reqBody.PaymentRequirements) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + return + } + + c.JSON(http.StatusOK, result) + }) + + fmt.Printf("🚀 Gas extensions facilitator (exact + upto) listening on http://localhost:%s\n", defaultPort) + fmt.Printf(" Extensions: eip2612GasSponsoring, erc20ApprovalGasSponsoring\n") + fmt.Printf(" EVM: %s on %s\n", evmSigner.GetAddresses()[0], evmNetwork) + fmt.Println() + + return r.Run(":" + defaultPort) +} diff --git a/examples/go/facilitator/advanced/go.mod b/examples/go/facilitator/advanced/go.mod index 9c32300874..642f48e7be 100644 --- a/examples/go/facilitator/advanced/go.mod +++ b/examples/go/facilitator/advanced/go.mod @@ -1,17 +1,17 @@ -module github.com/coinbase/x402/examples/go/facilitator +module github.com/x402-foundation/x402/examples/go/facilitator go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 github.com/ethereum/go-ethereum v1.16.7 github.com/gagliardetto/solana-go v1.14.0 github.com/gin-gonic/gin v1.11.0 github.com/joho/godotenv v1.5.1 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 ) require ( @@ -52,7 +52,7 @@ require ( github.com/klauspost/cpuid/v2 v2.3.0 // indirect github.com/leodido/go-urn v1.4.0 // indirect github.com/logrusorgru/aurora v2.0.3+incompatible // indirect - github.com/mattn/go-colorable v0.1.13 // indirect + github.com/mattn/go-colorable v0.1.14 // indirect github.com/mattn/go-isatty v0.0.20 // indirect github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect @@ -78,14 +78,14 @@ require ( go.uber.org/ratelimit v0.2.0 // indirect go.uber.org/zap v1.21.0 // indirect golang.org/x/arch v0.20.0 // indirect - golang.org/x/crypto v0.41.0 // indirect - golang.org/x/mod v0.27.0 // indirect - golang.org/x/net v0.43.0 // indirect - golang.org/x/sync v0.16.0 // indirect - golang.org/x/sys v0.36.0 // indirect - golang.org/x/term v0.34.0 // indirect - golang.org/x/text v0.28.0 // indirect - golang.org/x/time v0.9.0 // indirect - golang.org/x/tools v0.36.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/mod v0.30.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/term v0.38.0 // indirect + golang.org/x/text v0.32.0 // indirect + golang.org/x/time v0.14.0 // indirect + golang.org/x/tools v0.39.0 // indirect google.golang.org/protobuf v1.36.9 // indirect ) diff --git a/examples/go/facilitator/advanced/go.sum b/examples/go/facilitator/advanced/go.sum index 45699e88a1..d4e085f5b8 100644 --- a/examples/go/facilitator/advanced/go.sum +++ b/examples/go/facilitator/advanced/go.sum @@ -163,9 +163,8 @@ github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= github.com/logrusorgru/aurora v2.0.3+incompatible h1:tOpm7WcpBTn4fjmVfgpQq0EfczGlG91VSDkswnjF5A8= github.com/logrusorgru/aurora v2.0.3+incompatible/go.mod h1:7rIyQOR62GCctdiQpZ/zOJlFyk6y+94wXzv6RNZgaR4= -github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= -github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= -github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= @@ -301,15 +300,15 @@ golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8U golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.41.0 h1:WKYxWedPGCTVVl5+WHSSrOBT0O8lx32+zxmHxijgXp4= -golang.org/x/crypto v0.41.0/go.mod h1:pO5AFd7FA68rFak7rOAGVuygIISepHftHnr8dr6+sUc= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/mod v0.27.0 h1:kb+q2PyFnEADO2IEF935ehFUXlWiNjJWtRNgBLSfbxQ= -golang.org/x/mod v0.27.0/go.mod h1:rWI627Fq0DEoudcK+MBkNkCe0EetEaDSwJJkCcjpazc= +golang.org/x/mod v0.30.0 h1:fDEXFVZ/fmCKProc/yAXXUijritrDzahmwwefnjoPFk= +golang.org/x/mod v0.30.0/go.mod h1:lAsf5O2EvJeSFMiBxXDki7sCgAxEUcZHXoXMKT4GJKc= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -317,13 +316,13 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.43.0 h1:lat02VYK2j4aLzMzecihNvTlJNQUq316m2Mr9rnM6YE= -golang.org/x/net v0.43.0/go.mod h1:vhO1fvI4dGsIjh73sWfUVjj3N7CA9WkKJNQm2svM6Jg= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.16.0 h1:ycBJEhp9p4vXvUZNszeOq0kGTPghopOL8q0fq3vstxw= -golang.org/x/sync v0.16.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -334,34 +333,33 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.36.0 h1:KVRy2GtZBrk1cBYA7MKu5bEZFxQk4NIDV6RLVcC8o0k= -golang.org/x/sys v0.36.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.34.0 h1:O/2T7POpk0ZZ7MAzMeWFSg6S5IpWd/RXDlM9hgM3DR4= -golang.org/x/term v0.34.0/go.mod h1:5jC53AEywhIVebHgPVeg0mj8OD3VO9OzclacVrqpaAw= +golang.org/x/term v0.38.0 h1:PQ5pkm/rLO6HnxFR7N2lJHOZX6Kez5Y1gDSJla6jo7Q= +golang.org/x/term v0.38.0/go.mod h1:bSEAKrOT1W+VSu9TSCMtoGEOUcKxOKgl3LE5QEF/xVg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.28.0 h1:rhazDwis8INMIwQ4tpjLDzUhx6RlXqZNPEM0huQojng= -golang.org/x/text v0.28.0/go.mod h1:U8nCwOR8jO/marOQ0QbDiOngZVEBB7MAiitBuMjXiNU= -golang.org/x/time v0.9.0 h1:EsRrnYcQiGH+5FfbgvV4AP7qEZstoyrHB0DzarOQ4ZY= -golang.org/x/time v0.9.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/tools v0.36.0 h1:kWS0uv/zsvHEle1LbV5LE8QujrxB3wfQyxHfhOk0Qkg= -golang.org/x/tools v0.36.0/go.mod h1:WBDiHKJK8YgLHlcQPYQzNCkUxUypCaa5ZegCVutKm+s= +golang.org/x/tools v0.39.0 h1:ik4ho21kwuQln40uelmciQPp9SipgNDdrafrYA4TmQQ= +golang.org/x/tools v0.39.0/go.mod h1:JnefbkDPyD8UU2kI5fuf8ZX4/yUeh9W877ZeBONxUqQ= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/examples/go/facilitator/advanced/main.go b/examples/go/facilitator/advanced/main.go index 4822ec339f..b3a6a4bf64 100644 --- a/examples/go/facilitator/advanced/main.go +++ b/examples/go/facilitator/advanced/main.go @@ -15,11 +15,13 @@ import ( * - all-networks: Facilitator with all supported networks * - bazaar: Facilitator with bazaar discovery extension * - payment-identifier: Facilitator with payment identifier idempotency + * - gas-extensions: Base Sepolia exact + upto with EIP-2612 and ERC-20 approval gas sponsoring * * Usage: * go run . all-networks * go run . bazaar * go run . payment-identifier + * go run . gas-extensions */ func main() { @@ -39,6 +41,18 @@ func main() { evmPrivateKey := os.Getenv("EVM_PRIVATE_KEY") svmPrivateKey := os.Getenv("SVM_PRIVATE_KEY") + if pattern == "gas-extensions" { + if evmPrivateKey == "" { + fmt.Println("❌ EVM_PRIVATE_KEY environment variable is required for gas-extensions") + os.Exit(1) + } + if err := runGasExtensionsExample(evmPrivateKey); err != nil { + fmt.Printf("❌ Error: %v\n", err) + os.Exit(1) + } + return + } + // Validate at least one private key is provided if evmPrivateKey == "" && svmPrivateKey == "" { fmt.Println("❌ At least one of EVM_PRIVATE_KEY or SVM_PRIVATE_KEY is required") @@ -67,7 +81,7 @@ func main() { default: fmt.Printf("❌ Unknown pattern: %s\n", pattern) - fmt.Println("Available patterns: all-networks, bazaar, payment-identifier") + fmt.Println("Available patterns: all-networks, bazaar, payment-identifier, gas-extensions") os.Exit(1) } } diff --git a/examples/go/facilitator/advanced/payment-identifier.go b/examples/go/facilitator/advanced/payment-identifier.go index 13bea06836..d3dae551c0 100644 --- a/examples/go/facilitator/advanced/payment-identifier.go +++ b/examples/go/facilitator/advanced/payment-identifier.go @@ -8,11 +8,11 @@ import ( "sync" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/paymentidentifier" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/facilitator" "github.com/gin-gonic/gin" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/paymentidentifier" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/facilitator" ) /** diff --git a/examples/go/facilitator/advanced/signer.go b/examples/go/facilitator/advanced/signer.go index eac33b0a58..a7a3d8e8fa 100644 --- a/examples/go/facilitator/advanced/signer.go +++ b/examples/go/facilitator/advanced/signer.go @@ -9,8 +9,6 @@ import ( "strings" "time" - evmmech "github.com/coinbase/x402/go/mechanisms/evm" - svmmech "github.com/coinbase/x402/go/mechanisms/svm" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -21,6 +19,9 @@ import ( "github.com/ethereum/go-ethereum/signer/core/apitypes" solana "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + evmmech "github.com/x402-foundation/x402/go/mechanisms/evm" + svmmech "github.com/x402-foundation/x402/go/mechanisms/svm" ) const ( @@ -384,6 +385,53 @@ func (s *facilitatorEvmSigner) GetCode(ctx context.Context, address string) ([]b return code, nil } +// erc20ApprovalGasSponsorSigner wraps facilitatorEvmSigner with SendTransactions for the +// erc20ApprovalGasSponsoring facilitator extension (see gas_extensions example). +type erc20ApprovalGasSponsorSigner struct { + *facilitatorEvmSigner +} + +func newErc20ApprovalGasSponsorSigner(base *facilitatorEvmSigner) *erc20ApprovalGasSponsorSigner { + return &erc20ApprovalGasSponsorSigner{facilitatorEvmSigner: base} +} + +// SendTransactions implements erc20approvalgassponsor.Erc20ApprovalGasSponsoringSigner. +func (s *erc20ApprovalGasSponsorSigner) SendTransactions(ctx context.Context, txs []erc20approvalgassponsor.TransactionRequest) ([]string, error) { + hashes := make([]string, 0, len(txs)) + for _, req := range txs { + var txHash string + switch { + case req.Serialized != "": + raw := common.FromHex(strings.TrimPrefix(req.Serialized, "0x")) + var tx types.Transaction + if err := tx.UnmarshalBinary(raw); err != nil { + return nil, fmt.Errorf("decode signed transaction: %w", err) + } + if err := s.client.SendTransaction(ctx, &tx); err != nil { + return nil, fmt.Errorf("send raw transaction: %w", err) + } + txHash = tx.Hash().Hex() + case req.Call != nil: + h, err := s.WriteContract(ctx, req.Call.Address, req.Call.ABI, req.Call.Function, req.Call.Args...) + if err != nil { + return nil, err + } + txHash = h + default: + return nil, fmt.Errorf("empty transaction request") + } + rec, err := s.WaitForTransactionReceipt(ctx, txHash) + if err != nil { + return nil, err + } + if rec.Status != evmmech.TxStatusSuccess { + return nil, fmt.Errorf("transaction failed: %s", txHash) + } + hashes = append(hashes, txHash) + } + return hashes, nil +} + // ============================================================================ // SVM (Solana) Facilitator Signer // ============================================================================ diff --git a/examples/go/facilitator/basic/README.md b/examples/go/facilitator/basic/README.md index 9bdae3db57..50b66f1753 100644 --- a/examples/go/facilitator/basic/README.md +++ b/examples/go/facilitator/basic/README.md @@ -73,7 +73,7 @@ EVM_PRIVATE_KEY= SVM_PRIVATE_KEY= ``` -**⚠️ Security Note:** The facilitator private key needs ETH/SOL for gas fees. Use a dedicated testnet account. +**⚠️ Security Note:** The facilitator private key needs ETH/SOL for gas fees. Use a dedicated facilitator account for settlement, and keep it separate from your seller `payTo` wallet and buyer test wallets. 2. Install dependencies and run: @@ -235,9 +235,9 @@ Register additional schemes for other networks: ```go import ( - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/facilitator" + x402 "github.com/x402-foundation/x402/go" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/facilitator" ) facilitator := x402.Newx402Facilitator() diff --git a/examples/go/facilitator/basic/go.mod b/examples/go/facilitator/basic/go.mod index 450c76d2cf..2004fb3aa8 100644 --- a/examples/go/facilitator/basic/go.mod +++ b/examples/go/facilitator/basic/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/facilitator +module github.com/x402-foundation/x402/examples/go/facilitator go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/ethereum/go-ethereum v1.16.7 github.com/gagliardetto/solana-go v1.14.0 github.com/gin-gonic/gin v1.11.0 diff --git a/examples/go/facilitator/basic/main.go b/examples/go/facilitator/basic/main.go index c9ead5daa9..af46580655 100644 --- a/examples/go/facilitator/basic/main.go +++ b/examples/go/facilitator/basic/main.go @@ -8,14 +8,15 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - evmv1 "github.com/coinbase/x402/go/mechanisms/evm/exact/v1/facilitator" - svmmech "github.com/coinbase/x402/go/mechanisms/svm" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/facilitator" - svmv1 "github.com/coinbase/x402/go/mechanisms/svm/exact/v1/facilitator" "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + evmv1 "github.com/x402-foundation/x402/go/mechanisms/evm/exact/v1/facilitator" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/facilitator" + svmmech "github.com/x402-foundation/x402/go/mechanisms/svm" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/facilitator" + svmv1 "github.com/x402-foundation/x402/go/mechanisms/svm/exact/v1/facilitator" ) const ( @@ -48,12 +49,13 @@ func main() { } facilitator := x402.Newx402Facilitator() - + // Register V2 EVM scheme with smart wallet deployment enabled evmConfig := &evm.ExactEvmSchemeConfig{ DeployERC4337WithEIP6492: true, } facilitator.Register([]x402.Network{evmNetwork}, evm.NewExactEvmScheme(evmSigner, evmConfig)) + facilitator.Register([]x402.Network{evmNetwork}, uptoevm.NewUptoEvmScheme(evmSigner, nil)) // Register V1 EVM scheme with smart wallet deployment enabled evmV1Config := &evmv1.ExactEvmSchemeV1Config{ @@ -166,4 +168,3 @@ func main() { os.Exit(1) } } - diff --git a/examples/go/facilitator/basic/signer.go b/examples/go/facilitator/basic/signer.go index 442da10515..e46bcebfb1 100644 --- a/examples/go/facilitator/basic/signer.go +++ b/examples/go/facilitator/basic/signer.go @@ -9,8 +9,6 @@ import ( "strings" "time" - evmmech "github.com/coinbase/x402/go/mechanisms/evm" - svmmech "github.com/coinbase/x402/go/mechanisms/svm" "github.com/ethereum/go-ethereum" "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" @@ -21,6 +19,8 @@ import ( "github.com/ethereum/go-ethereum/signer/core/apitypes" solana "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" + evmmech "github.com/x402-foundation/x402/go/mechanisms/evm" + svmmech "github.com/x402-foundation/x402/go/mechanisms/svm" ) const ( @@ -214,7 +214,7 @@ func (s *facilitatorEvmSigner) ReadContract( if err != nil { return nil, fmt.Errorf("failed to call contract: %w", err) } - + if len(methodObj.Outputs) == 0 { return nil, nil } diff --git a/examples/go/facilitator/batch-settlement/.env-example b/examples/go/facilitator/batch-settlement/.env-example new file mode 100644 index 0000000000..5700a55cfa --- /dev/null +++ b/examples/go/facilitator/batch-settlement/.env-example @@ -0,0 +1,8 @@ +EVM_PRIVATE_KEY=0x... +EVM_RPC_URL=https://sepolia.base.org + +# Optional dedicated authorizer key (defaults to EVM_PRIVATE_KEY) +EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY= + +# Optional listen port (default 4022). +PORT= diff --git a/examples/go/facilitator/batch-settlement/README.md b/examples/go/facilitator/batch-settlement/README.md new file mode 100644 index 0000000000..72df340ae6 --- /dev/null +++ b/examples/go/facilitator/batch-settlement/README.md @@ -0,0 +1,35 @@ +# Batch-Settlement Facilitator (Go) + +Standalone HTTP facilitator with the batch-settlement EVM scheme registered for +Base Sepolia. Exposes the standard x402 endpoints: + +- `GET /supported` +- `POST /verify` +- `POST /settle` + +The facilitator's `evmSigner` submits onchain transactions for `deposit`, +`claimWithSignature`, `settle`, and `refundWithSignature`. The `authorizerSigner` +produces the EIP-712 signatures advertised in `/supported.kinds[].extra.receiverAuthorizer`. + +Servers may delegate to the facilitator's authorizer (omit +`EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY` on the server) or run a self-managed authorizer. + +## Run + +```bash +cp .env-example .env +# fill in EVM_PRIVATE_KEY + +go run . +``` + +Listens on `http://localhost:4022` by default (`PORT` overrides). + +## Environment + +| Variable | Description | +|-------------------------------------------|-------------| +| `EVM_PRIVATE_KEY` (required) | Facilitator wallet — signs and submits onchain transactions | +| `EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY` | Optional dedicated authorizer key. Defaults to `EVM_PRIVATE_KEY`. | +| `EVM_RPC_URL` | Default `https://sepolia.base.org` | +| `PORT` | Listen port (default `4022`) | diff --git a/examples/go/facilitator/batch-settlement/authorizer.go b/examples/go/facilitator/batch-settlement/authorizer.go new file mode 100644 index 0000000000..272760a660 --- /dev/null +++ b/examples/go/facilitator/batch-settlement/authorizer.go @@ -0,0 +1,130 @@ +package main + +import ( + "context" + "crypto/ecdsa" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" + evmmech "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +// authorizerSigner produces ClaimBatch and Refund EIP-712 signatures advertised +// by the facilitator under /supported. Servers may delegate to this signer or +// supply their own (the recommended path — see the README). +type authorizerSigner struct { + privateKey *ecdsa.PrivateKey + address common.Address +} + +func newAuthorizerSigner(privateKeyHex string) (*authorizerSigner, error) { + pk, err := crypto.HexToECDSA(strings.TrimPrefix(privateKeyHex, "0x")) + if err != nil { + return nil, fmt.Errorf("parse private key: %w", err) + } + return &authorizerSigner{ + privateKey: pk, + address: crypto.PubkeyToAddress(pk.PublicKey), + }, nil +} + +func (a *authorizerSigner) Address() string { return a.address.Hex() } + +func (a *authorizerSigner) SignClaimBatch(ctx context.Context, claims []batchsettlement.BatchSettlementVoucherClaim, network string) ([]byte, error) { + chainId, err := evmmech.GetEvmChainId(network) + if err != nil { + return nil, err + } + domain := batchsettlement.GetBatchSettlementEip712Domain(chainId) + + allTypes := map[string][]evmmech.TypedDataField{ + "EIP712Domain": { + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "ClaimBatch": batchsettlement.ClaimBatchTypes["ClaimBatch"], + "ClaimEntry": batchsettlement.ClaimBatchTypes["ClaimEntry"], + } + + entries := make([]map[string]interface{}, len(claims)) + for i, claim := range claims { + channelId, _ := batchsettlement.ComputeChannelId(claim.Voucher.Channel, network) + channelIdBytes, _ := evmmech.HexToBytes(channelId) + maxClaimable, _ := new(big.Int).SetString(claim.Voucher.MaxClaimableAmount, 10) + totalClaimed, _ := new(big.Int).SetString(claim.TotalClaimed, 10) + entries[i] = map[string]interface{}{ + "channelId": channelIdBytes, + "maxClaimableAmount": maxClaimable, + "totalClaimed": totalClaimed, + } + } + message := map[string]interface{}{"claims": entries} + + return a.signTypedData(domain, allTypes, "ClaimBatch", message) +} + +func (a *authorizerSigner) SignRefund(ctx context.Context, channelId string, amount string, nonce string, network string) ([]byte, error) { + chainId, err := evmmech.GetEvmChainId(network) + if err != nil { + return nil, err + } + refundAmount, ok := new(big.Int).SetString(amount, 10) + if !ok { + return nil, fmt.Errorf("invalid refund amount: %s", amount) + } + refundNonce, ok := new(big.Int).SetString(nonce, 10) + if !ok { + return nil, fmt.Errorf("invalid nonce: %s", nonce) + } + channelIdBytes, err := evmmech.HexToBytes(channelId) + if err != nil { + return nil, err + } + + domain := batchsettlement.GetBatchSettlementEip712Domain(chainId) + allTypes := map[string][]evmmech.TypedDataField{ + "EIP712Domain": { + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "Refund": batchsettlement.RefundTypes["Refund"], + } + message := map[string]interface{}{ + "channelId": channelIdBytes, + "nonce": refundNonce, + "amount": refundAmount, + } + return a.signTypedData(domain, allTypes, "Refund", message) +} + +func (a *authorizerSigner) signTypedData( + domain evmmech.TypedDataDomain, + allTypes map[string][]evmmech.TypedDataField, + primaryType string, + message map[string]interface{}, +) ([]byte, error) { + td := buildTypedData(domain, allTypes, primaryType, message) + dataHash, err := td.HashStruct(td.PrimaryType, td.Message) + if err != nil { + return nil, fmt.Errorf("hash struct: %w", err) + } + domainSep, err := td.HashStruct("EIP712Domain", td.Domain.Map()) + if err != nil { + return nil, fmt.Errorf("hash domain: %w", err) + } + digest := crypto.Keccak256(append([]byte{0x19, 0x01}, append(domainSep, dataHash...)...)) + sig, err := crypto.Sign(digest, a.privateKey) + if err != nil { + return nil, fmt.Errorf("sign: %w", err) + } + sig[64] += 27 + return sig, nil +} diff --git a/examples/go/facilitator/batch-settlement/evm_signer.go b/examples/go/facilitator/batch-settlement/evm_signer.go new file mode 100644 index 0000000000..2e37a53b62 --- /dev/null +++ b/examples/go/facilitator/batch-settlement/evm_signer.go @@ -0,0 +1,272 @@ +package main + +import ( + "bytes" + "context" + "crypto/ecdsa" + "fmt" + "math/big" + "strings" + "time" + + "github.com/ethereum/go-ethereum" + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/core/types" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + evmmech "github.com/x402-foundation/x402/go/mechanisms/evm" +) + +// facilitatorEvmSigner implements evmmech.FacilitatorEvmSigner. +type facilitatorEvmSigner struct { + privateKey *ecdsa.PrivateKey + address common.Address + client *ethclient.Client + chainID *big.Int +} + +func newFacilitatorEvmSigner(privateKeyHex string, rpcURL string) (*facilitatorEvmSigner, error) { + pk, err := crypto.HexToECDSA(strings.TrimPrefix(privateKeyHex, "0x")) + if err != nil { + return nil, fmt.Errorf("parse private key: %w", err) + } + client, err := ethclient.Dial(rpcURL) + if err != nil { + return nil, fmt.Errorf("dial RPC: %w", err) + } + chainID, err := client.ChainID(context.Background()) + if err != nil { + return nil, fmt.Errorf("get chain ID: %w", err) + } + return &facilitatorEvmSigner{ + privateKey: pk, + address: crypto.PubkeyToAddress(pk.PublicKey), + client: client, + chainID: chainID, + }, nil +} + +func (s *facilitatorEvmSigner) GetAddresses() []string { + return []string{s.address.Hex()} +} + +func (s *facilitatorEvmSigner) GetChainID(_ context.Context) (*big.Int, error) { + return s.chainID, nil +} + +func (s *facilitatorEvmSigner) VerifyTypedData( + _ context.Context, + address string, + domain evmmech.TypedDataDomain, + types map[string][]evmmech.TypedDataField, + primaryType string, + message map[string]interface{}, + signature []byte, +) (bool, error) { + td := buildTypedData(domain, types, primaryType, message) + + dataHash, err := td.HashStruct(td.PrimaryType, td.Message) + if err != nil { + return false, fmt.Errorf("hash struct: %w", err) + } + domainSep, err := td.HashStruct("EIP712Domain", td.Domain.Map()) + if err != nil { + return false, fmt.Errorf("hash domain: %w", err) + } + digest := crypto.Keccak256(append([]byte{0x19, 0x01}, append(domainSep, dataHash...)...)) + + if len(signature) != 65 { + return false, fmt.Errorf("invalid signature length: %d", len(signature)) + } + sig := make([]byte, 65) + copy(sig, signature) + if sig[64] >= 27 { + sig[64] -= 27 + } + + pub, err := crypto.SigToPub(digest, sig) + if err != nil { + return false, fmt.Errorf("recover pubkey: %w", err) + } + return bytes.Equal(crypto.PubkeyToAddress(*pub).Bytes(), common.HexToAddress(address).Bytes()), nil +} + +func (s *facilitatorEvmSigner) ReadContract( + ctx context.Context, + contractAddress string, + abiJSON []byte, + method string, + args ...interface{}, +) (interface{}, error) { + parsedABI, err := abi.JSON(strings.NewReader(string(abiJSON))) + if err != nil { + return nil, fmt.Errorf("parse ABI: %w", err) + } + methodObj, ok := parsedABI.Methods[method] + if !ok { + return nil, fmt.Errorf("method %s not found", method) + } + data, err := parsedABI.Pack(method, args...) + if err != nil { + return nil, fmt.Errorf("pack call: %w", err) + } + to := common.HexToAddress(contractAddress) + out, err := s.client.CallContract(ctx, ethereum.CallMsg{To: &to, Data: data}, nil) + if err != nil { + return nil, fmt.Errorf("call contract: %w", err) + } + if len(methodObj.Outputs) == 0 { + return nil, nil + } + results, err := methodObj.Outputs.Unpack(out) + if err != nil { + return nil, fmt.Errorf("unpack: %w", err) + } + if len(results) > 0 { + return results[0], nil + } + return nil, nil +} + +func (s *facilitatorEvmSigner) WriteContract( + ctx context.Context, + contractAddress string, + abiJSON []byte, + method string, + args ...interface{}, +) (string, error) { + parsedABI, err := abi.JSON(strings.NewReader(string(abiJSON))) + if err != nil { + return "", fmt.Errorf("parse ABI: %w", err) + } + data, err := parsedABI.Pack(method, args...) + if err != nil { + return "", fmt.Errorf("pack call: %w", err) + } + return s.SendTransaction(ctx, contractAddress, data) +} + +func (s *facilitatorEvmSigner) SendTransaction(ctx context.Context, to string, data []byte) (string, error) { + nonce, err := s.client.PendingNonceAt(ctx, s.address) + if err != nil { + return "", fmt.Errorf("get nonce: %w", err) + } + gasPrice, err := s.client.SuggestGasPrice(ctx) + if err != nil { + return "", fmt.Errorf("suggest gas price: %w", err) + } + toAddr := common.HexToAddress(to) + tx := types.NewTransaction(nonce, toAddr, big.NewInt(0), 500000, gasPrice, data) + signedTx, err := types.SignTx(tx, types.LatestSignerForChainID(s.chainID), s.privateKey) + if err != nil { + return "", fmt.Errorf("sign tx: %w", err) + } + if err := s.client.SendTransaction(ctx, signedTx); err != nil { + return "", fmt.Errorf("send tx: %w", err) + } + return signedTx.Hash().Hex(), nil +} + +func (s *facilitatorEvmSigner) WaitForTransactionReceipt(ctx context.Context, txHash string) (*evmmech.TransactionReceipt, error) { + hash := common.HexToHash(txHash) + for i := 0; i < 60; i++ { + receipt, err := s.client.TransactionReceipt(ctx, hash) + if err == nil && receipt != nil { + return &evmmech.TransactionReceipt{ + Status: uint64(receipt.Status), + BlockNumber: receipt.BlockNumber.Uint64(), + TxHash: receipt.TxHash.Hex(), + }, nil + } + select { + case <-ctx.Done(): + return nil, ctx.Err() + case <-time.After(time.Second): + } + } + return nil, fmt.Errorf("transaction receipt not found") +} + +func (s *facilitatorEvmSigner) GetBalance(ctx context.Context, address string, tokenAddress string) (*big.Int, error) { + if tokenAddress == "" || tokenAddress == "0x0000000000000000000000000000000000000000" { + return s.client.BalanceAt(ctx, common.HexToAddress(address), nil) + } + const erc20ABI = `[{"constant":true,"inputs":[{"name":"account","type":"address"}],"name":"balanceOf","outputs":[{"name":"","type":"uint256"}],"type":"function"}]` + out, err := s.ReadContract(ctx, tokenAddress, []byte(erc20ABI), "balanceOf", common.HexToAddress(address)) + if err != nil { + return nil, err + } + if balance, ok := out.(*big.Int); ok { + return balance, nil + } + return nil, fmt.Errorf("unexpected balance type: %T", out) +} + +func (s *facilitatorEvmSigner) GetCode(ctx context.Context, address string) ([]byte, error) { + return s.client.CodeAt(ctx, common.HexToAddress(address), nil) +} + +func buildTypedData( + domain evmmech.TypedDataDomain, + in map[string][]evmmech.TypedDataField, + primaryType string, + message map[string]interface{}, +) apitypes.TypedData { + td := apitypes.TypedData{ + Types: apitypes.Types{}, + PrimaryType: primaryType, + Domain: apitypes.TypedDataDomain{ + Name: toString(domain.Name), + Version: toString(domain.Version), + ChainId: toHexBigInt(domain.ChainID), + VerifyingContract: toString(domain.VerifyingContract), + }, + Message: message, + } + for name, fields := range in { + conv := make([]apitypes.Type, len(fields)) + for i, f := range fields { + conv[i] = apitypes.Type{Name: f.Name, Type: f.Type} + } + td.Types[name] = conv + } + if _, ok := td.Types["EIP712Domain"]; !ok { + td.Types["EIP712Domain"] = []apitypes.Type{ + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + } + } + return td +} + +func toString(v interface{}) string { + switch s := v.(type) { + case string: + return s + case *string: + if s != nil { + return *s + } + } + return "" +} + +func toHexBigInt(v interface{}) *math.HexOrDecimal256 { + switch n := v.(type) { + case *big.Int: + return (*math.HexOrDecimal256)(n) + case int64: + return (*math.HexOrDecimal256)(big.NewInt(n)) + case string: + b, ok := new(big.Int).SetString(n, 10) + if ok { + return (*math.HexOrDecimal256)(b) + } + } + return (*math.HexOrDecimal256)(big.NewInt(0)) +} diff --git a/examples/go/facilitator/batch-settlement/go.mod b/examples/go/facilitator/batch-settlement/go.mod new file mode 100644 index 0000000000..8ab6c6a114 --- /dev/null +++ b/examples/go/facilitator/batch-settlement/go.mod @@ -0,0 +1,37 @@ +module github.com/x402-foundation/x402/examples/go/facilitator/batch-settlement + +go 1.24.0 + +toolchain go1.24.1 + +replace github.com/x402-foundation/x402/go => ../../../../go + +require ( + github.com/ethereum/go-ethereum v1.16.7 + github.com/joho/godotenv v1.5.1 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect + github.com/bits-and-blooms/bitset v1.20.0 // indirect + github.com/consensys/gnark-crypto v0.18.0 // indirect + github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect + github.com/ethereum/go-verkle v0.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/holiman/uint256 v1.3.2 // indirect + github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect + github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect +) diff --git a/examples/go/facilitator/batch-settlement/go.sum b/examples/go/facilitator/batch-settlement/go.sum new file mode 100644 index 0000000000..f57af6f3ca --- /dev/null +++ b/examples/go/facilitator/batch-settlement/go.sum @@ -0,0 +1,189 @@ +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= +github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= +github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= +github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= +github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= +github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= +github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= +github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= +github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8= +github.com/ethereum/go-ethereum v1.16.7 h1:qeM4TvbrWK0UC0tgkZ7NiRsmBGwsjqc64BHo20U59UQ= +github.com/ethereum/go-ethereum v1.16.7/go.mod h1:Fs6QebQbavneQTYcA39PEKv2+zIjX7rPUZ14DER46wk= +github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= +github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= +github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= +github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= +github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= +github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= +github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM= +github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw= +github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/go/facilitator/batch-settlement/main.go b/examples/go/facilitator/batch-settlement/main.go new file mode 100644 index 0000000000..c6dc4ba5b3 --- /dev/null +++ b/examples/go/facilitator/batch-settlement/main.go @@ -0,0 +1,137 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "net/http" + "os" + "time" + + "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + batchedfac "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/facilitator" +) + +const defaultPort = "4022" + +func main() { + _ = godotenv.Load() + + port := envOr("PORT", defaultPort) + + evmPrivateKey := os.Getenv("EVM_PRIVATE_KEY") + if evmPrivateKey == "" { + fmt.Println("EVM_PRIVATE_KEY environment variable is required") + os.Exit(1) + } + + rpcURL := envOr("EVM_RPC_URL", "https://sepolia.base.org") + + // receiverAuthorizer signs ClaimBatch / Refund messages. Defaults to the same + // key as the facilitator if a dedicated authorizer key isn't supplied. + authKey := envOr("EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY", evmPrivateKey) + + evmSigner, err := newFacilitatorEvmSigner(evmPrivateKey, rpcURL) + if err != nil { + fmt.Printf("Failed to create EVM signer: %v\n", err) + os.Exit(1) + } + + authorizer, err := newAuthorizerSigner(authKey) + if err != nil { + fmt.Printf("Failed to create authorizer signer: %v\n", err) + os.Exit(1) + } + + fmt.Printf("EVM Facilitator account: %s\n", evmSigner.GetAddresses()[0]) + fmt.Printf("EVM Receiver Authorizer: %s\n", authorizer.Address()) + + facilitator := x402.Newx402Facilitator() + facilitator.Register( + []x402.Network{"eip155:84532"}, + batchedfac.NewBatchSettlementEvmScheme(evmSigner, authorizer), + ) + + facilitator.OnAfterVerify(func(ctx x402.FacilitatorVerifyResultContext) error { + fmt.Printf("Payment verified\n") + return nil + }) + facilitator.OnAfterSettle(func(ctx x402.FacilitatorSettleResultContext) error { + fmt.Printf("Payment settled: %s\n", ctx.Result.Transaction) + return nil + }) + + mux := http.NewServeMux() + + mux.HandleFunc("GET /supported", func(w http.ResponseWriter, r *http.Request) { + writeJSON(w, http.StatusOK, facilitator.GetSupported()) + }) + + mux.HandleFunc("POST /verify", func(w http.ResponseWriter, r *http.Request) { + ctx, cancel := context.WithTimeout(r.Context(), 30*time.Second) + defer cancel() + + payload, requirements, err := readVerifyBody(r) + if err != nil { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) + return + } + result, err := facilitator.Verify(ctx, payload, requirements) + if err != nil { + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) + return + } + writeJSON(w, http.StatusOK, result) + }) + + mux.HandleFunc("POST /settle", func(w http.ResponseWriter, r *http.Request) { + ctx, cancel := context.WithTimeout(r.Context(), 60*time.Second) + defer cancel() + + payload, requirements, err := readVerifyBody(r) + if err != nil { + writeJSON(w, http.StatusBadRequest, map[string]string{"error": err.Error()}) + return + } + result, err := facilitator.Settle(ctx, payload, requirements) + if err != nil { + writeJSON(w, http.StatusInternalServerError, map[string]string{"error": err.Error()}) + return + } + writeJSON(w, http.StatusOK, result) + }) + + fmt.Printf("Facilitator listening on http://localhost:%s\n", port) + if err := http.ListenAndServe(":"+port, mux); err != nil { + fmt.Printf("Server error: %v\n", err) + os.Exit(1) + } +} + +func envOr(key, def string) string { + if v := os.Getenv(key); v != "" { + return v + } + return def +} + +func readVerifyBody(r *http.Request) (json.RawMessage, json.RawMessage, error) { + var body struct { + PaymentPayload json.RawMessage `json:"paymentPayload"` + PaymentRequirements json.RawMessage `json:"paymentRequirements"` + } + if err := json.NewDecoder(r.Body).Decode(&body); err != nil { + return nil, nil, fmt.Errorf("invalid JSON body: %w", err) + } + if len(body.PaymentPayload) == 0 || len(body.PaymentRequirements) == 0 { + return nil, nil, fmt.Errorf("missing paymentPayload or paymentRequirements") + } + return body.PaymentPayload, body.PaymentRequirements, nil +} + +func writeJSON(w http.ResponseWriter, status int, v any) { + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(status) + _ = json.NewEncoder(w).Encode(v) +} diff --git a/examples/go/servers/advanced/all_networks.go b/examples/go/servers/advanced/all_networks.go index 24de2fcc43..fb3501baa1 100644 --- a/examples/go/servers/advanced/all_networks.go +++ b/examples/go/servers/advanced/all_networks.go @@ -6,13 +6,13 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" ginfw "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) /** diff --git a/examples/go/servers/advanced/bazaar.go b/examples/go/servers/advanced/bazaar.go index 22976f042d..4e0288c136 100644 --- a/examples/go/servers/advanced/bazaar.go +++ b/examples/go/servers/advanced/bazaar.go @@ -6,14 +6,14 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - "github.com/coinbase/x402/go/extensions/types" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" ginfw "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + "github.com/x402-foundation/x402/go/extensions/types" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) const DefaultPort = "4021" @@ -114,7 +114,7 @@ func main() { {Network: evmNetwork, Server: evm.NewExactEvmScheme()}, }, SyncFacilitatorOnStart: true, - Timeout: 30 * time.Second, + Timeout: 30 * time.Second, })) r.GET("/weather", func(c *ginfw.Context) { @@ -145,4 +145,3 @@ func main() { os.Exit(1) } } - diff --git a/examples/go/servers/advanced/custom-money-definition.go b/examples/go/servers/advanced/custom-money-definition.go index 13d5e8973d..163ae29251 100644 --- a/examples/go/servers/advanced/custom-money-definition.go +++ b/examples/go/servers/advanced/custom-money-definition.go @@ -7,12 +7,12 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" ginfw "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) const DefaultPort = "4021" @@ -108,7 +108,7 @@ func main() { {Network: evmNetwork, Server: evmScheme}, // Use custom scheme }, SyncFacilitatorOnStart: true, - Timeout: 30 * time.Second, + Timeout: 30 * time.Second, })) r.GET("/weather", func(c *ginfw.Context) { @@ -128,4 +128,3 @@ func main() { os.Exit(1) } } - diff --git a/examples/go/servers/advanced/dynamic-pay-to.go b/examples/go/servers/advanced/dynamic-pay-to.go index 849792f593..ec8ea2648b 100644 --- a/examples/go/servers/advanced/dynamic-pay-to.go +++ b/examples/go/servers/advanced/dynamic-pay-to.go @@ -7,12 +7,12 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" ginfw "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) const DefaultPort = "4021" @@ -110,7 +110,7 @@ func main() { {Network: evmNetwork, Server: evm.NewExactEvmScheme()}, }, SyncFacilitatorOnStart: true, - Timeout: 30 * time.Second, + Timeout: 30 * time.Second, })) r.GET("/weather", func(c *ginfw.Context) { @@ -130,4 +130,3 @@ func main() { os.Exit(1) } } - diff --git a/examples/go/servers/advanced/dynamic-price.go b/examples/go/servers/advanced/dynamic-price.go index 5b6dc89c23..dbe1aaa132 100644 --- a/examples/go/servers/advanced/dynamic-price.go +++ b/examples/go/servers/advanced/dynamic-price.go @@ -7,12 +7,12 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" ginfw "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) const DefaultPort = "4021" @@ -58,10 +58,10 @@ func main() { dynamicPrice := func(ctx context.Context, reqCtx x402http.HTTPRequestContext) (x402.Price, error) { // In a real implementation, you would extract the tier from query params // or headers using reqCtx.Adapter - + // For this example, we'll demonstrate the concept with a default tier tier := "standard" // default - + // You could extract tier from request like: // if reqCtx.Adapter != nil { // tier = extractQueryParam(reqCtx.Adapter, "tier") @@ -101,7 +101,7 @@ func main() { {Network: evmNetwork, Server: evm.NewExactEvmScheme()}, }, SyncFacilitatorOnStart: true, - Timeout: 30 * time.Second, + Timeout: 30 * time.Second, })) r.GET("/weather", func(c *ginfw.Context) { @@ -141,4 +141,3 @@ func main() { os.Exit(1) } } - diff --git a/examples/go/servers/advanced/eip2612-gas-sponsoring.go b/examples/go/servers/advanced/eip2612-gas-sponsoring.go index dba8157f0c..99ff6436f0 100644 --- a/examples/go/servers/advanced/eip2612-gas-sponsoring.go +++ b/examples/go/servers/advanced/eip2612-gas-sponsoring.go @@ -6,13 +6,13 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" ginfw "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) const eip2612DefaultPort = "4021" diff --git a/examples/go/servers/advanced/go.mod b/examples/go/servers/advanced/go.mod index 4b2303b641..84e13727a3 100644 --- a/examples/go/servers/advanced/go.mod +++ b/examples/go/servers/advanced/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/servers/gin +module github.com/x402-foundation/x402/examples/go/servers/gin go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/gin-gonic/gin v1.11.0 github.com/joho/godotenv v1.5.1 ) diff --git a/examples/go/servers/advanced/hooks.go b/examples/go/servers/advanced/hooks.go index 402c9dbf2e..584498b2ac 100644 --- a/examples/go/servers/advanced/hooks.go +++ b/examples/go/servers/advanced/hooks.go @@ -5,12 +5,12 @@ import ( "net/http" "os" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" ginfw "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) const DefaultPort = "4021" @@ -48,7 +48,7 @@ func main() { // Create EVM scheme server evmScheme := evm.NewExactEvmScheme() - // Create x402 resource server with hooks + // Create x402 resource server with hooks server := x402.Newx402ResourceServer( x402.WithFacilitatorClient(facilitatorClient), ). diff --git a/examples/go/servers/batch-settlement/.env-example b/examples/go/servers/batch-settlement/.env-example new file mode 100644 index 0000000000..e39e3110de --- /dev/null +++ b/examples/go/servers/batch-settlement/.env-example @@ -0,0 +1,10 @@ +EVM_ADDRESS=0x... +FACILITATOR_URL=http://localhost:4022 + +# Recommended: self-managed receiver authorizer key. Channels survive facilitator changes. +# Omit to delegate to the facilitator's advertised authorizer (channels are then bound to +# that facilitator until drained). +EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY= + +STORAGE_DIR= +DEFERRED_WITHDRAW_DELAY_SECONDS=900 diff --git a/examples/go/servers/batch-settlement/README.md b/examples/go/servers/batch-settlement/README.md new file mode 100644 index 0000000000..22807c17c3 --- /dev/null +++ b/examples/go/servers/batch-settlement/README.md @@ -0,0 +1,36 @@ +# Batch-Settlement Server (Go) + +Demo resource server using the batch-settlement scheme: a client opens a payment channel with a single deposit; subsequent paid requests update an off-chain voucher. The `ChannelManager` periodically claims and settles onchain. + +The route demonstrates **dynamic pricing**: the client authorizes up to `$0.01` per request, and the handler bills a random fraction of that via `Settlement-Overrides`. + +## Run + +```bash +cp .env-example .env +# fill in EVM_ADDRESS (the receiver) and FACILITATOR_URL + +go run . +``` + +The server listens on `http://localhost:4021` and exposes `GET /weather`. Pair with `examples/go/clients/batch-settlement` and `examples/go/facilitator/batch-settlement`. + +## Environment + +| Variable | Required | Description | +|---------------------------------------|----------|-------------| +| `EVM_ADDRESS` | yes | `payTo` address (channel receiver) | +| `FACILITATOR_URL` | yes | Batch-settlement facilitator endpoint (e.g. `http://localhost:4022`) | +| `EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY` | no | Self-managed authorizer key. **Recommended** — channels survive facilitator changes when you control this key. Omit to delegate to the facilitator's advertised authorizer (existing channels must be drained before switching facilitators). | +| `STORAGE_DIR` | no | If set, persists channel sessions under `${STORAGE_DIR}/server/` | +| `DEFERRED_WITHDRAW_DELAY_SECONDS` | no | Channel `withdrawDelay`; defaults to `86400` (1 day) | + +## Auto-settlement + +The example wires up a `ChannelManager` with simple local-demo triggers: + +- **Claim** every 60 s. +- **Settle** every 120 s (sweeps claimed funds to `payTo`). +- **Refund** channels idle for 180 s (cooperative — claims first, then refunds the unclaimed remainder to the payer). + +For production, choose a `withdrawDelay` greater than your claim cadence plus an operational safety margin. diff --git a/examples/go/servers/batch-settlement/go.mod b/examples/go/servers/batch-settlement/go.mod new file mode 100644 index 0000000000..6b637a6e80 --- /dev/null +++ b/examples/go/servers/batch-settlement/go.mod @@ -0,0 +1,42 @@ +module github.com/x402-foundation/x402/examples/go/servers/batch-settlement + +go 1.24.0 + +toolchain go1.24.1 + +replace github.com/x402-foundation/x402/go => ../../../../go + +require ( + github.com/ethereum/go-ethereum v1.16.7 + github.com/joho/godotenv v1.5.1 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 +) + +require ( + github.com/Microsoft/go-winio v0.6.2 // indirect + github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 // indirect + github.com/StackExchange/wmi v1.2.1 // indirect + github.com/bits-and-blooms/bitset v1.20.0 // indirect + github.com/consensys/gnark-crypto v0.18.0 // indirect + github.com/crate-crypto/go-eth-kzg v1.4.0 // indirect + github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a // indirect + github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 // indirect + github.com/ethereum/c-kzg-4844/v2 v2.1.5 // indirect + github.com/ethereum/go-verkle v0.2.2 // indirect + github.com/go-ole/go-ole v1.3.0 // indirect + github.com/gorilla/websocket v1.4.2 // indirect + github.com/holiman/uint256 v1.3.2 // indirect + github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible // indirect + github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe // indirect + github.com/tklauser/go-sysconf v0.3.12 // indirect + github.com/tklauser/numcpus v0.6.1 // indirect + github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect + github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect + github.com/xeipuuv/gojsonschema v1.2.0 // indirect + golang.org/x/crypto v0.46.0 // indirect + golang.org/x/net v0.48.0 // indirect + golang.org/x/sync v0.19.0 // indirect + golang.org/x/sys v0.39.0 // indirect + golang.org/x/text v0.32.0 // indirect +) diff --git a/examples/go/servers/batch-settlement/go.sum b/examples/go/servers/batch-settlement/go.sum new file mode 100644 index 0000000000..97963a23e2 --- /dev/null +++ b/examples/go/servers/batch-settlement/go.sum @@ -0,0 +1,202 @@ +github.com/DataDog/zstd v1.4.5 h1:EndNeuB0l9syBZhut0wns3gV1hL8zX8LIu6ZiVHWLIQ= +github.com/DataDog/zstd v1.4.5/go.mod h1:1jcaCB/ufaK+sKp1NBhlGmpz41jOoPQ35bpF36t7BBo= +github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= +github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6 h1:1zYrtlhrZ6/b6SAjLSfKzWtdgqK0U+HtH/VcBWh1BaU= +github.com/ProjectZKM/Ziren/crates/go-runtime/zkvm_runtime v0.0.0-20251001021608-1fe7b43fc4d6/go.mod h1:ioLG6R+5bUSO1oeGSDxOV3FADARuMoytZCSX6MEMQkI= +github.com/StackExchange/wmi v1.2.1 h1:VIkavFPXSjcnS+O8yTq7NI32k0R5Aj+v39y29VYDOSA= +github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8= +github.com/VictoriaMetrics/fastcache v1.13.0 h1:AW4mheMR5Vd9FkAPUv+NH6Nhw+fmbTMGMsNAoA/+4G0= +github.com/VictoriaMetrics/fastcache v1.13.0/go.mod h1:hHXhl4DA2fTL2HTZDJFXWgW0LNjo6B+4aj2Wmng3TjU= +github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM= +github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw= +github.com/bits-and-blooms/bitset v1.20.0 h1:2F+rfL86jE2d/bmw7OhqUg2Sj/1rURkBn3MdfoPyRVU= +github.com/bits-and-blooms/bitset v1.20.0/go.mod h1:7hO7Gc7Pp1vODcmWvKMRA9BNmbv6a/7QIWpPxHddWR8= +github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs= +github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cockroachdb/errors v1.11.3 h1:5bA+k2Y6r+oz/6Z/RFlNeVCesGARKuC6YymtcDrbC/I= +github.com/cockroachdb/errors v1.11.3/go.mod h1:m4UIW4CDjx+R5cybPsNrRbreomiFqt8o1h1wUVazSd8= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce h1:giXvy4KSc/6g/esnpM7Geqxka4WSqI1SZc7sMJFd3y4= +github.com/cockroachdb/fifo v0.0.0-20240606204812-0bbfbd93a7ce/go.mod h1:9/y3cnZ5GKakj/H4y9r9GTjCvAFta7KLgSHPJJYc52M= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE= +github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b/go.mod h1:Vz9DsVWQQhf3vs21MhPMZpMGSht7O/2vFW2xusFUVOs= +github.com/cockroachdb/pebble v1.1.5 h1:5AAWCBWbat0uE0blr8qzufZP5tBjkRyy/jWe1QWLnvw= +github.com/cockroachdb/pebble v1.1.5/go.mod h1:17wO9el1YEigxkP/YtV8NtCivQDgoCyBg5c4VR/eOWo= +github.com/cockroachdb/redact v1.1.5 h1:u1PMllDkdFfPWaNGMyLD1+so+aq3uUItthCFqzwPJ30= +github.com/cockroachdb/redact v1.1.5/go.mod h1:BVNblN9mBWFyMyqK1k3AAiSxhvhfK2oOZZ2lK+dpvRg= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06 h1:zuQyyAKVxetITBuuhv3BI9cMrmStnpT18zmgmTxunpo= +github.com/cockroachdb/tokenbucket v0.0.0-20230807174530-cc333fc44b06/go.mod h1:7nc4anLGjupUW/PeY5qiNYsdNXj7zopG+eqsS7To5IQ= +github.com/consensys/gnark-crypto v0.18.0 h1:vIye/FqI50VeAr0B3dx+YjeIvmc3LWz4yEfbWBpTUf0= +github.com/consensys/gnark-crypto v0.18.0/go.mod h1:L3mXGFTe1ZN+RSJ+CLjUt9x7PNdx8ubaYfDROyp2Z8c= +github.com/cpuguy83/go-md2man/v2 v2.0.5 h1:ZtcqGrnekaHpVLArFSe4HK5DoKx1T0rq2DwVB0alcyc= +github.com/cpuguy83/go-md2man/v2 v2.0.5/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/crate-crypto/go-eth-kzg v1.4.0 h1:WzDGjHk4gFg6YzV0rJOAsTK4z3Qkz5jd4RE3DAvPFkg= +github.com/crate-crypto/go-eth-kzg v1.4.0/go.mod h1:J9/u5sWfznSObptgfa92Jq8rTswn6ahQWEuiLHOjCUI= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a h1:W8mUrRp6NOVl3J+MYp5kPMoUZPp7aOYHtaua31lwRHg= +github.com/crate-crypto/go-ipa v0.0.0-20240724233137-53bbb0ceb27a/go.mod h1:sTwzHBvIzm2RfVCGNEBZgRyjwK40bVoun3ZnGOCafNM= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dchest/siphash v1.2.3 h1:QXwFc8cFOR2dSa/gE6o/HokBMWtLUaNDVd+22aKHeEA= +github.com/dchest/siphash v1.2.3/go.mod h1:0NvQU092bT0ipiFN++/rXm69QG9tVxLAlQHIXMPAkHc= +github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= +github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/decred/dcrd/crypto/blake256 v1.0.0 h1:/8DMNYp9SGi5f0w7uCm6d6M4OU2rGFK09Y2A4Xv7EE0= +github.com/decred/dcrd/crypto/blake256 v1.0.0/go.mod h1:sQl2p6Y26YV+ZOcSTP6thNdn47hh8kt6rqSlvmrXFAc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1 h1:YLtO71vCjJRCBcrPMtQ9nqBsqpA1m5sE92cU+pd5Mcc= +github.com/decred/dcrd/dcrec/secp256k1/v4 v4.0.1/go.mod h1:hyedUtir6IdtD/7lIxGeCxkaw7y45JueMRL4DIyJDKs= +github.com/emicklei/dot v1.6.2 h1:08GN+DD79cy/tzN6uLCT84+2Wk9u+wvqP+Hkx/dIR8A= +github.com/emicklei/dot v1.6.2/go.mod h1:DeV7GvQtIw4h2u73RKBkkFdvVAz0D9fzeJrgPW6gy/s= +github.com/ethereum/c-kzg-4844/v2 v2.1.5 h1:aVtoLK5xwJ6c5RiqO8g8ptJ5KU+2Hdquf6G3aXiHh5s= +github.com/ethereum/c-kzg-4844/v2 v2.1.5/go.mod h1:u59hRTTah4Co6i9fDWtiCjTrblJv0UwsqZKCc0GfgUs= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab h1:rvv6MJhy07IMfEKuARQ9TKojGqLVNxQajaXEp/BoqSk= +github.com/ethereum/go-bigmodexpfix v0.0.0-20250911101455-f9e208c548ab/go.mod h1:IuLm4IsPipXKF7CW5Lzf68PIbZ5yl7FFd74l/E0o9A8= +github.com/ethereum/go-ethereum v1.16.7 h1:qeM4TvbrWK0UC0tgkZ7NiRsmBGwsjqc64BHo20U59UQ= +github.com/ethereum/go-ethereum v1.16.7/go.mod h1:Fs6QebQbavneQTYcA39PEKv2+zIjX7rPUZ14DER46wk= +github.com/ethereum/go-verkle v0.2.2 h1:I2W0WjnrFUIzzVPwm8ykY+7pL2d4VhlsePn4j7cnFk8= +github.com/ethereum/go-verkle v0.2.2/go.mod h1:M3b90YRnzqKyyzBEWJGqj8Qff4IDeXnzFw0P9bFw3uk= +github.com/ferranbt/fastssz v0.1.4 h1:OCDB+dYDEQDvAgtAGnTSidK1Pe2tW3nFV40XyMkTeDY= +github.com/ferranbt/fastssz v0.1.4/go.mod h1:Ea3+oeoRGGLGm5shYAeDgu6PGUlcvQhE2fILyD9+tGg= +github.com/getsentry/sentry-go v0.27.0 h1:Pv98CIbtB3LkMWmXi4Joa5OOcwbmnX88sF5qbK3r3Ps= +github.com/getsentry/sentry-go v0.27.0/go.mod h1:lc76E2QywIyW8WuBnwl8Lc4bkmQH4+w1gwTf25trprY= +github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0= +github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= +github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= +github.com/gofrs/flock v0.12.1 h1:MTLVXXHf8ekldpJk3AKicLij9MdwOWkZ+a/jHHZby9E= +github.com/gofrs/flock v0.12.1/go.mod h1:9zxTsyu5xtJ9DK+1tFZyibEV7y3uwDxPPfbxeeHCoD0= +github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= +github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= +github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI= +github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= +github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/golang/snappy v1.0.0 h1:Oy607GVXHs7RtbggtPBnr2RmDArIsAefDwvrdWvRhGs= +github.com/golang/snappy v1.0.0/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= +github.com/google/gofuzz v1.2.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/gorilla/websocket v1.4.2 h1:+/TMaTYc4QFitKJxsQ7Yye35DkWvkdLcvGKqM+x0Ufc= +github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= +github.com/hashicorp/go-bexpr v0.1.10 h1:9kuI5PFotCboP3dkDYFr/wi0gg0QVbSNz5oFRpxn4uE= +github.com/hashicorp/go-bexpr v0.1.10/go.mod h1:oxlubA2vC/gFVfX1A6JGp7ls7uCDlfJn732ehYYg+g0= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db h1:IZUYC/xb3giYwBLMnr8d0TGTzPKFGNTCGgGLoyeX330= +github.com/holiman/billy v0.0.0-20250707135307-f2f9b9aae7db/go.mod h1:xTEYN9KCHxuYHs+NmrmzFcnvHMzLLNiGFafCb1n3Mfg= +github.com/holiman/bloomfilter/v2 v2.0.3 h1:73e0e/V0tCydx14a0SCYS/EWCxgwLZ18CZcZKVu0fao= +github.com/holiman/bloomfilter/v2 v2.0.3/go.mod h1:zpoh+gs7qcpqrHr3dB55AMiJwo0iURXE7ZOP9L9hSkA= +github.com/holiman/uint256 v1.3.2 h1:a9EgMPSC1AAaj1SZL5zIQD3WbwTuHrMGOerLjGmM/TA= +github.com/holiman/uint256 v1.3.2/go.mod h1:EOMSn4q6Nyt9P6efbI3bueV4e1b3dGlUCXeiRV4ng7E= +github.com/huin/goupnp v1.3.0 h1:UvLUlWDNpoUdYzb2TCn+MuTWtcjXKSza2n6CBdQ0xXc= +github.com/huin/goupnp v1.3.0/go.mod h1:gnGPsThkYa7bFi/KWmEysQRf48l2dvR5bxr2OFckNX8= +github.com/jackpal/go-nat-pmp v1.0.2 h1:KzKSgb7qkJvOUTqYl9/Hg/me3pWgBmERKrTGD7BdWus= +github.com/jackpal/go-nat-pmp v1.0.2/go.mod h1:QPH045xvCAeXUZOxsnwmrtiCoxIr9eob+4orBN1SBKc= +github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0= +github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4= +github.com/klauspost/compress v1.16.0 h1:iULayQNOReoYUe+1qtKOqw9CwJv3aNQu8ivo7lw1HU4= +github.com/klauspost/compress v1.16.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= +github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= +github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= +github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= +github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= +github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= +github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= +github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= +github.com/leanovate/gopter v0.2.11 h1:vRjThO1EKPb/1NsDXuDrzldR28RLkBflWYcU9CvzWu4= +github.com/leanovate/gopter v0.2.11/go.mod h1:aK3tzZP/C+p1m3SPRE4SYZFGP7jjkuSI4f7Xvpt0S9c= +github.com/mattn/go-colorable v0.1.14 h1:9A9LHSqF/7dyVVX6g0U9cwm9pG3kP9gSzcuIPHPsaIE= +github.com/mattn/go-colorable v0.1.14/go.mod h1:6LmQG8QLFO4G5z1gPvYEzlUgJ2wF+stgPZH1UqBm1s8= +github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= +github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= +github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU= +github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo= +github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4= +github.com/minio/sha256-simd v1.0.0 h1:v1ta+49hkWZyvaKwrQB8elexRqm6Y0aMLjCNsrYxo6g= +github.com/minio/sha256-simd v1.0.0/go.mod h1:OuYzVNI5vcoYIAmbIvHPl3N3jUzVedXbKy5RFepssQM= +github.com/mitchellh/mapstructure v1.4.1 h1:CpVNEelQCZBooIPDn+AR3NpivK/TIKU8bDxdASFVQag= +github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= +github.com/mitchellh/pointerstructure v1.2.0 h1:O+i9nHnXS3l/9Wu7r4NrEdwA2VFTicjUEN1uBnDo34A= +github.com/mitchellh/pointerstructure v1.2.0/go.mod h1:BRAsLI5zgXmw97Lf6s25bs8ohIXc3tViBH44KcwB2g4= +github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= +github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= +github.com/pion/dtls/v2 v2.2.7 h1:cSUBsETxepsCSFSxC3mc/aDo14qQLMSL+O6IjG28yV8= +github.com/pion/dtls/v2 v2.2.7/go.mod h1:8WiMkebSHFD0T+dIU+UeBaoV7kDhOW5oDCzZ7WZ/F9s= +github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY= +github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/stun/v2 v2.0.0 h1:A5+wXKLAypxQri59+tmQKVs7+l6mMM+3d+eER9ifRU0= +github.com/pion/stun/v2 v2.0.0/go.mod h1:22qRSh08fSEttYUmJZGlriq9+03jtVmXNODgLccj8GQ= +github.com/pion/transport/v2 v2.2.1 h1:7qYnCBlpgSJNYMbLCKuSY9KbQdBFoETvPNETv0y4N7c= +github.com/pion/transport/v2 v2.2.1/go.mod h1:cXXWavvCnFF6McHTft3DWS9iic2Mftcz1Aq29pGcU5g= +github.com/pion/transport/v3 v3.0.1 h1:gDTlPJwROfSfz6QfSi0ZmeCSkFcnWWiiR9ES0ouANiM= +github.com/pion/transport/v3 v3.0.1/go.mod h1:UY7kiITrlMv7/IKgd5eTUcaahZx5oUN3l9SzK5f5xE0= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v1.15.0 h1:5fCgGYogn0hFdhyhLbw7hEsWxufKtY9klyvdNfFlFhM= +github.com/prometheus/client_golang v1.15.0/go.mod h1:e9yaBhRPU2pPNsZwE+JdQl0KEt1N9XgF6zxWmaC0xOk= +github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4= +github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w= +github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM= +github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc= +github.com/prometheus/procfs v0.9.0 h1:wzCHvIvM5SxWqYvwgVL7yJY8Lz3PKn49KQtpgMYJfhI= +github.com/prometheus/procfs v0.9.0/go.mod h1:+pB4zwohETzFnmlpe6yd2lSc+0/46IYZRB/chUwxUZY= +github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY= +github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= +github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= +github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= +github.com/rs/cors v1.7.0 h1:+88SsELBHx5r+hZ8TCkggzSstaWNbDvThkVK8H6f9ik= +github.com/rs/cors v1.7.0/go.mod h1:gFx+x8UowdsKA9AchylcLynDq+nNFfI8FkUZdN/jGCU= +github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible h1:Bn1aCHHRnjv4Bl16T8rcaFjYSrGrIZvpiGO6P3Q4GpU= +github.com/shirou/gopsutil v3.21.4-0.20210419000835-c7a38de76ee5+incompatible/go.mod h1:5b4v6he4MtMOwMlS0TUMTu2PcXUg8+E1lC7eC3UO/RA= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U= +github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U= +github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe h1:nbdqkIGOGfUAD54q1s2YBcBz/WcsxCO9HUQ4aGV5hUw= +github.com/supranational/blst v0.3.16-0.20250831170142-f48500c1fdbe/go.mod h1:jZJtfjgudtNl4en1tzwPIV3KjUnQUvG3/j+w+fVonLw= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7 h1:epCh84lMvA70Z7CTTCmYQn2CKbY8j86K7/FAIr141uY= +github.com/syndtr/goleveldb v1.0.1-0.20210819022825-2ae1ddf74ef7/go.mod h1:q4W45IWZaF22tdD+VEXcAWRA037jwmWEB5VWYORlTpc= +github.com/tklauser/go-sysconf v0.3.12 h1:0QaGUFOdQaIVdPgfITYzaTegZvdCjmYO52cSFAEVmqU= +github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= +github.com/tklauser/numcpus v0.6.1 h1:ng9scYS7az0Bk4OZLvrNXNSAO2Pxr1XXRAPyjhIx+Fk= +github.com/tklauser/numcpus v0.6.1/go.mod h1:1XfjsgE2zo8GVw7POkMbHENHzVg3GzmoZ9fESEdAacY= +github.com/urfave/cli/v2 v2.27.5 h1:WoHEJLdsXr6dDWoJgMq/CboDmyY/8HMMH1fTECbih+w= +github.com/urfave/cli/v2 v2.27.5/go.mod h1:3Sevf16NykTbInEnD0yKkjDAeZDS0A6bzhBH5hrMvTQ= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c= +github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0= +github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415/go.mod h1:GwrjFmJcFw6At/Gs6z4yjiIwzuJ1/+UwLxMQDVQXShQ= +github.com/xeipuuv/gojsonschema v1.2.0 h1:LhYJRs+L4fBtjZUfuSZIKGeVu0QRy8e5Xi7D17UxZ74= +github.com/xeipuuv/gojsonschema v1.2.0/go.mod h1:anYRn/JVcOK2ZgGU+IjEV4nwlhoK5sQluxsYJ78Id3Y= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1 h1:gEOO8jv9F4OT7lGCjxCBTO/36wtF6j2nSip77qHd4x4= +github.com/xrash/smetrics v0.0.0-20240521201337-686a1a2994c1/go.mod h1:Ohn+xnUBiLI6FVj/9LpzZWtj1/D6lUovWYBkxHVV3aM= +golang.org/x/crypto v0.46.0 h1:cKRW/pmt1pKAfetfu+RCEvjvZkA9RimPbh7bhFjGVBU= +golang.org/x/crypto v0.46.0/go.mod h1:Evb/oLKmMraqjZ2iQTwDwvCtJkczlDuTmdJXoZVzqU0= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df h1:UA2aFVmmsIlefxMk29Dp2juaUSth8Pyn3Tq5Y5mJGME= +golang.org/x/exp v0.0.0-20230626212559-97b1e661b5df/go.mod h1:FXUEEKJgO7OQYeo8N01OfiKP8RXMtf6e8aTskBGqWdc= +golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU= +golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY= +golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= +golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= +golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk= +golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU= +golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY= +golang.org/x/time v0.14.0 h1:MRx4UaLrDotUKUdCIqzPC48t1Y9hANFKIRpNx+Te8PI= +golang.org/x/time v0.14.0/go.mod h1:eL/Oa2bBBK0TkX57Fyni+NgnyQQN4LitPmob2Hjnqw4= +google.golang.org/protobuf v1.36.9 h1:w2gp2mA27hUeUzj9Ex9FBjsBm40zfaDtEWow293U7Iw= +google.golang.org/protobuf v1.36.9/go.mod h1:fuxRtAxBytpl4zzqUh6/eyUujkJdNiuEkXntxiD/uRU= +gopkg.in/natefinch/lumberjack.v2 v2.2.1 h1:bBRl1b0OH9s/DuPhuXpNl+VtCaJXFZ5/uEFST95x9zc= +gopkg.in/natefinch/lumberjack.v2 v2.2.1/go.mod h1:YD8tP3GAjkrDg1eZH7EGmyESg/lsYskCTPBJVb9jqSc= +gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/examples/go/servers/batch-settlement/main.go b/examples/go/servers/batch-settlement/main.go new file mode 100644 index 0000000000..63ff1f1484 --- /dev/null +++ b/examples/go/servers/batch-settlement/main.go @@ -0,0 +1,184 @@ +package main + +import ( + "context" + "encoding/json" + "fmt" + "math/rand" + "net/http" + "os" + "os/signal" + "regexp" + "strconv" + "syscall" + "time" + + "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + nethttpmw "github.com/x402-foundation/x402/go/http/nethttp" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + batchedserver "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/server" +) + +const ( + defaultPort = "4021" + network = x402.Network("eip155:84532") + maxPrice = "$0.01" +) + +func main() { + _ = godotenv.Load() + + evmAddress := os.Getenv("EVM_ADDRESS") + if !regexp.MustCompile(`^0x[0-9a-fA-F]{40}$`).MatchString(evmAddress) { + fmt.Println("Missing or invalid EVM_ADDRESS (checksummed 20-byte hex, 0x-prefixed)") + os.Exit(1) + } + + facilitatorURL := os.Getenv("FACILITATOR_URL") + if facilitatorURL == "" { + fmt.Println("Missing required FACILITATOR_URL environment variable") + os.Exit(1) + } + + // Default channel withdraw delay is 1 day when the env var is unset. + withdrawDelay := 86400 + if v := os.Getenv("DEFERRED_WITHDRAW_DELAY_SECONDS"); v != "" { + if n, err := strconv.Atoi(v); err == nil { + withdrawDelay = n + } + } + + receiverAuthKey := os.Getenv("EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY") + storageDir := os.Getenv("STORAGE_DIR") + + cfg := &batchedserver.BatchSettlementEvmSchemeServerConfig{ + WithdrawDelay: withdrawDelay, + } + if receiverAuthKey != "" { + signer, err := newReceiverAuthorizerSigner(receiverAuthKey) + if err != nil { + fmt.Printf("Invalid EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY: %v\n", err) + os.Exit(1) + } + cfg.ReceiverAuthorizerSigner = signer + } + if storageDir != "" { + cfg.Storage = batchedserver.NewFileChannelStorage(batchsettlement.FileChannelStorageOptions{ + Directory: storageDir, + }) + } + + scheme := batchedserver.NewBatchSettlementEvmScheme(evmAddress, cfg) + + facilitator := x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ + URL: facilitatorURL, + }) + + manager := scheme.CreateChannelManager(facilitator, network) + manager.Start(batchedserver.AutoSettlementConfig{ + ClaimIntervalSecs: 60, + SettleIntervalSecs: 120, + RefundIntervalSecs: 180, + MaxClaimsPerBatch: 100, + // Refund channels after 3 minutes of inactivity. + SelectRefundChannels: func(channels []*batchedserver.ChannelSession, ctx batchedserver.AutoSettlementContext) ([]*batchedserver.ChannelSession, error) { + out := make([]*batchedserver.ChannelSession, 0, len(channels)) + for _, c := range channels { + if c.Balance == "" || c.Balance == "0" { + continue + } + if c.PendingRequest != nil && c.PendingRequest.ExpiresAt > ctx.Now { + continue + } + if ctx.Now-c.LastRequestTimestamp < 180_000 { + continue + } + out = append(out, c) + } + return out, nil + }, + OnClaim: func(r batchedserver.ClaimResult) { + fmt.Printf("Claimed %d vouchers (tx: %s)\n", r.Vouchers, r.Transaction) + }, + OnSettle: func(r batchedserver.SettleResult) { + fmt.Printf("Settled to %s (tx: %s)\n", evmAddress, r.Transaction) + }, + OnRefund: func(r batchedserver.RefundResult) { + fmt.Printf("Refunded channel %s (tx: %s)\n", r.Channel, r.Transaction) + }, + OnError: func(err error) { + fmt.Printf("Settlement error: %v\n", err) + }, + }) + + // Flush pending channel work during interactive shutdown. + sigCh := make(chan os.Signal, 1) + signal.Notify(sigCh, syscall.SIGINT) + + routes := x402http.RoutesConfig{ + "GET /weather": { + Accepts: x402http.PaymentOptions{ + { + Scheme: batchsettlement.SchemeBatched, + Price: maxPrice, + Network: network, + PayTo: evmAddress, + }, + }, + Description: "Weather data", + MimeType: "application/json", + }, + } + + mux := http.NewServeMux() + mux.HandleFunc("GET /weather", func(w http.ResponseWriter, r *http.Request) { + // Bill a random fraction of maxPrice (1-100%) to demonstrate usage-based pricing. + chargedPercent := 1 + rand.Intn(100) + nethttpmw.SetSettlementOverrides(w, &x402.SettlementOverrides{ + Amount: fmt.Sprintf("%d%%", chargedPercent), + }) + + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(map[string]any{ + "report": map[string]any{ + "weather": "sunny", + "temperature": 70, + }, + }) + }) + + handler := nethttpmw.X402Payment(nethttpmw.Config{ + Routes: routes, + Facilitator: facilitator, + Schemes: []nethttpmw.SchemeConfig{ + {Network: network, Server: scheme}, + }, + Timeout: 30 * time.Second, + })(mux) + + server := &http.Server{Addr: ":" + defaultPort, Handler: handler} + go func() { + if err := server.ListenAndServe(); err != nil && err != http.ErrServerClosed { + fmt.Printf("Server error: %v\n", err) + os.Exit(1) + } + }() + + fmt.Printf("Batch-settlement server listening at http://localhost:%s\n", defaultPort) + fmt.Printf(" GET /weather\n") + if cfg.ReceiverAuthorizerSigner != nil { + fmt.Printf(" Receiver authorizer: local signer %s\n", cfg.ReceiverAuthorizerSigner.Address()) + } else { + fmt.Println(" Receiver authorizer: facilitator") + } + + <-sigCh + + fmt.Println("Shutting down — flushing pending claims…") + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + _ = manager.Stop(ctx, &batchedserver.StopOptions{Flush: true}) + _ = server.Shutdown(ctx) +} diff --git a/examples/go/servers/batch-settlement/signer.go b/examples/go/servers/batch-settlement/signer.go new file mode 100644 index 0000000000..180e3c5e6c --- /dev/null +++ b/examples/go/servers/batch-settlement/signer.go @@ -0,0 +1,117 @@ +package main + +import ( + "context" + "crypto/ecdsa" + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + "github.com/x402-foundation/x402/go/mechanisms/evm" +) + +func toString(v interface{}) string { + switch s := v.(type) { + case string: + return s + case *string: + if s != nil { + return *s + } + } + return "" +} + +func toHexBigInt(v interface{}) *math.HexOrDecimal256 { + switch n := v.(type) { + case *big.Int: + return (*math.HexOrDecimal256)(n) + case int64: + return (*math.HexOrDecimal256)(big.NewInt(n)) + case string: + b, ok := new(big.Int).SetString(n, 10) + if ok { + return (*math.HexOrDecimal256)(b) + } + } + return (*math.HexOrDecimal256)(big.NewInt(0)) +} + +// receiverAuthorizerSigner implements server.AuthorizerSigner using a local +// ECDSA key. In production you'd wrap your KMS / HSM here instead. +type receiverAuthorizerSigner struct { + privateKey *ecdsa.PrivateKey + address common.Address +} + +func newReceiverAuthorizerSigner(privateKeyHex string) (*receiverAuthorizerSigner, error) { + pk, err := crypto.HexToECDSA(strings.TrimPrefix(privateKeyHex, "0x")) + if err != nil { + return nil, fmt.Errorf("parse private key: %w", err) + } + return &receiverAuthorizerSigner{ + privateKey: pk, + address: crypto.PubkeyToAddress(pk.PublicKey), + }, nil +} + +func (s *receiverAuthorizerSigner) Address() string { + return s.address.Hex() +} + +func (s *receiverAuthorizerSigner) SignTypedData( + _ context.Context, + domain evm.TypedDataDomain, + types map[string][]evm.TypedDataField, + primaryType string, + message map[string]interface{}, +) ([]byte, error) { + td := apitypes.TypedData{ + Types: apitypes.Types{}, + PrimaryType: primaryType, + Domain: apitypes.TypedDataDomain{ + Name: toString(domain.Name), + Version: toString(domain.Version), + ChainId: toHexBigInt(domain.ChainID), + VerifyingContract: toString(domain.VerifyingContract), + }, + Message: message, + } + for name, fields := range types { + conv := make([]apitypes.Type, len(fields)) + for i, f := range fields { + conv[i] = apitypes.Type{Name: f.Name, Type: f.Type} + } + td.Types[name] = conv + } + if _, ok := td.Types["EIP712Domain"]; !ok { + td.Types["EIP712Domain"] = []apitypes.Type{ + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + } + } + + dataHash, err := td.HashStruct(td.PrimaryType, td.Message) + if err != nil { + return nil, fmt.Errorf("hash struct: %w", err) + } + domainSep, err := td.HashStruct("EIP712Domain", td.Domain.Map()) + if err != nil { + return nil, fmt.Errorf("hash domain: %w", err) + } + + digest := crypto.Keccak256(append([]byte{0x19, 0x01}, append(domainSep, dataHash...)...)) + sig, err := crypto.Sign(digest, s.privateKey) + if err != nil { + return nil, fmt.Errorf("sign: %w", err) + } + // EIP-155 v adjustment. + sig[64] += 27 + return sig, nil +} diff --git a/examples/go/servers/bazaar/go.mod b/examples/go/servers/bazaar/go.mod index 5b5b438c56..1d11fd6b64 100644 --- a/examples/go/servers/bazaar/go.mod +++ b/examples/go/servers/bazaar/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/servers/bazaar +module github.com/x402-foundation/x402/examples/go/servers/bazaar go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/gin-gonic/gin v1.11.0 github.com/joho/godotenv v1.5.1 ) diff --git a/examples/go/servers/bazaar/main.go b/examples/go/servers/bazaar/main.go index c6e6c48e0c..32502a724c 100644 --- a/examples/go/servers/bazaar/main.go +++ b/examples/go/servers/bazaar/main.go @@ -6,14 +6,14 @@ import ( "os" "time" - x402http "github.com/coinbase/x402/go/http" - "github.com/coinbase/x402/go/extensions/bazaar" - "github.com/coinbase/x402/go/extensions/types" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" ginfw "github.com/gin-gonic/gin" "github.com/joho/godotenv" + "github.com/x402-foundation/x402/go/extensions/bazaar" + "github.com/x402-foundation/x402/go/extensions/types" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) const ( diff --git a/examples/go/servers/custom/go.mod b/examples/go/servers/custom/go.mod index 1896b9b7ab..a80a79990c 100644 --- a/examples/go/servers/custom/go.mod +++ b/examples/go/servers/custom/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/servers/custom +module github.com/x402-foundation/x402/examples/go/servers/custom go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/gin-gonic/gin v1.11.0 github.com/joho/godotenv v1.5.1 ) diff --git a/examples/go/servers/custom/main.go b/examples/go/servers/custom/main.go index a217a9aa60..d95fb8437d 100644 --- a/examples/go/servers/custom/main.go +++ b/examples/go/servers/custom/main.go @@ -10,11 +10,11 @@ import ( "sync" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) const ( @@ -324,7 +324,7 @@ func main() { // Initialize the server (queries facilitator for supported schemes) ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) defer cancel() - + if err := x402Server.Initialize(ctx); err != nil { fmt.Printf("⚠️ Warning: failed to initialize x402 server: %v\n", err) } @@ -406,4 +406,3 @@ func main() { os.Exit(1) } } - diff --git a/examples/go/servers/echo/go.mod b/examples/go/servers/echo/go.mod index 4c09ee7ccd..605f8c5ff8 100644 --- a/examples/go/servers/echo/go.mod +++ b/examples/go/servers/echo/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/servers/echo +module github.com/x402-foundation/x402/examples/go/servers/echo go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0 + github.com/x402-foundation/x402/go v0.0.0 github.com/joho/godotenv v1.5.1 github.com/labstack/echo/v4 v4.15.1 ) diff --git a/examples/go/servers/echo/main.go b/examples/go/servers/echo/main.go index 9c34a3998e..00bfa8dc92 100644 --- a/examples/go/servers/echo/main.go +++ b/examples/go/servers/echo/main.go @@ -6,13 +6,13 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - echomw "github.com/coinbase/x402/go/http/echo" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" "github.com/joho/godotenv" "github.com/labstack/echo/v4" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + echomw "github.com/x402-foundation/x402/go/http/echo" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) const ( diff --git a/examples/go/servers/gin/go.mod b/examples/go/servers/gin/go.mod index 4b2303b641..84e13727a3 100644 --- a/examples/go/servers/gin/go.mod +++ b/examples/go/servers/gin/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/servers/gin +module github.com/x402-foundation/x402/examples/go/servers/gin go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/gin-gonic/gin v1.11.0 github.com/joho/godotenv v1.5.1 ) diff --git a/examples/go/servers/gin/main.go b/examples/go/servers/gin/main.go index 046d70c587..c45495f0d2 100644 --- a/examples/go/servers/gin/main.go +++ b/examples/go/servers/gin/main.go @@ -6,13 +6,13 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" ginfw "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) const ( @@ -96,7 +96,7 @@ func main() { ginmw.SchemeConfig{Network: "eip155:84532", Server: evm.NewExactEvmScheme()}, ginmw.SchemeConfig{Network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", Server: svm.NewExactSvmScheme()}, }, - Timeout: 30 * time.Second, + Timeout: 30 * time.Second, })) /** @@ -147,4 +147,3 @@ func main() { os.Exit(1) } } - diff --git a/examples/go/servers/mcp/advanced.go b/examples/go/servers/mcp/advanced.go index 85d985606f..118365ae6e 100644 --- a/examples/go/servers/mcp/advanced.go +++ b/examples/go/servers/mcp/advanced.go @@ -19,12 +19,12 @@ import ( "net/http" "os" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - "github.com/coinbase/x402/go/mcp" "github.com/joho/godotenv" mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/mcp" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) func runAdvanced() error { diff --git a/examples/go/servers/mcp/existing-server.go b/examples/go/servers/mcp/existing-server.go index 077fba5b11..7b90dcd654 100644 --- a/examples/go/servers/mcp/existing-server.go +++ b/examples/go/servers/mcp/existing-server.go @@ -17,12 +17,12 @@ import ( "net/http" "os" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - "github.com/coinbase/x402/go/mcp" "github.com/joho/godotenv" mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/mcp" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) func runExisting() error { diff --git a/examples/go/servers/mcp/go.mod b/examples/go/servers/mcp/go.mod index 797f9c3815..257a6f39bf 100644 --- a/examples/go/servers/mcp/go.mod +++ b/examples/go/servers/mcp/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/servers/mcp +module github.com/x402-foundation/x402/examples/go/servers/mcp go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/joho/godotenv v1.5.1 github.com/modelcontextprotocol/go-sdk v1.3.0 ) diff --git a/examples/go/servers/mcp/simple.go b/examples/go/servers/mcp/simple.go index 820c09a2ad..c5fc5da93d 100644 --- a/examples/go/servers/mcp/simple.go +++ b/examples/go/servers/mcp/simple.go @@ -17,12 +17,12 @@ import ( "net/http" "os" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - "github.com/coinbase/x402/go/mcp" "github.com/joho/godotenv" mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/mcp" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) func runSimple() error { diff --git a/examples/go/servers/nethttp/go.mod b/examples/go/servers/nethttp/go.mod index cf8d3a11de..6716326d01 100644 --- a/examples/go/servers/nethttp/go.mod +++ b/examples/go/servers/nethttp/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/servers/nethttp +module github.com/x402-foundation/x402/examples/go/servers/nethttp go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0 + github.com/x402-foundation/x402/go v0.0.0 github.com/joho/godotenv v1.5.1 ) diff --git a/examples/go/servers/nethttp/main.go b/examples/go/servers/nethttp/main.go index 71c683874a..072402cf7e 100644 --- a/examples/go/servers/nethttp/main.go +++ b/examples/go/servers/nethttp/main.go @@ -7,12 +7,12 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - nethttpmw "github.com/coinbase/x402/go/http/nethttp" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + nethttpmw "github.com/x402-foundation/x402/go/http/nethttp" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) const ( diff --git a/examples/go/servers/payment-identifier/README.md b/examples/go/servers/payment-identifier/README.md index ac285739b9..a62db7ea49 100644 --- a/examples/go/servers/payment-identifier/README.md +++ b/examples/go/servers/payment-identifier/README.md @@ -48,7 +48,7 @@ go run main.go ### Declaring the Extension ```go -import "github.com/coinbase/x402/go/extensions/paymentidentifier" +import "github.com/x402-foundation/x402/go/extensions/paymentidentifier" // Require payment identifier (clients MUST provide one) paymentIdExtension := paymentidentifier.DeclarePaymentIdentifierExtension(true) @@ -83,6 +83,13 @@ if existingOrder, found := processedPayments[paymentID]; found { } ``` +In production, store the payment ID together with a normalized fingerprint of +the paid operation, for example the HTTP method, route, selected payment +requirements, and application order ID. A retry with the same payment ID and the +same fingerprint can return the cached response. A request with the same payment +ID but a different fingerprint should return `409 Conflict` instead of creating +or charging for a different order. + ## API ### POST /order @@ -114,6 +121,9 @@ Creates an order with payment. Requires a payment identifier. - Replace the in-memory `processedPayments` map with Redis or a database - Set appropriate TTL for payment ID records - Consider distributed locking for high-concurrency scenarios +- Scope idempotency records by tenant, merchant, or route if the same storage + layer is shared across paid resources +- Bind each payment ID to a request fingerprint and reject conflicting replays ## Related Examples diff --git a/examples/go/servers/payment-identifier/go.mod b/examples/go/servers/payment-identifier/go.mod index 3f33b32f5e..73aa915e66 100644 --- a/examples/go/servers/payment-identifier/go.mod +++ b/examples/go/servers/payment-identifier/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/servers/payment-identifier +module github.com/x402-foundation/x402/examples/go/servers/payment-identifier go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/gin-gonic/gin v1.11.0 github.com/joho/godotenv v1.5.1 ) diff --git a/examples/go/servers/payment-identifier/main.go b/examples/go/servers/payment-identifier/main.go index d581cbc8a3..ac69bfa4ef 100644 --- a/examples/go/servers/payment-identifier/main.go +++ b/examples/go/servers/payment-identifier/main.go @@ -9,13 +9,13 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/paymentidentifier" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/paymentidentifier" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) const DefaultPort = "4021" diff --git a/examples/go/servers/upto/go.mod b/examples/go/servers/upto/go.mod index dceea77cf5..aeec5bd1b4 100644 --- a/examples/go/servers/upto/go.mod +++ b/examples/go/servers/upto/go.mod @@ -1,13 +1,13 @@ -module github.com/coinbase/x402/examples/go/servers/upto +module github.com/x402-foundation/x402/examples/go/servers/upto go 1.24.0 toolchain go1.24.1 -replace github.com/coinbase/x402/go => ../../../../go +replace github.com/x402-foundation/x402/go => ../../../../go require ( - github.com/coinbase/x402/go v0.0.0-00010101000000-000000000000 + github.com/x402-foundation/x402/go v0.0.0-00010101000000-000000000000 github.com/gin-gonic/gin v1.11.0 github.com/joho/godotenv v1.5.1 ) diff --git a/examples/go/servers/upto/main.go b/examples/go/servers/upto/main.go index 3a2c41f77a..b61fd8a20f 100644 --- a/examples/go/servers/upto/main.go +++ b/examples/go/servers/upto/main.go @@ -7,12 +7,12 @@ import ( "os" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - uptoevm "github.com/coinbase/x402/go/mechanisms/evm/upto/server" ginfw "github.com/gin-gonic/gin" "github.com/joho/godotenv" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/server" ) const DefaultPort = "4021" diff --git a/examples/python/clients/advanced/.env-local b/examples/python/clients/advanced/.env-local index 8b6ba4c6ba..1904b1d9e5 100644 --- a/examples/python/clients/advanced/.env-local +++ b/examples/python/clients/advanced/.env-local @@ -1,4 +1,8 @@ EVM_PRIVATE_KEY= SVM_PRIVATE_KEY= +TVM_PRIVATE_KEY= +TVM_NETWORK=tvm:-3 +TONCENTER_API_KEY= +TONCENTER_BASE_URL=https://testnet.toncenter.com RESOURCE_SERVER_URL=http://localhost:4021 ENDPOINT_PATH=/weather diff --git a/examples/python/clients/advanced/README.md b/examples/python/clients/advanced/README.md index c905b152ce..6805b2eb7d 100644 --- a/examples/python/clients/advanced/README.md +++ b/examples/python/clients/advanced/README.md @@ -1,13 +1,19 @@ # Advanced Python Client Examples -This directory contains advanced x402 client examples demonstrating hooks, custom selectors, and builder patterns. +This directory contains advanced x402 client examples demonstrating hooks, custom selectors, and builder patterns across EVM, SVM, and TVM networks. ## Prerequisites - Python 3.11+ -- An EVM private key with testnet funds (e.g., Base Sepolia) +- At least one configured signer: + - EVM private key with testnet funds (e.g., Base Sepolia) + - SVM private key with Solana Devnet funds + - TVM private key with TON testnet funds and testnet USDT - A running x402 resource server (e.g., the FastAPI example server) +To fund your TVM payer wallet, request testnet TON from [@testgiver_ton_bot](https://t.me/testgiver_ton_bot) for fees. Then open the [testnet USDT transfer link](https://app.tonkeeper.com/transfer/kQDNUDJC0iQvJoZp0ml-YteL1NtTXKphU03CTI5v4VtBhGYs?amount=49000000&bin=te6cckEBAQEAFgAAKClXdJkAAAAAAAAAAAAAAAAAmJaAhDUekg) or scan the QR code below to obtain testnet USDT: +QR code for the testnet USDT transfer link + ## Setup 1. **Install dependencies:** @@ -21,7 +27,7 @@ This directory contains advanced x402 client examples demonstrating hooks, custo ```bash cp .env-local .env - # Edit .env and add your private key + # Edit .env and add one or more signer credentials ``` 3. **Start a test server** (in another terminal): @@ -62,7 +68,7 @@ uv run python builder_pattern.py ### 0. All Networks (`all_networks.py`) -Demonstrates how to add all supported networks with optional chain configuration +Demonstrates how to add all supported networks with optional chain configuration, including TVM. ### 1. Hooks (`hooks.py`) @@ -110,6 +116,7 @@ Demonstrates network-specific scheme registration: advanced/ ├── .env-local # Environment template ├── README.md # This file +├── all_networks.py # Register EVM, SVM, and TVM schemes ├── pyproject.toml # Dependencies ├── index.py # CLI entry point ├── hooks.py # Lifecycle hooks example diff --git a/examples/python/clients/advanced/all_networks.py b/examples/python/clients/advanced/all_networks.py index fa4158d010..ae44f23a36 100644 --- a/examples/python/clients/advanced/all_networks.py +++ b/examples/python/clients/advanced/all_networks.py @@ -4,7 +4,7 @@ optional chain configuration via environment variables. New chain support should be added here in alphabetic order by network prefix -(e.g., "eip155" before "solana"). +(e.g., "eip155" before "solana" before "tvm"). """ import asyncio @@ -21,28 +21,37 @@ from x402.mechanisms.evm.exact.register import register_exact_evm_client from x402.mechanisms.svm import KeypairSigner from x402.mechanisms.svm.exact.register import register_exact_svm_client +from x402.mechanisms.tvm import ( + TVM_MAINNET, + TVM_PROVIDER_TONAPI, + TVM_TESTNET, + WalletV5R1Config, + WalletV5R1MnemonicSigner, +) +from x402.mechanisms.tvm.exact import ExactTvmClientScheme # Load environment variables load_dotenv() -def validate_environment() -> tuple[str | None, str | None, str, str]: +def validate_environment() -> tuple[str | None, str | None, str | None, str, str]: """Validate required environment variables. Returns: - Tuple of (evm_private_key, svm_private_key, base_url, endpoint_path). + Tuple of (evm_private_key, svm_private_key, tvm_private_key, base_url, endpoint_path). Raises: SystemExit: If required environment variables are missing. """ evm_private_key = os.getenv("EVM_PRIVATE_KEY") svm_private_key = os.getenv("SVM_PRIVATE_KEY") + tvm_private_key = os.getenv("TVM_PRIVATE_KEY") base_url = os.getenv("RESOURCE_SERVER_URL") endpoint_path = os.getenv("ENDPOINT_PATH") - # Validate at least one private key is provided - if not evm_private_key and not svm_private_key: - print("❌ At least one of EVM_PRIVATE_KEY or SVM_PRIVATE_KEY is required") + # Validate at least one signer credential is provided + if not evm_private_key and not svm_private_key and not tvm_private_key: + print("❌ At least one of EVM_PRIVATE_KEY, SVM_PRIVATE_KEY, or TVM_PRIVATE_KEY is required") print("Please copy .env-local to .env and fill in the values.") sys.exit(1) @@ -54,13 +63,21 @@ def validate_environment() -> tuple[str | None, str | None, str, str]: print("❌ ENDPOINT_PATH is required") sys.exit(1) - return evm_private_key, svm_private_key, base_url, endpoint_path + return ( + evm_private_key, + svm_private_key, + tvm_private_key, + base_url, + endpoint_path, + ) async def main() -> None: """Main entry point demonstrating httpx with x402 payments.""" # Validate environment - evm_private_key, svm_private_key, base_url, endpoint_path = validate_environment() + evm_private_key, svm_private_key, tvm_private_key, base_url, endpoint_path = ( + validate_environment() + ) # Create x402 client client = x402Client() @@ -77,6 +94,30 @@ async def main() -> None: register_exact_svm_client(client, svm_signer) print(f"Initialized SVM account: {svm_signer.address}") + # Register TVM payment scheme if private key provided + if tvm_private_key: + tvm_network = os.getenv("TVM_NETWORK", TVM_TESTNET) + if tvm_network not in {TVM_TESTNET, TVM_MAINNET}: + print(f"❌ Unsupported TVM network: {tvm_network}") + sys.exit(1) + + tvm_config = WalletV5R1Config.from_private_key(tvm_network, tvm_private_key) + tvm_provider = (os.getenv("TVM_PROVIDER") or "").strip().lower() + tvm_config.provider = tvm_provider or tvm_config.provider + tvm_config.api_key = ( + os.getenv("TONAPI_API_KEY") + if tvm_provider == TVM_PROVIDER_TONAPI + else os.getenv("TONCENTER_API_KEY") + ) + tvm_config.provider_base_url = ( + os.getenv("TONAPI_BASE_URL") + if tvm_provider == TVM_PROVIDER_TONAPI + else os.getenv("TONCENTER_BASE_URL") + ) + tvm_signer = WalletV5R1MnemonicSigner(tvm_config) + client.register(tvm_network, ExactTvmClientScheme(tvm_signer)) + print(f"Initialized TVM account: {tvm_signer.address}") + # Create HTTP client helper for payment response extraction http_client = x402HTTPClient(client) @@ -85,7 +126,7 @@ async def main() -> None: print(f"\nMaking request to: {url}\n") # Make request using async context manager - async with x402HttpxClient(client) as http: + async with x402HttpxClient(client, timeout=30.0) as http: response = await http.get(url) await response.aread() diff --git a/examples/python/clients/advanced/pyproject.toml b/examples/python/clients/advanced/pyproject.toml index 1d30abdddb..0d38666249 100644 --- a/examples/python/clients/advanced/pyproject.toml +++ b/examples/python/clients/advanced/pyproject.toml @@ -5,9 +5,12 @@ description = "Advanced x402 client examples demonstrating hooks, custom selecto readme = "README.md" requires-python = ">=3.11" dependencies = [ - "x402[evm,svm,httpx]", + "x402[evm,svm,tvm,httpx]", "python-dotenv>=1.0.0", ] +[tool.uv] +exclude-newer = "3 days" + [tool.uv.sources] x402 = { path = "../../../../python/x402", editable = true } diff --git a/examples/python/clients/advanced/uv.lock b/examples/python/clients/advanced/uv.lock index 0d9249b34f..e8f7e12d01 100644 --- a/examples/python/clients/advanced/uv.lock +++ b/examples/python/clients/advanced/uv.lock @@ -239,6 +239,76 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.4" @@ -1069,6 +1139,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + [[package]] name = "pycryptodome" version = "3.23.0" @@ -1099,6 +1178,36 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, ] +[[package]] +name = "pycryptodomex" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -1211,6 +1320,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/36/c7/cfc8e811f061c841d7990b0201912c3556bfeb99cdcb7ed24adc8d6f8704/pydantic_core-2.41.5-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:56121965f7a4dc965bff783d70b907ddf3d57f6eba29b6d2e5dabfaf07799c51", size = 2145302, upload-time = "2025-11-04T13:43:46.64Z" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "python-dotenv" version = "1.2.1" @@ -1220,6 +1364,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/1b/a298b06749107c305e1fe0f814c6c74aea7b2f1e10989cb30f544a1b3253/python_dotenv-1.2.1-py3-none-any.whl", hash = "sha256:b81ee9561e9ca4004139c6cbba3a238c32b03e4894671e181b671e8cb8425d61", size = 21230, upload-time = "2025-10-26T15:12:09.109Z" }, ] +[[package]] +name = "pytoniq" +version = "0.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytoniq-core" }, + { name = "requests" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/b2/9991a953e4b766918a142fe111f71f12803c6acf65eb30f36eb85ed08f31/pytoniq-0.1.43.tar.gz", hash = "sha256:b4b1c8fed2f9d2f1b6f0ab4b3f1fc5503a0088630d8081f817807ff31e608606", size = 50463, upload-time = "2025-11-30T12:30:41.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/c1/b6e5c739839e0e12bde4563438acd55d39552ea63f6de123724b4b91ac64/pytoniq-0.1.43-py3-none-any.whl", hash = "sha256:922c1721124bf7214e0b7044fba2a439e006367778611c0ce813cbe5b00079d3", size = 56118, upload-time = "2025-11-30T12:30:39.65Z" }, +] + +[[package]] +name = "pytoniq-core" +version = "0.1.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "x25519" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/2c/7afbb9003a3aa72ccfe69711433fe36d2493db2c4acf66dde32f7b55799b/pytoniq_core-0.1.46.tar.gz", hash = "sha256:c8e3cf9ccb1852780a725cd51ba7a66a28122eb39c8b9bb97dcdc5bd02c24734", size = 101236, upload-time = "2025-11-28T10:23:21.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/0e/e27cf7ce1bebb47fb95e1d6deae5c91c6ffcb7851f156990e57079cbe8db/pytoniq_core-0.1.46-py3-none-any.whl", hash = "sha256:0a284c8b68f9fed9d54e4dad871238d844339183bf985a614796360e36e1b95e", size = 91400, upload-time = "2025-11-28T10:23:20.95Z" }, +] + [[package]] name = "pyunormalize" version = "17.0.0" @@ -1367,6 +1542,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/99/fb/e4c0ced9893b84ac95b7181d69a9786ce5879aeb3bbbcbba80a164f85d6a/rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f", size = 19973, upload-time = "2025-02-04T22:05:57.05Z" }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + [[package]] name = "solana" version = "0.36.11" @@ -1521,9 +1705,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] +[[package]] +name = "x25519" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/b6/fca895aff0800cdf941f856df0685a5513094163664b904576e3e3ef1460/x25519-0.0.2.tar.gz", hash = "sha256:ed91d0aba7f4f4959ed8b37118c11d94f56d36c38bb6f2e6c20d0438d75b1556", size = 4833, upload-time = "2021-10-24T15:18:38.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d1/66c637eb8e7a9601675bf7f04bb9a3015358a0f49e4c31d29a2b9a9d72d9/x25519-0.0.2-py3-none-any.whl", hash = "sha256:5c0833260a548bea9137a5a1b5c30334b751a59d148a62832df0c9e7b919ce99", size = 4907, upload-time = "2021-10-24T15:18:36.727Z" }, +] + [[package]] name = "x402" -version = "2.1.0" +version = "2.5.0" source = { editable = "../../../../python/x402" } dependencies = [ { name = "nest-asyncio" }, @@ -1546,38 +1739,48 @@ svm = [ { name = "solana" }, { name = "solders" }, ] +tvm = [ + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, +] [package.metadata] requires-dist = [ { name = "eth-abi", marker = "extra == 'evm'", specifier = ">=5.0.0" }, - { name = "eth-account", marker = "extra == 'evm'", specifier = ">=0.12.0" }, + { name = "eth-account", marker = "extra == 'evm'", specifier = ">=0.13.0" }, { name = "eth-keys", marker = "extra == 'evm'", specifier = ">=0.5.0" }, { name = "eth-utils", marker = "extra == 'evm'", specifier = ">=4.0.0" }, { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.115.0" }, { name = "flask", marker = "extra == 'flask'", specifier = ">=3.0.0" }, { name = "httpx", marker = "extra == 'httpx'", specifier = ">=0.28.1" }, + { name = "httpx", marker = "extra == 'tvm'", specifier = ">=0.28.1" }, { name = "jsonschema", marker = "extra == 'extensions'", specifier = ">=4.0.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pynacl", marker = "extra == 'tvm'", specifier = ">=1.5.0" }, + { name = "pytoniq", marker = "extra == 'tvm'", specifier = ">=0.1.39" }, + { name = "pytoniq-core", marker = "extra == 'tvm'", specifier = ">=0.1.36" }, { name = "requests", marker = "extra == 'requests'", specifier = ">=2.31.0" }, { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0" }, { name = "solders", marker = "extra == 'svm'", specifier = ">=0.27.0" }, { name = "starlette", marker = "extra == 'fastapi'", specifier = ">=0.27.0" }, { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "web3", marker = "extra == 'evm'", specifier = ">=7.0.0" }, - { name = "x402", extras = ["evm", "svm"], marker = "extra == 'mechanisms'" }, + { name = "x402", extras = ["evm", "svm", "tvm"], marker = "extra == 'mechanisms'" }, { name = "x402", extras = ["flask", "fastapi"], marker = "extra == 'servers'" }, { name = "x402", extras = ["httpx", "requests"], marker = "extra == 'clients'" }, - { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions"], marker = "extra == 'all'" }, + { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions"], marker = "extra == 'all'" }, ] -provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] +provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] [package.metadata.requires-dev] dev = [ { name = "black", specifier = ">=23.0.0" }, { name = "eth-abi", specifier = ">=5.0.0" }, - { name = "eth-account", specifier = ">=0.12.0" }, + { name = "eth-account", specifier = ">=0.13.0" }, { name = "eth-keys", specifier = ">=0.5.0" }, { name = "eth-utils", specifier = ">=4.0.0" }, { name = "fastapi", extras = ["standard"], specifier = ">=0.115.0" }, @@ -1587,8 +1790,11 @@ dev = [ { name = "mcp", specifier = ">=1.26.0" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, + { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytest", specifier = ">=7.0.0" }, { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytoniq", specifier = ">=0.1.39" }, + { name = "pytoniq-core", specifier = ">=0.1.36" }, { name = "requests", specifier = ">=2.31.0" }, { name = "ruff", specifier = ">=0.1.0" }, { name = "solana", specifier = ">=0.36.0" }, @@ -1604,13 +1810,13 @@ version = "0.1.0" source = { virtual = "." } dependencies = [ { name = "python-dotenv" }, - { name = "x402", extra = ["evm", "httpx", "svm"] }, + { name = "x402", extra = ["evm", "httpx", "svm", "tvm"] }, ] [package.metadata] requires-dist = [ { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "x402", extras = ["evm", "svm", "httpx"], editable = "../../../../python/x402" }, + { name = "x402", extras = ["evm", "svm", "tvm", "httpx"], editable = "../../../../python/x402" }, ] [[package]] diff --git a/examples/python/clients/custom/pyproject.toml b/examples/python/clients/custom/pyproject.toml index 8b3e0c1dc4..d886698161 100644 --- a/examples/python/clients/custom/pyproject.toml +++ b/examples/python/clients/custom/pyproject.toml @@ -20,6 +20,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/clients/httpx/pyproject.toml b/examples/python/clients/httpx/pyproject.toml index bdd5834a96..578f29ac48 100644 --- a/examples/python/clients/httpx/pyproject.toml +++ b/examples/python/clients/httpx/pyproject.toml @@ -19,6 +19,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/clients/mcp-chatbot/pyproject.toml b/examples/python/clients/mcp-chatbot/pyproject.toml index ac5d548e48..36f08db3b2 100644 --- a/examples/python/clients/mcp-chatbot/pyproject.toml +++ b/examples/python/clients/mcp-chatbot/pyproject.toml @@ -11,6 +11,7 @@ dependencies = [ ] [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/clients/mcp/pyproject.toml b/examples/python/clients/mcp/pyproject.toml index 1785dc7669..f44ac482c7 100644 --- a/examples/python/clients/mcp/pyproject.toml +++ b/examples/python/clients/mcp/pyproject.toml @@ -10,6 +10,7 @@ dependencies = [ ] [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/clients/payment-identifier/pyproject.toml b/examples/python/clients/payment-identifier/pyproject.toml index 2061533c9f..1a76495bce 100644 --- a/examples/python/clients/payment-identifier/pyproject.toml +++ b/examples/python/clients/payment-identifier/pyproject.toml @@ -19,6 +19,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/clients/requests/pyproject.toml b/examples/python/clients/requests/pyproject.toml index 7960f5c158..2687b74511 100644 --- a/examples/python/clients/requests/pyproject.toml +++ b/examples/python/clients/requests/pyproject.toml @@ -19,6 +19,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/facilitator/.env-local b/examples/python/facilitator/.env-local index 553e40d27d..69ff9ccf5c 100644 --- a/examples/python/facilitator/.env-local +++ b/examples/python/facilitator/.env-local @@ -1,3 +1,6 @@ PORT= EVM_PRIVATE_KEY= SVM_PRIVATE_KEY= +TVM_PRIVATE_KEY= +TONCENTER_API_KEY= +TONCENTER_BASE_URL= diff --git a/examples/python/facilitator/advanced/.env-local b/examples/python/facilitator/advanced/.env-local new file mode 100644 index 0000000000..a0fe6af403 --- /dev/null +++ b/examples/python/facilitator/advanced/.env-local @@ -0,0 +1,7 @@ +PORT=4022 +EVM_PRIVATE_KEY= +SVM_PRIVATE_KEY= +TVM_PRIVATE_KEY= +TVM_NETWORK=tvm:-3 +TONCENTER_API_KEY= +TONCENTER_BASE_URL= diff --git a/examples/python/facilitator/advanced/README.md b/examples/python/facilitator/advanced/README.md index c2421cbc97..fcf3730f4e 100644 --- a/examples/python/facilitator/advanced/README.md +++ b/examples/python/facilitator/advanced/README.md @@ -1,13 +1,22 @@ # x402 Advanced Facilitator Examples (Python) -FastAPI facilitator service demonstrating advanced x402 patterns including all-networks support, bazaar discovery, and lifecycle hooks. +FastAPI facilitator service demonstrating advanced x402 patterns including all-networks support, bazaar discovery, and lifecycle hooks across EVM, SVM, and TVM. ## Prerequisites - Python 3.10+ - uv (install via [docs.astral.sh/uv](https://docs.astral.sh/uv/getting-started/installation/)) -- EVM private key with Base Sepolia ETH for transaction fees -- SVM private key with Solana Devnet SOL for transaction fees +- Any configured payment signer set: + - EVM private key with Base Sepolia ETH for transaction fees + - SVM private key with Solana Devnet SOL for transaction fees + - TVM private key with TON testnet funds + +To fund the TVM facilitator wallet, request testnet TON from [@testgiver_ton_bot](https://t.me/testgiver_ton_bot). The facilitator wallet only needs TON for relay fees and must hold **at least 1.1 TON** before running tests. + +> **Note:** the facilitator uses a highload-wallet-v3 account, so the facilitator's wallet address differs from your W5 address — fund the highload-v3 address, not the W5 one derived from the same key. + +To get testnet-USDT for the payer wallet, open the [testnet USDT transfer link](https://app.tonkeeper.com/transfer/kQDNUDJC0iQvJoZp0ml-YteL1NtTXKphU03CTI5v4VtBhGYs?amount=49000000&bin=te6cckEBAQEAFgAAKClXdJkAAAAAAAAAAAAAAAAAmJaAhDUekg) or scan the QR code below: +QR code for the testnet USDT transfer link ## Setup @@ -21,6 +30,10 @@ cp .env-local .env - `EVM_PRIVATE_KEY` - Ethereum private key - `SVM_PRIVATE_KEY` - Solana private key +- `TVM_PRIVATE_KEY` - TVM private key for the facilitator wallet +- `TVM_NETWORK` - TVM CAIP-2 network (optional, defaults to `tvm:-3`) +- `TONCENTER_API_KEY` - Toncenter API key for TVM testnet (optional) +- `TONCENTER_BASE_URL` - Custom Toncenter base URL (optional) - `PORT` - Server port (optional, defaults to 4022) 3. Install dependencies: @@ -38,10 +51,10 @@ uv run python bazaar.py # Bazaar discovery extension ## Available Examples -| Example | Command | Description | -| --- | --- | --- | +| Example | Command | Description | +| -------------- | ------------------------------- | -------------------------------------------------------- | | `all_networks` | `uv run python all_networks.py` | All supported networks with optional chain configuration | -| `bazaar` | `uv run python bazaar.py` | Bazaar discovery extension for cataloging x402 resources | +| `bazaar` | `uv run python bazaar.py` | Bazaar discovery extension for cataloging x402 resources | ## API Endpoints @@ -65,3 +78,5 @@ Networks use [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/cai - `eip155:8453` — Base Mainnet - `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` — Solana Devnet - `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` — Solana Mainnet +- `tvm:-3` — TON Testnet +- `tvm:-239` — TON Mainnet diff --git a/examples/python/facilitator/advanced/all_networks.py b/examples/python/facilitator/advanced/all_networks.py index 2cc72f2656..99981dc98a 100644 --- a/examples/python/facilitator/advanced/all_networks.py +++ b/examples/python/facilitator/advanced/all_networks.py @@ -4,7 +4,7 @@ optional chain configuration via environment variables. New chain support should be added here in alphabetic order by network prefix -(e.g., "eip155" before "solana"). +(e.g., "eip155" before "solana" before "tvm"). """ import os @@ -20,6 +20,13 @@ from x402.mechanisms.evm.exact.facilitator import ExactEvmScheme, ExactEvmSchemeConfig from x402.mechanisms.svm import FacilitatorKeypairSigner from x402.mechanisms.svm.exact.facilitator import ExactSvmScheme +from x402.mechanisms.tvm import ( + TVM_PROVIDER_TONAPI, + TVM_TESTNET, + FacilitatorHighloadV3Signer, + HighloadV3Config, +) +from x402.mechanisms.tvm.exact.facilitator import ExactTvmScheme # Load environment variables load_dotenv() @@ -30,19 +37,22 @@ # Configuration - optional per network evm_private_key = os.environ.get("EVM_PRIVATE_KEY") svm_private_key = os.environ.get("SVM_PRIVATE_KEY") +tvm_private_key = os.environ.get("TVM_PRIVATE_KEY") # Validate at least one private key is provided -if not evm_private_key and not svm_private_key: - print("❌ At least one of EVM_PRIVATE_KEY or SVM_PRIVATE_KEY is required") +if not evm_private_key and not svm_private_key and not tvm_private_key: + print("❌ At least one of EVM_PRIVATE_KEY, SVM_PRIVATE_KEY, or TVM_PRIVATE_KEY is required") sys.exit(1) # Network configuration -EVM_NETWORK = "eip155:84532" # Base Sepolia -SVM_NETWORK = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" # Solana Devnet +EVM_NETWORK = os.environ.get("EVM_NETWORK", "eip155:84532") # Base Sepolia +SVM_NETWORK = os.environ.get("SVM_NETWORK", "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1") +TVM_NETWORK = os.environ.get("TVM_NETWORK", TVM_TESTNET) # Initialize signers based on available keys evm_signer = None svm_signer = None +tvm_signer = None if evm_private_key: evm_signer = FacilitatorWeb3Signer( @@ -56,6 +66,23 @@ svm_signer = FacilitatorKeypairSigner(svm_keypair) print(f"SVM Facilitator account: {svm_signer.get_addresses()[0]}") +if tvm_private_key: + tvm_config = HighloadV3Config.from_private_key(tvm_private_key) + tvm_provider = (os.environ.get("TVM_PROVIDER") or "").strip().lower() + tvm_config.provider = tvm_provider or tvm_config.provider + tvm_config.api_key = ( + os.environ.get("TONAPI_API_KEY") + if tvm_provider == TVM_PROVIDER_TONAPI + else os.environ.get("TONCENTER_API_KEY") + ) + tvm_config.provider_base_url = ( + os.environ.get("TONAPI_BASE_URL") + if tvm_provider == TVM_PROVIDER_TONAPI + else os.environ.get("TONCENTER_BASE_URL") + ) + tvm_signer = FacilitatorHighloadV3Signer({TVM_NETWORK: tvm_config}) + print(f"TVM Facilitator account: {tvm_signer.get_addresses()[0]}") + # Async hook functions for the facilitator async def before_verify_hook(ctx): @@ -100,6 +127,11 @@ async def settle_failure_hook(ctx): if svm_signer: facilitator.register([SVM_NETWORK], ExactSvmScheme(svm_signer)) +if tvm_signer: + facilitator.register( + [TVM_NETWORK], + ExactTvmScheme(tvm_signer), + ) # Pydantic models for request/response @@ -120,7 +152,7 @@ class SettleRequest(BaseModel): # Initialize FastAPI app app = FastAPI( title="All Networks Facilitator", - description="Verifies and settles x402 payments on-chain with optional EVM/SVM support", + description="Verifies and settles x402 payments on-chain with optional EVM/SVM/TVM support", version="2.0.0", ) diff --git a/examples/python/facilitator/advanced/bazaar.py b/examples/python/facilitator/advanced/bazaar.py index 807a82e7f5..d25f5c25c2 100644 --- a/examples/python/facilitator/advanced/bazaar.py +++ b/examples/python/facilitator/advanced/bazaar.py @@ -6,11 +6,13 @@ import os import sys +import base64 +import json from datetime import datetime from typing import Any from dotenv import load_dotenv -from fastapi import FastAPI, HTTPException +from fastapi import FastAPI, HTTPException, Response from pydantic import BaseModel from solders.keypair import Keypair @@ -53,6 +55,7 @@ class CatalogResource(BaseModel): accepts: list[dict[str, Any]] discoveryInfo: dict[str, Any] | None = None lastUpdated: str + extensions: dict[str, Any] | None = None # BazaarCatalog stores discovered resources @@ -70,9 +73,50 @@ def get_all(self) -> list[CatalogResource]: """Get all resources in the catalog.""" return list(self.resources.values()) + def search( + self, + query: str, + resource_type: str | None = None, + limit: int | None = None, + ) -> list[CatalogResource]: + """Search resources using case-insensitive keyword matching. + + Matches against resource URL, type, and extension values. + + Args: + query: The search query string. + resource_type: Optional filter by resource type. + limit: Optional advisory maximum results. + + Returns: + Matching resources. + """ + needle = query.lower() + results = [] + for r in self.resources.values(): + haystack = " ".join( + [r.resource, r.type] + [str(v) for v in (r.extensions or {}).values()] + ).lower() + if needle in haystack: + results.append(r) + + if resource_type: + results = [r for r in results if r.type == resource_type] + + return results[:limit] if limit is not None else results + bazaar_catalog = BazaarCatalog() +EXTENSION_RESPONSES_HEADER = "EXTENSION-RESPONSES" + + +def _set_extension_responses_header(response: Response) -> None: + """Attach an example bazaar extension response header for client readback.""" + extension_responses = {"bazaar": {"status": "success"}} + encoded = base64.b64encode(json.dumps(extension_responses).encode("utf-8")).decode("ascii") + response.headers[EXTENSION_RESPONSES_HEADER] = encoded + # Initialize signers based on available keys evm_signer = None svm_signer = None @@ -131,6 +175,7 @@ def _handle_after_verify(ctx: Any) -> None: ], discoveryInfo=discovery_info_dict, lastUpdated=datetime.now().isoformat(), + extensions={}, ) ) print(" ✅ Added to bazaar catalog") @@ -182,7 +227,7 @@ class SettleRequest(BaseModel): @app.post("/verify") -async def verify(request: VerifyRequest): +async def verify(request: VerifyRequest, http_response: Response): """Verify a payment against requirements. Note: Payment tracking and bazaar discovery are handled by lifecycle hooks. @@ -203,16 +248,17 @@ async def verify(request: VerifyRequest): # Hooks will automatically: # - Track verified payment (on_after_verify) # - Extract and catalog discovery info (on_after_verify) - response = await facilitator.verify(payload, requirements) + verify_result = await facilitator.verify(payload, requirements) - return response.model_dump(by_alias=True, exclude_none=True) + _set_extension_responses_header(http_response) + return verify_result.model_dump(by_alias=True, exclude_none=True) except Exception as e: print(f"Verify error: {e}") raise HTTPException(status_code=500, detail=str(e)) from e @app.post("/settle") -async def settle(request: SettleRequest): +async def settle(request: SettleRequest, http_response: Response): """Settle a payment on-chain. Args: @@ -228,9 +274,10 @@ async def settle(request: SettleRequest): payload = parse_payment_payload(request.paymentPayload) requirements = PaymentRequirements.model_validate(request.paymentRequirements) - response = await facilitator.settle(payload, requirements) + settle_result = await facilitator.settle(payload, requirements) - return response.model_dump(by_alias=True, exclude_none=True) + _set_extension_responses_header(http_response) + return settle_result.model_dump(by_alias=True, exclude_none=True) except Exception as e: print(f"Settle error: {e}") @@ -292,6 +339,31 @@ async def discovery_resources(): raise HTTPException(status_code=500, detail=str(e)) from e +@app.get("/discovery/search") +async def discovery_search(query: str, type: str | None = None, limit: int | None = None): + """Search discovered resources using keyword matching. + + Args: + query: The search query string. + type: Optional filter by resource type. + limit: Optional advisory maximum number of results. + + Returns: + Search response with x402Version, items, and optional pagination hints. + """ + try: + results = bazaar_catalog.search(query, type, limit) + return { + "x402Version": 2, + "resources": [r.model_dump(by_alias=True) for r in results], + "partialResults": False, + "pagination": None, + } + except Exception as e: + print(f"Discovery search error: {e}") + raise HTTPException(status_code=500, detail=str(e)) from e + + @app.get("/health") async def health(): """Health check endpoint.""" diff --git a/examples/python/facilitator/advanced/pyproject.toml b/examples/python/facilitator/advanced/pyproject.toml index 3452fba5aa..7ff84b9779 100644 --- a/examples/python/facilitator/advanced/pyproject.toml +++ b/examples/python/facilitator/advanced/pyproject.toml @@ -6,7 +6,7 @@ readme = "README.md" requires-python = ">=3.10" keywords = ["x402", "payment", "protocol", "facilitator", "402"] dependencies = [ - "x402[fastapi,evm,svm,extensions]", + "x402[fastapi,evm,svm,tvm,extensions]", "python-dotenv>=1.2.1", "uvicorn[standard]>=0.40.0", ] @@ -21,6 +21,7 @@ dev = [ ] [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] @@ -55,4 +56,3 @@ warn_unused_configs = true [tool.pytest.ini_options] testpaths = ["tests"] - diff --git a/examples/python/facilitator/advanced/uv.lock b/examples/python/facilitator/advanced/uv.lock index a2cd7d69aa..5fe4421980 100644 --- a/examples/python/facilitator/advanced/uv.lock +++ b/examples/python/facilitator/advanced/uv.lock @@ -342,6 +342,88 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.4" @@ -1883,6 +1965,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + [[package]] name = "pycryptodome" version = "3.23.0" @@ -1918,6 +2009,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, ] +[[package]] +name = "pycryptodomex" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -2092,6 +2218,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "pytest" version = "9.0.2" @@ -2151,6 +2312,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" }, ] +[[package]] +name = "pytoniq" +version = "0.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytoniq-core" }, + { name = "requests" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/b2/9991a953e4b766918a142fe111f71f12803c6acf65eb30f36eb85ed08f31/pytoniq-0.1.43.tar.gz", hash = "sha256:b4b1c8fed2f9d2f1b6f0ab4b3f1fc5503a0088630d8081f817807ff31e608606", size = 50463, upload-time = "2025-11-30T12:30:41.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/c1/b6e5c739839e0e12bde4563438acd55d39552ea63f6de123724b4b91ac64/pytoniq-0.1.43-py3-none-any.whl", hash = "sha256:922c1721124bf7214e0b7044fba2a439e006367778611c0ce813cbe5b00079d3", size = 56118, upload-time = "2025-11-30T12:30:39.65Z" }, +] + +[[package]] +name = "pytoniq-core" +version = "0.1.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "x25519" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/2c/7afbb9003a3aa72ccfe69711433fe36d2493db2c4acf66dde32f7b55799b/pytoniq_core-0.1.46.tar.gz", hash = "sha256:c8e3cf9ccb1852780a725cd51ba7a66a28122eb39c8b9bb97dcdc5bd02c24734", size = 101236, upload-time = "2025-11-28T10:23:21.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/0e/e27cf7ce1bebb47fb95e1d6deae5c91c6ffcb7851f156990e57079cbe8db/pytoniq_core-0.1.46-py3-none-any.whl", hash = "sha256:0a284c8b68f9fed9d54e4dad871238d844339183bf985a614796360e36e1b95e", size = 91400, upload-time = "2025-11-28T10:23:20.95Z" }, +] + [[package]] name = "pyunormalize" version = "17.0.0" @@ -2703,6 +2895,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/43/1c586f9f413765201234541857cb82fda076f4b0f7bad4a0ec248da39cf3/sentry_sdk-2.49.0-py2.py3-none-any.whl", hash = "sha256:6ea78499133874445a20fe9c826c9e960070abeb7ae0cdf930314ab16bb97aa0", size = 415693, upload-time = "2026-01-08T09:56:21.872Z" }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + [[package]] name = "shellingham" version = "1.5.4" @@ -3137,9 +3338,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] +[[package]] +name = "x25519" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/b6/fca895aff0800cdf941f856df0685a5513094163664b904576e3e3ef1460/x25519-0.0.2.tar.gz", hash = "sha256:ed91d0aba7f4f4959ed8b37118c11d94f56d36c38bb6f2e6c20d0438d75b1556", size = 4833, upload-time = "2021-10-24T15:18:38.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d1/66c637eb8e7a9601675bf7f04bb9a3015358a0f49e4c31d29a2b9a9d72d9/x25519-0.0.2-py3-none-any.whl", hash = "sha256:5c0833260a548bea9137a5a1b5c30334b751a59d148a62832df0c9e7b919ce99", size = 4907, upload-time = "2021-10-24T15:18:36.727Z" }, +] + [[package]] name = "x402" -version = "2.1.0" +version = "2.5.0" source = { editable = "../../../../python/x402" } dependencies = [ { name = "nest-asyncio" }, @@ -3166,38 +3376,48 @@ svm = [ { name = "solana" }, { name = "solders" }, ] +tvm = [ + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, +] [package.metadata] requires-dist = [ { name = "eth-abi", marker = "extra == 'evm'", specifier = ">=5.0.0" }, - { name = "eth-account", marker = "extra == 'evm'", specifier = ">=0.12.0" }, + { name = "eth-account", marker = "extra == 'evm'", specifier = ">=0.13.0" }, { name = "eth-keys", marker = "extra == 'evm'", specifier = ">=0.5.0" }, { name = "eth-utils", marker = "extra == 'evm'", specifier = ">=4.0.0" }, { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.115.0" }, { name = "flask", marker = "extra == 'flask'", specifier = ">=3.0.0" }, { name = "httpx", marker = "extra == 'httpx'", specifier = ">=0.28.1" }, + { name = "httpx", marker = "extra == 'tvm'", specifier = ">=0.28.1" }, { name = "jsonschema", marker = "extra == 'extensions'", specifier = ">=4.0.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pynacl", marker = "extra == 'tvm'", specifier = ">=1.5.0" }, + { name = "pytoniq", marker = "extra == 'tvm'", specifier = ">=0.1.39" }, + { name = "pytoniq-core", marker = "extra == 'tvm'", specifier = ">=0.1.36" }, { name = "requests", marker = "extra == 'requests'", specifier = ">=2.31.0" }, { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0" }, { name = "solders", marker = "extra == 'svm'", specifier = ">=0.27.0" }, { name = "starlette", marker = "extra == 'fastapi'", specifier = ">=0.27.0" }, { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "web3", marker = "extra == 'evm'", specifier = ">=7.0.0" }, - { name = "x402", extras = ["evm", "svm"], marker = "extra == 'mechanisms'" }, + { name = "x402", extras = ["evm", "svm", "tvm"], marker = "extra == 'mechanisms'" }, { name = "x402", extras = ["flask", "fastapi"], marker = "extra == 'servers'" }, { name = "x402", extras = ["httpx", "requests"], marker = "extra == 'clients'" }, - { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions"], marker = "extra == 'all'" }, + { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions"], marker = "extra == 'all'" }, ] -provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] +provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] [package.metadata.requires-dev] dev = [ { name = "black", specifier = ">=23.0.0" }, { name = "eth-abi", specifier = ">=5.0.0" }, - { name = "eth-account", specifier = ">=0.12.0" }, + { name = "eth-account", specifier = ">=0.13.0" }, { name = "eth-keys", specifier = ">=0.5.0" }, { name = "eth-utils", specifier = ">=4.0.0" }, { name = "fastapi", extras = ["standard"], specifier = ">=0.115.0" }, @@ -3207,8 +3427,11 @@ dev = [ { name = "mcp", specifier = ">=1.26.0" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, + { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytest", specifier = ">=7.0.0" }, { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytoniq", specifier = ">=0.1.39" }, + { name = "pytoniq-core", specifier = ">=0.1.36" }, { name = "requests", specifier = ">=2.31.0" }, { name = "ruff", specifier = ">=0.1.0" }, { name = "solana", specifier = ">=0.36.0" }, @@ -3225,7 +3448,7 @@ source = { virtual = "." } dependencies = [ { name = "python-dotenv" }, { name = "uvicorn", extra = ["standard"] }, - { name = "x402", extra = ["evm", "extensions", "fastapi", "svm"] }, + { name = "x402", extra = ["evm", "extensions", "fastapi", "svm", "tvm"] }, ] [package.dev-dependencies] @@ -3241,7 +3464,7 @@ dev = [ requires-dist = [ { name = "python-dotenv", specifier = ">=1.2.1" }, { name = "uvicorn", extras = ["standard"], specifier = ">=0.40.0" }, - { name = "x402", extras = ["fastapi", "evm", "svm", "extensions"], editable = "../../../../python/x402" }, + { name = "x402", extras = ["fastapi", "evm", "svm", "tvm", "extensions"], editable = "../../../../python/x402" }, ] [package.metadata.requires-dev] diff --git a/examples/python/facilitator/basic/README.md b/examples/python/facilitator/basic/README.md index a3095d4bdd..86c77412f9 100644 --- a/examples/python/facilitator/basic/README.md +++ b/examples/python/facilitator/basic/README.md @@ -6,8 +6,8 @@ FastAPI-based facilitator service that verifies and settles payments on-chain fo - Python 3.10+ (install via [pyenv](https://github.com/pyenv/pyenv) or [uv](https://docs.astral.sh/uv/)) - uv package manager (install via [uv installation](https://docs.astral.sh/uv/getting-started/installation/)) -- EVM private key with Base Sepolia ETH for transaction fees -- SVM private key with Solana Devnet SOL for transaction fees +- Dedicated EVM facilitator private key with Base Sepolia ETH for transaction fees +- Dedicated SVM facilitator private key with Solana Devnet SOL for transaction fees ## Setup @@ -19,11 +19,13 @@ cp .env-local .env and fill required environment variables: -- `EVM_PRIVATE_KEY` - Ethereum private key (hex with 0x prefix) -- `SVM_PRIVATE_KEY` - Solana private key (base58 encoded) +- `EVM_PRIVATE_KEY` - Ethereum facilitator private key (hex with 0x prefix) +- `SVM_PRIVATE_KEY` - Solana facilitator private key (base58 encoded) - `PORT` - Server port (optional, defaults to 4022) - `EVM_RPC_URL` - Custom EVM RPC URL (optional, defaults to Base Sepolia) +**⚠️ Security Note:** The facilitator key is the signer used to settle payments on-chain. Keep it separate from your seller `payTo` wallet and buyer test wallets, and make sure it is funded only for facilitator gas/fees. + 2. Install dependencies: ```bash diff --git a/examples/python/facilitator/basic/pyproject.toml b/examples/python/facilitator/basic/pyproject.toml index 2284133f78..bccdbfeb78 100644 --- a/examples/python/facilitator/basic/pyproject.toml +++ b/examples/python/facilitator/basic/pyproject.toml @@ -21,6 +21,7 @@ dev = [ ] [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/legacy/README.md b/examples/python/legacy/README.md deleted file mode 100644 index 24c4a1d27a..0000000000 --- a/examples/python/legacy/README.md +++ /dev/null @@ -1,79 +0,0 @@ -# X402 Python Examples - -This directory contains a collection of Python examples demonstrating how to use the X402 protocol in various contexts. These examples use the Python `x402` package and standard Python web frameworks/HTTP clients. - -## Setup - -Before running any examples, ensure you have: - -- Python 3.10+ -- `uv` package manager installed (see `https://github.com/astral-sh/uv`) - -Then install dependencies for the examples you want to run. You can either: - -```bash -# Option A: sync each example individually (recommended by each example README) -cd -uv sync - -# Option B: run the helper script to sync all examples -cd examples/python -uv run python sync.py -``` - -## Example Structure - -The examples are organized into several categories: - -### Clients - -Examples of different client implementations for interacting with x402-protected services: - -- `clients/httpx/` - Two approaches with httpx: a pre-configured `x402HttpxClient` and an extensible `event_hooks` integration. -- `clients/requests/` - Two approaches with requests: a simple `x402_requests` session and an extensible HTTP adapter. - -### Discovery - -- `discovery/` - Uses the facilitator to list available x402-protected resources (Bazaar) with CDP credentials. - -### Fullstack - -- `fullstack/fastapi/` - FastAPI application with x402 middleware protecting routes. Includes simple UI assets. -- `fullstack/flask/` - Flask application with x402 middleware protecting routes. Includes simple UI assets. - -### Servers - -Examples of different server implementations: - -- `servers/fastapi/` - FastAPI server using x402 middleware to protect endpoints. -- `servers/flask/` - Flask server using x402 middleware to protect endpoints. -- `servers/advanced/` - FastAPI server without middleware: delayed settlement, dynamic pricing, multiple requirements. -- `servers/mainnet/` - Server example for accepting real USDC on Base mainnet using the Coinbase hosted facilitator. - -## Running Examples - -Each example directory contains its own README with specific instructions. In general: - -```bash -cd -cp .env-local .env # then fill in required values -uv sync -uv run python main.py -``` - -Some client examples also provide an `extensible.py` variant that demonstrates lower-level integrations. - -## Development - -This workspace uses: - -- `uv` for Python environment and dependency management -- Python 3.10+ and standard tooling - -The examples are independent projects; install dependencies per example before running. - -## A note on private keys - -The examples in this folder commonly use private keys to sign messages. **Never put a private key with mainnet funds in a `.env` file**. This can result in keys getting checked into codebases and being drained. - -Use a development wallet funded on testnets (e.g., Base Sepolia USDC/ETH). You can fund a dev wallet via the testnet [CDP Faucet](https://portal.cdp.coinbase.com/products/faucet). diff --git a/examples/python/legacy/clients/httpx/.env-local b/examples/python/legacy/clients/httpx/.env-local deleted file mode 100644 index 8504936460..0000000000 --- a/examples/python/legacy/clients/httpx/.env-local +++ /dev/null @@ -1,3 +0,0 @@ -RESOURCE_SERVER_URL=http://localhost:4021 -ENDPOINT_PATH=/weather -PRIVATE_KEY= \ No newline at end of file diff --git a/examples/python/legacy/clients/httpx/README.md b/examples/python/legacy/clients/httpx/README.md deleted file mode 100644 index f763032978..0000000000 --- a/examples/python/legacy/clients/httpx/README.md +++ /dev/null @@ -1,60 +0,0 @@ -# x402 httpx Client Example - -This example demonstrates two different approaches to use the x402 package with httpx to make requests to 402-protected endpoints. - -## Setup and Usage - -1. Copy `.env-local` to `.env` and add your private key. - -```bash -cp .env-local .env -``` - -2. Install dependencies: -```bash -uv sync -``` - -3. Run one of the examples: -```bash -# Simple approach -uv run python main.py - -# Extensible approach -uv run python extensible.py -``` - -## Two Integration Approaches - -### Simple Approach (main.py) - -The simple approach uses `x402HttpxClient`, a pre-configured client that handles payments automatically: - -```python -from x402.clients import x402HttpxClient - -async with x402HttpxClient(account=account, base_url=base_url) as client: - response = await client.get(endpoint_path) -``` - -### Extensible Approach (extensible.py) - -The extensible approach uses `x402_payment_hooks` with your own httpx client: - -```python -from x402.clients import x402_payment_hooks -import httpx - -async with httpx.AsyncClient(base_url=base_url) as client: - client.event_hooks = x402_payment_hooks(account) - response = await client.get(endpoint_path) -``` - -## How it Works - -Both examples: -1. Initialize an eth_account.Account instance from a private key -2. Configure the httpx client with x402 payment handling -3. Make a request to a protected endpoint -4. Handle the 402 Payment Required response automatically -5. Print the final response diff --git a/examples/python/legacy/clients/httpx/extensible.py b/examples/python/legacy/clients/httpx/extensible.py deleted file mode 100644 index 9edc695c27..0000000000 --- a/examples/python/legacy/clients/httpx/extensible.py +++ /dev/null @@ -1,57 +0,0 @@ -import os -import asyncio -from dotenv import load_dotenv -from eth_account import Account -from x402.clients.httpx import x402_payment_hooks -from x402.clients.base import decode_x_payment_response -import httpx - -# Load environment variables -load_dotenv() - -# Get environment variables -private_key = os.getenv("PRIVATE_KEY") -base_url = os.getenv("RESOURCE_SERVER_URL") -endpoint_path = os.getenv("ENDPOINT_PATH") - -if not all([private_key, base_url, endpoint_path]): - print("Error: Missing required environment variables") - exit(1) - -# Create eth_account from private key -account = Account.from_key(private_key) -print(f"Initialized account: {account.address}") - - -async def main(): - # Create httpx client with x402 payment hooks - async with httpx.AsyncClient(base_url=base_url) as client: - # Add payment hooks directly to client.event_hooks - client.event_hooks = x402_payment_hooks(account) - - # Make request - try: - print(f"Making request to {endpoint_path}") - response = await client.get(endpoint_path) - - # Read the response content - content = await response.aread() - print(f"Response: {content.decode()}") - - # Check for payment response header - if "X-Payment-Response" in response.headers: - payment_response = decode_x_payment_response( - response.headers["X-Payment-Response"] - ) - print( - f"Payment response transaction hash: {payment_response['transaction']}" - ) - else: - print("Warning: No payment response header found") - - except Exception as e: - print(f"Error occurred: {str(e)}") - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/examples/python/legacy/clients/httpx/main.py b/examples/python/legacy/clients/httpx/main.py deleted file mode 100644 index 3016d1046a..0000000000 --- a/examples/python/legacy/clients/httpx/main.py +++ /dev/null @@ -1,78 +0,0 @@ -import os -import asyncio -from dotenv import load_dotenv -from eth_account import Account -from x402.clients.httpx import x402HttpxClient -from x402.clients.base import decode_x_payment_response, x402Client - -# Load environment variables -load_dotenv() - -# Get environment variables -private_key = os.getenv("PRIVATE_KEY") -base_url = os.getenv("RESOURCE_SERVER_URL") -endpoint_path = os.getenv("ENDPOINT_PATH") - -if not all([private_key, base_url, endpoint_path]): - print("Error: Missing required environment variables") - exit(1) - -# Create eth_account from private key -account = Account.from_key(private_key) -print(f"Initialized account: {account.address}") - - -def custom_payment_selector( - accepts, network_filter=None, scheme_filter=None, max_value=None -): - """Custom payment selector that filters by network.""" - # Ignore the network_filter parameter for this example - we hardcode base-sepolia - _ = network_filter - - # NOTE: In a real application, you'd want to dynamically choose the most - # appropriate payment requirement based on user preferences, available funds, - # network conditions, or other business logic rather than hardcoding a network. - - # Filter by base-sepolia network (testnet) - return x402Client.default_payment_requirements_selector( - accepts, - network_filter="base-sepolia", - scheme_filter=scheme_filter, - max_value=max_value, - ) - - -async def main(): - # Create x402HttpxClient with built-in payment handling and network filtering - async with x402HttpxClient( - account=account, - base_url=base_url, - payment_requirements_selector=custom_payment_selector, - ) as client: - # Make request - payment handling is automatic - try: - assert endpoint_path is not None # we already guard against None above - print(f"Making request to {endpoint_path}") - response = await client.get(endpoint_path) - - # Read the response content - content = await response.aread() - print(f"Response: {content.decode()}") - - # Check for payment response header - if "X-Payment-Response" in response.headers: - payment_response = decode_x_payment_response( - response.headers["X-Payment-Response"] - ) - print( - f"Payment response transaction hash: {payment_response['transaction']}" - ) - else: - print("Warning: No payment response header found") - - except Exception as e: - print(f"Error occurred: {str(e)}") - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/examples/python/legacy/clients/httpx/pyproject.toml b/examples/python/legacy/clients/httpx/pyproject.toml deleted file mode 100644 index 277ded7e15..0000000000 --- a/examples/python/legacy/clients/httpx/pyproject.toml +++ /dev/null @@ -1,26 +0,0 @@ -[project] -name = "x402-httpx-example" -version = "0.1.0" -description = "Example of using x402 with httpx" -requires-python = ">=3.10" -dependencies = [ - "httpx>=0.24.0", - "eth-account>=0.8.0", - "x402" -] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -packages = ["."] - -[tool.hatch.metadata] -allow-direct-references = true - -[tool.uv] -package = false - -[tool.uv.sources] -x402 = { path = "../../../../../python/legacy", editable = true } diff --git a/examples/python/legacy/clients/httpx/uv.lock b/examples/python/legacy/clients/httpx/uv.lock deleted file mode 100644 index 111cc4c2b6..0000000000 --- a/examples/python/legacy/clients/httpx/uv.lock +++ /dev/null @@ -1,1973 +0,0 @@ -version = 1 -revision = 2 -requires-python = ">=3.10" - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, -] - -[[package]] -name = "aiohttp" -version = "3.12.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f2/84/ea27e6ad14747d8c51afe201fb88a5c8282b6278256d30a6f71f730add88/aiohttp-3.12.12.tar.gz", hash = "sha256:05875595d2483d96cb61fa9f64e75262d7ac6251a7e3c811d8e26f7d721760bd", size = 7818643, upload-time = "2025-06-10T05:22:00.247Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/d9/cfde93b9cb75253c716b8b1c773565209e3d4dd0772dd3ce3a2adcaa4639/aiohttp-3.12.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6f25e9d274d6abbb15254f76f100c3984d6b9ad6e66263cc60a465dd5c7e48f5", size = 702071, upload-time = "2025-06-10T05:18:23.986Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/46e38b8bc0bc645317deec32612af922ad9bafd85a1df255a67c2f2305f6/aiohttp-3.12.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b8ec3c1a1c13d24941b5b913607e57b9364e4c0ea69d5363181467492c4b2ba6", size = 478436, upload-time = "2025-06-10T05:18:28.411Z" }, - { url = "https://files.pythonhosted.org/packages/8f/47/9c83db7f02ca71eb99a707ee13657fc24ba703b9babc59000c1f58ac1198/aiohttp-3.12.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81ef2f9253c327c211cb7b06ea2edd90e637cf21c347b894d540466b8d304e08", size = 466213, upload-time = "2025-06-10T05:18:30.706Z" }, - { url = "https://files.pythonhosted.org/packages/31/fe/4690c112e269e06c9182c32eeb43f3a95c4f203fdb095502717327993b80/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28ded835c3663fd41c9ad44685811b11e34e6ac9a7516a30bfce13f6abba4496", size = 1648258, upload-time = "2025-06-10T05:18:32.498Z" }, - { url = "https://files.pythonhosted.org/packages/c8/1f/dacca6c7bbe69c77d8535d7a672478803e7078cc20fd9993fe09aa5be880/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a4b78ccf254fc10605b263996949a94ca3f50e4f9100e05137d6583e266b711e", size = 1622316, upload-time = "2025-06-10T05:18:34.357Z" }, - { url = "https://files.pythonhosted.org/packages/ff/65/5ef47708f70524fcdecda735e0aea06e0feb7b8679e976e9bd1e7900f4c0/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f4a5af90d5232c41bb857568fe7d11ed84408653ec9da1ff999cc30258b9bd1", size = 1694723, upload-time = "2025-06-10T05:18:36.858Z" }, - { url = "https://files.pythonhosted.org/packages/18/62/ab32bfa59f61292e4096c383316863e10001eec30e5b4b314856ed7156e2/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffa5205c2f53f1120e93fdf2eca41b0f6344db131bc421246ee82c1e1038a14a", size = 1737037, upload-time = "2025-06-10T05:18:39.663Z" }, - { url = "https://files.pythonhosted.org/packages/c1/b9/8b8f793081311e4f63aea63003a519064048e406c627c0454d6ed09dbc99/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68301660f0d7a3eddfb84f959f78a8f9db98c76a49b5235508fa16edaad0f7c", size = 1641701, upload-time = "2025-06-10T05:18:41.666Z" }, - { url = "https://files.pythonhosted.org/packages/1a/5c/72f510d42d626463b526345dcb8d14b390de89a9ba27a4717b518460bcd4/aiohttp-3.12.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db874d3b0c92fdbb553751af9d2733b378c25cc83cd9dfba87f12fafd2dc9cd5", size = 1581824, upload-time = "2025-06-10T05:18:44.136Z" }, - { url = "https://files.pythonhosted.org/packages/61/6f/9378c9e1543d1c800ca040e21cd333b8f923ed051ae82b5a49ad96a6ac71/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5e53cf9c201b45838a2d07b1f2d5f7fec9666db7979240002ce64f9b8a1e0cf2", size = 1625674, upload-time = "2025-06-10T05:18:46.716Z" }, - { url = "https://files.pythonhosted.org/packages/bb/85/4eef9bd52b497a405c88469cc099f4d15d33b149b5746ca4ef8ec6ab6388/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:8687cc5f32b4e328c233acd387d09a1b477007896b2f03c1c823a0fd05f63883", size = 1636460, upload-time = "2025-06-10T05:18:49.305Z" }, - { url = "https://files.pythonhosted.org/packages/56/59/d8e954830b375fd658843cf7d88d27ca5e38dd5fcbfe62db3d1ba415d0fe/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ee537ad29de716a3d8dc46c609908de0c25ffeebf93cd94a03d64cdc07d66d0", size = 1611912, upload-time = "2025-06-10T05:18:51.694Z" }, - { url = "https://files.pythonhosted.org/packages/c3/5d/d0096a02f0515a38dff67db42d966273a12d17fc895e91466bfb4ab3875e/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:411f821be5af6af11dc5bed6c6c1dc6b6b25b91737d968ec2756f9baa75e5f9b", size = 1691498, upload-time = "2025-06-10T05:18:54.36Z" }, - { url = "https://files.pythonhosted.org/packages/87/8d/d3a02397a6345c06623ae4648e2aef18fced858510b4a89d7262cfa4c683/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f90319d94cf5f9786773237f24bd235a7b5959089f1af8ec1154580a3434b503", size = 1714737, upload-time = "2025-06-10T05:18:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/a9/40/b81000bf07c96db878703ea3dc561393d82441597729910459a8e06acc9a/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:73b148e606f34e9d513c451fd65efe1091772659ca5703338a396a99f60108ff", size = 1643078, upload-time = "2025-06-10T05:18:59.33Z" }, - { url = "https://files.pythonhosted.org/packages/41/e5/31830642ce2c6d3dba74ed8a94933213df5e1651c1e8b4efc81cc88105ab/aiohttp-3.12.12-cp310-cp310-win32.whl", hash = "sha256:d40e7bfd577fdc8a92b72f35dfbdd3ec90f1bc8a72a42037fefe34d4eca2d4a1", size = 427517, upload-time = "2025-06-10T05:19:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/55/9d/a4e5379d44679e5f8d7d7ebecb0dae8cafab95176c4e753da6bc4b4aebb5/aiohttp-3.12.12-cp310-cp310-win_amd64.whl", hash = "sha256:65c7804a2343893d6dea9fce69811aea0a9ac47f68312cf2e3ee1668cd9a387f", size = 450725, upload-time = "2025-06-10T05:19:03.874Z" }, - { url = "https://files.pythonhosted.org/packages/47/1f/b1b66e05dc3066a9ba7862d50e2e95b3871db82ccf9652568845f353eeba/aiohttp-3.12.12-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:38823fe0d8bc059b3eaedb263fe427d887c7032e72b4ef92c472953285f0e658", size = 709385, upload-time = "2025-06-10T05:19:05.763Z" }, - { url = "https://files.pythonhosted.org/packages/43/e6/3230e42af16438b450b1e193c537fd3d2d31771dafda3c2105a8d11af707/aiohttp-3.12.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:10237f2c34711215d04ed21da63852ce023608299554080a45c576215d9df81c", size = 481660, upload-time = "2025-06-10T05:19:08.332Z" }, - { url = "https://files.pythonhosted.org/packages/06/ba/cfa91fe5cc262535e1175b1522d8fcc09f9d6ad18b85241f4ee3be1d780f/aiohttp-3.12.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:563ec477c0dc6d56fc7f943a3475b5acdb399c7686c30f5a98ada24bb7562c7a", size = 469924, upload-time = "2025-06-10T05:19:10.342Z" }, - { url = "https://files.pythonhosted.org/packages/9a/f0/5c706cfddd4769b55c0cda466aa6034412d39e416f0b30dda81c4a24616f/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3d05c46a61aca7c47df74afff818bc06a251ab95d95ff80b53665edfe1e0bdf", size = 1740116, upload-time = "2025-06-10T05:19:12.783Z" }, - { url = "https://files.pythonhosted.org/packages/4d/9f/04dba2e1c8bee53c3c623d11a1f947c9e2712500f734dc0dfd06daad32ec/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:277c882916759b4a6b6dc7e2ceb124aad071b3c6456487808d9ab13e1b448d57", size = 1688784, upload-time = "2025-06-10T05:19:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/df/24/19d6d4c41fbf8304fe7c111fcc701e0aa5a2232ee3ac16272677a11f9cfe/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:216abf74b324b0f4e67041dd4fb2819613909a825904f8a51701fbcd40c09cd7", size = 1787575, upload-time = "2025-06-10T05:19:18.586Z" }, - { url = "https://files.pythonhosted.org/packages/0c/59/01f4c55a1f91ad3b5255b2498b3a22362a3fe6ee9bc9ba1af3cc668244da/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65d6cefad286459b68e7f867b9586a821fb7f121057b88f02f536ef570992329", size = 1826621, upload-time = "2025-06-10T05:19:21.284Z" }, - { url = "https://files.pythonhosted.org/packages/55/85/6357166918ff5025602a7cc41332c1ae7a5b57f2fe3da4d755ae30f24bd0/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feaaaff61966b5f4b4eae0b79fc79427f49484e4cfa5ab7d138ecd933ab540a8", size = 1729082, upload-time = "2025-06-10T05:19:23.307Z" }, - { url = "https://files.pythonhosted.org/packages/e3/ca/de3b5ccd5a2aa9352f6ec6f446565f6e1601ebb54860c94c686a9ff76660/aiohttp-3.12.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a05917780b7cad1755784b16cfaad806bc16029a93d15f063ca60185b7d9ba05", size = 1666159, upload-time = "2025-06-10T05:19:25.929Z" }, - { url = "https://files.pythonhosted.org/packages/d1/69/a1006021a1d3244c0872ee75cd8da150e0098b3b2ec6945c225754d11a60/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:082c5ec6d262c1b2ee01c63f4fb9152c17f11692bf16f0f100ad94a7a287d456", size = 1714433, upload-time = "2025-06-10T05:19:28.044Z" }, - { url = "https://files.pythonhosted.org/packages/d2/2a/15aa1179e9fbdd0d17cdf117b4296dedad098abb5a93f8e9c8ab4626f6ea/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:b265a3a8b379b38696ac78bdef943bdc4f4a5d6bed1a3fb5c75c6bab1ecea422", size = 1709590, upload-time = "2025-06-10T05:19:30.165Z" }, - { url = "https://files.pythonhosted.org/packages/a2/f0/95ed9e21250815f1d1a0cd3e868a3f39400a16010ae59f19ddd4ccc4e787/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2e0f2e208914ecbc4b2a3b7b4daa759d0c587d9a0b451bb0835ac47fae7fa735", size = 1689776, upload-time = "2025-06-10T05:19:32.965Z" }, - { url = "https://files.pythonhosted.org/packages/81/4d/370ecc133c648c98a85445f2d331c1272859c89cd52c29a293015bc352c7/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9923b025845b72f64d167bca221113377c8ffabd0a351dc18fb839d401ee8e22", size = 1783378, upload-time = "2025-06-10T05:19:35.14Z" }, - { url = "https://files.pythonhosted.org/packages/a8/86/414e3dae7e07caf6b02cd75d7148d0d8673d4c5077f407be3627d6e33fac/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1ebb213445900527831fecc70e185bf142fdfe5f2a691075f22d63c65ee3c35a", size = 1803841, upload-time = "2025-06-10T05:19:37.41Z" }, - { url = "https://files.pythonhosted.org/packages/88/df/486f10df681cd1a8c898acc8dc2edbd46ffb088b886757b71ae362bf44d3/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6fc369fb273a8328077d37798b77c1e65676709af5c182cb74bd169ca9defe81", size = 1716896, upload-time = "2025-06-10T05:19:40.172Z" }, - { url = "https://files.pythonhosted.org/packages/07/1e/1cacaf5d838869432e96ece1580d0b51494ebb66351f0e8118b74b38d2f0/aiohttp-3.12.12-cp311-cp311-win32.whl", hash = "sha256:58ecd10fda6a44c311cd3742cfd2aea8c4c600338e9f27cb37434d9f5ca9ddaa", size = 427030, upload-time = "2025-06-10T05:19:42.152Z" }, - { url = "https://files.pythonhosted.org/packages/30/dd/e89c1d190da2c84e0ca03c2970b9988a9c56005d18db7f447cf62b3ae6d0/aiohttp-3.12.12-cp311-cp311-win_amd64.whl", hash = "sha256:b0066e88f30be00badffb5ef8f2281532b9a9020863d873ae15f7c147770b6ec", size = 451419, upload-time = "2025-06-10T05:19:44.176Z" }, - { url = "https://files.pythonhosted.org/packages/df/e6/df14ec151942818ecc5e685fa8a4b07d3d3d8a9e4a7d2701047c89290551/aiohttp-3.12.12-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:98451ce9ce229d092f278a74a7c2a06b3aa72984673c87796126d7ccade893e9", size = 700494, upload-time = "2025-06-10T05:19:46.18Z" }, - { url = "https://files.pythonhosted.org/packages/4f/dc/7bc6e17adcd7a82b0d0317ad3e792ac22c93fb672077f0eade93e8d70182/aiohttp-3.12.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:adbac7286d89245e1aff42e948503fdc6edf6d5d65c8e305a67c40f6a8fb95f4", size = 475095, upload-time = "2025-06-10T05:19:48.246Z" }, - { url = "https://files.pythonhosted.org/packages/80/fd/c4e8846ad9d9ecdb7d5ba96de65b7bf2c1582f0b2732f2023080c1c05255/aiohttp-3.12.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0728882115bfa85cbd8d0f664c8ccc0cfd5bd3789dd837596785450ae52fac31", size = 467929, upload-time = "2025-06-10T05:19:50.79Z" }, - { url = "https://files.pythonhosted.org/packages/70/40/abebcf5c81f5e65b4379c05929773be2731ce12414264d3e0fe09ee241eb/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf3b9d9e767f9d0e09fb1a31516410fc741a62cc08754578c40abc497d09540", size = 1714729, upload-time = "2025-06-10T05:19:52.989Z" }, - { url = "https://files.pythonhosted.org/packages/8e/67/4c4f96ef6f16405e7c5205ab3c28852c7e904493b6ddc1c744dda1c97a81/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c944860e86b9f77a462321a440ccf6fa10f5719bb9d026f6b0b11307b1c96c7b", size = 1697380, upload-time = "2025-06-10T05:19:55.832Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a2/dae9ebea4caa8030170c0237e55fa0960df44b3596a849ab9ea621964054/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b1979e1f0c98c06fd0cd940988833b102fa3aa56751f6c40ffe85cabc51f6fd", size = 1752474, upload-time = "2025-06-10T05:19:58.007Z" }, - { url = "https://files.pythonhosted.org/packages/31/ef/f3d9073565ac7ad5257aaa1490ebfc2f182dfc817d3ccfd38c8ab35b2247/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:120b7dd084e96cfdad85acea2ce1e7708c70a26db913eabb8d7b417c728f5d84", size = 1798631, upload-time = "2025-06-10T05:20:00.393Z" }, - { url = "https://files.pythonhosted.org/packages/8b/0b/8b1978662274c80c8e4a739d9be1ae9ef25e5ce42b55838d6a9d1a4e3497/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e58f5ae79649ffa247081c2e8c85e31d29623cf2a3137dda985ae05c9478aae", size = 1718071, upload-time = "2025-06-10T05:20:02.812Z" }, - { url = "https://files.pythonhosted.org/packages/56/aa/35786137db867901b41cb3d2c19c0f4c56dfe581694dba99dec2683d8f8d/aiohttp-3.12.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aa5f049e3e2745b0141f13e5a64e7c48b1a1427ed18bbb7957b348f282fee56", size = 1633871, upload-time = "2025-06-10T05:20:05.127Z" }, - { url = "https://files.pythonhosted.org/packages/63/1d/34d45497dd04d08d662ecda875c44e91d271bbc5d21f4c9e4cbd3ddf7ae2/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7163cc9cf3722d90f1822f8a38b211e3ae2fc651c63bb55449f03dc1b3ff1d44", size = 1694933, upload-time = "2025-06-10T05:20:07.431Z" }, - { url = "https://files.pythonhosted.org/packages/29/c7/41e09a4517449eabbb0a7fe6d60f584fe5b21d4bff761197eb0b81e70034/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ef97c4d035b721de6607f3980fa3e4ef0ec3aca76474b5789b7fac286a8c4e23", size = 1716386, upload-time = "2025-06-10T05:20:09.787Z" }, - { url = "https://files.pythonhosted.org/packages/3a/32/907bd2010b51b70de5314ad707dfc4e898ea0011ff3d678cdf43d6f8980a/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1c14448d6a86acadc3f7b2f4cc385d1fb390acb6f37dce27f86fe629410d92e3", size = 1657039, upload-time = "2025-06-10T05:20:12.198Z" }, - { url = "https://files.pythonhosted.org/packages/60/27/8d87344a33346dcd39273adc33060aeb135e0ef70d1d6e71a3b03894a8e9/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a1b6df6255cfc493454c79221183d64007dd5080bcda100db29b7ff181b8832c", size = 1736599, upload-time = "2025-06-10T05:20:14.519Z" }, - { url = "https://files.pythonhosted.org/packages/ca/45/57c7ef1af694a6d0906abab6edde03787c8c6b0cf5d8359b69d1eb0679df/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:60fc7338dfb0626c2927bfbac4785de3ea2e2bbe3d328ba5f3ece123edda4977", size = 1764575, upload-time = "2025-06-10T05:20:16.993Z" }, - { url = "https://files.pythonhosted.org/packages/2a/cc/b1f918cd702efa9ead9d41f89214e9225cda4e5d013d6eed7f1915c17d0a/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d2afc72207ef4c9d4ca9fcd00689a6a37ef2d625600c3d757b5c2b80c9d0cf9a", size = 1724184, upload-time = "2025-06-10T05:20:19.296Z" }, - { url = "https://files.pythonhosted.org/packages/47/55/089762ee32c2a2e0f523d9ab38c9da2a344cac0e0cc8d16ecf206517ef7e/aiohttp-3.12.12-cp312-cp312-win32.whl", hash = "sha256:8098a48f93b2cbcdb5778e7c9a0e0375363e40ad692348e6e65c3b70d593b27c", size = 421762, upload-time = "2025-06-10T05:20:22.063Z" }, - { url = "https://files.pythonhosted.org/packages/ab/47/151f657e429972916f61399bd52b410e9072d5a2cae1b794f890930e5797/aiohttp-3.12.12-cp312-cp312-win_amd64.whl", hash = "sha256:d1c1879b2e0fc337d7a1b63fe950553c2b9e93c071cf95928aeea1902d441403", size = 447863, upload-time = "2025-06-10T05:20:24.326Z" }, - { url = "https://files.pythonhosted.org/packages/ee/3e/396a7d1c47aa7a74612b186dc716857506c61afac72337a7a96215c2a124/aiohttp-3.12.12-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ea5d604318234427929d486954e3199aded65f41593ac57aa0241ab93dda3d15", size = 694901, upload-time = "2025-06-10T05:20:26.58Z" }, - { url = "https://files.pythonhosted.org/packages/cc/97/235e48eadf73a1854b4d4da29b88d00049309d897d55a511e1cbe4412603/aiohttp-3.12.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e03ff38250b8b572dce6fcd7b6fb6ee398bb8a59e6aa199009c5322d721df4fc", size = 472552, upload-time = "2025-06-10T05:20:28.957Z" }, - { url = "https://files.pythonhosted.org/packages/6b/73/cd7c9439e8cab4113650541017c6524bd0e675b219dfdbbf945a78305e3f/aiohttp-3.12.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:71125b1fc2b6a94bccc63bbece620906a4dead336d2051f8af9cbf04480bc5af", size = 464853, upload-time = "2025-06-10T05:20:31.652Z" }, - { url = "https://files.pythonhosted.org/packages/d1/33/eea88ee55ed4b3f74732d9fc773e6fcf134a2971a19c7ecc49a291e7e57f/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:784a66f9f853a22c6b8c2bd0ff157f9b879700f468d6d72cfa99167df08c5c9c", size = 1703671, upload-time = "2025-06-10T05:20:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/2a/e3/a67ecf9c154b13bad9e2a86ea3782a4b73e889343ffde8c1aadcf9099c09/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a5be0b58670b54301404bd1840e4902570a1c3be00358e2700919cb1ea73c438", size = 1684934, upload-time = "2025-06-10T05:20:36.721Z" }, - { url = "https://files.pythonhosted.org/packages/89/f0/3aaea866531be2f2fcf3a87607e1f55fa72e6ce5acd6b058941a4fc35e15/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8f13566fc7bf5a728275b434bc3bdea87a7ed3ad5f734102b02ca59d9b510f", size = 1737004, upload-time = "2025-06-10T05:20:39.533Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/15867a4c7d39d8fd9bd02191cf60b1d06415fc407bbd4ff2f9660845f1cb/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d736e57d1901683bc9be648aa308cb73e646252c74b4c639c35dcd401ed385ea", size = 1786378, upload-time = "2025-06-10T05:20:42.03Z" }, - { url = "https://files.pythonhosted.org/packages/bd/61/82b15f87088b35705e01fce55806241b45a1099b3470bbca0bed8ee98662/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2007eaa7aae9102f211c519d1ec196bd3cecb1944a095db19eeaf132b798738", size = 1708707, upload-time = "2025-06-10T05:20:44.474Z" }, - { url = "https://files.pythonhosted.org/packages/28/f2/aed0786d5a1c2ed1f5a13ff2a98baacc27206b81d93812da28fc49d8a5d0/aiohttp-3.12.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a813e61583cab6d5cdbaa34bc28863acdb92f9f46e11de1b3b9251a1e8238f6", size = 1622410, upload-time = "2025-06-10T05:20:46.957Z" }, - { url = "https://files.pythonhosted.org/packages/17/54/8305f49a960376136ada977be1370fddb584c63d40bd1b9bef59469f28c7/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e408293aa910b0aea48b86a28eace41d497a85ba16c20f619f0c604597ef996c", size = 1675435, upload-time = "2025-06-10T05:20:49.379Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dc/0a55350025bc297265cfa6c6b1b1f7508f4226ca3238697cbe5e772a7d76/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f3d31faf290f5a30acba46b388465b67c6dbe8655d183e9efe2f6a1d594e6d9d", size = 1707099, upload-time = "2025-06-10T05:20:51.974Z" }, - { url = "https://files.pythonhosted.org/packages/d8/70/d949a1612b996e49d540c10ed77a0a1465c482a590e9a59c1c7897746119/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0b84731697325b023902aa643bd1726d999f5bc7854bc28b17ff410a81151d4b", size = 1649693, upload-time = "2025-06-10T05:20:54.973Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ea/fb87beb7135e25576a1e6fbe98106c037d9fcf1543f19108f9ceb73c192c/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a324c6852b6e327811748446e56cc9bb6eaa58710557922183175816e82a4234", size = 1725825, upload-time = "2025-06-10T05:20:57.433Z" }, - { url = "https://files.pythonhosted.org/packages/f1/1f/adbeb3e440d49b733cef499ace94723ab1fe9fb516425e219379e03b7c9a/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:22fd867fbd72612dcf670c90486dbcbaf702cb807fb0b42bc0b7a142a573574a", size = 1759300, upload-time = "2025-06-10T05:21:00.444Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c1/2fe007ad930f409d0d7fd9916cd55ec9b78b6a611a237424266ed71da48b/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3e092f1a970223794a4bf620a26c0e4e4e8e36bccae9b0b5da35e6d8ee598a03", size = 1708189, upload-time = "2025-06-10T05:21:02.969Z" }, - { url = "https://files.pythonhosted.org/packages/85/5e/ed3ed640fafae3972eae6cd26f66240108cf62452ac8128d59970d538cb1/aiohttp-3.12.12-cp313-cp313-win32.whl", hash = "sha256:7f5f5eb8717ef8ba15ab35fcde5a70ad28bbdc34157595d1cddd888a985f5aae", size = 420783, upload-time = "2025-06-10T05:21:06.287Z" }, - { url = "https://files.pythonhosted.org/packages/a6/db/57d2bb4af52dd0c6f62c42c7d34b82495b2902e50440134f70bfb7ee0fdd/aiohttp-3.12.12-cp313-cp313-win_amd64.whl", hash = "sha256:ace2499bdd03c329c054dc4b47361f2b19d5aa470f7db5c7e0e989336761b33c", size = 446721, upload-time = "2025-06-10T05:21:08.738Z" }, -] - -[[package]] -name = "aiosignal" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, -] - -[[package]] -name = "async-timeout" -version = "5.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, -] - -[[package]] -name = "attrs" -version = "25.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, -] - -[[package]] -name = "bitarray" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/0d/15826c7c2d49a4518a1b24b0d432f1ecad2e0b68168f942058b5de498498/bitarray-3.4.2.tar.gz", hash = "sha256:78ed2b911aabede3a31e3329b1de8abdc8104bd5e0545184ddbd9c7f668f4059", size = 143756, upload-time = "2025-05-21T16:21:44.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/61/fa3a06d74bfba1dc591efa9f4f5ad2e5645f06a8c4d113cf12d18b5ac25b/bitarray-3.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:42b552f885c5629182928c79237b375a92bcf1bc1e725b1c8a5e8eab28ea300d", size = 141280, upload-time = "2025-05-21T16:18:02.593Z" }, - { url = "https://files.pythonhosted.org/packages/17/ba/7eb30374c0e4c4b732a3ca3457d9fb0e44165ae4c5af9758597b03211a28/bitarray-3.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3e16d6184f349587b6a5045bcf073baf763a86273aab454485ba437d0bca82e8", size = 138031, upload-time = "2025-05-21T16:18:05.616Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6d/91582b0a232b54e910add5d0db34a926d0bdfdd1447685b8750349c71958/bitarray-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ecf456f0dee61bd818011e290d922e3e3b1aeb0544f6f19c4da9c5fc2e52818", size = 306437, upload-time = "2025-05-21T16:18:06.793Z" }, - { url = "https://files.pythonhosted.org/packages/b8/23/113ccc20f6324d517ef6210c8fc6ae300346eb481c5a0483735e19b4deea/bitarray-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8bbe8249ae90dc0cd78b21d5d5d27a614e15bf30737ae6e8a0e2e60cc492acc", size = 322335, upload-time = "2025-05-21T16:18:07.925Z" }, - { url = "https://files.pythonhosted.org/packages/6d/89/bf5a36e05ac3d77bdccbe9ba0eea4c47253411c2616379de0f181c27ecee/bitarray-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe7706f75f3b86e7afa516452bed9757ee301b59aea580c551c32a5e1cef082c", size = 314137, upload-time = "2025-05-21T16:18:09.333Z" }, - { url = "https://files.pythonhosted.org/packages/66/a6/bed287f9095a2a266fc68ee42d6ee2815ff500783f973876d86a6d37a434/bitarray-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c60c8d30bb6efd2c04cf82d077df6449964234aeca996f6f1df317a08feffc0", size = 307963, upload-time = "2025-05-21T16:18:10.618Z" }, - { url = "https://files.pythonhosted.org/packages/2f/50/3ca2adaf0da034e6c1a2ed60a3781b065672dd282e67f88593290c3990a7/bitarray-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b4cb5c22706d411010c7ce5efc0a4cc99f755a30fc7f6770eb1b1a0c0962bbb", size = 295182, upload-time = "2025-05-21T16:18:11.932Z" }, - { url = "https://files.pythonhosted.org/packages/90/de/8c3d96e273bc51e4912185bd809fc6a9ec14a09e607336892c149e0c57c5/bitarray-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0fd60137a9474ce53bdace68c718a7c538f9df01d390452cc984f1ee78d7bcdb", size = 300063, upload-time = "2025-05-21T16:18:13.221Z" }, - { url = "https://files.pythonhosted.org/packages/9d/71/34f0ea6ac5b2cbdd84f3e6283b5b796628cef616e786cb442cefce0fe224/bitarray-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cd514a8e27d0751f0254861df60335edabacccfcb2457793ff30c8b2ed8f799d", size = 292053, upload-time = "2025-05-21T16:18:14.802Z" }, - { url = "https://files.pythonhosted.org/packages/77/99/6ef41312536d2c37f14f0f7173aa1a012e9675d62900c10afa7641b47f75/bitarray-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6c8f7447cdf2faff1d176c5dd207f0134f05cfa2a238d3d3944dc5019dc41593", size = 317007, upload-time = "2025-05-21T16:18:16.117Z" }, - { url = "https://files.pythonhosted.org/packages/22/f9/cc4e73f54698bcdd1e0f1ea582da7e005464651e8116291a226deab95e1b/bitarray-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:75040a2a1abe4ccd40236f4ba0d39abde981d23f3ce7691b3b3f2137f134b99b", size = 319402, upload-time = "2025-05-21T16:18:18.097Z" }, - { url = "https://files.pythonhosted.org/packages/55/40/c23dd5726107cbbc5e698b3fcca5ffac83d29146ef469f27f5277d18c2d7/bitarray-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ba15725cd9040b9b1b2650edb33253cb2ba7b68d087974e296e5ff082198952f", size = 299456, upload-time = "2025-05-21T16:18:20.029Z" }, - { url = "https://files.pythonhosted.org/packages/21/31/6bfd9fda776f8d98512d5484fcb55fbb25e60796e7b5d3b9a3a300e8bc1c/bitarray-3.4.2-cp310-cp310-win32.whl", hash = "sha256:2959dfc61d963546e97220cfcaab7dfc489276c6e00092b57710522e68712b28", size = 134279, upload-time = "2025-05-21T16:18:21.609Z" }, - { url = "https://files.pythonhosted.org/packages/82/9d/7067f6548b470beb86d83f7ac6c45cac3b9c28cf77fa0f9f3e67353d69d3/bitarray-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:97077fa0ec3b7eed57cd8d1cb0eb75d670423d20b7e4901482347a81efe2f6fd", size = 141360, upload-time = "2025-05-21T16:18:23.197Z" }, - { url = "https://files.pythonhosted.org/packages/94/ba/508ba6a3ea16eb6c21baae33cd1b7bf6e299d21a496a1f90b8203a22d6d0/bitarray-3.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90ca8e260b75a7ac0c542093e5f29154e51fd0d2d0fa5041c038cb2b58415eeb", size = 141425, upload-time = "2025-05-21T16:18:24.452Z" }, - { url = "https://files.pythonhosted.org/packages/eb/a1/44d9b88cd3daee3734ea98dac691acc2c935a3bfbd5bfc38267a59bd986d/bitarray-3.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549dabcae78fb8f9133e3138b9473c7648d6054bb6fec84d28d3861aaec5ddd1", size = 138172, upload-time = "2025-05-21T16:18:25.601Z" }, - { url = "https://files.pythonhosted.org/packages/5f/aa/5a8c33ab39e8a894978d42427ad0a1ba2d5c9cb61c8480101be555c0e3a7/bitarray-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3da536ac84e6911cbc8e86be0baf1cab0d4f4ccb80c0f39b4fa28509f2db1a", size = 313373, upload-time = "2025-05-21T16:18:26.796Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/b0d28e21d91ec5c0477a320b9443096ddc816fbc59778b367f9e49094532/bitarray-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a5e84d6b737de2d773ab1bd538e6f37fa7f667ea734f00a48d9a973b181c751", size = 329657, upload-time = "2025-05-21T16:18:28.097Z" }, - { url = "https://files.pythonhosted.org/packages/bd/d5/1f858bd559568286435a460e7a169a5185b2b29184684e6c6fa303af3ca9/bitarray-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e265c5eede8316ba64bb6029832f282f6284a557b625bb3207a7680fd5da7925", size = 321873, upload-time = "2025-05-21T16:18:29.511Z" }, - { url = "https://files.pythonhosted.org/packages/e8/c8/23df4174142cccf6a8bd114651b8e9bf965005ab1ef741d37c9f72e8d2eb/bitarray-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63fb45c60c7ab7a724aa64203305e56f344489e12d41619bdc9d7887d6562e01", size = 314796, upload-time = "2025-05-21T16:18:31.2Z" }, - { url = "https://files.pythonhosted.org/packages/8f/21/329178b165f1aaf3f2ace3eb24aca5ad197febae908d7b41e552a69043e9/bitarray-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:083c2a9234dacf3e4e166a5844256da2a397941d3f6397e5b919bffca638f6ef", size = 302724, upload-time = "2025-05-21T16:18:32.729Z" }, - { url = "https://files.pythonhosted.org/packages/26/a8/a66d3c0d3410d01f51824f8476b060f96b3353db7d6b45c87dba6d1aa0e0/bitarray-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e72606adb2438002873cb0e8e81c3fce926386a59bbafa82fea07cdb2a6d8a05", size = 307434, upload-time = "2025-05-21T16:18:34.394Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ac/3052386e7ff80c80eb2549a22c890f511e9f9f7fbbe6244b04255adae031/bitarray-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dc994d22a3a563e1d402dc2f64c61e60605a1a3e66dd8aea7636f607b99f03cb", size = 299232, upload-time = "2025-05-21T16:18:35.708Z" }, - { url = "https://files.pythonhosted.org/packages/9d/46/91a32ccd39d40371ed7404d96a6f3cf1e381eaf36be5390c6bff5034f344/bitarray-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:214468391680ba1c831872a7949f1b563ab3cd832d10adc52df4f36e0af24446", size = 324056, upload-time = "2025-05-21T16:18:37.536Z" }, - { url = "https://files.pythonhosted.org/packages/39/0e/cb824f0e0302cd08809f67b35b3ae21b47af5dd122e99740bfe6bde1c824/bitarray-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c7483b97807bb018a7cd7f9741800c714c9c56ba4e5a7e962c5f956c4b858f3c", size = 327058, upload-time = "2025-05-21T16:18:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/09/01/845e977d490e4e261179785540d1fdeff966c99296f503adc0e5407fc257/bitarray-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5774bf14ec451d5ac311cfcfe0b0cf2a1a9fa74b6ca81dfbc4f56a98872a5541", size = 306629, upload-time = "2025-05-21T16:18:40.211Z" }, - { url = "https://files.pythonhosted.org/packages/29/ef/33ee8533ff1b2a8cd0b9e84fd81b2a90d66c2774544c861e281c5361eaa2/bitarray-3.4.2-cp311-cp311-win32.whl", hash = "sha256:e6f35567347ddb8b9e8b6bf6ab7d64be88bdb6b6c107b8edbb2c3d426c1590a0", size = 134450, upload-time = "2025-05-21T16:18:42.435Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/069c255d067319a9695c93369641d7f5539625069c1cf3ded2becff1bfbc/bitarray-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae5b0a8d3caf6284220232738dc7c05af81ec3a9f93d4a462295462dd0a492b2", size = 141596, upload-time = "2025-05-21T16:18:43.743Z" }, - { url = "https://files.pythonhosted.org/packages/05/57/0b2b50eb3f50c3144f705d0994171f17fda00ee3a72d563ba764ea235f66/bitarray-3.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a0e498563e0eefa96a1b92461d083de11256f6510b7706d5f2e6473cd9b7137a", size = 141191, upload-time = "2025-05-21T16:18:45.436Z" }, - { url = "https://files.pythonhosted.org/packages/81/c3/1d9ce4d0041c10ce90d924b8cea63afdda84a64623179045c0c67998922c/bitarray-3.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:114870ab71a0ebdac211aa0a120a54206c333b74b99fdf4b58fbe904979e1fef", size = 138158, upload-time = "2025-05-21T16:18:46.685Z" }, - { url = "https://files.pythonhosted.org/packages/5d/dd/a8653dac671ba97b1c68ee73b08a0eb2042f24e5e31f51b86afc09588c06/bitarray-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fbf6121978cba4313c31f7cc5961e481242def2b8ddfea34ca27ba9da52c9c1", size = 315834, upload-time = "2025-05-21T16:18:47.926Z" }, - { url = "https://files.pythonhosted.org/packages/3d/a2/30547bea0a35f9f953e99f5157749d56304d3f3a96b01a982dd604a9dc48/bitarray-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:423bb4e1bec0bc5d63969e12bcc5cc0081cc5aec4d7b62a6cd8240342aa36107", size = 331317, upload-time = "2025-05-21T16:18:49.169Z" }, - { url = "https://files.pythonhosted.org/packages/2d/b9/1789476280f46455a9a30bcd252fda6fd995583d97d1b919ec0296393e2a/bitarray-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ef80a96487c82477e8def69a58a218491794f7989b3e191cbaaa7b450315a5c", size = 324416, upload-time = "2025-05-21T16:18:50.917Z" }, - { url = "https://files.pythonhosted.org/packages/84/89/519c829ca641a3e7b8c9be56d177aaa05572b7e15e4298df4a77959b6a1e/bitarray-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35f5c69a79047e50bc1d54a777541b0a86b213e23559b1ac3d76fa9a42cc5522", size = 317634, upload-time = "2025-05-21T16:18:52.718Z" }, - { url = "https://files.pythonhosted.org/packages/0d/39/ebb6a6539261279c0994836b40b99384fa5e27ec239e70b203e310343f80/bitarray-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:002f7b128ed9d18d3ecb51ca78aeea5afffbe8e80d6be4ff2984d045b1c4b937", size = 305392, upload-time = "2025-05-21T16:18:54.888Z" }, - { url = "https://files.pythonhosted.org/packages/83/04/0ee0d57b2a60fdf881346f196fd92b824f44f4736026da1d8c7970745266/bitarray-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:999bccc72704afcf4a3d9868db4d149c032cdf910f9f7d91e30166978530af7f", size = 309740, upload-time = "2025-05-21T16:18:56.76Z" }, - { url = "https://files.pythonhosted.org/packages/f6/39/5ab0339e93097f2a2631ea281a6386c31707011499d5cf68b4e0e37ba124/bitarray-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2e44cfe2bc161cde3b11604f279e3048ef7bd3413837aadbd2ca30b5233c82cb", size = 301607, upload-time = "2025-05-21T16:18:58.144Z" }, - { url = "https://files.pythonhosted.org/packages/e8/bb/b8f697ba6a16c1e393afe75029d069e2dd457e62b112c3cb26768d2e65eb/bitarray-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f408ba3e6f706a0eabae405d1906ceb539f34a318562a91ab9799c5e1712e18c", size = 325942, upload-time = "2025-05-21T16:18:59.471Z" }, - { url = "https://files.pythonhosted.org/packages/64/ec/77d866a96909c09c5a34f1716f015386f9d9bbbf4b5dc7219f642b8043e2/bitarray-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bf94513ae559b2525e6218e41b03790f866d75df5404490420f2c25e42cf55e7", size = 329491, upload-time = "2025-05-21T16:19:01.205Z" }, - { url = "https://files.pythonhosted.org/packages/37/6e/633b7d392a39df655c92035da9ee52f7332bb165ae72038692a33a6def6c/bitarray-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f2c88c792815d2755c49a3a1fca256e142c4adfadf1a2142b5a3a37e4d4b871", size = 309566, upload-time = "2025-05-21T16:19:02.762Z" }, - { url = "https://files.pythonhosted.org/packages/ab/38/9d7ad6eca72e09b81097176dd66eed3aeaabdea4c24cf6ce25609599ce7b/bitarray-3.4.2-cp312-cp312-win32.whl", hash = "sha256:f4dac6b942c4d7ae5f6eb555ee3993de1432bf9c8f46e3caf74b6671ac5571a3", size = 134600, upload-time = "2025-05-21T16:19:04.057Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d3/c83ec3d912be73861a064f1a705436f270b8c5b5926350a875bd6c06b6df/bitarray-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:6c37e6814633041307f0df281651a86372b0ccdb1e4768247a87e83e2b68f9b9", size = 141844, upload-time = "2025-05-21T16:19:05.254Z" }, - { url = "https://files.pythonhosted.org/packages/f2/22/973d377477e1f27cf64f9e3292343219577136e32665a52667589380100d/bitarray-3.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:16263bdbb05ce379e7b8e9a9f3e0a61a9204a06a037bbc91322d2939b3079fd5", size = 141162, upload-time = "2025-05-21T16:19:06.488Z" }, - { url = "https://files.pythonhosted.org/packages/eb/53/65541b94fb6df1e8aa9a7359ac68f469c3243d8bc7302c5fb8ff8936dab2/bitarray-3.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:41fdc6fb8c3aabfcfe0073302c69fef0c74d6499491f133ba58755c3f2afb3d0", size = 138162, upload-time = "2025-05-21T16:19:07.688Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b2/83d587965f7969a5016a5bf5c9295a0651a34b668df41fa089d7c924ac08/bitarray-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c2571337b11c69206e339170516f3e72b4ec16250876c4f2bbb6e82b9caa15", size = 315760, upload-time = "2025-05-21T16:19:09.834Z" }, - { url = "https://files.pythonhosted.org/packages/4f/f5/2b2924181809debdb644143aa33d16facdce5763d5ff17e5301ecdaf89dc/bitarray-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0e3d5f37217dde9b206418c37c4d86e173f072a892670e9714e6bb20b228e95", size = 331250, upload-time = "2025-05-21T16:19:11.449Z" }, - { url = "https://files.pythonhosted.org/packages/00/2b/8ed4eeb947e05ef54614feff4cc4badd03e29ec35d46aa0218513cc9f8ac/bitarray-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83202735f21fc781f27228daeae94b6c7df1a9f673b9dd6a1c0b3764d92b8e50", size = 324299, upload-time = "2025-05-21T16:19:13.236Z" }, - { url = "https://files.pythonhosted.org/packages/05/27/d7f1b15c079cbeffad76f97c41c27635873be4d5600f6896b2bbc4f5caff/bitarray-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b3f8c35812d85a299d6c0ff097f93e18dfb7a324c129e20a4ec0ecfc4ba995", size = 317522, upload-time = "2025-05-21T16:19:14.832Z" }, - { url = "https://files.pythonhosted.org/packages/a5/db/e6a857a23222360dbc0b0d177e6060ecd88d63a1d6a3c2b52333c21a9683/bitarray-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef3f2e8ba5d6e0f38b57960d1bfb72aa9e2115f7cdca48561fadced652798d49", size = 305290, upload-time = "2025-05-21T16:19:16.57Z" }, - { url = "https://files.pythonhosted.org/packages/16/12/3b945e415233889c57c26f95a9a6a245da546e2c8d1de09991332cb796ff/bitarray-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:508ec6547bdd9f0c435c322fbb127a3dfd74c943a6c7f77fa5dfcb3e9ce1de66", size = 309764, upload-time = "2025-05-21T16:19:18.34Z" }, - { url = "https://files.pythonhosted.org/packages/6c/0e/9effb83e23ef5495c9078bdbac948df4fe2b202fb0ac5b33412848ab4b1e/bitarray-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1a3a08cc920f601258ea33d97b4454cd7cb04d17930e0a3bc7328ba3d732f8b0", size = 301690, upload-time = "2025-05-21T16:19:19.694Z" }, - { url = "https://files.pythonhosted.org/packages/cb/67/9a73476c8cd6a67ff5ab9c5c1d916307e4fb9178d76ee2781552451c995c/bitarray-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:60189130ae1ebaadbab27e3ad0a7d7ed44f5d9456bbfae07c72138501ce59053", size = 326049, upload-time = "2025-05-21T16:19:21.371Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b1/2a81f5f96c1ccc033d8c63b4584aedbd9e27499cf2276fc70d4f87ad673b/bitarray-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9e425eaf21a8d7b76531630029441c6d61f6064cbf4dd592af1607c79eb2e4d0", size = 329565, upload-time = "2025-05-21T16:19:22.88Z" }, - { url = "https://files.pythonhosted.org/packages/2e/30/670efe7771944b4b7d0aacdc076969adc9428c9d0939ee70230bdf4c8aed/bitarray-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:952cc40c593f663ba083be76d1ccdb6dc9dafab8fb6d949056405636b2e720f3", size = 309661, upload-time = "2025-05-21T16:19:24.574Z" }, - { url = "https://files.pythonhosted.org/packages/ee/2e/b2d8e842fe484d7d18fcd137289e396c7784b8484e0ec7e94ffe4bb7e8f9/bitarray-3.4.2-cp313-cp313-win32.whl", hash = "sha256:158f6b1a315eaf971f88e66f9b93431c3b580b46d2121c6a1166e7b761408fdf", size = 134614, upload-time = "2025-05-21T16:19:25.914Z" }, - { url = "https://files.pythonhosted.org/packages/0c/50/0ec25a51197410a66146eea7950e3597baedb000f2f2e2458bb6d5306b0a/bitarray-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:2d24658ac96a82beb4da2f5c71bef9790f3dcabadbe8ead8dda742ab207fe2f9", size = 141851, upload-time = "2025-05-21T16:19:27.388Z" }, - { url = "https://files.pythonhosted.org/packages/e7/03/77eca3d93f162c0982f370e6459d1fcb6ff51e84f80adb34c43256653bda/bitarray-3.4.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9c02f3234b1ec391aa235b265a3649e8078d814cdd6b42bc5aee267cc370b0c8", size = 135778, upload-time = "2025-05-21T16:20:58.492Z" }, - { url = "https://files.pythonhosted.org/packages/68/fd/5b148fb07e2b74e1cd17db7b940abdb1c7af6ac3a024810a5931db6e436b/bitarray-3.4.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:e19e5a35f53c0eaf4516cfa3f80de110eb831fd3d9785aa8b8f4a8a8c0d99523", size = 132826, upload-time = "2025-05-21T16:21:00.901Z" }, - { url = "https://files.pythonhosted.org/packages/e5/50/8cfb459218cd074a3af7121f6509ac55be2d6ac5a0a048b188934976f589/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f633d1e92fdc6a039b118d67f23d17b9ac4046a629bde04e178b770fe83a618f", size = 141592, upload-time = "2025-05-21T16:21:02.4Z" }, - { url = "https://files.pythonhosted.org/packages/43/c0/a70a212ecfd4256e7281456beee5330945ea09cec8fb0be3f99ed6828a08/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c08bc2ec3f15fbb3a99923ef1b16b621af45ab9d5146a06f970c0f0d7cab22ba", size = 142502, upload-time = "2025-05-21T16:21:08.366Z" }, - { url = "https://files.pythonhosted.org/packages/1e/8e/9fc84001701ef1fd7f18b0254bf08d594adaed34fe0b5770d8c032b4d53a/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eed46fa39af8440b1cff09a9805d65449583d524006efa29e5262bea9e08787e", size = 143930, upload-time = "2025-05-21T16:21:09.819Z" }, - { url = "https://files.pythonhosted.org/packages/f7/05/2f6753d75282033e66e0a9626ef4209500cd7a08aa8f92cc70fa49681cf3/bitarray-3.4.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9cf23c13c84c1559ed28bd211a6290b7326c2011f6c30c82cee052b254ac09f0", size = 140275, upload-time = "2025-05-21T16:21:11.481Z" }, -] - -[[package]] -name = "blinker" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, -] - -[[package]] -name = "certifi" -version = "2025.4.26" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9b/892a8c8af9110935e5adcbb06d9c6fe741b6bb02608c6513983048ba1a18/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd", size = 144649, upload-time = "2025-05-02T08:31:48.889Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a5/4179abd063ff6414223575e008593861d62abfc22455b5d1a44995b7c101/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6", size = 155045, upload-time = "2025-05-02T08:31:50.757Z" }, - { url = "https://files.pythonhosted.org/packages/3b/95/bc08c7dfeddd26b4be8c8287b9bb055716f31077c8b0ea1cd09553794665/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d", size = 147356, upload-time = "2025-05-02T08:31:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/7a5b635aa65284bf3eab7653e8b4151ab420ecbae918d3e359d1947b4d61/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86", size = 149471, upload-time = "2025-05-02T08:31:56.207Z" }, - { url = "https://files.pythonhosted.org/packages/ae/38/51fc6ac74251fd331a8cfdb7ec57beba8c23fd5493f1050f71c87ef77ed0/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c", size = 151317, upload-time = "2025-05-02T08:31:57.613Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/edee1e32215ee6e9e46c3e482645b46575a44a2d72c7dfd49e49f60ce6bf/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0", size = 146368, upload-time = "2025-05-02T08:31:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/26/2c/ea3e66f2b5f21fd00b2825c94cafb8c326ea6240cd80a91eb09e4a285830/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef", size = 154491, upload-time = "2025-05-02T08:32:01.219Z" }, - { url = "https://files.pythonhosted.org/packages/52/47/7be7fa972422ad062e909fd62460d45c3ef4c141805b7078dbab15904ff7/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6", size = 157695, upload-time = "2025-05-02T08:32:03.045Z" }, - { url = "https://files.pythonhosted.org/packages/2f/42/9f02c194da282b2b340f28e5fb60762de1151387a36842a92b533685c61e/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366", size = 154849, upload-time = "2025-05-02T08:32:04.651Z" }, - { url = "https://files.pythonhosted.org/packages/67/44/89cacd6628f31fb0b63201a618049be4be2a7435a31b55b5eb1c3674547a/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db", size = 150091, upload-time = "2025-05-02T08:32:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/1f/79/4b8da9f712bc079c0f16b6d67b099b0b8d808c2292c937f267d816ec5ecc/charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a", size = 98445, upload-time = "2025-05-02T08:32:08.66Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d7/96970afb4fb66497a40761cdf7bd4f6fca0fc7bafde3a84f836c1f57a926/charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509", size = 105782, upload-time = "2025-05-02T08:32:10.46Z" }, - { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" }, - { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" }, - { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" }, - { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" }, - { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" }, - { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, -] - -[[package]] -name = "ckzg" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/55/df/f6db8e83bd4594c1ea685cd37fb81d5399e55765aae16d1a8a9502598f4e/ckzg-2.1.1.tar.gz", hash = "sha256:d6b306b7ec93a24e4346aa53d07f7f75053bc0afc7398e35fa649e5f9d48fcc4", size = 1120500, upload-time = "2025-03-31T21:24:12.324Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/4b/cd25e857cdf46a752e97c530fe2582fae77c4d16c29fff5a15b7a998e2fd/ckzg-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b9825a1458219e8b4b023012b8ef027ef1f47e903f9541cbca4615f80132730", size = 116377, upload-time = "2025-03-31T21:22:26.952Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bc/5dfef36589545f797245ecacb54ed2acfa75507f63cfe12182d1277a88f1/ckzg-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2a40a3ba65cca4b52825d26829e6f7eb464aa27a9e9efb6b8b2ce183442c741", size = 100208, upload-time = "2025-03-31T21:22:28.04Z" }, - { url = "https://files.pythonhosted.org/packages/b7/52/96f0e3affbed321dc52b9b4ca13e0fb594da572d1f8edc47378fe48d8e9a/ckzg-2.1.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1d753fbe85be7c21602eddc2d40e0915e25fce10329f4f801a0002a4f886cc7", size = 174800, upload-time = "2025-03-31T21:22:29.719Z" }, - { url = "https://files.pythonhosted.org/packages/dc/21/b1bc07cc8e5ed32817e89b054e2399d38775d92ff2d55e24bf233f537c02/ckzg-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d76b50527f1d12430bf118aff6fa4051e9860eada43f29177258b8d399448ea", size = 160847, upload-time = "2025-03-31T21:22:30.973Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5a/97b173d4ff9bce798031beb12b340c4f1729eaaddd07f69f368f843db28e/ckzg-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44c8603e43c021d100f355f50189183135d1df3cbbddb8881552d57fbf421dde", size = 169712, upload-time = "2025-03-31T21:22:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/7b/52/48be78c07f362438e189e2fbea7df8543290c3ee99845442549c8dc5405b/ckzg-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:38707a638c9d715b3c30b29352b969f78d8fc10faed7db5faf517f04359895c0", size = 172942, upload-time = "2025-03-31T21:22:32.8Z" }, - { url = "https://files.pythonhosted.org/packages/13/42/3cfcd6cbdfb9030b9071d5e413a458f93883e47ad4a7d8d4c1d57608e57d/ckzg-2.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:52c4d257bdcbe822d20c5cd24c8154ec5aac33c49a8f5a19e716d9107a1c8785", size = 187707, upload-time = "2025-03-31T21:22:33.673Z" }, - { url = "https://files.pythonhosted.org/packages/eb/54/d43bc3a2de486fb8be29ffedc3ec80f5726765ee4fa78beabe2ab2440f93/ckzg-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1507f7bfb9bcf51d816db5d8d0f0ed53c8289605137820d437b69daea8333e16", size = 182505, upload-time = "2025-03-31T21:22:34.563Z" }, - { url = "https://files.pythonhosted.org/packages/21/43/5bcd2b7630732b532006572fbb8d64a29f69530c630ae4811167a2a0dc3b/ckzg-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d02eaaf4f841910133552b3a051dea53bcfe60cd98199fc4cf80b27609d8baa2", size = 98822, upload-time = "2025-03-31T21:22:35.786Z" }, - { url = "https://files.pythonhosted.org/packages/95/2c/44120b2d9dcb0246d67a1f28b9eaa625c499014d4d42561467e28eedd285/ckzg-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:465e2b71cf9dc383f66f1979269420a0da9274a3a9e98b1a4455e84927dfe491", size = 116378, upload-time = "2025-03-31T21:22:36.96Z" }, - { url = "https://files.pythonhosted.org/packages/23/88/c5b89ba9a730fee5e089be9e0c7048fb6707c1a0e4b6c30fcf725c3eef44/ckzg-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ee2f26f17a64ad0aab833d637b276f28486b82a29e34f32cf54b237b8f8ab72d", size = 100202, upload-time = "2025-03-31T21:22:37.799Z" }, - { url = "https://files.pythonhosted.org/packages/ee/11/b0a473e80346db52ad9a629bc9fd8f773c718ed78932ea3a70392306ffc3/ckzg-2.1.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99cc2c4e9fb8c62e3e0862c7f4df9142f07ba640da17fded5f6e0fd09f75909f", size = 175595, upload-time = "2025-03-31T21:22:39.013Z" }, - { url = "https://files.pythonhosted.org/packages/52/fa/17a7e125d07a96dd6dce4db7262231f7583856b2be5d5b7df59e04bfa188/ckzg-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773dd016693d74aca1f5d7982db2bad7dde2e147563aeb16a783f7e5f69c01fe", size = 161681, upload-time = "2025-03-31T21:22:40.257Z" }, - { url = "https://files.pythonhosted.org/packages/57/bd/46d6b90bf53da732f9adab7593d132a0834ed4f2f7659b4c7414d8f78d39/ckzg-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af2b2144f87ba218d8db01382a961b3ecbdde5ede4fa0d9428d35f8c8a595ba", size = 170471, upload-time = "2025-03-31T21:22:41.513Z" }, - { url = "https://files.pythonhosted.org/packages/9d/98/113c7704749d037d75f23240ffc5c46dfe8416de574b946438587835715f/ckzg-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f55e63d3f7c934a2cb53728ed1d815479e177aca8c84efe991c2920977cff6", size = 173595, upload-time = "2025-03-31T21:22:42.534Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d5/05fca6dcb5a19327be491157794eafc3d7498daf615c2ff5a5b745852945/ckzg-2.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ecb42aaa0ffa427ff14a9dde9356ba69e5ae6014650b397af55b31bdae7a9b6e", size = 188417, upload-time = "2025-03-31T21:22:43.466Z" }, - { url = "https://files.pythonhosted.org/packages/72/36/131ae2dfc82d0fdc98fae8e3bbfe71ff14265bb434b23bd07b585afc6d61/ckzg-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5a01514239f12fb1a7ad9009c20062a4496e13b09541c1a65f97e295da648c70", size = 183286, upload-time = "2025-03-31T21:22:44.732Z" }, - { url = "https://files.pythonhosted.org/packages/c5/6a/d371b27024422b25228fc11fa57b1ba7756a94cc9fb0c75da292c235fdaa/ckzg-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:6516b9684aae262c85cf7fddd8b585b8139ad20e08ec03994e219663abbb0916", size = 98819, upload-time = "2025-03-31T21:22:45.57Z" }, - { url = "https://files.pythonhosted.org/packages/93/a1/9c07513dd0ea01e5db727e67bd2660f3b300a4511281cdb8d5e04afa1cfd/ckzg-2.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c60e8903344ce98ce036f0fabacce952abb714cad4607198b2f0961c28b8aa72", size = 116421, upload-time = "2025-03-31T21:22:46.434Z" }, - { url = "https://files.pythonhosted.org/packages/27/04/b69a0dfbb2722a14c98a52973f276679151ec56a14178cb48e6f2e1697bc/ckzg-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4299149dd72448e5a8d2d1cc6cc7472c92fc9d9f00b1377f5b017c089d9cd92", size = 100216, upload-time = "2025-03-31T21:22:47.633Z" }, - { url = "https://files.pythonhosted.org/packages/2e/24/9cc850d0b8ead395ad5064de67c7c91adacaf31b6b35292ab53fbd93270b/ckzg-2.1.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:025dd31ffdcc799f3ff842570a2a6683b6c5b01567da0109c0c05d11768729c4", size = 175764, upload-time = "2025-03-31T21:22:48.768Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c1/eb13ba399082a98b932f10b230ec08e6456051c0ce3886b3f6d8548d11ab/ckzg-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b42ab8385c273f40a693657c09d2bba40cb4f4666141e263906ba2e519e80bd", size = 161885, upload-time = "2025-03-31T21:22:50.05Z" }, - { url = "https://files.pythonhosted.org/packages/57/c7/58baa64199781950c5a8c6139a46e1acff0f057a36e56769817400eb87fb/ckzg-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be3890fc1543f4fcfc0063e4baf5c036eb14bcf736dabdc6171ab017e0f1671", size = 170757, upload-time = "2025-03-31T21:22:51.282Z" }, - { url = "https://files.pythonhosted.org/packages/65/bd/4b8e1c70972c98829371b7004dc750a45268c5d3442d602e1b62f13ca867/ckzg-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b754210ded172968b201e2d7252573af6bf52d6ad127ddd13d0b9a45a51dae7b", size = 173761, upload-time = "2025-03-31T21:22:52.6Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/c3fd1002f97ba3e0c5b1d9ab2c8fb7a6f475fa9b80ed9c4fa55975501a54/ckzg-2.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2f8fda87865897a269c4e951e3826c2e814427a6cdfed6731cccfe548f12b36", size = 188666, upload-time = "2025-03-31T21:22:53.47Z" }, - { url = "https://files.pythonhosted.org/packages/e2/d9/91cf5a8169ee60c9397c975163cbca34432571f94facec5f8c0086bb47d8/ckzg-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:98e70b5923d77c7359432490145e9d1ab0bf873eb5de56ec53f4a551d7eaec79", size = 183652, upload-time = "2025-03-31T21:22:54.351Z" }, - { url = "https://files.pythonhosted.org/packages/25/d4/8c9f6b852f99926862344b29f0c59681916ccfec2ac60a85952a369e0bca/ckzg-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:42af7bde4ca45469cd93a96c3d15d69d51d40e7f0d30e3a20711ebd639465fcb", size = 98816, upload-time = "2025-03-31T21:22:55.23Z" }, - { url = "https://files.pythonhosted.org/packages/b7/9a/fa698b12e97452d11dd314e0335aae759725284ef6e1c1665aed56b1cd3e/ckzg-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e4edfdaf87825ff43b9885fabfdea408737a714f4ce5467100d9d1d0a03b673", size = 116426, upload-time = "2025-03-31T21:22:56.108Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/8cccd308bd11b49b40eecad6900b5769da117951cac33e880dd25e851ef7/ckzg-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:815fd2a87d6d6c57d669fda30c150bc9bf387d47e67d84535aa42b909fdc28ea", size = 100219, upload-time = "2025-03-31T21:22:56.982Z" }, - { url = "https://files.pythonhosted.org/packages/30/0e/63573d816c1292b9a4d70eb6a7366b3593d29a977794039e926805a76ca0/ckzg-2.1.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32466e809b1ab3ff01d3b0bb0b9912f61dcf72957885615595f75e3f7cc10e5", size = 175725, upload-time = "2025-03-31T21:22:58.213Z" }, - { url = "https://files.pythonhosted.org/packages/86/f6/a279609516695ad3fb8b201098c669ba3b2844cbf4fa0d83a0f02b9bb29b/ckzg-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f11b73ccf37b12993f39a7dbace159c6d580aacacde6ee17282848476550ddbc", size = 161835, upload-time = "2025-03-31T21:22:59.448Z" }, - { url = "https://files.pythonhosted.org/packages/39/e4/8cf7aef7dc05a777cb221e94046f947c6fe5317159a8dae2cd7090d52ef2/ckzg-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3b9433a1f2604bd9ac1646d3c83ad84a850d454d3ac589fe8e70c94b38a6b0", size = 170759, upload-time = "2025-03-31T21:23:01.022Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/b34e3c08eb36bc67e338b114f289b2595e581b8bdc09a8f12299a1db5d2f/ckzg-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b7d7e1b5ea06234558cd95c483666fd785a629b720a7f1622b3cbffebdc62033", size = 173787, upload-time = "2025-03-31T21:23:01.974Z" }, - { url = "https://files.pythonhosted.org/packages/2e/f0/aff87c3ed80713453cb6c84fe6fbb7582d86a7a5e4460fda2a497d47f489/ckzg-2.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9f5556e6675866040cc4335907be6c537051e7f668da289fa660fdd8a30c9ddb", size = 188722, upload-time = "2025-03-31T21:23:02.966Z" }, - { url = "https://files.pythonhosted.org/packages/44/d9/1f08bfb8fd1cbb8c7513e7ad3fb76bbb5c3fb446238c1eba582276e4d905/ckzg-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55b2ba30c5c9daac0c55f1aac851f1b7bf1f7aa0028c2db4440e963dd5b866d6", size = 183686, upload-time = "2025-03-31T21:23:03.905Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ff/434f6d2893cbdfad00c20d17e9a52d426ca042f5e980d5c3db96bc6b6e15/ckzg-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:10d201601fc8f28c0e8cec3406676797024dd374c367bbeec5a7a9eac9147237", size = 98817, upload-time = "2025-03-31T21:23:05.2Z" }, - { url = "https://files.pythonhosted.org/packages/30/b3/a0c7d7ba6e669cf04605dc0329173db62fc1fe3c488761755cc01e5e1b4d/ckzg-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:375918e25eafb9bafe5215ab91698504cba3fe51b4fe92f5896af6c5663f50c6", size = 113191, upload-time = "2025-03-31T21:23:40.646Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b9/a6cf403b8528d18d7d9154e28381a397bf466c86aa8e0b3327cffdde5749/ckzg-2.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:38b3b7802c76d4ad015db2b7a79a49c193babae50ee5f77e9ac2865c9e9ddb09", size = 96207, upload-time = "2025-03-31T21:23:41.596Z" }, - { url = "https://files.pythonhosted.org/packages/63/6b/5ddd713d97886becb8450e3e13db891199125f722366d30d087ad5438390/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438a5009fd254ace0bc1ad974d524547f1a41e6aa5e778c5cd41f4ee3106bcd6", size = 126160, upload-time = "2025-03-31T21:23:42.553Z" }, - { url = "https://files.pythonhosted.org/packages/c7/dd/e05aecc01e62108a7579f8df5e5d38536841f50e12172f8a84677edac0fa/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce11cc163a2e0dab3af7455aca7053f9d5bb8d157f231acc7665fd230565d48", size = 102811, upload-time = "2025-03-31T21:23:43.494Z" }, - { url = "https://files.pythonhosted.org/packages/c6/81/6cdadd8626ac11290af3f58ae5dcffe38bd2c8f8c798dacee7475e244aac/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b53964c07f6a076e97eaa1ef35045e935d7040aff14f80bae7e9105717702d05", size = 111328, upload-time = "2025-03-31T21:23:44.449Z" }, - { url = "https://files.pythonhosted.org/packages/36/b7/b129ff6955cd264c6ab3dbd52dd1b2759d1b121c09c03f9991e4c722c72f/ckzg-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cf085f15ae52ab2599c9b5a3d5842794bcf5613b7f58661fbfb0c5d9eac988b9", size = 98846, upload-time = "2025-03-31T21:23:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ba/7d9c1f9cec7e0e382653c72165896194a05743e589b1dae2aa80236aa87f/ckzg-2.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4b0c850bd6cad22ac79b2a2ab884e0e7cd2b54a67d643cd616c145ebdb535a11", size = 113188, upload-time = "2025-03-31T21:23:46.337Z" }, - { url = "https://files.pythonhosted.org/packages/2f/92/9728f5ccc1c5e87c6c5ae7941250a447b61fd5a63aadbc15249e29c21bcf/ckzg-2.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:26951f36bb60c9150bbd38110f5e1625596f9779dad54d1d492d8ec38bc84e3a", size = 96208, upload-time = "2025-03-31T21:23:47.255Z" }, - { url = "https://files.pythonhosted.org/packages/39/63/5e27d587bd224fee70cb66b022e7c4ef95d0e091e08ee76c25ec12094b0d/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbe12445e49c4bee67746b7b958e90a973b0de116d0390749b0df351d94e9a8c", size = 126158, upload-time = "2025-03-31T21:23:48.195Z" }, - { url = "https://files.pythonhosted.org/packages/43/98/e0a45946575a7b823d8ee0b47afb104b6017e54e1208f07da2529bc01900/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c5d4f66f09de4a99271acac74d2acb3559a77de77a366b34a91e99e8822667", size = 102812, upload-time = "2025-03-31T21:23:49.16Z" }, - { url = "https://files.pythonhosted.org/packages/cb/50/718ca7b03e4b89b18cdf99cc3038050105b0acbf9b612c23cd513093c6de/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42673c1d007372a4e8b48f6ef8f0ce31a9688a463317a98539757d1e2fb1ecc7", size = 111327, upload-time = "2025-03-31T21:23:50.126Z" }, - { url = "https://files.pythonhosted.org/packages/29/c5/80e5a0c6967d02d801150104320484a258e5a49bd191e198643e74039320/ckzg-2.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:57a7dc41ec6b69c1d9117eb61cf001295e6b4f67a736020442e71fb4367fb1a5", size = 98847, upload-time = "2025-03-31T21:23:51.084Z" }, -] - -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "cytoolz" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "toolz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/f9/3243eed3a6545c2a33a21f74f655e3fcb5d2192613cd3db81a93369eb339/cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6", size = 626652, upload-time = "2024-12-13T05:47:36.672Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d9/f13d66c16cff1fa1cb6c234698029877c456f35f577ef274aba3b86e7c51/cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042", size = 403515, upload-time = "2024-12-13T05:44:27.845Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2d/4cdf848a69300c7d44984f2ebbebb3b8576e5449c8dea157298f3bdc4da3/cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608", size = 383936, upload-time = "2024-12-13T05:44:29.5Z" }, - { url = "https://files.pythonhosted.org/packages/72/a4/ccfdd3f0ed9cc818f734b424261f6018fc61e3ec833bf85225a9aca0d994/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90124bdc42ff58b88cdea1d24a6bc5f776414a314cc4d94f25c88badb3a16d1", size = 1934569, upload-time = "2024-12-13T05:44:30.799Z" }, - { url = "https://files.pythonhosted.org/packages/50/fc/38d5344fa595683ad10dc819cfc1d8b9d2b3391ccf3e8cb7bab4899a01f5/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e74801b751e28f7c5cc3ad264c123954a051f546f2fdfe089f5aa7a12ccfa6da", size = 2015129, upload-time = "2024-12-13T05:44:32.297Z" }, - { url = "https://files.pythonhosted.org/packages/28/29/75261748dc54a20a927f33641f4e9aac674cfc6d3fbd4f332e10d0b37639/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582dad4545ddfb5127494ef23f3fa4855f1673a35d50c66f7638e9fb49805089", size = 2000506, upload-time = "2024-12-13T05:44:34.403Z" }, - { url = "https://files.pythonhosted.org/packages/00/ae/e4ead004cc2698281d153c4a5388638d67cdb5544d6d6cc1e5b3db2bd2a3/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7bd0618e16efe03bd12f19c2a26a27e6e6b75d7105adb7be1cd2a53fa755d8", size = 1957537, upload-time = "2024-12-13T05:44:39.499Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ff/4f3aa07f4f47701f7f63df60ce0a5669fa09c256c3d4a33503a9414ea5cc/cytoolz-1.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d74cca6acf1c4af58b2e4a89cc565ed61c5e201de2e434748c93e5a0f5c541a5", size = 1863331, upload-time = "2024-12-13T05:44:42.61Z" }, - { url = "https://files.pythonhosted.org/packages/a2/29/654f57f2a9b8e9765a4ab876765f64f94530b61fc6471a07feea42ece6d4/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:823a3763828d8d457f542b2a45d75d6b4ced5e470b5c7cf2ed66a02f508ed442", size = 1849938, upload-time = "2024-12-13T05:44:45.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/7b/11f457db6b291060a98315ab2c7198077d8bddeeebe5f7126d9dad98cc54/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:51633a14e6844c61db1d68c1ffd077cf949f5c99c60ed5f1e265b9e2966f1b52", size = 1852345, upload-time = "2024-12-13T05:44:47.994Z" }, - { url = "https://files.pythonhosted.org/packages/6b/92/0dccc96ce0323be236d404f5084479b79b747fa0e74e43a270e95868b5f9/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3ec9b01c45348f1d0d712507d54c2bfd69c62fbd7c9ef555c9d8298693c2432", size = 1989877, upload-time = "2024-12-13T05:44:51.514Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c8/1c5203a81200bae51aa8f7b5fad613f695bf1afa03f16251ca23ecb2ef9f/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1855022b712a9c7a5bce354517ab4727a38095f81e2d23d3eabaf1daeb6a3b3c", size = 1994492, upload-time = "2024-12-13T05:44:52.922Z" }, - { url = "https://files.pythonhosted.org/packages/e2/8a/04bc193c4d7ced8ef6bb62cdcd0bf40b5e5eb26586ed2cfb4433ec7dfd0a/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9930f7288c4866a1dc1cc87174f0c6ff4cad1671eb1f6306808aa6c445857d78", size = 1896077, upload-time = "2024-12-13T05:44:56.118Z" }, - { url = "https://files.pythonhosted.org/packages/21/a5/bee63a58f51d2c74856db66e6119a014464ff8cb1c9387fa4bd2d94e49b0/cytoolz-1.0.1-cp310-cp310-win32.whl", hash = "sha256:a9baad795d72fadc3445ccd0f122abfdbdf94269157e6d6d4835636dad318804", size = 322135, upload-time = "2024-12-13T05:44:57.695Z" }, - { url = "https://files.pythonhosted.org/packages/e8/16/7abfb1685e8b7f2838264551ee33651748994813f566ac4c3d737dfe90e5/cytoolz-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad95b386a84e18e1f6136f6d343d2509d4c3aae9f5a536f3dc96808fcc56a8cf", size = 363599, upload-time = "2024-12-13T05:44:58.875Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ea/8131ae39119820b8867cddc23716fa9f681f2b3bbce6f693e68dfb36b55b/cytoolz-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d958d4f04d9d7018e5c1850790d9d8e68b31c9a2deebca74b903706fdddd2b6", size = 406162, upload-time = "2024-12-13T05:45:01.196Z" }, - { url = "https://files.pythonhosted.org/packages/26/18/3d9bd4c146f6ea6e51300c242b20cb416966b21d481dac230e1304f1e54b/cytoolz-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0f445b8b731fc0ecb1865b8e68a070084eb95d735d04f5b6c851db2daf3048ab", size = 384961, upload-time = "2024-12-13T05:45:02.387Z" }, - { url = "https://files.pythonhosted.org/packages/e4/73/9034827907c7f85c7c484c9494e905d022fb8174526004e9ef332570349e/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f546a96460a7e28eb2ec439f4664fa646c9b3e51c6ebad9a59d3922bbe65e30", size = 2091698, upload-time = "2024-12-13T05:45:04.353Z" }, - { url = "https://files.pythonhosted.org/packages/74/af/d5c2733b0fde1a08254ff1a8a8d567874040c9eb1606363cfebc0713c73f/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0317681dd065532d21836f860b0563b199ee716f55d0c1f10de3ce7100c78a3b", size = 2188452, upload-time = "2024-12-13T05:45:05.748Z" }, - { url = "https://files.pythonhosted.org/packages/6a/bb/77c71fa9c217260b4056a732d754748903423c2cdd82a673d6064741e375/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0ef52febd5a7821a3fd8d10f21d460d1a3d2992f724ba9c91fbd7a96745d41", size = 2174203, upload-time = "2024-12-13T05:45:07.777Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a9/a5b4a3ff5d22faa1b60293bfe97362e2caf4a830c26d37ab5557f60d04b2/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebaf419acf2de73b643cf96108702b8aef8e825cf4f63209ceb078d5fbbbfd", size = 2099831, upload-time = "2024-12-13T05:45:11.477Z" }, - { url = "https://files.pythonhosted.org/packages/35/08/7f6869ea1ff31ce5289a7d58d0e7090acfe7058baa2764473048ff61ea3c/cytoolz-1.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f7f04eeb4088947585c92d6185a618b25ad4a0f8f66ea30c8db83cf94a425e3", size = 1996744, upload-time = "2024-12-13T05:45:14.172Z" }, - { url = "https://files.pythonhosted.org/packages/46/b4/9ac424c994b51763fd1bbed62d95f8fba8fa0e45c8c3c583904fdaf8f51d/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f61928803bb501c17914b82d457c6f50fe838b173fb40d39c38d5961185bd6c7", size = 2013733, upload-time = "2024-12-13T05:45:16.912Z" }, - { url = "https://files.pythonhosted.org/packages/3e/99/03009765c4b87d742d5b5a8670abb56a8c7ede033c2cdaa4be8662d3b001/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d2960cb4fa01ccb985ad1280db41f90dc97a80b397af970a15d5a5de403c8c61", size = 1994850, upload-time = "2024-12-13T05:45:18.414Z" }, - { url = "https://files.pythonhosted.org/packages/40/9a/8458af9a5557e177ea42f8cf7e477bede518b0bbef564e28c4151feaa52c/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2b407cc3e9defa8df5eb46644f6f136586f70ba49eba96f43de67b9a0984fd3", size = 2155352, upload-time = "2024-12-13T05:45:19.763Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5c/2a701423e001fcbec288b4f3fc2bf67557d114c2388237fc1ae67e1e2686/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8245f929144d4d3bd7b972c9593300195c6cea246b81b4c46053c48b3f044580", size = 2163515, upload-time = "2024-12-13T05:45:21.08Z" }, - { url = "https://files.pythonhosted.org/packages/36/16/ee2e06e65d9d533bc05cd52a0b355ba9072fc8f60d77289e529c6d2e3750/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37385db03af65763933befe89fa70faf25301effc3b0485fec1c15d4ce4f052", size = 2054431, upload-time = "2024-12-13T05:45:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d5/2fac8315f210fa1bc7106e27c19e1211580aa25bb7fa17dfd79505e5baf2/cytoolz-1.0.1-cp311-cp311-win32.whl", hash = "sha256:50f9c530f83e3e574fc95c264c3350adde8145f4f8fc8099f65f00cc595e5ead", size = 322004, upload-time = "2024-12-13T05:45:24.048Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9e/0b70b641850a95f9ff90adde9d094a4b1d81ec54dadfd97fec0a2aaf440e/cytoolz-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b7f6b617454b4326af7bd3c7c49b0fc80767f134eb9fd6449917a058d17a0e3c", size = 365358, upload-time = "2024-12-13T05:45:25.383Z" }, - { url = "https://files.pythonhosted.org/packages/d8/e8/218098344ed2cb5f8441fade9b2428e435e7073962374a9c71e59ac141a7/cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4", size = 414121, upload-time = "2024-12-13T05:45:26.588Z" }, - { url = "https://files.pythonhosted.org/packages/de/27/4d729a5653718109262b758fec1a959aa9facb74c15460d9074dc76d6635/cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662", size = 390904, upload-time = "2024-12-13T05:45:27.718Z" }, - { url = "https://files.pythonhosted.org/packages/72/c0/cbabfa788bab9c6038953bf9478adaec06e88903a726946ea7c88092f5c4/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3", size = 2090734, upload-time = "2024-12-13T05:45:30.515Z" }, - { url = "https://files.pythonhosted.org/packages/c3/66/369262c60f9423c2da82a60864a259c852f1aa122aced4acd2c679af58c0/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1", size = 2155933, upload-time = "2024-12-13T05:45:32.721Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4e/ee55186802f8d24b5fbf9a11405ccd1203b30eded07cc17750618219b94e/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8", size = 2171903, upload-time = "2024-12-13T05:45:34.205Z" }, - { url = "https://files.pythonhosted.org/packages/a1/96/bd1a9f3396e9b7f618db8cd08d15630769ce3c8b7d0534f92cd639c977ae/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d", size = 2125270, upload-time = "2024-12-13T05:45:36.982Z" }, - { url = "https://files.pythonhosted.org/packages/28/48/2a3762873091c88a69e161111cfbc6c222ff145d57ff011a642b169f04f1/cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f", size = 1973967, upload-time = "2024-12-13T05:45:39.505Z" }, - { url = "https://files.pythonhosted.org/packages/e4/50/500bd69774bdc49a4d78ec8779eb6ac7c1a9d706bfd91cf2a1dba604373a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7", size = 2021695, upload-time = "2024-12-13T05:45:40.911Z" }, - { url = "https://files.pythonhosted.org/packages/e4/4e/ba5a0ce34869495eb50653de8d676847490cf13a2cac1760fc4d313e78de/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126", size = 2010177, upload-time = "2024-12-13T05:45:42.48Z" }, - { url = "https://files.pythonhosted.org/packages/87/57/615c630b3089a13adb15351d958d227430cf624f03b1dd39eb52c34c1f59/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0", size = 2154321, upload-time = "2024-12-13T05:45:43.979Z" }, - { url = "https://files.pythonhosted.org/packages/7f/0f/fe1aa2d931e3b35ecc05215bd75da945ea7346095b3b6f6027164e602d5a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b", size = 2188374, upload-time = "2024-12-13T05:45:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/de/fa/fd363d97a641b6d0e2fd1d5c35b8fd41d9ccaeb4df56302f53bf23a58e3a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d", size = 2077911, upload-time = "2024-12-13T05:45:48.219Z" }, - { url = "https://files.pythonhosted.org/packages/d9/68/0a22946b98ae5201b54ccb4e651295285c0fb79406022b6ee8b2f791940c/cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9", size = 321903, upload-time = "2024-12-13T05:45:50.3Z" }, - { url = "https://files.pythonhosted.org/packages/62/1a/f3903197956055032f8cb297342e2dff07e50f83991aebfe5b4c4fcb55e4/cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b", size = 364490, upload-time = "2024-12-13T05:45:51.494Z" }, - { url = "https://files.pythonhosted.org/packages/aa/2e/a9f069db0107749e9e72baf6c21abe3f006841a3bcfdc9b8420e22ef31eb/cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0", size = 407365, upload-time = "2024-12-13T05:45:52.803Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9b/5e87dd0e31f54c778b4f9f34cc14c1162d3096c8d746b0f8be97d70dd73c/cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a", size = 385233, upload-time = "2024-12-13T05:45:53.994Z" }, - { url = "https://files.pythonhosted.org/packages/63/00/2fd32b16284cdb97cfe092822179bc0c3bcdd5e927dd39f986169a517642/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242", size = 2062903, upload-time = "2024-12-13T05:45:55.202Z" }, - { url = "https://files.pythonhosted.org/packages/85/39/b3cbb5a9847ba59584a263772ad4f8ca2dbfd2a0e11efd09211d1219804c/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296", size = 2139517, upload-time = "2024-12-13T05:45:56.804Z" }, - { url = "https://files.pythonhosted.org/packages/ea/39/bfcab4a46d50c467e36fe704f19d8904efead417787806ee210327f68390/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b", size = 2154849, upload-time = "2024-12-13T05:45:58.814Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/3bc6ee61b0aa47e1cb40819adc1a456d7efa809f0dea9faddacb43fdde8f/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b", size = 2102302, upload-time = "2024-12-13T05:46:00.181Z" }, - { url = "https://files.pythonhosted.org/packages/00/66/3f636c6ddea7b18026b90a8c238af472e423b86e427b11df02213689b012/cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266", size = 1960872, upload-time = "2024-12-13T05:46:01.612Z" }, - { url = "https://files.pythonhosted.org/packages/40/36/cb3b7cdd651007b69f9c48e9d104cec7cb8dc53afa1d6a720e5ad08022fa/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5", size = 2014430, upload-time = "2024-12-13T05:46:03.022Z" }, - { url = "https://files.pythonhosted.org/packages/88/3f/2e9bd2a16cfd269808922147551dcb2d8b68ba54a2c4deca2fa6a6cd0d5f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3", size = 2003127, upload-time = "2024-12-13T05:46:04.401Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7d/08604ff940aa784df8343c387fdf2489b948b714a6afb587775ae94da912/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296", size = 2142369, upload-time = "2024-12-13T05:46:06.004Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c6/39919a0645bdbdf720e97cae107f959ea9d1267fbc3b0d94fc6e1d12ac8f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140", size = 2180427, upload-time = "2024-12-13T05:46:07.526Z" }, - { url = "https://files.pythonhosted.org/packages/d8/03/dbb9d47556ee54337e7e0ac209d17ceff2d2a197c34de08005abc7a7449b/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581", size = 2069785, upload-time = "2024-12-13T05:46:10.122Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f8/11bb7b8947002231faae3ec2342df5896afbc19eb783a332cce6d219ff79/cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9", size = 320685, upload-time = "2024-12-13T05:46:11.553Z" }, - { url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297", size = 362898, upload-time = "2024-12-13T05:46:12.771Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f7/ef2a10daaec5c0f7d781d50758c6187eee484256e356ae8ef178d6c48497/cytoolz-1.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:83d19d55738ad9c60763b94f3f6d3c6e4de979aeb8d76841c1401081e0e58d96", size = 345702, upload-time = "2024-12-13T05:47:09.266Z" }, - { url = "https://files.pythonhosted.org/packages/c8/14/53c84adddedb67ff1546abb86fea04d26e24298c3ceab8436d20122ed0b9/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f112a71fad6ea824578e6393765ce5c054603afe1471a5c753ff6c67fd872d10", size = 385695, upload-time = "2024-12-13T05:47:11.011Z" }, - { url = "https://files.pythonhosted.org/packages/bd/80/3ae356c5e7b8d7dc7d1adb52f6932fee85cd748ed4e1217c269d2dfd610f/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a515df8f8aa6e1eaaf397761a6e4aff2eef73b5f920aedf271416d5471ae5ee", size = 406261, upload-time = "2024-12-13T05:47:12.24Z" }, - { url = "https://files.pythonhosted.org/packages/0c/31/8e43761ffc82d90bf9cab7e0959712eedcd1e33c211397e143dd42d7af57/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c398e7b7023460bea2edffe5fcd0a76029580f06c3f6938ac3d198b47156f3", size = 397207, upload-time = "2024-12-13T05:47:13.561Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b9/fe9da37090b6444c65f848a83e390f87d8cb43d6a4df46de1556ad7e5ceb/cytoolz-1.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3237e56211e03b13df47435b2369f5df281e02b04ad80a948ebd199b7bc10a47", size = 343358, upload-time = "2024-12-13T05:47:16.291Z" }, -] - -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - -[[package]] -name = "email-validator" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, -] - -[[package]] -name = "eth-abi" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "parsimonious" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/71/d9e1380bd77fd22f98b534699af564f189b56d539cc2b9dab908d4e4c242/eth_abi-5.2.0.tar.gz", hash = "sha256:178703fa98c07d8eecd5ae569e7e8d159e493ebb6eeb534a8fe973fbc4e40ef0", size = 49797, upload-time = "2025-01-14T16:29:34.629Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/b4/2f3982c4cbcbf5eeb6aec62df1533c0e63c653b3021ff338d44944405676/eth_abi-5.2.0-py3-none-any.whl", hash = "sha256:17abe47560ad753f18054f5b3089fcb588f3e3a092136a416b6c1502cb7e8877", size = 28511, upload-time = "2025-01-14T16:29:31.862Z" }, -] - -[[package]] -name = "eth-account" -version = "0.13.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bitarray" }, - { name = "ckzg" }, - { name = "eth-abi" }, - { name = "eth-keyfile" }, - { name = "eth-keys" }, - { name = "eth-rlp" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "rlp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/cf/20f76a29be97339c969fd765f1237154286a565a1d61be98e76bb7af946a/eth_account-0.13.7.tar.gz", hash = "sha256:5853ecbcbb22e65411176f121f5f24b8afeeaf13492359d254b16d8b18c77a46", size = 935998, upload-time = "2025-04-21T21:11:21.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/18/088fb250018cbe665bc2111974301b2d59f294a565aff7564c4df6878da2/eth_account-0.13.7-py3-none-any.whl", hash = "sha256:39727de8c94d004ff61d10da7587509c04d2dc7eac71e04830135300bdfc6d24", size = 587452, upload-time = "2025-04-21T21:11:18.346Z" }, -] - -[[package]] -name = "eth-hash" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/38/577b7bc9380ef9dff0f1dffefe0c9a1ded2385e7a06c306fd95afb6f9451/eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5", size = 12227, upload-time = "2025-01-13T21:29:21.765Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/db/f8775490669d28aca24871c67dd56b3e72105cb3bcae9a4ec65dd70859b3/eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a", size = 8028, upload-time = "2025-01-13T21:29:19.365Z" }, -] - -[package.optional-dependencies] -pycryptodome = [ - { name = "pycryptodome" }, -] - -[[package]] -name = "eth-keyfile" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-keys" }, - { name = "eth-utils" }, - { name = "pycryptodome" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/66/dd823b1537befefbbff602e2ada88f1477c5b40ec3731e3d9bc676c5f716/eth_keyfile-0.8.1.tar.gz", hash = "sha256:9708bc31f386b52cca0969238ff35b1ac72bd7a7186f2a84b86110d3c973bec1", size = 12267, upload-time = "2024-04-23T20:28:53.862Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/fc/48a586175f847dd9e05e5b8994d2fe8336098781ec2e9836a2ad94280281/eth_keyfile-0.8.1-py3-none-any.whl", hash = "sha256:65387378b82fe7e86d7cb9f8d98e6d639142661b2f6f490629da09fddbef6d64", size = 7510, upload-time = "2024-04-23T20:28:51.063Z" }, -] - -[[package]] -name = "eth-keys" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/11/1ed831c50bd74f57829aa06e58bd82a809c37e070ee501c953b9ac1f1552/eth_keys-0.7.0.tar.gz", hash = "sha256:79d24fd876201df67741de3e3fefb3f4dbcbb6ace66e47e6fe662851a4547814", size = 30166, upload-time = "2025-04-07T17:40:21.697Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/25/0ae00f2b0095e559d61ad3dc32171bd5a29dfd95ab04b4edd641f7c75f72/eth_keys-0.7.0-py3-none-any.whl", hash = "sha256:b0cdda8ffe8e5ba69c7c5ca33f153828edcace844f67aabd4542d7de38b159cf", size = 20656, upload-time = "2025-04-07T17:40:20.441Z" }, -] - -[[package]] -name = "eth-rlp" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "rlp" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7f/ea/ad39d001fa9fed07fad66edb00af701e29b48be0ed44a3bcf58cb3adf130/eth_rlp-2.2.0.tar.gz", hash = "sha256:5e4b2eb1b8213e303d6a232dfe35ab8c29e2d3051b86e8d359def80cd21db83d", size = 7720, upload-time = "2025-02-04T21:51:08.134Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/3b/57efe2bc2df0980680d57c01a36516cd3171d2319ceb30e675de19fc2cc5/eth_rlp-2.2.0-py3-none-any.whl", hash = "sha256:5692d595a741fbaef1203db6a2fedffbd2506d31455a6ad378c8449ee5985c47", size = 4446, upload-time = "2025-02-04T21:51:05.823Z" }, -] - -[[package]] -name = "eth-typing" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/54/62aa24b9cc708f06316167ee71c362779c8ed21fc8234a5cd94a8f53b623/eth_typing-5.2.1.tar.gz", hash = "sha256:7557300dbf02a93c70fa44af352b5c4a58f94e997a0fd6797fb7d1c29d9538ee", size = 21806, upload-time = "2025-04-14T20:39:28.217Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/72/c370bbe4c53da7bf998d3523f5a0f38867654923a82192df88d0705013d3/eth_typing-5.2.1-py3-none-any.whl", hash = "sha256:b0c2812ff978267563b80e9d701f487dd926f1d376d674f3b535cfe28b665d3d", size = 19163, upload-time = "2025-04-14T20:39:26.571Z" }, -] - -[[package]] -name = "eth-utils" -version = "5.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cytoolz", marker = "implementation_name == 'cpython'" }, - { name = "eth-hash" }, - { name = "eth-typing" }, - { name = "pydantic" }, - { name = "toolz", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0d/49/bee95f16d2ef068097afeeffbd6c67738107001ee57ad7bcdd4fc4d3c6a7/eth_utils-5.3.0.tar.gz", hash = "sha256:1f096867ac6be895f456fa3acb26e9573ae66e753abad9208f316d24d6178156", size = 123753, upload-time = "2025-04-14T19:35:56.431Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/c6/0417a92e6a3fc9b85f5a8380d9f9d43b69ba836a90e45f79f9ae74d41e53/eth_utils-5.3.0-py3-none-any.whl", hash = "sha256:ac184883ab299d923428bbe25dae5e356979a3993e0ef695a864db0a20bc262d", size = 102531, upload-time = "2025-04-14T19:35:55.176Z" }, -] - -[[package]] -name = "exceptiongroup" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, -] - -[[package]] -name = "fastapi" -version = "0.115.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236, upload-time = "2025-03-23T22:55:43.822Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164, upload-time = "2025-03-23T22:55:42.101Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, - { name = "httpx" }, - { name = "jinja2" }, - { name = "python-multipart" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cli" -version = "0.0.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "rich-toolkit" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/73/82a5831fbbf8ed75905bacf5b2d9d3dfd6f04d6968b29fe6f72a5ae9ceb1/fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e", size = 16753, upload-time = "2024-12-15T14:28:10.028Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705, upload-time = "2024-12-15T14:28:06.18Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "flask" -version = "3.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "blinker" }, - { name = "click" }, - { name = "itsdangerous" }, - { name = "jinja2" }, - { name = "markupsafe" }, - { name = "werkzeug" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/de/e47735752347f4128bcf354e0da07ef311a78244eba9e3dc1d4a5ab21a98/flask-3.1.1.tar.gz", hash = "sha256:284c7b8f2f58cb737f0cf1c30fd7eaf0ccfcde196099d24ecede3fc2005aa59e", size = 753440, upload-time = "2025-05-13T15:01:17.447Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl", hash = "sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c", size = 103305, upload-time = "2025-05-13T15:01:15.591Z" }, -] - -[[package]] -name = "frozenlist" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, - { url = "https://files.pythonhosted.org/packages/77/f0/77c11d13d39513b298e267b22eb6cb559c103d56f155aa9a49097221f0b6/frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61", size = 47735, upload-time = "2025-06-09T22:59:48.133Z" }, - { url = "https://files.pythonhosted.org/packages/37/12/9d07fa18971a44150593de56b2f2947c46604819976784bcf6ea0d5db43b/frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d", size = 46775, upload-time = "2025-06-09T22:59:49.564Z" }, - { url = "https://files.pythonhosted.org/packages/70/34/f73539227e06288fcd1f8a76853e755b2b48bca6747e99e283111c18bcd4/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e", size = 224644, upload-time = "2025-06-09T22:59:51.35Z" }, - { url = "https://files.pythonhosted.org/packages/fb/68/c1d9c2f4a6e438e14613bad0f2973567586610cc22dcb1e1241da71de9d3/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9", size = 222125, upload-time = "2025-06-09T22:59:52.884Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d0/98e8f9a515228d708344d7c6986752be3e3192d1795f748c24bcf154ad99/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c", size = 233455, upload-time = "2025-06-09T22:59:54.74Z" }, - { url = "https://files.pythonhosted.org/packages/79/df/8a11bcec5600557f40338407d3e5bea80376ed1c01a6c0910fcfdc4b8993/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981", size = 227339, upload-time = "2025-06-09T22:59:56.187Z" }, - { url = "https://files.pythonhosted.org/packages/50/82/41cb97d9c9a5ff94438c63cc343eb7980dac4187eb625a51bdfdb7707314/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615", size = 212969, upload-time = "2025-06-09T22:59:57.604Z" }, - { url = "https://files.pythonhosted.org/packages/13/47/f9179ee5ee4f55629e4f28c660b3fdf2775c8bfde8f9c53f2de2d93f52a9/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50", size = 222862, upload-time = "2025-06-09T22:59:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/df81e41ec6b953902c8b7e3a83bee48b195cb0e5ec2eabae5d8330c78038/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa", size = 222492, upload-time = "2025-06-09T23:00:01.026Z" }, - { url = "https://files.pythonhosted.org/packages/84/17/30d6ea87fa95a9408245a948604b82c1a4b8b3e153cea596421a2aef2754/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577", size = 238250, upload-time = "2025-06-09T23:00:03.401Z" }, - { url = "https://files.pythonhosted.org/packages/8f/00/ecbeb51669e3c3df76cf2ddd66ae3e48345ec213a55e3887d216eb4fbab3/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59", size = 218720, upload-time = "2025-06-09T23:00:05.282Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c0/c224ce0e0eb31cc57f67742071bb470ba8246623c1823a7530be0e76164c/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e", size = 232585, upload-time = "2025-06-09T23:00:07.962Z" }, - { url = "https://files.pythonhosted.org/packages/55/3c/34cb694abf532f31f365106deebdeac9e45c19304d83cf7d51ebbb4ca4d1/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd", size = 234248, upload-time = "2025-06-09T23:00:09.428Z" }, - { url = "https://files.pythonhosted.org/packages/98/c0/2052d8b6cecda2e70bd81299e3512fa332abb6dcd2969b9c80dfcdddbf75/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718", size = 221621, upload-time = "2025-06-09T23:00:11.32Z" }, - { url = "https://files.pythonhosted.org/packages/c5/bf/7dcebae315436903b1d98ffb791a09d674c88480c158aa171958a3ac07f0/frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e", size = 39578, upload-time = "2025-06-09T23:00:13.526Z" }, - { url = "https://files.pythonhosted.org/packages/8f/5f/f69818f017fa9a3d24d1ae39763e29b7f60a59e46d5f91b9c6b21622f4cd/frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464", size = 43830, upload-time = "2025-06-09T23:00:14.98Z" }, - { url = "https://files.pythonhosted.org/packages/34/7e/803dde33760128acd393a27eb002f2020ddb8d99d30a44bfbaab31c5f08a/frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a", size = 82251, upload-time = "2025-06-09T23:00:16.279Z" }, - { url = "https://files.pythonhosted.org/packages/75/a9/9c2c5760b6ba45eae11334db454c189d43d34a4c0b489feb2175e5e64277/frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750", size = 48183, upload-time = "2025-06-09T23:00:17.698Z" }, - { url = "https://files.pythonhosted.org/packages/47/be/4038e2d869f8a2da165f35a6befb9158c259819be22eeaf9c9a8f6a87771/frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd", size = 47107, upload-time = "2025-06-09T23:00:18.952Z" }, - { url = "https://files.pythonhosted.org/packages/79/26/85314b8a83187c76a37183ceed886381a5f992975786f883472fcb6dc5f2/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2", size = 237333, upload-time = "2025-06-09T23:00:20.275Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fd/e5b64f7d2c92a41639ffb2ad44a6a82f347787abc0c7df5f49057cf11770/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f", size = 231724, upload-time = "2025-06-09T23:00:21.705Z" }, - { url = "https://files.pythonhosted.org/packages/20/fb/03395c0a43a5976af4bf7534759d214405fbbb4c114683f434dfdd3128ef/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30", size = 245842, upload-time = "2025-06-09T23:00:23.148Z" }, - { url = "https://files.pythonhosted.org/packages/d0/15/c01c8e1dffdac5d9803507d824f27aed2ba76b6ed0026fab4d9866e82f1f/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98", size = 239767, upload-time = "2025-06-09T23:00:25.103Z" }, - { url = "https://files.pythonhosted.org/packages/14/99/3f4c6fe882c1f5514b6848aa0a69b20cb5e5d8e8f51a339d48c0e9305ed0/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86", size = 224130, upload-time = "2025-06-09T23:00:27.061Z" }, - { url = "https://files.pythonhosted.org/packages/4d/83/220a374bd7b2aeba9d0725130665afe11de347d95c3620b9b82cc2fcab97/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae", size = 235301, upload-time = "2025-06-09T23:00:29.02Z" }, - { url = "https://files.pythonhosted.org/packages/03/3c/3e3390d75334a063181625343e8daab61b77e1b8214802cc4e8a1bb678fc/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8", size = 234606, upload-time = "2025-06-09T23:00:30.514Z" }, - { url = "https://files.pythonhosted.org/packages/23/1e/58232c19608b7a549d72d9903005e2d82488f12554a32de2d5fb59b9b1ba/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31", size = 248372, upload-time = "2025-06-09T23:00:31.966Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a4/e4a567e01702a88a74ce8a324691e62a629bf47d4f8607f24bf1c7216e7f/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7", size = 229860, upload-time = "2025-06-09T23:00:33.375Z" }, - { url = "https://files.pythonhosted.org/packages/73/a6/63b3374f7d22268b41a9db73d68a8233afa30ed164c46107b33c4d18ecdd/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5", size = 245893, upload-time = "2025-06-09T23:00:35.002Z" }, - { url = "https://files.pythonhosted.org/packages/6d/eb/d18b3f6e64799a79673c4ba0b45e4cfbe49c240edfd03a68be20002eaeaa/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898", size = 246323, upload-time = "2025-06-09T23:00:36.468Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f5/720f3812e3d06cd89a1d5db9ff6450088b8f5c449dae8ffb2971a44da506/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56", size = 233149, upload-time = "2025-06-09T23:00:37.963Z" }, - { url = "https://files.pythonhosted.org/packages/69/68/03efbf545e217d5db8446acfd4c447c15b7c8cf4dbd4a58403111df9322d/frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7", size = 39565, upload-time = "2025-06-09T23:00:39.753Z" }, - { url = "https://files.pythonhosted.org/packages/58/17/fe61124c5c333ae87f09bb67186d65038834a47d974fc10a5fadb4cc5ae1/frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d", size = 44019, upload-time = "2025-06-09T23:00:40.988Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, - { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, - { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, - { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, - { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, - { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, - { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, - { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, - { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, - { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" }, - { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" }, - { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" }, - { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" }, - { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" }, - { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" }, - { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" }, - { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" }, - { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" }, - { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" }, - { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" }, - { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" }, - { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" }, - { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" }, - { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" }, - { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" }, - { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" }, - { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" }, - { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" }, - { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" }, - { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" }, - { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" }, - { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" }, - { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" }, - { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" }, - { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" }, - { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" }, - { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" }, - { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" }, - { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" }, - { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" }, - { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "hexbytes" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/87/adf4635b4b8c050283d74e6db9a81496063229c9263e6acc1903ab79fbec/hexbytes-1.3.1.tar.gz", hash = "sha256:a657eebebdfe27254336f98d8af6e2236f3f83aed164b87466b6cf6c5f5a4765", size = 8633, upload-time = "2025-05-14T16:45:17.5Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/e0/3b31492b1c89da3c5a846680517871455b30c54738486fc57ac79a5761bd/hexbytes-1.3.1-py3-none-any.whl", hash = "sha256:da01ff24a1a9a2b1881c4b85f0e9f9b0f51b526b379ffa23832ae7899d29c2c7", size = 5074, upload-time = "2025-05-14T16:45:16.179Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httptools" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/17c672b4bc5c7ba7f201eada4e96c71d0a59fbc185e60e42580093a86f21/httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da", size = 103297, upload-time = "2024-10-16T19:44:08.129Z" }, - { url = "https://files.pythonhosted.org/packages/92/5e/b4a826fe91971a0b68e8c2bd4e7db3e7519882f5a8ccdb1194be2b3ab98f/httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1", size = 443130, upload-time = "2024-10-16T19:44:09.45Z" }, - { url = "https://files.pythonhosted.org/packages/b0/51/ce61e531e40289a681a463e1258fa1e05e0be54540e40d91d065a264cd8f/httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50", size = 442148, upload-time = "2024-10-16T19:44:11.539Z" }, - { url = "https://files.pythonhosted.org/packages/ea/9e/270b7d767849b0c96f275c695d27ca76c30671f8eb8cc1bab6ced5c5e1d0/httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959", size = 415949, upload-time = "2024-10-16T19:44:13.388Z" }, - { url = "https://files.pythonhosted.org/packages/81/86/ced96e3179c48c6f656354e106934e65c8963d48b69be78f355797f0e1b3/httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4", size = 417591, upload-time = "2024-10-16T19:44:15.258Z" }, - { url = "https://files.pythonhosted.org/packages/75/73/187a3f620ed3175364ddb56847d7a608a6fc42d551e133197098c0143eca/httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c", size = 88344, upload-time = "2024-10-16T19:44:16.54Z" }, - { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029, upload-time = "2024-10-16T19:44:18.427Z" }, - { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492, upload-time = "2024-10-16T19:44:19.515Z" }, - { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891, upload-time = "2024-10-16T19:44:21.067Z" }, - { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788, upload-time = "2024-10-16T19:44:22.958Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214, upload-time = "2024-10-16T19:44:24.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120, upload-time = "2024-10-16T19:44:26.295Z" }, - { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565, upload-time = "2024-10-16T19:44:29.188Z" }, - { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683, upload-time = "2024-10-16T19:44:30.175Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337, upload-time = "2024-10-16T19:44:31.786Z" }, - { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796, upload-time = "2024-10-16T19:44:32.825Z" }, - { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837, upload-time = "2024-10-16T19:44:33.974Z" }, - { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289, upload-time = "2024-10-16T19:44:35.111Z" }, - { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779, upload-time = "2024-10-16T19:44:36.253Z" }, - { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634, upload-time = "2024-10-16T19:44:37.357Z" }, - { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" }, - { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" }, - { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" }, - { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" }, - { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" }, - { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "itsdangerous" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "multidict" -version = "6.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/2f/a3470242707058fe856fe59241eee5635d79087100b7042a867368863a27/multidict-6.4.4.tar.gz", hash = "sha256:69ee9e6ba214b5245031b76233dd95408a0fd57fdb019ddcc1ead4790932a8e8", size = 90183, upload-time = "2025-05-19T14:16:37.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/92/0926a5baafa164b5d0ade3cd7932be39310375d7e25c9d7ceca05cb26a45/multidict-6.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8adee3ac041145ffe4488ea73fa0a622b464cc25340d98be76924d0cda8545ff", size = 66052, upload-time = "2025-05-19T14:13:49.944Z" }, - { url = "https://files.pythonhosted.org/packages/b2/54/8a857ae4f8f643ec444d91f419fdd49cc7a90a2ca0e42d86482b604b63bd/multidict-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b61e98c3e2a861035aaccd207da585bdcacef65fe01d7a0d07478efac005e028", size = 38867, upload-time = "2025-05-19T14:13:51.92Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5f/63add9069f945c19bc8b217ea6b0f8a1ad9382eab374bb44fae4354b3baf/multidict-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75493f28dbadecdbb59130e74fe935288813301a8554dc32f0c631b6bdcdf8b0", size = 38138, upload-time = "2025-05-19T14:13:53.778Z" }, - { url = "https://files.pythonhosted.org/packages/97/8b/fbd9c0fc13966efdb4a47f5bcffff67a4f2a3189fbeead5766eaa4250b20/multidict-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc3c6a37e048b5395ee235e4a2a0d639c2349dffa32d9367a42fc20d399772", size = 220433, upload-time = "2025-05-19T14:13:55.346Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c4/5132b2d75b3ea2daedb14d10f91028f09f74f5b4d373b242c1b8eec47571/multidict-6.4.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87cb72263946b301570b0f63855569a24ee8758aaae2cd182aae7d95fbc92ca7", size = 218059, upload-time = "2025-05-19T14:13:56.993Z" }, - { url = "https://files.pythonhosted.org/packages/1a/70/f1e818c7a29b908e2d7b4fafb1d7939a41c64868e79de2982eea0a13193f/multidict-6.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bbf7bd39822fd07e3609b6b4467af4c404dd2b88ee314837ad1830a7f4a8299", size = 231120, upload-time = "2025-05-19T14:13:58.333Z" }, - { url = "https://files.pythonhosted.org/packages/b4/7e/95a194d85f27d5ef9cbe48dff9ded722fc6d12fedf641ec6e1e680890be7/multidict-6.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1f7cbd4f1f44ddf5fd86a8675b7679176eae770f2fc88115d6dddb6cefb59bc", size = 227457, upload-time = "2025-05-19T14:13:59.663Z" }, - { url = "https://files.pythonhosted.org/packages/25/2b/590ad220968d1babb42f265debe7be5c5c616df6c5688c995a06d8a9b025/multidict-6.4.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb5ac9e5bfce0e6282e7f59ff7b7b9a74aa8e5c60d38186a4637f5aa764046ad", size = 219111, upload-time = "2025-05-19T14:14:01.019Z" }, - { url = "https://files.pythonhosted.org/packages/e0/f0/b07682b995d3fb5313f339b59d7de02db19ba0c02d1f77c27bdf8212d17c/multidict-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4efc31dfef8c4eeb95b6b17d799eedad88c4902daba39ce637e23a17ea078915", size = 213012, upload-time = "2025-05-19T14:14:02.396Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/c77b5f36feef2ec92f1119756e468ac9c3eebc35aa8a4c9e51df664cbbc9/multidict-6.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9fcad2945b1b91c29ef2b4050f590bfcb68d8ac8e0995a74e659aa57e8d78e01", size = 225408, upload-time = "2025-05-19T14:14:04.826Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b3/e8189b82af9b198b47bc637766208fc917189eea91d674bad417e657bbdf/multidict-6.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d877447e7368c7320832acb7159557e49b21ea10ffeb135c1077dbbc0816b598", size = 214396, upload-time = "2025-05-19T14:14:06.187Z" }, - { url = "https://files.pythonhosted.org/packages/20/e0/200d14c84e35ae13ee99fd65dc106e1a1acb87a301f15e906fc7d5b30c17/multidict-6.4.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:33a12ebac9f380714c298cbfd3e5b9c0c4e89c75fe612ae496512ee51028915f", size = 222237, upload-time = "2025-05-19T14:14:07.778Z" }, - { url = "https://files.pythonhosted.org/packages/13/f3/bb3df40045ca8262694a3245298732ff431dc781414a89a6a364ebac6840/multidict-6.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0f14ea68d29b43a9bf37953881b1e3eb75b2739e896ba4a6aa4ad4c5b9ffa145", size = 231425, upload-time = "2025-05-19T14:14:09.516Z" }, - { url = "https://files.pythonhosted.org/packages/85/3b/538563dc18514384dac169bcba938753ad9ab4d4c8d49b55d6ae49fb2579/multidict-6.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0327ad2c747a6600e4797d115d3c38a220fdb28e54983abe8964fd17e95ae83c", size = 226251, upload-time = "2025-05-19T14:14:10.82Z" }, - { url = "https://files.pythonhosted.org/packages/56/79/77e1a65513f09142358f1beb1d4cbc06898590b34a7de2e47023e3c5a3a2/multidict-6.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d1a20707492db9719a05fc62ee215fd2c29b22b47c1b1ba347f9abc831e26683", size = 220363, upload-time = "2025-05-19T14:14:12.638Z" }, - { url = "https://files.pythonhosted.org/packages/16/57/67b0516c3e348f8daaa79c369b3de4359a19918320ab82e2e586a1c624ef/multidict-6.4.4-cp310-cp310-win32.whl", hash = "sha256:d83f18315b9fca5db2452d1881ef20f79593c4aa824095b62cb280019ef7aa3d", size = 35175, upload-time = "2025-05-19T14:14:14.805Z" }, - { url = "https://files.pythonhosted.org/packages/86/5a/4ed8fec642d113fa653777cda30ef67aa5c8a38303c091e24c521278a6c6/multidict-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:9c17341ee04545fd962ae07330cb5a39977294c883485c8d74634669b1f7fe04", size = 38678, upload-time = "2025-05-19T14:14:16.949Z" }, - { url = "https://files.pythonhosted.org/packages/19/1b/4c6e638195851524a63972c5773c7737bea7e47b1ba402186a37773acee2/multidict-6.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f5f29794ac0e73d2a06ac03fd18870adc0135a9d384f4a306a951188ed02f95", size = 65515, upload-time = "2025-05-19T14:14:19.767Z" }, - { url = "https://files.pythonhosted.org/packages/25/d5/10e6bca9a44b8af3c7f920743e5fc0c2bcf8c11bf7a295d4cfe00b08fb46/multidict-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c04157266344158ebd57b7120d9b0b35812285d26d0e78193e17ef57bfe2979a", size = 38609, upload-time = "2025-05-19T14:14:21.538Z" }, - { url = "https://files.pythonhosted.org/packages/26/b4/91fead447ccff56247edc7f0535fbf140733ae25187a33621771ee598a18/multidict-6.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb61ffd3ab8310d93427e460f565322c44ef12769f51f77277b4abad7b6f7223", size = 37871, upload-time = "2025-05-19T14:14:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/3b/37/cbc977cae59277e99d15bbda84cc53b5e0c4929ffd91d958347200a42ad0/multidict-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e0ba18a9afd495f17c351d08ebbc4284e9c9f7971d715f196b79636a4d0de44", size = 226661, upload-time = "2025-05-19T14:14:24.124Z" }, - { url = "https://files.pythonhosted.org/packages/15/cd/7e0b57fbd4dc2fc105169c4ecce5be1a63970f23bb4ec8c721b67e11953d/multidict-6.4.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9faf1b1dcaadf9f900d23a0e6d6c8eadd6a95795a0e57fcca73acce0eb912065", size = 223422, upload-time = "2025-05-19T14:14:25.437Z" }, - { url = "https://files.pythonhosted.org/packages/f1/01/1de268da121bac9f93242e30cd3286f6a819e5f0b8896511162d6ed4bf8d/multidict-6.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4d1cb1327c6082c4fce4e2a438483390964c02213bc6b8d782cf782c9b1471f", size = 235447, upload-time = "2025-05-19T14:14:26.793Z" }, - { url = "https://files.pythonhosted.org/packages/d2/8c/8b9a5e4aaaf4f2de14e86181a3a3d7b105077f668b6a06f043ec794f684c/multidict-6.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:941f1bec2f5dbd51feeb40aea654c2747f811ab01bdd3422a48a4e4576b7d76a", size = 231455, upload-time = "2025-05-19T14:14:28.149Z" }, - { url = "https://files.pythonhosted.org/packages/35/db/e1817dcbaa10b319c412769cf999b1016890849245d38905b73e9c286862/multidict-6.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5f8a146184da7ea12910a4cec51ef85e44f6268467fb489c3caf0cd512f29c2", size = 223666, upload-time = "2025-05-19T14:14:29.584Z" }, - { url = "https://files.pythonhosted.org/packages/4a/e1/66e8579290ade8a00e0126b3d9a93029033ffd84f0e697d457ed1814d0fc/multidict-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:232b7237e57ec3c09be97206bfb83a0aa1c5d7d377faa019c68a210fa35831f1", size = 217392, upload-time = "2025-05-19T14:14:30.961Z" }, - { url = "https://files.pythonhosted.org/packages/7b/6f/f8639326069c24a48c7747c2a5485d37847e142a3f741ff3340c88060a9a/multidict-6.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:55ae0721c1513e5e3210bca4fc98456b980b0c2c016679d3d723119b6b202c42", size = 228969, upload-time = "2025-05-19T14:14:32.672Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c3/3d58182f76b960eeade51c89fcdce450f93379340457a328e132e2f8f9ed/multidict-6.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d662c072579f63137919d7bb8fc250655ce79f00c82ecf11cab678f335062e", size = 217433, upload-time = "2025-05-19T14:14:34.016Z" }, - { url = "https://files.pythonhosted.org/packages/e1/4b/f31a562906f3bd375f3d0e83ce314e4a660c01b16c2923e8229b53fba5d7/multidict-6.4.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0e05c39962baa0bb19a6b210e9b1422c35c093b651d64246b6c2e1a7e242d9fd", size = 225418, upload-time = "2025-05-19T14:14:35.376Z" }, - { url = "https://files.pythonhosted.org/packages/99/89/78bb95c89c496d64b5798434a3deee21996114d4d2c28dd65850bf3a691e/multidict-6.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b1cc3ab8c31d9ebf0faa6e3540fb91257590da330ffe6d2393d4208e638925", size = 235042, upload-time = "2025-05-19T14:14:36.723Z" }, - { url = "https://files.pythonhosted.org/packages/74/91/8780a6e5885a8770442a8f80db86a0887c4becca0e5a2282ba2cae702bc4/multidict-6.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:93ec84488a384cd7b8a29c2c7f467137d8a73f6fe38bb810ecf29d1ade011a7c", size = 230280, upload-time = "2025-05-19T14:14:38.194Z" }, - { url = "https://files.pythonhosted.org/packages/68/c1/fcf69cabd542eb6f4b892469e033567ee6991d361d77abdc55e3a0f48349/multidict-6.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b308402608493638763abc95f9dc0030bbd6ac6aff784512e8ac3da73a88af08", size = 223322, upload-time = "2025-05-19T14:14:40.015Z" }, - { url = "https://files.pythonhosted.org/packages/b8/85/5b80bf4b83d8141bd763e1d99142a9cdfd0db83f0739b4797172a4508014/multidict-6.4.4-cp311-cp311-win32.whl", hash = "sha256:343892a27d1a04d6ae455ecece12904d242d299ada01633d94c4f431d68a8c49", size = 35070, upload-time = "2025-05-19T14:14:41.904Z" }, - { url = "https://files.pythonhosted.org/packages/09/66/0bed198ffd590ab86e001f7fa46b740d58cf8ff98c2f254e4a36bf8861ad/multidict-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:73484a94f55359780c0f458bbd3c39cb9cf9c182552177d2136e828269dee529", size = 38667, upload-time = "2025-05-19T14:14:43.534Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b5/5675377da23d60875fe7dae6be841787755878e315e2f517235f22f59e18/multidict-6.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc388f75a1c00000824bf28b7633e40854f4127ede80512b44c3cfeeea1839a2", size = 64293, upload-time = "2025-05-19T14:14:44.724Z" }, - { url = "https://files.pythonhosted.org/packages/34/a7/be384a482754bb8c95d2bbe91717bf7ccce6dc38c18569997a11f95aa554/multidict-6.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:98af87593a666f739d9dba5d0ae86e01b0e1a9cfcd2e30d2d361fbbbd1a9162d", size = 38096, upload-time = "2025-05-19T14:14:45.95Z" }, - { url = "https://files.pythonhosted.org/packages/66/6d/d59854bb4352306145bdfd1704d210731c1bb2c890bfee31fb7bbc1c4c7f/multidict-6.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aff4cafea2d120327d55eadd6b7f1136a8e5a0ecf6fb3b6863e8aca32cd8e50a", size = 37214, upload-time = "2025-05-19T14:14:47.158Z" }, - { url = "https://files.pythonhosted.org/packages/99/e0/c29d9d462d7cfc5fc8f9bf24f9c6843b40e953c0b55e04eba2ad2cf54fba/multidict-6.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:169c4ba7858176b797fe551d6e99040c531c775d2d57b31bcf4de6d7a669847f", size = 224686, upload-time = "2025-05-19T14:14:48.366Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4a/da99398d7fd8210d9de068f9a1b5f96dfaf67d51e3f2521f17cba4ee1012/multidict-6.4.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9eb4c59c54421a32b3273d4239865cb14ead53a606db066d7130ac80cc8ec93", size = 231061, upload-time = "2025-05-19T14:14:49.952Z" }, - { url = "https://files.pythonhosted.org/packages/21/f5/ac11add39a0f447ac89353e6ca46666847051103649831c08a2800a14455/multidict-6.4.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cf3bd54c56aa16fdb40028d545eaa8d051402b61533c21e84046e05513d5780", size = 232412, upload-time = "2025-05-19T14:14:51.812Z" }, - { url = "https://files.pythonhosted.org/packages/d9/11/4b551e2110cded705a3c13a1d4b6a11f73891eb5a1c449f1b2b6259e58a6/multidict-6.4.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f682c42003c7264134bfe886376299db4cc0c6cd06a3295b41b347044bcb5482", size = 231563, upload-time = "2025-05-19T14:14:53.262Z" }, - { url = "https://files.pythonhosted.org/packages/4c/02/751530c19e78fe73b24c3da66618eda0aa0d7f6e7aa512e46483de6be210/multidict-6.4.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920f9cf2abdf6e493c519492d892c362007f113c94da4c239ae88429835bad1", size = 223811, upload-time = "2025-05-19T14:14:55.232Z" }, - { url = "https://files.pythonhosted.org/packages/c7/cb/2be8a214643056289e51ca356026c7b2ce7225373e7a1f8c8715efee8988/multidict-6.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:530d86827a2df6504526106b4c104ba19044594f8722d3e87714e847c74a0275", size = 216524, upload-time = "2025-05-19T14:14:57.226Z" }, - { url = "https://files.pythonhosted.org/packages/19/f3/6d5011ec375c09081f5250af58de85f172bfcaafebff286d8089243c4bd4/multidict-6.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ecde56ea2439b96ed8a8d826b50c57364612ddac0438c39e473fafad7ae1c23b", size = 229012, upload-time = "2025-05-19T14:14:58.597Z" }, - { url = "https://files.pythonhosted.org/packages/67/9c/ca510785df5cf0eaf5b2a8132d7d04c1ce058dcf2c16233e596ce37a7f8e/multidict-6.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:dc8c9736d8574b560634775ac0def6bdc1661fc63fa27ffdfc7264c565bcb4f2", size = 226765, upload-time = "2025-05-19T14:15:00.048Z" }, - { url = "https://files.pythonhosted.org/packages/36/c8/ca86019994e92a0f11e642bda31265854e6ea7b235642f0477e8c2e25c1f/multidict-6.4.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7f3d3b3c34867579ea47cbd6c1f2ce23fbfd20a273b6f9e3177e256584f1eacc", size = 222888, upload-time = "2025-05-19T14:15:01.568Z" }, - { url = "https://files.pythonhosted.org/packages/c6/67/bc25a8e8bd522935379066950ec4e2277f9b236162a73548a2576d4b9587/multidict-6.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:87a728af265e08f96b6318ebe3c0f68b9335131f461efab2fc64cc84a44aa6ed", size = 234041, upload-time = "2025-05-19T14:15:03.759Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a0/70c4c2d12857fccbe607b334b7ee28b6b5326c322ca8f73ee54e70d76484/multidict-6.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9f193eeda1857f8e8d3079a4abd258f42ef4a4bc87388452ed1e1c4d2b0c8740", size = 231046, upload-time = "2025-05-19T14:15:05.698Z" }, - { url = "https://files.pythonhosted.org/packages/c1/0f/52954601d02d39742aab01d6b92f53c1dd38b2392248154c50797b4df7f1/multidict-6.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be06e73c06415199200e9a2324a11252a3d62030319919cde5e6950ffeccf72e", size = 227106, upload-time = "2025-05-19T14:15:07.124Z" }, - { url = "https://files.pythonhosted.org/packages/af/24/679d83ec4379402d28721790dce818e5d6b9f94ce1323a556fb17fa9996c/multidict-6.4.4-cp312-cp312-win32.whl", hash = "sha256:622f26ea6a7e19b7c48dd9228071f571b2fbbd57a8cd71c061e848f281550e6b", size = 35351, upload-time = "2025-05-19T14:15:08.556Z" }, - { url = "https://files.pythonhosted.org/packages/52/ef/40d98bc5f986f61565f9b345f102409534e29da86a6454eb6b7c00225a13/multidict-6.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:5e2bcda30d5009996ff439e02a9f2b5c3d64a20151d34898c000a6281faa3781", size = 38791, upload-time = "2025-05-19T14:15:09.825Z" }, - { url = "https://files.pythonhosted.org/packages/df/2a/e166d2ffbf4b10131b2d5b0e458f7cee7d986661caceae0de8753042d4b2/multidict-6.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:82ffabefc8d84c2742ad19c37f02cde5ec2a1ee172d19944d380f920a340e4b9", size = 64123, upload-time = "2025-05-19T14:15:11.044Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/e200e379ae5b6f95cbae472e0199ea98913f03d8c9a709f42612a432932c/multidict-6.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6a2f58a66fe2c22615ad26156354005391e26a2f3721c3621504cd87c1ea87bf", size = 38049, upload-time = "2025-05-19T14:15:12.902Z" }, - { url = "https://files.pythonhosted.org/packages/75/fb/47afd17b83f6a8c7fa863c6d23ac5ba6a0e6145ed8a6bcc8da20b2b2c1d2/multidict-6.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5883d6ee0fd9d8a48e9174df47540b7545909841ac82354c7ae4cbe9952603bd", size = 37078, upload-time = "2025-05-19T14:15:14.282Z" }, - { url = "https://files.pythonhosted.org/packages/fa/70/1af3143000eddfb19fd5ca5e78393985ed988ac493bb859800fe0914041f/multidict-6.4.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9abcf56a9511653fa1d052bfc55fbe53dbee8f34e68bd6a5a038731b0ca42d15", size = 224097, upload-time = "2025-05-19T14:15:15.566Z" }, - { url = "https://files.pythonhosted.org/packages/b1/39/d570c62b53d4fba844e0378ffbcd02ac25ca423d3235047013ba2f6f60f8/multidict-6.4.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6ed5ae5605d4ad5a049fad2a28bb7193400700ce2f4ae484ab702d1e3749c3f9", size = 230768, upload-time = "2025-05-19T14:15:17.308Z" }, - { url = "https://files.pythonhosted.org/packages/fd/f8/ed88f2c4d06f752b015933055eb291d9bc184936903752c66f68fb3c95a7/multidict-6.4.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbfcb60396f9bcfa63e017a180c3105b8c123a63e9d1428a36544e7d37ca9e20", size = 231331, upload-time = "2025-05-19T14:15:18.73Z" }, - { url = "https://files.pythonhosted.org/packages/9c/6f/8e07cffa32f483ab887b0d56bbd8747ac2c1acd00dc0af6fcf265f4a121e/multidict-6.4.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0f1987787f5f1e2076b59692352ab29a955b09ccc433c1f6b8e8e18666f608b", size = 230169, upload-time = "2025-05-19T14:15:20.179Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2b/5dcf173be15e42f330110875a2668ddfc208afc4229097312212dc9c1236/multidict-6.4.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0121ccce8c812047d8d43d691a1ad7641f72c4f730474878a5aeae1b8ead8c", size = 222947, upload-time = "2025-05-19T14:15:21.714Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/4ddcbcebe5ebcd6faa770b629260d15840a5fc07ce8ad295a32e14993726/multidict-6.4.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83ec4967114295b8afd120a8eec579920c882831a3e4c3331d591a8e5bfbbc0f", size = 215761, upload-time = "2025-05-19T14:15:23.242Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c9/55e998ae45ff15c5608e384206aa71a11e1b7f48b64d166db400b14a3433/multidict-6.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:995f985e2e268deaf17867801b859a282e0448633f1310e3704b30616d269d69", size = 227605, upload-time = "2025-05-19T14:15:24.763Z" }, - { url = "https://files.pythonhosted.org/packages/04/49/c2404eac74497503c77071bd2e6f88c7e94092b8a07601536b8dbe99be50/multidict-6.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d832c608f94b9f92a0ec8b7e949be7792a642b6e535fcf32f3e28fab69eeb046", size = 226144, upload-time = "2025-05-19T14:15:26.249Z" }, - { url = "https://files.pythonhosted.org/packages/62/c5/0cd0c3c6f18864c40846aa2252cd69d308699cb163e1c0d989ca301684da/multidict-6.4.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d21c1212171cf7da703c5b0b7a0e85be23b720818aef502ad187d627316d5645", size = 221100, upload-time = "2025-05-19T14:15:28.303Z" }, - { url = "https://files.pythonhosted.org/packages/71/7b/f2f3887bea71739a046d601ef10e689528d4f911d84da873b6be9194ffea/multidict-6.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:cbebaa076aaecad3d4bb4c008ecc73b09274c952cf6a1b78ccfd689e51f5a5b0", size = 232731, upload-time = "2025-05-19T14:15:30.263Z" }, - { url = "https://files.pythonhosted.org/packages/e5/b3/d9de808349df97fa75ec1372758701b5800ebad3c46ae377ad63058fbcc6/multidict-6.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c93a6fb06cc8e5d3628b2b5fda215a5db01e8f08fc15fadd65662d9b857acbe4", size = 229637, upload-time = "2025-05-19T14:15:33.337Z" }, - { url = "https://files.pythonhosted.org/packages/5e/57/13207c16b615eb4f1745b44806a96026ef8e1b694008a58226c2d8f5f0a5/multidict-6.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8cd8f81f1310182362fb0c7898145ea9c9b08a71081c5963b40ee3e3cac589b1", size = 225594, upload-time = "2025-05-19T14:15:34.832Z" }, - { url = "https://files.pythonhosted.org/packages/3a/e4/d23bec2f70221604f5565000632c305fc8f25ba953e8ce2d8a18842b9841/multidict-6.4.4-cp313-cp313-win32.whl", hash = "sha256:3e9f1cd61a0ab857154205fb0b1f3d3ace88d27ebd1409ab7af5096e409614cd", size = 35359, upload-time = "2025-05-19T14:15:36.246Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/cfe1a47632be861b627f46f642c1d031704cc1c0f5c0efbde2ad44aa34bd/multidict-6.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373", size = 38903, upload-time = "2025-05-19T14:15:37.507Z" }, - { url = "https://files.pythonhosted.org/packages/68/7b/15c259b0ab49938a0a1c8f3188572802704a779ddb294edc1b2a72252e7c/multidict-6.4.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6a602151dbf177be2450ef38966f4be3467d41a86c6a845070d12e17c858a156", size = 68895, upload-time = "2025-05-19T14:15:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/f1/7d/168b5b822bccd88142e0a3ce985858fea612404edd228698f5af691020c9/multidict-6.4.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d2b9712211b860d123815a80b859075d86a4d54787e247d7fbee9db6832cf1c", size = 40183, upload-time = "2025-05-19T14:15:40.197Z" }, - { url = "https://files.pythonhosted.org/packages/e0/b7/d4b8d98eb850ef28a4922ba508c31d90715fd9b9da3801a30cea2967130b/multidict-6.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d2fa86af59f8fc1972e121ade052145f6da22758f6996a197d69bb52f8204e7e", size = 39592, upload-time = "2025-05-19T14:15:41.508Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/a554678898a19583548e742080cf55d169733baf57efc48c2f0273a08583/multidict-6.4.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50855d03e9e4d66eab6947ba688ffb714616f985838077bc4b490e769e48da51", size = 226071, upload-time = "2025-05-19T14:15:42.877Z" }, - { url = "https://files.pythonhosted.org/packages/ee/dc/7ba6c789d05c310e294f85329efac1bf5b450338d2542498db1491a264df/multidict-6.4.4-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5bce06b83be23225be1905dcdb6b789064fae92499fbc458f59a8c0e68718601", size = 222597, upload-time = "2025-05-19T14:15:44.412Z" }, - { url = "https://files.pythonhosted.org/packages/24/4f/34eadbbf401b03768dba439be0fb94b0d187facae9142821a3d5599ccb3b/multidict-6.4.4-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66ed0731f8e5dfd8369a883b6e564aca085fb9289aacabd9decd70568b9a30de", size = 228253, upload-time = "2025-05-19T14:15:46.474Z" }, - { url = "https://files.pythonhosted.org/packages/c0/e6/493225a3cdb0d8d80d43a94503fc313536a07dae54a3f030d279e629a2bc/multidict-6.4.4-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:329ae97fc2f56f44d91bc47fe0972b1f52d21c4b7a2ac97040da02577e2daca2", size = 226146, upload-time = "2025-05-19T14:15:48.003Z" }, - { url = "https://files.pythonhosted.org/packages/2f/70/e411a7254dc3bff6f7e6e004303b1b0591358e9f0b7c08639941e0de8bd6/multidict-6.4.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c27e5dcf520923d6474d98b96749e6805f7677e93aaaf62656005b8643f907ab", size = 220585, upload-time = "2025-05-19T14:15:49.546Z" }, - { url = "https://files.pythonhosted.org/packages/08/8f/beb3ae7406a619100d2b1fb0022c3bb55a8225ab53c5663648ba50dfcd56/multidict-6.4.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:058cc59b9e9b143cc56715e59e22941a5d868c322242278d28123a5d09cdf6b0", size = 212080, upload-time = "2025-05-19T14:15:51.151Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ec/355124e9d3d01cf8edb072fd14947220f357e1c5bc79c88dff89297e9342/multidict-6.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:69133376bc9a03f8c47343d33f91f74a99c339e8b58cea90433d8e24bb298031", size = 226558, upload-time = "2025-05-19T14:15:52.665Z" }, - { url = "https://files.pythonhosted.org/packages/fd/22/d2b95cbebbc2ada3be3812ea9287dcc9712d7f1a012fad041770afddb2ad/multidict-6.4.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d6b15c55721b1b115c5ba178c77104123745b1417527ad9641a4c5e2047450f0", size = 212168, upload-time = "2025-05-19T14:15:55.279Z" }, - { url = "https://files.pythonhosted.org/packages/4d/c5/62bfc0b2f9ce88326dbe7179f9824a939c6c7775b23b95de777267b9725c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a887b77f51d3d41e6e1a63cf3bc7ddf24de5939d9ff69441387dfefa58ac2e26", size = 217970, upload-time = "2025-05-19T14:15:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/79/74/977cea1aadc43ff1c75d23bd5bc4768a8fac98c14e5878d6ee8d6bab743c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:632a3bf8f1787f7ef7d3c2f68a7bde5be2f702906f8b5842ad6da9d974d0aab3", size = 226980, upload-time = "2025-05-19T14:15:58.313Z" }, - { url = "https://files.pythonhosted.org/packages/48/fc/cc4a1a2049df2eb84006607dc428ff237af38e0fcecfdb8a29ca47b1566c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a145c550900deb7540973c5cdb183b0d24bed6b80bf7bddf33ed8f569082535e", size = 220641, upload-time = "2025-05-19T14:15:59.866Z" }, - { url = "https://files.pythonhosted.org/packages/3b/6a/a7444d113ab918701988d4abdde373dbdfd2def7bd647207e2bf645c7eac/multidict-6.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc5d83c6619ca5c9672cb78b39ed8542f1975a803dee2cda114ff73cbb076edd", size = 221728, upload-time = "2025-05-19T14:16:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b0/fdf4c73ad1c55e0f4dbbf2aa59dd37037334091f9a4961646d2b7ac91a86/multidict-6.4.4-cp313-cp313t-win32.whl", hash = "sha256:3312f63261b9df49be9d57aaa6abf53a6ad96d93b24f9cc16cf979956355ce6e", size = 41913, upload-time = "2025-05-19T14:16:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/8e/92/27989ecca97e542c0d01d05a98a5ae12198a243a9ee12563a0313291511f/multidict-6.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:ba852168d814b2c73333073e1c7116d9395bea69575a01b0b3c89d2d5a87c8fb", size = 46112, upload-time = "2025-05-19T14:16:04.909Z" }, - { url = "https://files.pythonhosted.org/packages/84/5d/e17845bb0fa76334477d5de38654d27946d5b5d3695443987a094a71b440/multidict-6.4.4-py3-none-any.whl", hash = "sha256:bd4557071b561a8b3b6075c3ce93cf9bfb6182cb241805c3d66ced3b75eff4ac", size = 10481, upload-time = "2025-05-19T14:16:36.024Z" }, -] - -[[package]] -name = "parsimonious" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7b/91/abdc50c4ef06fdf8d047f60ee777ca9b2a7885e1a9cea81343fbecda52d7/parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c", size = 52172, upload-time = "2022-09-03T17:01:17.004Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/0f/c8b64d9b54ea631fcad4e9e3c8dbe8c11bb32a623be94f22974c88e71eaf/parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f", size = 48427, upload-time = "2022-09-03T17:01:13.814Z" }, -] - -[[package]] -name = "propcache" -version = "0.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4e/ad52a7925ff01c1325653a730c7ec3175a23f948f08626a534133427dcff/propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3", size = 43133, upload-time = "2025-06-09T22:53:41.965Z" }, - { url = "https://files.pythonhosted.org/packages/63/7c/e9399ba5da7780871db4eac178e9c2e204c23dd3e7d32df202092a1ed400/propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3", size = 43039, upload-time = "2025-06-09T22:53:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/22/e1/58da211eb8fdc6fc854002387d38f415a6ca5f5c67c1315b204a5d3e9d7a/propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e", size = 201903, upload-time = "2025-06-09T22:53:44.872Z" }, - { url = "https://files.pythonhosted.org/packages/c4/0a/550ea0f52aac455cb90111c8bab995208443e46d925e51e2f6ebdf869525/propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220", size = 213362, upload-time = "2025-06-09T22:53:46.707Z" }, - { url = "https://files.pythonhosted.org/packages/5a/af/9893b7d878deda9bb69fcf54600b247fba7317761b7db11fede6e0f28bd0/propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb", size = 210525, upload-time = "2025-06-09T22:53:48.547Z" }, - { url = "https://files.pythonhosted.org/packages/7c/bb/38fd08b278ca85cde36d848091ad2b45954bc5f15cce494bb300b9285831/propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614", size = 198283, upload-time = "2025-06-09T22:53:50.067Z" }, - { url = "https://files.pythonhosted.org/packages/78/8c/9fe55bd01d362bafb413dfe508c48753111a1e269737fa143ba85693592c/propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50", size = 191872, upload-time = "2025-06-09T22:53:51.438Z" }, - { url = "https://files.pythonhosted.org/packages/54/14/4701c33852937a22584e08abb531d654c8bcf7948a8f87ad0a4822394147/propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339", size = 199452, upload-time = "2025-06-09T22:53:53.229Z" }, - { url = "https://files.pythonhosted.org/packages/16/44/447f2253d859602095356007657ee535e0093215ea0b3d1d6a41d16e5201/propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0", size = 191567, upload-time = "2025-06-09T22:53:54.541Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/e4756258749bb2d3b46defcff606a2f47410bab82be5824a67e84015b267/propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2", size = 193015, upload-time = "2025-06-09T22:53:56.44Z" }, - { url = "https://files.pythonhosted.org/packages/1e/df/e6d3c7574233164b6330b9fd697beeac402afd367280e6dc377bb99b43d9/propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7", size = 204660, upload-time = "2025-06-09T22:53:57.839Z" }, - { url = "https://files.pythonhosted.org/packages/b2/53/e4d31dd5170b4a0e2e6b730f2385a96410633b4833dc25fe5dffd1f73294/propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b", size = 206105, upload-time = "2025-06-09T22:53:59.638Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fe/74d54cf9fbe2a20ff786e5f7afcfde446588f0cf15fb2daacfbc267b866c/propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c", size = 196980, upload-time = "2025-06-09T22:54:01.071Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/c469c9d59dada8a7679625e0440b544fe72e99311a4679c279562051f6fc/propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70", size = 37679, upload-time = "2025-06-09T22:54:03.003Z" }, - { url = "https://files.pythonhosted.org/packages/38/35/07a471371ac89d418f8d0b699c75ea6dca2041fbda360823de21f6a9ce0a/propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9", size = 41459, upload-time = "2025-06-09T22:54:04.134Z" }, - { url = "https://files.pythonhosted.org/packages/80/8d/e8b436717ab9c2cfc23b116d2c297305aa4cd8339172a456d61ebf5669b8/propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be", size = 74207, upload-time = "2025-06-09T22:54:05.399Z" }, - { url = "https://files.pythonhosted.org/packages/d6/29/1e34000e9766d112171764b9fa3226fa0153ab565d0c242c70e9945318a7/propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f", size = 43648, upload-time = "2025-06-09T22:54:08.023Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/1ad5af0df781e76988897da39b5f086c2bf0f028b7f9bd1f409bb05b6874/propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9", size = 43496, upload-time = "2025-06-09T22:54:09.228Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ce/e96392460f9fb68461fabab3e095cb00c8ddf901205be4eae5ce246e5b7e/propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf", size = 217288, upload-time = "2025-06-09T22:54:10.466Z" }, - { url = "https://files.pythonhosted.org/packages/c5/2a/866726ea345299f7ceefc861a5e782b045545ae6940851930a6adaf1fca6/propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9", size = 227456, upload-time = "2025-06-09T22:54:11.828Z" }, - { url = "https://files.pythonhosted.org/packages/de/03/07d992ccb6d930398689187e1b3c718339a1c06b8b145a8d9650e4726166/propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66", size = 225429, upload-time = "2025-06-09T22:54:13.823Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/116ba39448753b1330f48ab8ba927dcd6cf0baea8a0ccbc512dfb49ba670/propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df", size = 213472, upload-time = "2025-06-09T22:54:15.232Z" }, - { url = "https://files.pythonhosted.org/packages/a6/85/f01f5d97e54e428885a5497ccf7f54404cbb4f906688a1690cd51bf597dc/propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2", size = 204480, upload-time = "2025-06-09T22:54:17.104Z" }, - { url = "https://files.pythonhosted.org/packages/e3/79/7bf5ab9033b8b8194cc3f7cf1aaa0e9c3256320726f64a3e1f113a812dce/propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7", size = 214530, upload-time = "2025-06-09T22:54:18.512Z" }, - { url = "https://files.pythonhosted.org/packages/31/0b/bd3e0c00509b609317df4a18e6b05a450ef2d9a963e1d8bc9c9415d86f30/propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95", size = 205230, upload-time = "2025-06-09T22:54:19.947Z" }, - { url = "https://files.pythonhosted.org/packages/7a/23/fae0ff9b54b0de4e819bbe559508da132d5683c32d84d0dc2ccce3563ed4/propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e", size = 206754, upload-time = "2025-06-09T22:54:21.716Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7f/ad6a3c22630aaa5f618b4dc3c3598974a72abb4c18e45a50b3cdd091eb2f/propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e", size = 218430, upload-time = "2025-06-09T22:54:23.17Z" }, - { url = "https://files.pythonhosted.org/packages/5b/2c/ba4f1c0e8a4b4c75910742f0d333759d441f65a1c7f34683b4a74c0ee015/propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf", size = 223884, upload-time = "2025-06-09T22:54:25.539Z" }, - { url = "https://files.pythonhosted.org/packages/88/e4/ebe30fc399e98572019eee82ad0caf512401661985cbd3da5e3140ffa1b0/propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e", size = 211480, upload-time = "2025-06-09T22:54:26.892Z" }, - { url = "https://files.pythonhosted.org/packages/96/0a/7d5260b914e01d1d0906f7f38af101f8d8ed0dc47426219eeaf05e8ea7c2/propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897", size = 37757, upload-time = "2025-06-09T22:54:28.241Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2d/89fe4489a884bc0da0c3278c552bd4ffe06a1ace559db5ef02ef24ab446b/propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39", size = 41500, upload-time = "2025-06-09T22:54:29.4Z" }, - { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, - { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, - { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, - { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, - { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, - { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, - { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, - { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, - { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, - { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, - { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, - { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, - { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, - { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, - { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, - { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, - { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, - { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, - { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, - { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, - { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, - { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, - { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, - { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, - { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, - { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, - { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, - { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, - { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, -] - -[[package]] -name = "pycryptodome" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" }, - { url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" }, - { url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" }, - { url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" }, - { url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" }, - { url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" }, - { url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" }, - { url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" }, - { url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" }, - { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, - { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, - { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, - { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, - { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, - { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, - { url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886, upload-time = "2025-05-17T17:21:20.614Z" }, - { url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151, upload-time = "2025-05-17T17:21:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461, upload-time = "2025-05-17T17:21:25.225Z" }, - { url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440, upload-time = "2025-05-17T17:21:27.991Z" }, - { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, -] - -[[package]] -name = "pydantic" -version = "2.10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/70/7e/fb60e6fee04d0ef8f15e4e01ff187a196fa976eb0f0ab524af4599e5754c/pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06", size = 762094, upload-time = "2024-12-18T17:09:24.84Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/26/3e1bbe954fde7ee22a6e7d31582c642aad9e84ffe4b5fb61e63b87cd326f/pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", size = 431765, upload-time = "2024-12-18T17:09:21.953Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.27.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443, upload-time = "2024-12-18T11:31:54.917Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938, upload-time = "2024-12-18T11:27:14.406Z" }, - { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684, upload-time = "2024-12-18T11:27:16.489Z" }, - { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169, upload-time = "2024-12-18T11:27:22.16Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227, upload-time = "2024-12-18T11:27:25.097Z" }, - { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695, upload-time = "2024-12-18T11:27:28.656Z" }, - { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662, upload-time = "2024-12-18T11:27:30.798Z" }, - { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370, upload-time = "2024-12-18T11:27:33.692Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813, upload-time = "2024-12-18T11:27:37.111Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287, upload-time = "2024-12-18T11:27:40.566Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414, upload-time = "2024-12-18T11:27:43.757Z" }, - { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301, upload-time = "2024-12-18T11:27:47.36Z" }, - { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685, upload-time = "2024-12-18T11:27:50.508Z" }, - { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876, upload-time = "2024-12-18T11:27:53.54Z" }, - { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421, upload-time = "2024-12-18T11:27:55.409Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998, upload-time = "2024-12-18T11:27:57.252Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167, upload-time = "2024-12-18T11:27:59.146Z" }, - { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071, upload-time = "2024-12-18T11:28:02.625Z" }, - { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244, upload-time = "2024-12-18T11:28:04.442Z" }, - { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470, upload-time = "2024-12-18T11:28:07.679Z" }, - { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291, upload-time = "2024-12-18T11:28:10.297Z" }, - { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613, upload-time = "2024-12-18T11:28:13.362Z" }, - { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355, upload-time = "2024-12-18T11:28:16.587Z" }, - { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661, upload-time = "2024-12-18T11:28:18.407Z" }, - { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261, upload-time = "2024-12-18T11:28:21.471Z" }, - { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361, upload-time = "2024-12-18T11:28:23.53Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484, upload-time = "2024-12-18T11:28:25.391Z" }, - { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102, upload-time = "2024-12-18T11:28:28.593Z" }, - { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127, upload-time = "2024-12-18T11:28:30.346Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340, upload-time = "2024-12-18T11:28:32.521Z" }, - { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900, upload-time = "2024-12-18T11:28:34.507Z" }, - { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177, upload-time = "2024-12-18T11:28:36.488Z" }, - { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046, upload-time = "2024-12-18T11:28:39.409Z" }, - { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386, upload-time = "2024-12-18T11:28:41.221Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060, upload-time = "2024-12-18T11:28:44.709Z" }, - { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870, upload-time = "2024-12-18T11:28:46.839Z" }, - { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822, upload-time = "2024-12-18T11:28:48.896Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364, upload-time = "2024-12-18T11:28:50.755Z" }, - { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303, upload-time = "2024-12-18T11:28:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064, upload-time = "2024-12-18T11:28:56.074Z" }, - { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046, upload-time = "2024-12-18T11:28:58.107Z" }, - { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092, upload-time = "2024-12-18T11:29:01.335Z" }, - { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709, upload-time = "2024-12-18T11:29:03.193Z" }, - { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273, upload-time = "2024-12-18T11:29:05.306Z" }, - { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027, upload-time = "2024-12-18T11:29:07.294Z" }, - { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888, upload-time = "2024-12-18T11:29:09.249Z" }, - { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738, upload-time = "2024-12-18T11:29:11.23Z" }, - { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138, upload-time = "2024-12-18T11:29:16.396Z" }, - { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025, upload-time = "2024-12-18T11:29:20.25Z" }, - { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633, upload-time = "2024-12-18T11:29:23.877Z" }, - { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404, upload-time = "2024-12-18T11:29:25.872Z" }, - { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130, upload-time = "2024-12-18T11:29:29.252Z" }, - { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946, upload-time = "2024-12-18T11:29:31.338Z" }, - { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387, upload-time = "2024-12-18T11:29:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453, upload-time = "2024-12-18T11:29:35.533Z" }, - { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186, upload-time = "2024-12-18T11:29:37.649Z" }, - { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159, upload-time = "2024-12-18T11:30:54.382Z" }, - { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331, upload-time = "2024-12-18T11:30:58.178Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467, upload-time = "2024-12-18T11:31:00.6Z" }, - { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797, upload-time = "2024-12-18T11:31:07.243Z" }, - { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839, upload-time = "2024-12-18T11:31:09.775Z" }, - { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861, upload-time = "2024-12-18T11:31:13.469Z" }, - { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582, upload-time = "2024-12-18T11:31:17.423Z" }, - { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985, upload-time = "2024-12-18T11:31:19.901Z" }, - { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715, upload-time = "2024-12-18T11:31:22.821Z" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234, upload-time = "2025-04-18T16:44:48.265Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356, upload-time = "2025-04-18T16:44:46.617Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920, upload-time = "2025-03-25T10:14:56.835Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256, upload-time = "2025-03-25T10:14:55.034Z" }, -] - -[[package]] -name = "python-multipart" -version = "0.0.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, -] - -[[package]] -name = "pyunormalize" -version = "16.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/08/568036c725dac746ecb267bb749ef930fb7907454fe69fce83c8557287fb/pyunormalize-16.0.0.tar.gz", hash = "sha256:2e1dfbb4a118154ae26f70710426a52a364b926c9191f764601f5a8cb12761f7", size = 49968, upload-time = "2024-09-17T17:08:18.245Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/f9/9d86e56f716e0651194a5ad58be9c146fcaf1de6901ac6f3cd3affeeb74e/pyunormalize-16.0.0-py3-none-any.whl", hash = "sha256:c647d95e5d1e2ea9a2f448d1d95d8518348df24eab5c3fd32d2b5c3300a49152", size = 49173, upload-time = "2024-09-17T17:08:17.078Z" }, -] - -[[package]] -name = "pywin32" -version = "310" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, - { url = "https://files.pythonhosted.org/packages/3c/84/1a8e3d7a15490d28a5d816efa229ecb4999cdc51a7c30dd8914f669093b8/pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213", size = 8522963, upload-time = "2025-03-17T00:55:50.969Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b1/68aa2986129fb1011dabbe95f0136f44509afaf072b12b8f815905a39f33/pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd", size = 8784284, upload-time = "2025-03-17T00:55:53.124Z" }, - { url = "https://files.pythonhosted.org/packages/b3/bd/d1592635992dd8db5bb8ace0551bc3a769de1ac8850200cfa517e72739fb/pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c", size = 9520748, upload-time = "2025-03-17T00:55:55.203Z" }, - { url = "https://files.pythonhosted.org/packages/90/b1/ac8b1ffce6603849eb45a91cf126c0fa5431f186c2e768bf56889c46f51c/pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582", size = 8455941, upload-time = "2025-03-17T00:55:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, - { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384, upload-time = "2025-03-17T00:56:04.383Z" }, - { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039, upload-time = "2025-03-17T00:56:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152, upload-time = "2025-03-17T00:56:07.819Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" }, - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, - { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669, upload-time = "2024-11-06T20:09:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684, upload-time = "2024-11-06T20:09:32.915Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589, upload-time = "2024-11-06T20:09:35.504Z" }, - { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121, upload-time = "2024-11-06T20:09:37.701Z" }, - { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275, upload-time = "2024-11-06T20:09:40.371Z" }, - { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257, upload-time = "2024-11-06T20:09:43.059Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727, upload-time = "2024-11-06T20:09:48.19Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667, upload-time = "2024-11-06T20:09:49.828Z" }, - { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963, upload-time = "2024-11-06T20:09:51.819Z" }, - { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700, upload-time = "2024-11-06T20:09:53.982Z" }, - { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592, upload-time = "2024-11-06T20:09:56.222Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929, upload-time = "2024-11-06T20:09:58.642Z" }, - { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213, upload-time = "2024-11-06T20:10:00.867Z" }, - { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734, upload-time = "2024-11-06T20:10:03.361Z" }, - { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052, upload-time = "2024-11-06T20:10:05.179Z" }, - { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, - { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, - { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, - { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, - { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, - { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, - { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, - { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, - { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, - { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, - { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, - { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, - { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, - { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, - { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, - { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, - { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, - { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, - { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, - { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, - { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, - { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, - { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, - { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, -] - -[[package]] -name = "requests" -version = "2.32.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, -] - -[[package]] -name = "rich" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, -] - -[[package]] -name = "rich-toolkit" -version = "0.14.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/7a/cb48b7024b247631ce39b1f14a0f1abedf311fb27b892b0e0387d809d4b5/rich_toolkit-0.14.7.tar.gz", hash = "sha256:6cca5a68850cc5778915f528eb785662c27ba3b4b2624612cce8340fa9701c5e", size = 104977, upload-time = "2025-05-27T15:48:09.377Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/2e/95fde5b818dac9a37683ea064096323f593442d0f6358923c5f635974393/rich_toolkit-0.14.7-py3-none-any.whl", hash = "sha256:def05cc6e0f1176d6263b6a26648f16a62c4563b277ca2f8538683acdba1e0da", size = 24870, upload-time = "2025-05-27T15:48:07.942Z" }, -] - -[[package]] -name = "rlp" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/2d/439b0728a92964a04d9c88ea1ca9ebb128893fbbd5834faa31f987f2fd4c/rlp-4.1.0.tar.gz", hash = "sha256:be07564270a96f3e225e2c107db263de96b5bc1f27722d2855bd3459a08e95a9", size = 33429, upload-time = "2025-02-04T22:05:59.089Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/fb/e4c0ced9893b84ac95b7181d69a9786ce5879aeb3bbbcbba80a164f85d6a/rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f", size = 19973, upload-time = "2025-02-04T22:05:57.05Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "starlette" -version = "0.46.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, -] - -[[package]] -name = "toolz" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790, upload-time = "2024-10-04T16:17:04.001Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383, upload-time = "2024-10-04T16:17:01.533Z" }, -] - -[[package]] -name = "typer" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, -] - -[[package]] -name = "types-requests" -version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/7f/73b3a04a53b0fd2a911d4ec517940ecd6600630b559e4505cc7b68beb5a0/types_requests-2.32.4.20250611.tar.gz", hash = "sha256:741c8777ed6425830bf51e54d6abe245f79b4dcb9019f1622b773463946bf826", size = 23118, upload-time = "2025-06-11T03:11:41.272Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/ea/0be9258c5a4fa1ba2300111aa5a0767ee6d18eb3fd20e91616c12082284d/types_requests-2.32.4.20250611-py3-none-any.whl", hash = "sha256:ad2fe5d3b0cb3c2c902c8815a70e7fb2302c4b8c1f77bdcd738192cdb3878072", size = 20643, upload-time = "2025-06-11T03:11:40.186Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, -] - -[[package]] -name = "urllib3" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, -] - -[[package]] -name = "uvicorn" -version = "0.34.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631, upload-time = "2025-06-01T07:48:17.531Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431, upload-time = "2025-06-01T07:48:15.664Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, - { url = "https://files.pythonhosted.org/packages/35/5a/62d5800358a78cc25c8a6c72ef8b10851bdb8cca22e14d9c74167b7f86da/uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d", size = 801898, upload-time = "2024-10-14T23:37:22.663Z" }, - { url = "https://files.pythonhosted.org/packages/f3/96/63695e0ebd7da6c741ccd4489b5947394435e198a1382349c17b1146bb97/uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26", size = 3827735, upload-time = "2024-10-14T23:37:25.129Z" }, - { url = "https://files.pythonhosted.org/packages/61/e0/f0f8ec84979068ffae132c58c79af1de9cceeb664076beea86d941af1a30/uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb", size = 3825126, upload-time = "2024-10-14T23:37:27.59Z" }, - { url = "https://files.pythonhosted.org/packages/bf/fe/5e94a977d058a54a19df95f12f7161ab6e323ad49f4dabc28822eb2df7ea/uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f", size = 3705789, upload-time = "2024-10-14T23:37:29.385Z" }, - { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523, upload-time = "2024-10-14T23:37:32.048Z" }, - { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410, upload-time = "2024-10-14T23:37:33.612Z" }, - { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476, upload-time = "2024-10-14T23:37:36.11Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855, upload-time = "2024-10-14T23:37:37.683Z" }, - { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185, upload-time = "2024-10-14T23:37:40.226Z" }, - { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256, upload-time = "2024-10-14T23:37:42.839Z" }, - { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323, upload-time = "2024-10-14T23:37:45.337Z" }, - { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284, upload-time = "2024-10-14T23:37:47.833Z" }, - { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349, upload-time = "2024-10-14T23:37:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089, upload-time = "2024-10-14T23:37:51.703Z" }, - { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770, upload-time = "2024-10-14T23:37:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321, upload-time = "2024-10-14T23:37:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022, upload-time = "2024-10-14T23:37:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" }, - { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" }, - { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" }, - { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" }, - { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" }, - { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" }, -] - -[[package]] -name = "watchfiles" -version = "1.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/e2/8ed598c42057de7aa5d97c472254af4906ff0a59a66699d426fc9ef795d7/watchfiles-1.0.5.tar.gz", hash = "sha256:b7529b5dcc114679d43827d8c35a07c493ad6f083633d573d81c660abc5979e9", size = 94537, upload-time = "2025-04-08T10:36:26.722Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/4d/d02e6ea147bb7fff5fd109c694a95109612f419abed46548a930e7f7afa3/watchfiles-1.0.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5c40fe7dd9e5f81e0847b1ea64e1f5dd79dd61afbedb57759df06767ac719b40", size = 405632, upload-time = "2025-04-08T10:34:41.832Z" }, - { url = "https://files.pythonhosted.org/packages/60/31/9ee50e29129d53a9a92ccf1d3992751dc56fc3c8f6ee721be1c7b9c81763/watchfiles-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c0db396e6003d99bb2d7232c957b5f0b5634bbd1b24e381a5afcc880f7373fb", size = 395734, upload-time = "2025-04-08T10:34:44.236Z" }, - { url = "https://files.pythonhosted.org/packages/ad/8c/759176c97195306f028024f878e7f1c776bda66ccc5c68fa51e699cf8f1d/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b551d4fb482fc57d852b4541f911ba28957d051c8776e79c3b4a51eb5e2a1b11", size = 455008, upload-time = "2025-04-08T10:34:45.617Z" }, - { url = "https://files.pythonhosted.org/packages/55/1a/5e977250c795ee79a0229e3b7f5e3a1b664e4e450756a22da84d2f4979fe/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:830aa432ba5c491d52a15b51526c29e4a4b92bf4f92253787f9726fe01519487", size = 459029, upload-time = "2025-04-08T10:34:46.814Z" }, - { url = "https://files.pythonhosted.org/packages/e6/17/884cf039333605c1d6e296cf5be35fad0836953c3dfd2adb71b72f9dbcd0/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a16512051a822a416b0d477d5f8c0e67b67c1a20d9acecb0aafa3aa4d6e7d256", size = 488916, upload-time = "2025-04-08T10:34:48.571Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e0/bcb6e64b45837056c0a40f3a2db3ef51c2ced19fda38484fa7508e00632c/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe0cbc787770e52a96c6fda6726ace75be7f840cb327e1b08d7d54eadc3bc85", size = 523763, upload-time = "2025-04-08T10:34:50.268Z" }, - { url = "https://files.pythonhosted.org/packages/24/e9/f67e9199f3bb35c1837447ecf07e9830ec00ff5d35a61e08c2cd67217949/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d363152c5e16b29d66cbde8fa614f9e313e6f94a8204eaab268db52231fe5358", size = 502891, upload-time = "2025-04-08T10:34:51.419Z" }, - { url = "https://files.pythonhosted.org/packages/23/ed/a6cf815f215632f5c8065e9c41fe872025ffea35aa1f80499f86eae922db/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee32c9a9bee4d0b7bd7cbeb53cb185cf0b622ac761efaa2eba84006c3b3a614", size = 454921, upload-time = "2025-04-08T10:34:52.67Z" }, - { url = "https://files.pythonhosted.org/packages/92/4c/e14978599b80cde8486ab5a77a821e8a982ae8e2fcb22af7b0886a033ec8/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29c7fd632ccaf5517c16a5188e36f6612d6472ccf55382db6c7fe3fcccb7f59f", size = 631422, upload-time = "2025-04-08T10:34:53.985Z" }, - { url = "https://files.pythonhosted.org/packages/b2/1a/9263e34c3458f7614b657f974f4ee61fd72f58adce8b436e16450e054efd/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e637810586e6fe380c8bc1b3910accd7f1d3a9a7262c8a78d4c8fb3ba6a2b3d", size = 625675, upload-time = "2025-04-08T10:34:55.173Z" }, - { url = "https://files.pythonhosted.org/packages/96/1f/1803a18bd6ab04a0766386a19bcfe64641381a04939efdaa95f0e3b0eb58/watchfiles-1.0.5-cp310-cp310-win32.whl", hash = "sha256:cd47d063fbeabd4c6cae1d4bcaa38f0902f8dc5ed168072874ea11d0c7afc1ff", size = 277921, upload-time = "2025-04-08T10:34:56.318Z" }, - { url = "https://files.pythonhosted.org/packages/c2/3b/29a89de074a7d6e8b4dc67c26e03d73313e4ecf0d6e97e942a65fa7c195e/watchfiles-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:86c0df05b47a79d80351cd179893f2f9c1b1cae49d96e8b3290c7f4bd0ca0a92", size = 291526, upload-time = "2025-04-08T10:34:57.95Z" }, - { url = "https://files.pythonhosted.org/packages/39/f4/41b591f59021786ef517e1cdc3b510383551846703e03f204827854a96f8/watchfiles-1.0.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:237f9be419e977a0f8f6b2e7b0475ababe78ff1ab06822df95d914a945eac827", size = 405336, upload-time = "2025-04-08T10:34:59.359Z" }, - { url = "https://files.pythonhosted.org/packages/ae/06/93789c135be4d6d0e4f63e96eea56dc54050b243eacc28439a26482b5235/watchfiles-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0da39ff917af8b27a4bdc5a97ac577552a38aac0d260a859c1517ea3dc1a7c4", size = 395977, upload-time = "2025-04-08T10:35:00.522Z" }, - { url = "https://files.pythonhosted.org/packages/d2/db/1cd89bd83728ca37054512d4d35ab69b5f12b8aa2ac9be3b0276b3bf06cc/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cfcb3952350e95603f232a7a15f6c5f86c5375e46f0bd4ae70d43e3e063c13d", size = 455232, upload-time = "2025-04-08T10:35:01.698Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/d8a4d44ffe960517e487c9c04f77b06b8abf05eb680bed71c82b5f2cad62/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b2dddba7a4e6151384e252a5632efcaa9bc5d1c4b567f3cb621306b2ca9f63", size = 459151, upload-time = "2025-04-08T10:35:03.358Z" }, - { url = "https://files.pythonhosted.org/packages/6c/da/267a1546f26465dead1719caaba3ce660657f83c9d9c052ba98fb8856e13/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95cf944fcfc394c5f9de794ce581914900f82ff1f855326f25ebcf24d5397418", size = 489054, upload-time = "2025-04-08T10:35:04.561Z" }, - { url = "https://files.pythonhosted.org/packages/b1/31/33850dfd5c6efb6f27d2465cc4c6b27c5a6f5ed53c6fa63b7263cf5f60f6/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecf6cd9f83d7c023b1aba15d13f705ca7b7d38675c121f3cc4a6e25bd0857ee9", size = 523955, upload-time = "2025-04-08T10:35:05.786Z" }, - { url = "https://files.pythonhosted.org/packages/09/84/b7d7b67856efb183a421f1416b44ca975cb2ea6c4544827955dfb01f7dc2/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:852de68acd6212cd6d33edf21e6f9e56e5d98c6add46f48244bd479d97c967c6", size = 502234, upload-time = "2025-04-08T10:35:07.187Z" }, - { url = "https://files.pythonhosted.org/packages/71/87/6dc5ec6882a2254cfdd8b0718b684504e737273903b65d7338efaba08b52/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5730f3aa35e646103b53389d5bc77edfbf578ab6dab2e005142b5b80a35ef25", size = 454750, upload-time = "2025-04-08T10:35:08.859Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6c/3786c50213451a0ad15170d091570d4a6554976cf0df19878002fc96075a/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:18b3bd29954bc4abeeb4e9d9cf0b30227f0f206c86657674f544cb032296acd5", size = 631591, upload-time = "2025-04-08T10:35:10.64Z" }, - { url = "https://files.pythonhosted.org/packages/1b/b3/1427425ade4e359a0deacce01a47a26024b2ccdb53098f9d64d497f6684c/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ba5552a1b07c8edbf197055bc9d518b8f0d98a1c6a73a293bc0726dce068ed01", size = 625370, upload-time = "2025-04-08T10:35:12.412Z" }, - { url = "https://files.pythonhosted.org/packages/15/ba/f60e053b0b5b8145d682672024aa91370a29c5c921a88977eb565de34086/watchfiles-1.0.5-cp311-cp311-win32.whl", hash = "sha256:2f1fefb2e90e89959447bc0420fddd1e76f625784340d64a2f7d5983ef9ad246", size = 277791, upload-time = "2025-04-08T10:35:13.719Z" }, - { url = "https://files.pythonhosted.org/packages/50/ed/7603c4e164225c12c0d4e8700b64bb00e01a6c4eeea372292a3856be33a4/watchfiles-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:b6e76ceb1dd18c8e29c73f47d41866972e891fc4cc7ba014f487def72c1cf096", size = 291622, upload-time = "2025-04-08T10:35:15.071Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c2/99bb7c96b4450e36877fde33690ded286ff555b5a5c1d925855d556968a1/watchfiles-1.0.5-cp311-cp311-win_arm64.whl", hash = "sha256:266710eb6fddc1f5e51843c70e3bebfb0f5e77cf4f27129278c70554104d19ed", size = 283699, upload-time = "2025-04-08T10:35:16.732Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8c/4f0b9bdb75a1bfbd9c78fad7d8854369283f74fe7cf03eb16be77054536d/watchfiles-1.0.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5eb568c2aa6018e26da9e6c86f3ec3fd958cee7f0311b35c2630fa4217d17f2", size = 401511, upload-time = "2025-04-08T10:35:17.956Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4e/7e15825def77f8bd359b6d3f379f0c9dac4eb09dd4ddd58fd7d14127179c/watchfiles-1.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a04059f4923ce4e856b4b4e5e783a70f49d9663d22a4c3b3298165996d1377f", size = 392715, upload-time = "2025-04-08T10:35:19.202Z" }, - { url = "https://files.pythonhosted.org/packages/58/65/b72fb817518728e08de5840d5d38571466c1b4a3f724d190cec909ee6f3f/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e380c89983ce6e6fe2dd1e1921b9952fb4e6da882931abd1824c092ed495dec", size = 454138, upload-time = "2025-04-08T10:35:20.586Z" }, - { url = "https://files.pythonhosted.org/packages/3e/a4/86833fd2ea2e50ae28989f5950b5c3f91022d67092bfec08f8300d8b347b/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe43139b2c0fdc4a14d4f8d5b5d967f7a2777fd3d38ecf5b1ec669b0d7e43c21", size = 458592, upload-time = "2025-04-08T10:35:21.87Z" }, - { url = "https://files.pythonhosted.org/packages/38/7e/42cb8df8be9a37e50dd3a818816501cf7a20d635d76d6bd65aae3dbbff68/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee0822ce1b8a14fe5a066f93edd20aada932acfe348bede8aa2149f1a4489512", size = 487532, upload-time = "2025-04-08T10:35:23.143Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/13d26721c85d7f3df6169d8b495fcac8ab0dc8f0945ebea8845de4681dab/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0dbcb1c2d8f2ab6e0a81c6699b236932bd264d4cef1ac475858d16c403de74d", size = 522865, upload-time = "2025-04-08T10:35:24.702Z" }, - { url = "https://files.pythonhosted.org/packages/a1/0d/7f9ae243c04e96c5455d111e21b09087d0eeaf9a1369e13a01c7d3d82478/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2014a2b18ad3ca53b1f6c23f8cd94a18ce930c1837bd891262c182640eb40a6", size = 499887, upload-time = "2025-04-08T10:35:25.969Z" }, - { url = "https://files.pythonhosted.org/packages/8e/0f/a257766998e26aca4b3acf2ae97dff04b57071e991a510857d3799247c67/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6ae86d5cb647bf58f9f655fcf577f713915a5d69057a0371bc257e2553234", size = 454498, upload-time = "2025-04-08T10:35:27.353Z" }, - { url = "https://files.pythonhosted.org/packages/81/79/8bf142575a03e0af9c3d5f8bcae911ee6683ae93a625d349d4ecf4c8f7df/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1a7bac2bde1d661fb31f4d4e8e539e178774b76db3c2c17c4bb3e960a5de07a2", size = 630663, upload-time = "2025-04-08T10:35:28.685Z" }, - { url = "https://files.pythonhosted.org/packages/f1/80/abe2e79f610e45c63a70d271caea90c49bbf93eb00fa947fa9b803a1d51f/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ab626da2fc1ac277bbf752446470b367f84b50295264d2d313e28dc4405d663", size = 625410, upload-time = "2025-04-08T10:35:30.42Z" }, - { url = "https://files.pythonhosted.org/packages/91/6f/bc7fbecb84a41a9069c2c6eb6319f7f7df113adf113e358c57fc1aff7ff5/watchfiles-1.0.5-cp312-cp312-win32.whl", hash = "sha256:9f4571a783914feda92018ef3901dab8caf5b029325b5fe4558c074582815249", size = 277965, upload-time = "2025-04-08T10:35:32.023Z" }, - { url = "https://files.pythonhosted.org/packages/99/a5/bf1c297ea6649ec59e935ab311f63d8af5faa8f0b86993e3282b984263e3/watchfiles-1.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:360a398c3a19672cf93527f7e8d8b60d8275119c5d900f2e184d32483117a705", size = 291693, upload-time = "2025-04-08T10:35:33.225Z" }, - { url = "https://files.pythonhosted.org/packages/7f/7b/fd01087cc21db5c47e5beae507b87965db341cce8a86f9eb12bf5219d4e0/watchfiles-1.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:1a2902ede862969077b97523987c38db28abbe09fb19866e711485d9fbf0d417", size = 283287, upload-time = "2025-04-08T10:35:34.568Z" }, - { url = "https://files.pythonhosted.org/packages/c7/62/435766874b704f39b2fecd8395a29042db2b5ec4005bd34523415e9bd2e0/watchfiles-1.0.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0b289572c33a0deae62daa57e44a25b99b783e5f7aed81b314232b3d3c81a11d", size = 401531, upload-time = "2025-04-08T10:35:35.792Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a6/e52a02c05411b9cb02823e6797ef9bbba0bfaf1bb627da1634d44d8af833/watchfiles-1.0.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a056c2f692d65bf1e99c41045e3bdcaea3cb9e6b5a53dcaf60a5f3bd95fc9763", size = 392417, upload-time = "2025-04-08T10:35:37.048Z" }, - { url = "https://files.pythonhosted.org/packages/3f/53/c4af6819770455932144e0109d4854437769672d7ad897e76e8e1673435d/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9dca99744991fc9850d18015c4f0438865414e50069670f5f7eee08340d8b40", size = 453423, upload-time = "2025-04-08T10:35:38.357Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d1/8e88df58bbbf819b8bc5cfbacd3c79e01b40261cad0fc84d1e1ebd778a07/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:894342d61d355446d02cd3988a7326af344143eb33a2fd5d38482a92072d9563", size = 458185, upload-time = "2025-04-08T10:35:39.708Z" }, - { url = "https://files.pythonhosted.org/packages/ff/70/fffaa11962dd5429e47e478a18736d4e42bec42404f5ee3b92ef1b87ad60/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab44e1580924d1ffd7b3938e02716d5ad190441965138b4aa1d1f31ea0877f04", size = 486696, upload-time = "2025-04-08T10:35:41.469Z" }, - { url = "https://files.pythonhosted.org/packages/39/db/723c0328e8b3692d53eb273797d9a08be6ffb1d16f1c0ba2bdbdc2a3852c/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6f9367b132078b2ceb8d066ff6c93a970a18c3029cea37bfd7b2d3dd2e5db8f", size = 522327, upload-time = "2025-04-08T10:35:43.289Z" }, - { url = "https://files.pythonhosted.org/packages/cd/05/9fccc43c50c39a76b68343484b9da7b12d42d0859c37c61aec018c967a32/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2e55a9b162e06e3f862fb61e399fe9f05d908d019d87bf5b496a04ef18a970a", size = 499741, upload-time = "2025-04-08T10:35:44.574Z" }, - { url = "https://files.pythonhosted.org/packages/23/14/499e90c37fa518976782b10a18b18db9f55ea73ca14641615056f8194bb3/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0125f91f70e0732a9f8ee01e49515c35d38ba48db507a50c5bdcad9503af5827", size = 453995, upload-time = "2025-04-08T10:35:46.336Z" }, - { url = "https://files.pythonhosted.org/packages/61/d9/f75d6840059320df5adecd2c687fbc18960a7f97b55c300d20f207d48aef/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:13bb21f8ba3248386337c9fa51c528868e6c34a707f729ab041c846d52a0c69a", size = 629693, upload-time = "2025-04-08T10:35:48.161Z" }, - { url = "https://files.pythonhosted.org/packages/fc/17/180ca383f5061b61406477218c55d66ec118e6c0c51f02d8142895fcf0a9/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:839ebd0df4a18c5b3c1b890145b5a3f5f64063c2a0d02b13c76d78fe5de34936", size = 624677, upload-time = "2025-04-08T10:35:49.65Z" }, - { url = "https://files.pythonhosted.org/packages/bf/15/714d6ef307f803f236d69ee9d421763707899d6298d9f3183e55e366d9af/watchfiles-1.0.5-cp313-cp313-win32.whl", hash = "sha256:4a8ec1e4e16e2d5bafc9ba82f7aaecfeec990ca7cd27e84fb6f191804ed2fcfc", size = 277804, upload-time = "2025-04-08T10:35:51.093Z" }, - { url = "https://files.pythonhosted.org/packages/a8/b4/c57b99518fadf431f3ef47a610839e46e5f8abf9814f969859d1c65c02c7/watchfiles-1.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:f436601594f15bf406518af922a89dcaab416568edb6f65c4e5bbbad1ea45c11", size = 291087, upload-time = "2025-04-08T10:35:52.458Z" }, - { url = "https://files.pythonhosted.org/packages/1a/03/81f9fcc3963b3fc415cd4b0b2b39ee8cc136c42fb10a36acf38745e9d283/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f59b870db1f1ae5a9ac28245707d955c8721dd6565e7f411024fa374b5362d1d", size = 405947, upload-time = "2025-04-08T10:36:13.721Z" }, - { url = "https://files.pythonhosted.org/packages/54/97/8c4213a852feb64807ec1d380f42d4fc8bfaef896bdbd94318f8fd7f3e4e/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9475b0093767e1475095f2aeb1d219fb9664081d403d1dff81342df8cd707034", size = 397276, upload-time = "2025-04-08T10:36:15.131Z" }, - { url = "https://files.pythonhosted.org/packages/78/12/d4464d19860cb9672efa45eec1b08f8472c478ed67dcd30647c51ada7aef/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc533aa50664ebd6c628b2f30591956519462f5d27f951ed03d6c82b2dfd9965", size = 455550, upload-time = "2025-04-08T10:36:16.635Z" }, - { url = "https://files.pythonhosted.org/packages/90/fb/b07bcdf1034d8edeaef4c22f3e9e3157d37c5071b5f9492ffdfa4ad4bed7/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed1cd825158dcaae36acce7b2db33dcbfd12b30c34317a88b8ed80f0541cc57", size = 455542, upload-time = "2025-04-08T10:36:18.655Z" }, -] - -[[package]] -name = "web3" -version = "7.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "eth-abi" }, - { name = "eth-account" }, - { name = "eth-hash", extra = ["pycryptodome"] }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "pyunormalize" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "requests" }, - { name = "types-requests" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7d/1e/fc1f5b5a12615cbdca57d35014cdb9823db7392d73b730fa0d89d6a13f6a/web3-7.12.0.tar.gz", hash = "sha256:08fbe79a2e2503c9820132ebad24ba0372831588cabac5f467999c97ace7dda3", size = 2195693, upload-time = "2025-05-22T21:06:05.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/df/0ccf18f244b96a93ba2710f7ce696da1f8dd44ef1126e3603dfb65cd68fe/web3-7.12.0-py3-none-any.whl", hash = "sha256:c7e2b9c1db5a379ef53b45fe8a19bdc2d47ad262039fbf6675794bc40f74bf06", size = 1369328, upload-time = "2025-05-22T21:06:03.124Z" }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, - { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, - { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, - { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, - { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, - { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, - { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, - { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, - { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - -[[package]] -name = "werkzeug" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, -] - -[[package]] -name = "x402" -version = "1.0.0" -source = { editable = "../../../../../python/legacy" } -dependencies = [ - { name = "eth-account" }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "fastapi", extra = ["standard"] }, - { name = "flask" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "web3" }, -] - -[package.metadata] -requires-dist = [ - { name = "eth-account", specifier = ">=0.13.7" }, - { name = "eth-typing", specifier = ">=4.0.0" }, - { name = "eth-utils", specifier = ">=3.0.0" }, - { name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" }, - { name = "flask", specifier = ">=3.0.0" }, - { name = "pydantic", specifier = ">=2.10.3" }, - { name = "pydantic-settings", specifier = ">=2.2.1" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "web3", specifier = ">=6.0.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.5" }, - { name = "pytest-asyncio", specifier = ">=1.0.0" }, - { name = "ruff", specifier = ">=0.11.9" }, -] - -[[package]] -name = "x402-httpx-example" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "eth-account" }, - { name = "httpx" }, - { name = "x402" }, -] - -[package.metadata] -requires-dist = [ - { name = "eth-account", specifier = ">=0.8.0" }, - { name = "httpx", specifier = ">=0.24.0" }, - { name = "x402", editable = "../../../../../python/legacy" }, -] - -[[package]] -name = "yarl" -version = "1.20.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/65/7fed0d774abf47487c64be14e9223749468922817b5e8792b8a64792a1bb/yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4", size = 132910, upload-time = "2025-06-10T00:42:31.108Z" }, - { url = "https://files.pythonhosted.org/packages/8a/7b/988f55a52da99df9e56dc733b8e4e5a6ae2090081dc2754fc8fd34e60aa0/yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a", size = 90644, upload-time = "2025-06-10T00:42:33.851Z" }, - { url = "https://files.pythonhosted.org/packages/f7/de/30d98f03e95d30c7e3cc093759982d038c8833ec2451001d45ef4854edc1/yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed", size = 89322, upload-time = "2025-06-10T00:42:35.688Z" }, - { url = "https://files.pythonhosted.org/packages/e0/7a/f2f314f5ebfe9200724b0b748de2186b927acb334cf964fd312eb86fc286/yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e", size = 323786, upload-time = "2025-06-10T00:42:37.817Z" }, - { url = "https://files.pythonhosted.org/packages/15/3f/718d26f189db96d993d14b984ce91de52e76309d0fd1d4296f34039856aa/yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73", size = 319627, upload-time = "2025-06-10T00:42:39.937Z" }, - { url = "https://files.pythonhosted.org/packages/a5/76/8fcfbf5fa2369157b9898962a4a7d96764b287b085b5b3d9ffae69cdefd1/yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e", size = 339149, upload-time = "2025-06-10T00:42:42.627Z" }, - { url = "https://files.pythonhosted.org/packages/3c/95/d7fc301cc4661785967acc04f54a4a42d5124905e27db27bb578aac49b5c/yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8", size = 333327, upload-time = "2025-06-10T00:42:44.842Z" }, - { url = "https://files.pythonhosted.org/packages/65/94/e21269718349582eee81efc5c1c08ee71c816bfc1585b77d0ec3f58089eb/yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23", size = 326054, upload-time = "2025-06-10T00:42:47.149Z" }, - { url = "https://files.pythonhosted.org/packages/32/ae/8616d1f07853704523519f6131d21f092e567c5af93de7e3e94b38d7f065/yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70", size = 315035, upload-time = "2025-06-10T00:42:48.852Z" }, - { url = "https://files.pythonhosted.org/packages/48/aa/0ace06280861ef055855333707db5e49c6e3a08840a7ce62682259d0a6c0/yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb", size = 338962, upload-time = "2025-06-10T00:42:51.024Z" }, - { url = "https://files.pythonhosted.org/packages/20/52/1e9d0e6916f45a8fb50e6844f01cb34692455f1acd548606cbda8134cd1e/yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2", size = 335399, upload-time = "2025-06-10T00:42:53.007Z" }, - { url = "https://files.pythonhosted.org/packages/f2/65/60452df742952c630e82f394cd409de10610481d9043aa14c61bf846b7b1/yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30", size = 338649, upload-time = "2025-06-10T00:42:54.964Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f5/6cd4ff38dcde57a70f23719a838665ee17079640c77087404c3d34da6727/yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309", size = 358563, upload-time = "2025-06-10T00:42:57.28Z" }, - { url = "https://files.pythonhosted.org/packages/d1/90/c42eefd79d0d8222cb3227bdd51b640c0c1d0aa33fe4cc86c36eccba77d3/yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24", size = 357609, upload-time = "2025-06-10T00:42:59.055Z" }, - { url = "https://files.pythonhosted.org/packages/03/c8/cea6b232cb4617514232e0f8a718153a95b5d82b5290711b201545825532/yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13", size = 350224, upload-time = "2025-06-10T00:43:01.248Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a3/eaa0ab9712f1f3d01faf43cf6f1f7210ce4ea4a7e9b28b489a2261ca8db9/yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8", size = 81753, upload-time = "2025-06-10T00:43:03.486Z" }, - { url = "https://files.pythonhosted.org/packages/8f/34/e4abde70a9256465fe31c88ed02c3f8502b7b5dead693a4f350a06413f28/yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16", size = 86817, upload-time = "2025-06-10T00:43:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b1/18/893b50efc2350e47a874c5c2d67e55a0ea5df91186b2a6f5ac52eff887cd/yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e", size = 133833, upload-time = "2025-06-10T00:43:07.393Z" }, - { url = "https://files.pythonhosted.org/packages/89/ed/b8773448030e6fc47fa797f099ab9eab151a43a25717f9ac043844ad5ea3/yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b", size = 91070, upload-time = "2025-06-10T00:43:09.538Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e3/409bd17b1e42619bf69f60e4f031ce1ccb29bd7380117a55529e76933464/yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b", size = 89818, upload-time = "2025-06-10T00:43:11.575Z" }, - { url = "https://files.pythonhosted.org/packages/f8/77/64d8431a4d77c856eb2d82aa3de2ad6741365245a29b3a9543cd598ed8c5/yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4", size = 347003, upload-time = "2025-06-10T00:43:14.088Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d2/0c7e4def093dcef0bd9fa22d4d24b023788b0a33b8d0088b51aa51e21e99/yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1", size = 336537, upload-time = "2025-06-10T00:43:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f3/fc514f4b2cf02cb59d10cbfe228691d25929ce8f72a38db07d3febc3f706/yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833", size = 362358, upload-time = "2025-06-10T00:43:18.704Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6d/a313ac8d8391381ff9006ac05f1d4331cee3b1efaa833a53d12253733255/yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d", size = 357362, upload-time = "2025-06-10T00:43:20.888Z" }, - { url = "https://files.pythonhosted.org/packages/00/70/8f78a95d6935a70263d46caa3dd18e1f223cf2f2ff2037baa01a22bc5b22/yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8", size = 348979, upload-time = "2025-06-10T00:43:23.169Z" }, - { url = "https://files.pythonhosted.org/packages/cb/05/42773027968968f4f15143553970ee36ead27038d627f457cc44bbbeecf3/yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf", size = 337274, upload-time = "2025-06-10T00:43:27.111Z" }, - { url = "https://files.pythonhosted.org/packages/05/be/665634aa196954156741ea591d2f946f1b78ceee8bb8f28488bf28c0dd62/yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e", size = 363294, upload-time = "2025-06-10T00:43:28.96Z" }, - { url = "https://files.pythonhosted.org/packages/eb/90/73448401d36fa4e210ece5579895731f190d5119c4b66b43b52182e88cd5/yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389", size = 358169, upload-time = "2025-06-10T00:43:30.701Z" }, - { url = "https://files.pythonhosted.org/packages/c3/b0/fce922d46dc1eb43c811f1889f7daa6001b27a4005587e94878570300881/yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f", size = 362776, upload-time = "2025-06-10T00:43:32.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/0d/b172628fce039dae8977fd22caeff3eeebffd52e86060413f5673767c427/yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845", size = 381341, upload-time = "2025-06-10T00:43:34.543Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9b/5b886d7671f4580209e855974fe1cecec409aa4a89ea58b8f0560dc529b1/yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1", size = 379988, upload-time = "2025-06-10T00:43:36.489Z" }, - { url = "https://files.pythonhosted.org/packages/73/be/75ef5fd0fcd8f083a5d13f78fd3f009528132a1f2a1d7c925c39fa20aa79/yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e", size = 371113, upload-time = "2025-06-10T00:43:38.592Z" }, - { url = "https://files.pythonhosted.org/packages/50/4f/62faab3b479dfdcb741fe9e3f0323e2a7d5cd1ab2edc73221d57ad4834b2/yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773", size = 81485, upload-time = "2025-06-10T00:43:41.038Z" }, - { url = "https://files.pythonhosted.org/packages/f0/09/d9c7942f8f05c32ec72cd5c8e041c8b29b5807328b68b4801ff2511d4d5e/yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e", size = 86686, upload-time = "2025-06-10T00:43:42.692Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, - { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, - { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, - { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, - { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, - { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, - { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, - { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, - { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, - { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, - { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, - { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, - { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, - { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, - { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, - { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, - { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, - { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, - { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, - { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, - { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, - { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, - { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, - { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, - { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, - { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, - { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, - { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, - { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, - { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, - { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, - { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, - { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, - { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, - { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, - { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, - { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, -] diff --git a/examples/python/legacy/clients/requests/.env-local b/examples/python/legacy/clients/requests/.env-local deleted file mode 100644 index 8504936460..0000000000 --- a/examples/python/legacy/clients/requests/.env-local +++ /dev/null @@ -1,3 +0,0 @@ -RESOURCE_SERVER_URL=http://localhost:4021 -ENDPOINT_PATH=/weather -PRIVATE_KEY= \ No newline at end of file diff --git a/examples/python/legacy/clients/requests/README.md b/examples/python/legacy/clients/requests/README.md deleted file mode 100644 index 80fa16f96d..0000000000 --- a/examples/python/legacy/clients/requests/README.md +++ /dev/null @@ -1,62 +0,0 @@ -# x402 requests Client Example - -This example demonstrates two different approaches to use the x402 package with requests to make requests to 402-protected endpoints. - -## Setup and Usage - -1. Copy `.env-local` to `.env` and add your private key. - -```bash -cp .env-local .env -``` - -2. Install dependencies: -```bash -uv sync -``` - -3. Run one of the examples: -```bash -# Simple approach -python main.py - -# Extensible approach -python extensible.py -``` - -## Two Integration Approaches - -### Simple Approach (main.py) - -The simple approach uses `x402_requests`, which returns a pre-configured session that handles payments automatically: - -```python -from x402.clients import x402_requests - -session = x402_requests(account) -response = session.get(url) -``` - -### Extensible Approach (extensible.py) - -The extensible approach uses `x402_http_adapter` with your own requests session: - -```python -from x402.clients import x402_http_adapter -import requests - -session = requests.Session() -adapter = x402_http_adapter(account) -session.mount("http://", adapter) -session.mount("https://", adapter) -response = session.get(url) -``` - -## How it Works - -Both examples: -1. Initialize an eth_account.Account instance from a private key -2. Configure the requests session with x402 payment handling -3. Make a request to a protected endpoint -4. Handle the 402 Payment Required response automatically -5. Print the final response diff --git a/examples/python/legacy/clients/requests/extensible.py b/examples/python/legacy/clients/requests/extensible.py deleted file mode 100644 index 312dfa0325..0000000000 --- a/examples/python/legacy/clients/requests/extensible.py +++ /dev/null @@ -1,59 +0,0 @@ -import os -from dotenv import load_dotenv -from eth_account import Account -from x402.clients.requests import x402_http_adapter -from x402.clients.base import decode_x_payment_response -import requests - -# Load environment variables -load_dotenv() - -# Get environment variables -private_key = os.getenv("PRIVATE_KEY") -base_url = os.getenv("RESOURCE_SERVER_URL") -endpoint_path = os.getenv("ENDPOINT_PATH") - -if not all([private_key, base_url, endpoint_path]): - print("Error: Missing required environment variables") - exit(1) - -# Create eth_account from private key -account = Account.from_key(private_key) -print(f"Initialized account: {account.address}") - - -def main(): - # Create a session and mount the x402 adapter - session = requests.Session() - adapter = x402_http_adapter(account) - - # Mount the adapter for both HTTP and HTTPS - session.mount("http://", adapter) - session.mount("https://", adapter) - - # Make request - try: - print(f"Making request to {endpoint_path}") - response = session.get(f"{base_url}{endpoint_path}") - - # Read the response content - content = response.content - print(f"Response: {content.decode()}") - - # Check for payment response header - if "X-Payment-Response" in response.headers: - payment_response = decode_x_payment_response( - response.headers["X-Payment-Response"] - ) - print( - f"Payment response transaction hash: {payment_response['transaction']}" - ) - else: - print("Warning: No payment response header found") - - except Exception as e: - print(f"Error occurred: {str(e)}") - - -if __name__ == "__main__": - main() diff --git a/examples/python/legacy/clients/requests/main.py b/examples/python/legacy/clients/requests/main.py deleted file mode 100644 index 148b9d92ec..0000000000 --- a/examples/python/legacy/clients/requests/main.py +++ /dev/null @@ -1,76 +0,0 @@ -import os -from dotenv import load_dotenv -from eth_account import Account -from x402.clients.requests import x402_requests -from x402.clients.base import decode_x_payment_response, x402Client - -# Load environment variables -load_dotenv() - -# Get environment variables -private_key = os.getenv("PRIVATE_KEY") -base_url = os.getenv("RESOURCE_SERVER_URL") -endpoint_path = os.getenv("ENDPOINT_PATH") - -if not all([private_key, base_url, endpoint_path]): - print("Error: Missing required environment variables") - exit(1) - -# Create eth_account from private key -account = Account.from_key(private_key) -print(f"Initialized account: {account.address}") - - -def custom_payment_selector( - accepts, network_filter=None, scheme_filter=None, max_value=None -): - """Custom payment selector that filters by network.""" - # Ignore the network_filter parameter for this example - we hardcode base-sepolia - _ = network_filter - - # NOTE: In a real application, you'd want to dynamically choose the most - # appropriate payment requirement based on user preferences, available funds, - # network conditions, or other business logic rather than hardcoding a network. - - # Filter by base-sepolia network (testnet) - return x402Client.default_payment_requirements_selector( - accepts, - network_filter="base-sepolia", - scheme_filter=scheme_filter, - max_value=max_value, - ) - - -def main(): - # Create requests session with x402 payment handling and network filtering - session = x402_requests( - account, - payment_requirements_selector=custom_payment_selector, - ) - - # Make request - try: - print(f"Making request to {endpoint_path}") - response = session.get(f"{base_url}{endpoint_path}") - - # Read the response content - content = response.content - print(f"Response: {content.decode()}") - - # Check for payment response header - if "X-Payment-Response" in response.headers: - payment_response = decode_x_payment_response( - response.headers["X-Payment-Response"] - ) - print( - f"Payment response transaction hash: {payment_response['transaction']}" - ) - else: - print("Warning: No payment response header found") - - except Exception as e: - print(f"Error occurred: {str(e)}") - - -if __name__ == "__main__": - main() diff --git a/examples/python/legacy/clients/requests/pyproject.toml b/examples/python/legacy/clients/requests/pyproject.toml deleted file mode 100644 index 99cd68ad3f..0000000000 --- a/examples/python/legacy/clients/requests/pyproject.toml +++ /dev/null @@ -1,26 +0,0 @@ -[project] -name = "x402-requests-example" -version = "0.1.0" -description = "Example of using x402 with requests" -requires-python = ">=3.10" -dependencies = [ - "requests>=2.31.0", - "eth-account>=0.8.0", - "x402" -] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -packages = ["."] - -[tool.hatch.metadata] -allow-direct-references = true - -[tool.uv] -package = false - -[tool.uv.sources] -x402 = { path = "../../../../../python/legacy", editable = true } diff --git a/examples/python/legacy/clients/requests/uv.lock b/examples/python/legacy/clients/requests/uv.lock deleted file mode 100644 index d9afd69cf4..0000000000 --- a/examples/python/legacy/clients/requests/uv.lock +++ /dev/null @@ -1,1973 +0,0 @@ -version = 1 -revision = 2 -requires-python = ">=3.10" - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, -] - -[[package]] -name = "aiohttp" -version = "3.12.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f2/84/ea27e6ad14747d8c51afe201fb88a5c8282b6278256d30a6f71f730add88/aiohttp-3.12.12.tar.gz", hash = "sha256:05875595d2483d96cb61fa9f64e75262d7ac6251a7e3c811d8e26f7d721760bd", size = 7818643, upload-time = "2025-06-10T05:22:00.247Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/d9/cfde93b9cb75253c716b8b1c773565209e3d4dd0772dd3ce3a2adcaa4639/aiohttp-3.12.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6f25e9d274d6abbb15254f76f100c3984d6b9ad6e66263cc60a465dd5c7e48f5", size = 702071, upload-time = "2025-06-10T05:18:23.986Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/46e38b8bc0bc645317deec32612af922ad9bafd85a1df255a67c2f2305f6/aiohttp-3.12.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b8ec3c1a1c13d24941b5b913607e57b9364e4c0ea69d5363181467492c4b2ba6", size = 478436, upload-time = "2025-06-10T05:18:28.411Z" }, - { url = "https://files.pythonhosted.org/packages/8f/47/9c83db7f02ca71eb99a707ee13657fc24ba703b9babc59000c1f58ac1198/aiohttp-3.12.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81ef2f9253c327c211cb7b06ea2edd90e637cf21c347b894d540466b8d304e08", size = 466213, upload-time = "2025-06-10T05:18:30.706Z" }, - { url = "https://files.pythonhosted.org/packages/31/fe/4690c112e269e06c9182c32eeb43f3a95c4f203fdb095502717327993b80/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28ded835c3663fd41c9ad44685811b11e34e6ac9a7516a30bfce13f6abba4496", size = 1648258, upload-time = "2025-06-10T05:18:32.498Z" }, - { url = "https://files.pythonhosted.org/packages/c8/1f/dacca6c7bbe69c77d8535d7a672478803e7078cc20fd9993fe09aa5be880/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a4b78ccf254fc10605b263996949a94ca3f50e4f9100e05137d6583e266b711e", size = 1622316, upload-time = "2025-06-10T05:18:34.357Z" }, - { url = "https://files.pythonhosted.org/packages/ff/65/5ef47708f70524fcdecda735e0aea06e0feb7b8679e976e9bd1e7900f4c0/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f4a5af90d5232c41bb857568fe7d11ed84408653ec9da1ff999cc30258b9bd1", size = 1694723, upload-time = "2025-06-10T05:18:36.858Z" }, - { url = "https://files.pythonhosted.org/packages/18/62/ab32bfa59f61292e4096c383316863e10001eec30e5b4b314856ed7156e2/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffa5205c2f53f1120e93fdf2eca41b0f6344db131bc421246ee82c1e1038a14a", size = 1737037, upload-time = "2025-06-10T05:18:39.663Z" }, - { url = "https://files.pythonhosted.org/packages/c1/b9/8b8f793081311e4f63aea63003a519064048e406c627c0454d6ed09dbc99/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68301660f0d7a3eddfb84f959f78a8f9db98c76a49b5235508fa16edaad0f7c", size = 1641701, upload-time = "2025-06-10T05:18:41.666Z" }, - { url = "https://files.pythonhosted.org/packages/1a/5c/72f510d42d626463b526345dcb8d14b390de89a9ba27a4717b518460bcd4/aiohttp-3.12.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db874d3b0c92fdbb553751af9d2733b378c25cc83cd9dfba87f12fafd2dc9cd5", size = 1581824, upload-time = "2025-06-10T05:18:44.136Z" }, - { url = "https://files.pythonhosted.org/packages/61/6f/9378c9e1543d1c800ca040e21cd333b8f923ed051ae82b5a49ad96a6ac71/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5e53cf9c201b45838a2d07b1f2d5f7fec9666db7979240002ce64f9b8a1e0cf2", size = 1625674, upload-time = "2025-06-10T05:18:46.716Z" }, - { url = "https://files.pythonhosted.org/packages/bb/85/4eef9bd52b497a405c88469cc099f4d15d33b149b5746ca4ef8ec6ab6388/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:8687cc5f32b4e328c233acd387d09a1b477007896b2f03c1c823a0fd05f63883", size = 1636460, upload-time = "2025-06-10T05:18:49.305Z" }, - { url = "https://files.pythonhosted.org/packages/56/59/d8e954830b375fd658843cf7d88d27ca5e38dd5fcbfe62db3d1ba415d0fe/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ee537ad29de716a3d8dc46c609908de0c25ffeebf93cd94a03d64cdc07d66d0", size = 1611912, upload-time = "2025-06-10T05:18:51.694Z" }, - { url = "https://files.pythonhosted.org/packages/c3/5d/d0096a02f0515a38dff67db42d966273a12d17fc895e91466bfb4ab3875e/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:411f821be5af6af11dc5bed6c6c1dc6b6b25b91737d968ec2756f9baa75e5f9b", size = 1691498, upload-time = "2025-06-10T05:18:54.36Z" }, - { url = "https://files.pythonhosted.org/packages/87/8d/d3a02397a6345c06623ae4648e2aef18fced858510b4a89d7262cfa4c683/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f90319d94cf5f9786773237f24bd235a7b5959089f1af8ec1154580a3434b503", size = 1714737, upload-time = "2025-06-10T05:18:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/a9/40/b81000bf07c96db878703ea3dc561393d82441597729910459a8e06acc9a/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:73b148e606f34e9d513c451fd65efe1091772659ca5703338a396a99f60108ff", size = 1643078, upload-time = "2025-06-10T05:18:59.33Z" }, - { url = "https://files.pythonhosted.org/packages/41/e5/31830642ce2c6d3dba74ed8a94933213df5e1651c1e8b4efc81cc88105ab/aiohttp-3.12.12-cp310-cp310-win32.whl", hash = "sha256:d40e7bfd577fdc8a92b72f35dfbdd3ec90f1bc8a72a42037fefe34d4eca2d4a1", size = 427517, upload-time = "2025-06-10T05:19:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/55/9d/a4e5379d44679e5f8d7d7ebecb0dae8cafab95176c4e753da6bc4b4aebb5/aiohttp-3.12.12-cp310-cp310-win_amd64.whl", hash = "sha256:65c7804a2343893d6dea9fce69811aea0a9ac47f68312cf2e3ee1668cd9a387f", size = 450725, upload-time = "2025-06-10T05:19:03.874Z" }, - { url = "https://files.pythonhosted.org/packages/47/1f/b1b66e05dc3066a9ba7862d50e2e95b3871db82ccf9652568845f353eeba/aiohttp-3.12.12-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:38823fe0d8bc059b3eaedb263fe427d887c7032e72b4ef92c472953285f0e658", size = 709385, upload-time = "2025-06-10T05:19:05.763Z" }, - { url = "https://files.pythonhosted.org/packages/43/e6/3230e42af16438b450b1e193c537fd3d2d31771dafda3c2105a8d11af707/aiohttp-3.12.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:10237f2c34711215d04ed21da63852ce023608299554080a45c576215d9df81c", size = 481660, upload-time = "2025-06-10T05:19:08.332Z" }, - { url = "https://files.pythonhosted.org/packages/06/ba/cfa91fe5cc262535e1175b1522d8fcc09f9d6ad18b85241f4ee3be1d780f/aiohttp-3.12.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:563ec477c0dc6d56fc7f943a3475b5acdb399c7686c30f5a98ada24bb7562c7a", size = 469924, upload-time = "2025-06-10T05:19:10.342Z" }, - { url = "https://files.pythonhosted.org/packages/9a/f0/5c706cfddd4769b55c0cda466aa6034412d39e416f0b30dda81c4a24616f/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3d05c46a61aca7c47df74afff818bc06a251ab95d95ff80b53665edfe1e0bdf", size = 1740116, upload-time = "2025-06-10T05:19:12.783Z" }, - { url = "https://files.pythonhosted.org/packages/4d/9f/04dba2e1c8bee53c3c623d11a1f947c9e2712500f734dc0dfd06daad32ec/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:277c882916759b4a6b6dc7e2ceb124aad071b3c6456487808d9ab13e1b448d57", size = 1688784, upload-time = "2025-06-10T05:19:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/df/24/19d6d4c41fbf8304fe7c111fcc701e0aa5a2232ee3ac16272677a11f9cfe/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:216abf74b324b0f4e67041dd4fb2819613909a825904f8a51701fbcd40c09cd7", size = 1787575, upload-time = "2025-06-10T05:19:18.586Z" }, - { url = "https://files.pythonhosted.org/packages/0c/59/01f4c55a1f91ad3b5255b2498b3a22362a3fe6ee9bc9ba1af3cc668244da/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65d6cefad286459b68e7f867b9586a821fb7f121057b88f02f536ef570992329", size = 1826621, upload-time = "2025-06-10T05:19:21.284Z" }, - { url = "https://files.pythonhosted.org/packages/55/85/6357166918ff5025602a7cc41332c1ae7a5b57f2fe3da4d755ae30f24bd0/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feaaaff61966b5f4b4eae0b79fc79427f49484e4cfa5ab7d138ecd933ab540a8", size = 1729082, upload-time = "2025-06-10T05:19:23.307Z" }, - { url = "https://files.pythonhosted.org/packages/e3/ca/de3b5ccd5a2aa9352f6ec6f446565f6e1601ebb54860c94c686a9ff76660/aiohttp-3.12.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a05917780b7cad1755784b16cfaad806bc16029a93d15f063ca60185b7d9ba05", size = 1666159, upload-time = "2025-06-10T05:19:25.929Z" }, - { url = "https://files.pythonhosted.org/packages/d1/69/a1006021a1d3244c0872ee75cd8da150e0098b3b2ec6945c225754d11a60/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:082c5ec6d262c1b2ee01c63f4fb9152c17f11692bf16f0f100ad94a7a287d456", size = 1714433, upload-time = "2025-06-10T05:19:28.044Z" }, - { url = "https://files.pythonhosted.org/packages/d2/2a/15aa1179e9fbdd0d17cdf117b4296dedad098abb5a93f8e9c8ab4626f6ea/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:b265a3a8b379b38696ac78bdef943bdc4f4a5d6bed1a3fb5c75c6bab1ecea422", size = 1709590, upload-time = "2025-06-10T05:19:30.165Z" }, - { url = "https://files.pythonhosted.org/packages/a2/f0/95ed9e21250815f1d1a0cd3e868a3f39400a16010ae59f19ddd4ccc4e787/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2e0f2e208914ecbc4b2a3b7b4daa759d0c587d9a0b451bb0835ac47fae7fa735", size = 1689776, upload-time = "2025-06-10T05:19:32.965Z" }, - { url = "https://files.pythonhosted.org/packages/81/4d/370ecc133c648c98a85445f2d331c1272859c89cd52c29a293015bc352c7/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9923b025845b72f64d167bca221113377c8ffabd0a351dc18fb839d401ee8e22", size = 1783378, upload-time = "2025-06-10T05:19:35.14Z" }, - { url = "https://files.pythonhosted.org/packages/a8/86/414e3dae7e07caf6b02cd75d7148d0d8673d4c5077f407be3627d6e33fac/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1ebb213445900527831fecc70e185bf142fdfe5f2a691075f22d63c65ee3c35a", size = 1803841, upload-time = "2025-06-10T05:19:37.41Z" }, - { url = "https://files.pythonhosted.org/packages/88/df/486f10df681cd1a8c898acc8dc2edbd46ffb088b886757b71ae362bf44d3/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6fc369fb273a8328077d37798b77c1e65676709af5c182cb74bd169ca9defe81", size = 1716896, upload-time = "2025-06-10T05:19:40.172Z" }, - { url = "https://files.pythonhosted.org/packages/07/1e/1cacaf5d838869432e96ece1580d0b51494ebb66351f0e8118b74b38d2f0/aiohttp-3.12.12-cp311-cp311-win32.whl", hash = "sha256:58ecd10fda6a44c311cd3742cfd2aea8c4c600338e9f27cb37434d9f5ca9ddaa", size = 427030, upload-time = "2025-06-10T05:19:42.152Z" }, - { url = "https://files.pythonhosted.org/packages/30/dd/e89c1d190da2c84e0ca03c2970b9988a9c56005d18db7f447cf62b3ae6d0/aiohttp-3.12.12-cp311-cp311-win_amd64.whl", hash = "sha256:b0066e88f30be00badffb5ef8f2281532b9a9020863d873ae15f7c147770b6ec", size = 451419, upload-time = "2025-06-10T05:19:44.176Z" }, - { url = "https://files.pythonhosted.org/packages/df/e6/df14ec151942818ecc5e685fa8a4b07d3d3d8a9e4a7d2701047c89290551/aiohttp-3.12.12-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:98451ce9ce229d092f278a74a7c2a06b3aa72984673c87796126d7ccade893e9", size = 700494, upload-time = "2025-06-10T05:19:46.18Z" }, - { url = "https://files.pythonhosted.org/packages/4f/dc/7bc6e17adcd7a82b0d0317ad3e792ac22c93fb672077f0eade93e8d70182/aiohttp-3.12.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:adbac7286d89245e1aff42e948503fdc6edf6d5d65c8e305a67c40f6a8fb95f4", size = 475095, upload-time = "2025-06-10T05:19:48.246Z" }, - { url = "https://files.pythonhosted.org/packages/80/fd/c4e8846ad9d9ecdb7d5ba96de65b7bf2c1582f0b2732f2023080c1c05255/aiohttp-3.12.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0728882115bfa85cbd8d0f664c8ccc0cfd5bd3789dd837596785450ae52fac31", size = 467929, upload-time = "2025-06-10T05:19:50.79Z" }, - { url = "https://files.pythonhosted.org/packages/70/40/abebcf5c81f5e65b4379c05929773be2731ce12414264d3e0fe09ee241eb/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf3b9d9e767f9d0e09fb1a31516410fc741a62cc08754578c40abc497d09540", size = 1714729, upload-time = "2025-06-10T05:19:52.989Z" }, - { url = "https://files.pythonhosted.org/packages/8e/67/4c4f96ef6f16405e7c5205ab3c28852c7e904493b6ddc1c744dda1c97a81/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c944860e86b9f77a462321a440ccf6fa10f5719bb9d026f6b0b11307b1c96c7b", size = 1697380, upload-time = "2025-06-10T05:19:55.832Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a2/dae9ebea4caa8030170c0237e55fa0960df44b3596a849ab9ea621964054/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b1979e1f0c98c06fd0cd940988833b102fa3aa56751f6c40ffe85cabc51f6fd", size = 1752474, upload-time = "2025-06-10T05:19:58.007Z" }, - { url = "https://files.pythonhosted.org/packages/31/ef/f3d9073565ac7ad5257aaa1490ebfc2f182dfc817d3ccfd38c8ab35b2247/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:120b7dd084e96cfdad85acea2ce1e7708c70a26db913eabb8d7b417c728f5d84", size = 1798631, upload-time = "2025-06-10T05:20:00.393Z" }, - { url = "https://files.pythonhosted.org/packages/8b/0b/8b1978662274c80c8e4a739d9be1ae9ef25e5ce42b55838d6a9d1a4e3497/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e58f5ae79649ffa247081c2e8c85e31d29623cf2a3137dda985ae05c9478aae", size = 1718071, upload-time = "2025-06-10T05:20:02.812Z" }, - { url = "https://files.pythonhosted.org/packages/56/aa/35786137db867901b41cb3d2c19c0f4c56dfe581694dba99dec2683d8f8d/aiohttp-3.12.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aa5f049e3e2745b0141f13e5a64e7c48b1a1427ed18bbb7957b348f282fee56", size = 1633871, upload-time = "2025-06-10T05:20:05.127Z" }, - { url = "https://files.pythonhosted.org/packages/63/1d/34d45497dd04d08d662ecda875c44e91d271bbc5d21f4c9e4cbd3ddf7ae2/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7163cc9cf3722d90f1822f8a38b211e3ae2fc651c63bb55449f03dc1b3ff1d44", size = 1694933, upload-time = "2025-06-10T05:20:07.431Z" }, - { url = "https://files.pythonhosted.org/packages/29/c7/41e09a4517449eabbb0a7fe6d60f584fe5b21d4bff761197eb0b81e70034/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ef97c4d035b721de6607f3980fa3e4ef0ec3aca76474b5789b7fac286a8c4e23", size = 1716386, upload-time = "2025-06-10T05:20:09.787Z" }, - { url = "https://files.pythonhosted.org/packages/3a/32/907bd2010b51b70de5314ad707dfc4e898ea0011ff3d678cdf43d6f8980a/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1c14448d6a86acadc3f7b2f4cc385d1fb390acb6f37dce27f86fe629410d92e3", size = 1657039, upload-time = "2025-06-10T05:20:12.198Z" }, - { url = "https://files.pythonhosted.org/packages/60/27/8d87344a33346dcd39273adc33060aeb135e0ef70d1d6e71a3b03894a8e9/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a1b6df6255cfc493454c79221183d64007dd5080bcda100db29b7ff181b8832c", size = 1736599, upload-time = "2025-06-10T05:20:14.519Z" }, - { url = "https://files.pythonhosted.org/packages/ca/45/57c7ef1af694a6d0906abab6edde03787c8c6b0cf5d8359b69d1eb0679df/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:60fc7338dfb0626c2927bfbac4785de3ea2e2bbe3d328ba5f3ece123edda4977", size = 1764575, upload-time = "2025-06-10T05:20:16.993Z" }, - { url = "https://files.pythonhosted.org/packages/2a/cc/b1f918cd702efa9ead9d41f89214e9225cda4e5d013d6eed7f1915c17d0a/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d2afc72207ef4c9d4ca9fcd00689a6a37ef2d625600c3d757b5c2b80c9d0cf9a", size = 1724184, upload-time = "2025-06-10T05:20:19.296Z" }, - { url = "https://files.pythonhosted.org/packages/47/55/089762ee32c2a2e0f523d9ab38c9da2a344cac0e0cc8d16ecf206517ef7e/aiohttp-3.12.12-cp312-cp312-win32.whl", hash = "sha256:8098a48f93b2cbcdb5778e7c9a0e0375363e40ad692348e6e65c3b70d593b27c", size = 421762, upload-time = "2025-06-10T05:20:22.063Z" }, - { url = "https://files.pythonhosted.org/packages/ab/47/151f657e429972916f61399bd52b410e9072d5a2cae1b794f890930e5797/aiohttp-3.12.12-cp312-cp312-win_amd64.whl", hash = "sha256:d1c1879b2e0fc337d7a1b63fe950553c2b9e93c071cf95928aeea1902d441403", size = 447863, upload-time = "2025-06-10T05:20:24.326Z" }, - { url = "https://files.pythonhosted.org/packages/ee/3e/396a7d1c47aa7a74612b186dc716857506c61afac72337a7a96215c2a124/aiohttp-3.12.12-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ea5d604318234427929d486954e3199aded65f41593ac57aa0241ab93dda3d15", size = 694901, upload-time = "2025-06-10T05:20:26.58Z" }, - { url = "https://files.pythonhosted.org/packages/cc/97/235e48eadf73a1854b4d4da29b88d00049309d897d55a511e1cbe4412603/aiohttp-3.12.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e03ff38250b8b572dce6fcd7b6fb6ee398bb8a59e6aa199009c5322d721df4fc", size = 472552, upload-time = "2025-06-10T05:20:28.957Z" }, - { url = "https://files.pythonhosted.org/packages/6b/73/cd7c9439e8cab4113650541017c6524bd0e675b219dfdbbf945a78305e3f/aiohttp-3.12.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:71125b1fc2b6a94bccc63bbece620906a4dead336d2051f8af9cbf04480bc5af", size = 464853, upload-time = "2025-06-10T05:20:31.652Z" }, - { url = "https://files.pythonhosted.org/packages/d1/33/eea88ee55ed4b3f74732d9fc773e6fcf134a2971a19c7ecc49a291e7e57f/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:784a66f9f853a22c6b8c2bd0ff157f9b879700f468d6d72cfa99167df08c5c9c", size = 1703671, upload-time = "2025-06-10T05:20:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/2a/e3/a67ecf9c154b13bad9e2a86ea3782a4b73e889343ffde8c1aadcf9099c09/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a5be0b58670b54301404bd1840e4902570a1c3be00358e2700919cb1ea73c438", size = 1684934, upload-time = "2025-06-10T05:20:36.721Z" }, - { url = "https://files.pythonhosted.org/packages/89/f0/3aaea866531be2f2fcf3a87607e1f55fa72e6ce5acd6b058941a4fc35e15/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8f13566fc7bf5a728275b434bc3bdea87a7ed3ad5f734102b02ca59d9b510f", size = 1737004, upload-time = "2025-06-10T05:20:39.533Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/15867a4c7d39d8fd9bd02191cf60b1d06415fc407bbd4ff2f9660845f1cb/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d736e57d1901683bc9be648aa308cb73e646252c74b4c639c35dcd401ed385ea", size = 1786378, upload-time = "2025-06-10T05:20:42.03Z" }, - { url = "https://files.pythonhosted.org/packages/bd/61/82b15f87088b35705e01fce55806241b45a1099b3470bbca0bed8ee98662/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2007eaa7aae9102f211c519d1ec196bd3cecb1944a095db19eeaf132b798738", size = 1708707, upload-time = "2025-06-10T05:20:44.474Z" }, - { url = "https://files.pythonhosted.org/packages/28/f2/aed0786d5a1c2ed1f5a13ff2a98baacc27206b81d93812da28fc49d8a5d0/aiohttp-3.12.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a813e61583cab6d5cdbaa34bc28863acdb92f9f46e11de1b3b9251a1e8238f6", size = 1622410, upload-time = "2025-06-10T05:20:46.957Z" }, - { url = "https://files.pythonhosted.org/packages/17/54/8305f49a960376136ada977be1370fddb584c63d40bd1b9bef59469f28c7/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e408293aa910b0aea48b86a28eace41d497a85ba16c20f619f0c604597ef996c", size = 1675435, upload-time = "2025-06-10T05:20:49.379Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dc/0a55350025bc297265cfa6c6b1b1f7508f4226ca3238697cbe5e772a7d76/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f3d31faf290f5a30acba46b388465b67c6dbe8655d183e9efe2f6a1d594e6d9d", size = 1707099, upload-time = "2025-06-10T05:20:51.974Z" }, - { url = "https://files.pythonhosted.org/packages/d8/70/d949a1612b996e49d540c10ed77a0a1465c482a590e9a59c1c7897746119/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0b84731697325b023902aa643bd1726d999f5bc7854bc28b17ff410a81151d4b", size = 1649693, upload-time = "2025-06-10T05:20:54.973Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ea/fb87beb7135e25576a1e6fbe98106c037d9fcf1543f19108f9ceb73c192c/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a324c6852b6e327811748446e56cc9bb6eaa58710557922183175816e82a4234", size = 1725825, upload-time = "2025-06-10T05:20:57.433Z" }, - { url = "https://files.pythonhosted.org/packages/f1/1f/adbeb3e440d49b733cef499ace94723ab1fe9fb516425e219379e03b7c9a/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:22fd867fbd72612dcf670c90486dbcbaf702cb807fb0b42bc0b7a142a573574a", size = 1759300, upload-time = "2025-06-10T05:21:00.444Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c1/2fe007ad930f409d0d7fd9916cd55ec9b78b6a611a237424266ed71da48b/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3e092f1a970223794a4bf620a26c0e4e4e8e36bccae9b0b5da35e6d8ee598a03", size = 1708189, upload-time = "2025-06-10T05:21:02.969Z" }, - { url = "https://files.pythonhosted.org/packages/85/5e/ed3ed640fafae3972eae6cd26f66240108cf62452ac8128d59970d538cb1/aiohttp-3.12.12-cp313-cp313-win32.whl", hash = "sha256:7f5f5eb8717ef8ba15ab35fcde5a70ad28bbdc34157595d1cddd888a985f5aae", size = 420783, upload-time = "2025-06-10T05:21:06.287Z" }, - { url = "https://files.pythonhosted.org/packages/a6/db/57d2bb4af52dd0c6f62c42c7d34b82495b2902e50440134f70bfb7ee0fdd/aiohttp-3.12.12-cp313-cp313-win_amd64.whl", hash = "sha256:ace2499bdd03c329c054dc4b47361f2b19d5aa470f7db5c7e0e989336761b33c", size = 446721, upload-time = "2025-06-10T05:21:08.738Z" }, -] - -[[package]] -name = "aiosignal" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, -] - -[[package]] -name = "async-timeout" -version = "5.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, -] - -[[package]] -name = "attrs" -version = "25.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, -] - -[[package]] -name = "bitarray" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/0d/15826c7c2d49a4518a1b24b0d432f1ecad2e0b68168f942058b5de498498/bitarray-3.4.2.tar.gz", hash = "sha256:78ed2b911aabede3a31e3329b1de8abdc8104bd5e0545184ddbd9c7f668f4059", size = 143756, upload-time = "2025-05-21T16:21:44.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/61/fa3a06d74bfba1dc591efa9f4f5ad2e5645f06a8c4d113cf12d18b5ac25b/bitarray-3.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:42b552f885c5629182928c79237b375a92bcf1bc1e725b1c8a5e8eab28ea300d", size = 141280, upload-time = "2025-05-21T16:18:02.593Z" }, - { url = "https://files.pythonhosted.org/packages/17/ba/7eb30374c0e4c4b732a3ca3457d9fb0e44165ae4c5af9758597b03211a28/bitarray-3.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3e16d6184f349587b6a5045bcf073baf763a86273aab454485ba437d0bca82e8", size = 138031, upload-time = "2025-05-21T16:18:05.616Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6d/91582b0a232b54e910add5d0db34a926d0bdfdd1447685b8750349c71958/bitarray-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ecf456f0dee61bd818011e290d922e3e3b1aeb0544f6f19c4da9c5fc2e52818", size = 306437, upload-time = "2025-05-21T16:18:06.793Z" }, - { url = "https://files.pythonhosted.org/packages/b8/23/113ccc20f6324d517ef6210c8fc6ae300346eb481c5a0483735e19b4deea/bitarray-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8bbe8249ae90dc0cd78b21d5d5d27a614e15bf30737ae6e8a0e2e60cc492acc", size = 322335, upload-time = "2025-05-21T16:18:07.925Z" }, - { url = "https://files.pythonhosted.org/packages/6d/89/bf5a36e05ac3d77bdccbe9ba0eea4c47253411c2616379de0f181c27ecee/bitarray-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe7706f75f3b86e7afa516452bed9757ee301b59aea580c551c32a5e1cef082c", size = 314137, upload-time = "2025-05-21T16:18:09.333Z" }, - { url = "https://files.pythonhosted.org/packages/66/a6/bed287f9095a2a266fc68ee42d6ee2815ff500783f973876d86a6d37a434/bitarray-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c60c8d30bb6efd2c04cf82d077df6449964234aeca996f6f1df317a08feffc0", size = 307963, upload-time = "2025-05-21T16:18:10.618Z" }, - { url = "https://files.pythonhosted.org/packages/2f/50/3ca2adaf0da034e6c1a2ed60a3781b065672dd282e67f88593290c3990a7/bitarray-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b4cb5c22706d411010c7ce5efc0a4cc99f755a30fc7f6770eb1b1a0c0962bbb", size = 295182, upload-time = "2025-05-21T16:18:11.932Z" }, - { url = "https://files.pythonhosted.org/packages/90/de/8c3d96e273bc51e4912185bd809fc6a9ec14a09e607336892c149e0c57c5/bitarray-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0fd60137a9474ce53bdace68c718a7c538f9df01d390452cc984f1ee78d7bcdb", size = 300063, upload-time = "2025-05-21T16:18:13.221Z" }, - { url = "https://files.pythonhosted.org/packages/9d/71/34f0ea6ac5b2cbdd84f3e6283b5b796628cef616e786cb442cefce0fe224/bitarray-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cd514a8e27d0751f0254861df60335edabacccfcb2457793ff30c8b2ed8f799d", size = 292053, upload-time = "2025-05-21T16:18:14.802Z" }, - { url = "https://files.pythonhosted.org/packages/77/99/6ef41312536d2c37f14f0f7173aa1a012e9675d62900c10afa7641b47f75/bitarray-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6c8f7447cdf2faff1d176c5dd207f0134f05cfa2a238d3d3944dc5019dc41593", size = 317007, upload-time = "2025-05-21T16:18:16.117Z" }, - { url = "https://files.pythonhosted.org/packages/22/f9/cc4e73f54698bcdd1e0f1ea582da7e005464651e8116291a226deab95e1b/bitarray-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:75040a2a1abe4ccd40236f4ba0d39abde981d23f3ce7691b3b3f2137f134b99b", size = 319402, upload-time = "2025-05-21T16:18:18.097Z" }, - { url = "https://files.pythonhosted.org/packages/55/40/c23dd5726107cbbc5e698b3fcca5ffac83d29146ef469f27f5277d18c2d7/bitarray-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ba15725cd9040b9b1b2650edb33253cb2ba7b68d087974e296e5ff082198952f", size = 299456, upload-time = "2025-05-21T16:18:20.029Z" }, - { url = "https://files.pythonhosted.org/packages/21/31/6bfd9fda776f8d98512d5484fcb55fbb25e60796e7b5d3b9a3a300e8bc1c/bitarray-3.4.2-cp310-cp310-win32.whl", hash = "sha256:2959dfc61d963546e97220cfcaab7dfc489276c6e00092b57710522e68712b28", size = 134279, upload-time = "2025-05-21T16:18:21.609Z" }, - { url = "https://files.pythonhosted.org/packages/82/9d/7067f6548b470beb86d83f7ac6c45cac3b9c28cf77fa0f9f3e67353d69d3/bitarray-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:97077fa0ec3b7eed57cd8d1cb0eb75d670423d20b7e4901482347a81efe2f6fd", size = 141360, upload-time = "2025-05-21T16:18:23.197Z" }, - { url = "https://files.pythonhosted.org/packages/94/ba/508ba6a3ea16eb6c21baae33cd1b7bf6e299d21a496a1f90b8203a22d6d0/bitarray-3.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90ca8e260b75a7ac0c542093e5f29154e51fd0d2d0fa5041c038cb2b58415eeb", size = 141425, upload-time = "2025-05-21T16:18:24.452Z" }, - { url = "https://files.pythonhosted.org/packages/eb/a1/44d9b88cd3daee3734ea98dac691acc2c935a3bfbd5bfc38267a59bd986d/bitarray-3.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549dabcae78fb8f9133e3138b9473c7648d6054bb6fec84d28d3861aaec5ddd1", size = 138172, upload-time = "2025-05-21T16:18:25.601Z" }, - { url = "https://files.pythonhosted.org/packages/5f/aa/5a8c33ab39e8a894978d42427ad0a1ba2d5c9cb61c8480101be555c0e3a7/bitarray-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3da536ac84e6911cbc8e86be0baf1cab0d4f4ccb80c0f39b4fa28509f2db1a", size = 313373, upload-time = "2025-05-21T16:18:26.796Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/b0d28e21d91ec5c0477a320b9443096ddc816fbc59778b367f9e49094532/bitarray-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a5e84d6b737de2d773ab1bd538e6f37fa7f667ea734f00a48d9a973b181c751", size = 329657, upload-time = "2025-05-21T16:18:28.097Z" }, - { url = "https://files.pythonhosted.org/packages/bd/d5/1f858bd559568286435a460e7a169a5185b2b29184684e6c6fa303af3ca9/bitarray-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e265c5eede8316ba64bb6029832f282f6284a557b625bb3207a7680fd5da7925", size = 321873, upload-time = "2025-05-21T16:18:29.511Z" }, - { url = "https://files.pythonhosted.org/packages/e8/c8/23df4174142cccf6a8bd114651b8e9bf965005ab1ef741d37c9f72e8d2eb/bitarray-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63fb45c60c7ab7a724aa64203305e56f344489e12d41619bdc9d7887d6562e01", size = 314796, upload-time = "2025-05-21T16:18:31.2Z" }, - { url = "https://files.pythonhosted.org/packages/8f/21/329178b165f1aaf3f2ace3eb24aca5ad197febae908d7b41e552a69043e9/bitarray-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:083c2a9234dacf3e4e166a5844256da2a397941d3f6397e5b919bffca638f6ef", size = 302724, upload-time = "2025-05-21T16:18:32.729Z" }, - { url = "https://files.pythonhosted.org/packages/26/a8/a66d3c0d3410d01f51824f8476b060f96b3353db7d6b45c87dba6d1aa0e0/bitarray-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e72606adb2438002873cb0e8e81c3fce926386a59bbafa82fea07cdb2a6d8a05", size = 307434, upload-time = "2025-05-21T16:18:34.394Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ac/3052386e7ff80c80eb2549a22c890f511e9f9f7fbbe6244b04255adae031/bitarray-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dc994d22a3a563e1d402dc2f64c61e60605a1a3e66dd8aea7636f607b99f03cb", size = 299232, upload-time = "2025-05-21T16:18:35.708Z" }, - { url = "https://files.pythonhosted.org/packages/9d/46/91a32ccd39d40371ed7404d96a6f3cf1e381eaf36be5390c6bff5034f344/bitarray-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:214468391680ba1c831872a7949f1b563ab3cd832d10adc52df4f36e0af24446", size = 324056, upload-time = "2025-05-21T16:18:37.536Z" }, - { url = "https://files.pythonhosted.org/packages/39/0e/cb824f0e0302cd08809f67b35b3ae21b47af5dd122e99740bfe6bde1c824/bitarray-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c7483b97807bb018a7cd7f9741800c714c9c56ba4e5a7e962c5f956c4b858f3c", size = 327058, upload-time = "2025-05-21T16:18:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/09/01/845e977d490e4e261179785540d1fdeff966c99296f503adc0e5407fc257/bitarray-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5774bf14ec451d5ac311cfcfe0b0cf2a1a9fa74b6ca81dfbc4f56a98872a5541", size = 306629, upload-time = "2025-05-21T16:18:40.211Z" }, - { url = "https://files.pythonhosted.org/packages/29/ef/33ee8533ff1b2a8cd0b9e84fd81b2a90d66c2774544c861e281c5361eaa2/bitarray-3.4.2-cp311-cp311-win32.whl", hash = "sha256:e6f35567347ddb8b9e8b6bf6ab7d64be88bdb6b6c107b8edbb2c3d426c1590a0", size = 134450, upload-time = "2025-05-21T16:18:42.435Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/069c255d067319a9695c93369641d7f5539625069c1cf3ded2becff1bfbc/bitarray-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae5b0a8d3caf6284220232738dc7c05af81ec3a9f93d4a462295462dd0a492b2", size = 141596, upload-time = "2025-05-21T16:18:43.743Z" }, - { url = "https://files.pythonhosted.org/packages/05/57/0b2b50eb3f50c3144f705d0994171f17fda00ee3a72d563ba764ea235f66/bitarray-3.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a0e498563e0eefa96a1b92461d083de11256f6510b7706d5f2e6473cd9b7137a", size = 141191, upload-time = "2025-05-21T16:18:45.436Z" }, - { url = "https://files.pythonhosted.org/packages/81/c3/1d9ce4d0041c10ce90d924b8cea63afdda84a64623179045c0c67998922c/bitarray-3.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:114870ab71a0ebdac211aa0a120a54206c333b74b99fdf4b58fbe904979e1fef", size = 138158, upload-time = "2025-05-21T16:18:46.685Z" }, - { url = "https://files.pythonhosted.org/packages/5d/dd/a8653dac671ba97b1c68ee73b08a0eb2042f24e5e31f51b86afc09588c06/bitarray-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fbf6121978cba4313c31f7cc5961e481242def2b8ddfea34ca27ba9da52c9c1", size = 315834, upload-time = "2025-05-21T16:18:47.926Z" }, - { url = "https://files.pythonhosted.org/packages/3d/a2/30547bea0a35f9f953e99f5157749d56304d3f3a96b01a982dd604a9dc48/bitarray-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:423bb4e1bec0bc5d63969e12bcc5cc0081cc5aec4d7b62a6cd8240342aa36107", size = 331317, upload-time = "2025-05-21T16:18:49.169Z" }, - { url = "https://files.pythonhosted.org/packages/2d/b9/1789476280f46455a9a30bcd252fda6fd995583d97d1b919ec0296393e2a/bitarray-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ef80a96487c82477e8def69a58a218491794f7989b3e191cbaaa7b450315a5c", size = 324416, upload-time = "2025-05-21T16:18:50.917Z" }, - { url = "https://files.pythonhosted.org/packages/84/89/519c829ca641a3e7b8c9be56d177aaa05572b7e15e4298df4a77959b6a1e/bitarray-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35f5c69a79047e50bc1d54a777541b0a86b213e23559b1ac3d76fa9a42cc5522", size = 317634, upload-time = "2025-05-21T16:18:52.718Z" }, - { url = "https://files.pythonhosted.org/packages/0d/39/ebb6a6539261279c0994836b40b99384fa5e27ec239e70b203e310343f80/bitarray-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:002f7b128ed9d18d3ecb51ca78aeea5afffbe8e80d6be4ff2984d045b1c4b937", size = 305392, upload-time = "2025-05-21T16:18:54.888Z" }, - { url = "https://files.pythonhosted.org/packages/83/04/0ee0d57b2a60fdf881346f196fd92b824f44f4736026da1d8c7970745266/bitarray-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:999bccc72704afcf4a3d9868db4d149c032cdf910f9f7d91e30166978530af7f", size = 309740, upload-time = "2025-05-21T16:18:56.76Z" }, - { url = "https://files.pythonhosted.org/packages/f6/39/5ab0339e93097f2a2631ea281a6386c31707011499d5cf68b4e0e37ba124/bitarray-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2e44cfe2bc161cde3b11604f279e3048ef7bd3413837aadbd2ca30b5233c82cb", size = 301607, upload-time = "2025-05-21T16:18:58.144Z" }, - { url = "https://files.pythonhosted.org/packages/e8/bb/b8f697ba6a16c1e393afe75029d069e2dd457e62b112c3cb26768d2e65eb/bitarray-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f408ba3e6f706a0eabae405d1906ceb539f34a318562a91ab9799c5e1712e18c", size = 325942, upload-time = "2025-05-21T16:18:59.471Z" }, - { url = "https://files.pythonhosted.org/packages/64/ec/77d866a96909c09c5a34f1716f015386f9d9bbbf4b5dc7219f642b8043e2/bitarray-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bf94513ae559b2525e6218e41b03790f866d75df5404490420f2c25e42cf55e7", size = 329491, upload-time = "2025-05-21T16:19:01.205Z" }, - { url = "https://files.pythonhosted.org/packages/37/6e/633b7d392a39df655c92035da9ee52f7332bb165ae72038692a33a6def6c/bitarray-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f2c88c792815d2755c49a3a1fca256e142c4adfadf1a2142b5a3a37e4d4b871", size = 309566, upload-time = "2025-05-21T16:19:02.762Z" }, - { url = "https://files.pythonhosted.org/packages/ab/38/9d7ad6eca72e09b81097176dd66eed3aeaabdea4c24cf6ce25609599ce7b/bitarray-3.4.2-cp312-cp312-win32.whl", hash = "sha256:f4dac6b942c4d7ae5f6eb555ee3993de1432bf9c8f46e3caf74b6671ac5571a3", size = 134600, upload-time = "2025-05-21T16:19:04.057Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d3/c83ec3d912be73861a064f1a705436f270b8c5b5926350a875bd6c06b6df/bitarray-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:6c37e6814633041307f0df281651a86372b0ccdb1e4768247a87e83e2b68f9b9", size = 141844, upload-time = "2025-05-21T16:19:05.254Z" }, - { url = "https://files.pythonhosted.org/packages/f2/22/973d377477e1f27cf64f9e3292343219577136e32665a52667589380100d/bitarray-3.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:16263bdbb05ce379e7b8e9a9f3e0a61a9204a06a037bbc91322d2939b3079fd5", size = 141162, upload-time = "2025-05-21T16:19:06.488Z" }, - { url = "https://files.pythonhosted.org/packages/eb/53/65541b94fb6df1e8aa9a7359ac68f469c3243d8bc7302c5fb8ff8936dab2/bitarray-3.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:41fdc6fb8c3aabfcfe0073302c69fef0c74d6499491f133ba58755c3f2afb3d0", size = 138162, upload-time = "2025-05-21T16:19:07.688Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b2/83d587965f7969a5016a5bf5c9295a0651a34b668df41fa089d7c924ac08/bitarray-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c2571337b11c69206e339170516f3e72b4ec16250876c4f2bbb6e82b9caa15", size = 315760, upload-time = "2025-05-21T16:19:09.834Z" }, - { url = "https://files.pythonhosted.org/packages/4f/f5/2b2924181809debdb644143aa33d16facdce5763d5ff17e5301ecdaf89dc/bitarray-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0e3d5f37217dde9b206418c37c4d86e173f072a892670e9714e6bb20b228e95", size = 331250, upload-time = "2025-05-21T16:19:11.449Z" }, - { url = "https://files.pythonhosted.org/packages/00/2b/8ed4eeb947e05ef54614feff4cc4badd03e29ec35d46aa0218513cc9f8ac/bitarray-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83202735f21fc781f27228daeae94b6c7df1a9f673b9dd6a1c0b3764d92b8e50", size = 324299, upload-time = "2025-05-21T16:19:13.236Z" }, - { url = "https://files.pythonhosted.org/packages/05/27/d7f1b15c079cbeffad76f97c41c27635873be4d5600f6896b2bbc4f5caff/bitarray-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b3f8c35812d85a299d6c0ff097f93e18dfb7a324c129e20a4ec0ecfc4ba995", size = 317522, upload-time = "2025-05-21T16:19:14.832Z" }, - { url = "https://files.pythonhosted.org/packages/a5/db/e6a857a23222360dbc0b0d177e6060ecd88d63a1d6a3c2b52333c21a9683/bitarray-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef3f2e8ba5d6e0f38b57960d1bfb72aa9e2115f7cdca48561fadced652798d49", size = 305290, upload-time = "2025-05-21T16:19:16.57Z" }, - { url = "https://files.pythonhosted.org/packages/16/12/3b945e415233889c57c26f95a9a6a245da546e2c8d1de09991332cb796ff/bitarray-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:508ec6547bdd9f0c435c322fbb127a3dfd74c943a6c7f77fa5dfcb3e9ce1de66", size = 309764, upload-time = "2025-05-21T16:19:18.34Z" }, - { url = "https://files.pythonhosted.org/packages/6c/0e/9effb83e23ef5495c9078bdbac948df4fe2b202fb0ac5b33412848ab4b1e/bitarray-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1a3a08cc920f601258ea33d97b4454cd7cb04d17930e0a3bc7328ba3d732f8b0", size = 301690, upload-time = "2025-05-21T16:19:19.694Z" }, - { url = "https://files.pythonhosted.org/packages/cb/67/9a73476c8cd6a67ff5ab9c5c1d916307e4fb9178d76ee2781552451c995c/bitarray-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:60189130ae1ebaadbab27e3ad0a7d7ed44f5d9456bbfae07c72138501ce59053", size = 326049, upload-time = "2025-05-21T16:19:21.371Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b1/2a81f5f96c1ccc033d8c63b4584aedbd9e27499cf2276fc70d4f87ad673b/bitarray-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9e425eaf21a8d7b76531630029441c6d61f6064cbf4dd592af1607c79eb2e4d0", size = 329565, upload-time = "2025-05-21T16:19:22.88Z" }, - { url = "https://files.pythonhosted.org/packages/2e/30/670efe7771944b4b7d0aacdc076969adc9428c9d0939ee70230bdf4c8aed/bitarray-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:952cc40c593f663ba083be76d1ccdb6dc9dafab8fb6d949056405636b2e720f3", size = 309661, upload-time = "2025-05-21T16:19:24.574Z" }, - { url = "https://files.pythonhosted.org/packages/ee/2e/b2d8e842fe484d7d18fcd137289e396c7784b8484e0ec7e94ffe4bb7e8f9/bitarray-3.4.2-cp313-cp313-win32.whl", hash = "sha256:158f6b1a315eaf971f88e66f9b93431c3b580b46d2121c6a1166e7b761408fdf", size = 134614, upload-time = "2025-05-21T16:19:25.914Z" }, - { url = "https://files.pythonhosted.org/packages/0c/50/0ec25a51197410a66146eea7950e3597baedb000f2f2e2458bb6d5306b0a/bitarray-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:2d24658ac96a82beb4da2f5c71bef9790f3dcabadbe8ead8dda742ab207fe2f9", size = 141851, upload-time = "2025-05-21T16:19:27.388Z" }, - { url = "https://files.pythonhosted.org/packages/e7/03/77eca3d93f162c0982f370e6459d1fcb6ff51e84f80adb34c43256653bda/bitarray-3.4.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9c02f3234b1ec391aa235b265a3649e8078d814cdd6b42bc5aee267cc370b0c8", size = 135778, upload-time = "2025-05-21T16:20:58.492Z" }, - { url = "https://files.pythonhosted.org/packages/68/fd/5b148fb07e2b74e1cd17db7b940abdb1c7af6ac3a024810a5931db6e436b/bitarray-3.4.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:e19e5a35f53c0eaf4516cfa3f80de110eb831fd3d9785aa8b8f4a8a8c0d99523", size = 132826, upload-time = "2025-05-21T16:21:00.901Z" }, - { url = "https://files.pythonhosted.org/packages/e5/50/8cfb459218cd074a3af7121f6509ac55be2d6ac5a0a048b188934976f589/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f633d1e92fdc6a039b118d67f23d17b9ac4046a629bde04e178b770fe83a618f", size = 141592, upload-time = "2025-05-21T16:21:02.4Z" }, - { url = "https://files.pythonhosted.org/packages/43/c0/a70a212ecfd4256e7281456beee5330945ea09cec8fb0be3f99ed6828a08/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c08bc2ec3f15fbb3a99923ef1b16b621af45ab9d5146a06f970c0f0d7cab22ba", size = 142502, upload-time = "2025-05-21T16:21:08.366Z" }, - { url = "https://files.pythonhosted.org/packages/1e/8e/9fc84001701ef1fd7f18b0254bf08d594adaed34fe0b5770d8c032b4d53a/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eed46fa39af8440b1cff09a9805d65449583d524006efa29e5262bea9e08787e", size = 143930, upload-time = "2025-05-21T16:21:09.819Z" }, - { url = "https://files.pythonhosted.org/packages/f7/05/2f6753d75282033e66e0a9626ef4209500cd7a08aa8f92cc70fa49681cf3/bitarray-3.4.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9cf23c13c84c1559ed28bd211a6290b7326c2011f6c30c82cee052b254ac09f0", size = 140275, upload-time = "2025-05-21T16:21:11.481Z" }, -] - -[[package]] -name = "blinker" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, -] - -[[package]] -name = "certifi" -version = "2025.4.26" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9b/892a8c8af9110935e5adcbb06d9c6fe741b6bb02608c6513983048ba1a18/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd", size = 144649, upload-time = "2025-05-02T08:31:48.889Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a5/4179abd063ff6414223575e008593861d62abfc22455b5d1a44995b7c101/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6", size = 155045, upload-time = "2025-05-02T08:31:50.757Z" }, - { url = "https://files.pythonhosted.org/packages/3b/95/bc08c7dfeddd26b4be8c8287b9bb055716f31077c8b0ea1cd09553794665/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d", size = 147356, upload-time = "2025-05-02T08:31:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/7a5b635aa65284bf3eab7653e8b4151ab420ecbae918d3e359d1947b4d61/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86", size = 149471, upload-time = "2025-05-02T08:31:56.207Z" }, - { url = "https://files.pythonhosted.org/packages/ae/38/51fc6ac74251fd331a8cfdb7ec57beba8c23fd5493f1050f71c87ef77ed0/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c", size = 151317, upload-time = "2025-05-02T08:31:57.613Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/edee1e32215ee6e9e46c3e482645b46575a44a2d72c7dfd49e49f60ce6bf/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0", size = 146368, upload-time = "2025-05-02T08:31:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/26/2c/ea3e66f2b5f21fd00b2825c94cafb8c326ea6240cd80a91eb09e4a285830/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef", size = 154491, upload-time = "2025-05-02T08:32:01.219Z" }, - { url = "https://files.pythonhosted.org/packages/52/47/7be7fa972422ad062e909fd62460d45c3ef4c141805b7078dbab15904ff7/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6", size = 157695, upload-time = "2025-05-02T08:32:03.045Z" }, - { url = "https://files.pythonhosted.org/packages/2f/42/9f02c194da282b2b340f28e5fb60762de1151387a36842a92b533685c61e/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366", size = 154849, upload-time = "2025-05-02T08:32:04.651Z" }, - { url = "https://files.pythonhosted.org/packages/67/44/89cacd6628f31fb0b63201a618049be4be2a7435a31b55b5eb1c3674547a/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db", size = 150091, upload-time = "2025-05-02T08:32:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/1f/79/4b8da9f712bc079c0f16b6d67b099b0b8d808c2292c937f267d816ec5ecc/charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a", size = 98445, upload-time = "2025-05-02T08:32:08.66Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d7/96970afb4fb66497a40761cdf7bd4f6fca0fc7bafde3a84f836c1f57a926/charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509", size = 105782, upload-time = "2025-05-02T08:32:10.46Z" }, - { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" }, - { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" }, - { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" }, - { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" }, - { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" }, - { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, -] - -[[package]] -name = "ckzg" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/55/df/f6db8e83bd4594c1ea685cd37fb81d5399e55765aae16d1a8a9502598f4e/ckzg-2.1.1.tar.gz", hash = "sha256:d6b306b7ec93a24e4346aa53d07f7f75053bc0afc7398e35fa649e5f9d48fcc4", size = 1120500, upload-time = "2025-03-31T21:24:12.324Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/4b/cd25e857cdf46a752e97c530fe2582fae77c4d16c29fff5a15b7a998e2fd/ckzg-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b9825a1458219e8b4b023012b8ef027ef1f47e903f9541cbca4615f80132730", size = 116377, upload-time = "2025-03-31T21:22:26.952Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bc/5dfef36589545f797245ecacb54ed2acfa75507f63cfe12182d1277a88f1/ckzg-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2a40a3ba65cca4b52825d26829e6f7eb464aa27a9e9efb6b8b2ce183442c741", size = 100208, upload-time = "2025-03-31T21:22:28.04Z" }, - { url = "https://files.pythonhosted.org/packages/b7/52/96f0e3affbed321dc52b9b4ca13e0fb594da572d1f8edc47378fe48d8e9a/ckzg-2.1.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1d753fbe85be7c21602eddc2d40e0915e25fce10329f4f801a0002a4f886cc7", size = 174800, upload-time = "2025-03-31T21:22:29.719Z" }, - { url = "https://files.pythonhosted.org/packages/dc/21/b1bc07cc8e5ed32817e89b054e2399d38775d92ff2d55e24bf233f537c02/ckzg-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d76b50527f1d12430bf118aff6fa4051e9860eada43f29177258b8d399448ea", size = 160847, upload-time = "2025-03-31T21:22:30.973Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5a/97b173d4ff9bce798031beb12b340c4f1729eaaddd07f69f368f843db28e/ckzg-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44c8603e43c021d100f355f50189183135d1df3cbbddb8881552d57fbf421dde", size = 169712, upload-time = "2025-03-31T21:22:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/7b/52/48be78c07f362438e189e2fbea7df8543290c3ee99845442549c8dc5405b/ckzg-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:38707a638c9d715b3c30b29352b969f78d8fc10faed7db5faf517f04359895c0", size = 172942, upload-time = "2025-03-31T21:22:32.8Z" }, - { url = "https://files.pythonhosted.org/packages/13/42/3cfcd6cbdfb9030b9071d5e413a458f93883e47ad4a7d8d4c1d57608e57d/ckzg-2.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:52c4d257bdcbe822d20c5cd24c8154ec5aac33c49a8f5a19e716d9107a1c8785", size = 187707, upload-time = "2025-03-31T21:22:33.673Z" }, - { url = "https://files.pythonhosted.org/packages/eb/54/d43bc3a2de486fb8be29ffedc3ec80f5726765ee4fa78beabe2ab2440f93/ckzg-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1507f7bfb9bcf51d816db5d8d0f0ed53c8289605137820d437b69daea8333e16", size = 182505, upload-time = "2025-03-31T21:22:34.563Z" }, - { url = "https://files.pythonhosted.org/packages/21/43/5bcd2b7630732b532006572fbb8d64a29f69530c630ae4811167a2a0dc3b/ckzg-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d02eaaf4f841910133552b3a051dea53bcfe60cd98199fc4cf80b27609d8baa2", size = 98822, upload-time = "2025-03-31T21:22:35.786Z" }, - { url = "https://files.pythonhosted.org/packages/95/2c/44120b2d9dcb0246d67a1f28b9eaa625c499014d4d42561467e28eedd285/ckzg-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:465e2b71cf9dc383f66f1979269420a0da9274a3a9e98b1a4455e84927dfe491", size = 116378, upload-time = "2025-03-31T21:22:36.96Z" }, - { url = "https://files.pythonhosted.org/packages/23/88/c5b89ba9a730fee5e089be9e0c7048fb6707c1a0e4b6c30fcf725c3eef44/ckzg-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ee2f26f17a64ad0aab833d637b276f28486b82a29e34f32cf54b237b8f8ab72d", size = 100202, upload-time = "2025-03-31T21:22:37.799Z" }, - { url = "https://files.pythonhosted.org/packages/ee/11/b0a473e80346db52ad9a629bc9fd8f773c718ed78932ea3a70392306ffc3/ckzg-2.1.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99cc2c4e9fb8c62e3e0862c7f4df9142f07ba640da17fded5f6e0fd09f75909f", size = 175595, upload-time = "2025-03-31T21:22:39.013Z" }, - { url = "https://files.pythonhosted.org/packages/52/fa/17a7e125d07a96dd6dce4db7262231f7583856b2be5d5b7df59e04bfa188/ckzg-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773dd016693d74aca1f5d7982db2bad7dde2e147563aeb16a783f7e5f69c01fe", size = 161681, upload-time = "2025-03-31T21:22:40.257Z" }, - { url = "https://files.pythonhosted.org/packages/57/bd/46d6b90bf53da732f9adab7593d132a0834ed4f2f7659b4c7414d8f78d39/ckzg-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af2b2144f87ba218d8db01382a961b3ecbdde5ede4fa0d9428d35f8c8a595ba", size = 170471, upload-time = "2025-03-31T21:22:41.513Z" }, - { url = "https://files.pythonhosted.org/packages/9d/98/113c7704749d037d75f23240ffc5c46dfe8416de574b946438587835715f/ckzg-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f55e63d3f7c934a2cb53728ed1d815479e177aca8c84efe991c2920977cff6", size = 173595, upload-time = "2025-03-31T21:22:42.534Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d5/05fca6dcb5a19327be491157794eafc3d7498daf615c2ff5a5b745852945/ckzg-2.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ecb42aaa0ffa427ff14a9dde9356ba69e5ae6014650b397af55b31bdae7a9b6e", size = 188417, upload-time = "2025-03-31T21:22:43.466Z" }, - { url = "https://files.pythonhosted.org/packages/72/36/131ae2dfc82d0fdc98fae8e3bbfe71ff14265bb434b23bd07b585afc6d61/ckzg-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5a01514239f12fb1a7ad9009c20062a4496e13b09541c1a65f97e295da648c70", size = 183286, upload-time = "2025-03-31T21:22:44.732Z" }, - { url = "https://files.pythonhosted.org/packages/c5/6a/d371b27024422b25228fc11fa57b1ba7756a94cc9fb0c75da292c235fdaa/ckzg-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:6516b9684aae262c85cf7fddd8b585b8139ad20e08ec03994e219663abbb0916", size = 98819, upload-time = "2025-03-31T21:22:45.57Z" }, - { url = "https://files.pythonhosted.org/packages/93/a1/9c07513dd0ea01e5db727e67bd2660f3b300a4511281cdb8d5e04afa1cfd/ckzg-2.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c60e8903344ce98ce036f0fabacce952abb714cad4607198b2f0961c28b8aa72", size = 116421, upload-time = "2025-03-31T21:22:46.434Z" }, - { url = "https://files.pythonhosted.org/packages/27/04/b69a0dfbb2722a14c98a52973f276679151ec56a14178cb48e6f2e1697bc/ckzg-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4299149dd72448e5a8d2d1cc6cc7472c92fc9d9f00b1377f5b017c089d9cd92", size = 100216, upload-time = "2025-03-31T21:22:47.633Z" }, - { url = "https://files.pythonhosted.org/packages/2e/24/9cc850d0b8ead395ad5064de67c7c91adacaf31b6b35292ab53fbd93270b/ckzg-2.1.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:025dd31ffdcc799f3ff842570a2a6683b6c5b01567da0109c0c05d11768729c4", size = 175764, upload-time = "2025-03-31T21:22:48.768Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c1/eb13ba399082a98b932f10b230ec08e6456051c0ce3886b3f6d8548d11ab/ckzg-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b42ab8385c273f40a693657c09d2bba40cb4f4666141e263906ba2e519e80bd", size = 161885, upload-time = "2025-03-31T21:22:50.05Z" }, - { url = "https://files.pythonhosted.org/packages/57/c7/58baa64199781950c5a8c6139a46e1acff0f057a36e56769817400eb87fb/ckzg-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be3890fc1543f4fcfc0063e4baf5c036eb14bcf736dabdc6171ab017e0f1671", size = 170757, upload-time = "2025-03-31T21:22:51.282Z" }, - { url = "https://files.pythonhosted.org/packages/65/bd/4b8e1c70972c98829371b7004dc750a45268c5d3442d602e1b62f13ca867/ckzg-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b754210ded172968b201e2d7252573af6bf52d6ad127ddd13d0b9a45a51dae7b", size = 173761, upload-time = "2025-03-31T21:22:52.6Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/c3fd1002f97ba3e0c5b1d9ab2c8fb7a6f475fa9b80ed9c4fa55975501a54/ckzg-2.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2f8fda87865897a269c4e951e3826c2e814427a6cdfed6731cccfe548f12b36", size = 188666, upload-time = "2025-03-31T21:22:53.47Z" }, - { url = "https://files.pythonhosted.org/packages/e2/d9/91cf5a8169ee60c9397c975163cbca34432571f94facec5f8c0086bb47d8/ckzg-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:98e70b5923d77c7359432490145e9d1ab0bf873eb5de56ec53f4a551d7eaec79", size = 183652, upload-time = "2025-03-31T21:22:54.351Z" }, - { url = "https://files.pythonhosted.org/packages/25/d4/8c9f6b852f99926862344b29f0c59681916ccfec2ac60a85952a369e0bca/ckzg-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:42af7bde4ca45469cd93a96c3d15d69d51d40e7f0d30e3a20711ebd639465fcb", size = 98816, upload-time = "2025-03-31T21:22:55.23Z" }, - { url = "https://files.pythonhosted.org/packages/b7/9a/fa698b12e97452d11dd314e0335aae759725284ef6e1c1665aed56b1cd3e/ckzg-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e4edfdaf87825ff43b9885fabfdea408737a714f4ce5467100d9d1d0a03b673", size = 116426, upload-time = "2025-03-31T21:22:56.108Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/8cccd308bd11b49b40eecad6900b5769da117951cac33e880dd25e851ef7/ckzg-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:815fd2a87d6d6c57d669fda30c150bc9bf387d47e67d84535aa42b909fdc28ea", size = 100219, upload-time = "2025-03-31T21:22:56.982Z" }, - { url = "https://files.pythonhosted.org/packages/30/0e/63573d816c1292b9a4d70eb6a7366b3593d29a977794039e926805a76ca0/ckzg-2.1.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32466e809b1ab3ff01d3b0bb0b9912f61dcf72957885615595f75e3f7cc10e5", size = 175725, upload-time = "2025-03-31T21:22:58.213Z" }, - { url = "https://files.pythonhosted.org/packages/86/f6/a279609516695ad3fb8b201098c669ba3b2844cbf4fa0d83a0f02b9bb29b/ckzg-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f11b73ccf37b12993f39a7dbace159c6d580aacacde6ee17282848476550ddbc", size = 161835, upload-time = "2025-03-31T21:22:59.448Z" }, - { url = "https://files.pythonhosted.org/packages/39/e4/8cf7aef7dc05a777cb221e94046f947c6fe5317159a8dae2cd7090d52ef2/ckzg-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3b9433a1f2604bd9ac1646d3c83ad84a850d454d3ac589fe8e70c94b38a6b0", size = 170759, upload-time = "2025-03-31T21:23:01.022Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/b34e3c08eb36bc67e338b114f289b2595e581b8bdc09a8f12299a1db5d2f/ckzg-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b7d7e1b5ea06234558cd95c483666fd785a629b720a7f1622b3cbffebdc62033", size = 173787, upload-time = "2025-03-31T21:23:01.974Z" }, - { url = "https://files.pythonhosted.org/packages/2e/f0/aff87c3ed80713453cb6c84fe6fbb7582d86a7a5e4460fda2a497d47f489/ckzg-2.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9f5556e6675866040cc4335907be6c537051e7f668da289fa660fdd8a30c9ddb", size = 188722, upload-time = "2025-03-31T21:23:02.966Z" }, - { url = "https://files.pythonhosted.org/packages/44/d9/1f08bfb8fd1cbb8c7513e7ad3fb76bbb5c3fb446238c1eba582276e4d905/ckzg-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55b2ba30c5c9daac0c55f1aac851f1b7bf1f7aa0028c2db4440e963dd5b866d6", size = 183686, upload-time = "2025-03-31T21:23:03.905Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ff/434f6d2893cbdfad00c20d17e9a52d426ca042f5e980d5c3db96bc6b6e15/ckzg-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:10d201601fc8f28c0e8cec3406676797024dd374c367bbeec5a7a9eac9147237", size = 98817, upload-time = "2025-03-31T21:23:05.2Z" }, - { url = "https://files.pythonhosted.org/packages/30/b3/a0c7d7ba6e669cf04605dc0329173db62fc1fe3c488761755cc01e5e1b4d/ckzg-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:375918e25eafb9bafe5215ab91698504cba3fe51b4fe92f5896af6c5663f50c6", size = 113191, upload-time = "2025-03-31T21:23:40.646Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b9/a6cf403b8528d18d7d9154e28381a397bf466c86aa8e0b3327cffdde5749/ckzg-2.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:38b3b7802c76d4ad015db2b7a79a49c193babae50ee5f77e9ac2865c9e9ddb09", size = 96207, upload-time = "2025-03-31T21:23:41.596Z" }, - { url = "https://files.pythonhosted.org/packages/63/6b/5ddd713d97886becb8450e3e13db891199125f722366d30d087ad5438390/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438a5009fd254ace0bc1ad974d524547f1a41e6aa5e778c5cd41f4ee3106bcd6", size = 126160, upload-time = "2025-03-31T21:23:42.553Z" }, - { url = "https://files.pythonhosted.org/packages/c7/dd/e05aecc01e62108a7579f8df5e5d38536841f50e12172f8a84677edac0fa/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce11cc163a2e0dab3af7455aca7053f9d5bb8d157f231acc7665fd230565d48", size = 102811, upload-time = "2025-03-31T21:23:43.494Z" }, - { url = "https://files.pythonhosted.org/packages/c6/81/6cdadd8626ac11290af3f58ae5dcffe38bd2c8f8c798dacee7475e244aac/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b53964c07f6a076e97eaa1ef35045e935d7040aff14f80bae7e9105717702d05", size = 111328, upload-time = "2025-03-31T21:23:44.449Z" }, - { url = "https://files.pythonhosted.org/packages/36/b7/b129ff6955cd264c6ab3dbd52dd1b2759d1b121c09c03f9991e4c722c72f/ckzg-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cf085f15ae52ab2599c9b5a3d5842794bcf5613b7f58661fbfb0c5d9eac988b9", size = 98846, upload-time = "2025-03-31T21:23:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ba/7d9c1f9cec7e0e382653c72165896194a05743e589b1dae2aa80236aa87f/ckzg-2.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4b0c850bd6cad22ac79b2a2ab884e0e7cd2b54a67d643cd616c145ebdb535a11", size = 113188, upload-time = "2025-03-31T21:23:46.337Z" }, - { url = "https://files.pythonhosted.org/packages/2f/92/9728f5ccc1c5e87c6c5ae7941250a447b61fd5a63aadbc15249e29c21bcf/ckzg-2.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:26951f36bb60c9150bbd38110f5e1625596f9779dad54d1d492d8ec38bc84e3a", size = 96208, upload-time = "2025-03-31T21:23:47.255Z" }, - { url = "https://files.pythonhosted.org/packages/39/63/5e27d587bd224fee70cb66b022e7c4ef95d0e091e08ee76c25ec12094b0d/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbe12445e49c4bee67746b7b958e90a973b0de116d0390749b0df351d94e9a8c", size = 126158, upload-time = "2025-03-31T21:23:48.195Z" }, - { url = "https://files.pythonhosted.org/packages/43/98/e0a45946575a7b823d8ee0b47afb104b6017e54e1208f07da2529bc01900/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c5d4f66f09de4a99271acac74d2acb3559a77de77a366b34a91e99e8822667", size = 102812, upload-time = "2025-03-31T21:23:49.16Z" }, - { url = "https://files.pythonhosted.org/packages/cb/50/718ca7b03e4b89b18cdf99cc3038050105b0acbf9b612c23cd513093c6de/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42673c1d007372a4e8b48f6ef8f0ce31a9688a463317a98539757d1e2fb1ecc7", size = 111327, upload-time = "2025-03-31T21:23:50.126Z" }, - { url = "https://files.pythonhosted.org/packages/29/c5/80e5a0c6967d02d801150104320484a258e5a49bd191e198643e74039320/ckzg-2.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:57a7dc41ec6b69c1d9117eb61cf001295e6b4f67a736020442e71fb4367fb1a5", size = 98847, upload-time = "2025-03-31T21:23:51.084Z" }, -] - -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "cytoolz" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "toolz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/f9/3243eed3a6545c2a33a21f74f655e3fcb5d2192613cd3db81a93369eb339/cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6", size = 626652, upload-time = "2024-12-13T05:47:36.672Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d9/f13d66c16cff1fa1cb6c234698029877c456f35f577ef274aba3b86e7c51/cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042", size = 403515, upload-time = "2024-12-13T05:44:27.845Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2d/4cdf848a69300c7d44984f2ebbebb3b8576e5449c8dea157298f3bdc4da3/cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608", size = 383936, upload-time = "2024-12-13T05:44:29.5Z" }, - { url = "https://files.pythonhosted.org/packages/72/a4/ccfdd3f0ed9cc818f734b424261f6018fc61e3ec833bf85225a9aca0d994/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90124bdc42ff58b88cdea1d24a6bc5f776414a314cc4d94f25c88badb3a16d1", size = 1934569, upload-time = "2024-12-13T05:44:30.799Z" }, - { url = "https://files.pythonhosted.org/packages/50/fc/38d5344fa595683ad10dc819cfc1d8b9d2b3391ccf3e8cb7bab4899a01f5/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e74801b751e28f7c5cc3ad264c123954a051f546f2fdfe089f5aa7a12ccfa6da", size = 2015129, upload-time = "2024-12-13T05:44:32.297Z" }, - { url = "https://files.pythonhosted.org/packages/28/29/75261748dc54a20a927f33641f4e9aac674cfc6d3fbd4f332e10d0b37639/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582dad4545ddfb5127494ef23f3fa4855f1673a35d50c66f7638e9fb49805089", size = 2000506, upload-time = "2024-12-13T05:44:34.403Z" }, - { url = "https://files.pythonhosted.org/packages/00/ae/e4ead004cc2698281d153c4a5388638d67cdb5544d6d6cc1e5b3db2bd2a3/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7bd0618e16efe03bd12f19c2a26a27e6e6b75d7105adb7be1cd2a53fa755d8", size = 1957537, upload-time = "2024-12-13T05:44:39.499Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ff/4f3aa07f4f47701f7f63df60ce0a5669fa09c256c3d4a33503a9414ea5cc/cytoolz-1.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d74cca6acf1c4af58b2e4a89cc565ed61c5e201de2e434748c93e5a0f5c541a5", size = 1863331, upload-time = "2024-12-13T05:44:42.61Z" }, - { url = "https://files.pythonhosted.org/packages/a2/29/654f57f2a9b8e9765a4ab876765f64f94530b61fc6471a07feea42ece6d4/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:823a3763828d8d457f542b2a45d75d6b4ced5e470b5c7cf2ed66a02f508ed442", size = 1849938, upload-time = "2024-12-13T05:44:45.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/7b/11f457db6b291060a98315ab2c7198077d8bddeeebe5f7126d9dad98cc54/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:51633a14e6844c61db1d68c1ffd077cf949f5c99c60ed5f1e265b9e2966f1b52", size = 1852345, upload-time = "2024-12-13T05:44:47.994Z" }, - { url = "https://files.pythonhosted.org/packages/6b/92/0dccc96ce0323be236d404f5084479b79b747fa0e74e43a270e95868b5f9/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3ec9b01c45348f1d0d712507d54c2bfd69c62fbd7c9ef555c9d8298693c2432", size = 1989877, upload-time = "2024-12-13T05:44:51.514Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c8/1c5203a81200bae51aa8f7b5fad613f695bf1afa03f16251ca23ecb2ef9f/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1855022b712a9c7a5bce354517ab4727a38095f81e2d23d3eabaf1daeb6a3b3c", size = 1994492, upload-time = "2024-12-13T05:44:52.922Z" }, - { url = "https://files.pythonhosted.org/packages/e2/8a/04bc193c4d7ced8ef6bb62cdcd0bf40b5e5eb26586ed2cfb4433ec7dfd0a/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9930f7288c4866a1dc1cc87174f0c6ff4cad1671eb1f6306808aa6c445857d78", size = 1896077, upload-time = "2024-12-13T05:44:56.118Z" }, - { url = "https://files.pythonhosted.org/packages/21/a5/bee63a58f51d2c74856db66e6119a014464ff8cb1c9387fa4bd2d94e49b0/cytoolz-1.0.1-cp310-cp310-win32.whl", hash = "sha256:a9baad795d72fadc3445ccd0f122abfdbdf94269157e6d6d4835636dad318804", size = 322135, upload-time = "2024-12-13T05:44:57.695Z" }, - { url = "https://files.pythonhosted.org/packages/e8/16/7abfb1685e8b7f2838264551ee33651748994813f566ac4c3d737dfe90e5/cytoolz-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad95b386a84e18e1f6136f6d343d2509d4c3aae9f5a536f3dc96808fcc56a8cf", size = 363599, upload-time = "2024-12-13T05:44:58.875Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ea/8131ae39119820b8867cddc23716fa9f681f2b3bbce6f693e68dfb36b55b/cytoolz-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d958d4f04d9d7018e5c1850790d9d8e68b31c9a2deebca74b903706fdddd2b6", size = 406162, upload-time = "2024-12-13T05:45:01.196Z" }, - { url = "https://files.pythonhosted.org/packages/26/18/3d9bd4c146f6ea6e51300c242b20cb416966b21d481dac230e1304f1e54b/cytoolz-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0f445b8b731fc0ecb1865b8e68a070084eb95d735d04f5b6c851db2daf3048ab", size = 384961, upload-time = "2024-12-13T05:45:02.387Z" }, - { url = "https://files.pythonhosted.org/packages/e4/73/9034827907c7f85c7c484c9494e905d022fb8174526004e9ef332570349e/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f546a96460a7e28eb2ec439f4664fa646c9b3e51c6ebad9a59d3922bbe65e30", size = 2091698, upload-time = "2024-12-13T05:45:04.353Z" }, - { url = "https://files.pythonhosted.org/packages/74/af/d5c2733b0fde1a08254ff1a8a8d567874040c9eb1606363cfebc0713c73f/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0317681dd065532d21836f860b0563b199ee716f55d0c1f10de3ce7100c78a3b", size = 2188452, upload-time = "2024-12-13T05:45:05.748Z" }, - { url = "https://files.pythonhosted.org/packages/6a/bb/77c71fa9c217260b4056a732d754748903423c2cdd82a673d6064741e375/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0ef52febd5a7821a3fd8d10f21d460d1a3d2992f724ba9c91fbd7a96745d41", size = 2174203, upload-time = "2024-12-13T05:45:07.777Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a9/a5b4a3ff5d22faa1b60293bfe97362e2caf4a830c26d37ab5557f60d04b2/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebaf419acf2de73b643cf96108702b8aef8e825cf4f63209ceb078d5fbbbfd", size = 2099831, upload-time = "2024-12-13T05:45:11.477Z" }, - { url = "https://files.pythonhosted.org/packages/35/08/7f6869ea1ff31ce5289a7d58d0e7090acfe7058baa2764473048ff61ea3c/cytoolz-1.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f7f04eeb4088947585c92d6185a618b25ad4a0f8f66ea30c8db83cf94a425e3", size = 1996744, upload-time = "2024-12-13T05:45:14.172Z" }, - { url = "https://files.pythonhosted.org/packages/46/b4/9ac424c994b51763fd1bbed62d95f8fba8fa0e45c8c3c583904fdaf8f51d/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f61928803bb501c17914b82d457c6f50fe838b173fb40d39c38d5961185bd6c7", size = 2013733, upload-time = "2024-12-13T05:45:16.912Z" }, - { url = "https://files.pythonhosted.org/packages/3e/99/03009765c4b87d742d5b5a8670abb56a8c7ede033c2cdaa4be8662d3b001/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d2960cb4fa01ccb985ad1280db41f90dc97a80b397af970a15d5a5de403c8c61", size = 1994850, upload-time = "2024-12-13T05:45:18.414Z" }, - { url = "https://files.pythonhosted.org/packages/40/9a/8458af9a5557e177ea42f8cf7e477bede518b0bbef564e28c4151feaa52c/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2b407cc3e9defa8df5eb46644f6f136586f70ba49eba96f43de67b9a0984fd3", size = 2155352, upload-time = "2024-12-13T05:45:19.763Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5c/2a701423e001fcbec288b4f3fc2bf67557d114c2388237fc1ae67e1e2686/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8245f929144d4d3bd7b972c9593300195c6cea246b81b4c46053c48b3f044580", size = 2163515, upload-time = "2024-12-13T05:45:21.08Z" }, - { url = "https://files.pythonhosted.org/packages/36/16/ee2e06e65d9d533bc05cd52a0b355ba9072fc8f60d77289e529c6d2e3750/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37385db03af65763933befe89fa70faf25301effc3b0485fec1c15d4ce4f052", size = 2054431, upload-time = "2024-12-13T05:45:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d5/2fac8315f210fa1bc7106e27c19e1211580aa25bb7fa17dfd79505e5baf2/cytoolz-1.0.1-cp311-cp311-win32.whl", hash = "sha256:50f9c530f83e3e574fc95c264c3350adde8145f4f8fc8099f65f00cc595e5ead", size = 322004, upload-time = "2024-12-13T05:45:24.048Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9e/0b70b641850a95f9ff90adde9d094a4b1d81ec54dadfd97fec0a2aaf440e/cytoolz-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b7f6b617454b4326af7bd3c7c49b0fc80767f134eb9fd6449917a058d17a0e3c", size = 365358, upload-time = "2024-12-13T05:45:25.383Z" }, - { url = "https://files.pythonhosted.org/packages/d8/e8/218098344ed2cb5f8441fade9b2428e435e7073962374a9c71e59ac141a7/cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4", size = 414121, upload-time = "2024-12-13T05:45:26.588Z" }, - { url = "https://files.pythonhosted.org/packages/de/27/4d729a5653718109262b758fec1a959aa9facb74c15460d9074dc76d6635/cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662", size = 390904, upload-time = "2024-12-13T05:45:27.718Z" }, - { url = "https://files.pythonhosted.org/packages/72/c0/cbabfa788bab9c6038953bf9478adaec06e88903a726946ea7c88092f5c4/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3", size = 2090734, upload-time = "2024-12-13T05:45:30.515Z" }, - { url = "https://files.pythonhosted.org/packages/c3/66/369262c60f9423c2da82a60864a259c852f1aa122aced4acd2c679af58c0/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1", size = 2155933, upload-time = "2024-12-13T05:45:32.721Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4e/ee55186802f8d24b5fbf9a11405ccd1203b30eded07cc17750618219b94e/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8", size = 2171903, upload-time = "2024-12-13T05:45:34.205Z" }, - { url = "https://files.pythonhosted.org/packages/a1/96/bd1a9f3396e9b7f618db8cd08d15630769ce3c8b7d0534f92cd639c977ae/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d", size = 2125270, upload-time = "2024-12-13T05:45:36.982Z" }, - { url = "https://files.pythonhosted.org/packages/28/48/2a3762873091c88a69e161111cfbc6c222ff145d57ff011a642b169f04f1/cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f", size = 1973967, upload-time = "2024-12-13T05:45:39.505Z" }, - { url = "https://files.pythonhosted.org/packages/e4/50/500bd69774bdc49a4d78ec8779eb6ac7c1a9d706bfd91cf2a1dba604373a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7", size = 2021695, upload-time = "2024-12-13T05:45:40.911Z" }, - { url = "https://files.pythonhosted.org/packages/e4/4e/ba5a0ce34869495eb50653de8d676847490cf13a2cac1760fc4d313e78de/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126", size = 2010177, upload-time = "2024-12-13T05:45:42.48Z" }, - { url = "https://files.pythonhosted.org/packages/87/57/615c630b3089a13adb15351d958d227430cf624f03b1dd39eb52c34c1f59/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0", size = 2154321, upload-time = "2024-12-13T05:45:43.979Z" }, - { url = "https://files.pythonhosted.org/packages/7f/0f/fe1aa2d931e3b35ecc05215bd75da945ea7346095b3b6f6027164e602d5a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b", size = 2188374, upload-time = "2024-12-13T05:45:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/de/fa/fd363d97a641b6d0e2fd1d5c35b8fd41d9ccaeb4df56302f53bf23a58e3a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d", size = 2077911, upload-time = "2024-12-13T05:45:48.219Z" }, - { url = "https://files.pythonhosted.org/packages/d9/68/0a22946b98ae5201b54ccb4e651295285c0fb79406022b6ee8b2f791940c/cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9", size = 321903, upload-time = "2024-12-13T05:45:50.3Z" }, - { url = "https://files.pythonhosted.org/packages/62/1a/f3903197956055032f8cb297342e2dff07e50f83991aebfe5b4c4fcb55e4/cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b", size = 364490, upload-time = "2024-12-13T05:45:51.494Z" }, - { url = "https://files.pythonhosted.org/packages/aa/2e/a9f069db0107749e9e72baf6c21abe3f006841a3bcfdc9b8420e22ef31eb/cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0", size = 407365, upload-time = "2024-12-13T05:45:52.803Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9b/5e87dd0e31f54c778b4f9f34cc14c1162d3096c8d746b0f8be97d70dd73c/cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a", size = 385233, upload-time = "2024-12-13T05:45:53.994Z" }, - { url = "https://files.pythonhosted.org/packages/63/00/2fd32b16284cdb97cfe092822179bc0c3bcdd5e927dd39f986169a517642/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242", size = 2062903, upload-time = "2024-12-13T05:45:55.202Z" }, - { url = "https://files.pythonhosted.org/packages/85/39/b3cbb5a9847ba59584a263772ad4f8ca2dbfd2a0e11efd09211d1219804c/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296", size = 2139517, upload-time = "2024-12-13T05:45:56.804Z" }, - { url = "https://files.pythonhosted.org/packages/ea/39/bfcab4a46d50c467e36fe704f19d8904efead417787806ee210327f68390/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b", size = 2154849, upload-time = "2024-12-13T05:45:58.814Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/3bc6ee61b0aa47e1cb40819adc1a456d7efa809f0dea9faddacb43fdde8f/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b", size = 2102302, upload-time = "2024-12-13T05:46:00.181Z" }, - { url = "https://files.pythonhosted.org/packages/00/66/3f636c6ddea7b18026b90a8c238af472e423b86e427b11df02213689b012/cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266", size = 1960872, upload-time = "2024-12-13T05:46:01.612Z" }, - { url = "https://files.pythonhosted.org/packages/40/36/cb3b7cdd651007b69f9c48e9d104cec7cb8dc53afa1d6a720e5ad08022fa/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5", size = 2014430, upload-time = "2024-12-13T05:46:03.022Z" }, - { url = "https://files.pythonhosted.org/packages/88/3f/2e9bd2a16cfd269808922147551dcb2d8b68ba54a2c4deca2fa6a6cd0d5f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3", size = 2003127, upload-time = "2024-12-13T05:46:04.401Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7d/08604ff940aa784df8343c387fdf2489b948b714a6afb587775ae94da912/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296", size = 2142369, upload-time = "2024-12-13T05:46:06.004Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c6/39919a0645bdbdf720e97cae107f959ea9d1267fbc3b0d94fc6e1d12ac8f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140", size = 2180427, upload-time = "2024-12-13T05:46:07.526Z" }, - { url = "https://files.pythonhosted.org/packages/d8/03/dbb9d47556ee54337e7e0ac209d17ceff2d2a197c34de08005abc7a7449b/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581", size = 2069785, upload-time = "2024-12-13T05:46:10.122Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f8/11bb7b8947002231faae3ec2342df5896afbc19eb783a332cce6d219ff79/cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9", size = 320685, upload-time = "2024-12-13T05:46:11.553Z" }, - { url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297", size = 362898, upload-time = "2024-12-13T05:46:12.771Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f7/ef2a10daaec5c0f7d781d50758c6187eee484256e356ae8ef178d6c48497/cytoolz-1.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:83d19d55738ad9c60763b94f3f6d3c6e4de979aeb8d76841c1401081e0e58d96", size = 345702, upload-time = "2024-12-13T05:47:09.266Z" }, - { url = "https://files.pythonhosted.org/packages/c8/14/53c84adddedb67ff1546abb86fea04d26e24298c3ceab8436d20122ed0b9/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f112a71fad6ea824578e6393765ce5c054603afe1471a5c753ff6c67fd872d10", size = 385695, upload-time = "2024-12-13T05:47:11.011Z" }, - { url = "https://files.pythonhosted.org/packages/bd/80/3ae356c5e7b8d7dc7d1adb52f6932fee85cd748ed4e1217c269d2dfd610f/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a515df8f8aa6e1eaaf397761a6e4aff2eef73b5f920aedf271416d5471ae5ee", size = 406261, upload-time = "2024-12-13T05:47:12.24Z" }, - { url = "https://files.pythonhosted.org/packages/0c/31/8e43761ffc82d90bf9cab7e0959712eedcd1e33c211397e143dd42d7af57/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c398e7b7023460bea2edffe5fcd0a76029580f06c3f6938ac3d198b47156f3", size = 397207, upload-time = "2024-12-13T05:47:13.561Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b9/fe9da37090b6444c65f848a83e390f87d8cb43d6a4df46de1556ad7e5ceb/cytoolz-1.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3237e56211e03b13df47435b2369f5df281e02b04ad80a948ebd199b7bc10a47", size = 343358, upload-time = "2024-12-13T05:47:16.291Z" }, -] - -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - -[[package]] -name = "email-validator" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, -] - -[[package]] -name = "eth-abi" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "parsimonious" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/71/d9e1380bd77fd22f98b534699af564f189b56d539cc2b9dab908d4e4c242/eth_abi-5.2.0.tar.gz", hash = "sha256:178703fa98c07d8eecd5ae569e7e8d159e493ebb6eeb534a8fe973fbc4e40ef0", size = 49797, upload-time = "2025-01-14T16:29:34.629Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/b4/2f3982c4cbcbf5eeb6aec62df1533c0e63c653b3021ff338d44944405676/eth_abi-5.2.0-py3-none-any.whl", hash = "sha256:17abe47560ad753f18054f5b3089fcb588f3e3a092136a416b6c1502cb7e8877", size = 28511, upload-time = "2025-01-14T16:29:31.862Z" }, -] - -[[package]] -name = "eth-account" -version = "0.13.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bitarray" }, - { name = "ckzg" }, - { name = "eth-abi" }, - { name = "eth-keyfile" }, - { name = "eth-keys" }, - { name = "eth-rlp" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "rlp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/cf/20f76a29be97339c969fd765f1237154286a565a1d61be98e76bb7af946a/eth_account-0.13.7.tar.gz", hash = "sha256:5853ecbcbb22e65411176f121f5f24b8afeeaf13492359d254b16d8b18c77a46", size = 935998, upload-time = "2025-04-21T21:11:21.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/18/088fb250018cbe665bc2111974301b2d59f294a565aff7564c4df6878da2/eth_account-0.13.7-py3-none-any.whl", hash = "sha256:39727de8c94d004ff61d10da7587509c04d2dc7eac71e04830135300bdfc6d24", size = 587452, upload-time = "2025-04-21T21:11:18.346Z" }, -] - -[[package]] -name = "eth-hash" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/38/577b7bc9380ef9dff0f1dffefe0c9a1ded2385e7a06c306fd95afb6f9451/eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5", size = 12227, upload-time = "2025-01-13T21:29:21.765Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/db/f8775490669d28aca24871c67dd56b3e72105cb3bcae9a4ec65dd70859b3/eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a", size = 8028, upload-time = "2025-01-13T21:29:19.365Z" }, -] - -[package.optional-dependencies] -pycryptodome = [ - { name = "pycryptodome" }, -] - -[[package]] -name = "eth-keyfile" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-keys" }, - { name = "eth-utils" }, - { name = "pycryptodome" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/66/dd823b1537befefbbff602e2ada88f1477c5b40ec3731e3d9bc676c5f716/eth_keyfile-0.8.1.tar.gz", hash = "sha256:9708bc31f386b52cca0969238ff35b1ac72bd7a7186f2a84b86110d3c973bec1", size = 12267, upload-time = "2024-04-23T20:28:53.862Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/fc/48a586175f847dd9e05e5b8994d2fe8336098781ec2e9836a2ad94280281/eth_keyfile-0.8.1-py3-none-any.whl", hash = "sha256:65387378b82fe7e86d7cb9f8d98e6d639142661b2f6f490629da09fddbef6d64", size = 7510, upload-time = "2024-04-23T20:28:51.063Z" }, -] - -[[package]] -name = "eth-keys" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/11/1ed831c50bd74f57829aa06e58bd82a809c37e070ee501c953b9ac1f1552/eth_keys-0.7.0.tar.gz", hash = "sha256:79d24fd876201df67741de3e3fefb3f4dbcbb6ace66e47e6fe662851a4547814", size = 30166, upload-time = "2025-04-07T17:40:21.697Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/25/0ae00f2b0095e559d61ad3dc32171bd5a29dfd95ab04b4edd641f7c75f72/eth_keys-0.7.0-py3-none-any.whl", hash = "sha256:b0cdda8ffe8e5ba69c7c5ca33f153828edcace844f67aabd4542d7de38b159cf", size = 20656, upload-time = "2025-04-07T17:40:20.441Z" }, -] - -[[package]] -name = "eth-rlp" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "rlp" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7f/ea/ad39d001fa9fed07fad66edb00af701e29b48be0ed44a3bcf58cb3adf130/eth_rlp-2.2.0.tar.gz", hash = "sha256:5e4b2eb1b8213e303d6a232dfe35ab8c29e2d3051b86e8d359def80cd21db83d", size = 7720, upload-time = "2025-02-04T21:51:08.134Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/3b/57efe2bc2df0980680d57c01a36516cd3171d2319ceb30e675de19fc2cc5/eth_rlp-2.2.0-py3-none-any.whl", hash = "sha256:5692d595a741fbaef1203db6a2fedffbd2506d31455a6ad378c8449ee5985c47", size = 4446, upload-time = "2025-02-04T21:51:05.823Z" }, -] - -[[package]] -name = "eth-typing" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/54/62aa24b9cc708f06316167ee71c362779c8ed21fc8234a5cd94a8f53b623/eth_typing-5.2.1.tar.gz", hash = "sha256:7557300dbf02a93c70fa44af352b5c4a58f94e997a0fd6797fb7d1c29d9538ee", size = 21806, upload-time = "2025-04-14T20:39:28.217Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/72/c370bbe4c53da7bf998d3523f5a0f38867654923a82192df88d0705013d3/eth_typing-5.2.1-py3-none-any.whl", hash = "sha256:b0c2812ff978267563b80e9d701f487dd926f1d376d674f3b535cfe28b665d3d", size = 19163, upload-time = "2025-04-14T20:39:26.571Z" }, -] - -[[package]] -name = "eth-utils" -version = "5.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cytoolz", marker = "implementation_name == 'cpython'" }, - { name = "eth-hash" }, - { name = "eth-typing" }, - { name = "pydantic" }, - { name = "toolz", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0d/49/bee95f16d2ef068097afeeffbd6c67738107001ee57ad7bcdd4fc4d3c6a7/eth_utils-5.3.0.tar.gz", hash = "sha256:1f096867ac6be895f456fa3acb26e9573ae66e753abad9208f316d24d6178156", size = 123753, upload-time = "2025-04-14T19:35:56.431Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/c6/0417a92e6a3fc9b85f5a8380d9f9d43b69ba836a90e45f79f9ae74d41e53/eth_utils-5.3.0-py3-none-any.whl", hash = "sha256:ac184883ab299d923428bbe25dae5e356979a3993e0ef695a864db0a20bc262d", size = 102531, upload-time = "2025-04-14T19:35:55.176Z" }, -] - -[[package]] -name = "exceptiongroup" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, -] - -[[package]] -name = "fastapi" -version = "0.115.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236, upload-time = "2025-03-23T22:55:43.822Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164, upload-time = "2025-03-23T22:55:42.101Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, - { name = "httpx" }, - { name = "jinja2" }, - { name = "python-multipart" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cli" -version = "0.0.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "rich-toolkit" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/73/82a5831fbbf8ed75905bacf5b2d9d3dfd6f04d6968b29fe6f72a5ae9ceb1/fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e", size = 16753, upload-time = "2024-12-15T14:28:10.028Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705, upload-time = "2024-12-15T14:28:06.18Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "flask" -version = "3.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "blinker" }, - { name = "click" }, - { name = "itsdangerous" }, - { name = "jinja2" }, - { name = "markupsafe" }, - { name = "werkzeug" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/de/e47735752347f4128bcf354e0da07ef311a78244eba9e3dc1d4a5ab21a98/flask-3.1.1.tar.gz", hash = "sha256:284c7b8f2f58cb737f0cf1c30fd7eaf0ccfcde196099d24ecede3fc2005aa59e", size = 753440, upload-time = "2025-05-13T15:01:17.447Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl", hash = "sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c", size = 103305, upload-time = "2025-05-13T15:01:15.591Z" }, -] - -[[package]] -name = "frozenlist" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, - { url = "https://files.pythonhosted.org/packages/77/f0/77c11d13d39513b298e267b22eb6cb559c103d56f155aa9a49097221f0b6/frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61", size = 47735, upload-time = "2025-06-09T22:59:48.133Z" }, - { url = "https://files.pythonhosted.org/packages/37/12/9d07fa18971a44150593de56b2f2947c46604819976784bcf6ea0d5db43b/frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d", size = 46775, upload-time = "2025-06-09T22:59:49.564Z" }, - { url = "https://files.pythonhosted.org/packages/70/34/f73539227e06288fcd1f8a76853e755b2b48bca6747e99e283111c18bcd4/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e", size = 224644, upload-time = "2025-06-09T22:59:51.35Z" }, - { url = "https://files.pythonhosted.org/packages/fb/68/c1d9c2f4a6e438e14613bad0f2973567586610cc22dcb1e1241da71de9d3/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9", size = 222125, upload-time = "2025-06-09T22:59:52.884Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d0/98e8f9a515228d708344d7c6986752be3e3192d1795f748c24bcf154ad99/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c", size = 233455, upload-time = "2025-06-09T22:59:54.74Z" }, - { url = "https://files.pythonhosted.org/packages/79/df/8a11bcec5600557f40338407d3e5bea80376ed1c01a6c0910fcfdc4b8993/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981", size = 227339, upload-time = "2025-06-09T22:59:56.187Z" }, - { url = "https://files.pythonhosted.org/packages/50/82/41cb97d9c9a5ff94438c63cc343eb7980dac4187eb625a51bdfdb7707314/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615", size = 212969, upload-time = "2025-06-09T22:59:57.604Z" }, - { url = "https://files.pythonhosted.org/packages/13/47/f9179ee5ee4f55629e4f28c660b3fdf2775c8bfde8f9c53f2de2d93f52a9/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50", size = 222862, upload-time = "2025-06-09T22:59:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/df81e41ec6b953902c8b7e3a83bee48b195cb0e5ec2eabae5d8330c78038/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa", size = 222492, upload-time = "2025-06-09T23:00:01.026Z" }, - { url = "https://files.pythonhosted.org/packages/84/17/30d6ea87fa95a9408245a948604b82c1a4b8b3e153cea596421a2aef2754/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577", size = 238250, upload-time = "2025-06-09T23:00:03.401Z" }, - { url = "https://files.pythonhosted.org/packages/8f/00/ecbeb51669e3c3df76cf2ddd66ae3e48345ec213a55e3887d216eb4fbab3/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59", size = 218720, upload-time = "2025-06-09T23:00:05.282Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c0/c224ce0e0eb31cc57f67742071bb470ba8246623c1823a7530be0e76164c/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e", size = 232585, upload-time = "2025-06-09T23:00:07.962Z" }, - { url = "https://files.pythonhosted.org/packages/55/3c/34cb694abf532f31f365106deebdeac9e45c19304d83cf7d51ebbb4ca4d1/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd", size = 234248, upload-time = "2025-06-09T23:00:09.428Z" }, - { url = "https://files.pythonhosted.org/packages/98/c0/2052d8b6cecda2e70bd81299e3512fa332abb6dcd2969b9c80dfcdddbf75/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718", size = 221621, upload-time = "2025-06-09T23:00:11.32Z" }, - { url = "https://files.pythonhosted.org/packages/c5/bf/7dcebae315436903b1d98ffb791a09d674c88480c158aa171958a3ac07f0/frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e", size = 39578, upload-time = "2025-06-09T23:00:13.526Z" }, - { url = "https://files.pythonhosted.org/packages/8f/5f/f69818f017fa9a3d24d1ae39763e29b7f60a59e46d5f91b9c6b21622f4cd/frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464", size = 43830, upload-time = "2025-06-09T23:00:14.98Z" }, - { url = "https://files.pythonhosted.org/packages/34/7e/803dde33760128acd393a27eb002f2020ddb8d99d30a44bfbaab31c5f08a/frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a", size = 82251, upload-time = "2025-06-09T23:00:16.279Z" }, - { url = "https://files.pythonhosted.org/packages/75/a9/9c2c5760b6ba45eae11334db454c189d43d34a4c0b489feb2175e5e64277/frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750", size = 48183, upload-time = "2025-06-09T23:00:17.698Z" }, - { url = "https://files.pythonhosted.org/packages/47/be/4038e2d869f8a2da165f35a6befb9158c259819be22eeaf9c9a8f6a87771/frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd", size = 47107, upload-time = "2025-06-09T23:00:18.952Z" }, - { url = "https://files.pythonhosted.org/packages/79/26/85314b8a83187c76a37183ceed886381a5f992975786f883472fcb6dc5f2/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2", size = 237333, upload-time = "2025-06-09T23:00:20.275Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fd/e5b64f7d2c92a41639ffb2ad44a6a82f347787abc0c7df5f49057cf11770/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f", size = 231724, upload-time = "2025-06-09T23:00:21.705Z" }, - { url = "https://files.pythonhosted.org/packages/20/fb/03395c0a43a5976af4bf7534759d214405fbbb4c114683f434dfdd3128ef/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30", size = 245842, upload-time = "2025-06-09T23:00:23.148Z" }, - { url = "https://files.pythonhosted.org/packages/d0/15/c01c8e1dffdac5d9803507d824f27aed2ba76b6ed0026fab4d9866e82f1f/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98", size = 239767, upload-time = "2025-06-09T23:00:25.103Z" }, - { url = "https://files.pythonhosted.org/packages/14/99/3f4c6fe882c1f5514b6848aa0a69b20cb5e5d8e8f51a339d48c0e9305ed0/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86", size = 224130, upload-time = "2025-06-09T23:00:27.061Z" }, - { url = "https://files.pythonhosted.org/packages/4d/83/220a374bd7b2aeba9d0725130665afe11de347d95c3620b9b82cc2fcab97/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae", size = 235301, upload-time = "2025-06-09T23:00:29.02Z" }, - { url = "https://files.pythonhosted.org/packages/03/3c/3e3390d75334a063181625343e8daab61b77e1b8214802cc4e8a1bb678fc/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8", size = 234606, upload-time = "2025-06-09T23:00:30.514Z" }, - { url = "https://files.pythonhosted.org/packages/23/1e/58232c19608b7a549d72d9903005e2d82488f12554a32de2d5fb59b9b1ba/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31", size = 248372, upload-time = "2025-06-09T23:00:31.966Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a4/e4a567e01702a88a74ce8a324691e62a629bf47d4f8607f24bf1c7216e7f/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7", size = 229860, upload-time = "2025-06-09T23:00:33.375Z" }, - { url = "https://files.pythonhosted.org/packages/73/a6/63b3374f7d22268b41a9db73d68a8233afa30ed164c46107b33c4d18ecdd/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5", size = 245893, upload-time = "2025-06-09T23:00:35.002Z" }, - { url = "https://files.pythonhosted.org/packages/6d/eb/d18b3f6e64799a79673c4ba0b45e4cfbe49c240edfd03a68be20002eaeaa/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898", size = 246323, upload-time = "2025-06-09T23:00:36.468Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f5/720f3812e3d06cd89a1d5db9ff6450088b8f5c449dae8ffb2971a44da506/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56", size = 233149, upload-time = "2025-06-09T23:00:37.963Z" }, - { url = "https://files.pythonhosted.org/packages/69/68/03efbf545e217d5db8446acfd4c447c15b7c8cf4dbd4a58403111df9322d/frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7", size = 39565, upload-time = "2025-06-09T23:00:39.753Z" }, - { url = "https://files.pythonhosted.org/packages/58/17/fe61124c5c333ae87f09bb67186d65038834a47d974fc10a5fadb4cc5ae1/frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d", size = 44019, upload-time = "2025-06-09T23:00:40.988Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, - { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, - { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, - { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, - { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, - { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, - { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, - { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, - { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, - { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" }, - { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" }, - { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" }, - { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" }, - { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" }, - { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" }, - { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" }, - { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" }, - { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" }, - { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" }, - { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" }, - { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" }, - { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" }, - { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" }, - { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" }, - { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" }, - { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" }, - { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" }, - { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" }, - { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" }, - { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" }, - { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" }, - { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" }, - { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" }, - { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" }, - { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" }, - { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" }, - { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" }, - { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" }, - { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" }, - { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" }, - { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "hexbytes" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/87/adf4635b4b8c050283d74e6db9a81496063229c9263e6acc1903ab79fbec/hexbytes-1.3.1.tar.gz", hash = "sha256:a657eebebdfe27254336f98d8af6e2236f3f83aed164b87466b6cf6c5f5a4765", size = 8633, upload-time = "2025-05-14T16:45:17.5Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/e0/3b31492b1c89da3c5a846680517871455b30c54738486fc57ac79a5761bd/hexbytes-1.3.1-py3-none-any.whl", hash = "sha256:da01ff24a1a9a2b1881c4b85f0e9f9b0f51b526b379ffa23832ae7899d29c2c7", size = 5074, upload-time = "2025-05-14T16:45:16.179Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httptools" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/17c672b4bc5c7ba7f201eada4e96c71d0a59fbc185e60e42580093a86f21/httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da", size = 103297, upload-time = "2024-10-16T19:44:08.129Z" }, - { url = "https://files.pythonhosted.org/packages/92/5e/b4a826fe91971a0b68e8c2bd4e7db3e7519882f5a8ccdb1194be2b3ab98f/httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1", size = 443130, upload-time = "2024-10-16T19:44:09.45Z" }, - { url = "https://files.pythonhosted.org/packages/b0/51/ce61e531e40289a681a463e1258fa1e05e0be54540e40d91d065a264cd8f/httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50", size = 442148, upload-time = "2024-10-16T19:44:11.539Z" }, - { url = "https://files.pythonhosted.org/packages/ea/9e/270b7d767849b0c96f275c695d27ca76c30671f8eb8cc1bab6ced5c5e1d0/httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959", size = 415949, upload-time = "2024-10-16T19:44:13.388Z" }, - { url = "https://files.pythonhosted.org/packages/81/86/ced96e3179c48c6f656354e106934e65c8963d48b69be78f355797f0e1b3/httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4", size = 417591, upload-time = "2024-10-16T19:44:15.258Z" }, - { url = "https://files.pythonhosted.org/packages/75/73/187a3f620ed3175364ddb56847d7a608a6fc42d551e133197098c0143eca/httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c", size = 88344, upload-time = "2024-10-16T19:44:16.54Z" }, - { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029, upload-time = "2024-10-16T19:44:18.427Z" }, - { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492, upload-time = "2024-10-16T19:44:19.515Z" }, - { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891, upload-time = "2024-10-16T19:44:21.067Z" }, - { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788, upload-time = "2024-10-16T19:44:22.958Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214, upload-time = "2024-10-16T19:44:24.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120, upload-time = "2024-10-16T19:44:26.295Z" }, - { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565, upload-time = "2024-10-16T19:44:29.188Z" }, - { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683, upload-time = "2024-10-16T19:44:30.175Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337, upload-time = "2024-10-16T19:44:31.786Z" }, - { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796, upload-time = "2024-10-16T19:44:32.825Z" }, - { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837, upload-time = "2024-10-16T19:44:33.974Z" }, - { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289, upload-time = "2024-10-16T19:44:35.111Z" }, - { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779, upload-time = "2024-10-16T19:44:36.253Z" }, - { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634, upload-time = "2024-10-16T19:44:37.357Z" }, - { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" }, - { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" }, - { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" }, - { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" }, - { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" }, - { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "itsdangerous" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "multidict" -version = "6.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/2f/a3470242707058fe856fe59241eee5635d79087100b7042a867368863a27/multidict-6.4.4.tar.gz", hash = "sha256:69ee9e6ba214b5245031b76233dd95408a0fd57fdb019ddcc1ead4790932a8e8", size = 90183, upload-time = "2025-05-19T14:16:37.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/92/0926a5baafa164b5d0ade3cd7932be39310375d7e25c9d7ceca05cb26a45/multidict-6.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8adee3ac041145ffe4488ea73fa0a622b464cc25340d98be76924d0cda8545ff", size = 66052, upload-time = "2025-05-19T14:13:49.944Z" }, - { url = "https://files.pythonhosted.org/packages/b2/54/8a857ae4f8f643ec444d91f419fdd49cc7a90a2ca0e42d86482b604b63bd/multidict-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b61e98c3e2a861035aaccd207da585bdcacef65fe01d7a0d07478efac005e028", size = 38867, upload-time = "2025-05-19T14:13:51.92Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5f/63add9069f945c19bc8b217ea6b0f8a1ad9382eab374bb44fae4354b3baf/multidict-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75493f28dbadecdbb59130e74fe935288813301a8554dc32f0c631b6bdcdf8b0", size = 38138, upload-time = "2025-05-19T14:13:53.778Z" }, - { url = "https://files.pythonhosted.org/packages/97/8b/fbd9c0fc13966efdb4a47f5bcffff67a4f2a3189fbeead5766eaa4250b20/multidict-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc3c6a37e048b5395ee235e4a2a0d639c2349dffa32d9367a42fc20d399772", size = 220433, upload-time = "2025-05-19T14:13:55.346Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c4/5132b2d75b3ea2daedb14d10f91028f09f74f5b4d373b242c1b8eec47571/multidict-6.4.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87cb72263946b301570b0f63855569a24ee8758aaae2cd182aae7d95fbc92ca7", size = 218059, upload-time = "2025-05-19T14:13:56.993Z" }, - { url = "https://files.pythonhosted.org/packages/1a/70/f1e818c7a29b908e2d7b4fafb1d7939a41c64868e79de2982eea0a13193f/multidict-6.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bbf7bd39822fd07e3609b6b4467af4c404dd2b88ee314837ad1830a7f4a8299", size = 231120, upload-time = "2025-05-19T14:13:58.333Z" }, - { url = "https://files.pythonhosted.org/packages/b4/7e/95a194d85f27d5ef9cbe48dff9ded722fc6d12fedf641ec6e1e680890be7/multidict-6.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1f7cbd4f1f44ddf5fd86a8675b7679176eae770f2fc88115d6dddb6cefb59bc", size = 227457, upload-time = "2025-05-19T14:13:59.663Z" }, - { url = "https://files.pythonhosted.org/packages/25/2b/590ad220968d1babb42f265debe7be5c5c616df6c5688c995a06d8a9b025/multidict-6.4.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb5ac9e5bfce0e6282e7f59ff7b7b9a74aa8e5c60d38186a4637f5aa764046ad", size = 219111, upload-time = "2025-05-19T14:14:01.019Z" }, - { url = "https://files.pythonhosted.org/packages/e0/f0/b07682b995d3fb5313f339b59d7de02db19ba0c02d1f77c27bdf8212d17c/multidict-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4efc31dfef8c4eeb95b6b17d799eedad88c4902daba39ce637e23a17ea078915", size = 213012, upload-time = "2025-05-19T14:14:02.396Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/c77b5f36feef2ec92f1119756e468ac9c3eebc35aa8a4c9e51df664cbbc9/multidict-6.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9fcad2945b1b91c29ef2b4050f590bfcb68d8ac8e0995a74e659aa57e8d78e01", size = 225408, upload-time = "2025-05-19T14:14:04.826Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b3/e8189b82af9b198b47bc637766208fc917189eea91d674bad417e657bbdf/multidict-6.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d877447e7368c7320832acb7159557e49b21ea10ffeb135c1077dbbc0816b598", size = 214396, upload-time = "2025-05-19T14:14:06.187Z" }, - { url = "https://files.pythonhosted.org/packages/20/e0/200d14c84e35ae13ee99fd65dc106e1a1acb87a301f15e906fc7d5b30c17/multidict-6.4.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:33a12ebac9f380714c298cbfd3e5b9c0c4e89c75fe612ae496512ee51028915f", size = 222237, upload-time = "2025-05-19T14:14:07.778Z" }, - { url = "https://files.pythonhosted.org/packages/13/f3/bb3df40045ca8262694a3245298732ff431dc781414a89a6a364ebac6840/multidict-6.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0f14ea68d29b43a9bf37953881b1e3eb75b2739e896ba4a6aa4ad4c5b9ffa145", size = 231425, upload-time = "2025-05-19T14:14:09.516Z" }, - { url = "https://files.pythonhosted.org/packages/85/3b/538563dc18514384dac169bcba938753ad9ab4d4c8d49b55d6ae49fb2579/multidict-6.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0327ad2c747a6600e4797d115d3c38a220fdb28e54983abe8964fd17e95ae83c", size = 226251, upload-time = "2025-05-19T14:14:10.82Z" }, - { url = "https://files.pythonhosted.org/packages/56/79/77e1a65513f09142358f1beb1d4cbc06898590b34a7de2e47023e3c5a3a2/multidict-6.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d1a20707492db9719a05fc62ee215fd2c29b22b47c1b1ba347f9abc831e26683", size = 220363, upload-time = "2025-05-19T14:14:12.638Z" }, - { url = "https://files.pythonhosted.org/packages/16/57/67b0516c3e348f8daaa79c369b3de4359a19918320ab82e2e586a1c624ef/multidict-6.4.4-cp310-cp310-win32.whl", hash = "sha256:d83f18315b9fca5db2452d1881ef20f79593c4aa824095b62cb280019ef7aa3d", size = 35175, upload-time = "2025-05-19T14:14:14.805Z" }, - { url = "https://files.pythonhosted.org/packages/86/5a/4ed8fec642d113fa653777cda30ef67aa5c8a38303c091e24c521278a6c6/multidict-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:9c17341ee04545fd962ae07330cb5a39977294c883485c8d74634669b1f7fe04", size = 38678, upload-time = "2025-05-19T14:14:16.949Z" }, - { url = "https://files.pythonhosted.org/packages/19/1b/4c6e638195851524a63972c5773c7737bea7e47b1ba402186a37773acee2/multidict-6.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f5f29794ac0e73d2a06ac03fd18870adc0135a9d384f4a306a951188ed02f95", size = 65515, upload-time = "2025-05-19T14:14:19.767Z" }, - { url = "https://files.pythonhosted.org/packages/25/d5/10e6bca9a44b8af3c7f920743e5fc0c2bcf8c11bf7a295d4cfe00b08fb46/multidict-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c04157266344158ebd57b7120d9b0b35812285d26d0e78193e17ef57bfe2979a", size = 38609, upload-time = "2025-05-19T14:14:21.538Z" }, - { url = "https://files.pythonhosted.org/packages/26/b4/91fead447ccff56247edc7f0535fbf140733ae25187a33621771ee598a18/multidict-6.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb61ffd3ab8310d93427e460f565322c44ef12769f51f77277b4abad7b6f7223", size = 37871, upload-time = "2025-05-19T14:14:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/3b/37/cbc977cae59277e99d15bbda84cc53b5e0c4929ffd91d958347200a42ad0/multidict-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e0ba18a9afd495f17c351d08ebbc4284e9c9f7971d715f196b79636a4d0de44", size = 226661, upload-time = "2025-05-19T14:14:24.124Z" }, - { url = "https://files.pythonhosted.org/packages/15/cd/7e0b57fbd4dc2fc105169c4ecce5be1a63970f23bb4ec8c721b67e11953d/multidict-6.4.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9faf1b1dcaadf9f900d23a0e6d6c8eadd6a95795a0e57fcca73acce0eb912065", size = 223422, upload-time = "2025-05-19T14:14:25.437Z" }, - { url = "https://files.pythonhosted.org/packages/f1/01/1de268da121bac9f93242e30cd3286f6a819e5f0b8896511162d6ed4bf8d/multidict-6.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4d1cb1327c6082c4fce4e2a438483390964c02213bc6b8d782cf782c9b1471f", size = 235447, upload-time = "2025-05-19T14:14:26.793Z" }, - { url = "https://files.pythonhosted.org/packages/d2/8c/8b9a5e4aaaf4f2de14e86181a3a3d7b105077f668b6a06f043ec794f684c/multidict-6.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:941f1bec2f5dbd51feeb40aea654c2747f811ab01bdd3422a48a4e4576b7d76a", size = 231455, upload-time = "2025-05-19T14:14:28.149Z" }, - { url = "https://files.pythonhosted.org/packages/35/db/e1817dcbaa10b319c412769cf999b1016890849245d38905b73e9c286862/multidict-6.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5f8a146184da7ea12910a4cec51ef85e44f6268467fb489c3caf0cd512f29c2", size = 223666, upload-time = "2025-05-19T14:14:29.584Z" }, - { url = "https://files.pythonhosted.org/packages/4a/e1/66e8579290ade8a00e0126b3d9a93029033ffd84f0e697d457ed1814d0fc/multidict-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:232b7237e57ec3c09be97206bfb83a0aa1c5d7d377faa019c68a210fa35831f1", size = 217392, upload-time = "2025-05-19T14:14:30.961Z" }, - { url = "https://files.pythonhosted.org/packages/7b/6f/f8639326069c24a48c7747c2a5485d37847e142a3f741ff3340c88060a9a/multidict-6.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:55ae0721c1513e5e3210bca4fc98456b980b0c2c016679d3d723119b6b202c42", size = 228969, upload-time = "2025-05-19T14:14:32.672Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c3/3d58182f76b960eeade51c89fcdce450f93379340457a328e132e2f8f9ed/multidict-6.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d662c072579f63137919d7bb8fc250655ce79f00c82ecf11cab678f335062e", size = 217433, upload-time = "2025-05-19T14:14:34.016Z" }, - { url = "https://files.pythonhosted.org/packages/e1/4b/f31a562906f3bd375f3d0e83ce314e4a660c01b16c2923e8229b53fba5d7/multidict-6.4.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0e05c39962baa0bb19a6b210e9b1422c35c093b651d64246b6c2e1a7e242d9fd", size = 225418, upload-time = "2025-05-19T14:14:35.376Z" }, - { url = "https://files.pythonhosted.org/packages/99/89/78bb95c89c496d64b5798434a3deee21996114d4d2c28dd65850bf3a691e/multidict-6.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b1cc3ab8c31d9ebf0faa6e3540fb91257590da330ffe6d2393d4208e638925", size = 235042, upload-time = "2025-05-19T14:14:36.723Z" }, - { url = "https://files.pythonhosted.org/packages/74/91/8780a6e5885a8770442a8f80db86a0887c4becca0e5a2282ba2cae702bc4/multidict-6.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:93ec84488a384cd7b8a29c2c7f467137d8a73f6fe38bb810ecf29d1ade011a7c", size = 230280, upload-time = "2025-05-19T14:14:38.194Z" }, - { url = "https://files.pythonhosted.org/packages/68/c1/fcf69cabd542eb6f4b892469e033567ee6991d361d77abdc55e3a0f48349/multidict-6.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b308402608493638763abc95f9dc0030bbd6ac6aff784512e8ac3da73a88af08", size = 223322, upload-time = "2025-05-19T14:14:40.015Z" }, - { url = "https://files.pythonhosted.org/packages/b8/85/5b80bf4b83d8141bd763e1d99142a9cdfd0db83f0739b4797172a4508014/multidict-6.4.4-cp311-cp311-win32.whl", hash = "sha256:343892a27d1a04d6ae455ecece12904d242d299ada01633d94c4f431d68a8c49", size = 35070, upload-time = "2025-05-19T14:14:41.904Z" }, - { url = "https://files.pythonhosted.org/packages/09/66/0bed198ffd590ab86e001f7fa46b740d58cf8ff98c2f254e4a36bf8861ad/multidict-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:73484a94f55359780c0f458bbd3c39cb9cf9c182552177d2136e828269dee529", size = 38667, upload-time = "2025-05-19T14:14:43.534Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b5/5675377da23d60875fe7dae6be841787755878e315e2f517235f22f59e18/multidict-6.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc388f75a1c00000824bf28b7633e40854f4127ede80512b44c3cfeeea1839a2", size = 64293, upload-time = "2025-05-19T14:14:44.724Z" }, - { url = "https://files.pythonhosted.org/packages/34/a7/be384a482754bb8c95d2bbe91717bf7ccce6dc38c18569997a11f95aa554/multidict-6.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:98af87593a666f739d9dba5d0ae86e01b0e1a9cfcd2e30d2d361fbbbd1a9162d", size = 38096, upload-time = "2025-05-19T14:14:45.95Z" }, - { url = "https://files.pythonhosted.org/packages/66/6d/d59854bb4352306145bdfd1704d210731c1bb2c890bfee31fb7bbc1c4c7f/multidict-6.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aff4cafea2d120327d55eadd6b7f1136a8e5a0ecf6fb3b6863e8aca32cd8e50a", size = 37214, upload-time = "2025-05-19T14:14:47.158Z" }, - { url = "https://files.pythonhosted.org/packages/99/e0/c29d9d462d7cfc5fc8f9bf24f9c6843b40e953c0b55e04eba2ad2cf54fba/multidict-6.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:169c4ba7858176b797fe551d6e99040c531c775d2d57b31bcf4de6d7a669847f", size = 224686, upload-time = "2025-05-19T14:14:48.366Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4a/da99398d7fd8210d9de068f9a1b5f96dfaf67d51e3f2521f17cba4ee1012/multidict-6.4.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9eb4c59c54421a32b3273d4239865cb14ead53a606db066d7130ac80cc8ec93", size = 231061, upload-time = "2025-05-19T14:14:49.952Z" }, - { url = "https://files.pythonhosted.org/packages/21/f5/ac11add39a0f447ac89353e6ca46666847051103649831c08a2800a14455/multidict-6.4.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cf3bd54c56aa16fdb40028d545eaa8d051402b61533c21e84046e05513d5780", size = 232412, upload-time = "2025-05-19T14:14:51.812Z" }, - { url = "https://files.pythonhosted.org/packages/d9/11/4b551e2110cded705a3c13a1d4b6a11f73891eb5a1c449f1b2b6259e58a6/multidict-6.4.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f682c42003c7264134bfe886376299db4cc0c6cd06a3295b41b347044bcb5482", size = 231563, upload-time = "2025-05-19T14:14:53.262Z" }, - { url = "https://files.pythonhosted.org/packages/4c/02/751530c19e78fe73b24c3da66618eda0aa0d7f6e7aa512e46483de6be210/multidict-6.4.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920f9cf2abdf6e493c519492d892c362007f113c94da4c239ae88429835bad1", size = 223811, upload-time = "2025-05-19T14:14:55.232Z" }, - { url = "https://files.pythonhosted.org/packages/c7/cb/2be8a214643056289e51ca356026c7b2ce7225373e7a1f8c8715efee8988/multidict-6.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:530d86827a2df6504526106b4c104ba19044594f8722d3e87714e847c74a0275", size = 216524, upload-time = "2025-05-19T14:14:57.226Z" }, - { url = "https://files.pythonhosted.org/packages/19/f3/6d5011ec375c09081f5250af58de85f172bfcaafebff286d8089243c4bd4/multidict-6.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ecde56ea2439b96ed8a8d826b50c57364612ddac0438c39e473fafad7ae1c23b", size = 229012, upload-time = "2025-05-19T14:14:58.597Z" }, - { url = "https://files.pythonhosted.org/packages/67/9c/ca510785df5cf0eaf5b2a8132d7d04c1ce058dcf2c16233e596ce37a7f8e/multidict-6.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:dc8c9736d8574b560634775ac0def6bdc1661fc63fa27ffdfc7264c565bcb4f2", size = 226765, upload-time = "2025-05-19T14:15:00.048Z" }, - { url = "https://files.pythonhosted.org/packages/36/c8/ca86019994e92a0f11e642bda31265854e6ea7b235642f0477e8c2e25c1f/multidict-6.4.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7f3d3b3c34867579ea47cbd6c1f2ce23fbfd20a273b6f9e3177e256584f1eacc", size = 222888, upload-time = "2025-05-19T14:15:01.568Z" }, - { url = "https://files.pythonhosted.org/packages/c6/67/bc25a8e8bd522935379066950ec4e2277f9b236162a73548a2576d4b9587/multidict-6.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:87a728af265e08f96b6318ebe3c0f68b9335131f461efab2fc64cc84a44aa6ed", size = 234041, upload-time = "2025-05-19T14:15:03.759Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a0/70c4c2d12857fccbe607b334b7ee28b6b5326c322ca8f73ee54e70d76484/multidict-6.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9f193eeda1857f8e8d3079a4abd258f42ef4a4bc87388452ed1e1c4d2b0c8740", size = 231046, upload-time = "2025-05-19T14:15:05.698Z" }, - { url = "https://files.pythonhosted.org/packages/c1/0f/52954601d02d39742aab01d6b92f53c1dd38b2392248154c50797b4df7f1/multidict-6.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be06e73c06415199200e9a2324a11252a3d62030319919cde5e6950ffeccf72e", size = 227106, upload-time = "2025-05-19T14:15:07.124Z" }, - { url = "https://files.pythonhosted.org/packages/af/24/679d83ec4379402d28721790dce818e5d6b9f94ce1323a556fb17fa9996c/multidict-6.4.4-cp312-cp312-win32.whl", hash = "sha256:622f26ea6a7e19b7c48dd9228071f571b2fbbd57a8cd71c061e848f281550e6b", size = 35351, upload-time = "2025-05-19T14:15:08.556Z" }, - { url = "https://files.pythonhosted.org/packages/52/ef/40d98bc5f986f61565f9b345f102409534e29da86a6454eb6b7c00225a13/multidict-6.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:5e2bcda30d5009996ff439e02a9f2b5c3d64a20151d34898c000a6281faa3781", size = 38791, upload-time = "2025-05-19T14:15:09.825Z" }, - { url = "https://files.pythonhosted.org/packages/df/2a/e166d2ffbf4b10131b2d5b0e458f7cee7d986661caceae0de8753042d4b2/multidict-6.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:82ffabefc8d84c2742ad19c37f02cde5ec2a1ee172d19944d380f920a340e4b9", size = 64123, upload-time = "2025-05-19T14:15:11.044Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/e200e379ae5b6f95cbae472e0199ea98913f03d8c9a709f42612a432932c/multidict-6.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6a2f58a66fe2c22615ad26156354005391e26a2f3721c3621504cd87c1ea87bf", size = 38049, upload-time = "2025-05-19T14:15:12.902Z" }, - { url = "https://files.pythonhosted.org/packages/75/fb/47afd17b83f6a8c7fa863c6d23ac5ba6a0e6145ed8a6bcc8da20b2b2c1d2/multidict-6.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5883d6ee0fd9d8a48e9174df47540b7545909841ac82354c7ae4cbe9952603bd", size = 37078, upload-time = "2025-05-19T14:15:14.282Z" }, - { url = "https://files.pythonhosted.org/packages/fa/70/1af3143000eddfb19fd5ca5e78393985ed988ac493bb859800fe0914041f/multidict-6.4.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9abcf56a9511653fa1d052bfc55fbe53dbee8f34e68bd6a5a038731b0ca42d15", size = 224097, upload-time = "2025-05-19T14:15:15.566Z" }, - { url = "https://files.pythonhosted.org/packages/b1/39/d570c62b53d4fba844e0378ffbcd02ac25ca423d3235047013ba2f6f60f8/multidict-6.4.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6ed5ae5605d4ad5a049fad2a28bb7193400700ce2f4ae484ab702d1e3749c3f9", size = 230768, upload-time = "2025-05-19T14:15:17.308Z" }, - { url = "https://files.pythonhosted.org/packages/fd/f8/ed88f2c4d06f752b015933055eb291d9bc184936903752c66f68fb3c95a7/multidict-6.4.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbfcb60396f9bcfa63e017a180c3105b8c123a63e9d1428a36544e7d37ca9e20", size = 231331, upload-time = "2025-05-19T14:15:18.73Z" }, - { url = "https://files.pythonhosted.org/packages/9c/6f/8e07cffa32f483ab887b0d56bbd8747ac2c1acd00dc0af6fcf265f4a121e/multidict-6.4.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0f1987787f5f1e2076b59692352ab29a955b09ccc433c1f6b8e8e18666f608b", size = 230169, upload-time = "2025-05-19T14:15:20.179Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2b/5dcf173be15e42f330110875a2668ddfc208afc4229097312212dc9c1236/multidict-6.4.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0121ccce8c812047d8d43d691a1ad7641f72c4f730474878a5aeae1b8ead8c", size = 222947, upload-time = "2025-05-19T14:15:21.714Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/4ddcbcebe5ebcd6faa770b629260d15840a5fc07ce8ad295a32e14993726/multidict-6.4.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83ec4967114295b8afd120a8eec579920c882831a3e4c3331d591a8e5bfbbc0f", size = 215761, upload-time = "2025-05-19T14:15:23.242Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c9/55e998ae45ff15c5608e384206aa71a11e1b7f48b64d166db400b14a3433/multidict-6.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:995f985e2e268deaf17867801b859a282e0448633f1310e3704b30616d269d69", size = 227605, upload-time = "2025-05-19T14:15:24.763Z" }, - { url = "https://files.pythonhosted.org/packages/04/49/c2404eac74497503c77071bd2e6f88c7e94092b8a07601536b8dbe99be50/multidict-6.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d832c608f94b9f92a0ec8b7e949be7792a642b6e535fcf32f3e28fab69eeb046", size = 226144, upload-time = "2025-05-19T14:15:26.249Z" }, - { url = "https://files.pythonhosted.org/packages/62/c5/0cd0c3c6f18864c40846aa2252cd69d308699cb163e1c0d989ca301684da/multidict-6.4.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d21c1212171cf7da703c5b0b7a0e85be23b720818aef502ad187d627316d5645", size = 221100, upload-time = "2025-05-19T14:15:28.303Z" }, - { url = "https://files.pythonhosted.org/packages/71/7b/f2f3887bea71739a046d601ef10e689528d4f911d84da873b6be9194ffea/multidict-6.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:cbebaa076aaecad3d4bb4c008ecc73b09274c952cf6a1b78ccfd689e51f5a5b0", size = 232731, upload-time = "2025-05-19T14:15:30.263Z" }, - { url = "https://files.pythonhosted.org/packages/e5/b3/d9de808349df97fa75ec1372758701b5800ebad3c46ae377ad63058fbcc6/multidict-6.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c93a6fb06cc8e5d3628b2b5fda215a5db01e8f08fc15fadd65662d9b857acbe4", size = 229637, upload-time = "2025-05-19T14:15:33.337Z" }, - { url = "https://files.pythonhosted.org/packages/5e/57/13207c16b615eb4f1745b44806a96026ef8e1b694008a58226c2d8f5f0a5/multidict-6.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8cd8f81f1310182362fb0c7898145ea9c9b08a71081c5963b40ee3e3cac589b1", size = 225594, upload-time = "2025-05-19T14:15:34.832Z" }, - { url = "https://files.pythonhosted.org/packages/3a/e4/d23bec2f70221604f5565000632c305fc8f25ba953e8ce2d8a18842b9841/multidict-6.4.4-cp313-cp313-win32.whl", hash = "sha256:3e9f1cd61a0ab857154205fb0b1f3d3ace88d27ebd1409ab7af5096e409614cd", size = 35359, upload-time = "2025-05-19T14:15:36.246Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/cfe1a47632be861b627f46f642c1d031704cc1c0f5c0efbde2ad44aa34bd/multidict-6.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373", size = 38903, upload-time = "2025-05-19T14:15:37.507Z" }, - { url = "https://files.pythonhosted.org/packages/68/7b/15c259b0ab49938a0a1c8f3188572802704a779ddb294edc1b2a72252e7c/multidict-6.4.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6a602151dbf177be2450ef38966f4be3467d41a86c6a845070d12e17c858a156", size = 68895, upload-time = "2025-05-19T14:15:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/f1/7d/168b5b822bccd88142e0a3ce985858fea612404edd228698f5af691020c9/multidict-6.4.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d2b9712211b860d123815a80b859075d86a4d54787e247d7fbee9db6832cf1c", size = 40183, upload-time = "2025-05-19T14:15:40.197Z" }, - { url = "https://files.pythonhosted.org/packages/e0/b7/d4b8d98eb850ef28a4922ba508c31d90715fd9b9da3801a30cea2967130b/multidict-6.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d2fa86af59f8fc1972e121ade052145f6da22758f6996a197d69bb52f8204e7e", size = 39592, upload-time = "2025-05-19T14:15:41.508Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/a554678898a19583548e742080cf55d169733baf57efc48c2f0273a08583/multidict-6.4.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50855d03e9e4d66eab6947ba688ffb714616f985838077bc4b490e769e48da51", size = 226071, upload-time = "2025-05-19T14:15:42.877Z" }, - { url = "https://files.pythonhosted.org/packages/ee/dc/7ba6c789d05c310e294f85329efac1bf5b450338d2542498db1491a264df/multidict-6.4.4-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5bce06b83be23225be1905dcdb6b789064fae92499fbc458f59a8c0e68718601", size = 222597, upload-time = "2025-05-19T14:15:44.412Z" }, - { url = "https://files.pythonhosted.org/packages/24/4f/34eadbbf401b03768dba439be0fb94b0d187facae9142821a3d5599ccb3b/multidict-6.4.4-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66ed0731f8e5dfd8369a883b6e564aca085fb9289aacabd9decd70568b9a30de", size = 228253, upload-time = "2025-05-19T14:15:46.474Z" }, - { url = "https://files.pythonhosted.org/packages/c0/e6/493225a3cdb0d8d80d43a94503fc313536a07dae54a3f030d279e629a2bc/multidict-6.4.4-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:329ae97fc2f56f44d91bc47fe0972b1f52d21c4b7a2ac97040da02577e2daca2", size = 226146, upload-time = "2025-05-19T14:15:48.003Z" }, - { url = "https://files.pythonhosted.org/packages/2f/70/e411a7254dc3bff6f7e6e004303b1b0591358e9f0b7c08639941e0de8bd6/multidict-6.4.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c27e5dcf520923d6474d98b96749e6805f7677e93aaaf62656005b8643f907ab", size = 220585, upload-time = "2025-05-19T14:15:49.546Z" }, - { url = "https://files.pythonhosted.org/packages/08/8f/beb3ae7406a619100d2b1fb0022c3bb55a8225ab53c5663648ba50dfcd56/multidict-6.4.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:058cc59b9e9b143cc56715e59e22941a5d868c322242278d28123a5d09cdf6b0", size = 212080, upload-time = "2025-05-19T14:15:51.151Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ec/355124e9d3d01cf8edb072fd14947220f357e1c5bc79c88dff89297e9342/multidict-6.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:69133376bc9a03f8c47343d33f91f74a99c339e8b58cea90433d8e24bb298031", size = 226558, upload-time = "2025-05-19T14:15:52.665Z" }, - { url = "https://files.pythonhosted.org/packages/fd/22/d2b95cbebbc2ada3be3812ea9287dcc9712d7f1a012fad041770afddb2ad/multidict-6.4.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d6b15c55721b1b115c5ba178c77104123745b1417527ad9641a4c5e2047450f0", size = 212168, upload-time = "2025-05-19T14:15:55.279Z" }, - { url = "https://files.pythonhosted.org/packages/4d/c5/62bfc0b2f9ce88326dbe7179f9824a939c6c7775b23b95de777267b9725c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a887b77f51d3d41e6e1a63cf3bc7ddf24de5939d9ff69441387dfefa58ac2e26", size = 217970, upload-time = "2025-05-19T14:15:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/79/74/977cea1aadc43ff1c75d23bd5bc4768a8fac98c14e5878d6ee8d6bab743c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:632a3bf8f1787f7ef7d3c2f68a7bde5be2f702906f8b5842ad6da9d974d0aab3", size = 226980, upload-time = "2025-05-19T14:15:58.313Z" }, - { url = "https://files.pythonhosted.org/packages/48/fc/cc4a1a2049df2eb84006607dc428ff237af38e0fcecfdb8a29ca47b1566c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a145c550900deb7540973c5cdb183b0d24bed6b80bf7bddf33ed8f569082535e", size = 220641, upload-time = "2025-05-19T14:15:59.866Z" }, - { url = "https://files.pythonhosted.org/packages/3b/6a/a7444d113ab918701988d4abdde373dbdfd2def7bd647207e2bf645c7eac/multidict-6.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc5d83c6619ca5c9672cb78b39ed8542f1975a803dee2cda114ff73cbb076edd", size = 221728, upload-time = "2025-05-19T14:16:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b0/fdf4c73ad1c55e0f4dbbf2aa59dd37037334091f9a4961646d2b7ac91a86/multidict-6.4.4-cp313-cp313t-win32.whl", hash = "sha256:3312f63261b9df49be9d57aaa6abf53a6ad96d93b24f9cc16cf979956355ce6e", size = 41913, upload-time = "2025-05-19T14:16:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/8e/92/27989ecca97e542c0d01d05a98a5ae12198a243a9ee12563a0313291511f/multidict-6.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:ba852168d814b2c73333073e1c7116d9395bea69575a01b0b3c89d2d5a87c8fb", size = 46112, upload-time = "2025-05-19T14:16:04.909Z" }, - { url = "https://files.pythonhosted.org/packages/84/5d/e17845bb0fa76334477d5de38654d27946d5b5d3695443987a094a71b440/multidict-6.4.4-py3-none-any.whl", hash = "sha256:bd4557071b561a8b3b6075c3ce93cf9bfb6182cb241805c3d66ced3b75eff4ac", size = 10481, upload-time = "2025-05-19T14:16:36.024Z" }, -] - -[[package]] -name = "parsimonious" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7b/91/abdc50c4ef06fdf8d047f60ee777ca9b2a7885e1a9cea81343fbecda52d7/parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c", size = 52172, upload-time = "2022-09-03T17:01:17.004Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/0f/c8b64d9b54ea631fcad4e9e3c8dbe8c11bb32a623be94f22974c88e71eaf/parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f", size = 48427, upload-time = "2022-09-03T17:01:13.814Z" }, -] - -[[package]] -name = "propcache" -version = "0.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4e/ad52a7925ff01c1325653a730c7ec3175a23f948f08626a534133427dcff/propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3", size = 43133, upload-time = "2025-06-09T22:53:41.965Z" }, - { url = "https://files.pythonhosted.org/packages/63/7c/e9399ba5da7780871db4eac178e9c2e204c23dd3e7d32df202092a1ed400/propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3", size = 43039, upload-time = "2025-06-09T22:53:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/22/e1/58da211eb8fdc6fc854002387d38f415a6ca5f5c67c1315b204a5d3e9d7a/propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e", size = 201903, upload-time = "2025-06-09T22:53:44.872Z" }, - { url = "https://files.pythonhosted.org/packages/c4/0a/550ea0f52aac455cb90111c8bab995208443e46d925e51e2f6ebdf869525/propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220", size = 213362, upload-time = "2025-06-09T22:53:46.707Z" }, - { url = "https://files.pythonhosted.org/packages/5a/af/9893b7d878deda9bb69fcf54600b247fba7317761b7db11fede6e0f28bd0/propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb", size = 210525, upload-time = "2025-06-09T22:53:48.547Z" }, - { url = "https://files.pythonhosted.org/packages/7c/bb/38fd08b278ca85cde36d848091ad2b45954bc5f15cce494bb300b9285831/propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614", size = 198283, upload-time = "2025-06-09T22:53:50.067Z" }, - { url = "https://files.pythonhosted.org/packages/78/8c/9fe55bd01d362bafb413dfe508c48753111a1e269737fa143ba85693592c/propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50", size = 191872, upload-time = "2025-06-09T22:53:51.438Z" }, - { url = "https://files.pythonhosted.org/packages/54/14/4701c33852937a22584e08abb531d654c8bcf7948a8f87ad0a4822394147/propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339", size = 199452, upload-time = "2025-06-09T22:53:53.229Z" }, - { url = "https://files.pythonhosted.org/packages/16/44/447f2253d859602095356007657ee535e0093215ea0b3d1d6a41d16e5201/propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0", size = 191567, upload-time = "2025-06-09T22:53:54.541Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/e4756258749bb2d3b46defcff606a2f47410bab82be5824a67e84015b267/propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2", size = 193015, upload-time = "2025-06-09T22:53:56.44Z" }, - { url = "https://files.pythonhosted.org/packages/1e/df/e6d3c7574233164b6330b9fd697beeac402afd367280e6dc377bb99b43d9/propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7", size = 204660, upload-time = "2025-06-09T22:53:57.839Z" }, - { url = "https://files.pythonhosted.org/packages/b2/53/e4d31dd5170b4a0e2e6b730f2385a96410633b4833dc25fe5dffd1f73294/propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b", size = 206105, upload-time = "2025-06-09T22:53:59.638Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fe/74d54cf9fbe2a20ff786e5f7afcfde446588f0cf15fb2daacfbc267b866c/propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c", size = 196980, upload-time = "2025-06-09T22:54:01.071Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/c469c9d59dada8a7679625e0440b544fe72e99311a4679c279562051f6fc/propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70", size = 37679, upload-time = "2025-06-09T22:54:03.003Z" }, - { url = "https://files.pythonhosted.org/packages/38/35/07a471371ac89d418f8d0b699c75ea6dca2041fbda360823de21f6a9ce0a/propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9", size = 41459, upload-time = "2025-06-09T22:54:04.134Z" }, - { url = "https://files.pythonhosted.org/packages/80/8d/e8b436717ab9c2cfc23b116d2c297305aa4cd8339172a456d61ebf5669b8/propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be", size = 74207, upload-time = "2025-06-09T22:54:05.399Z" }, - { url = "https://files.pythonhosted.org/packages/d6/29/1e34000e9766d112171764b9fa3226fa0153ab565d0c242c70e9945318a7/propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f", size = 43648, upload-time = "2025-06-09T22:54:08.023Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/1ad5af0df781e76988897da39b5f086c2bf0f028b7f9bd1f409bb05b6874/propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9", size = 43496, upload-time = "2025-06-09T22:54:09.228Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ce/e96392460f9fb68461fabab3e095cb00c8ddf901205be4eae5ce246e5b7e/propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf", size = 217288, upload-time = "2025-06-09T22:54:10.466Z" }, - { url = "https://files.pythonhosted.org/packages/c5/2a/866726ea345299f7ceefc861a5e782b045545ae6940851930a6adaf1fca6/propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9", size = 227456, upload-time = "2025-06-09T22:54:11.828Z" }, - { url = "https://files.pythonhosted.org/packages/de/03/07d992ccb6d930398689187e1b3c718339a1c06b8b145a8d9650e4726166/propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66", size = 225429, upload-time = "2025-06-09T22:54:13.823Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/116ba39448753b1330f48ab8ba927dcd6cf0baea8a0ccbc512dfb49ba670/propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df", size = 213472, upload-time = "2025-06-09T22:54:15.232Z" }, - { url = "https://files.pythonhosted.org/packages/a6/85/f01f5d97e54e428885a5497ccf7f54404cbb4f906688a1690cd51bf597dc/propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2", size = 204480, upload-time = "2025-06-09T22:54:17.104Z" }, - { url = "https://files.pythonhosted.org/packages/e3/79/7bf5ab9033b8b8194cc3f7cf1aaa0e9c3256320726f64a3e1f113a812dce/propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7", size = 214530, upload-time = "2025-06-09T22:54:18.512Z" }, - { url = "https://files.pythonhosted.org/packages/31/0b/bd3e0c00509b609317df4a18e6b05a450ef2d9a963e1d8bc9c9415d86f30/propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95", size = 205230, upload-time = "2025-06-09T22:54:19.947Z" }, - { url = "https://files.pythonhosted.org/packages/7a/23/fae0ff9b54b0de4e819bbe559508da132d5683c32d84d0dc2ccce3563ed4/propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e", size = 206754, upload-time = "2025-06-09T22:54:21.716Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7f/ad6a3c22630aaa5f618b4dc3c3598974a72abb4c18e45a50b3cdd091eb2f/propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e", size = 218430, upload-time = "2025-06-09T22:54:23.17Z" }, - { url = "https://files.pythonhosted.org/packages/5b/2c/ba4f1c0e8a4b4c75910742f0d333759d441f65a1c7f34683b4a74c0ee015/propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf", size = 223884, upload-time = "2025-06-09T22:54:25.539Z" }, - { url = "https://files.pythonhosted.org/packages/88/e4/ebe30fc399e98572019eee82ad0caf512401661985cbd3da5e3140ffa1b0/propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e", size = 211480, upload-time = "2025-06-09T22:54:26.892Z" }, - { url = "https://files.pythonhosted.org/packages/96/0a/7d5260b914e01d1d0906f7f38af101f8d8ed0dc47426219eeaf05e8ea7c2/propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897", size = 37757, upload-time = "2025-06-09T22:54:28.241Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2d/89fe4489a884bc0da0c3278c552bd4ffe06a1ace559db5ef02ef24ab446b/propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39", size = 41500, upload-time = "2025-06-09T22:54:29.4Z" }, - { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, - { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, - { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, - { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, - { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, - { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, - { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, - { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, - { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, - { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, - { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, - { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, - { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, - { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, - { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, - { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, - { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, - { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, - { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, - { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, - { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, - { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, - { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, - { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, - { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, - { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, - { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, - { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, - { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, -] - -[[package]] -name = "pycryptodome" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" }, - { url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" }, - { url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" }, - { url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" }, - { url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" }, - { url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" }, - { url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" }, - { url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" }, - { url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" }, - { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, - { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, - { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, - { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, - { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, - { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, - { url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886, upload-time = "2025-05-17T17:21:20.614Z" }, - { url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151, upload-time = "2025-05-17T17:21:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461, upload-time = "2025-05-17T17:21:25.225Z" }, - { url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440, upload-time = "2025-05-17T17:21:27.991Z" }, - { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, -] - -[[package]] -name = "pydantic" -version = "2.10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/70/7e/fb60e6fee04d0ef8f15e4e01ff187a196fa976eb0f0ab524af4599e5754c/pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06", size = 762094, upload-time = "2024-12-18T17:09:24.84Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/26/3e1bbe954fde7ee22a6e7d31582c642aad9e84ffe4b5fb61e63b87cd326f/pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", size = 431765, upload-time = "2024-12-18T17:09:21.953Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.27.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443, upload-time = "2024-12-18T11:31:54.917Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938, upload-time = "2024-12-18T11:27:14.406Z" }, - { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684, upload-time = "2024-12-18T11:27:16.489Z" }, - { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169, upload-time = "2024-12-18T11:27:22.16Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227, upload-time = "2024-12-18T11:27:25.097Z" }, - { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695, upload-time = "2024-12-18T11:27:28.656Z" }, - { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662, upload-time = "2024-12-18T11:27:30.798Z" }, - { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370, upload-time = "2024-12-18T11:27:33.692Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813, upload-time = "2024-12-18T11:27:37.111Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287, upload-time = "2024-12-18T11:27:40.566Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414, upload-time = "2024-12-18T11:27:43.757Z" }, - { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301, upload-time = "2024-12-18T11:27:47.36Z" }, - { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685, upload-time = "2024-12-18T11:27:50.508Z" }, - { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876, upload-time = "2024-12-18T11:27:53.54Z" }, - { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421, upload-time = "2024-12-18T11:27:55.409Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998, upload-time = "2024-12-18T11:27:57.252Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167, upload-time = "2024-12-18T11:27:59.146Z" }, - { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071, upload-time = "2024-12-18T11:28:02.625Z" }, - { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244, upload-time = "2024-12-18T11:28:04.442Z" }, - { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470, upload-time = "2024-12-18T11:28:07.679Z" }, - { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291, upload-time = "2024-12-18T11:28:10.297Z" }, - { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613, upload-time = "2024-12-18T11:28:13.362Z" }, - { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355, upload-time = "2024-12-18T11:28:16.587Z" }, - { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661, upload-time = "2024-12-18T11:28:18.407Z" }, - { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261, upload-time = "2024-12-18T11:28:21.471Z" }, - { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361, upload-time = "2024-12-18T11:28:23.53Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484, upload-time = "2024-12-18T11:28:25.391Z" }, - { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102, upload-time = "2024-12-18T11:28:28.593Z" }, - { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127, upload-time = "2024-12-18T11:28:30.346Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340, upload-time = "2024-12-18T11:28:32.521Z" }, - { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900, upload-time = "2024-12-18T11:28:34.507Z" }, - { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177, upload-time = "2024-12-18T11:28:36.488Z" }, - { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046, upload-time = "2024-12-18T11:28:39.409Z" }, - { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386, upload-time = "2024-12-18T11:28:41.221Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060, upload-time = "2024-12-18T11:28:44.709Z" }, - { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870, upload-time = "2024-12-18T11:28:46.839Z" }, - { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822, upload-time = "2024-12-18T11:28:48.896Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364, upload-time = "2024-12-18T11:28:50.755Z" }, - { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303, upload-time = "2024-12-18T11:28:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064, upload-time = "2024-12-18T11:28:56.074Z" }, - { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046, upload-time = "2024-12-18T11:28:58.107Z" }, - { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092, upload-time = "2024-12-18T11:29:01.335Z" }, - { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709, upload-time = "2024-12-18T11:29:03.193Z" }, - { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273, upload-time = "2024-12-18T11:29:05.306Z" }, - { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027, upload-time = "2024-12-18T11:29:07.294Z" }, - { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888, upload-time = "2024-12-18T11:29:09.249Z" }, - { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738, upload-time = "2024-12-18T11:29:11.23Z" }, - { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138, upload-time = "2024-12-18T11:29:16.396Z" }, - { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025, upload-time = "2024-12-18T11:29:20.25Z" }, - { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633, upload-time = "2024-12-18T11:29:23.877Z" }, - { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404, upload-time = "2024-12-18T11:29:25.872Z" }, - { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130, upload-time = "2024-12-18T11:29:29.252Z" }, - { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946, upload-time = "2024-12-18T11:29:31.338Z" }, - { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387, upload-time = "2024-12-18T11:29:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453, upload-time = "2024-12-18T11:29:35.533Z" }, - { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186, upload-time = "2024-12-18T11:29:37.649Z" }, - { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159, upload-time = "2024-12-18T11:30:54.382Z" }, - { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331, upload-time = "2024-12-18T11:30:58.178Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467, upload-time = "2024-12-18T11:31:00.6Z" }, - { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797, upload-time = "2024-12-18T11:31:07.243Z" }, - { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839, upload-time = "2024-12-18T11:31:09.775Z" }, - { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861, upload-time = "2024-12-18T11:31:13.469Z" }, - { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582, upload-time = "2024-12-18T11:31:17.423Z" }, - { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985, upload-time = "2024-12-18T11:31:19.901Z" }, - { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715, upload-time = "2024-12-18T11:31:22.821Z" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234, upload-time = "2025-04-18T16:44:48.265Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356, upload-time = "2025-04-18T16:44:46.617Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920, upload-time = "2025-03-25T10:14:56.835Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256, upload-time = "2025-03-25T10:14:55.034Z" }, -] - -[[package]] -name = "python-multipart" -version = "0.0.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, -] - -[[package]] -name = "pyunormalize" -version = "16.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/08/568036c725dac746ecb267bb749ef930fb7907454fe69fce83c8557287fb/pyunormalize-16.0.0.tar.gz", hash = "sha256:2e1dfbb4a118154ae26f70710426a52a364b926c9191f764601f5a8cb12761f7", size = 49968, upload-time = "2024-09-17T17:08:18.245Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/f9/9d86e56f716e0651194a5ad58be9c146fcaf1de6901ac6f3cd3affeeb74e/pyunormalize-16.0.0-py3-none-any.whl", hash = "sha256:c647d95e5d1e2ea9a2f448d1d95d8518348df24eab5c3fd32d2b5c3300a49152", size = 49173, upload-time = "2024-09-17T17:08:17.078Z" }, -] - -[[package]] -name = "pywin32" -version = "310" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, - { url = "https://files.pythonhosted.org/packages/3c/84/1a8e3d7a15490d28a5d816efa229ecb4999cdc51a7c30dd8914f669093b8/pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213", size = 8522963, upload-time = "2025-03-17T00:55:50.969Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b1/68aa2986129fb1011dabbe95f0136f44509afaf072b12b8f815905a39f33/pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd", size = 8784284, upload-time = "2025-03-17T00:55:53.124Z" }, - { url = "https://files.pythonhosted.org/packages/b3/bd/d1592635992dd8db5bb8ace0551bc3a769de1ac8850200cfa517e72739fb/pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c", size = 9520748, upload-time = "2025-03-17T00:55:55.203Z" }, - { url = "https://files.pythonhosted.org/packages/90/b1/ac8b1ffce6603849eb45a91cf126c0fa5431f186c2e768bf56889c46f51c/pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582", size = 8455941, upload-time = "2025-03-17T00:55:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, - { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384, upload-time = "2025-03-17T00:56:04.383Z" }, - { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039, upload-time = "2025-03-17T00:56:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152, upload-time = "2025-03-17T00:56:07.819Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" }, - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, - { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669, upload-time = "2024-11-06T20:09:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684, upload-time = "2024-11-06T20:09:32.915Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589, upload-time = "2024-11-06T20:09:35.504Z" }, - { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121, upload-time = "2024-11-06T20:09:37.701Z" }, - { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275, upload-time = "2024-11-06T20:09:40.371Z" }, - { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257, upload-time = "2024-11-06T20:09:43.059Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727, upload-time = "2024-11-06T20:09:48.19Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667, upload-time = "2024-11-06T20:09:49.828Z" }, - { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963, upload-time = "2024-11-06T20:09:51.819Z" }, - { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700, upload-time = "2024-11-06T20:09:53.982Z" }, - { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592, upload-time = "2024-11-06T20:09:56.222Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929, upload-time = "2024-11-06T20:09:58.642Z" }, - { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213, upload-time = "2024-11-06T20:10:00.867Z" }, - { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734, upload-time = "2024-11-06T20:10:03.361Z" }, - { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052, upload-time = "2024-11-06T20:10:05.179Z" }, - { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, - { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, - { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, - { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, - { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, - { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, - { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, - { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, - { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, - { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, - { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, - { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, - { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, - { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, - { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, - { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, - { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, - { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, - { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, - { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, - { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, - { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, - { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, - { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, -] - -[[package]] -name = "requests" -version = "2.32.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, -] - -[[package]] -name = "rich" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, -] - -[[package]] -name = "rich-toolkit" -version = "0.14.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/7a/cb48b7024b247631ce39b1f14a0f1abedf311fb27b892b0e0387d809d4b5/rich_toolkit-0.14.7.tar.gz", hash = "sha256:6cca5a68850cc5778915f528eb785662c27ba3b4b2624612cce8340fa9701c5e", size = 104977, upload-time = "2025-05-27T15:48:09.377Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/2e/95fde5b818dac9a37683ea064096323f593442d0f6358923c5f635974393/rich_toolkit-0.14.7-py3-none-any.whl", hash = "sha256:def05cc6e0f1176d6263b6a26648f16a62c4563b277ca2f8538683acdba1e0da", size = 24870, upload-time = "2025-05-27T15:48:07.942Z" }, -] - -[[package]] -name = "rlp" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/2d/439b0728a92964a04d9c88ea1ca9ebb128893fbbd5834faa31f987f2fd4c/rlp-4.1.0.tar.gz", hash = "sha256:be07564270a96f3e225e2c107db263de96b5bc1f27722d2855bd3459a08e95a9", size = 33429, upload-time = "2025-02-04T22:05:59.089Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/fb/e4c0ced9893b84ac95b7181d69a9786ce5879aeb3bbbcbba80a164f85d6a/rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f", size = 19973, upload-time = "2025-02-04T22:05:57.05Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "starlette" -version = "0.46.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, -] - -[[package]] -name = "toolz" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790, upload-time = "2024-10-04T16:17:04.001Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383, upload-time = "2024-10-04T16:17:01.533Z" }, -] - -[[package]] -name = "typer" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, -] - -[[package]] -name = "types-requests" -version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/7f/73b3a04a53b0fd2a911d4ec517940ecd6600630b559e4505cc7b68beb5a0/types_requests-2.32.4.20250611.tar.gz", hash = "sha256:741c8777ed6425830bf51e54d6abe245f79b4dcb9019f1622b773463946bf826", size = 23118, upload-time = "2025-06-11T03:11:41.272Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/ea/0be9258c5a4fa1ba2300111aa5a0767ee6d18eb3fd20e91616c12082284d/types_requests-2.32.4.20250611-py3-none-any.whl", hash = "sha256:ad2fe5d3b0cb3c2c902c8815a70e7fb2302c4b8c1f77bdcd738192cdb3878072", size = 20643, upload-time = "2025-06-11T03:11:40.186Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, -] - -[[package]] -name = "urllib3" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, -] - -[[package]] -name = "uvicorn" -version = "0.34.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631, upload-time = "2025-06-01T07:48:17.531Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431, upload-time = "2025-06-01T07:48:15.664Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, - { url = "https://files.pythonhosted.org/packages/35/5a/62d5800358a78cc25c8a6c72ef8b10851bdb8cca22e14d9c74167b7f86da/uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d", size = 801898, upload-time = "2024-10-14T23:37:22.663Z" }, - { url = "https://files.pythonhosted.org/packages/f3/96/63695e0ebd7da6c741ccd4489b5947394435e198a1382349c17b1146bb97/uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26", size = 3827735, upload-time = "2024-10-14T23:37:25.129Z" }, - { url = "https://files.pythonhosted.org/packages/61/e0/f0f8ec84979068ffae132c58c79af1de9cceeb664076beea86d941af1a30/uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb", size = 3825126, upload-time = "2024-10-14T23:37:27.59Z" }, - { url = "https://files.pythonhosted.org/packages/bf/fe/5e94a977d058a54a19df95f12f7161ab6e323ad49f4dabc28822eb2df7ea/uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f", size = 3705789, upload-time = "2024-10-14T23:37:29.385Z" }, - { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523, upload-time = "2024-10-14T23:37:32.048Z" }, - { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410, upload-time = "2024-10-14T23:37:33.612Z" }, - { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476, upload-time = "2024-10-14T23:37:36.11Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855, upload-time = "2024-10-14T23:37:37.683Z" }, - { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185, upload-time = "2024-10-14T23:37:40.226Z" }, - { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256, upload-time = "2024-10-14T23:37:42.839Z" }, - { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323, upload-time = "2024-10-14T23:37:45.337Z" }, - { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284, upload-time = "2024-10-14T23:37:47.833Z" }, - { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349, upload-time = "2024-10-14T23:37:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089, upload-time = "2024-10-14T23:37:51.703Z" }, - { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770, upload-time = "2024-10-14T23:37:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321, upload-time = "2024-10-14T23:37:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022, upload-time = "2024-10-14T23:37:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" }, - { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" }, - { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" }, - { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" }, - { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" }, - { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" }, -] - -[[package]] -name = "watchfiles" -version = "1.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/e2/8ed598c42057de7aa5d97c472254af4906ff0a59a66699d426fc9ef795d7/watchfiles-1.0.5.tar.gz", hash = "sha256:b7529b5dcc114679d43827d8c35a07c493ad6f083633d573d81c660abc5979e9", size = 94537, upload-time = "2025-04-08T10:36:26.722Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/4d/d02e6ea147bb7fff5fd109c694a95109612f419abed46548a930e7f7afa3/watchfiles-1.0.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5c40fe7dd9e5f81e0847b1ea64e1f5dd79dd61afbedb57759df06767ac719b40", size = 405632, upload-time = "2025-04-08T10:34:41.832Z" }, - { url = "https://files.pythonhosted.org/packages/60/31/9ee50e29129d53a9a92ccf1d3992751dc56fc3c8f6ee721be1c7b9c81763/watchfiles-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c0db396e6003d99bb2d7232c957b5f0b5634bbd1b24e381a5afcc880f7373fb", size = 395734, upload-time = "2025-04-08T10:34:44.236Z" }, - { url = "https://files.pythonhosted.org/packages/ad/8c/759176c97195306f028024f878e7f1c776bda66ccc5c68fa51e699cf8f1d/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b551d4fb482fc57d852b4541f911ba28957d051c8776e79c3b4a51eb5e2a1b11", size = 455008, upload-time = "2025-04-08T10:34:45.617Z" }, - { url = "https://files.pythonhosted.org/packages/55/1a/5e977250c795ee79a0229e3b7f5e3a1b664e4e450756a22da84d2f4979fe/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:830aa432ba5c491d52a15b51526c29e4a4b92bf4f92253787f9726fe01519487", size = 459029, upload-time = "2025-04-08T10:34:46.814Z" }, - { url = "https://files.pythonhosted.org/packages/e6/17/884cf039333605c1d6e296cf5be35fad0836953c3dfd2adb71b72f9dbcd0/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a16512051a822a416b0d477d5f8c0e67b67c1a20d9acecb0aafa3aa4d6e7d256", size = 488916, upload-time = "2025-04-08T10:34:48.571Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e0/bcb6e64b45837056c0a40f3a2db3ef51c2ced19fda38484fa7508e00632c/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe0cbc787770e52a96c6fda6726ace75be7f840cb327e1b08d7d54eadc3bc85", size = 523763, upload-time = "2025-04-08T10:34:50.268Z" }, - { url = "https://files.pythonhosted.org/packages/24/e9/f67e9199f3bb35c1837447ecf07e9830ec00ff5d35a61e08c2cd67217949/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d363152c5e16b29d66cbde8fa614f9e313e6f94a8204eaab268db52231fe5358", size = 502891, upload-time = "2025-04-08T10:34:51.419Z" }, - { url = "https://files.pythonhosted.org/packages/23/ed/a6cf815f215632f5c8065e9c41fe872025ffea35aa1f80499f86eae922db/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee32c9a9bee4d0b7bd7cbeb53cb185cf0b622ac761efaa2eba84006c3b3a614", size = 454921, upload-time = "2025-04-08T10:34:52.67Z" }, - { url = "https://files.pythonhosted.org/packages/92/4c/e14978599b80cde8486ab5a77a821e8a982ae8e2fcb22af7b0886a033ec8/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29c7fd632ccaf5517c16a5188e36f6612d6472ccf55382db6c7fe3fcccb7f59f", size = 631422, upload-time = "2025-04-08T10:34:53.985Z" }, - { url = "https://files.pythonhosted.org/packages/b2/1a/9263e34c3458f7614b657f974f4ee61fd72f58adce8b436e16450e054efd/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e637810586e6fe380c8bc1b3910accd7f1d3a9a7262c8a78d4c8fb3ba6a2b3d", size = 625675, upload-time = "2025-04-08T10:34:55.173Z" }, - { url = "https://files.pythonhosted.org/packages/96/1f/1803a18bd6ab04a0766386a19bcfe64641381a04939efdaa95f0e3b0eb58/watchfiles-1.0.5-cp310-cp310-win32.whl", hash = "sha256:cd47d063fbeabd4c6cae1d4bcaa38f0902f8dc5ed168072874ea11d0c7afc1ff", size = 277921, upload-time = "2025-04-08T10:34:56.318Z" }, - { url = "https://files.pythonhosted.org/packages/c2/3b/29a89de074a7d6e8b4dc67c26e03d73313e4ecf0d6e97e942a65fa7c195e/watchfiles-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:86c0df05b47a79d80351cd179893f2f9c1b1cae49d96e8b3290c7f4bd0ca0a92", size = 291526, upload-time = "2025-04-08T10:34:57.95Z" }, - { url = "https://files.pythonhosted.org/packages/39/f4/41b591f59021786ef517e1cdc3b510383551846703e03f204827854a96f8/watchfiles-1.0.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:237f9be419e977a0f8f6b2e7b0475ababe78ff1ab06822df95d914a945eac827", size = 405336, upload-time = "2025-04-08T10:34:59.359Z" }, - { url = "https://files.pythonhosted.org/packages/ae/06/93789c135be4d6d0e4f63e96eea56dc54050b243eacc28439a26482b5235/watchfiles-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0da39ff917af8b27a4bdc5a97ac577552a38aac0d260a859c1517ea3dc1a7c4", size = 395977, upload-time = "2025-04-08T10:35:00.522Z" }, - { url = "https://files.pythonhosted.org/packages/d2/db/1cd89bd83728ca37054512d4d35ab69b5f12b8aa2ac9be3b0276b3bf06cc/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cfcb3952350e95603f232a7a15f6c5f86c5375e46f0bd4ae70d43e3e063c13d", size = 455232, upload-time = "2025-04-08T10:35:01.698Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/d8a4d44ffe960517e487c9c04f77b06b8abf05eb680bed71c82b5f2cad62/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b2dddba7a4e6151384e252a5632efcaa9bc5d1c4b567f3cb621306b2ca9f63", size = 459151, upload-time = "2025-04-08T10:35:03.358Z" }, - { url = "https://files.pythonhosted.org/packages/6c/da/267a1546f26465dead1719caaba3ce660657f83c9d9c052ba98fb8856e13/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95cf944fcfc394c5f9de794ce581914900f82ff1f855326f25ebcf24d5397418", size = 489054, upload-time = "2025-04-08T10:35:04.561Z" }, - { url = "https://files.pythonhosted.org/packages/b1/31/33850dfd5c6efb6f27d2465cc4c6b27c5a6f5ed53c6fa63b7263cf5f60f6/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecf6cd9f83d7c023b1aba15d13f705ca7b7d38675c121f3cc4a6e25bd0857ee9", size = 523955, upload-time = "2025-04-08T10:35:05.786Z" }, - { url = "https://files.pythonhosted.org/packages/09/84/b7d7b67856efb183a421f1416b44ca975cb2ea6c4544827955dfb01f7dc2/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:852de68acd6212cd6d33edf21e6f9e56e5d98c6add46f48244bd479d97c967c6", size = 502234, upload-time = "2025-04-08T10:35:07.187Z" }, - { url = "https://files.pythonhosted.org/packages/71/87/6dc5ec6882a2254cfdd8b0718b684504e737273903b65d7338efaba08b52/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5730f3aa35e646103b53389d5bc77edfbf578ab6dab2e005142b5b80a35ef25", size = 454750, upload-time = "2025-04-08T10:35:08.859Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6c/3786c50213451a0ad15170d091570d4a6554976cf0df19878002fc96075a/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:18b3bd29954bc4abeeb4e9d9cf0b30227f0f206c86657674f544cb032296acd5", size = 631591, upload-time = "2025-04-08T10:35:10.64Z" }, - { url = "https://files.pythonhosted.org/packages/1b/b3/1427425ade4e359a0deacce01a47a26024b2ccdb53098f9d64d497f6684c/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ba5552a1b07c8edbf197055bc9d518b8f0d98a1c6a73a293bc0726dce068ed01", size = 625370, upload-time = "2025-04-08T10:35:12.412Z" }, - { url = "https://files.pythonhosted.org/packages/15/ba/f60e053b0b5b8145d682672024aa91370a29c5c921a88977eb565de34086/watchfiles-1.0.5-cp311-cp311-win32.whl", hash = "sha256:2f1fefb2e90e89959447bc0420fddd1e76f625784340d64a2f7d5983ef9ad246", size = 277791, upload-time = "2025-04-08T10:35:13.719Z" }, - { url = "https://files.pythonhosted.org/packages/50/ed/7603c4e164225c12c0d4e8700b64bb00e01a6c4eeea372292a3856be33a4/watchfiles-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:b6e76ceb1dd18c8e29c73f47d41866972e891fc4cc7ba014f487def72c1cf096", size = 291622, upload-time = "2025-04-08T10:35:15.071Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c2/99bb7c96b4450e36877fde33690ded286ff555b5a5c1d925855d556968a1/watchfiles-1.0.5-cp311-cp311-win_arm64.whl", hash = "sha256:266710eb6fddc1f5e51843c70e3bebfb0f5e77cf4f27129278c70554104d19ed", size = 283699, upload-time = "2025-04-08T10:35:16.732Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8c/4f0b9bdb75a1bfbd9c78fad7d8854369283f74fe7cf03eb16be77054536d/watchfiles-1.0.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5eb568c2aa6018e26da9e6c86f3ec3fd958cee7f0311b35c2630fa4217d17f2", size = 401511, upload-time = "2025-04-08T10:35:17.956Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4e/7e15825def77f8bd359b6d3f379f0c9dac4eb09dd4ddd58fd7d14127179c/watchfiles-1.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a04059f4923ce4e856b4b4e5e783a70f49d9663d22a4c3b3298165996d1377f", size = 392715, upload-time = "2025-04-08T10:35:19.202Z" }, - { url = "https://files.pythonhosted.org/packages/58/65/b72fb817518728e08de5840d5d38571466c1b4a3f724d190cec909ee6f3f/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e380c89983ce6e6fe2dd1e1921b9952fb4e6da882931abd1824c092ed495dec", size = 454138, upload-time = "2025-04-08T10:35:20.586Z" }, - { url = "https://files.pythonhosted.org/packages/3e/a4/86833fd2ea2e50ae28989f5950b5c3f91022d67092bfec08f8300d8b347b/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe43139b2c0fdc4a14d4f8d5b5d967f7a2777fd3d38ecf5b1ec669b0d7e43c21", size = 458592, upload-time = "2025-04-08T10:35:21.87Z" }, - { url = "https://files.pythonhosted.org/packages/38/7e/42cb8df8be9a37e50dd3a818816501cf7a20d635d76d6bd65aae3dbbff68/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee0822ce1b8a14fe5a066f93edd20aada932acfe348bede8aa2149f1a4489512", size = 487532, upload-time = "2025-04-08T10:35:23.143Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/13d26721c85d7f3df6169d8b495fcac8ab0dc8f0945ebea8845de4681dab/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0dbcb1c2d8f2ab6e0a81c6699b236932bd264d4cef1ac475858d16c403de74d", size = 522865, upload-time = "2025-04-08T10:35:24.702Z" }, - { url = "https://files.pythonhosted.org/packages/a1/0d/7f9ae243c04e96c5455d111e21b09087d0eeaf9a1369e13a01c7d3d82478/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2014a2b18ad3ca53b1f6c23f8cd94a18ce930c1837bd891262c182640eb40a6", size = 499887, upload-time = "2025-04-08T10:35:25.969Z" }, - { url = "https://files.pythonhosted.org/packages/8e/0f/a257766998e26aca4b3acf2ae97dff04b57071e991a510857d3799247c67/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6ae86d5cb647bf58f9f655fcf577f713915a5d69057a0371bc257e2553234", size = 454498, upload-time = "2025-04-08T10:35:27.353Z" }, - { url = "https://files.pythonhosted.org/packages/81/79/8bf142575a03e0af9c3d5f8bcae911ee6683ae93a625d349d4ecf4c8f7df/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1a7bac2bde1d661fb31f4d4e8e539e178774b76db3c2c17c4bb3e960a5de07a2", size = 630663, upload-time = "2025-04-08T10:35:28.685Z" }, - { url = "https://files.pythonhosted.org/packages/f1/80/abe2e79f610e45c63a70d271caea90c49bbf93eb00fa947fa9b803a1d51f/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ab626da2fc1ac277bbf752446470b367f84b50295264d2d313e28dc4405d663", size = 625410, upload-time = "2025-04-08T10:35:30.42Z" }, - { url = "https://files.pythonhosted.org/packages/91/6f/bc7fbecb84a41a9069c2c6eb6319f7f7df113adf113e358c57fc1aff7ff5/watchfiles-1.0.5-cp312-cp312-win32.whl", hash = "sha256:9f4571a783914feda92018ef3901dab8caf5b029325b5fe4558c074582815249", size = 277965, upload-time = "2025-04-08T10:35:32.023Z" }, - { url = "https://files.pythonhosted.org/packages/99/a5/bf1c297ea6649ec59e935ab311f63d8af5faa8f0b86993e3282b984263e3/watchfiles-1.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:360a398c3a19672cf93527f7e8d8b60d8275119c5d900f2e184d32483117a705", size = 291693, upload-time = "2025-04-08T10:35:33.225Z" }, - { url = "https://files.pythonhosted.org/packages/7f/7b/fd01087cc21db5c47e5beae507b87965db341cce8a86f9eb12bf5219d4e0/watchfiles-1.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:1a2902ede862969077b97523987c38db28abbe09fb19866e711485d9fbf0d417", size = 283287, upload-time = "2025-04-08T10:35:34.568Z" }, - { url = "https://files.pythonhosted.org/packages/c7/62/435766874b704f39b2fecd8395a29042db2b5ec4005bd34523415e9bd2e0/watchfiles-1.0.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0b289572c33a0deae62daa57e44a25b99b783e5f7aed81b314232b3d3c81a11d", size = 401531, upload-time = "2025-04-08T10:35:35.792Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a6/e52a02c05411b9cb02823e6797ef9bbba0bfaf1bb627da1634d44d8af833/watchfiles-1.0.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a056c2f692d65bf1e99c41045e3bdcaea3cb9e6b5a53dcaf60a5f3bd95fc9763", size = 392417, upload-time = "2025-04-08T10:35:37.048Z" }, - { url = "https://files.pythonhosted.org/packages/3f/53/c4af6819770455932144e0109d4854437769672d7ad897e76e8e1673435d/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9dca99744991fc9850d18015c4f0438865414e50069670f5f7eee08340d8b40", size = 453423, upload-time = "2025-04-08T10:35:38.357Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d1/8e88df58bbbf819b8bc5cfbacd3c79e01b40261cad0fc84d1e1ebd778a07/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:894342d61d355446d02cd3988a7326af344143eb33a2fd5d38482a92072d9563", size = 458185, upload-time = "2025-04-08T10:35:39.708Z" }, - { url = "https://files.pythonhosted.org/packages/ff/70/fffaa11962dd5429e47e478a18736d4e42bec42404f5ee3b92ef1b87ad60/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab44e1580924d1ffd7b3938e02716d5ad190441965138b4aa1d1f31ea0877f04", size = 486696, upload-time = "2025-04-08T10:35:41.469Z" }, - { url = "https://files.pythonhosted.org/packages/39/db/723c0328e8b3692d53eb273797d9a08be6ffb1d16f1c0ba2bdbdc2a3852c/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6f9367b132078b2ceb8d066ff6c93a970a18c3029cea37bfd7b2d3dd2e5db8f", size = 522327, upload-time = "2025-04-08T10:35:43.289Z" }, - { url = "https://files.pythonhosted.org/packages/cd/05/9fccc43c50c39a76b68343484b9da7b12d42d0859c37c61aec018c967a32/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2e55a9b162e06e3f862fb61e399fe9f05d908d019d87bf5b496a04ef18a970a", size = 499741, upload-time = "2025-04-08T10:35:44.574Z" }, - { url = "https://files.pythonhosted.org/packages/23/14/499e90c37fa518976782b10a18b18db9f55ea73ca14641615056f8194bb3/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0125f91f70e0732a9f8ee01e49515c35d38ba48db507a50c5bdcad9503af5827", size = 453995, upload-time = "2025-04-08T10:35:46.336Z" }, - { url = "https://files.pythonhosted.org/packages/61/d9/f75d6840059320df5adecd2c687fbc18960a7f97b55c300d20f207d48aef/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:13bb21f8ba3248386337c9fa51c528868e6c34a707f729ab041c846d52a0c69a", size = 629693, upload-time = "2025-04-08T10:35:48.161Z" }, - { url = "https://files.pythonhosted.org/packages/fc/17/180ca383f5061b61406477218c55d66ec118e6c0c51f02d8142895fcf0a9/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:839ebd0df4a18c5b3c1b890145b5a3f5f64063c2a0d02b13c76d78fe5de34936", size = 624677, upload-time = "2025-04-08T10:35:49.65Z" }, - { url = "https://files.pythonhosted.org/packages/bf/15/714d6ef307f803f236d69ee9d421763707899d6298d9f3183e55e366d9af/watchfiles-1.0.5-cp313-cp313-win32.whl", hash = "sha256:4a8ec1e4e16e2d5bafc9ba82f7aaecfeec990ca7cd27e84fb6f191804ed2fcfc", size = 277804, upload-time = "2025-04-08T10:35:51.093Z" }, - { url = "https://files.pythonhosted.org/packages/a8/b4/c57b99518fadf431f3ef47a610839e46e5f8abf9814f969859d1c65c02c7/watchfiles-1.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:f436601594f15bf406518af922a89dcaab416568edb6f65c4e5bbbad1ea45c11", size = 291087, upload-time = "2025-04-08T10:35:52.458Z" }, - { url = "https://files.pythonhosted.org/packages/1a/03/81f9fcc3963b3fc415cd4b0b2b39ee8cc136c42fb10a36acf38745e9d283/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f59b870db1f1ae5a9ac28245707d955c8721dd6565e7f411024fa374b5362d1d", size = 405947, upload-time = "2025-04-08T10:36:13.721Z" }, - { url = "https://files.pythonhosted.org/packages/54/97/8c4213a852feb64807ec1d380f42d4fc8bfaef896bdbd94318f8fd7f3e4e/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9475b0093767e1475095f2aeb1d219fb9664081d403d1dff81342df8cd707034", size = 397276, upload-time = "2025-04-08T10:36:15.131Z" }, - { url = "https://files.pythonhosted.org/packages/78/12/d4464d19860cb9672efa45eec1b08f8472c478ed67dcd30647c51ada7aef/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc533aa50664ebd6c628b2f30591956519462f5d27f951ed03d6c82b2dfd9965", size = 455550, upload-time = "2025-04-08T10:36:16.635Z" }, - { url = "https://files.pythonhosted.org/packages/90/fb/b07bcdf1034d8edeaef4c22f3e9e3157d37c5071b5f9492ffdfa4ad4bed7/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed1cd825158dcaae36acce7b2db33dcbfd12b30c34317a88b8ed80f0541cc57", size = 455542, upload-time = "2025-04-08T10:36:18.655Z" }, -] - -[[package]] -name = "web3" -version = "7.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "eth-abi" }, - { name = "eth-account" }, - { name = "eth-hash", extra = ["pycryptodome"] }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "pyunormalize" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "requests" }, - { name = "types-requests" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7d/1e/fc1f5b5a12615cbdca57d35014cdb9823db7392d73b730fa0d89d6a13f6a/web3-7.12.0.tar.gz", hash = "sha256:08fbe79a2e2503c9820132ebad24ba0372831588cabac5f467999c97ace7dda3", size = 2195693, upload-time = "2025-05-22T21:06:05.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/df/0ccf18f244b96a93ba2710f7ce696da1f8dd44ef1126e3603dfb65cd68fe/web3-7.12.0-py3-none-any.whl", hash = "sha256:c7e2b9c1db5a379ef53b45fe8a19bdc2d47ad262039fbf6675794bc40f74bf06", size = 1369328, upload-time = "2025-05-22T21:06:03.124Z" }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, - { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, - { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, - { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, - { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, - { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, - { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, - { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, - { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - -[[package]] -name = "werkzeug" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, -] - -[[package]] -name = "x402" -version = "1.0.0" -source = { editable = "../../../../../python/legacy" } -dependencies = [ - { name = "eth-account" }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "fastapi", extra = ["standard"] }, - { name = "flask" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "web3" }, -] - -[package.metadata] -requires-dist = [ - { name = "eth-account", specifier = ">=0.13.7" }, - { name = "eth-typing", specifier = ">=4.0.0" }, - { name = "eth-utils", specifier = ">=3.0.0" }, - { name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" }, - { name = "flask", specifier = ">=3.0.0" }, - { name = "pydantic", specifier = ">=2.10.3" }, - { name = "pydantic-settings", specifier = ">=2.2.1" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "web3", specifier = ">=6.0.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.5" }, - { name = "pytest-asyncio", specifier = ">=1.0.0" }, - { name = "ruff", specifier = ">=0.11.9" }, -] - -[[package]] -name = "x402-requests-example" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "eth-account" }, - { name = "requests" }, - { name = "x402" }, -] - -[package.metadata] -requires-dist = [ - { name = "eth-account", specifier = ">=0.8.0" }, - { name = "requests", specifier = ">=2.31.0" }, - { name = "x402", editable = "../../../../../python/legacy" }, -] - -[[package]] -name = "yarl" -version = "1.20.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/65/7fed0d774abf47487c64be14e9223749468922817b5e8792b8a64792a1bb/yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4", size = 132910, upload-time = "2025-06-10T00:42:31.108Z" }, - { url = "https://files.pythonhosted.org/packages/8a/7b/988f55a52da99df9e56dc733b8e4e5a6ae2090081dc2754fc8fd34e60aa0/yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a", size = 90644, upload-time = "2025-06-10T00:42:33.851Z" }, - { url = "https://files.pythonhosted.org/packages/f7/de/30d98f03e95d30c7e3cc093759982d038c8833ec2451001d45ef4854edc1/yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed", size = 89322, upload-time = "2025-06-10T00:42:35.688Z" }, - { url = "https://files.pythonhosted.org/packages/e0/7a/f2f314f5ebfe9200724b0b748de2186b927acb334cf964fd312eb86fc286/yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e", size = 323786, upload-time = "2025-06-10T00:42:37.817Z" }, - { url = "https://files.pythonhosted.org/packages/15/3f/718d26f189db96d993d14b984ce91de52e76309d0fd1d4296f34039856aa/yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73", size = 319627, upload-time = "2025-06-10T00:42:39.937Z" }, - { url = "https://files.pythonhosted.org/packages/a5/76/8fcfbf5fa2369157b9898962a4a7d96764b287b085b5b3d9ffae69cdefd1/yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e", size = 339149, upload-time = "2025-06-10T00:42:42.627Z" }, - { url = "https://files.pythonhosted.org/packages/3c/95/d7fc301cc4661785967acc04f54a4a42d5124905e27db27bb578aac49b5c/yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8", size = 333327, upload-time = "2025-06-10T00:42:44.842Z" }, - { url = "https://files.pythonhosted.org/packages/65/94/e21269718349582eee81efc5c1c08ee71c816bfc1585b77d0ec3f58089eb/yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23", size = 326054, upload-time = "2025-06-10T00:42:47.149Z" }, - { url = "https://files.pythonhosted.org/packages/32/ae/8616d1f07853704523519f6131d21f092e567c5af93de7e3e94b38d7f065/yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70", size = 315035, upload-time = "2025-06-10T00:42:48.852Z" }, - { url = "https://files.pythonhosted.org/packages/48/aa/0ace06280861ef055855333707db5e49c6e3a08840a7ce62682259d0a6c0/yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb", size = 338962, upload-time = "2025-06-10T00:42:51.024Z" }, - { url = "https://files.pythonhosted.org/packages/20/52/1e9d0e6916f45a8fb50e6844f01cb34692455f1acd548606cbda8134cd1e/yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2", size = 335399, upload-time = "2025-06-10T00:42:53.007Z" }, - { url = "https://files.pythonhosted.org/packages/f2/65/60452df742952c630e82f394cd409de10610481d9043aa14c61bf846b7b1/yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30", size = 338649, upload-time = "2025-06-10T00:42:54.964Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f5/6cd4ff38dcde57a70f23719a838665ee17079640c77087404c3d34da6727/yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309", size = 358563, upload-time = "2025-06-10T00:42:57.28Z" }, - { url = "https://files.pythonhosted.org/packages/d1/90/c42eefd79d0d8222cb3227bdd51b640c0c1d0aa33fe4cc86c36eccba77d3/yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24", size = 357609, upload-time = "2025-06-10T00:42:59.055Z" }, - { url = "https://files.pythonhosted.org/packages/03/c8/cea6b232cb4617514232e0f8a718153a95b5d82b5290711b201545825532/yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13", size = 350224, upload-time = "2025-06-10T00:43:01.248Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a3/eaa0ab9712f1f3d01faf43cf6f1f7210ce4ea4a7e9b28b489a2261ca8db9/yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8", size = 81753, upload-time = "2025-06-10T00:43:03.486Z" }, - { url = "https://files.pythonhosted.org/packages/8f/34/e4abde70a9256465fe31c88ed02c3f8502b7b5dead693a4f350a06413f28/yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16", size = 86817, upload-time = "2025-06-10T00:43:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b1/18/893b50efc2350e47a874c5c2d67e55a0ea5df91186b2a6f5ac52eff887cd/yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e", size = 133833, upload-time = "2025-06-10T00:43:07.393Z" }, - { url = "https://files.pythonhosted.org/packages/89/ed/b8773448030e6fc47fa797f099ab9eab151a43a25717f9ac043844ad5ea3/yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b", size = 91070, upload-time = "2025-06-10T00:43:09.538Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e3/409bd17b1e42619bf69f60e4f031ce1ccb29bd7380117a55529e76933464/yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b", size = 89818, upload-time = "2025-06-10T00:43:11.575Z" }, - { url = "https://files.pythonhosted.org/packages/f8/77/64d8431a4d77c856eb2d82aa3de2ad6741365245a29b3a9543cd598ed8c5/yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4", size = 347003, upload-time = "2025-06-10T00:43:14.088Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d2/0c7e4def093dcef0bd9fa22d4d24b023788b0a33b8d0088b51aa51e21e99/yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1", size = 336537, upload-time = "2025-06-10T00:43:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f3/fc514f4b2cf02cb59d10cbfe228691d25929ce8f72a38db07d3febc3f706/yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833", size = 362358, upload-time = "2025-06-10T00:43:18.704Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6d/a313ac8d8391381ff9006ac05f1d4331cee3b1efaa833a53d12253733255/yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d", size = 357362, upload-time = "2025-06-10T00:43:20.888Z" }, - { url = "https://files.pythonhosted.org/packages/00/70/8f78a95d6935a70263d46caa3dd18e1f223cf2f2ff2037baa01a22bc5b22/yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8", size = 348979, upload-time = "2025-06-10T00:43:23.169Z" }, - { url = "https://files.pythonhosted.org/packages/cb/05/42773027968968f4f15143553970ee36ead27038d627f457cc44bbbeecf3/yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf", size = 337274, upload-time = "2025-06-10T00:43:27.111Z" }, - { url = "https://files.pythonhosted.org/packages/05/be/665634aa196954156741ea591d2f946f1b78ceee8bb8f28488bf28c0dd62/yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e", size = 363294, upload-time = "2025-06-10T00:43:28.96Z" }, - { url = "https://files.pythonhosted.org/packages/eb/90/73448401d36fa4e210ece5579895731f190d5119c4b66b43b52182e88cd5/yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389", size = 358169, upload-time = "2025-06-10T00:43:30.701Z" }, - { url = "https://files.pythonhosted.org/packages/c3/b0/fce922d46dc1eb43c811f1889f7daa6001b27a4005587e94878570300881/yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f", size = 362776, upload-time = "2025-06-10T00:43:32.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/0d/b172628fce039dae8977fd22caeff3eeebffd52e86060413f5673767c427/yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845", size = 381341, upload-time = "2025-06-10T00:43:34.543Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9b/5b886d7671f4580209e855974fe1cecec409aa4a89ea58b8f0560dc529b1/yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1", size = 379988, upload-time = "2025-06-10T00:43:36.489Z" }, - { url = "https://files.pythonhosted.org/packages/73/be/75ef5fd0fcd8f083a5d13f78fd3f009528132a1f2a1d7c925c39fa20aa79/yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e", size = 371113, upload-time = "2025-06-10T00:43:38.592Z" }, - { url = "https://files.pythonhosted.org/packages/50/4f/62faab3b479dfdcb741fe9e3f0323e2a7d5cd1ab2edc73221d57ad4834b2/yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773", size = 81485, upload-time = "2025-06-10T00:43:41.038Z" }, - { url = "https://files.pythonhosted.org/packages/f0/09/d9c7942f8f05c32ec72cd5c8e041c8b29b5807328b68b4801ff2511d4d5e/yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e", size = 86686, upload-time = "2025-06-10T00:43:42.692Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, - { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, - { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, - { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, - { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, - { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, - { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, - { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, - { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, - { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, - { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, - { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, - { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, - { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, - { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, - { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, - { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, - { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, - { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, - { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, - { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, - { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, - { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, - { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, - { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, - { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, - { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, - { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, - { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, - { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, - { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, - { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, - { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, - { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, - { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, - { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, - { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, -] diff --git a/examples/python/legacy/discovery/README.md b/examples/python/legacy/discovery/README.md deleted file mode 100644 index ec1192e96f..0000000000 --- a/examples/python/legacy/discovery/README.md +++ /dev/null @@ -1,104 +0,0 @@ -# x402 Discovery Example - -This example demonstrates how to use the x402 discovery feature to find and list available x402-protected resources across the network. - -## Prerequisites - -- Python 3.10+ -- uv package manager (install via [uv.dev](https://uv.dev)) - -## Setup - -1. Install and build all packages from the python examples root: -```bash -cd ../../ -uv sync -cd examples/python/discovery -``` - -2. Start the discovery example: -```bash -uv run python main.py -``` - -## How It Works - -The example demonstrates how to: -1. Use the x402 facilitator to discover available resources -2. List all x402-protected endpoints in the network -3. View detailed information about each resource including: - - Resource URLs - - Last update timestamps - - Accepted payment methods - - Resource metadata - - Protocol versions - -## Example Code - -```python -import json -import asyncio -from datetime import datetime -from x402.facilitator import FacilitatorClient -from cdp.x402 import create_facilitator_config - -# Initialize facilitator client (no API keys required for discovery) -facilitator = FacilitatorClient(create_facilitator_config()) - -async def main(): - try: - # Get the list of resources - response = await facilitator.list() - - print("\nDiscovered X402 Resources:") - print("========================\n") - - # Print each resource in a formatted way - for index, item in enumerate(response.items, 1): - print(f"Resource {index}:") - # Convert the item to JSON with proper formatting - item_json = json.loads(item.model_dump_json(by_alias=True)) - print(f" Resource URL: {item_json['resource']}") - print(f" Type: {item_json['type']}") - print(f" Last Updated: {datetime.fromisoformat(item_json['lastUpdated'].replace('Z', '+00:00')).strftime('%m/%d/%Y, %I:%M:%S %p')}") - print(f" X402 Version: {item_json['x402Version']}") - print(f" Accepts: {json.dumps(item_json['accepts'], indent=2)}") - if item_json.get("metadata"): - print(f" Metadata: {json.dumps(item_json['metadata'], indent=2)}") - print("------------------------\n") - - except Exception as e: - print(f"Error: {str(e)}") - -if __name__ == "__main__": - asyncio.run(main()) -``` - -## Output Example - -The script will output a formatted list of all discovered x402 resources, including their URLs, types, update times, and accepted payment methods. Example output: - -``` -Discovered X402 Resources: -======================== - -Resource 1: - Resource URL: https://api.example.com/x402/endpoint - Type: http - Last Updated: 8/9/2025, 1:07:04 AM - X402 Version: 1 - Accepts: [ - { - "scheme": "exact", - "network": "base-sepolia", - "maxAmountRequired": "1000000", - "resource": "https://api.example.com/x402/endpoint", - "description": "Example protected endpoint", - "mimeType": "application/json", - "payTo": "0x1234...", - "maxTimeoutSeconds": 300, - "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e" - } - ] ------------------------- -``` diff --git a/examples/python/legacy/discovery/main.py b/examples/python/legacy/discovery/main.py deleted file mode 100644 index d46bab3d65..0000000000 --- a/examples/python/legacy/discovery/main.py +++ /dev/null @@ -1,40 +0,0 @@ -import json -import asyncio -from datetime import datetime -from x402.facilitator import FacilitatorClient -from cdp.x402 import create_facilitator_config - -# Initialize facilitator client -facilitator = FacilitatorClient(create_facilitator_config()) - - -async def main(): - try: - # Get the list of resources - response = await facilitator.list() - - print("\nDiscovered X402 Resources:") - print("========================\n") - - # Print each resource in a formatted way - for index, item in enumerate(response.items, 1): - print(f"Resource {index}:") - # Convert the item to JSON with proper formatting - item_json = json.loads(item.model_dump_json(by_alias=True)) - print(f" Resource URL: {item_json['resource']}") - print(f" Type: {item_json['type']}") - print( - f" Last Updated: {datetime.fromisoformat(item_json['lastUpdated'].replace('Z', '+00:00')).strftime('%m/%d/%Y, %I:%M:%S %p')}" - ) - print(f" X402 Version: {item_json['x402Version']}") - print(f" Accepts: {json.dumps(item_json['accepts'], indent=2)}") - if item_json.get("metadata"): - print(f" Metadata: {json.dumps(item_json['metadata'], indent=2)}") - print("------------------------\n") - - except Exception as e: - print(f"Error: {str(e)}") - - -if __name__ == "__main__": - asyncio.run(main()) diff --git a/examples/python/legacy/discovery/pyproject.toml b/examples/python/legacy/discovery/pyproject.toml deleted file mode 100644 index 850cb1fa21..0000000000 --- a/examples/python/legacy/discovery/pyproject.toml +++ /dev/null @@ -1,27 +0,0 @@ -[project] -name = "client-discovery-example" -version = "0.1.0" -description = "Example of using the x402 discovery layer" -requires-python = ">=3.10" -dependencies = [ - "x402", - "cdp-sdk>=1.31.2", - "Flask>=3.1.1", - "uvicorn>=0.27.0" -] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -packages = ["."] - -[tool.hatch.metadata] -allow-direct-references = true - -[tool.uv] -package = false - -[tool.uv.sources] -x402 = { path = "../../../../python/legacy", editable = true } diff --git a/examples/python/legacy/discovery/uv.lock b/examples/python/legacy/discovery/uv.lock deleted file mode 100644 index 5f12b780bc..0000000000 --- a/examples/python/legacy/discovery/uv.lock +++ /dev/null @@ -1,2231 +0,0 @@ -version = 1 -revision = 2 -requires-python = ">=3.10" - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, -] - -[[package]] -name = "aiohttp" -version = "3.11.16" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f1/d9/1c4721d143e14af753f2bf5e3b681883e1f24b592c0482df6fa6e33597fa/aiohttp-3.11.16.tar.gz", hash = "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8", size = 7676826, upload-time = "2025-04-02T02:17:44.74Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/21/6bd4cb580a323b64cda3b11fcb3f68deba77568e97806727a858de57349d/aiohttp-3.11.16-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb46bb0f24813e6cede6cc07b1961d4b04f331f7112a23b5e21f567da4ee50aa", size = 708259, upload-time = "2025-04-02T02:15:15.439Z" }, - { url = "https://files.pythonhosted.org/packages/96/8c/7b4b9debe90ffc31931b85ee8612a5c83f34d8fdc6d90ee3eb27b43639e4/aiohttp-3.11.16-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:54eb3aead72a5c19fad07219acd882c1643a1027fbcdefac9b502c267242f955", size = 468886, upload-time = "2025-04-02T02:15:17.025Z" }, - { url = "https://files.pythonhosted.org/packages/13/da/a7fcd68e62acacf0a1930060afd2c970826f989265893082b6fb9eb25cb5/aiohttp-3.11.16-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:38bea84ee4fe24ebcc8edeb7b54bf20f06fd53ce4d2cc8b74344c5b9620597fd", size = 455846, upload-time = "2025-04-02T02:15:18.662Z" }, - { url = "https://files.pythonhosted.org/packages/5d/12/b73d9423253f4c872d276a3771decb0722cb5f962352593bd617445977ba/aiohttp-3.11.16-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0666afbe984f6933fe72cd1f1c3560d8c55880a0bdd728ad774006eb4241ecd", size = 1587183, upload-time = "2025-04-02T02:15:20.048Z" }, - { url = "https://files.pythonhosted.org/packages/75/d3/291b57d54719d996e6cb8c1db8b13d01bdb24dca90434815ac7e6a70393f/aiohttp-3.11.16-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba92a2d9ace559a0a14b03d87f47e021e4fa7681dc6970ebbc7b447c7d4b7cd", size = 1634937, upload-time = "2025-04-02T02:15:22.156Z" }, - { url = "https://files.pythonhosted.org/packages/be/85/4229eba92b433173065b0b459ab677ca11ead4a179f76ccfe55d8738b188/aiohttp-3.11.16-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ad1d59fd7114e6a08c4814983bb498f391c699f3c78712770077518cae63ff7", size = 1667980, upload-time = "2025-04-02T02:15:23.843Z" }, - { url = "https://files.pythonhosted.org/packages/2b/0d/d2423936962e3c711fafd5bb9172a99e6b07dd63e086515aa957d8a991fd/aiohttp-3.11.16-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b88a2bf26965f2015a771381624dd4b0839034b70d406dc74fd8be4cc053e3", size = 1590365, upload-time = "2025-04-02T02:15:25.809Z" }, - { url = "https://files.pythonhosted.org/packages/ea/93/04209affc20834982c1ef4214b1afc07743667998a9975d69413e9c1e1c1/aiohttp-3.11.16-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:576f5ca28d1b3276026f7df3ec841ae460e0fc3aac2a47cbf72eabcfc0f102e1", size = 1547614, upload-time = "2025-04-02T02:15:27.544Z" }, - { url = "https://files.pythonhosted.org/packages/f6/fb/194ad4e4cae98023ae19556e576347f402ce159e80d74cc0713d460c4a39/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a2a450bcce4931b295fc0848f384834c3f9b00edfc2150baafb4488c27953de6", size = 1532815, upload-time = "2025-04-02T02:15:28.985Z" }, - { url = "https://files.pythonhosted.org/packages/33/6d/a4da7adbac90188bf1228c73b6768a607dd279c146721a9ff7dcb75c5ac6/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:37dcee4906454ae377be5937ab2a66a9a88377b11dd7c072df7a7c142b63c37c", size = 1559005, upload-time = "2025-04-02T02:15:30.406Z" }, - { url = "https://files.pythonhosted.org/packages/7e/88/2fa9fbfd23fc16cb2cfdd1f290343e085e7e327438041e9c6aa0208a854d/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4d0c970c0d602b1017e2067ff3b7dac41c98fef4f7472ec2ea26fd8a4e8c2149", size = 1535231, upload-time = "2025-04-02T02:15:32.468Z" }, - { url = "https://files.pythonhosted.org/packages/f5/8f/9623cd2558e3e182d02dcda8b480643e1c48a0550a86e3050210e98dba27/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:004511d3413737700835e949433536a2fe95a7d0297edd911a1e9705c5b5ea43", size = 1609985, upload-time = "2025-04-02T02:15:33.899Z" }, - { url = "https://files.pythonhosted.org/packages/f8/a2/53a8d1bfc67130710f1c8091f623cdefe7f85cd5d09e14637ed2ed6e1a6d/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c15b2271c44da77ee9d822552201180779e5e942f3a71fb74e026bf6172ff287", size = 1628842, upload-time = "2025-04-02T02:15:35.396Z" }, - { url = "https://files.pythonhosted.org/packages/49/3a/35fb43d07489573c6c1f8c6a3e6c657196124a63223705b7feeddaea06f1/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad9509ffb2396483ceacb1eee9134724443ee45b92141105a4645857244aecc8", size = 1566929, upload-time = "2025-04-02T02:15:36.863Z" }, - { url = "https://files.pythonhosted.org/packages/d5/82/bb3f4f2cc7677e790ba4c040db7dd8445c234a810ef893a858e217647d38/aiohttp-3.11.16-cp310-cp310-win32.whl", hash = "sha256:634d96869be6c4dc232fc503e03e40c42d32cfaa51712aee181e922e61d74814", size = 416935, upload-time = "2025-04-02T02:15:38.337Z" }, - { url = "https://files.pythonhosted.org/packages/df/ad/a64db1c18063569d6dff474c46a7d4de7ab85ff55e2a35839b149b1850ea/aiohttp-3.11.16-cp310-cp310-win_amd64.whl", hash = "sha256:938f756c2b9374bbcc262a37eea521d8a0e6458162f2a9c26329cc87fdf06534", size = 442168, upload-time = "2025-04-02T02:15:39.757Z" }, - { url = "https://files.pythonhosted.org/packages/b1/98/be30539cd84260d9f3ea1936d50445e25aa6029a4cb9707f3b64cfd710f7/aiohttp-3.11.16-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8cb0688a8d81c63d716e867d59a9ccc389e97ac7037ebef904c2b89334407180", size = 708664, upload-time = "2025-04-02T02:15:41.433Z" }, - { url = "https://files.pythonhosted.org/packages/e6/27/d51116ce18bdfdea7a2244b55ad38d7b01a4298af55765eed7e8431f013d/aiohttp-3.11.16-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ad1fb47da60ae1ddfb316f0ff16d1f3b8e844d1a1e154641928ea0583d486ed", size = 468953, upload-time = "2025-04-02T02:15:43.118Z" }, - { url = "https://files.pythonhosted.org/packages/34/23/eedf80ec42865ea5355b46265a2433134138eff9a4fea17e1348530fa4ae/aiohttp-3.11.16-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:df7db76400bf46ec6a0a73192b14c8295bdb9812053f4fe53f4e789f3ea66bbb", size = 456065, upload-time = "2025-04-02T02:15:44.994Z" }, - { url = "https://files.pythonhosted.org/packages/36/23/4a5b1ef6cff994936bf96d981dd817b487d9db755457a0d1c2939920d620/aiohttp-3.11.16-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc3a145479a76ad0ed646434d09216d33d08eef0d8c9a11f5ae5cdc37caa3540", size = 1687976, upload-time = "2025-04-02T02:15:46.632Z" }, - { url = "https://files.pythonhosted.org/packages/d0/5d/c7474b4c3069bb35276d54c82997dff4f7575e4b73f0a7b1b08a39ece1eb/aiohttp-3.11.16-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d007aa39a52d62373bd23428ba4a2546eed0e7643d7bf2e41ddcefd54519842c", size = 1752711, upload-time = "2025-04-02T02:15:48.276Z" }, - { url = "https://files.pythonhosted.org/packages/64/4c/ee416987b6729558f2eb1b727c60196580aafdb141e83bd78bb031d1c000/aiohttp-3.11.16-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6ddd90d9fb4b501c97a4458f1c1720e42432c26cb76d28177c5b5ad4e332601", size = 1791305, upload-time = "2025-04-02T02:15:49.965Z" }, - { url = "https://files.pythonhosted.org/packages/58/28/3e1e1884070b95f1f69c473a1995852a6f8516670bb1c29d6cb2dbb73e1c/aiohttp-3.11.16-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a2f451849e6b39e5c226803dcacfa9c7133e9825dcefd2f4e837a2ec5a3bb98", size = 1674499, upload-time = "2025-04-02T02:15:51.718Z" }, - { url = "https://files.pythonhosted.org/packages/ad/55/a032b32fa80a662d25d9eb170ed1e2c2be239304ca114ec66c89dc40f37f/aiohttp-3.11.16-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8df6612df74409080575dca38a5237282865408016e65636a76a2eb9348c2567", size = 1622313, upload-time = "2025-04-02T02:15:53.377Z" }, - { url = "https://files.pythonhosted.org/packages/b1/df/ca775605f72abbda4e4746e793c408c84373ca2c6ce7a106a09f853f1e89/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:78e6e23b954644737e385befa0deb20233e2dfddf95dd11e9db752bdd2a294d3", size = 1658274, upload-time = "2025-04-02T02:15:55.035Z" }, - { url = "https://files.pythonhosted.org/packages/cc/6c/21c45b66124df5b4b0ab638271ecd8c6402b702977120cb4d5be6408e15d/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:696ef00e8a1f0cec5e30640e64eca75d8e777933d1438f4facc9c0cdf288a810", size = 1666704, upload-time = "2025-04-02T02:15:56.581Z" }, - { url = "https://files.pythonhosted.org/packages/1d/e2/7d92adc03e3458edd18a21da2575ab84e58f16b1672ae98529e4eeee45ab/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3538bc9fe1b902bef51372462e3d7c96fce2b566642512138a480b7adc9d508", size = 1652815, upload-time = "2025-04-02T02:15:58.126Z" }, - { url = "https://files.pythonhosted.org/packages/3a/52/7549573cd654ad651e3c5786ec3946d8f0ee379023e22deb503ff856b16c/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3ab3367bb7f61ad18793fea2ef71f2d181c528c87948638366bf1de26e239183", size = 1735669, upload-time = "2025-04-02T02:16:00.313Z" }, - { url = "https://files.pythonhosted.org/packages/d5/54/dcd24a23c7a5a2922123e07a296a5f79ea87ce605f531be068415c326de6/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:56a3443aca82abda0e07be2e1ecb76a050714faf2be84256dae291182ba59049", size = 1760422, upload-time = "2025-04-02T02:16:02.233Z" }, - { url = "https://files.pythonhosted.org/packages/a7/53/87327fe982fa310944e1450e97bf7b2a28015263771931372a1dfe682c58/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:61c721764e41af907c9d16b6daa05a458f066015abd35923051be8705108ed17", size = 1694457, upload-time = "2025-04-02T02:16:04.233Z" }, - { url = "https://files.pythonhosted.org/packages/ce/6d/c5ccf41059267bcf89853d3db9d8d217dacf0a04f4086cb6bf278323011f/aiohttp-3.11.16-cp311-cp311-win32.whl", hash = "sha256:3e061b09f6fa42997cf627307f220315e313ece74907d35776ec4373ed718b86", size = 416817, upload-time = "2025-04-02T02:16:06.268Z" }, - { url = "https://files.pythonhosted.org/packages/e7/dd/01f6fe028e054ef4f909c9d63e3a2399e77021bb2e1bb51d56ca8b543989/aiohttp-3.11.16-cp311-cp311-win_amd64.whl", hash = "sha256:745f1ed5e2c687baefc3c5e7b4304e91bf3e2f32834d07baaee243e349624b24", size = 442986, upload-time = "2025-04-02T02:16:07.712Z" }, - { url = "https://files.pythonhosted.org/packages/db/38/100d01cbc60553743baf0fba658cb125f8ad674a8a771f765cdc155a890d/aiohttp-3.11.16-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:911a6e91d08bb2c72938bc17f0a2d97864c531536b7832abee6429d5296e5b27", size = 704881, upload-time = "2025-04-02T02:16:09.26Z" }, - { url = "https://files.pythonhosted.org/packages/21/ed/b4102bb6245e36591209e29f03fe87e7956e54cb604ee12e20f7eb47f994/aiohttp-3.11.16-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac13b71761e49d5f9e4d05d33683bbafef753e876e8e5a7ef26e937dd766713", size = 464564, upload-time = "2025-04-02T02:16:10.781Z" }, - { url = "https://files.pythonhosted.org/packages/3b/e1/a9ab6c47b62ecee080eeb33acd5352b40ecad08fb2d0779bcc6739271745/aiohttp-3.11.16-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fd36c119c5d6551bce374fcb5c19269638f8d09862445f85a5a48596fd59f4bb", size = 456548, upload-time = "2025-04-02T02:16:12.764Z" }, - { url = "https://files.pythonhosted.org/packages/80/ad/216c6f71bdff2becce6c8776f0aa32cb0fa5d83008d13b49c3208d2e4016/aiohttp-3.11.16-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d489d9778522fbd0f8d6a5c6e48e3514f11be81cb0a5954bdda06f7e1594b321", size = 1691749, upload-time = "2025-04-02T02:16:14.304Z" }, - { url = "https://files.pythonhosted.org/packages/bd/ea/7df7bcd3f4e734301605f686ffc87993f2d51b7acb6bcc9b980af223f297/aiohttp-3.11.16-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69a2cbd61788d26f8f1e626e188044834f37f6ae3f937bd9f08b65fc9d7e514e", size = 1736874, upload-time = "2025-04-02T02:16:16.538Z" }, - { url = "https://files.pythonhosted.org/packages/51/41/c7724b9c87a29b7cfd1202ec6446bae8524a751473d25e2ff438bc9a02bf/aiohttp-3.11.16-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd464ba806e27ee24a91362ba3621bfc39dbbb8b79f2e1340201615197370f7c", size = 1786885, upload-time = "2025-04-02T02:16:18.268Z" }, - { url = "https://files.pythonhosted.org/packages/86/b3/f61f8492fa6569fa87927ad35a40c159408862f7e8e70deaaead349e2fba/aiohttp-3.11.16-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce63ae04719513dd2651202352a2beb9f67f55cb8490c40f056cea3c5c355ce", size = 1698059, upload-time = "2025-04-02T02:16:20.234Z" }, - { url = "https://files.pythonhosted.org/packages/ce/be/7097cf860a9ce8bbb0e8960704e12869e111abcd3fbd245153373079ccec/aiohttp-3.11.16-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b00dd520d88eac9d1768439a59ab3d145065c91a8fab97f900d1b5f802895e", size = 1626527, upload-time = "2025-04-02T02:16:22.092Z" }, - { url = "https://files.pythonhosted.org/packages/1d/1d/aaa841c340e8c143a8d53a1f644c2a2961c58cfa26e7b398d6bf75cf5d23/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7f6428fee52d2bcf96a8aa7b62095b190ee341ab0e6b1bcf50c615d7966fd45b", size = 1644036, upload-time = "2025-04-02T02:16:23.707Z" }, - { url = "https://files.pythonhosted.org/packages/2c/88/59d870f76e9345e2b149f158074e78db457985c2b4da713038d9da3020a8/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:13ceac2c5cdcc3f64b9015710221ddf81c900c5febc505dbd8f810e770011540", size = 1685270, upload-time = "2025-04-02T02:16:25.874Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b1/c6686948d4c79c3745595efc469a9f8a43cab3c7efc0b5991be65d9e8cb8/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fadbb8f1d4140825069db3fedbbb843290fd5f5bc0a5dbd7eaf81d91bf1b003b", size = 1650852, upload-time = "2025-04-02T02:16:27.556Z" }, - { url = "https://files.pythonhosted.org/packages/fe/94/3e42a6916fd3441721941e0f1b8438e1ce2a4c49af0e28e0d3c950c9b3c9/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6a792ce34b999fbe04a7a71a90c74f10c57ae4c51f65461a411faa70e154154e", size = 1704481, upload-time = "2025-04-02T02:16:29.573Z" }, - { url = "https://files.pythonhosted.org/packages/b1/6d/6ab5854ff59b27075c7a8c610597d2b6c38945f9a1284ee8758bc3720ff6/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f4065145bf69de124accdd17ea5f4dc770da0a6a6e440c53f6e0a8c27b3e635c", size = 1735370, upload-time = "2025-04-02T02:16:31.191Z" }, - { url = "https://files.pythonhosted.org/packages/73/2a/08a68eec3c99a6659067d271d7553e4d490a0828d588e1daa3970dc2b771/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa73e8c2656a3653ae6c307b3f4e878a21f87859a9afab228280ddccd7369d71", size = 1697619, upload-time = "2025-04-02T02:16:32.873Z" }, - { url = "https://files.pythonhosted.org/packages/61/d5/fea8dbbfb0cd68fbb56f0ae913270a79422d9a41da442a624febf72d2aaf/aiohttp-3.11.16-cp312-cp312-win32.whl", hash = "sha256:f244b8e541f414664889e2c87cac11a07b918cb4b540c36f7ada7bfa76571ea2", size = 411710, upload-time = "2025-04-02T02:16:34.525Z" }, - { url = "https://files.pythonhosted.org/packages/33/fb/41cde15fbe51365024550bf77b95a4fc84ef41365705c946da0421f0e1e0/aiohttp-3.11.16-cp312-cp312-win_amd64.whl", hash = "sha256:23a15727fbfccab973343b6d1b7181bfb0b4aa7ae280f36fd2f90f5476805682", size = 438012, upload-time = "2025-04-02T02:16:36.103Z" }, - { url = "https://files.pythonhosted.org/packages/52/52/7c712b2d9fb4d5e5fd6d12f9ab76e52baddfee71e3c8203ca7a7559d7f51/aiohttp-3.11.16-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489", size = 698005, upload-time = "2025-04-02T02:16:37.923Z" }, - { url = "https://files.pythonhosted.org/packages/51/3e/61057814f7247666d43ac538abcd6335b022869ade2602dab9bf33f607d2/aiohttp-3.11.16-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50", size = 461106, upload-time = "2025-04-02T02:16:39.961Z" }, - { url = "https://files.pythonhosted.org/packages/4f/85/6b79fb0ea6e913d596d5b949edc2402b20803f51b1a59e1bbc5bb7ba7569/aiohttp-3.11.16-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133", size = 453394, upload-time = "2025-04-02T02:16:41.562Z" }, - { url = "https://files.pythonhosted.org/packages/4b/04/e1bb3fcfbd2c26753932c759593a32299aff8625eaa0bf8ff7d9c0c34a36/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0", size = 1666643, upload-time = "2025-04-02T02:16:43.62Z" }, - { url = "https://files.pythonhosted.org/packages/0e/27/97bc0fdd1f439b8f060beb3ba8fb47b908dc170280090801158381ad7942/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca", size = 1721948, upload-time = "2025-04-02T02:16:45.617Z" }, - { url = "https://files.pythonhosted.org/packages/2c/4f/bc4c5119e75c05ef15c5670ef1563bbe25d4ed4893b76c57b0184d815e8b/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d", size = 1774454, upload-time = "2025-04-02T02:16:48.562Z" }, - { url = "https://files.pythonhosted.org/packages/73/5b/54b42b2150bb26fdf795464aa55ceb1a49c85f84e98e6896d211eabc6670/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb", size = 1677785, upload-time = "2025-04-02T02:16:50.367Z" }, - { url = "https://files.pythonhosted.org/packages/10/ee/a0fe68916d3f82eae199b8535624cf07a9c0a0958c7a76e56dd21140487a/aiohttp-3.11.16-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4", size = 1608456, upload-time = "2025-04-02T02:16:52.158Z" }, - { url = "https://files.pythonhosted.org/packages/8b/48/83afd779242b7cf7e1ceed2ff624a86d3221e17798061cf9a79e0b246077/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7", size = 1622424, upload-time = "2025-04-02T02:16:54.386Z" }, - { url = "https://files.pythonhosted.org/packages/6f/27/452f1d5fca1f516f9f731539b7f5faa9e9d3bf8a3a6c3cd7c4b031f20cbd/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd", size = 1660943, upload-time = "2025-04-02T02:16:56.887Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e1/5c7d63143b8d00c83b958b9e78e7048c4a69903c760c1e329bf02bac57a1/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f", size = 1622797, upload-time = "2025-04-02T02:16:58.676Z" }, - { url = "https://files.pythonhosted.org/packages/46/9e/2ac29cca2746ee8e449e73cd2fcb3d454467393ec03a269d50e49af743f1/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd", size = 1687162, upload-time = "2025-04-02T02:17:01.076Z" }, - { url = "https://files.pythonhosted.org/packages/ad/6b/eaa6768e02edebaf37d77f4ffb74dd55f5cbcbb6a0dbf798ccec7b0ac23b/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34", size = 1718518, upload-time = "2025-04-02T02:17:03.388Z" }, - { url = "https://files.pythonhosted.org/packages/e5/18/dda87cbad29472a51fa058d6d8257dfce168289adaeb358b86bd93af3b20/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913", size = 1675254, upload-time = "2025-04-02T02:17:05.579Z" }, - { url = "https://files.pythonhosted.org/packages/32/d9/d2fb08c614df401d92c12fcbc60e6e879608d5e8909ef75c5ad8d4ad8aa7/aiohttp-3.11.16-cp313-cp313-win32.whl", hash = "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979", size = 410698, upload-time = "2025-04-02T02:17:07.499Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ed/853e36d5a33c24544cfa46585895547de152dfef0b5c79fa675f6e4b7b87/aiohttp-3.11.16-cp313-cp313-win_amd64.whl", hash = "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802", size = 436395, upload-time = "2025-04-02T02:17:09.566Z" }, -] - -[[package]] -name = "aiohttp-retry" -version = "2.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/61/ebda4d8e3d8cfa1fd3db0fb428db2dd7461d5742cea35178277ad180b033/aiohttp_retry-2.9.1.tar.gz", hash = "sha256:8eb75e904ed4ee5c2ec242fefe85bf04240f685391c4879d8f541d6028ff01f1", size = 13608, upload-time = "2024-11-06T10:44:54.574Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/99/84ba7273339d0f3dfa57901b846489d2e5c2cd731470167757f1935fffbd/aiohttp_retry-2.9.1-py3-none-any.whl", hash = "sha256:66d2759d1921838256a05a3f80ad7e724936f083e35be5abb5e16eed6be6dc54", size = 9981, upload-time = "2024-11-06T10:44:52.917Z" }, -] - -[[package]] -name = "aiosignal" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, -] - -[[package]] -name = "async-timeout" -version = "5.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, -] - -[[package]] -name = "attrs" -version = "25.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, -] - -[[package]] -name = "base58" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/45/8ae61209bb9015f516102fa559a2914178da1d5868428bd86a1b4421141d/base58-2.1.1.tar.gz", hash = "sha256:c5d0cb3f5b6e81e8e35da5754388ddcc6d0d14b6c6a132cb93d69ed580a7278c", size = 6528, upload-time = "2021-10-30T22:12:17.858Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/45/ec96b29162a402fc4c1c5512d114d7b3787b9d1c2ec241d9568b4816ee23/base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2", size = 5621, upload-time = "2021-10-30T22:12:16.658Z" }, -] - -[[package]] -name = "bitarray" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/0d/15826c7c2d49a4518a1b24b0d432f1ecad2e0b68168f942058b5de498498/bitarray-3.4.2.tar.gz", hash = "sha256:78ed2b911aabede3a31e3329b1de8abdc8104bd5e0545184ddbd9c7f668f4059", size = 143756, upload-time = "2025-05-21T16:21:44.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/61/fa3a06d74bfba1dc591efa9f4f5ad2e5645f06a8c4d113cf12d18b5ac25b/bitarray-3.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:42b552f885c5629182928c79237b375a92bcf1bc1e725b1c8a5e8eab28ea300d", size = 141280, upload-time = "2025-05-21T16:18:02.593Z" }, - { url = "https://files.pythonhosted.org/packages/17/ba/7eb30374c0e4c4b732a3ca3457d9fb0e44165ae4c5af9758597b03211a28/bitarray-3.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3e16d6184f349587b6a5045bcf073baf763a86273aab454485ba437d0bca82e8", size = 138031, upload-time = "2025-05-21T16:18:05.616Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6d/91582b0a232b54e910add5d0db34a926d0bdfdd1447685b8750349c71958/bitarray-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ecf456f0dee61bd818011e290d922e3e3b1aeb0544f6f19c4da9c5fc2e52818", size = 306437, upload-time = "2025-05-21T16:18:06.793Z" }, - { url = "https://files.pythonhosted.org/packages/b8/23/113ccc20f6324d517ef6210c8fc6ae300346eb481c5a0483735e19b4deea/bitarray-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8bbe8249ae90dc0cd78b21d5d5d27a614e15bf30737ae6e8a0e2e60cc492acc", size = 322335, upload-time = "2025-05-21T16:18:07.925Z" }, - { url = "https://files.pythonhosted.org/packages/6d/89/bf5a36e05ac3d77bdccbe9ba0eea4c47253411c2616379de0f181c27ecee/bitarray-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe7706f75f3b86e7afa516452bed9757ee301b59aea580c551c32a5e1cef082c", size = 314137, upload-time = "2025-05-21T16:18:09.333Z" }, - { url = "https://files.pythonhosted.org/packages/66/a6/bed287f9095a2a266fc68ee42d6ee2815ff500783f973876d86a6d37a434/bitarray-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c60c8d30bb6efd2c04cf82d077df6449964234aeca996f6f1df317a08feffc0", size = 307963, upload-time = "2025-05-21T16:18:10.618Z" }, - { url = "https://files.pythonhosted.org/packages/2f/50/3ca2adaf0da034e6c1a2ed60a3781b065672dd282e67f88593290c3990a7/bitarray-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b4cb5c22706d411010c7ce5efc0a4cc99f755a30fc7f6770eb1b1a0c0962bbb", size = 295182, upload-time = "2025-05-21T16:18:11.932Z" }, - { url = "https://files.pythonhosted.org/packages/90/de/8c3d96e273bc51e4912185bd809fc6a9ec14a09e607336892c149e0c57c5/bitarray-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0fd60137a9474ce53bdace68c718a7c538f9df01d390452cc984f1ee78d7bcdb", size = 300063, upload-time = "2025-05-21T16:18:13.221Z" }, - { url = "https://files.pythonhosted.org/packages/9d/71/34f0ea6ac5b2cbdd84f3e6283b5b796628cef616e786cb442cefce0fe224/bitarray-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cd514a8e27d0751f0254861df60335edabacccfcb2457793ff30c8b2ed8f799d", size = 292053, upload-time = "2025-05-21T16:18:14.802Z" }, - { url = "https://files.pythonhosted.org/packages/77/99/6ef41312536d2c37f14f0f7173aa1a012e9675d62900c10afa7641b47f75/bitarray-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6c8f7447cdf2faff1d176c5dd207f0134f05cfa2a238d3d3944dc5019dc41593", size = 317007, upload-time = "2025-05-21T16:18:16.117Z" }, - { url = "https://files.pythonhosted.org/packages/22/f9/cc4e73f54698bcdd1e0f1ea582da7e005464651e8116291a226deab95e1b/bitarray-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:75040a2a1abe4ccd40236f4ba0d39abde981d23f3ce7691b3b3f2137f134b99b", size = 319402, upload-time = "2025-05-21T16:18:18.097Z" }, - { url = "https://files.pythonhosted.org/packages/55/40/c23dd5726107cbbc5e698b3fcca5ffac83d29146ef469f27f5277d18c2d7/bitarray-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ba15725cd9040b9b1b2650edb33253cb2ba7b68d087974e296e5ff082198952f", size = 299456, upload-time = "2025-05-21T16:18:20.029Z" }, - { url = "https://files.pythonhosted.org/packages/21/31/6bfd9fda776f8d98512d5484fcb55fbb25e60796e7b5d3b9a3a300e8bc1c/bitarray-3.4.2-cp310-cp310-win32.whl", hash = "sha256:2959dfc61d963546e97220cfcaab7dfc489276c6e00092b57710522e68712b28", size = 134279, upload-time = "2025-05-21T16:18:21.609Z" }, - { url = "https://files.pythonhosted.org/packages/82/9d/7067f6548b470beb86d83f7ac6c45cac3b9c28cf77fa0f9f3e67353d69d3/bitarray-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:97077fa0ec3b7eed57cd8d1cb0eb75d670423d20b7e4901482347a81efe2f6fd", size = 141360, upload-time = "2025-05-21T16:18:23.197Z" }, - { url = "https://files.pythonhosted.org/packages/94/ba/508ba6a3ea16eb6c21baae33cd1b7bf6e299d21a496a1f90b8203a22d6d0/bitarray-3.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90ca8e260b75a7ac0c542093e5f29154e51fd0d2d0fa5041c038cb2b58415eeb", size = 141425, upload-time = "2025-05-21T16:18:24.452Z" }, - { url = "https://files.pythonhosted.org/packages/eb/a1/44d9b88cd3daee3734ea98dac691acc2c935a3bfbd5bfc38267a59bd986d/bitarray-3.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549dabcae78fb8f9133e3138b9473c7648d6054bb6fec84d28d3861aaec5ddd1", size = 138172, upload-time = "2025-05-21T16:18:25.601Z" }, - { url = "https://files.pythonhosted.org/packages/5f/aa/5a8c33ab39e8a894978d42427ad0a1ba2d5c9cb61c8480101be555c0e3a7/bitarray-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3da536ac84e6911cbc8e86be0baf1cab0d4f4ccb80c0f39b4fa28509f2db1a", size = 313373, upload-time = "2025-05-21T16:18:26.796Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/b0d28e21d91ec5c0477a320b9443096ddc816fbc59778b367f9e49094532/bitarray-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a5e84d6b737de2d773ab1bd538e6f37fa7f667ea734f00a48d9a973b181c751", size = 329657, upload-time = "2025-05-21T16:18:28.097Z" }, - { url = "https://files.pythonhosted.org/packages/bd/d5/1f858bd559568286435a460e7a169a5185b2b29184684e6c6fa303af3ca9/bitarray-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e265c5eede8316ba64bb6029832f282f6284a557b625bb3207a7680fd5da7925", size = 321873, upload-time = "2025-05-21T16:18:29.511Z" }, - { url = "https://files.pythonhosted.org/packages/e8/c8/23df4174142cccf6a8bd114651b8e9bf965005ab1ef741d37c9f72e8d2eb/bitarray-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63fb45c60c7ab7a724aa64203305e56f344489e12d41619bdc9d7887d6562e01", size = 314796, upload-time = "2025-05-21T16:18:31.2Z" }, - { url = "https://files.pythonhosted.org/packages/8f/21/329178b165f1aaf3f2ace3eb24aca5ad197febae908d7b41e552a69043e9/bitarray-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:083c2a9234dacf3e4e166a5844256da2a397941d3f6397e5b919bffca638f6ef", size = 302724, upload-time = "2025-05-21T16:18:32.729Z" }, - { url = "https://files.pythonhosted.org/packages/26/a8/a66d3c0d3410d01f51824f8476b060f96b3353db7d6b45c87dba6d1aa0e0/bitarray-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e72606adb2438002873cb0e8e81c3fce926386a59bbafa82fea07cdb2a6d8a05", size = 307434, upload-time = "2025-05-21T16:18:34.394Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ac/3052386e7ff80c80eb2549a22c890f511e9f9f7fbbe6244b04255adae031/bitarray-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dc994d22a3a563e1d402dc2f64c61e60605a1a3e66dd8aea7636f607b99f03cb", size = 299232, upload-time = "2025-05-21T16:18:35.708Z" }, - { url = "https://files.pythonhosted.org/packages/9d/46/91a32ccd39d40371ed7404d96a6f3cf1e381eaf36be5390c6bff5034f344/bitarray-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:214468391680ba1c831872a7949f1b563ab3cd832d10adc52df4f36e0af24446", size = 324056, upload-time = "2025-05-21T16:18:37.536Z" }, - { url = "https://files.pythonhosted.org/packages/39/0e/cb824f0e0302cd08809f67b35b3ae21b47af5dd122e99740bfe6bde1c824/bitarray-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c7483b97807bb018a7cd7f9741800c714c9c56ba4e5a7e962c5f956c4b858f3c", size = 327058, upload-time = "2025-05-21T16:18:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/09/01/845e977d490e4e261179785540d1fdeff966c99296f503adc0e5407fc257/bitarray-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5774bf14ec451d5ac311cfcfe0b0cf2a1a9fa74b6ca81dfbc4f56a98872a5541", size = 306629, upload-time = "2025-05-21T16:18:40.211Z" }, - { url = "https://files.pythonhosted.org/packages/29/ef/33ee8533ff1b2a8cd0b9e84fd81b2a90d66c2774544c861e281c5361eaa2/bitarray-3.4.2-cp311-cp311-win32.whl", hash = "sha256:e6f35567347ddb8b9e8b6bf6ab7d64be88bdb6b6c107b8edbb2c3d426c1590a0", size = 134450, upload-time = "2025-05-21T16:18:42.435Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/069c255d067319a9695c93369641d7f5539625069c1cf3ded2becff1bfbc/bitarray-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae5b0a8d3caf6284220232738dc7c05af81ec3a9f93d4a462295462dd0a492b2", size = 141596, upload-time = "2025-05-21T16:18:43.743Z" }, - { url = "https://files.pythonhosted.org/packages/05/57/0b2b50eb3f50c3144f705d0994171f17fda00ee3a72d563ba764ea235f66/bitarray-3.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a0e498563e0eefa96a1b92461d083de11256f6510b7706d5f2e6473cd9b7137a", size = 141191, upload-time = "2025-05-21T16:18:45.436Z" }, - { url = "https://files.pythonhosted.org/packages/81/c3/1d9ce4d0041c10ce90d924b8cea63afdda84a64623179045c0c67998922c/bitarray-3.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:114870ab71a0ebdac211aa0a120a54206c333b74b99fdf4b58fbe904979e1fef", size = 138158, upload-time = "2025-05-21T16:18:46.685Z" }, - { url = "https://files.pythonhosted.org/packages/5d/dd/a8653dac671ba97b1c68ee73b08a0eb2042f24e5e31f51b86afc09588c06/bitarray-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fbf6121978cba4313c31f7cc5961e481242def2b8ddfea34ca27ba9da52c9c1", size = 315834, upload-time = "2025-05-21T16:18:47.926Z" }, - { url = "https://files.pythonhosted.org/packages/3d/a2/30547bea0a35f9f953e99f5157749d56304d3f3a96b01a982dd604a9dc48/bitarray-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:423bb4e1bec0bc5d63969e12bcc5cc0081cc5aec4d7b62a6cd8240342aa36107", size = 331317, upload-time = "2025-05-21T16:18:49.169Z" }, - { url = "https://files.pythonhosted.org/packages/2d/b9/1789476280f46455a9a30bcd252fda6fd995583d97d1b919ec0296393e2a/bitarray-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ef80a96487c82477e8def69a58a218491794f7989b3e191cbaaa7b450315a5c", size = 324416, upload-time = "2025-05-21T16:18:50.917Z" }, - { url = "https://files.pythonhosted.org/packages/84/89/519c829ca641a3e7b8c9be56d177aaa05572b7e15e4298df4a77959b6a1e/bitarray-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35f5c69a79047e50bc1d54a777541b0a86b213e23559b1ac3d76fa9a42cc5522", size = 317634, upload-time = "2025-05-21T16:18:52.718Z" }, - { url = "https://files.pythonhosted.org/packages/0d/39/ebb6a6539261279c0994836b40b99384fa5e27ec239e70b203e310343f80/bitarray-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:002f7b128ed9d18d3ecb51ca78aeea5afffbe8e80d6be4ff2984d045b1c4b937", size = 305392, upload-time = "2025-05-21T16:18:54.888Z" }, - { url = "https://files.pythonhosted.org/packages/83/04/0ee0d57b2a60fdf881346f196fd92b824f44f4736026da1d8c7970745266/bitarray-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:999bccc72704afcf4a3d9868db4d149c032cdf910f9f7d91e30166978530af7f", size = 309740, upload-time = "2025-05-21T16:18:56.76Z" }, - { url = "https://files.pythonhosted.org/packages/f6/39/5ab0339e93097f2a2631ea281a6386c31707011499d5cf68b4e0e37ba124/bitarray-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2e44cfe2bc161cde3b11604f279e3048ef7bd3413837aadbd2ca30b5233c82cb", size = 301607, upload-time = "2025-05-21T16:18:58.144Z" }, - { url = "https://files.pythonhosted.org/packages/e8/bb/b8f697ba6a16c1e393afe75029d069e2dd457e62b112c3cb26768d2e65eb/bitarray-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f408ba3e6f706a0eabae405d1906ceb539f34a318562a91ab9799c5e1712e18c", size = 325942, upload-time = "2025-05-21T16:18:59.471Z" }, - { url = "https://files.pythonhosted.org/packages/64/ec/77d866a96909c09c5a34f1716f015386f9d9bbbf4b5dc7219f642b8043e2/bitarray-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bf94513ae559b2525e6218e41b03790f866d75df5404490420f2c25e42cf55e7", size = 329491, upload-time = "2025-05-21T16:19:01.205Z" }, - { url = "https://files.pythonhosted.org/packages/37/6e/633b7d392a39df655c92035da9ee52f7332bb165ae72038692a33a6def6c/bitarray-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f2c88c792815d2755c49a3a1fca256e142c4adfadf1a2142b5a3a37e4d4b871", size = 309566, upload-time = "2025-05-21T16:19:02.762Z" }, - { url = "https://files.pythonhosted.org/packages/ab/38/9d7ad6eca72e09b81097176dd66eed3aeaabdea4c24cf6ce25609599ce7b/bitarray-3.4.2-cp312-cp312-win32.whl", hash = "sha256:f4dac6b942c4d7ae5f6eb555ee3993de1432bf9c8f46e3caf74b6671ac5571a3", size = 134600, upload-time = "2025-05-21T16:19:04.057Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d3/c83ec3d912be73861a064f1a705436f270b8c5b5926350a875bd6c06b6df/bitarray-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:6c37e6814633041307f0df281651a86372b0ccdb1e4768247a87e83e2b68f9b9", size = 141844, upload-time = "2025-05-21T16:19:05.254Z" }, - { url = "https://files.pythonhosted.org/packages/f2/22/973d377477e1f27cf64f9e3292343219577136e32665a52667589380100d/bitarray-3.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:16263bdbb05ce379e7b8e9a9f3e0a61a9204a06a037bbc91322d2939b3079fd5", size = 141162, upload-time = "2025-05-21T16:19:06.488Z" }, - { url = "https://files.pythonhosted.org/packages/eb/53/65541b94fb6df1e8aa9a7359ac68f469c3243d8bc7302c5fb8ff8936dab2/bitarray-3.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:41fdc6fb8c3aabfcfe0073302c69fef0c74d6499491f133ba58755c3f2afb3d0", size = 138162, upload-time = "2025-05-21T16:19:07.688Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b2/83d587965f7969a5016a5bf5c9295a0651a34b668df41fa089d7c924ac08/bitarray-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c2571337b11c69206e339170516f3e72b4ec16250876c4f2bbb6e82b9caa15", size = 315760, upload-time = "2025-05-21T16:19:09.834Z" }, - { url = "https://files.pythonhosted.org/packages/4f/f5/2b2924181809debdb644143aa33d16facdce5763d5ff17e5301ecdaf89dc/bitarray-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0e3d5f37217dde9b206418c37c4d86e173f072a892670e9714e6bb20b228e95", size = 331250, upload-time = "2025-05-21T16:19:11.449Z" }, - { url = "https://files.pythonhosted.org/packages/00/2b/8ed4eeb947e05ef54614feff4cc4badd03e29ec35d46aa0218513cc9f8ac/bitarray-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83202735f21fc781f27228daeae94b6c7df1a9f673b9dd6a1c0b3764d92b8e50", size = 324299, upload-time = "2025-05-21T16:19:13.236Z" }, - { url = "https://files.pythonhosted.org/packages/05/27/d7f1b15c079cbeffad76f97c41c27635873be4d5600f6896b2bbc4f5caff/bitarray-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b3f8c35812d85a299d6c0ff097f93e18dfb7a324c129e20a4ec0ecfc4ba995", size = 317522, upload-time = "2025-05-21T16:19:14.832Z" }, - { url = "https://files.pythonhosted.org/packages/a5/db/e6a857a23222360dbc0b0d177e6060ecd88d63a1d6a3c2b52333c21a9683/bitarray-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef3f2e8ba5d6e0f38b57960d1bfb72aa9e2115f7cdca48561fadced652798d49", size = 305290, upload-time = "2025-05-21T16:19:16.57Z" }, - { url = "https://files.pythonhosted.org/packages/16/12/3b945e415233889c57c26f95a9a6a245da546e2c8d1de09991332cb796ff/bitarray-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:508ec6547bdd9f0c435c322fbb127a3dfd74c943a6c7f77fa5dfcb3e9ce1de66", size = 309764, upload-time = "2025-05-21T16:19:18.34Z" }, - { url = "https://files.pythonhosted.org/packages/6c/0e/9effb83e23ef5495c9078bdbac948df4fe2b202fb0ac5b33412848ab4b1e/bitarray-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1a3a08cc920f601258ea33d97b4454cd7cb04d17930e0a3bc7328ba3d732f8b0", size = 301690, upload-time = "2025-05-21T16:19:19.694Z" }, - { url = "https://files.pythonhosted.org/packages/cb/67/9a73476c8cd6a67ff5ab9c5c1d916307e4fb9178d76ee2781552451c995c/bitarray-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:60189130ae1ebaadbab27e3ad0a7d7ed44f5d9456bbfae07c72138501ce59053", size = 326049, upload-time = "2025-05-21T16:19:21.371Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b1/2a81f5f96c1ccc033d8c63b4584aedbd9e27499cf2276fc70d4f87ad673b/bitarray-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9e425eaf21a8d7b76531630029441c6d61f6064cbf4dd592af1607c79eb2e4d0", size = 329565, upload-time = "2025-05-21T16:19:22.88Z" }, - { url = "https://files.pythonhosted.org/packages/2e/30/670efe7771944b4b7d0aacdc076969adc9428c9d0939ee70230bdf4c8aed/bitarray-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:952cc40c593f663ba083be76d1ccdb6dc9dafab8fb6d949056405636b2e720f3", size = 309661, upload-time = "2025-05-21T16:19:24.574Z" }, - { url = "https://files.pythonhosted.org/packages/ee/2e/b2d8e842fe484d7d18fcd137289e396c7784b8484e0ec7e94ffe4bb7e8f9/bitarray-3.4.2-cp313-cp313-win32.whl", hash = "sha256:158f6b1a315eaf971f88e66f9b93431c3b580b46d2121c6a1166e7b761408fdf", size = 134614, upload-time = "2025-05-21T16:19:25.914Z" }, - { url = "https://files.pythonhosted.org/packages/0c/50/0ec25a51197410a66146eea7950e3597baedb000f2f2e2458bb6d5306b0a/bitarray-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:2d24658ac96a82beb4da2f5c71bef9790f3dcabadbe8ead8dda742ab207fe2f9", size = 141851, upload-time = "2025-05-21T16:19:27.388Z" }, - { url = "https://files.pythonhosted.org/packages/e7/03/77eca3d93f162c0982f370e6459d1fcb6ff51e84f80adb34c43256653bda/bitarray-3.4.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9c02f3234b1ec391aa235b265a3649e8078d814cdd6b42bc5aee267cc370b0c8", size = 135778, upload-time = "2025-05-21T16:20:58.492Z" }, - { url = "https://files.pythonhosted.org/packages/68/fd/5b148fb07e2b74e1cd17db7b940abdb1c7af6ac3a024810a5931db6e436b/bitarray-3.4.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:e19e5a35f53c0eaf4516cfa3f80de110eb831fd3d9785aa8b8f4a8a8c0d99523", size = 132826, upload-time = "2025-05-21T16:21:00.901Z" }, - { url = "https://files.pythonhosted.org/packages/e5/50/8cfb459218cd074a3af7121f6509ac55be2d6ac5a0a048b188934976f589/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f633d1e92fdc6a039b118d67f23d17b9ac4046a629bde04e178b770fe83a618f", size = 141592, upload-time = "2025-05-21T16:21:02.4Z" }, - { url = "https://files.pythonhosted.org/packages/43/c0/a70a212ecfd4256e7281456beee5330945ea09cec8fb0be3f99ed6828a08/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c08bc2ec3f15fbb3a99923ef1b16b621af45ab9d5146a06f970c0f0d7cab22ba", size = 142502, upload-time = "2025-05-21T16:21:08.366Z" }, - { url = "https://files.pythonhosted.org/packages/1e/8e/9fc84001701ef1fd7f18b0254bf08d594adaed34fe0b5770d8c032b4d53a/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eed46fa39af8440b1cff09a9805d65449583d524006efa29e5262bea9e08787e", size = 143930, upload-time = "2025-05-21T16:21:09.819Z" }, - { url = "https://files.pythonhosted.org/packages/f7/05/2f6753d75282033e66e0a9626ef4209500cd7a08aa8f92cc70fa49681cf3/bitarray-3.4.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9cf23c13c84c1559ed28bd211a6290b7326c2011f6c30c82cee052b254ac09f0", size = 140275, upload-time = "2025-05-21T16:21:11.481Z" }, -] - -[[package]] -name = "blinker" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, -] - -[[package]] -name = "cdp-sdk" -version = "1.35.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "aiohttp-retry" }, - { name = "base58" }, - { name = "cryptography" }, - { name = "nest-asyncio" }, - { name = "pydantic" }, - { name = "pyjwt" }, - { name = "python-dateutil" }, - { name = "solana" }, - { name = "solders" }, - { name = "urllib3" }, - { name = "web3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/80/a0/58ffc1630427771d4ef5dfc2052251d95c63a6f1c4aa1c8970aaca6b67bb/cdp_sdk-1.35.0.tar.gz", hash = "sha256:aa3337be7d722625540b5c3fdc36d183cc6b416c969979c80bff68f160299082", size = 327816, upload-time = "2025-12-09T01:16:05.525Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d8/90/99d6c53ff36bb6d683d406673620cf68e0a1e02c6d22ab1c7967a21f6165/cdp_sdk-1.35.0-py3-none-any.whl", hash = "sha256:bb4e1d2d59aa88ca04c099b99cf295fc3c6d1a527dff0477e9a39e024db6d3b2", size = 822924, upload-time = "2025-12-09T01:16:03.959Z" }, -] - -[[package]] -name = "certifi" -version = "2025.4.26" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, -] - -[[package]] -name = "cffi" -version = "1.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191, upload-time = "2024-09-04T20:43:30.027Z" }, - { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592, upload-time = "2024-09-04T20:43:32.108Z" }, - { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024, upload-time = "2024-09-04T20:43:34.186Z" }, - { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188, upload-time = "2024-09-04T20:43:36.286Z" }, - { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571, upload-time = "2024-09-04T20:43:38.586Z" }, - { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687, upload-time = "2024-09-04T20:43:40.084Z" }, - { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211, upload-time = "2024-09-04T20:43:41.526Z" }, - { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325, upload-time = "2024-09-04T20:43:43.117Z" }, - { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784, upload-time = "2024-09-04T20:43:45.256Z" }, - { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564, upload-time = "2024-09-04T20:43:46.779Z" }, - { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804, upload-time = "2024-09-04T20:43:48.186Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299, upload-time = "2024-09-04T20:43:49.812Z" }, - { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264, upload-time = "2024-09-04T20:43:51.124Z" }, - { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651, upload-time = "2024-09-04T20:43:52.872Z" }, - { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" }, - { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" }, - { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" }, - { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" }, - { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" }, - { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" }, - { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" }, - { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727, upload-time = "2024-09-04T20:44:09.481Z" }, - { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400, upload-time = "2024-09-04T20:44:10.873Z" }, - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, - { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, - { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, - { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, - { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, - { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, - { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, - { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9b/892a8c8af9110935e5adcbb06d9c6fe741b6bb02608c6513983048ba1a18/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd", size = 144649, upload-time = "2025-05-02T08:31:48.889Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a5/4179abd063ff6414223575e008593861d62abfc22455b5d1a44995b7c101/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6", size = 155045, upload-time = "2025-05-02T08:31:50.757Z" }, - { url = "https://files.pythonhosted.org/packages/3b/95/bc08c7dfeddd26b4be8c8287b9bb055716f31077c8b0ea1cd09553794665/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d", size = 147356, upload-time = "2025-05-02T08:31:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/7a5b635aa65284bf3eab7653e8b4151ab420ecbae918d3e359d1947b4d61/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86", size = 149471, upload-time = "2025-05-02T08:31:56.207Z" }, - { url = "https://files.pythonhosted.org/packages/ae/38/51fc6ac74251fd331a8cfdb7ec57beba8c23fd5493f1050f71c87ef77ed0/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c", size = 151317, upload-time = "2025-05-02T08:31:57.613Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/edee1e32215ee6e9e46c3e482645b46575a44a2d72c7dfd49e49f60ce6bf/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0", size = 146368, upload-time = "2025-05-02T08:31:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/26/2c/ea3e66f2b5f21fd00b2825c94cafb8c326ea6240cd80a91eb09e4a285830/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef", size = 154491, upload-time = "2025-05-02T08:32:01.219Z" }, - { url = "https://files.pythonhosted.org/packages/52/47/7be7fa972422ad062e909fd62460d45c3ef4c141805b7078dbab15904ff7/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6", size = 157695, upload-time = "2025-05-02T08:32:03.045Z" }, - { url = "https://files.pythonhosted.org/packages/2f/42/9f02c194da282b2b340f28e5fb60762de1151387a36842a92b533685c61e/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366", size = 154849, upload-time = "2025-05-02T08:32:04.651Z" }, - { url = "https://files.pythonhosted.org/packages/67/44/89cacd6628f31fb0b63201a618049be4be2a7435a31b55b5eb1c3674547a/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db", size = 150091, upload-time = "2025-05-02T08:32:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/1f/79/4b8da9f712bc079c0f16b6d67b099b0b8d808c2292c937f267d816ec5ecc/charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a", size = 98445, upload-time = "2025-05-02T08:32:08.66Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d7/96970afb4fb66497a40761cdf7bd4f6fca0fc7bafde3a84f836c1f57a926/charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509", size = 105782, upload-time = "2025-05-02T08:32:10.46Z" }, - { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" }, - { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" }, - { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" }, - { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" }, - { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" }, - { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, -] - -[[package]] -name = "ckzg" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/55/df/f6db8e83bd4594c1ea685cd37fb81d5399e55765aae16d1a8a9502598f4e/ckzg-2.1.1.tar.gz", hash = "sha256:d6b306b7ec93a24e4346aa53d07f7f75053bc0afc7398e35fa649e5f9d48fcc4", size = 1120500, upload-time = "2025-03-31T21:24:12.324Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/4b/cd25e857cdf46a752e97c530fe2582fae77c4d16c29fff5a15b7a998e2fd/ckzg-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b9825a1458219e8b4b023012b8ef027ef1f47e903f9541cbca4615f80132730", size = 116377, upload-time = "2025-03-31T21:22:26.952Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bc/5dfef36589545f797245ecacb54ed2acfa75507f63cfe12182d1277a88f1/ckzg-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2a40a3ba65cca4b52825d26829e6f7eb464aa27a9e9efb6b8b2ce183442c741", size = 100208, upload-time = "2025-03-31T21:22:28.04Z" }, - { url = "https://files.pythonhosted.org/packages/b7/52/96f0e3affbed321dc52b9b4ca13e0fb594da572d1f8edc47378fe48d8e9a/ckzg-2.1.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1d753fbe85be7c21602eddc2d40e0915e25fce10329f4f801a0002a4f886cc7", size = 174800, upload-time = "2025-03-31T21:22:29.719Z" }, - { url = "https://files.pythonhosted.org/packages/dc/21/b1bc07cc8e5ed32817e89b054e2399d38775d92ff2d55e24bf233f537c02/ckzg-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d76b50527f1d12430bf118aff6fa4051e9860eada43f29177258b8d399448ea", size = 160847, upload-time = "2025-03-31T21:22:30.973Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5a/97b173d4ff9bce798031beb12b340c4f1729eaaddd07f69f368f843db28e/ckzg-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44c8603e43c021d100f355f50189183135d1df3cbbddb8881552d57fbf421dde", size = 169712, upload-time = "2025-03-31T21:22:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/7b/52/48be78c07f362438e189e2fbea7df8543290c3ee99845442549c8dc5405b/ckzg-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:38707a638c9d715b3c30b29352b969f78d8fc10faed7db5faf517f04359895c0", size = 172942, upload-time = "2025-03-31T21:22:32.8Z" }, - { url = "https://files.pythonhosted.org/packages/13/42/3cfcd6cbdfb9030b9071d5e413a458f93883e47ad4a7d8d4c1d57608e57d/ckzg-2.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:52c4d257bdcbe822d20c5cd24c8154ec5aac33c49a8f5a19e716d9107a1c8785", size = 187707, upload-time = "2025-03-31T21:22:33.673Z" }, - { url = "https://files.pythonhosted.org/packages/eb/54/d43bc3a2de486fb8be29ffedc3ec80f5726765ee4fa78beabe2ab2440f93/ckzg-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1507f7bfb9bcf51d816db5d8d0f0ed53c8289605137820d437b69daea8333e16", size = 182505, upload-time = "2025-03-31T21:22:34.563Z" }, - { url = "https://files.pythonhosted.org/packages/21/43/5bcd2b7630732b532006572fbb8d64a29f69530c630ae4811167a2a0dc3b/ckzg-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d02eaaf4f841910133552b3a051dea53bcfe60cd98199fc4cf80b27609d8baa2", size = 98822, upload-time = "2025-03-31T21:22:35.786Z" }, - { url = "https://files.pythonhosted.org/packages/95/2c/44120b2d9dcb0246d67a1f28b9eaa625c499014d4d42561467e28eedd285/ckzg-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:465e2b71cf9dc383f66f1979269420a0da9274a3a9e98b1a4455e84927dfe491", size = 116378, upload-time = "2025-03-31T21:22:36.96Z" }, - { url = "https://files.pythonhosted.org/packages/23/88/c5b89ba9a730fee5e089be9e0c7048fb6707c1a0e4b6c30fcf725c3eef44/ckzg-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ee2f26f17a64ad0aab833d637b276f28486b82a29e34f32cf54b237b8f8ab72d", size = 100202, upload-time = "2025-03-31T21:22:37.799Z" }, - { url = "https://files.pythonhosted.org/packages/ee/11/b0a473e80346db52ad9a629bc9fd8f773c718ed78932ea3a70392306ffc3/ckzg-2.1.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99cc2c4e9fb8c62e3e0862c7f4df9142f07ba640da17fded5f6e0fd09f75909f", size = 175595, upload-time = "2025-03-31T21:22:39.013Z" }, - { url = "https://files.pythonhosted.org/packages/52/fa/17a7e125d07a96dd6dce4db7262231f7583856b2be5d5b7df59e04bfa188/ckzg-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773dd016693d74aca1f5d7982db2bad7dde2e147563aeb16a783f7e5f69c01fe", size = 161681, upload-time = "2025-03-31T21:22:40.257Z" }, - { url = "https://files.pythonhosted.org/packages/57/bd/46d6b90bf53da732f9adab7593d132a0834ed4f2f7659b4c7414d8f78d39/ckzg-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af2b2144f87ba218d8db01382a961b3ecbdde5ede4fa0d9428d35f8c8a595ba", size = 170471, upload-time = "2025-03-31T21:22:41.513Z" }, - { url = "https://files.pythonhosted.org/packages/9d/98/113c7704749d037d75f23240ffc5c46dfe8416de574b946438587835715f/ckzg-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f55e63d3f7c934a2cb53728ed1d815479e177aca8c84efe991c2920977cff6", size = 173595, upload-time = "2025-03-31T21:22:42.534Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d5/05fca6dcb5a19327be491157794eafc3d7498daf615c2ff5a5b745852945/ckzg-2.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ecb42aaa0ffa427ff14a9dde9356ba69e5ae6014650b397af55b31bdae7a9b6e", size = 188417, upload-time = "2025-03-31T21:22:43.466Z" }, - { url = "https://files.pythonhosted.org/packages/72/36/131ae2dfc82d0fdc98fae8e3bbfe71ff14265bb434b23bd07b585afc6d61/ckzg-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5a01514239f12fb1a7ad9009c20062a4496e13b09541c1a65f97e295da648c70", size = 183286, upload-time = "2025-03-31T21:22:44.732Z" }, - { url = "https://files.pythonhosted.org/packages/c5/6a/d371b27024422b25228fc11fa57b1ba7756a94cc9fb0c75da292c235fdaa/ckzg-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:6516b9684aae262c85cf7fddd8b585b8139ad20e08ec03994e219663abbb0916", size = 98819, upload-time = "2025-03-31T21:22:45.57Z" }, - { url = "https://files.pythonhosted.org/packages/93/a1/9c07513dd0ea01e5db727e67bd2660f3b300a4511281cdb8d5e04afa1cfd/ckzg-2.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c60e8903344ce98ce036f0fabacce952abb714cad4607198b2f0961c28b8aa72", size = 116421, upload-time = "2025-03-31T21:22:46.434Z" }, - { url = "https://files.pythonhosted.org/packages/27/04/b69a0dfbb2722a14c98a52973f276679151ec56a14178cb48e6f2e1697bc/ckzg-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4299149dd72448e5a8d2d1cc6cc7472c92fc9d9f00b1377f5b017c089d9cd92", size = 100216, upload-time = "2025-03-31T21:22:47.633Z" }, - { url = "https://files.pythonhosted.org/packages/2e/24/9cc850d0b8ead395ad5064de67c7c91adacaf31b6b35292ab53fbd93270b/ckzg-2.1.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:025dd31ffdcc799f3ff842570a2a6683b6c5b01567da0109c0c05d11768729c4", size = 175764, upload-time = "2025-03-31T21:22:48.768Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c1/eb13ba399082a98b932f10b230ec08e6456051c0ce3886b3f6d8548d11ab/ckzg-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b42ab8385c273f40a693657c09d2bba40cb4f4666141e263906ba2e519e80bd", size = 161885, upload-time = "2025-03-31T21:22:50.05Z" }, - { url = "https://files.pythonhosted.org/packages/57/c7/58baa64199781950c5a8c6139a46e1acff0f057a36e56769817400eb87fb/ckzg-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be3890fc1543f4fcfc0063e4baf5c036eb14bcf736dabdc6171ab017e0f1671", size = 170757, upload-time = "2025-03-31T21:22:51.282Z" }, - { url = "https://files.pythonhosted.org/packages/65/bd/4b8e1c70972c98829371b7004dc750a45268c5d3442d602e1b62f13ca867/ckzg-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b754210ded172968b201e2d7252573af6bf52d6ad127ddd13d0b9a45a51dae7b", size = 173761, upload-time = "2025-03-31T21:22:52.6Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/c3fd1002f97ba3e0c5b1d9ab2c8fb7a6f475fa9b80ed9c4fa55975501a54/ckzg-2.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2f8fda87865897a269c4e951e3826c2e814427a6cdfed6731cccfe548f12b36", size = 188666, upload-time = "2025-03-31T21:22:53.47Z" }, - { url = "https://files.pythonhosted.org/packages/e2/d9/91cf5a8169ee60c9397c975163cbca34432571f94facec5f8c0086bb47d8/ckzg-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:98e70b5923d77c7359432490145e9d1ab0bf873eb5de56ec53f4a551d7eaec79", size = 183652, upload-time = "2025-03-31T21:22:54.351Z" }, - { url = "https://files.pythonhosted.org/packages/25/d4/8c9f6b852f99926862344b29f0c59681916ccfec2ac60a85952a369e0bca/ckzg-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:42af7bde4ca45469cd93a96c3d15d69d51d40e7f0d30e3a20711ebd639465fcb", size = 98816, upload-time = "2025-03-31T21:22:55.23Z" }, - { url = "https://files.pythonhosted.org/packages/b7/9a/fa698b12e97452d11dd314e0335aae759725284ef6e1c1665aed56b1cd3e/ckzg-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e4edfdaf87825ff43b9885fabfdea408737a714f4ce5467100d9d1d0a03b673", size = 116426, upload-time = "2025-03-31T21:22:56.108Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/8cccd308bd11b49b40eecad6900b5769da117951cac33e880dd25e851ef7/ckzg-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:815fd2a87d6d6c57d669fda30c150bc9bf387d47e67d84535aa42b909fdc28ea", size = 100219, upload-time = "2025-03-31T21:22:56.982Z" }, - { url = "https://files.pythonhosted.org/packages/30/0e/63573d816c1292b9a4d70eb6a7366b3593d29a977794039e926805a76ca0/ckzg-2.1.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32466e809b1ab3ff01d3b0bb0b9912f61dcf72957885615595f75e3f7cc10e5", size = 175725, upload-time = "2025-03-31T21:22:58.213Z" }, - { url = "https://files.pythonhosted.org/packages/86/f6/a279609516695ad3fb8b201098c669ba3b2844cbf4fa0d83a0f02b9bb29b/ckzg-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f11b73ccf37b12993f39a7dbace159c6d580aacacde6ee17282848476550ddbc", size = 161835, upload-time = "2025-03-31T21:22:59.448Z" }, - { url = "https://files.pythonhosted.org/packages/39/e4/8cf7aef7dc05a777cb221e94046f947c6fe5317159a8dae2cd7090d52ef2/ckzg-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3b9433a1f2604bd9ac1646d3c83ad84a850d454d3ac589fe8e70c94b38a6b0", size = 170759, upload-time = "2025-03-31T21:23:01.022Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/b34e3c08eb36bc67e338b114f289b2595e581b8bdc09a8f12299a1db5d2f/ckzg-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b7d7e1b5ea06234558cd95c483666fd785a629b720a7f1622b3cbffebdc62033", size = 173787, upload-time = "2025-03-31T21:23:01.974Z" }, - { url = "https://files.pythonhosted.org/packages/2e/f0/aff87c3ed80713453cb6c84fe6fbb7582d86a7a5e4460fda2a497d47f489/ckzg-2.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9f5556e6675866040cc4335907be6c537051e7f668da289fa660fdd8a30c9ddb", size = 188722, upload-time = "2025-03-31T21:23:02.966Z" }, - { url = "https://files.pythonhosted.org/packages/44/d9/1f08bfb8fd1cbb8c7513e7ad3fb76bbb5c3fb446238c1eba582276e4d905/ckzg-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55b2ba30c5c9daac0c55f1aac851f1b7bf1f7aa0028c2db4440e963dd5b866d6", size = 183686, upload-time = "2025-03-31T21:23:03.905Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ff/434f6d2893cbdfad00c20d17e9a52d426ca042f5e980d5c3db96bc6b6e15/ckzg-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:10d201601fc8f28c0e8cec3406676797024dd374c367bbeec5a7a9eac9147237", size = 98817, upload-time = "2025-03-31T21:23:05.2Z" }, - { url = "https://files.pythonhosted.org/packages/30/b3/a0c7d7ba6e669cf04605dc0329173db62fc1fe3c488761755cc01e5e1b4d/ckzg-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:375918e25eafb9bafe5215ab91698504cba3fe51b4fe92f5896af6c5663f50c6", size = 113191, upload-time = "2025-03-31T21:23:40.646Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b9/a6cf403b8528d18d7d9154e28381a397bf466c86aa8e0b3327cffdde5749/ckzg-2.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:38b3b7802c76d4ad015db2b7a79a49c193babae50ee5f77e9ac2865c9e9ddb09", size = 96207, upload-time = "2025-03-31T21:23:41.596Z" }, - { url = "https://files.pythonhosted.org/packages/63/6b/5ddd713d97886becb8450e3e13db891199125f722366d30d087ad5438390/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438a5009fd254ace0bc1ad974d524547f1a41e6aa5e778c5cd41f4ee3106bcd6", size = 126160, upload-time = "2025-03-31T21:23:42.553Z" }, - { url = "https://files.pythonhosted.org/packages/c7/dd/e05aecc01e62108a7579f8df5e5d38536841f50e12172f8a84677edac0fa/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce11cc163a2e0dab3af7455aca7053f9d5bb8d157f231acc7665fd230565d48", size = 102811, upload-time = "2025-03-31T21:23:43.494Z" }, - { url = "https://files.pythonhosted.org/packages/c6/81/6cdadd8626ac11290af3f58ae5dcffe38bd2c8f8c798dacee7475e244aac/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b53964c07f6a076e97eaa1ef35045e935d7040aff14f80bae7e9105717702d05", size = 111328, upload-time = "2025-03-31T21:23:44.449Z" }, - { url = "https://files.pythonhosted.org/packages/36/b7/b129ff6955cd264c6ab3dbd52dd1b2759d1b121c09c03f9991e4c722c72f/ckzg-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cf085f15ae52ab2599c9b5a3d5842794bcf5613b7f58661fbfb0c5d9eac988b9", size = 98846, upload-time = "2025-03-31T21:23:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ba/7d9c1f9cec7e0e382653c72165896194a05743e589b1dae2aa80236aa87f/ckzg-2.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4b0c850bd6cad22ac79b2a2ab884e0e7cd2b54a67d643cd616c145ebdb535a11", size = 113188, upload-time = "2025-03-31T21:23:46.337Z" }, - { url = "https://files.pythonhosted.org/packages/2f/92/9728f5ccc1c5e87c6c5ae7941250a447b61fd5a63aadbc15249e29c21bcf/ckzg-2.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:26951f36bb60c9150bbd38110f5e1625596f9779dad54d1d492d8ec38bc84e3a", size = 96208, upload-time = "2025-03-31T21:23:47.255Z" }, - { url = "https://files.pythonhosted.org/packages/39/63/5e27d587bd224fee70cb66b022e7c4ef95d0e091e08ee76c25ec12094b0d/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbe12445e49c4bee67746b7b958e90a973b0de116d0390749b0df351d94e9a8c", size = 126158, upload-time = "2025-03-31T21:23:48.195Z" }, - { url = "https://files.pythonhosted.org/packages/43/98/e0a45946575a7b823d8ee0b47afb104b6017e54e1208f07da2529bc01900/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c5d4f66f09de4a99271acac74d2acb3559a77de77a366b34a91e99e8822667", size = 102812, upload-time = "2025-03-31T21:23:49.16Z" }, - { url = "https://files.pythonhosted.org/packages/cb/50/718ca7b03e4b89b18cdf99cc3038050105b0acbf9b612c23cd513093c6de/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42673c1d007372a4e8b48f6ef8f0ce31a9688a463317a98539757d1e2fb1ecc7", size = 111327, upload-time = "2025-03-31T21:23:50.126Z" }, - { url = "https://files.pythonhosted.org/packages/29/c5/80e5a0c6967d02d801150104320484a258e5a49bd191e198643e74039320/ckzg-2.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:57a7dc41ec6b69c1d9117eb61cf001295e6b4f67a736020442e71fb4367fb1a5", size = 98847, upload-time = "2025-03-31T21:23:51.084Z" }, -] - -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - -[[package]] -name = "client-discovery-example" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "cdp-sdk" }, - { name = "flask" }, - { name = "uvicorn" }, - { name = "x402" }, -] - -[package.metadata] -requires-dist = [ - { name = "cdp-sdk", specifier = ">=1.31.2" }, - { name = "flask", specifier = ">=3.1.1" }, - { name = "uvicorn", specifier = ">=0.27.0" }, - { name = "x402", editable = "../../../../python/legacy" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "construct" -version = "2.10.68" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/a4a032e94bcfdff481f2e6fecd472794d9da09f474a2185ed33b2c7cad64/construct-2.10.68.tar.gz", hash = "sha256:7b2a3fd8e5f597a5aa1d614c3bd516fa065db01704c72a1efaaeec6ef23d8b45", size = 57856, upload-time = "2022-02-21T23:09:15.1Z" } - -[[package]] -name = "construct-typing" -version = "0.6.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "construct" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f1/13/c609e60a687252813aa4b69f989f42754ccd5e217717216fc852eefedfd7/construct-typing-0.6.2.tar.gz", hash = "sha256:948e998cfc003681dc34f2d071c3a688cf35b805cbe107febbc488ef967ccba1", size = 22029, upload-time = "2023-08-03T07:31:06.205Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/0b/ab3ce2b27dd74b6a6703065bd304ea8211ff4de3b1c304446ed95234177b/construct_typing-0.6.2-py3-none-any.whl", hash = "sha256:ebea6989ac622d0c4eb457092cef0c7bfbcfa110bd018670fea7064d0bc09e47", size = 23298, upload-time = "2023-08-03T07:31:04.545Z" }, -] - -[[package]] -name = "cryptography" -version = "45.0.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d6/0d/d13399c94234ee8f3df384819dc67e0c5ce215fb751d567a55a1f4b028c7/cryptography-45.0.6.tar.gz", hash = "sha256:5c966c732cf6e4a276ce83b6e4c729edda2df6929083a952cc7da973c539c719", size = 744949, upload-time = "2025-08-05T23:59:27.93Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8c/29/2793d178d0eda1ca4a09a7c4e09a5185e75738cc6d526433e8663b460ea6/cryptography-45.0.6-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:048e7ad9e08cf4c0ab07ff7f36cc3115924e22e2266e034450a890d9e312dd74", size = 7042702, upload-time = "2025-08-05T23:58:23.464Z" }, - { url = "https://files.pythonhosted.org/packages/b3/b6/cabd07410f222f32c8d55486c464f432808abaa1f12af9afcbe8f2f19030/cryptography-45.0.6-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:44647c5d796f5fc042bbc6d61307d04bf29bccb74d188f18051b635f20a9c75f", size = 4206483, upload-time = "2025-08-05T23:58:27.132Z" }, - { url = "https://files.pythonhosted.org/packages/8b/9e/f9c7d36a38b1cfeb1cc74849aabe9bf817990f7603ff6eb485e0d70e0b27/cryptography-45.0.6-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e40b80ecf35ec265c452eea0ba94c9587ca763e739b8e559c128d23bff7ebbbf", size = 4429679, upload-time = "2025-08-05T23:58:29.152Z" }, - { url = "https://files.pythonhosted.org/packages/9c/2a/4434c17eb32ef30b254b9e8b9830cee4e516f08b47fdd291c5b1255b8101/cryptography-45.0.6-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:00e8724bdad672d75e6f069b27970883179bd472cd24a63f6e620ca7e41cc0c5", size = 4210553, upload-time = "2025-08-05T23:58:30.596Z" }, - { url = "https://files.pythonhosted.org/packages/ef/1d/09a5df8e0c4b7970f5d1f3aff1b640df6d4be28a64cae970d56c6cf1c772/cryptography-45.0.6-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:7a3085d1b319d35296176af31c90338eeb2ddac8104661df79f80e1d9787b8b2", size = 3894499, upload-time = "2025-08-05T23:58:32.03Z" }, - { url = "https://files.pythonhosted.org/packages/79/62/120842ab20d9150a9d3a6bdc07fe2870384e82f5266d41c53b08a3a96b34/cryptography-45.0.6-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:1b7fa6a1c1188c7ee32e47590d16a5a0646270921f8020efc9a511648e1b2e08", size = 4458484, upload-time = "2025-08-05T23:58:33.526Z" }, - { url = "https://files.pythonhosted.org/packages/fd/80/1bc3634d45ddfed0871bfba52cf8f1ad724761662a0c792b97a951fb1b30/cryptography-45.0.6-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:275ba5cc0d9e320cd70f8e7b96d9e59903c815ca579ab96c1e37278d231fc402", size = 4210281, upload-time = "2025-08-05T23:58:35.445Z" }, - { url = "https://files.pythonhosted.org/packages/7d/fe/ffb12c2d83d0ee625f124880a1f023b5878f79da92e64c37962bbbe35f3f/cryptography-45.0.6-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:f4028f29a9f38a2025abedb2e409973709c660d44319c61762202206ed577c42", size = 4456890, upload-time = "2025-08-05T23:58:36.923Z" }, - { url = "https://files.pythonhosted.org/packages/8c/8e/b3f3fe0dc82c77a0deb5f493b23311e09193f2268b77196ec0f7a36e3f3e/cryptography-45.0.6-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:ee411a1b977f40bd075392c80c10b58025ee5c6b47a822a33c1198598a7a5f05", size = 4333247, upload-time = "2025-08-05T23:58:38.781Z" }, - { url = "https://files.pythonhosted.org/packages/b3/a6/c3ef2ab9e334da27a1d7b56af4a2417d77e7806b2e0f90d6267ce120d2e4/cryptography-45.0.6-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:e2a21a8eda2d86bb604934b6b37691585bd095c1f788530c1fcefc53a82b3453", size = 4565045, upload-time = "2025-08-05T23:58:40.415Z" }, - { url = "https://files.pythonhosted.org/packages/31/c3/77722446b13fa71dddd820a5faab4ce6db49e7e0bf8312ef4192a3f78e2f/cryptography-45.0.6-cp311-abi3-win32.whl", hash = "sha256:d063341378d7ee9c91f9d23b431a3502fc8bfacd54ef0a27baa72a0843b29159", size = 2928923, upload-time = "2025-08-05T23:58:41.919Z" }, - { url = "https://files.pythonhosted.org/packages/38/63/a025c3225188a811b82932a4dcc8457a26c3729d81578ccecbcce2cb784e/cryptography-45.0.6-cp311-abi3-win_amd64.whl", hash = "sha256:833dc32dfc1e39b7376a87b9a6a4288a10aae234631268486558920029b086ec", size = 3403805, upload-time = "2025-08-05T23:58:43.792Z" }, - { url = "https://files.pythonhosted.org/packages/5b/af/bcfbea93a30809f126d51c074ee0fac5bd9d57d068edf56c2a73abedbea4/cryptography-45.0.6-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:3436128a60a5e5490603ab2adbabc8763613f638513ffa7d311c900a8349a2a0", size = 7020111, upload-time = "2025-08-05T23:58:45.316Z" }, - { url = "https://files.pythonhosted.org/packages/98/c6/ea5173689e014f1a8470899cd5beeb358e22bb3cf5a876060f9d1ca78af4/cryptography-45.0.6-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:0d9ef57b6768d9fa58e92f4947cea96ade1233c0e236db22ba44748ffedca394", size = 4198169, upload-time = "2025-08-05T23:58:47.121Z" }, - { url = "https://files.pythonhosted.org/packages/ba/73/b12995edc0c7e2311ffb57ebd3b351f6b268fed37d93bfc6f9856e01c473/cryptography-45.0.6-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:ea3c42f2016a5bbf71825537c2ad753f2870191134933196bee408aac397b3d9", size = 4421273, upload-time = "2025-08-05T23:58:48.557Z" }, - { url = "https://files.pythonhosted.org/packages/f7/6e/286894f6f71926bc0da67408c853dd9ba953f662dcb70993a59fd499f111/cryptography-45.0.6-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:20ae4906a13716139d6d762ceb3e0e7e110f7955f3bc3876e3a07f5daadec5f3", size = 4199211, upload-time = "2025-08-05T23:58:50.139Z" }, - { url = "https://files.pythonhosted.org/packages/de/34/a7f55e39b9623c5cb571d77a6a90387fe557908ffc44f6872f26ca8ae270/cryptography-45.0.6-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:2dac5ec199038b8e131365e2324c03d20e97fe214af051d20c49db129844e8b3", size = 3883732, upload-time = "2025-08-05T23:58:52.253Z" }, - { url = "https://files.pythonhosted.org/packages/f9/b9/c6d32edbcba0cd9f5df90f29ed46a65c4631c4fbe11187feb9169c6ff506/cryptography-45.0.6-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:18f878a34b90d688982e43f4b700408b478102dd58b3e39de21b5ebf6509c301", size = 4450655, upload-time = "2025-08-05T23:58:53.848Z" }, - { url = "https://files.pythonhosted.org/packages/77/2d/09b097adfdee0227cfd4c699b3375a842080f065bab9014248933497c3f9/cryptography-45.0.6-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:5bd6020c80c5b2b2242d6c48487d7b85700f5e0038e67b29d706f98440d66eb5", size = 4198956, upload-time = "2025-08-05T23:58:55.209Z" }, - { url = "https://files.pythonhosted.org/packages/55/66/061ec6689207d54effdff535bbdf85cc380d32dd5377173085812565cf38/cryptography-45.0.6-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:eccddbd986e43014263eda489abbddfbc287af5cddfd690477993dbb31e31016", size = 4449859, upload-time = "2025-08-05T23:58:56.639Z" }, - { url = "https://files.pythonhosted.org/packages/41/ff/e7d5a2ad2d035e5a2af116e1a3adb4d8fcd0be92a18032917a089c6e5028/cryptography-45.0.6-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:550ae02148206beb722cfe4ef0933f9352bab26b087af00e48fdfb9ade35c5b3", size = 4320254, upload-time = "2025-08-05T23:58:58.833Z" }, - { url = "https://files.pythonhosted.org/packages/82/27/092d311af22095d288f4db89fcaebadfb2f28944f3d790a4cf51fe5ddaeb/cryptography-45.0.6-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5b64e668fc3528e77efa51ca70fadcd6610e8ab231e3e06ae2bab3b31c2b8ed9", size = 4554815, upload-time = "2025-08-05T23:59:00.283Z" }, - { url = "https://files.pythonhosted.org/packages/7e/01/aa2f4940262d588a8fdf4edabe4cda45854d00ebc6eaac12568b3a491a16/cryptography-45.0.6-cp37-abi3-win32.whl", hash = "sha256:780c40fb751c7d2b0c6786ceee6b6f871e86e8718a8ff4bc35073ac353c7cd02", size = 2912147, upload-time = "2025-08-05T23:59:01.716Z" }, - { url = "https://files.pythonhosted.org/packages/0a/bc/16e0276078c2de3ceef6b5a34b965f4436215efac45313df90d55f0ba2d2/cryptography-45.0.6-cp37-abi3-win_amd64.whl", hash = "sha256:20d15aed3ee522faac1a39fbfdfee25d17b1284bafd808e1640a74846d7c4d1b", size = 3390459, upload-time = "2025-08-05T23:59:03.358Z" }, - { url = "https://files.pythonhosted.org/packages/56/d2/4482d97c948c029be08cb29854a91bd2ae8da7eb9c4152461f1244dcea70/cryptography-45.0.6-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:705bb7c7ecc3d79a50f236adda12ca331c8e7ecfbea51edd931ce5a7a7c4f012", size = 3576812, upload-time = "2025-08-05T23:59:04.833Z" }, - { url = "https://files.pythonhosted.org/packages/ec/24/55fc238fcaa122855442604b8badb2d442367dfbd5a7ca4bb0bd346e263a/cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:826b46dae41a1155a0c0e66fafba43d0ede1dc16570b95e40c4d83bfcf0a451d", size = 4141694, upload-time = "2025-08-05T23:59:06.66Z" }, - { url = "https://files.pythonhosted.org/packages/f9/7e/3ea4fa6fbe51baf3903806a0241c666b04c73d2358a3ecce09ebee8b9622/cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:cc4d66f5dc4dc37b89cfef1bd5044387f7a1f6f0abb490815628501909332d5d", size = 4375010, upload-time = "2025-08-05T23:59:08.14Z" }, - { url = "https://files.pythonhosted.org/packages/50/42/ec5a892d82d2a2c29f80fc19ced4ba669bca29f032faf6989609cff1f8dc/cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:f68f833a9d445cc49f01097d95c83a850795921b3f7cc6488731e69bde3288da", size = 4141377, upload-time = "2025-08-05T23:59:09.584Z" }, - { url = "https://files.pythonhosted.org/packages/e7/d7/246c4c973a22b9c2931999da953a2c19cae7c66b9154c2d62ffed811225e/cryptography-45.0.6-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:3b5bf5267e98661b9b888a9250d05b063220dfa917a8203744454573c7eb79db", size = 4374609, upload-time = "2025-08-05T23:59:11.923Z" }, - { url = "https://files.pythonhosted.org/packages/78/6d/c49ccf243f0a1b0781c2a8de8123ee552f0c8a417c6367a24d2ecb7c11b3/cryptography-45.0.6-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:2384f2ab18d9be88a6e4f8972923405e2dbb8d3e16c6b43f15ca491d7831bd18", size = 3322156, upload-time = "2025-08-05T23:59:13.597Z" }, - { url = "https://files.pythonhosted.org/packages/61/69/c252de4ec047ba2f567ecb53149410219577d408c2aea9c989acae7eafce/cryptography-45.0.6-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fc022c1fa5acff6def2fc6d7819bbbd31ccddfe67d075331a65d9cfb28a20983", size = 3584669, upload-time = "2025-08-05T23:59:15.431Z" }, - { url = "https://files.pythonhosted.org/packages/e3/fe/deea71e9f310a31fe0a6bfee670955152128d309ea2d1c79e2a5ae0f0401/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:3de77e4df42ac8d4e4d6cdb342d989803ad37707cf8f3fbf7b088c9cbdd46427", size = 4153022, upload-time = "2025-08-05T23:59:16.954Z" }, - { url = "https://files.pythonhosted.org/packages/60/45/a77452f5e49cb580feedba6606d66ae7b82c128947aa754533b3d1bd44b0/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:599c8d7df950aa68baa7e98f7b73f4f414c9f02d0e8104a30c0182a07732638b", size = 4386802, upload-time = "2025-08-05T23:59:18.55Z" }, - { url = "https://files.pythonhosted.org/packages/a3/b9/a2f747d2acd5e3075fdf5c145c7c3568895daaa38b3b0c960ef830db6cdc/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:31a2b9a10530a1cb04ffd6aa1cd4d3be9ed49f7d77a4dafe198f3b382f41545c", size = 4152706, upload-time = "2025-08-05T23:59:20.044Z" }, - { url = "https://files.pythonhosted.org/packages/81/ec/381b3e8d0685a3f3f304a382aa3dfce36af2d76467da0fd4bb21ddccc7b2/cryptography-45.0.6-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:e5b3dda1b00fb41da3af4c5ef3f922a200e33ee5ba0f0bc9ecf0b0c173958385", size = 4386740, upload-time = "2025-08-05T23:59:21.525Z" }, - { url = "https://files.pythonhosted.org/packages/0a/76/cf8d69da8d0b5ecb0db406f24a63a3f69ba5e791a11b782aeeefef27ccbb/cryptography-45.0.6-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:629127cfdcdc6806dfe234734d7cb8ac54edaf572148274fa377a7d3405b0043", size = 3331874, upload-time = "2025-08-05T23:59:23.017Z" }, -] - -[[package]] -name = "cytoolz" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "toolz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/f9/3243eed3a6545c2a33a21f74f655e3fcb5d2192613cd3db81a93369eb339/cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6", size = 626652, upload-time = "2024-12-13T05:47:36.672Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d9/f13d66c16cff1fa1cb6c234698029877c456f35f577ef274aba3b86e7c51/cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042", size = 403515, upload-time = "2024-12-13T05:44:27.845Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2d/4cdf848a69300c7d44984f2ebbebb3b8576e5449c8dea157298f3bdc4da3/cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608", size = 383936, upload-time = "2024-12-13T05:44:29.5Z" }, - { url = "https://files.pythonhosted.org/packages/72/a4/ccfdd3f0ed9cc818f734b424261f6018fc61e3ec833bf85225a9aca0d994/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90124bdc42ff58b88cdea1d24a6bc5f776414a314cc4d94f25c88badb3a16d1", size = 1934569, upload-time = "2024-12-13T05:44:30.799Z" }, - { url = "https://files.pythonhosted.org/packages/50/fc/38d5344fa595683ad10dc819cfc1d8b9d2b3391ccf3e8cb7bab4899a01f5/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e74801b751e28f7c5cc3ad264c123954a051f546f2fdfe089f5aa7a12ccfa6da", size = 2015129, upload-time = "2024-12-13T05:44:32.297Z" }, - { url = "https://files.pythonhosted.org/packages/28/29/75261748dc54a20a927f33641f4e9aac674cfc6d3fbd4f332e10d0b37639/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582dad4545ddfb5127494ef23f3fa4855f1673a35d50c66f7638e9fb49805089", size = 2000506, upload-time = "2024-12-13T05:44:34.403Z" }, - { url = "https://files.pythonhosted.org/packages/00/ae/e4ead004cc2698281d153c4a5388638d67cdb5544d6d6cc1e5b3db2bd2a3/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7bd0618e16efe03bd12f19c2a26a27e6e6b75d7105adb7be1cd2a53fa755d8", size = 1957537, upload-time = "2024-12-13T05:44:39.499Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ff/4f3aa07f4f47701f7f63df60ce0a5669fa09c256c3d4a33503a9414ea5cc/cytoolz-1.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d74cca6acf1c4af58b2e4a89cc565ed61c5e201de2e434748c93e5a0f5c541a5", size = 1863331, upload-time = "2024-12-13T05:44:42.61Z" }, - { url = "https://files.pythonhosted.org/packages/a2/29/654f57f2a9b8e9765a4ab876765f64f94530b61fc6471a07feea42ece6d4/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:823a3763828d8d457f542b2a45d75d6b4ced5e470b5c7cf2ed66a02f508ed442", size = 1849938, upload-time = "2024-12-13T05:44:45.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/7b/11f457db6b291060a98315ab2c7198077d8bddeeebe5f7126d9dad98cc54/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:51633a14e6844c61db1d68c1ffd077cf949f5c99c60ed5f1e265b9e2966f1b52", size = 1852345, upload-time = "2024-12-13T05:44:47.994Z" }, - { url = "https://files.pythonhosted.org/packages/6b/92/0dccc96ce0323be236d404f5084479b79b747fa0e74e43a270e95868b5f9/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3ec9b01c45348f1d0d712507d54c2bfd69c62fbd7c9ef555c9d8298693c2432", size = 1989877, upload-time = "2024-12-13T05:44:51.514Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c8/1c5203a81200bae51aa8f7b5fad613f695bf1afa03f16251ca23ecb2ef9f/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1855022b712a9c7a5bce354517ab4727a38095f81e2d23d3eabaf1daeb6a3b3c", size = 1994492, upload-time = "2024-12-13T05:44:52.922Z" }, - { url = "https://files.pythonhosted.org/packages/e2/8a/04bc193c4d7ced8ef6bb62cdcd0bf40b5e5eb26586ed2cfb4433ec7dfd0a/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9930f7288c4866a1dc1cc87174f0c6ff4cad1671eb1f6306808aa6c445857d78", size = 1896077, upload-time = "2024-12-13T05:44:56.118Z" }, - { url = "https://files.pythonhosted.org/packages/21/a5/bee63a58f51d2c74856db66e6119a014464ff8cb1c9387fa4bd2d94e49b0/cytoolz-1.0.1-cp310-cp310-win32.whl", hash = "sha256:a9baad795d72fadc3445ccd0f122abfdbdf94269157e6d6d4835636dad318804", size = 322135, upload-time = "2024-12-13T05:44:57.695Z" }, - { url = "https://files.pythonhosted.org/packages/e8/16/7abfb1685e8b7f2838264551ee33651748994813f566ac4c3d737dfe90e5/cytoolz-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad95b386a84e18e1f6136f6d343d2509d4c3aae9f5a536f3dc96808fcc56a8cf", size = 363599, upload-time = "2024-12-13T05:44:58.875Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ea/8131ae39119820b8867cddc23716fa9f681f2b3bbce6f693e68dfb36b55b/cytoolz-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d958d4f04d9d7018e5c1850790d9d8e68b31c9a2deebca74b903706fdddd2b6", size = 406162, upload-time = "2024-12-13T05:45:01.196Z" }, - { url = "https://files.pythonhosted.org/packages/26/18/3d9bd4c146f6ea6e51300c242b20cb416966b21d481dac230e1304f1e54b/cytoolz-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0f445b8b731fc0ecb1865b8e68a070084eb95d735d04f5b6c851db2daf3048ab", size = 384961, upload-time = "2024-12-13T05:45:02.387Z" }, - { url = "https://files.pythonhosted.org/packages/e4/73/9034827907c7f85c7c484c9494e905d022fb8174526004e9ef332570349e/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f546a96460a7e28eb2ec439f4664fa646c9b3e51c6ebad9a59d3922bbe65e30", size = 2091698, upload-time = "2024-12-13T05:45:04.353Z" }, - { url = "https://files.pythonhosted.org/packages/74/af/d5c2733b0fde1a08254ff1a8a8d567874040c9eb1606363cfebc0713c73f/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0317681dd065532d21836f860b0563b199ee716f55d0c1f10de3ce7100c78a3b", size = 2188452, upload-time = "2024-12-13T05:45:05.748Z" }, - { url = "https://files.pythonhosted.org/packages/6a/bb/77c71fa9c217260b4056a732d754748903423c2cdd82a673d6064741e375/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0ef52febd5a7821a3fd8d10f21d460d1a3d2992f724ba9c91fbd7a96745d41", size = 2174203, upload-time = "2024-12-13T05:45:07.777Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a9/a5b4a3ff5d22faa1b60293bfe97362e2caf4a830c26d37ab5557f60d04b2/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebaf419acf2de73b643cf96108702b8aef8e825cf4f63209ceb078d5fbbbfd", size = 2099831, upload-time = "2024-12-13T05:45:11.477Z" }, - { url = "https://files.pythonhosted.org/packages/35/08/7f6869ea1ff31ce5289a7d58d0e7090acfe7058baa2764473048ff61ea3c/cytoolz-1.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f7f04eeb4088947585c92d6185a618b25ad4a0f8f66ea30c8db83cf94a425e3", size = 1996744, upload-time = "2024-12-13T05:45:14.172Z" }, - { url = "https://files.pythonhosted.org/packages/46/b4/9ac424c994b51763fd1bbed62d95f8fba8fa0e45c8c3c583904fdaf8f51d/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f61928803bb501c17914b82d457c6f50fe838b173fb40d39c38d5961185bd6c7", size = 2013733, upload-time = "2024-12-13T05:45:16.912Z" }, - { url = "https://files.pythonhosted.org/packages/3e/99/03009765c4b87d742d5b5a8670abb56a8c7ede033c2cdaa4be8662d3b001/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d2960cb4fa01ccb985ad1280db41f90dc97a80b397af970a15d5a5de403c8c61", size = 1994850, upload-time = "2024-12-13T05:45:18.414Z" }, - { url = "https://files.pythonhosted.org/packages/40/9a/8458af9a5557e177ea42f8cf7e477bede518b0bbef564e28c4151feaa52c/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2b407cc3e9defa8df5eb46644f6f136586f70ba49eba96f43de67b9a0984fd3", size = 2155352, upload-time = "2024-12-13T05:45:19.763Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5c/2a701423e001fcbec288b4f3fc2bf67557d114c2388237fc1ae67e1e2686/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8245f929144d4d3bd7b972c9593300195c6cea246b81b4c46053c48b3f044580", size = 2163515, upload-time = "2024-12-13T05:45:21.08Z" }, - { url = "https://files.pythonhosted.org/packages/36/16/ee2e06e65d9d533bc05cd52a0b355ba9072fc8f60d77289e529c6d2e3750/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37385db03af65763933befe89fa70faf25301effc3b0485fec1c15d4ce4f052", size = 2054431, upload-time = "2024-12-13T05:45:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d5/2fac8315f210fa1bc7106e27c19e1211580aa25bb7fa17dfd79505e5baf2/cytoolz-1.0.1-cp311-cp311-win32.whl", hash = "sha256:50f9c530f83e3e574fc95c264c3350adde8145f4f8fc8099f65f00cc595e5ead", size = 322004, upload-time = "2024-12-13T05:45:24.048Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9e/0b70b641850a95f9ff90adde9d094a4b1d81ec54dadfd97fec0a2aaf440e/cytoolz-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b7f6b617454b4326af7bd3c7c49b0fc80767f134eb9fd6449917a058d17a0e3c", size = 365358, upload-time = "2024-12-13T05:45:25.383Z" }, - { url = "https://files.pythonhosted.org/packages/d8/e8/218098344ed2cb5f8441fade9b2428e435e7073962374a9c71e59ac141a7/cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4", size = 414121, upload-time = "2024-12-13T05:45:26.588Z" }, - { url = "https://files.pythonhosted.org/packages/de/27/4d729a5653718109262b758fec1a959aa9facb74c15460d9074dc76d6635/cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662", size = 390904, upload-time = "2024-12-13T05:45:27.718Z" }, - { url = "https://files.pythonhosted.org/packages/72/c0/cbabfa788bab9c6038953bf9478adaec06e88903a726946ea7c88092f5c4/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3", size = 2090734, upload-time = "2024-12-13T05:45:30.515Z" }, - { url = "https://files.pythonhosted.org/packages/c3/66/369262c60f9423c2da82a60864a259c852f1aa122aced4acd2c679af58c0/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1", size = 2155933, upload-time = "2024-12-13T05:45:32.721Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4e/ee55186802f8d24b5fbf9a11405ccd1203b30eded07cc17750618219b94e/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8", size = 2171903, upload-time = "2024-12-13T05:45:34.205Z" }, - { url = "https://files.pythonhosted.org/packages/a1/96/bd1a9f3396e9b7f618db8cd08d15630769ce3c8b7d0534f92cd639c977ae/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d", size = 2125270, upload-time = "2024-12-13T05:45:36.982Z" }, - { url = "https://files.pythonhosted.org/packages/28/48/2a3762873091c88a69e161111cfbc6c222ff145d57ff011a642b169f04f1/cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f", size = 1973967, upload-time = "2024-12-13T05:45:39.505Z" }, - { url = "https://files.pythonhosted.org/packages/e4/50/500bd69774bdc49a4d78ec8779eb6ac7c1a9d706bfd91cf2a1dba604373a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7", size = 2021695, upload-time = "2024-12-13T05:45:40.911Z" }, - { url = "https://files.pythonhosted.org/packages/e4/4e/ba5a0ce34869495eb50653de8d676847490cf13a2cac1760fc4d313e78de/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126", size = 2010177, upload-time = "2024-12-13T05:45:42.48Z" }, - { url = "https://files.pythonhosted.org/packages/87/57/615c630b3089a13adb15351d958d227430cf624f03b1dd39eb52c34c1f59/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0", size = 2154321, upload-time = "2024-12-13T05:45:43.979Z" }, - { url = "https://files.pythonhosted.org/packages/7f/0f/fe1aa2d931e3b35ecc05215bd75da945ea7346095b3b6f6027164e602d5a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b", size = 2188374, upload-time = "2024-12-13T05:45:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/de/fa/fd363d97a641b6d0e2fd1d5c35b8fd41d9ccaeb4df56302f53bf23a58e3a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d", size = 2077911, upload-time = "2024-12-13T05:45:48.219Z" }, - { url = "https://files.pythonhosted.org/packages/d9/68/0a22946b98ae5201b54ccb4e651295285c0fb79406022b6ee8b2f791940c/cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9", size = 321903, upload-time = "2024-12-13T05:45:50.3Z" }, - { url = "https://files.pythonhosted.org/packages/62/1a/f3903197956055032f8cb297342e2dff07e50f83991aebfe5b4c4fcb55e4/cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b", size = 364490, upload-time = "2024-12-13T05:45:51.494Z" }, - { url = "https://files.pythonhosted.org/packages/aa/2e/a9f069db0107749e9e72baf6c21abe3f006841a3bcfdc9b8420e22ef31eb/cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0", size = 407365, upload-time = "2024-12-13T05:45:52.803Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9b/5e87dd0e31f54c778b4f9f34cc14c1162d3096c8d746b0f8be97d70dd73c/cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a", size = 385233, upload-time = "2024-12-13T05:45:53.994Z" }, - { url = "https://files.pythonhosted.org/packages/63/00/2fd32b16284cdb97cfe092822179bc0c3bcdd5e927dd39f986169a517642/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242", size = 2062903, upload-time = "2024-12-13T05:45:55.202Z" }, - { url = "https://files.pythonhosted.org/packages/85/39/b3cbb5a9847ba59584a263772ad4f8ca2dbfd2a0e11efd09211d1219804c/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296", size = 2139517, upload-time = "2024-12-13T05:45:56.804Z" }, - { url = "https://files.pythonhosted.org/packages/ea/39/bfcab4a46d50c467e36fe704f19d8904efead417787806ee210327f68390/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b", size = 2154849, upload-time = "2024-12-13T05:45:58.814Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/3bc6ee61b0aa47e1cb40819adc1a456d7efa809f0dea9faddacb43fdde8f/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b", size = 2102302, upload-time = "2024-12-13T05:46:00.181Z" }, - { url = "https://files.pythonhosted.org/packages/00/66/3f636c6ddea7b18026b90a8c238af472e423b86e427b11df02213689b012/cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266", size = 1960872, upload-time = "2024-12-13T05:46:01.612Z" }, - { url = "https://files.pythonhosted.org/packages/40/36/cb3b7cdd651007b69f9c48e9d104cec7cb8dc53afa1d6a720e5ad08022fa/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5", size = 2014430, upload-time = "2024-12-13T05:46:03.022Z" }, - { url = "https://files.pythonhosted.org/packages/88/3f/2e9bd2a16cfd269808922147551dcb2d8b68ba54a2c4deca2fa6a6cd0d5f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3", size = 2003127, upload-time = "2024-12-13T05:46:04.401Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7d/08604ff940aa784df8343c387fdf2489b948b714a6afb587775ae94da912/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296", size = 2142369, upload-time = "2024-12-13T05:46:06.004Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c6/39919a0645bdbdf720e97cae107f959ea9d1267fbc3b0d94fc6e1d12ac8f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140", size = 2180427, upload-time = "2024-12-13T05:46:07.526Z" }, - { url = "https://files.pythonhosted.org/packages/d8/03/dbb9d47556ee54337e7e0ac209d17ceff2d2a197c34de08005abc7a7449b/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581", size = 2069785, upload-time = "2024-12-13T05:46:10.122Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f8/11bb7b8947002231faae3ec2342df5896afbc19eb783a332cce6d219ff79/cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9", size = 320685, upload-time = "2024-12-13T05:46:11.553Z" }, - { url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297", size = 362898, upload-time = "2024-12-13T05:46:12.771Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f7/ef2a10daaec5c0f7d781d50758c6187eee484256e356ae8ef178d6c48497/cytoolz-1.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:83d19d55738ad9c60763b94f3f6d3c6e4de979aeb8d76841c1401081e0e58d96", size = 345702, upload-time = "2024-12-13T05:47:09.266Z" }, - { url = "https://files.pythonhosted.org/packages/c8/14/53c84adddedb67ff1546abb86fea04d26e24298c3ceab8436d20122ed0b9/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f112a71fad6ea824578e6393765ce5c054603afe1471a5c753ff6c67fd872d10", size = 385695, upload-time = "2024-12-13T05:47:11.011Z" }, - { url = "https://files.pythonhosted.org/packages/bd/80/3ae356c5e7b8d7dc7d1adb52f6932fee85cd748ed4e1217c269d2dfd610f/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a515df8f8aa6e1eaaf397761a6e4aff2eef73b5f920aedf271416d5471ae5ee", size = 406261, upload-time = "2024-12-13T05:47:12.24Z" }, - { url = "https://files.pythonhosted.org/packages/0c/31/8e43761ffc82d90bf9cab7e0959712eedcd1e33c211397e143dd42d7af57/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c398e7b7023460bea2edffe5fcd0a76029580f06c3f6938ac3d198b47156f3", size = 397207, upload-time = "2024-12-13T05:47:13.561Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b9/fe9da37090b6444c65f848a83e390f87d8cb43d6a4df46de1556ad7e5ceb/cytoolz-1.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3237e56211e03b13df47435b2369f5df281e02b04ad80a948ebd199b7bc10a47", size = 343358, upload-time = "2024-12-13T05:47:16.291Z" }, -] - -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - -[[package]] -name = "email-validator" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, -] - -[[package]] -name = "eth-abi" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "parsimonious" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/71/d9e1380bd77fd22f98b534699af564f189b56d539cc2b9dab908d4e4c242/eth_abi-5.2.0.tar.gz", hash = "sha256:178703fa98c07d8eecd5ae569e7e8d159e493ebb6eeb534a8fe973fbc4e40ef0", size = 49797, upload-time = "2025-01-14T16:29:34.629Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/b4/2f3982c4cbcbf5eeb6aec62df1533c0e63c653b3021ff338d44944405676/eth_abi-5.2.0-py3-none-any.whl", hash = "sha256:17abe47560ad753f18054f5b3089fcb588f3e3a092136a416b6c1502cb7e8877", size = 28511, upload-time = "2025-01-14T16:29:31.862Z" }, -] - -[[package]] -name = "eth-account" -version = "0.13.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bitarray" }, - { name = "ckzg" }, - { name = "eth-abi" }, - { name = "eth-keyfile" }, - { name = "eth-keys" }, - { name = "eth-rlp" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "rlp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/cf/20f76a29be97339c969fd765f1237154286a565a1d61be98e76bb7af946a/eth_account-0.13.7.tar.gz", hash = "sha256:5853ecbcbb22e65411176f121f5f24b8afeeaf13492359d254b16d8b18c77a46", size = 935998, upload-time = "2025-04-21T21:11:21.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/18/088fb250018cbe665bc2111974301b2d59f294a565aff7564c4df6878da2/eth_account-0.13.7-py3-none-any.whl", hash = "sha256:39727de8c94d004ff61d10da7587509c04d2dc7eac71e04830135300bdfc6d24", size = 587452, upload-time = "2025-04-21T21:11:18.346Z" }, -] - -[[package]] -name = "eth-hash" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/38/577b7bc9380ef9dff0f1dffefe0c9a1ded2385e7a06c306fd95afb6f9451/eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5", size = 12227, upload-time = "2025-01-13T21:29:21.765Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/db/f8775490669d28aca24871c67dd56b3e72105cb3bcae9a4ec65dd70859b3/eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a", size = 8028, upload-time = "2025-01-13T21:29:19.365Z" }, -] - -[package.optional-dependencies] -pycryptodome = [ - { name = "pycryptodome" }, -] - -[[package]] -name = "eth-keyfile" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-keys" }, - { name = "eth-utils" }, - { name = "pycryptodome" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/66/dd823b1537befefbbff602e2ada88f1477c5b40ec3731e3d9bc676c5f716/eth_keyfile-0.8.1.tar.gz", hash = "sha256:9708bc31f386b52cca0969238ff35b1ac72bd7a7186f2a84b86110d3c973bec1", size = 12267, upload-time = "2024-04-23T20:28:53.862Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/fc/48a586175f847dd9e05e5b8994d2fe8336098781ec2e9836a2ad94280281/eth_keyfile-0.8.1-py3-none-any.whl", hash = "sha256:65387378b82fe7e86d7cb9f8d98e6d639142661b2f6f490629da09fddbef6d64", size = 7510, upload-time = "2024-04-23T20:28:51.063Z" }, -] - -[[package]] -name = "eth-keys" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/11/1ed831c50bd74f57829aa06e58bd82a809c37e070ee501c953b9ac1f1552/eth_keys-0.7.0.tar.gz", hash = "sha256:79d24fd876201df67741de3e3fefb3f4dbcbb6ace66e47e6fe662851a4547814", size = 30166, upload-time = "2025-04-07T17:40:21.697Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/25/0ae00f2b0095e559d61ad3dc32171bd5a29dfd95ab04b4edd641f7c75f72/eth_keys-0.7.0-py3-none-any.whl", hash = "sha256:b0cdda8ffe8e5ba69c7c5ca33f153828edcace844f67aabd4542d7de38b159cf", size = 20656, upload-time = "2025-04-07T17:40:20.441Z" }, -] - -[[package]] -name = "eth-rlp" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "rlp" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7f/ea/ad39d001fa9fed07fad66edb00af701e29b48be0ed44a3bcf58cb3adf130/eth_rlp-2.2.0.tar.gz", hash = "sha256:5e4b2eb1b8213e303d6a232dfe35ab8c29e2d3051b86e8d359def80cd21db83d", size = 7720, upload-time = "2025-02-04T21:51:08.134Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/3b/57efe2bc2df0980680d57c01a36516cd3171d2319ceb30e675de19fc2cc5/eth_rlp-2.2.0-py3-none-any.whl", hash = "sha256:5692d595a741fbaef1203db6a2fedffbd2506d31455a6ad378c8449ee5985c47", size = 4446, upload-time = "2025-02-04T21:51:05.823Z" }, -] - -[[package]] -name = "eth-typing" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/54/62aa24b9cc708f06316167ee71c362779c8ed21fc8234a5cd94a8f53b623/eth_typing-5.2.1.tar.gz", hash = "sha256:7557300dbf02a93c70fa44af352b5c4a58f94e997a0fd6797fb7d1c29d9538ee", size = 21806, upload-time = "2025-04-14T20:39:28.217Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/72/c370bbe4c53da7bf998d3523f5a0f38867654923a82192df88d0705013d3/eth_typing-5.2.1-py3-none-any.whl", hash = "sha256:b0c2812ff978267563b80e9d701f487dd926f1d376d674f3b535cfe28b665d3d", size = 19163, upload-time = "2025-04-14T20:39:26.571Z" }, -] - -[[package]] -name = "eth-utils" -version = "5.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cytoolz", marker = "implementation_name == 'cpython'" }, - { name = "eth-hash" }, - { name = "eth-typing" }, - { name = "pydantic" }, - { name = "toolz", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0d/49/bee95f16d2ef068097afeeffbd6c67738107001ee57ad7bcdd4fc4d3c6a7/eth_utils-5.3.0.tar.gz", hash = "sha256:1f096867ac6be895f456fa3acb26e9573ae66e753abad9208f316d24d6178156", size = 123753, upload-time = "2025-04-14T19:35:56.431Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/c6/0417a92e6a3fc9b85f5a8380d9f9d43b69ba836a90e45f79f9ae74d41e53/eth_utils-5.3.0-py3-none-any.whl", hash = "sha256:ac184883ab299d923428bbe25dae5e356979a3993e0ef695a864db0a20bc262d", size = 102531, upload-time = "2025-04-14T19:35:55.176Z" }, -] - -[[package]] -name = "exceptiongroup" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, -] - -[[package]] -name = "fastapi" -version = "0.115.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236, upload-time = "2025-03-23T22:55:43.822Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164, upload-time = "2025-03-23T22:55:42.101Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, - { name = "httpx" }, - { name = "jinja2" }, - { name = "python-multipart" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cli" -version = "0.0.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "rich-toolkit" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/73/82a5831fbbf8ed75905bacf5b2d9d3dfd6f04d6968b29fe6f72a5ae9ceb1/fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e", size = 16753, upload-time = "2024-12-15T14:28:10.028Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705, upload-time = "2024-12-15T14:28:06.18Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "flask" -version = "3.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "blinker" }, - { name = "click" }, - { name = "itsdangerous" }, - { name = "jinja2" }, - { name = "markupsafe" }, - { name = "werkzeug" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/de/e47735752347f4128bcf354e0da07ef311a78244eba9e3dc1d4a5ab21a98/flask-3.1.1.tar.gz", hash = "sha256:284c7b8f2f58cb737f0cf1c30fd7eaf0ccfcde196099d24ecede3fc2005aa59e", size = 753440, upload-time = "2025-05-13T15:01:17.447Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl", hash = "sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c", size = 103305, upload-time = "2025-05-13T15:01:15.591Z" }, -] - -[[package]] -name = "frozenlist" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, - { url = "https://files.pythonhosted.org/packages/77/f0/77c11d13d39513b298e267b22eb6cb559c103d56f155aa9a49097221f0b6/frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61", size = 47735, upload-time = "2025-06-09T22:59:48.133Z" }, - { url = "https://files.pythonhosted.org/packages/37/12/9d07fa18971a44150593de56b2f2947c46604819976784bcf6ea0d5db43b/frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d", size = 46775, upload-time = "2025-06-09T22:59:49.564Z" }, - { url = "https://files.pythonhosted.org/packages/70/34/f73539227e06288fcd1f8a76853e755b2b48bca6747e99e283111c18bcd4/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e", size = 224644, upload-time = "2025-06-09T22:59:51.35Z" }, - { url = "https://files.pythonhosted.org/packages/fb/68/c1d9c2f4a6e438e14613bad0f2973567586610cc22dcb1e1241da71de9d3/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9", size = 222125, upload-time = "2025-06-09T22:59:52.884Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d0/98e8f9a515228d708344d7c6986752be3e3192d1795f748c24bcf154ad99/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c", size = 233455, upload-time = "2025-06-09T22:59:54.74Z" }, - { url = "https://files.pythonhosted.org/packages/79/df/8a11bcec5600557f40338407d3e5bea80376ed1c01a6c0910fcfdc4b8993/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981", size = 227339, upload-time = "2025-06-09T22:59:56.187Z" }, - { url = "https://files.pythonhosted.org/packages/50/82/41cb97d9c9a5ff94438c63cc343eb7980dac4187eb625a51bdfdb7707314/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615", size = 212969, upload-time = "2025-06-09T22:59:57.604Z" }, - { url = "https://files.pythonhosted.org/packages/13/47/f9179ee5ee4f55629e4f28c660b3fdf2775c8bfde8f9c53f2de2d93f52a9/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50", size = 222862, upload-time = "2025-06-09T22:59:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/df81e41ec6b953902c8b7e3a83bee48b195cb0e5ec2eabae5d8330c78038/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa", size = 222492, upload-time = "2025-06-09T23:00:01.026Z" }, - { url = "https://files.pythonhosted.org/packages/84/17/30d6ea87fa95a9408245a948604b82c1a4b8b3e153cea596421a2aef2754/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577", size = 238250, upload-time = "2025-06-09T23:00:03.401Z" }, - { url = "https://files.pythonhosted.org/packages/8f/00/ecbeb51669e3c3df76cf2ddd66ae3e48345ec213a55e3887d216eb4fbab3/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59", size = 218720, upload-time = "2025-06-09T23:00:05.282Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c0/c224ce0e0eb31cc57f67742071bb470ba8246623c1823a7530be0e76164c/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e", size = 232585, upload-time = "2025-06-09T23:00:07.962Z" }, - { url = "https://files.pythonhosted.org/packages/55/3c/34cb694abf532f31f365106deebdeac9e45c19304d83cf7d51ebbb4ca4d1/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd", size = 234248, upload-time = "2025-06-09T23:00:09.428Z" }, - { url = "https://files.pythonhosted.org/packages/98/c0/2052d8b6cecda2e70bd81299e3512fa332abb6dcd2969b9c80dfcdddbf75/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718", size = 221621, upload-time = "2025-06-09T23:00:11.32Z" }, - { url = "https://files.pythonhosted.org/packages/c5/bf/7dcebae315436903b1d98ffb791a09d674c88480c158aa171958a3ac07f0/frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e", size = 39578, upload-time = "2025-06-09T23:00:13.526Z" }, - { url = "https://files.pythonhosted.org/packages/8f/5f/f69818f017fa9a3d24d1ae39763e29b7f60a59e46d5f91b9c6b21622f4cd/frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464", size = 43830, upload-time = "2025-06-09T23:00:14.98Z" }, - { url = "https://files.pythonhosted.org/packages/34/7e/803dde33760128acd393a27eb002f2020ddb8d99d30a44bfbaab31c5f08a/frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a", size = 82251, upload-time = "2025-06-09T23:00:16.279Z" }, - { url = "https://files.pythonhosted.org/packages/75/a9/9c2c5760b6ba45eae11334db454c189d43d34a4c0b489feb2175e5e64277/frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750", size = 48183, upload-time = "2025-06-09T23:00:17.698Z" }, - { url = "https://files.pythonhosted.org/packages/47/be/4038e2d869f8a2da165f35a6befb9158c259819be22eeaf9c9a8f6a87771/frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd", size = 47107, upload-time = "2025-06-09T23:00:18.952Z" }, - { url = "https://files.pythonhosted.org/packages/79/26/85314b8a83187c76a37183ceed886381a5f992975786f883472fcb6dc5f2/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2", size = 237333, upload-time = "2025-06-09T23:00:20.275Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fd/e5b64f7d2c92a41639ffb2ad44a6a82f347787abc0c7df5f49057cf11770/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f", size = 231724, upload-time = "2025-06-09T23:00:21.705Z" }, - { url = "https://files.pythonhosted.org/packages/20/fb/03395c0a43a5976af4bf7534759d214405fbbb4c114683f434dfdd3128ef/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30", size = 245842, upload-time = "2025-06-09T23:00:23.148Z" }, - { url = "https://files.pythonhosted.org/packages/d0/15/c01c8e1dffdac5d9803507d824f27aed2ba76b6ed0026fab4d9866e82f1f/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98", size = 239767, upload-time = "2025-06-09T23:00:25.103Z" }, - { url = "https://files.pythonhosted.org/packages/14/99/3f4c6fe882c1f5514b6848aa0a69b20cb5e5d8e8f51a339d48c0e9305ed0/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86", size = 224130, upload-time = "2025-06-09T23:00:27.061Z" }, - { url = "https://files.pythonhosted.org/packages/4d/83/220a374bd7b2aeba9d0725130665afe11de347d95c3620b9b82cc2fcab97/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae", size = 235301, upload-time = "2025-06-09T23:00:29.02Z" }, - { url = "https://files.pythonhosted.org/packages/03/3c/3e3390d75334a063181625343e8daab61b77e1b8214802cc4e8a1bb678fc/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8", size = 234606, upload-time = "2025-06-09T23:00:30.514Z" }, - { url = "https://files.pythonhosted.org/packages/23/1e/58232c19608b7a549d72d9903005e2d82488f12554a32de2d5fb59b9b1ba/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31", size = 248372, upload-time = "2025-06-09T23:00:31.966Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a4/e4a567e01702a88a74ce8a324691e62a629bf47d4f8607f24bf1c7216e7f/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7", size = 229860, upload-time = "2025-06-09T23:00:33.375Z" }, - { url = "https://files.pythonhosted.org/packages/73/a6/63b3374f7d22268b41a9db73d68a8233afa30ed164c46107b33c4d18ecdd/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5", size = 245893, upload-time = "2025-06-09T23:00:35.002Z" }, - { url = "https://files.pythonhosted.org/packages/6d/eb/d18b3f6e64799a79673c4ba0b45e4cfbe49c240edfd03a68be20002eaeaa/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898", size = 246323, upload-time = "2025-06-09T23:00:36.468Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f5/720f3812e3d06cd89a1d5db9ff6450088b8f5c449dae8ffb2971a44da506/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56", size = 233149, upload-time = "2025-06-09T23:00:37.963Z" }, - { url = "https://files.pythonhosted.org/packages/69/68/03efbf545e217d5db8446acfd4c447c15b7c8cf4dbd4a58403111df9322d/frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7", size = 39565, upload-time = "2025-06-09T23:00:39.753Z" }, - { url = "https://files.pythonhosted.org/packages/58/17/fe61124c5c333ae87f09bb67186d65038834a47d974fc10a5fadb4cc5ae1/frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d", size = 44019, upload-time = "2025-06-09T23:00:40.988Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, - { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, - { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, - { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, - { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, - { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, - { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, - { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, - { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, - { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" }, - { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" }, - { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" }, - { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" }, - { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" }, - { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" }, - { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" }, - { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" }, - { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" }, - { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" }, - { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" }, - { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" }, - { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" }, - { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" }, - { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" }, - { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" }, - { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" }, - { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" }, - { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" }, - { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" }, - { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" }, - { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" }, - { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" }, - { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" }, - { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" }, - { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" }, - { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" }, - { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" }, - { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" }, - { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" }, - { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" }, - { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "hexbytes" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/87/adf4635b4b8c050283d74e6db9a81496063229c9263e6acc1903ab79fbec/hexbytes-1.3.1.tar.gz", hash = "sha256:a657eebebdfe27254336f98d8af6e2236f3f83aed164b87466b6cf6c5f5a4765", size = 8633, upload-time = "2025-05-14T16:45:17.5Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/e0/3b31492b1c89da3c5a846680517871455b30c54738486fc57ac79a5761bd/hexbytes-1.3.1-py3-none-any.whl", hash = "sha256:da01ff24a1a9a2b1881c4b85f0e9f9b0f51b526b379ffa23832ae7899d29c2c7", size = 5074, upload-time = "2025-05-14T16:45:16.179Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httptools" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/17c672b4bc5c7ba7f201eada4e96c71d0a59fbc185e60e42580093a86f21/httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da", size = 103297, upload-time = "2024-10-16T19:44:08.129Z" }, - { url = "https://files.pythonhosted.org/packages/92/5e/b4a826fe91971a0b68e8c2bd4e7db3e7519882f5a8ccdb1194be2b3ab98f/httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1", size = 443130, upload-time = "2024-10-16T19:44:09.45Z" }, - { url = "https://files.pythonhosted.org/packages/b0/51/ce61e531e40289a681a463e1258fa1e05e0be54540e40d91d065a264cd8f/httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50", size = 442148, upload-time = "2024-10-16T19:44:11.539Z" }, - { url = "https://files.pythonhosted.org/packages/ea/9e/270b7d767849b0c96f275c695d27ca76c30671f8eb8cc1bab6ced5c5e1d0/httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959", size = 415949, upload-time = "2024-10-16T19:44:13.388Z" }, - { url = "https://files.pythonhosted.org/packages/81/86/ced96e3179c48c6f656354e106934e65c8963d48b69be78f355797f0e1b3/httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4", size = 417591, upload-time = "2024-10-16T19:44:15.258Z" }, - { url = "https://files.pythonhosted.org/packages/75/73/187a3f620ed3175364ddb56847d7a608a6fc42d551e133197098c0143eca/httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c", size = 88344, upload-time = "2024-10-16T19:44:16.54Z" }, - { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029, upload-time = "2024-10-16T19:44:18.427Z" }, - { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492, upload-time = "2024-10-16T19:44:19.515Z" }, - { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891, upload-time = "2024-10-16T19:44:21.067Z" }, - { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788, upload-time = "2024-10-16T19:44:22.958Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214, upload-time = "2024-10-16T19:44:24.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120, upload-time = "2024-10-16T19:44:26.295Z" }, - { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565, upload-time = "2024-10-16T19:44:29.188Z" }, - { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683, upload-time = "2024-10-16T19:44:30.175Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337, upload-time = "2024-10-16T19:44:31.786Z" }, - { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796, upload-time = "2024-10-16T19:44:32.825Z" }, - { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837, upload-time = "2024-10-16T19:44:33.974Z" }, - { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289, upload-time = "2024-10-16T19:44:35.111Z" }, - { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779, upload-time = "2024-10-16T19:44:36.253Z" }, - { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634, upload-time = "2024-10-16T19:44:37.357Z" }, - { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" }, - { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" }, - { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" }, - { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" }, - { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" }, - { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "itsdangerous" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "jsonalias" -version = "0.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/45/ee7e17002cb7f3264f755ff6a1a72c55d1830e07808d643167d2a2277c4f/jsonalias-0.1.1.tar.gz", hash = "sha256:64f04d935397d579fc94509e1fcb6212f2d081235d9d6395bd10baedf760a769", size = 1095, upload-time = "2022-10-28T22:57:56.224Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/41/ed/05aebce69f78c104feff2ffcdd5a6f9d668a208aba3a8bf56e3750809fd8/jsonalias-0.1.1-py3-none-any.whl", hash = "sha256:a56d2888e6397812c606156504e861e8ec00e188005af149f003c787db3d3f18", size = 1312, upload-time = "2022-10-28T22:57:54.763Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "multidict" -version = "6.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/2f/a3470242707058fe856fe59241eee5635d79087100b7042a867368863a27/multidict-6.4.4.tar.gz", hash = "sha256:69ee9e6ba214b5245031b76233dd95408a0fd57fdb019ddcc1ead4790932a8e8", size = 90183, upload-time = "2025-05-19T14:16:37.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/92/0926a5baafa164b5d0ade3cd7932be39310375d7e25c9d7ceca05cb26a45/multidict-6.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8adee3ac041145ffe4488ea73fa0a622b464cc25340d98be76924d0cda8545ff", size = 66052, upload-time = "2025-05-19T14:13:49.944Z" }, - { url = "https://files.pythonhosted.org/packages/b2/54/8a857ae4f8f643ec444d91f419fdd49cc7a90a2ca0e42d86482b604b63bd/multidict-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b61e98c3e2a861035aaccd207da585bdcacef65fe01d7a0d07478efac005e028", size = 38867, upload-time = "2025-05-19T14:13:51.92Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5f/63add9069f945c19bc8b217ea6b0f8a1ad9382eab374bb44fae4354b3baf/multidict-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75493f28dbadecdbb59130e74fe935288813301a8554dc32f0c631b6bdcdf8b0", size = 38138, upload-time = "2025-05-19T14:13:53.778Z" }, - { url = "https://files.pythonhosted.org/packages/97/8b/fbd9c0fc13966efdb4a47f5bcffff67a4f2a3189fbeead5766eaa4250b20/multidict-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc3c6a37e048b5395ee235e4a2a0d639c2349dffa32d9367a42fc20d399772", size = 220433, upload-time = "2025-05-19T14:13:55.346Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c4/5132b2d75b3ea2daedb14d10f91028f09f74f5b4d373b242c1b8eec47571/multidict-6.4.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87cb72263946b301570b0f63855569a24ee8758aaae2cd182aae7d95fbc92ca7", size = 218059, upload-time = "2025-05-19T14:13:56.993Z" }, - { url = "https://files.pythonhosted.org/packages/1a/70/f1e818c7a29b908e2d7b4fafb1d7939a41c64868e79de2982eea0a13193f/multidict-6.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bbf7bd39822fd07e3609b6b4467af4c404dd2b88ee314837ad1830a7f4a8299", size = 231120, upload-time = "2025-05-19T14:13:58.333Z" }, - { url = "https://files.pythonhosted.org/packages/b4/7e/95a194d85f27d5ef9cbe48dff9ded722fc6d12fedf641ec6e1e680890be7/multidict-6.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1f7cbd4f1f44ddf5fd86a8675b7679176eae770f2fc88115d6dddb6cefb59bc", size = 227457, upload-time = "2025-05-19T14:13:59.663Z" }, - { url = "https://files.pythonhosted.org/packages/25/2b/590ad220968d1babb42f265debe7be5c5c616df6c5688c995a06d8a9b025/multidict-6.4.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb5ac9e5bfce0e6282e7f59ff7b7b9a74aa8e5c60d38186a4637f5aa764046ad", size = 219111, upload-time = "2025-05-19T14:14:01.019Z" }, - { url = "https://files.pythonhosted.org/packages/e0/f0/b07682b995d3fb5313f339b59d7de02db19ba0c02d1f77c27bdf8212d17c/multidict-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4efc31dfef8c4eeb95b6b17d799eedad88c4902daba39ce637e23a17ea078915", size = 213012, upload-time = "2025-05-19T14:14:02.396Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/c77b5f36feef2ec92f1119756e468ac9c3eebc35aa8a4c9e51df664cbbc9/multidict-6.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9fcad2945b1b91c29ef2b4050f590bfcb68d8ac8e0995a74e659aa57e8d78e01", size = 225408, upload-time = "2025-05-19T14:14:04.826Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b3/e8189b82af9b198b47bc637766208fc917189eea91d674bad417e657bbdf/multidict-6.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d877447e7368c7320832acb7159557e49b21ea10ffeb135c1077dbbc0816b598", size = 214396, upload-time = "2025-05-19T14:14:06.187Z" }, - { url = "https://files.pythonhosted.org/packages/20/e0/200d14c84e35ae13ee99fd65dc106e1a1acb87a301f15e906fc7d5b30c17/multidict-6.4.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:33a12ebac9f380714c298cbfd3e5b9c0c4e89c75fe612ae496512ee51028915f", size = 222237, upload-time = "2025-05-19T14:14:07.778Z" }, - { url = "https://files.pythonhosted.org/packages/13/f3/bb3df40045ca8262694a3245298732ff431dc781414a89a6a364ebac6840/multidict-6.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0f14ea68d29b43a9bf37953881b1e3eb75b2739e896ba4a6aa4ad4c5b9ffa145", size = 231425, upload-time = "2025-05-19T14:14:09.516Z" }, - { url = "https://files.pythonhosted.org/packages/85/3b/538563dc18514384dac169bcba938753ad9ab4d4c8d49b55d6ae49fb2579/multidict-6.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0327ad2c747a6600e4797d115d3c38a220fdb28e54983abe8964fd17e95ae83c", size = 226251, upload-time = "2025-05-19T14:14:10.82Z" }, - { url = "https://files.pythonhosted.org/packages/56/79/77e1a65513f09142358f1beb1d4cbc06898590b34a7de2e47023e3c5a3a2/multidict-6.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d1a20707492db9719a05fc62ee215fd2c29b22b47c1b1ba347f9abc831e26683", size = 220363, upload-time = "2025-05-19T14:14:12.638Z" }, - { url = "https://files.pythonhosted.org/packages/16/57/67b0516c3e348f8daaa79c369b3de4359a19918320ab82e2e586a1c624ef/multidict-6.4.4-cp310-cp310-win32.whl", hash = "sha256:d83f18315b9fca5db2452d1881ef20f79593c4aa824095b62cb280019ef7aa3d", size = 35175, upload-time = "2025-05-19T14:14:14.805Z" }, - { url = "https://files.pythonhosted.org/packages/86/5a/4ed8fec642d113fa653777cda30ef67aa5c8a38303c091e24c521278a6c6/multidict-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:9c17341ee04545fd962ae07330cb5a39977294c883485c8d74634669b1f7fe04", size = 38678, upload-time = "2025-05-19T14:14:16.949Z" }, - { url = "https://files.pythonhosted.org/packages/19/1b/4c6e638195851524a63972c5773c7737bea7e47b1ba402186a37773acee2/multidict-6.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f5f29794ac0e73d2a06ac03fd18870adc0135a9d384f4a306a951188ed02f95", size = 65515, upload-time = "2025-05-19T14:14:19.767Z" }, - { url = "https://files.pythonhosted.org/packages/25/d5/10e6bca9a44b8af3c7f920743e5fc0c2bcf8c11bf7a295d4cfe00b08fb46/multidict-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c04157266344158ebd57b7120d9b0b35812285d26d0e78193e17ef57bfe2979a", size = 38609, upload-time = "2025-05-19T14:14:21.538Z" }, - { url = "https://files.pythonhosted.org/packages/26/b4/91fead447ccff56247edc7f0535fbf140733ae25187a33621771ee598a18/multidict-6.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb61ffd3ab8310d93427e460f565322c44ef12769f51f77277b4abad7b6f7223", size = 37871, upload-time = "2025-05-19T14:14:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/3b/37/cbc977cae59277e99d15bbda84cc53b5e0c4929ffd91d958347200a42ad0/multidict-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e0ba18a9afd495f17c351d08ebbc4284e9c9f7971d715f196b79636a4d0de44", size = 226661, upload-time = "2025-05-19T14:14:24.124Z" }, - { url = "https://files.pythonhosted.org/packages/15/cd/7e0b57fbd4dc2fc105169c4ecce5be1a63970f23bb4ec8c721b67e11953d/multidict-6.4.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9faf1b1dcaadf9f900d23a0e6d6c8eadd6a95795a0e57fcca73acce0eb912065", size = 223422, upload-time = "2025-05-19T14:14:25.437Z" }, - { url = "https://files.pythonhosted.org/packages/f1/01/1de268da121bac9f93242e30cd3286f6a819e5f0b8896511162d6ed4bf8d/multidict-6.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4d1cb1327c6082c4fce4e2a438483390964c02213bc6b8d782cf782c9b1471f", size = 235447, upload-time = "2025-05-19T14:14:26.793Z" }, - { url = "https://files.pythonhosted.org/packages/d2/8c/8b9a5e4aaaf4f2de14e86181a3a3d7b105077f668b6a06f043ec794f684c/multidict-6.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:941f1bec2f5dbd51feeb40aea654c2747f811ab01bdd3422a48a4e4576b7d76a", size = 231455, upload-time = "2025-05-19T14:14:28.149Z" }, - { url = "https://files.pythonhosted.org/packages/35/db/e1817dcbaa10b319c412769cf999b1016890849245d38905b73e9c286862/multidict-6.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5f8a146184da7ea12910a4cec51ef85e44f6268467fb489c3caf0cd512f29c2", size = 223666, upload-time = "2025-05-19T14:14:29.584Z" }, - { url = "https://files.pythonhosted.org/packages/4a/e1/66e8579290ade8a00e0126b3d9a93029033ffd84f0e697d457ed1814d0fc/multidict-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:232b7237e57ec3c09be97206bfb83a0aa1c5d7d377faa019c68a210fa35831f1", size = 217392, upload-time = "2025-05-19T14:14:30.961Z" }, - { url = "https://files.pythonhosted.org/packages/7b/6f/f8639326069c24a48c7747c2a5485d37847e142a3f741ff3340c88060a9a/multidict-6.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:55ae0721c1513e5e3210bca4fc98456b980b0c2c016679d3d723119b6b202c42", size = 228969, upload-time = "2025-05-19T14:14:32.672Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c3/3d58182f76b960eeade51c89fcdce450f93379340457a328e132e2f8f9ed/multidict-6.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d662c072579f63137919d7bb8fc250655ce79f00c82ecf11cab678f335062e", size = 217433, upload-time = "2025-05-19T14:14:34.016Z" }, - { url = "https://files.pythonhosted.org/packages/e1/4b/f31a562906f3bd375f3d0e83ce314e4a660c01b16c2923e8229b53fba5d7/multidict-6.4.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0e05c39962baa0bb19a6b210e9b1422c35c093b651d64246b6c2e1a7e242d9fd", size = 225418, upload-time = "2025-05-19T14:14:35.376Z" }, - { url = "https://files.pythonhosted.org/packages/99/89/78bb95c89c496d64b5798434a3deee21996114d4d2c28dd65850bf3a691e/multidict-6.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b1cc3ab8c31d9ebf0faa6e3540fb91257590da330ffe6d2393d4208e638925", size = 235042, upload-time = "2025-05-19T14:14:36.723Z" }, - { url = "https://files.pythonhosted.org/packages/74/91/8780a6e5885a8770442a8f80db86a0887c4becca0e5a2282ba2cae702bc4/multidict-6.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:93ec84488a384cd7b8a29c2c7f467137d8a73f6fe38bb810ecf29d1ade011a7c", size = 230280, upload-time = "2025-05-19T14:14:38.194Z" }, - { url = "https://files.pythonhosted.org/packages/68/c1/fcf69cabd542eb6f4b892469e033567ee6991d361d77abdc55e3a0f48349/multidict-6.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b308402608493638763abc95f9dc0030bbd6ac6aff784512e8ac3da73a88af08", size = 223322, upload-time = "2025-05-19T14:14:40.015Z" }, - { url = "https://files.pythonhosted.org/packages/b8/85/5b80bf4b83d8141bd763e1d99142a9cdfd0db83f0739b4797172a4508014/multidict-6.4.4-cp311-cp311-win32.whl", hash = "sha256:343892a27d1a04d6ae455ecece12904d242d299ada01633d94c4f431d68a8c49", size = 35070, upload-time = "2025-05-19T14:14:41.904Z" }, - { url = "https://files.pythonhosted.org/packages/09/66/0bed198ffd590ab86e001f7fa46b740d58cf8ff98c2f254e4a36bf8861ad/multidict-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:73484a94f55359780c0f458bbd3c39cb9cf9c182552177d2136e828269dee529", size = 38667, upload-time = "2025-05-19T14:14:43.534Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b5/5675377da23d60875fe7dae6be841787755878e315e2f517235f22f59e18/multidict-6.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc388f75a1c00000824bf28b7633e40854f4127ede80512b44c3cfeeea1839a2", size = 64293, upload-time = "2025-05-19T14:14:44.724Z" }, - { url = "https://files.pythonhosted.org/packages/34/a7/be384a482754bb8c95d2bbe91717bf7ccce6dc38c18569997a11f95aa554/multidict-6.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:98af87593a666f739d9dba5d0ae86e01b0e1a9cfcd2e30d2d361fbbbd1a9162d", size = 38096, upload-time = "2025-05-19T14:14:45.95Z" }, - { url = "https://files.pythonhosted.org/packages/66/6d/d59854bb4352306145bdfd1704d210731c1bb2c890bfee31fb7bbc1c4c7f/multidict-6.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aff4cafea2d120327d55eadd6b7f1136a8e5a0ecf6fb3b6863e8aca32cd8e50a", size = 37214, upload-time = "2025-05-19T14:14:47.158Z" }, - { url = "https://files.pythonhosted.org/packages/99/e0/c29d9d462d7cfc5fc8f9bf24f9c6843b40e953c0b55e04eba2ad2cf54fba/multidict-6.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:169c4ba7858176b797fe551d6e99040c531c775d2d57b31bcf4de6d7a669847f", size = 224686, upload-time = "2025-05-19T14:14:48.366Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4a/da99398d7fd8210d9de068f9a1b5f96dfaf67d51e3f2521f17cba4ee1012/multidict-6.4.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9eb4c59c54421a32b3273d4239865cb14ead53a606db066d7130ac80cc8ec93", size = 231061, upload-time = "2025-05-19T14:14:49.952Z" }, - { url = "https://files.pythonhosted.org/packages/21/f5/ac11add39a0f447ac89353e6ca46666847051103649831c08a2800a14455/multidict-6.4.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cf3bd54c56aa16fdb40028d545eaa8d051402b61533c21e84046e05513d5780", size = 232412, upload-time = "2025-05-19T14:14:51.812Z" }, - { url = "https://files.pythonhosted.org/packages/d9/11/4b551e2110cded705a3c13a1d4b6a11f73891eb5a1c449f1b2b6259e58a6/multidict-6.4.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f682c42003c7264134bfe886376299db4cc0c6cd06a3295b41b347044bcb5482", size = 231563, upload-time = "2025-05-19T14:14:53.262Z" }, - { url = "https://files.pythonhosted.org/packages/4c/02/751530c19e78fe73b24c3da66618eda0aa0d7f6e7aa512e46483de6be210/multidict-6.4.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920f9cf2abdf6e493c519492d892c362007f113c94da4c239ae88429835bad1", size = 223811, upload-time = "2025-05-19T14:14:55.232Z" }, - { url = "https://files.pythonhosted.org/packages/c7/cb/2be8a214643056289e51ca356026c7b2ce7225373e7a1f8c8715efee8988/multidict-6.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:530d86827a2df6504526106b4c104ba19044594f8722d3e87714e847c74a0275", size = 216524, upload-time = "2025-05-19T14:14:57.226Z" }, - { url = "https://files.pythonhosted.org/packages/19/f3/6d5011ec375c09081f5250af58de85f172bfcaafebff286d8089243c4bd4/multidict-6.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ecde56ea2439b96ed8a8d826b50c57364612ddac0438c39e473fafad7ae1c23b", size = 229012, upload-time = "2025-05-19T14:14:58.597Z" }, - { url = "https://files.pythonhosted.org/packages/67/9c/ca510785df5cf0eaf5b2a8132d7d04c1ce058dcf2c16233e596ce37a7f8e/multidict-6.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:dc8c9736d8574b560634775ac0def6bdc1661fc63fa27ffdfc7264c565bcb4f2", size = 226765, upload-time = "2025-05-19T14:15:00.048Z" }, - { url = "https://files.pythonhosted.org/packages/36/c8/ca86019994e92a0f11e642bda31265854e6ea7b235642f0477e8c2e25c1f/multidict-6.4.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7f3d3b3c34867579ea47cbd6c1f2ce23fbfd20a273b6f9e3177e256584f1eacc", size = 222888, upload-time = "2025-05-19T14:15:01.568Z" }, - { url = "https://files.pythonhosted.org/packages/c6/67/bc25a8e8bd522935379066950ec4e2277f9b236162a73548a2576d4b9587/multidict-6.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:87a728af265e08f96b6318ebe3c0f68b9335131f461efab2fc64cc84a44aa6ed", size = 234041, upload-time = "2025-05-19T14:15:03.759Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a0/70c4c2d12857fccbe607b334b7ee28b6b5326c322ca8f73ee54e70d76484/multidict-6.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9f193eeda1857f8e8d3079a4abd258f42ef4a4bc87388452ed1e1c4d2b0c8740", size = 231046, upload-time = "2025-05-19T14:15:05.698Z" }, - { url = "https://files.pythonhosted.org/packages/c1/0f/52954601d02d39742aab01d6b92f53c1dd38b2392248154c50797b4df7f1/multidict-6.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be06e73c06415199200e9a2324a11252a3d62030319919cde5e6950ffeccf72e", size = 227106, upload-time = "2025-05-19T14:15:07.124Z" }, - { url = "https://files.pythonhosted.org/packages/af/24/679d83ec4379402d28721790dce818e5d6b9f94ce1323a556fb17fa9996c/multidict-6.4.4-cp312-cp312-win32.whl", hash = "sha256:622f26ea6a7e19b7c48dd9228071f571b2fbbd57a8cd71c061e848f281550e6b", size = 35351, upload-time = "2025-05-19T14:15:08.556Z" }, - { url = "https://files.pythonhosted.org/packages/52/ef/40d98bc5f986f61565f9b345f102409534e29da86a6454eb6b7c00225a13/multidict-6.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:5e2bcda30d5009996ff439e02a9f2b5c3d64a20151d34898c000a6281faa3781", size = 38791, upload-time = "2025-05-19T14:15:09.825Z" }, - { url = "https://files.pythonhosted.org/packages/df/2a/e166d2ffbf4b10131b2d5b0e458f7cee7d986661caceae0de8753042d4b2/multidict-6.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:82ffabefc8d84c2742ad19c37f02cde5ec2a1ee172d19944d380f920a340e4b9", size = 64123, upload-time = "2025-05-19T14:15:11.044Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/e200e379ae5b6f95cbae472e0199ea98913f03d8c9a709f42612a432932c/multidict-6.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6a2f58a66fe2c22615ad26156354005391e26a2f3721c3621504cd87c1ea87bf", size = 38049, upload-time = "2025-05-19T14:15:12.902Z" }, - { url = "https://files.pythonhosted.org/packages/75/fb/47afd17b83f6a8c7fa863c6d23ac5ba6a0e6145ed8a6bcc8da20b2b2c1d2/multidict-6.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5883d6ee0fd9d8a48e9174df47540b7545909841ac82354c7ae4cbe9952603bd", size = 37078, upload-time = "2025-05-19T14:15:14.282Z" }, - { url = "https://files.pythonhosted.org/packages/fa/70/1af3143000eddfb19fd5ca5e78393985ed988ac493bb859800fe0914041f/multidict-6.4.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9abcf56a9511653fa1d052bfc55fbe53dbee8f34e68bd6a5a038731b0ca42d15", size = 224097, upload-time = "2025-05-19T14:15:15.566Z" }, - { url = "https://files.pythonhosted.org/packages/b1/39/d570c62b53d4fba844e0378ffbcd02ac25ca423d3235047013ba2f6f60f8/multidict-6.4.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6ed5ae5605d4ad5a049fad2a28bb7193400700ce2f4ae484ab702d1e3749c3f9", size = 230768, upload-time = "2025-05-19T14:15:17.308Z" }, - { url = "https://files.pythonhosted.org/packages/fd/f8/ed88f2c4d06f752b015933055eb291d9bc184936903752c66f68fb3c95a7/multidict-6.4.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbfcb60396f9bcfa63e017a180c3105b8c123a63e9d1428a36544e7d37ca9e20", size = 231331, upload-time = "2025-05-19T14:15:18.73Z" }, - { url = "https://files.pythonhosted.org/packages/9c/6f/8e07cffa32f483ab887b0d56bbd8747ac2c1acd00dc0af6fcf265f4a121e/multidict-6.4.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0f1987787f5f1e2076b59692352ab29a955b09ccc433c1f6b8e8e18666f608b", size = 230169, upload-time = "2025-05-19T14:15:20.179Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2b/5dcf173be15e42f330110875a2668ddfc208afc4229097312212dc9c1236/multidict-6.4.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0121ccce8c812047d8d43d691a1ad7641f72c4f730474878a5aeae1b8ead8c", size = 222947, upload-time = "2025-05-19T14:15:21.714Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/4ddcbcebe5ebcd6faa770b629260d15840a5fc07ce8ad295a32e14993726/multidict-6.4.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83ec4967114295b8afd120a8eec579920c882831a3e4c3331d591a8e5bfbbc0f", size = 215761, upload-time = "2025-05-19T14:15:23.242Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c9/55e998ae45ff15c5608e384206aa71a11e1b7f48b64d166db400b14a3433/multidict-6.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:995f985e2e268deaf17867801b859a282e0448633f1310e3704b30616d269d69", size = 227605, upload-time = "2025-05-19T14:15:24.763Z" }, - { url = "https://files.pythonhosted.org/packages/04/49/c2404eac74497503c77071bd2e6f88c7e94092b8a07601536b8dbe99be50/multidict-6.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d832c608f94b9f92a0ec8b7e949be7792a642b6e535fcf32f3e28fab69eeb046", size = 226144, upload-time = "2025-05-19T14:15:26.249Z" }, - { url = "https://files.pythonhosted.org/packages/62/c5/0cd0c3c6f18864c40846aa2252cd69d308699cb163e1c0d989ca301684da/multidict-6.4.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d21c1212171cf7da703c5b0b7a0e85be23b720818aef502ad187d627316d5645", size = 221100, upload-time = "2025-05-19T14:15:28.303Z" }, - { url = "https://files.pythonhosted.org/packages/71/7b/f2f3887bea71739a046d601ef10e689528d4f911d84da873b6be9194ffea/multidict-6.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:cbebaa076aaecad3d4bb4c008ecc73b09274c952cf6a1b78ccfd689e51f5a5b0", size = 232731, upload-time = "2025-05-19T14:15:30.263Z" }, - { url = "https://files.pythonhosted.org/packages/e5/b3/d9de808349df97fa75ec1372758701b5800ebad3c46ae377ad63058fbcc6/multidict-6.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c93a6fb06cc8e5d3628b2b5fda215a5db01e8f08fc15fadd65662d9b857acbe4", size = 229637, upload-time = "2025-05-19T14:15:33.337Z" }, - { url = "https://files.pythonhosted.org/packages/5e/57/13207c16b615eb4f1745b44806a96026ef8e1b694008a58226c2d8f5f0a5/multidict-6.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8cd8f81f1310182362fb0c7898145ea9c9b08a71081c5963b40ee3e3cac589b1", size = 225594, upload-time = "2025-05-19T14:15:34.832Z" }, - { url = "https://files.pythonhosted.org/packages/3a/e4/d23bec2f70221604f5565000632c305fc8f25ba953e8ce2d8a18842b9841/multidict-6.4.4-cp313-cp313-win32.whl", hash = "sha256:3e9f1cd61a0ab857154205fb0b1f3d3ace88d27ebd1409ab7af5096e409614cd", size = 35359, upload-time = "2025-05-19T14:15:36.246Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/cfe1a47632be861b627f46f642c1d031704cc1c0f5c0efbde2ad44aa34bd/multidict-6.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373", size = 38903, upload-time = "2025-05-19T14:15:37.507Z" }, - { url = "https://files.pythonhosted.org/packages/68/7b/15c259b0ab49938a0a1c8f3188572802704a779ddb294edc1b2a72252e7c/multidict-6.4.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6a602151dbf177be2450ef38966f4be3467d41a86c6a845070d12e17c858a156", size = 68895, upload-time = "2025-05-19T14:15:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/f1/7d/168b5b822bccd88142e0a3ce985858fea612404edd228698f5af691020c9/multidict-6.4.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d2b9712211b860d123815a80b859075d86a4d54787e247d7fbee9db6832cf1c", size = 40183, upload-time = "2025-05-19T14:15:40.197Z" }, - { url = "https://files.pythonhosted.org/packages/e0/b7/d4b8d98eb850ef28a4922ba508c31d90715fd9b9da3801a30cea2967130b/multidict-6.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d2fa86af59f8fc1972e121ade052145f6da22758f6996a197d69bb52f8204e7e", size = 39592, upload-time = "2025-05-19T14:15:41.508Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/a554678898a19583548e742080cf55d169733baf57efc48c2f0273a08583/multidict-6.4.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50855d03e9e4d66eab6947ba688ffb714616f985838077bc4b490e769e48da51", size = 226071, upload-time = "2025-05-19T14:15:42.877Z" }, - { url = "https://files.pythonhosted.org/packages/ee/dc/7ba6c789d05c310e294f85329efac1bf5b450338d2542498db1491a264df/multidict-6.4.4-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5bce06b83be23225be1905dcdb6b789064fae92499fbc458f59a8c0e68718601", size = 222597, upload-time = "2025-05-19T14:15:44.412Z" }, - { url = "https://files.pythonhosted.org/packages/24/4f/34eadbbf401b03768dba439be0fb94b0d187facae9142821a3d5599ccb3b/multidict-6.4.4-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66ed0731f8e5dfd8369a883b6e564aca085fb9289aacabd9decd70568b9a30de", size = 228253, upload-time = "2025-05-19T14:15:46.474Z" }, - { url = "https://files.pythonhosted.org/packages/c0/e6/493225a3cdb0d8d80d43a94503fc313536a07dae54a3f030d279e629a2bc/multidict-6.4.4-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:329ae97fc2f56f44d91bc47fe0972b1f52d21c4b7a2ac97040da02577e2daca2", size = 226146, upload-time = "2025-05-19T14:15:48.003Z" }, - { url = "https://files.pythonhosted.org/packages/2f/70/e411a7254dc3bff6f7e6e004303b1b0591358e9f0b7c08639941e0de8bd6/multidict-6.4.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c27e5dcf520923d6474d98b96749e6805f7677e93aaaf62656005b8643f907ab", size = 220585, upload-time = "2025-05-19T14:15:49.546Z" }, - { url = "https://files.pythonhosted.org/packages/08/8f/beb3ae7406a619100d2b1fb0022c3bb55a8225ab53c5663648ba50dfcd56/multidict-6.4.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:058cc59b9e9b143cc56715e59e22941a5d868c322242278d28123a5d09cdf6b0", size = 212080, upload-time = "2025-05-19T14:15:51.151Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ec/355124e9d3d01cf8edb072fd14947220f357e1c5bc79c88dff89297e9342/multidict-6.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:69133376bc9a03f8c47343d33f91f74a99c339e8b58cea90433d8e24bb298031", size = 226558, upload-time = "2025-05-19T14:15:52.665Z" }, - { url = "https://files.pythonhosted.org/packages/fd/22/d2b95cbebbc2ada3be3812ea9287dcc9712d7f1a012fad041770afddb2ad/multidict-6.4.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d6b15c55721b1b115c5ba178c77104123745b1417527ad9641a4c5e2047450f0", size = 212168, upload-time = "2025-05-19T14:15:55.279Z" }, - { url = "https://files.pythonhosted.org/packages/4d/c5/62bfc0b2f9ce88326dbe7179f9824a939c6c7775b23b95de777267b9725c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a887b77f51d3d41e6e1a63cf3bc7ddf24de5939d9ff69441387dfefa58ac2e26", size = 217970, upload-time = "2025-05-19T14:15:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/79/74/977cea1aadc43ff1c75d23bd5bc4768a8fac98c14e5878d6ee8d6bab743c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:632a3bf8f1787f7ef7d3c2f68a7bde5be2f702906f8b5842ad6da9d974d0aab3", size = 226980, upload-time = "2025-05-19T14:15:58.313Z" }, - { url = "https://files.pythonhosted.org/packages/48/fc/cc4a1a2049df2eb84006607dc428ff237af38e0fcecfdb8a29ca47b1566c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a145c550900deb7540973c5cdb183b0d24bed6b80bf7bddf33ed8f569082535e", size = 220641, upload-time = "2025-05-19T14:15:59.866Z" }, - { url = "https://files.pythonhosted.org/packages/3b/6a/a7444d113ab918701988d4abdde373dbdfd2def7bd647207e2bf645c7eac/multidict-6.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc5d83c6619ca5c9672cb78b39ed8542f1975a803dee2cda114ff73cbb076edd", size = 221728, upload-time = "2025-05-19T14:16:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b0/fdf4c73ad1c55e0f4dbbf2aa59dd37037334091f9a4961646d2b7ac91a86/multidict-6.4.4-cp313-cp313t-win32.whl", hash = "sha256:3312f63261b9df49be9d57aaa6abf53a6ad96d93b24f9cc16cf979956355ce6e", size = 41913, upload-time = "2025-05-19T14:16:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/8e/92/27989ecca97e542c0d01d05a98a5ae12198a243a9ee12563a0313291511f/multidict-6.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:ba852168d814b2c73333073e1c7116d9395bea69575a01b0b3c89d2d5a87c8fb", size = 46112, upload-time = "2025-05-19T14:16:04.909Z" }, - { url = "https://files.pythonhosted.org/packages/84/5d/e17845bb0fa76334477d5de38654d27946d5b5d3695443987a094a71b440/multidict-6.4.4-py3-none-any.whl", hash = "sha256:bd4557071b561a8b3b6075c3ce93cf9bfb6182cb241805c3d66ced3b75eff4ac", size = 10481, upload-time = "2025-05-19T14:16:36.024Z" }, -] - -[[package]] -name = "nest-asyncio" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, -] - -[[package]] -name = "parsimonious" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7b/91/abdc50c4ef06fdf8d047f60ee777ca9b2a7885e1a9cea81343fbecda52d7/parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c", size = 52172, upload-time = "2022-09-03T17:01:17.004Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/0f/c8b64d9b54ea631fcad4e9e3c8dbe8c11bb32a623be94f22974c88e71eaf/parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f", size = 48427, upload-time = "2022-09-03T17:01:13.814Z" }, -] - -[[package]] -name = "propcache" -version = "0.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4e/ad52a7925ff01c1325653a730c7ec3175a23f948f08626a534133427dcff/propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3", size = 43133, upload-time = "2025-06-09T22:53:41.965Z" }, - { url = "https://files.pythonhosted.org/packages/63/7c/e9399ba5da7780871db4eac178e9c2e204c23dd3e7d32df202092a1ed400/propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3", size = 43039, upload-time = "2025-06-09T22:53:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/22/e1/58da211eb8fdc6fc854002387d38f415a6ca5f5c67c1315b204a5d3e9d7a/propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e", size = 201903, upload-time = "2025-06-09T22:53:44.872Z" }, - { url = "https://files.pythonhosted.org/packages/c4/0a/550ea0f52aac455cb90111c8bab995208443e46d925e51e2f6ebdf869525/propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220", size = 213362, upload-time = "2025-06-09T22:53:46.707Z" }, - { url = "https://files.pythonhosted.org/packages/5a/af/9893b7d878deda9bb69fcf54600b247fba7317761b7db11fede6e0f28bd0/propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb", size = 210525, upload-time = "2025-06-09T22:53:48.547Z" }, - { url = "https://files.pythonhosted.org/packages/7c/bb/38fd08b278ca85cde36d848091ad2b45954bc5f15cce494bb300b9285831/propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614", size = 198283, upload-time = "2025-06-09T22:53:50.067Z" }, - { url = "https://files.pythonhosted.org/packages/78/8c/9fe55bd01d362bafb413dfe508c48753111a1e269737fa143ba85693592c/propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50", size = 191872, upload-time = "2025-06-09T22:53:51.438Z" }, - { url = "https://files.pythonhosted.org/packages/54/14/4701c33852937a22584e08abb531d654c8bcf7948a8f87ad0a4822394147/propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339", size = 199452, upload-time = "2025-06-09T22:53:53.229Z" }, - { url = "https://files.pythonhosted.org/packages/16/44/447f2253d859602095356007657ee535e0093215ea0b3d1d6a41d16e5201/propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0", size = 191567, upload-time = "2025-06-09T22:53:54.541Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/e4756258749bb2d3b46defcff606a2f47410bab82be5824a67e84015b267/propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2", size = 193015, upload-time = "2025-06-09T22:53:56.44Z" }, - { url = "https://files.pythonhosted.org/packages/1e/df/e6d3c7574233164b6330b9fd697beeac402afd367280e6dc377bb99b43d9/propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7", size = 204660, upload-time = "2025-06-09T22:53:57.839Z" }, - { url = "https://files.pythonhosted.org/packages/b2/53/e4d31dd5170b4a0e2e6b730f2385a96410633b4833dc25fe5dffd1f73294/propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b", size = 206105, upload-time = "2025-06-09T22:53:59.638Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fe/74d54cf9fbe2a20ff786e5f7afcfde446588f0cf15fb2daacfbc267b866c/propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c", size = 196980, upload-time = "2025-06-09T22:54:01.071Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/c469c9d59dada8a7679625e0440b544fe72e99311a4679c279562051f6fc/propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70", size = 37679, upload-time = "2025-06-09T22:54:03.003Z" }, - { url = "https://files.pythonhosted.org/packages/38/35/07a471371ac89d418f8d0b699c75ea6dca2041fbda360823de21f6a9ce0a/propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9", size = 41459, upload-time = "2025-06-09T22:54:04.134Z" }, - { url = "https://files.pythonhosted.org/packages/80/8d/e8b436717ab9c2cfc23b116d2c297305aa4cd8339172a456d61ebf5669b8/propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be", size = 74207, upload-time = "2025-06-09T22:54:05.399Z" }, - { url = "https://files.pythonhosted.org/packages/d6/29/1e34000e9766d112171764b9fa3226fa0153ab565d0c242c70e9945318a7/propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f", size = 43648, upload-time = "2025-06-09T22:54:08.023Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/1ad5af0df781e76988897da39b5f086c2bf0f028b7f9bd1f409bb05b6874/propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9", size = 43496, upload-time = "2025-06-09T22:54:09.228Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ce/e96392460f9fb68461fabab3e095cb00c8ddf901205be4eae5ce246e5b7e/propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf", size = 217288, upload-time = "2025-06-09T22:54:10.466Z" }, - { url = "https://files.pythonhosted.org/packages/c5/2a/866726ea345299f7ceefc861a5e782b045545ae6940851930a6adaf1fca6/propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9", size = 227456, upload-time = "2025-06-09T22:54:11.828Z" }, - { url = "https://files.pythonhosted.org/packages/de/03/07d992ccb6d930398689187e1b3c718339a1c06b8b145a8d9650e4726166/propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66", size = 225429, upload-time = "2025-06-09T22:54:13.823Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/116ba39448753b1330f48ab8ba927dcd6cf0baea8a0ccbc512dfb49ba670/propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df", size = 213472, upload-time = "2025-06-09T22:54:15.232Z" }, - { url = "https://files.pythonhosted.org/packages/a6/85/f01f5d97e54e428885a5497ccf7f54404cbb4f906688a1690cd51bf597dc/propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2", size = 204480, upload-time = "2025-06-09T22:54:17.104Z" }, - { url = "https://files.pythonhosted.org/packages/e3/79/7bf5ab9033b8b8194cc3f7cf1aaa0e9c3256320726f64a3e1f113a812dce/propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7", size = 214530, upload-time = "2025-06-09T22:54:18.512Z" }, - { url = "https://files.pythonhosted.org/packages/31/0b/bd3e0c00509b609317df4a18e6b05a450ef2d9a963e1d8bc9c9415d86f30/propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95", size = 205230, upload-time = "2025-06-09T22:54:19.947Z" }, - { url = "https://files.pythonhosted.org/packages/7a/23/fae0ff9b54b0de4e819bbe559508da132d5683c32d84d0dc2ccce3563ed4/propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e", size = 206754, upload-time = "2025-06-09T22:54:21.716Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7f/ad6a3c22630aaa5f618b4dc3c3598974a72abb4c18e45a50b3cdd091eb2f/propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e", size = 218430, upload-time = "2025-06-09T22:54:23.17Z" }, - { url = "https://files.pythonhosted.org/packages/5b/2c/ba4f1c0e8a4b4c75910742f0d333759d441f65a1c7f34683b4a74c0ee015/propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf", size = 223884, upload-time = "2025-06-09T22:54:25.539Z" }, - { url = "https://files.pythonhosted.org/packages/88/e4/ebe30fc399e98572019eee82ad0caf512401661985cbd3da5e3140ffa1b0/propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e", size = 211480, upload-time = "2025-06-09T22:54:26.892Z" }, - { url = "https://files.pythonhosted.org/packages/96/0a/7d5260b914e01d1d0906f7f38af101f8d8ed0dc47426219eeaf05e8ea7c2/propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897", size = 37757, upload-time = "2025-06-09T22:54:28.241Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2d/89fe4489a884bc0da0c3278c552bd4ffe06a1ace559db5ef02ef24ab446b/propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39", size = 41500, upload-time = "2025-06-09T22:54:29.4Z" }, - { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, - { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, - { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, - { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, - { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, - { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, - { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, - { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, - { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, - { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, - { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, - { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, - { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, - { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, - { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, - { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, - { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, - { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, - { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, - { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, - { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, - { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, - { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, - { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, - { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, - { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, - { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, - { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, - { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, -] - -[[package]] -name = "pycparser" -version = "2.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, -] - -[[package]] -name = "pycryptodome" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" }, - { url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" }, - { url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" }, - { url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" }, - { url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" }, - { url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" }, - { url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" }, - { url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" }, - { url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" }, - { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, - { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, - { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, - { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, - { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, - { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, - { url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886, upload-time = "2025-05-17T17:21:20.614Z" }, - { url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151, upload-time = "2025-05-17T17:21:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461, upload-time = "2025-05-17T17:21:25.225Z" }, - { url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440, upload-time = "2025-05-17T17:21:27.991Z" }, - { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, -] - -[[package]] -name = "pydantic" -version = "2.10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/70/7e/fb60e6fee04d0ef8f15e4e01ff187a196fa976eb0f0ab524af4599e5754c/pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06", size = 762094, upload-time = "2024-12-18T17:09:24.84Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/26/3e1bbe954fde7ee22a6e7d31582c642aad9e84ffe4b5fb61e63b87cd326f/pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", size = 431765, upload-time = "2024-12-18T17:09:21.953Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.27.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443, upload-time = "2024-12-18T11:31:54.917Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938, upload-time = "2024-12-18T11:27:14.406Z" }, - { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684, upload-time = "2024-12-18T11:27:16.489Z" }, - { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169, upload-time = "2024-12-18T11:27:22.16Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227, upload-time = "2024-12-18T11:27:25.097Z" }, - { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695, upload-time = "2024-12-18T11:27:28.656Z" }, - { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662, upload-time = "2024-12-18T11:27:30.798Z" }, - { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370, upload-time = "2024-12-18T11:27:33.692Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813, upload-time = "2024-12-18T11:27:37.111Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287, upload-time = "2024-12-18T11:27:40.566Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414, upload-time = "2024-12-18T11:27:43.757Z" }, - { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301, upload-time = "2024-12-18T11:27:47.36Z" }, - { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685, upload-time = "2024-12-18T11:27:50.508Z" }, - { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876, upload-time = "2024-12-18T11:27:53.54Z" }, - { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421, upload-time = "2024-12-18T11:27:55.409Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998, upload-time = "2024-12-18T11:27:57.252Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167, upload-time = "2024-12-18T11:27:59.146Z" }, - { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071, upload-time = "2024-12-18T11:28:02.625Z" }, - { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244, upload-time = "2024-12-18T11:28:04.442Z" }, - { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470, upload-time = "2024-12-18T11:28:07.679Z" }, - { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291, upload-time = "2024-12-18T11:28:10.297Z" }, - { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613, upload-time = "2024-12-18T11:28:13.362Z" }, - { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355, upload-time = "2024-12-18T11:28:16.587Z" }, - { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661, upload-time = "2024-12-18T11:28:18.407Z" }, - { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261, upload-time = "2024-12-18T11:28:21.471Z" }, - { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361, upload-time = "2024-12-18T11:28:23.53Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484, upload-time = "2024-12-18T11:28:25.391Z" }, - { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102, upload-time = "2024-12-18T11:28:28.593Z" }, - { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127, upload-time = "2024-12-18T11:28:30.346Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340, upload-time = "2024-12-18T11:28:32.521Z" }, - { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900, upload-time = "2024-12-18T11:28:34.507Z" }, - { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177, upload-time = "2024-12-18T11:28:36.488Z" }, - { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046, upload-time = "2024-12-18T11:28:39.409Z" }, - { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386, upload-time = "2024-12-18T11:28:41.221Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060, upload-time = "2024-12-18T11:28:44.709Z" }, - { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870, upload-time = "2024-12-18T11:28:46.839Z" }, - { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822, upload-time = "2024-12-18T11:28:48.896Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364, upload-time = "2024-12-18T11:28:50.755Z" }, - { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303, upload-time = "2024-12-18T11:28:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064, upload-time = "2024-12-18T11:28:56.074Z" }, - { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046, upload-time = "2024-12-18T11:28:58.107Z" }, - { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092, upload-time = "2024-12-18T11:29:01.335Z" }, - { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709, upload-time = "2024-12-18T11:29:03.193Z" }, - { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273, upload-time = "2024-12-18T11:29:05.306Z" }, - { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027, upload-time = "2024-12-18T11:29:07.294Z" }, - { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888, upload-time = "2024-12-18T11:29:09.249Z" }, - { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738, upload-time = "2024-12-18T11:29:11.23Z" }, - { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138, upload-time = "2024-12-18T11:29:16.396Z" }, - { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025, upload-time = "2024-12-18T11:29:20.25Z" }, - { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633, upload-time = "2024-12-18T11:29:23.877Z" }, - { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404, upload-time = "2024-12-18T11:29:25.872Z" }, - { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130, upload-time = "2024-12-18T11:29:29.252Z" }, - { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946, upload-time = "2024-12-18T11:29:31.338Z" }, - { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387, upload-time = "2024-12-18T11:29:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453, upload-time = "2024-12-18T11:29:35.533Z" }, - { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186, upload-time = "2024-12-18T11:29:37.649Z" }, - { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159, upload-time = "2024-12-18T11:30:54.382Z" }, - { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331, upload-time = "2024-12-18T11:30:58.178Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467, upload-time = "2024-12-18T11:31:00.6Z" }, - { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797, upload-time = "2024-12-18T11:31:07.243Z" }, - { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839, upload-time = "2024-12-18T11:31:09.775Z" }, - { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861, upload-time = "2024-12-18T11:31:13.469Z" }, - { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582, upload-time = "2024-12-18T11:31:17.423Z" }, - { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985, upload-time = "2024-12-18T11:31:19.901Z" }, - { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715, upload-time = "2024-12-18T11:31:22.821Z" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234, upload-time = "2025-04-18T16:44:48.265Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356, upload-time = "2025-04-18T16:44:46.617Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, -] - -[[package]] -name = "pyjwt" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/d9/77/bd458a2e387e98f71de86dcc2ca2cab64489736004c80bc12b70da8b5488/python-dateutil-2.9.0.tar.gz", hash = "sha256:78e73e19c63f5b20ffa567001531680d939dc042bf7850431877645523c66709", size = 342990, upload-time = "2024-03-01T03:52:54.963Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/7f/98d6f9ca8b731506c85785bbb8806c01f5966a4df6d68c0d1cf3b16967e1/python_dateutil-2.9.0-py2.py3-none-any.whl", hash = "sha256:cbf2f1da5e6083ac2fbfd4da39a25f34312230110440f424a14c7558bb85d82e", size = 230495, upload-time = "2024-03-01T03:52:51.479Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920, upload-time = "2025-03-25T10:14:56.835Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256, upload-time = "2025-03-25T10:14:55.034Z" }, -] - -[[package]] -name = "python-multipart" -version = "0.0.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, -] - -[[package]] -name = "pyunormalize" -version = "16.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/08/568036c725dac746ecb267bb749ef930fb7907454fe69fce83c8557287fb/pyunormalize-16.0.0.tar.gz", hash = "sha256:2e1dfbb4a118154ae26f70710426a52a364b926c9191f764601f5a8cb12761f7", size = 49968, upload-time = "2024-09-17T17:08:18.245Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/f9/9d86e56f716e0651194a5ad58be9c146fcaf1de6901ac6f3cd3affeeb74e/pyunormalize-16.0.0-py3-none-any.whl", hash = "sha256:c647d95e5d1e2ea9a2f448d1d95d8518348df24eab5c3fd32d2b5c3300a49152", size = 49173, upload-time = "2024-09-17T17:08:17.078Z" }, -] - -[[package]] -name = "pywin32" -version = "310" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, - { url = "https://files.pythonhosted.org/packages/3c/84/1a8e3d7a15490d28a5d816efa229ecb4999cdc51a7c30dd8914f669093b8/pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213", size = 8522963, upload-time = "2025-03-17T00:55:50.969Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b1/68aa2986129fb1011dabbe95f0136f44509afaf072b12b8f815905a39f33/pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd", size = 8784284, upload-time = "2025-03-17T00:55:53.124Z" }, - { url = "https://files.pythonhosted.org/packages/b3/bd/d1592635992dd8db5bb8ace0551bc3a769de1ac8850200cfa517e72739fb/pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c", size = 9520748, upload-time = "2025-03-17T00:55:55.203Z" }, - { url = "https://files.pythonhosted.org/packages/90/b1/ac8b1ffce6603849eb45a91cf126c0fa5431f186c2e768bf56889c46f51c/pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582", size = 8455941, upload-time = "2025-03-17T00:55:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, - { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384, upload-time = "2025-03-17T00:56:04.383Z" }, - { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039, upload-time = "2025-03-17T00:56:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152, upload-time = "2025-03-17T00:56:07.819Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" }, - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, - { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669, upload-time = "2024-11-06T20:09:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684, upload-time = "2024-11-06T20:09:32.915Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589, upload-time = "2024-11-06T20:09:35.504Z" }, - { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121, upload-time = "2024-11-06T20:09:37.701Z" }, - { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275, upload-time = "2024-11-06T20:09:40.371Z" }, - { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257, upload-time = "2024-11-06T20:09:43.059Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727, upload-time = "2024-11-06T20:09:48.19Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667, upload-time = "2024-11-06T20:09:49.828Z" }, - { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963, upload-time = "2024-11-06T20:09:51.819Z" }, - { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700, upload-time = "2024-11-06T20:09:53.982Z" }, - { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592, upload-time = "2024-11-06T20:09:56.222Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929, upload-time = "2024-11-06T20:09:58.642Z" }, - { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213, upload-time = "2024-11-06T20:10:00.867Z" }, - { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734, upload-time = "2024-11-06T20:10:03.361Z" }, - { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052, upload-time = "2024-11-06T20:10:05.179Z" }, - { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, - { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, - { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, - { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, - { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, - { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, - { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, - { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, - { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, - { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, - { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, - { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, - { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, - { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, - { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, - { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, - { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, - { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, - { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, - { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, - { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, - { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, - { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, - { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, -] - -[[package]] -name = "requests" -version = "2.32.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, -] - -[[package]] -name = "rich" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, -] - -[[package]] -name = "rich-toolkit" -version = "0.14.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/7a/cb48b7024b247631ce39b1f14a0f1abedf311fb27b892b0e0387d809d4b5/rich_toolkit-0.14.7.tar.gz", hash = "sha256:6cca5a68850cc5778915f528eb785662c27ba3b4b2624612cce8340fa9701c5e", size = 104977, upload-time = "2025-05-27T15:48:09.377Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/2e/95fde5b818dac9a37683ea064096323f593442d0f6358923c5f635974393/rich_toolkit-0.14.7-py3-none-any.whl", hash = "sha256:def05cc6e0f1176d6263b6a26648f16a62c4563b277ca2f8538683acdba1e0da", size = 24870, upload-time = "2025-05-27T15:48:07.942Z" }, -] - -[[package]] -name = "rlp" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/2d/439b0728a92964a04d9c88ea1ca9ebb128893fbbd5834faa31f987f2fd4c/rlp-4.1.0.tar.gz", hash = "sha256:be07564270a96f3e225e2c107db263de96b5bc1f27722d2855bd3459a08e95a9", size = 33429, upload-time = "2025-02-04T22:05:59.089Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/fb/e4c0ced9893b84ac95b7181d69a9786ce5879aeb3bbbcbba80a164f85d6a/rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f", size = 19973, upload-time = "2025-02-04T22:05:57.05Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "solana" -version = "0.36.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "construct-typing" }, - { name = "httpx" }, - { name = "solders" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/05/92/c55cd7258699d8536d5f7ed6b8f9b3fbeebd340373f9ec493a67a934b6d2/solana-0.36.7.tar.gz", hash = "sha256:71def6a0e54ed38b232e8778493878f7621bed34aa932770189dcbce6e0390d3", size = 52344, upload-time = "2025-06-05T03:45:15.295Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/63/f2e252d9d41d38686b3596989423c892b361857f63f6124e51a1b8c15255/solana-0.36.7-py3-none-any.whl", hash = "sha256:7f3200d4c33c67aa23c39b1141fb9487a0a551edb26e8d3fe22d8156d2ed58df", size = 62490, upload-time = "2025-06-05T03:45:14.248Z" }, -] - -[[package]] -name = "solders" -version = "0.26.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jsonalias" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/87/96/23ad2e43e2676b78834064fe051e3db3ce1899336ecd4797f92fcd06113a/solders-0.26.0.tar.gz", hash = "sha256:057533892d6fa432c1ce1e2f5e3428802964666c10b57d3d1bcaab86295f046c", size = 181123, upload-time = "2025-02-18T19:23:57.734Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/ce/58bbb4d2c696e770cdd37e5f6dc2891ef7610c0c085bf400f9c42dcff1ad/solders-0.26.0-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:9c1a0ef5daa1a05934af5fb6e7e32eab7c42cede406c80067fee006f461ffc4a", size = 24344472, upload-time = "2025-02-18T19:23:30.273Z" }, - { url = "https://files.pythonhosted.org/packages/5a/35/221cec0e5900c2202833e7e9110c3405a2d96ed25e110b247f88b8782e29/solders-0.26.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1b964efbd7c0b38aef3bf4293ea5938517ae649b9a23e7cd147d889931775aab", size = 6674734, upload-time = "2025-02-18T19:23:35.15Z" }, - { url = "https://files.pythonhosted.org/packages/41/33/d17b7dbc92672351d59fc65cdb93b8924fc682deba09f6d96f25440187ae/solders-0.26.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36e6a769c5298b887b7588edb171d93709a89302aef75913fe893d11c653739d", size = 13472961, upload-time = "2025-02-18T19:23:38.582Z" }, - { url = "https://files.pythonhosted.org/packages/bb/e7/533367d815ab000587ccc37d89e154132f63347f02dcaaac5df72bd851de/solders-0.26.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b3cc55b971ec6ed1b4466fa7e7e09eee9baba492b8cd9e3204e3e1a0c5a0c4aa", size = 6886198, upload-time = "2025-02-18T19:23:41.453Z" }, - { url = "https://files.pythonhosted.org/packages/52/e0/ab41ab3df5fdf3b0e55613be93a43c2fe58b15a6ea8ceca26d3fba02e3c6/solders-0.26.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3e3973074c17265921c70246a17bcf80972c5b96a3e1ed7f5049101f11865092", size = 7319170, upload-time = "2025-02-18T19:23:43.758Z" }, - { url = "https://files.pythonhosted.org/packages/7d/34/5174ce592607e0ac020aff203217f2f113a55eec49af3db12945fea42d89/solders-0.26.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:59b52419452602f697e659199a25acacda8365971c376ef3c0687aecdd929e07", size = 7134977, upload-time = "2025-02-18T19:23:46.157Z" }, - { url = "https://files.pythonhosted.org/packages/ba/5e/822faabda0d473c29bdf59fe8869a411fd436af8ca6f5d6e89f7513f682f/solders-0.26.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5946ec3f2a340afa9ce5c2b8ab628ae1dea2ad2235551b1297cafdd7e3e5c51a", size = 6984222, upload-time = "2025-02-18T19:23:49.429Z" }, - { url = "https://files.pythonhosted.org/packages/23/e8/dc992f677762ea2de44b7768120d95887ef39fab10d6f29fb53e6a9882c1/solders-0.26.0-cp37-abi3-win_amd64.whl", hash = "sha256:5466616610170aab08c627ae01724e425bcf90085bc574da682e9f3bd954900b", size = 5480492, upload-time = "2025-02-18T19:23:53.285Z" }, -] - -[[package]] -name = "starlette" -version = "0.46.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, -] - -[[package]] -name = "toolz" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790, upload-time = "2024-10-04T16:17:04.001Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383, upload-time = "2024-10-04T16:17:01.533Z" }, -] - -[[package]] -name = "typer" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, -] - -[[package]] -name = "types-requests" -version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/7f/73b3a04a53b0fd2a911d4ec517940ecd6600630b559e4505cc7b68beb5a0/types_requests-2.32.4.20250611.tar.gz", hash = "sha256:741c8777ed6425830bf51e54d6abe245f79b4dcb9019f1622b773463946bf826", size = 23118, upload-time = "2025-06-11T03:11:41.272Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/ea/0be9258c5a4fa1ba2300111aa5a0767ee6d18eb3fd20e91616c12082284d/types_requests-2.32.4.20250611-py3-none-any.whl", hash = "sha256:ad2fe5d3b0cb3c2c902c8815a70e7fb2302c4b8c1f77bdcd738192cdb3878072", size = 20643, upload-time = "2025-06-11T03:11:40.186Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, -] - -[[package]] -name = "urllib3" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268, upload-time = "2024-12-22T07:47:30.032Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369, upload-time = "2024-12-22T07:47:28.074Z" }, -] - -[[package]] -name = "uvicorn" -version = "0.34.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631, upload-time = "2025-06-01T07:48:17.531Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431, upload-time = "2025-06-01T07:48:15.664Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, - { url = "https://files.pythonhosted.org/packages/35/5a/62d5800358a78cc25c8a6c72ef8b10851bdb8cca22e14d9c74167b7f86da/uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d", size = 801898, upload-time = "2024-10-14T23:37:22.663Z" }, - { url = "https://files.pythonhosted.org/packages/f3/96/63695e0ebd7da6c741ccd4489b5947394435e198a1382349c17b1146bb97/uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26", size = 3827735, upload-time = "2024-10-14T23:37:25.129Z" }, - { url = "https://files.pythonhosted.org/packages/61/e0/f0f8ec84979068ffae132c58c79af1de9cceeb664076beea86d941af1a30/uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb", size = 3825126, upload-time = "2024-10-14T23:37:27.59Z" }, - { url = "https://files.pythonhosted.org/packages/bf/fe/5e94a977d058a54a19df95f12f7161ab6e323ad49f4dabc28822eb2df7ea/uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f", size = 3705789, upload-time = "2024-10-14T23:37:29.385Z" }, - { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523, upload-time = "2024-10-14T23:37:32.048Z" }, - { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410, upload-time = "2024-10-14T23:37:33.612Z" }, - { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476, upload-time = "2024-10-14T23:37:36.11Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855, upload-time = "2024-10-14T23:37:37.683Z" }, - { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185, upload-time = "2024-10-14T23:37:40.226Z" }, - { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256, upload-time = "2024-10-14T23:37:42.839Z" }, - { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323, upload-time = "2024-10-14T23:37:45.337Z" }, - { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284, upload-time = "2024-10-14T23:37:47.833Z" }, - { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349, upload-time = "2024-10-14T23:37:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089, upload-time = "2024-10-14T23:37:51.703Z" }, - { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770, upload-time = "2024-10-14T23:37:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321, upload-time = "2024-10-14T23:37:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022, upload-time = "2024-10-14T23:37:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" }, - { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" }, - { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" }, - { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" }, - { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" }, - { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" }, -] - -[[package]] -name = "watchfiles" -version = "1.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/e2/8ed598c42057de7aa5d97c472254af4906ff0a59a66699d426fc9ef795d7/watchfiles-1.0.5.tar.gz", hash = "sha256:b7529b5dcc114679d43827d8c35a07c493ad6f083633d573d81c660abc5979e9", size = 94537, upload-time = "2025-04-08T10:36:26.722Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/4d/d02e6ea147bb7fff5fd109c694a95109612f419abed46548a930e7f7afa3/watchfiles-1.0.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5c40fe7dd9e5f81e0847b1ea64e1f5dd79dd61afbedb57759df06767ac719b40", size = 405632, upload-time = "2025-04-08T10:34:41.832Z" }, - { url = "https://files.pythonhosted.org/packages/60/31/9ee50e29129d53a9a92ccf1d3992751dc56fc3c8f6ee721be1c7b9c81763/watchfiles-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c0db396e6003d99bb2d7232c957b5f0b5634bbd1b24e381a5afcc880f7373fb", size = 395734, upload-time = "2025-04-08T10:34:44.236Z" }, - { url = "https://files.pythonhosted.org/packages/ad/8c/759176c97195306f028024f878e7f1c776bda66ccc5c68fa51e699cf8f1d/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b551d4fb482fc57d852b4541f911ba28957d051c8776e79c3b4a51eb5e2a1b11", size = 455008, upload-time = "2025-04-08T10:34:45.617Z" }, - { url = "https://files.pythonhosted.org/packages/55/1a/5e977250c795ee79a0229e3b7f5e3a1b664e4e450756a22da84d2f4979fe/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:830aa432ba5c491d52a15b51526c29e4a4b92bf4f92253787f9726fe01519487", size = 459029, upload-time = "2025-04-08T10:34:46.814Z" }, - { url = "https://files.pythonhosted.org/packages/e6/17/884cf039333605c1d6e296cf5be35fad0836953c3dfd2adb71b72f9dbcd0/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a16512051a822a416b0d477d5f8c0e67b67c1a20d9acecb0aafa3aa4d6e7d256", size = 488916, upload-time = "2025-04-08T10:34:48.571Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e0/bcb6e64b45837056c0a40f3a2db3ef51c2ced19fda38484fa7508e00632c/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe0cbc787770e52a96c6fda6726ace75be7f840cb327e1b08d7d54eadc3bc85", size = 523763, upload-time = "2025-04-08T10:34:50.268Z" }, - { url = "https://files.pythonhosted.org/packages/24/e9/f67e9199f3bb35c1837447ecf07e9830ec00ff5d35a61e08c2cd67217949/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d363152c5e16b29d66cbde8fa614f9e313e6f94a8204eaab268db52231fe5358", size = 502891, upload-time = "2025-04-08T10:34:51.419Z" }, - { url = "https://files.pythonhosted.org/packages/23/ed/a6cf815f215632f5c8065e9c41fe872025ffea35aa1f80499f86eae922db/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee32c9a9bee4d0b7bd7cbeb53cb185cf0b622ac761efaa2eba84006c3b3a614", size = 454921, upload-time = "2025-04-08T10:34:52.67Z" }, - { url = "https://files.pythonhosted.org/packages/92/4c/e14978599b80cde8486ab5a77a821e8a982ae8e2fcb22af7b0886a033ec8/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29c7fd632ccaf5517c16a5188e36f6612d6472ccf55382db6c7fe3fcccb7f59f", size = 631422, upload-time = "2025-04-08T10:34:53.985Z" }, - { url = "https://files.pythonhosted.org/packages/b2/1a/9263e34c3458f7614b657f974f4ee61fd72f58adce8b436e16450e054efd/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e637810586e6fe380c8bc1b3910accd7f1d3a9a7262c8a78d4c8fb3ba6a2b3d", size = 625675, upload-time = "2025-04-08T10:34:55.173Z" }, - { url = "https://files.pythonhosted.org/packages/96/1f/1803a18bd6ab04a0766386a19bcfe64641381a04939efdaa95f0e3b0eb58/watchfiles-1.0.5-cp310-cp310-win32.whl", hash = "sha256:cd47d063fbeabd4c6cae1d4bcaa38f0902f8dc5ed168072874ea11d0c7afc1ff", size = 277921, upload-time = "2025-04-08T10:34:56.318Z" }, - { url = "https://files.pythonhosted.org/packages/c2/3b/29a89de074a7d6e8b4dc67c26e03d73313e4ecf0d6e97e942a65fa7c195e/watchfiles-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:86c0df05b47a79d80351cd179893f2f9c1b1cae49d96e8b3290c7f4bd0ca0a92", size = 291526, upload-time = "2025-04-08T10:34:57.95Z" }, - { url = "https://files.pythonhosted.org/packages/39/f4/41b591f59021786ef517e1cdc3b510383551846703e03f204827854a96f8/watchfiles-1.0.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:237f9be419e977a0f8f6b2e7b0475ababe78ff1ab06822df95d914a945eac827", size = 405336, upload-time = "2025-04-08T10:34:59.359Z" }, - { url = "https://files.pythonhosted.org/packages/ae/06/93789c135be4d6d0e4f63e96eea56dc54050b243eacc28439a26482b5235/watchfiles-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0da39ff917af8b27a4bdc5a97ac577552a38aac0d260a859c1517ea3dc1a7c4", size = 395977, upload-time = "2025-04-08T10:35:00.522Z" }, - { url = "https://files.pythonhosted.org/packages/d2/db/1cd89bd83728ca37054512d4d35ab69b5f12b8aa2ac9be3b0276b3bf06cc/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cfcb3952350e95603f232a7a15f6c5f86c5375e46f0bd4ae70d43e3e063c13d", size = 455232, upload-time = "2025-04-08T10:35:01.698Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/d8a4d44ffe960517e487c9c04f77b06b8abf05eb680bed71c82b5f2cad62/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b2dddba7a4e6151384e252a5632efcaa9bc5d1c4b567f3cb621306b2ca9f63", size = 459151, upload-time = "2025-04-08T10:35:03.358Z" }, - { url = "https://files.pythonhosted.org/packages/6c/da/267a1546f26465dead1719caaba3ce660657f83c9d9c052ba98fb8856e13/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95cf944fcfc394c5f9de794ce581914900f82ff1f855326f25ebcf24d5397418", size = 489054, upload-time = "2025-04-08T10:35:04.561Z" }, - { url = "https://files.pythonhosted.org/packages/b1/31/33850dfd5c6efb6f27d2465cc4c6b27c5a6f5ed53c6fa63b7263cf5f60f6/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecf6cd9f83d7c023b1aba15d13f705ca7b7d38675c121f3cc4a6e25bd0857ee9", size = 523955, upload-time = "2025-04-08T10:35:05.786Z" }, - { url = "https://files.pythonhosted.org/packages/09/84/b7d7b67856efb183a421f1416b44ca975cb2ea6c4544827955dfb01f7dc2/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:852de68acd6212cd6d33edf21e6f9e56e5d98c6add46f48244bd479d97c967c6", size = 502234, upload-time = "2025-04-08T10:35:07.187Z" }, - { url = "https://files.pythonhosted.org/packages/71/87/6dc5ec6882a2254cfdd8b0718b684504e737273903b65d7338efaba08b52/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5730f3aa35e646103b53389d5bc77edfbf578ab6dab2e005142b5b80a35ef25", size = 454750, upload-time = "2025-04-08T10:35:08.859Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6c/3786c50213451a0ad15170d091570d4a6554976cf0df19878002fc96075a/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:18b3bd29954bc4abeeb4e9d9cf0b30227f0f206c86657674f544cb032296acd5", size = 631591, upload-time = "2025-04-08T10:35:10.64Z" }, - { url = "https://files.pythonhosted.org/packages/1b/b3/1427425ade4e359a0deacce01a47a26024b2ccdb53098f9d64d497f6684c/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ba5552a1b07c8edbf197055bc9d518b8f0d98a1c6a73a293bc0726dce068ed01", size = 625370, upload-time = "2025-04-08T10:35:12.412Z" }, - { url = "https://files.pythonhosted.org/packages/15/ba/f60e053b0b5b8145d682672024aa91370a29c5c921a88977eb565de34086/watchfiles-1.0.5-cp311-cp311-win32.whl", hash = "sha256:2f1fefb2e90e89959447bc0420fddd1e76f625784340d64a2f7d5983ef9ad246", size = 277791, upload-time = "2025-04-08T10:35:13.719Z" }, - { url = "https://files.pythonhosted.org/packages/50/ed/7603c4e164225c12c0d4e8700b64bb00e01a6c4eeea372292a3856be33a4/watchfiles-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:b6e76ceb1dd18c8e29c73f47d41866972e891fc4cc7ba014f487def72c1cf096", size = 291622, upload-time = "2025-04-08T10:35:15.071Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c2/99bb7c96b4450e36877fde33690ded286ff555b5a5c1d925855d556968a1/watchfiles-1.0.5-cp311-cp311-win_arm64.whl", hash = "sha256:266710eb6fddc1f5e51843c70e3bebfb0f5e77cf4f27129278c70554104d19ed", size = 283699, upload-time = "2025-04-08T10:35:16.732Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8c/4f0b9bdb75a1bfbd9c78fad7d8854369283f74fe7cf03eb16be77054536d/watchfiles-1.0.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5eb568c2aa6018e26da9e6c86f3ec3fd958cee7f0311b35c2630fa4217d17f2", size = 401511, upload-time = "2025-04-08T10:35:17.956Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4e/7e15825def77f8bd359b6d3f379f0c9dac4eb09dd4ddd58fd7d14127179c/watchfiles-1.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a04059f4923ce4e856b4b4e5e783a70f49d9663d22a4c3b3298165996d1377f", size = 392715, upload-time = "2025-04-08T10:35:19.202Z" }, - { url = "https://files.pythonhosted.org/packages/58/65/b72fb817518728e08de5840d5d38571466c1b4a3f724d190cec909ee6f3f/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e380c89983ce6e6fe2dd1e1921b9952fb4e6da882931abd1824c092ed495dec", size = 454138, upload-time = "2025-04-08T10:35:20.586Z" }, - { url = "https://files.pythonhosted.org/packages/3e/a4/86833fd2ea2e50ae28989f5950b5c3f91022d67092bfec08f8300d8b347b/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe43139b2c0fdc4a14d4f8d5b5d967f7a2777fd3d38ecf5b1ec669b0d7e43c21", size = 458592, upload-time = "2025-04-08T10:35:21.87Z" }, - { url = "https://files.pythonhosted.org/packages/38/7e/42cb8df8be9a37e50dd3a818816501cf7a20d635d76d6bd65aae3dbbff68/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee0822ce1b8a14fe5a066f93edd20aada932acfe348bede8aa2149f1a4489512", size = 487532, upload-time = "2025-04-08T10:35:23.143Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/13d26721c85d7f3df6169d8b495fcac8ab0dc8f0945ebea8845de4681dab/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0dbcb1c2d8f2ab6e0a81c6699b236932bd264d4cef1ac475858d16c403de74d", size = 522865, upload-time = "2025-04-08T10:35:24.702Z" }, - { url = "https://files.pythonhosted.org/packages/a1/0d/7f9ae243c04e96c5455d111e21b09087d0eeaf9a1369e13a01c7d3d82478/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2014a2b18ad3ca53b1f6c23f8cd94a18ce930c1837bd891262c182640eb40a6", size = 499887, upload-time = "2025-04-08T10:35:25.969Z" }, - { url = "https://files.pythonhosted.org/packages/8e/0f/a257766998e26aca4b3acf2ae97dff04b57071e991a510857d3799247c67/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6ae86d5cb647bf58f9f655fcf577f713915a5d69057a0371bc257e2553234", size = 454498, upload-time = "2025-04-08T10:35:27.353Z" }, - { url = "https://files.pythonhosted.org/packages/81/79/8bf142575a03e0af9c3d5f8bcae911ee6683ae93a625d349d4ecf4c8f7df/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1a7bac2bde1d661fb31f4d4e8e539e178774b76db3c2c17c4bb3e960a5de07a2", size = 630663, upload-time = "2025-04-08T10:35:28.685Z" }, - { url = "https://files.pythonhosted.org/packages/f1/80/abe2e79f610e45c63a70d271caea90c49bbf93eb00fa947fa9b803a1d51f/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ab626da2fc1ac277bbf752446470b367f84b50295264d2d313e28dc4405d663", size = 625410, upload-time = "2025-04-08T10:35:30.42Z" }, - { url = "https://files.pythonhosted.org/packages/91/6f/bc7fbecb84a41a9069c2c6eb6319f7f7df113adf113e358c57fc1aff7ff5/watchfiles-1.0.5-cp312-cp312-win32.whl", hash = "sha256:9f4571a783914feda92018ef3901dab8caf5b029325b5fe4558c074582815249", size = 277965, upload-time = "2025-04-08T10:35:32.023Z" }, - { url = "https://files.pythonhosted.org/packages/99/a5/bf1c297ea6649ec59e935ab311f63d8af5faa8f0b86993e3282b984263e3/watchfiles-1.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:360a398c3a19672cf93527f7e8d8b60d8275119c5d900f2e184d32483117a705", size = 291693, upload-time = "2025-04-08T10:35:33.225Z" }, - { url = "https://files.pythonhosted.org/packages/7f/7b/fd01087cc21db5c47e5beae507b87965db341cce8a86f9eb12bf5219d4e0/watchfiles-1.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:1a2902ede862969077b97523987c38db28abbe09fb19866e711485d9fbf0d417", size = 283287, upload-time = "2025-04-08T10:35:34.568Z" }, - { url = "https://files.pythonhosted.org/packages/c7/62/435766874b704f39b2fecd8395a29042db2b5ec4005bd34523415e9bd2e0/watchfiles-1.0.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0b289572c33a0deae62daa57e44a25b99b783e5f7aed81b314232b3d3c81a11d", size = 401531, upload-time = "2025-04-08T10:35:35.792Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a6/e52a02c05411b9cb02823e6797ef9bbba0bfaf1bb627da1634d44d8af833/watchfiles-1.0.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a056c2f692d65bf1e99c41045e3bdcaea3cb9e6b5a53dcaf60a5f3bd95fc9763", size = 392417, upload-time = "2025-04-08T10:35:37.048Z" }, - { url = "https://files.pythonhosted.org/packages/3f/53/c4af6819770455932144e0109d4854437769672d7ad897e76e8e1673435d/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9dca99744991fc9850d18015c4f0438865414e50069670f5f7eee08340d8b40", size = 453423, upload-time = "2025-04-08T10:35:38.357Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d1/8e88df58bbbf819b8bc5cfbacd3c79e01b40261cad0fc84d1e1ebd778a07/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:894342d61d355446d02cd3988a7326af344143eb33a2fd5d38482a92072d9563", size = 458185, upload-time = "2025-04-08T10:35:39.708Z" }, - { url = "https://files.pythonhosted.org/packages/ff/70/fffaa11962dd5429e47e478a18736d4e42bec42404f5ee3b92ef1b87ad60/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab44e1580924d1ffd7b3938e02716d5ad190441965138b4aa1d1f31ea0877f04", size = 486696, upload-time = "2025-04-08T10:35:41.469Z" }, - { url = "https://files.pythonhosted.org/packages/39/db/723c0328e8b3692d53eb273797d9a08be6ffb1d16f1c0ba2bdbdc2a3852c/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6f9367b132078b2ceb8d066ff6c93a970a18c3029cea37bfd7b2d3dd2e5db8f", size = 522327, upload-time = "2025-04-08T10:35:43.289Z" }, - { url = "https://files.pythonhosted.org/packages/cd/05/9fccc43c50c39a76b68343484b9da7b12d42d0859c37c61aec018c967a32/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2e55a9b162e06e3f862fb61e399fe9f05d908d019d87bf5b496a04ef18a970a", size = 499741, upload-time = "2025-04-08T10:35:44.574Z" }, - { url = "https://files.pythonhosted.org/packages/23/14/499e90c37fa518976782b10a18b18db9f55ea73ca14641615056f8194bb3/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0125f91f70e0732a9f8ee01e49515c35d38ba48db507a50c5bdcad9503af5827", size = 453995, upload-time = "2025-04-08T10:35:46.336Z" }, - { url = "https://files.pythonhosted.org/packages/61/d9/f75d6840059320df5adecd2c687fbc18960a7f97b55c300d20f207d48aef/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:13bb21f8ba3248386337c9fa51c528868e6c34a707f729ab041c846d52a0c69a", size = 629693, upload-time = "2025-04-08T10:35:48.161Z" }, - { url = "https://files.pythonhosted.org/packages/fc/17/180ca383f5061b61406477218c55d66ec118e6c0c51f02d8142895fcf0a9/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:839ebd0df4a18c5b3c1b890145b5a3f5f64063c2a0d02b13c76d78fe5de34936", size = 624677, upload-time = "2025-04-08T10:35:49.65Z" }, - { url = "https://files.pythonhosted.org/packages/bf/15/714d6ef307f803f236d69ee9d421763707899d6298d9f3183e55e366d9af/watchfiles-1.0.5-cp313-cp313-win32.whl", hash = "sha256:4a8ec1e4e16e2d5bafc9ba82f7aaecfeec990ca7cd27e84fb6f191804ed2fcfc", size = 277804, upload-time = "2025-04-08T10:35:51.093Z" }, - { url = "https://files.pythonhosted.org/packages/a8/b4/c57b99518fadf431f3ef47a610839e46e5f8abf9814f969859d1c65c02c7/watchfiles-1.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:f436601594f15bf406518af922a89dcaab416568edb6f65c4e5bbbad1ea45c11", size = 291087, upload-time = "2025-04-08T10:35:52.458Z" }, - { url = "https://files.pythonhosted.org/packages/1a/03/81f9fcc3963b3fc415cd4b0b2b39ee8cc136c42fb10a36acf38745e9d283/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f59b870db1f1ae5a9ac28245707d955c8721dd6565e7f411024fa374b5362d1d", size = 405947, upload-time = "2025-04-08T10:36:13.721Z" }, - { url = "https://files.pythonhosted.org/packages/54/97/8c4213a852feb64807ec1d380f42d4fc8bfaef896bdbd94318f8fd7f3e4e/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9475b0093767e1475095f2aeb1d219fb9664081d403d1dff81342df8cd707034", size = 397276, upload-time = "2025-04-08T10:36:15.131Z" }, - { url = "https://files.pythonhosted.org/packages/78/12/d4464d19860cb9672efa45eec1b08f8472c478ed67dcd30647c51ada7aef/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc533aa50664ebd6c628b2f30591956519462f5d27f951ed03d6c82b2dfd9965", size = 455550, upload-time = "2025-04-08T10:36:16.635Z" }, - { url = "https://files.pythonhosted.org/packages/90/fb/b07bcdf1034d8edeaef4c22f3e9e3157d37c5071b5f9492ffdfa4ad4bed7/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed1cd825158dcaae36acce7b2db33dcbfd12b30c34317a88b8ed80f0541cc57", size = 455542, upload-time = "2025-04-08T10:36:18.655Z" }, -] - -[[package]] -name = "web3" -version = "7.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "eth-abi" }, - { name = "eth-account" }, - { name = "eth-hash", extra = ["pycryptodome"] }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "pyunormalize" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "requests" }, - { name = "types-requests" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/19/c1e213dd87ead2ace55ff1dd179df6050bcf5d9006440c9153969c7d6863/web3-7.10.0.tar.gz", hash = "sha256:0cace05ea14f800a4497649ecd99332ca4e85c8a90ea577e05ae909cb08902b9", size = 2193725, upload-time = "2025-03-27T17:02:27.919Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/c5/a8e25e3ff51c7cd6d2bdecf75da2afb2923b29eba28e5dfe4fde72ad2322/web3-7.10.0-py3-none-any.whl", hash = "sha256:06fcab920554450e9f7d108da5e6b9d29c0d1a981a59a5551cc82d2cb2233b34", size = 1365880, upload-time = "2025-03-27T17:02:25.04Z" }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, - { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, - { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, - { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, - { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, - { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, - { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, - { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, - { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - -[[package]] -name = "werkzeug" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, -] - -[[package]] -name = "x402" -version = "1.0.0" -source = { editable = "../../../../python/legacy" } -dependencies = [ - { name = "eth-account" }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "fastapi", extra = ["standard"] }, - { name = "flask" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "web3" }, -] - -[package.metadata] -requires-dist = [ - { name = "eth-account", specifier = ">=0.13.7" }, - { name = "eth-typing", specifier = ">=4.0.0" }, - { name = "eth-utils", specifier = ">=3.0.0" }, - { name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" }, - { name = "flask", specifier = ">=3.0.0" }, - { name = "pydantic", specifier = ">=2.10.3" }, - { name = "pydantic-settings", specifier = ">=2.2.1" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "web3", specifier = ">=6.0.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.5" }, - { name = "pytest-asyncio", specifier = ">=1.0.0" }, - { name = "ruff", specifier = ">=0.11.9" }, -] - -[[package]] -name = "yarl" -version = "1.20.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/65/7fed0d774abf47487c64be14e9223749468922817b5e8792b8a64792a1bb/yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4", size = 132910, upload-time = "2025-06-10T00:42:31.108Z" }, - { url = "https://files.pythonhosted.org/packages/8a/7b/988f55a52da99df9e56dc733b8e4e5a6ae2090081dc2754fc8fd34e60aa0/yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a", size = 90644, upload-time = "2025-06-10T00:42:33.851Z" }, - { url = "https://files.pythonhosted.org/packages/f7/de/30d98f03e95d30c7e3cc093759982d038c8833ec2451001d45ef4854edc1/yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed", size = 89322, upload-time = "2025-06-10T00:42:35.688Z" }, - { url = "https://files.pythonhosted.org/packages/e0/7a/f2f314f5ebfe9200724b0b748de2186b927acb334cf964fd312eb86fc286/yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e", size = 323786, upload-time = "2025-06-10T00:42:37.817Z" }, - { url = "https://files.pythonhosted.org/packages/15/3f/718d26f189db96d993d14b984ce91de52e76309d0fd1d4296f34039856aa/yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73", size = 319627, upload-time = "2025-06-10T00:42:39.937Z" }, - { url = "https://files.pythonhosted.org/packages/a5/76/8fcfbf5fa2369157b9898962a4a7d96764b287b085b5b3d9ffae69cdefd1/yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e", size = 339149, upload-time = "2025-06-10T00:42:42.627Z" }, - { url = "https://files.pythonhosted.org/packages/3c/95/d7fc301cc4661785967acc04f54a4a42d5124905e27db27bb578aac49b5c/yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8", size = 333327, upload-time = "2025-06-10T00:42:44.842Z" }, - { url = "https://files.pythonhosted.org/packages/65/94/e21269718349582eee81efc5c1c08ee71c816bfc1585b77d0ec3f58089eb/yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23", size = 326054, upload-time = "2025-06-10T00:42:47.149Z" }, - { url = "https://files.pythonhosted.org/packages/32/ae/8616d1f07853704523519f6131d21f092e567c5af93de7e3e94b38d7f065/yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70", size = 315035, upload-time = "2025-06-10T00:42:48.852Z" }, - { url = "https://files.pythonhosted.org/packages/48/aa/0ace06280861ef055855333707db5e49c6e3a08840a7ce62682259d0a6c0/yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb", size = 338962, upload-time = "2025-06-10T00:42:51.024Z" }, - { url = "https://files.pythonhosted.org/packages/20/52/1e9d0e6916f45a8fb50e6844f01cb34692455f1acd548606cbda8134cd1e/yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2", size = 335399, upload-time = "2025-06-10T00:42:53.007Z" }, - { url = "https://files.pythonhosted.org/packages/f2/65/60452df742952c630e82f394cd409de10610481d9043aa14c61bf846b7b1/yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30", size = 338649, upload-time = "2025-06-10T00:42:54.964Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f5/6cd4ff38dcde57a70f23719a838665ee17079640c77087404c3d34da6727/yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309", size = 358563, upload-time = "2025-06-10T00:42:57.28Z" }, - { url = "https://files.pythonhosted.org/packages/d1/90/c42eefd79d0d8222cb3227bdd51b640c0c1d0aa33fe4cc86c36eccba77d3/yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24", size = 357609, upload-time = "2025-06-10T00:42:59.055Z" }, - { url = "https://files.pythonhosted.org/packages/03/c8/cea6b232cb4617514232e0f8a718153a95b5d82b5290711b201545825532/yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13", size = 350224, upload-time = "2025-06-10T00:43:01.248Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a3/eaa0ab9712f1f3d01faf43cf6f1f7210ce4ea4a7e9b28b489a2261ca8db9/yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8", size = 81753, upload-time = "2025-06-10T00:43:03.486Z" }, - { url = "https://files.pythonhosted.org/packages/8f/34/e4abde70a9256465fe31c88ed02c3f8502b7b5dead693a4f350a06413f28/yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16", size = 86817, upload-time = "2025-06-10T00:43:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b1/18/893b50efc2350e47a874c5c2d67e55a0ea5df91186b2a6f5ac52eff887cd/yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e", size = 133833, upload-time = "2025-06-10T00:43:07.393Z" }, - { url = "https://files.pythonhosted.org/packages/89/ed/b8773448030e6fc47fa797f099ab9eab151a43a25717f9ac043844ad5ea3/yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b", size = 91070, upload-time = "2025-06-10T00:43:09.538Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e3/409bd17b1e42619bf69f60e4f031ce1ccb29bd7380117a55529e76933464/yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b", size = 89818, upload-time = "2025-06-10T00:43:11.575Z" }, - { url = "https://files.pythonhosted.org/packages/f8/77/64d8431a4d77c856eb2d82aa3de2ad6741365245a29b3a9543cd598ed8c5/yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4", size = 347003, upload-time = "2025-06-10T00:43:14.088Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d2/0c7e4def093dcef0bd9fa22d4d24b023788b0a33b8d0088b51aa51e21e99/yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1", size = 336537, upload-time = "2025-06-10T00:43:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f3/fc514f4b2cf02cb59d10cbfe228691d25929ce8f72a38db07d3febc3f706/yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833", size = 362358, upload-time = "2025-06-10T00:43:18.704Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6d/a313ac8d8391381ff9006ac05f1d4331cee3b1efaa833a53d12253733255/yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d", size = 357362, upload-time = "2025-06-10T00:43:20.888Z" }, - { url = "https://files.pythonhosted.org/packages/00/70/8f78a95d6935a70263d46caa3dd18e1f223cf2f2ff2037baa01a22bc5b22/yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8", size = 348979, upload-time = "2025-06-10T00:43:23.169Z" }, - { url = "https://files.pythonhosted.org/packages/cb/05/42773027968968f4f15143553970ee36ead27038d627f457cc44bbbeecf3/yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf", size = 337274, upload-time = "2025-06-10T00:43:27.111Z" }, - { url = "https://files.pythonhosted.org/packages/05/be/665634aa196954156741ea591d2f946f1b78ceee8bb8f28488bf28c0dd62/yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e", size = 363294, upload-time = "2025-06-10T00:43:28.96Z" }, - { url = "https://files.pythonhosted.org/packages/eb/90/73448401d36fa4e210ece5579895731f190d5119c4b66b43b52182e88cd5/yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389", size = 358169, upload-time = "2025-06-10T00:43:30.701Z" }, - { url = "https://files.pythonhosted.org/packages/c3/b0/fce922d46dc1eb43c811f1889f7daa6001b27a4005587e94878570300881/yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f", size = 362776, upload-time = "2025-06-10T00:43:32.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/0d/b172628fce039dae8977fd22caeff3eeebffd52e86060413f5673767c427/yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845", size = 381341, upload-time = "2025-06-10T00:43:34.543Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9b/5b886d7671f4580209e855974fe1cecec409aa4a89ea58b8f0560dc529b1/yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1", size = 379988, upload-time = "2025-06-10T00:43:36.489Z" }, - { url = "https://files.pythonhosted.org/packages/73/be/75ef5fd0fcd8f083a5d13f78fd3f009528132a1f2a1d7c925c39fa20aa79/yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e", size = 371113, upload-time = "2025-06-10T00:43:38.592Z" }, - { url = "https://files.pythonhosted.org/packages/50/4f/62faab3b479dfdcb741fe9e3f0323e2a7d5cd1ab2edc73221d57ad4834b2/yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773", size = 81485, upload-time = "2025-06-10T00:43:41.038Z" }, - { url = "https://files.pythonhosted.org/packages/f0/09/d9c7942f8f05c32ec72cd5c8e041c8b29b5807328b68b4801ff2511d4d5e/yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e", size = 86686, upload-time = "2025-06-10T00:43:42.692Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, - { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, - { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, - { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, - { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, - { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, - { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, - { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, - { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, - { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, - { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, - { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, - { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, - { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, - { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, - { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, - { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, - { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, - { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, - { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, - { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, - { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, - { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, - { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, - { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, - { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, - { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, - { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, - { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, - { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, - { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, - { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, - { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, - { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, - { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, - { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, - { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, -] diff --git a/examples/python/legacy/fullstack/fastapi/.env-local b/examples/python/legacy/fullstack/fastapi/.env-local deleted file mode 100644 index afb633e950..0000000000 --- a/examples/python/legacy/fullstack/fastapi/.env-local +++ /dev/null @@ -1,5 +0,0 @@ -NETWORK=base-sepolia -ADDRESS= - -# Optional: -CDP_CLIENT_KEY= \ No newline at end of file diff --git a/examples/python/legacy/fullstack/fastapi/README.md b/examples/python/legacy/fullstack/fastapi/README.md deleted file mode 100644 index b6234c9059..0000000000 --- a/examples/python/legacy/fullstack/fastapi/README.md +++ /dev/null @@ -1,54 +0,0 @@ -# x402 fastapi Example Server - -This is an example FastAPI server that demonstrates how to use the x402 `fastapi` middleware to implement paywall functionality in your API endpoints. - -## Prerequisites - -- Python 3.10+ -- A valid Ethereum address for receiving payments -- Optional: CDP API Client Key (requires a Coinbase Developer Platform account) - -## Setup - -1. Copy `.env-local` to `.env` and add your Ethereum address to receive payments: - -```bash -cp .env-local .env -``` - -2. Install dependencies: - -```bash -uv sync -``` - -3. Run the server: - -```bash -uv run python main.py -``` - -The server will start on http://localhost:4021 - -## Extending the Example - -To add more paid endpoints, follow this pattern: - -```python -# First, configure the payment middleware with your routes -app.middleware("http")( - require_payment( - path="/your-endpoint", - price="$0.10", - pay_to_address=ADDRESS, - network=NETWORK, - ) -) - -# Then define your routes as normal -@app.get("/your-endpoint") -async def your_endpoint(): - return { - # Your response data - } -``` diff --git a/examples/python/legacy/fullstack/fastapi/main.py b/examples/python/legacy/fullstack/fastapi/main.py deleted file mode 100644 index e3914e0e14..0000000000 --- a/examples/python/legacy/fullstack/fastapi/main.py +++ /dev/null @@ -1,50 +0,0 @@ -import os - -from dotenv import load_dotenv -from fastapi import FastAPI -from fastapi.responses import FileResponse -from fastapi.staticfiles import StaticFiles -from x402.fastapi.middleware import require_payment -from x402.types import PaywallConfig - -# Load environment variables -load_dotenv() - -# Get configuration from environment -NETWORK = os.getenv("NETWORK", "base-sepolia") -ADDRESS = os.getenv("ADDRESS") -CDP_CLIENT_KEY = os.getenv("CDP_CLIENT_KEY") - -if not ADDRESS: - raise ValueError("Missing required environment variables") - -app = FastAPI() - -# Mount static files directory -app.mount("/static", StaticFiles(directory="static"), name="static") - -# Apply payment middleware to browser-accessible paywalled routes -app.middleware("http")( - require_payment( - price="$0.01", - pay_to_address=ADDRESS, - path="/premium/*", - network=NETWORK, - paywall_config=PaywallConfig( - cdp_client_key=CDP_CLIENT_KEY or "", - app_name="x402 Python Example", - app_logo="/static/x402.png", - ), - ) -) - - -@app.get("/premium/content") -async def get_premium_content() -> FileResponse: - return FileResponse("static/premium.html") - - -if __name__ == "__main__": - import uvicorn - - uvicorn.run(app, host="0.0.0.0", port=4021) diff --git a/examples/python/legacy/fullstack/fastapi/pyproject.toml b/examples/python/legacy/fullstack/fastapi/pyproject.toml deleted file mode 100644 index ea47271053..0000000000 --- a/examples/python/legacy/fullstack/fastapi/pyproject.toml +++ /dev/null @@ -1,27 +0,0 @@ -[project] -name = "x402-fastapi-example" -version = "0.1.0" -description = "Example of using a fastapi server with x402 middleware" -requires-python = ">=3.10" -dependencies = [ - "x402", - "fastapi>=0.109.0", - "uvicorn>=0.27.0", - "python-dotenv>=1.0.0" -] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -packages = ["."] - -[tool.hatch.metadata] -allow-direct-references = true - -[tool.uv] -package = false - -[tool.uv.sources] -x402 = { path = "../../../../../python/legacy", editable = true } diff --git a/examples/python/legacy/fullstack/fastapi/static/premium.html b/examples/python/legacy/fullstack/fastapi/static/premium.html deleted file mode 100644 index e28735d6b8..0000000000 --- a/examples/python/legacy/fullstack/fastapi/static/premium.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - Protected Content - - - - -

-
-

Premium Content

-

- Your payment was successful! Enjoy this banger song. -

- - -
-
- - diff --git a/examples/python/legacy/fullstack/fastapi/static/x402.png b/examples/python/legacy/fullstack/fastapi/static/x402.png deleted file mode 100644 index 88254d78cd..0000000000 Binary files a/examples/python/legacy/fullstack/fastapi/static/x402.png and /dev/null differ diff --git a/examples/python/legacy/fullstack/fastapi/uv.lock b/examples/python/legacy/fullstack/fastapi/uv.lock deleted file mode 100644 index f095f6960b..0000000000 --- a/examples/python/legacy/fullstack/fastapi/uv.lock +++ /dev/null @@ -1,1975 +0,0 @@ -version = 1 -revision = 2 -requires-python = ">=3.10" - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, -] - -[[package]] -name = "aiohttp" -version = "3.12.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f2/84/ea27e6ad14747d8c51afe201fb88a5c8282b6278256d30a6f71f730add88/aiohttp-3.12.12.tar.gz", hash = "sha256:05875595d2483d96cb61fa9f64e75262d7ac6251a7e3c811d8e26f7d721760bd", size = 7818643, upload-time = "2025-06-10T05:22:00.247Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/d9/cfde93b9cb75253c716b8b1c773565209e3d4dd0772dd3ce3a2adcaa4639/aiohttp-3.12.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6f25e9d274d6abbb15254f76f100c3984d6b9ad6e66263cc60a465dd5c7e48f5", size = 702071, upload-time = "2025-06-10T05:18:23.986Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/46e38b8bc0bc645317deec32612af922ad9bafd85a1df255a67c2f2305f6/aiohttp-3.12.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b8ec3c1a1c13d24941b5b913607e57b9364e4c0ea69d5363181467492c4b2ba6", size = 478436, upload-time = "2025-06-10T05:18:28.411Z" }, - { url = "https://files.pythonhosted.org/packages/8f/47/9c83db7f02ca71eb99a707ee13657fc24ba703b9babc59000c1f58ac1198/aiohttp-3.12.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81ef2f9253c327c211cb7b06ea2edd90e637cf21c347b894d540466b8d304e08", size = 466213, upload-time = "2025-06-10T05:18:30.706Z" }, - { url = "https://files.pythonhosted.org/packages/31/fe/4690c112e269e06c9182c32eeb43f3a95c4f203fdb095502717327993b80/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28ded835c3663fd41c9ad44685811b11e34e6ac9a7516a30bfce13f6abba4496", size = 1648258, upload-time = "2025-06-10T05:18:32.498Z" }, - { url = "https://files.pythonhosted.org/packages/c8/1f/dacca6c7bbe69c77d8535d7a672478803e7078cc20fd9993fe09aa5be880/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a4b78ccf254fc10605b263996949a94ca3f50e4f9100e05137d6583e266b711e", size = 1622316, upload-time = "2025-06-10T05:18:34.357Z" }, - { url = "https://files.pythonhosted.org/packages/ff/65/5ef47708f70524fcdecda735e0aea06e0feb7b8679e976e9bd1e7900f4c0/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f4a5af90d5232c41bb857568fe7d11ed84408653ec9da1ff999cc30258b9bd1", size = 1694723, upload-time = "2025-06-10T05:18:36.858Z" }, - { url = "https://files.pythonhosted.org/packages/18/62/ab32bfa59f61292e4096c383316863e10001eec30e5b4b314856ed7156e2/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffa5205c2f53f1120e93fdf2eca41b0f6344db131bc421246ee82c1e1038a14a", size = 1737037, upload-time = "2025-06-10T05:18:39.663Z" }, - { url = "https://files.pythonhosted.org/packages/c1/b9/8b8f793081311e4f63aea63003a519064048e406c627c0454d6ed09dbc99/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68301660f0d7a3eddfb84f959f78a8f9db98c76a49b5235508fa16edaad0f7c", size = 1641701, upload-time = "2025-06-10T05:18:41.666Z" }, - { url = "https://files.pythonhosted.org/packages/1a/5c/72f510d42d626463b526345dcb8d14b390de89a9ba27a4717b518460bcd4/aiohttp-3.12.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db874d3b0c92fdbb553751af9d2733b378c25cc83cd9dfba87f12fafd2dc9cd5", size = 1581824, upload-time = "2025-06-10T05:18:44.136Z" }, - { url = "https://files.pythonhosted.org/packages/61/6f/9378c9e1543d1c800ca040e21cd333b8f923ed051ae82b5a49ad96a6ac71/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5e53cf9c201b45838a2d07b1f2d5f7fec9666db7979240002ce64f9b8a1e0cf2", size = 1625674, upload-time = "2025-06-10T05:18:46.716Z" }, - { url = "https://files.pythonhosted.org/packages/bb/85/4eef9bd52b497a405c88469cc099f4d15d33b149b5746ca4ef8ec6ab6388/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:8687cc5f32b4e328c233acd387d09a1b477007896b2f03c1c823a0fd05f63883", size = 1636460, upload-time = "2025-06-10T05:18:49.305Z" }, - { url = "https://files.pythonhosted.org/packages/56/59/d8e954830b375fd658843cf7d88d27ca5e38dd5fcbfe62db3d1ba415d0fe/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ee537ad29de716a3d8dc46c609908de0c25ffeebf93cd94a03d64cdc07d66d0", size = 1611912, upload-time = "2025-06-10T05:18:51.694Z" }, - { url = "https://files.pythonhosted.org/packages/c3/5d/d0096a02f0515a38dff67db42d966273a12d17fc895e91466bfb4ab3875e/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:411f821be5af6af11dc5bed6c6c1dc6b6b25b91737d968ec2756f9baa75e5f9b", size = 1691498, upload-time = "2025-06-10T05:18:54.36Z" }, - { url = "https://files.pythonhosted.org/packages/87/8d/d3a02397a6345c06623ae4648e2aef18fced858510b4a89d7262cfa4c683/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f90319d94cf5f9786773237f24bd235a7b5959089f1af8ec1154580a3434b503", size = 1714737, upload-time = "2025-06-10T05:18:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/a9/40/b81000bf07c96db878703ea3dc561393d82441597729910459a8e06acc9a/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:73b148e606f34e9d513c451fd65efe1091772659ca5703338a396a99f60108ff", size = 1643078, upload-time = "2025-06-10T05:18:59.33Z" }, - { url = "https://files.pythonhosted.org/packages/41/e5/31830642ce2c6d3dba74ed8a94933213df5e1651c1e8b4efc81cc88105ab/aiohttp-3.12.12-cp310-cp310-win32.whl", hash = "sha256:d40e7bfd577fdc8a92b72f35dfbdd3ec90f1bc8a72a42037fefe34d4eca2d4a1", size = 427517, upload-time = "2025-06-10T05:19:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/55/9d/a4e5379d44679e5f8d7d7ebecb0dae8cafab95176c4e753da6bc4b4aebb5/aiohttp-3.12.12-cp310-cp310-win_amd64.whl", hash = "sha256:65c7804a2343893d6dea9fce69811aea0a9ac47f68312cf2e3ee1668cd9a387f", size = 450725, upload-time = "2025-06-10T05:19:03.874Z" }, - { url = "https://files.pythonhosted.org/packages/47/1f/b1b66e05dc3066a9ba7862d50e2e95b3871db82ccf9652568845f353eeba/aiohttp-3.12.12-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:38823fe0d8bc059b3eaedb263fe427d887c7032e72b4ef92c472953285f0e658", size = 709385, upload-time = "2025-06-10T05:19:05.763Z" }, - { url = "https://files.pythonhosted.org/packages/43/e6/3230e42af16438b450b1e193c537fd3d2d31771dafda3c2105a8d11af707/aiohttp-3.12.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:10237f2c34711215d04ed21da63852ce023608299554080a45c576215d9df81c", size = 481660, upload-time = "2025-06-10T05:19:08.332Z" }, - { url = "https://files.pythonhosted.org/packages/06/ba/cfa91fe5cc262535e1175b1522d8fcc09f9d6ad18b85241f4ee3be1d780f/aiohttp-3.12.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:563ec477c0dc6d56fc7f943a3475b5acdb399c7686c30f5a98ada24bb7562c7a", size = 469924, upload-time = "2025-06-10T05:19:10.342Z" }, - { url = "https://files.pythonhosted.org/packages/9a/f0/5c706cfddd4769b55c0cda466aa6034412d39e416f0b30dda81c4a24616f/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3d05c46a61aca7c47df74afff818bc06a251ab95d95ff80b53665edfe1e0bdf", size = 1740116, upload-time = "2025-06-10T05:19:12.783Z" }, - { url = "https://files.pythonhosted.org/packages/4d/9f/04dba2e1c8bee53c3c623d11a1f947c9e2712500f734dc0dfd06daad32ec/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:277c882916759b4a6b6dc7e2ceb124aad071b3c6456487808d9ab13e1b448d57", size = 1688784, upload-time = "2025-06-10T05:19:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/df/24/19d6d4c41fbf8304fe7c111fcc701e0aa5a2232ee3ac16272677a11f9cfe/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:216abf74b324b0f4e67041dd4fb2819613909a825904f8a51701fbcd40c09cd7", size = 1787575, upload-time = "2025-06-10T05:19:18.586Z" }, - { url = "https://files.pythonhosted.org/packages/0c/59/01f4c55a1f91ad3b5255b2498b3a22362a3fe6ee9bc9ba1af3cc668244da/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65d6cefad286459b68e7f867b9586a821fb7f121057b88f02f536ef570992329", size = 1826621, upload-time = "2025-06-10T05:19:21.284Z" }, - { url = "https://files.pythonhosted.org/packages/55/85/6357166918ff5025602a7cc41332c1ae7a5b57f2fe3da4d755ae30f24bd0/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feaaaff61966b5f4b4eae0b79fc79427f49484e4cfa5ab7d138ecd933ab540a8", size = 1729082, upload-time = "2025-06-10T05:19:23.307Z" }, - { url = "https://files.pythonhosted.org/packages/e3/ca/de3b5ccd5a2aa9352f6ec6f446565f6e1601ebb54860c94c686a9ff76660/aiohttp-3.12.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a05917780b7cad1755784b16cfaad806bc16029a93d15f063ca60185b7d9ba05", size = 1666159, upload-time = "2025-06-10T05:19:25.929Z" }, - { url = "https://files.pythonhosted.org/packages/d1/69/a1006021a1d3244c0872ee75cd8da150e0098b3b2ec6945c225754d11a60/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:082c5ec6d262c1b2ee01c63f4fb9152c17f11692bf16f0f100ad94a7a287d456", size = 1714433, upload-time = "2025-06-10T05:19:28.044Z" }, - { url = "https://files.pythonhosted.org/packages/d2/2a/15aa1179e9fbdd0d17cdf117b4296dedad098abb5a93f8e9c8ab4626f6ea/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:b265a3a8b379b38696ac78bdef943bdc4f4a5d6bed1a3fb5c75c6bab1ecea422", size = 1709590, upload-time = "2025-06-10T05:19:30.165Z" }, - { url = "https://files.pythonhosted.org/packages/a2/f0/95ed9e21250815f1d1a0cd3e868a3f39400a16010ae59f19ddd4ccc4e787/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2e0f2e208914ecbc4b2a3b7b4daa759d0c587d9a0b451bb0835ac47fae7fa735", size = 1689776, upload-time = "2025-06-10T05:19:32.965Z" }, - { url = "https://files.pythonhosted.org/packages/81/4d/370ecc133c648c98a85445f2d331c1272859c89cd52c29a293015bc352c7/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9923b025845b72f64d167bca221113377c8ffabd0a351dc18fb839d401ee8e22", size = 1783378, upload-time = "2025-06-10T05:19:35.14Z" }, - { url = "https://files.pythonhosted.org/packages/a8/86/414e3dae7e07caf6b02cd75d7148d0d8673d4c5077f407be3627d6e33fac/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1ebb213445900527831fecc70e185bf142fdfe5f2a691075f22d63c65ee3c35a", size = 1803841, upload-time = "2025-06-10T05:19:37.41Z" }, - { url = "https://files.pythonhosted.org/packages/88/df/486f10df681cd1a8c898acc8dc2edbd46ffb088b886757b71ae362bf44d3/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6fc369fb273a8328077d37798b77c1e65676709af5c182cb74bd169ca9defe81", size = 1716896, upload-time = "2025-06-10T05:19:40.172Z" }, - { url = "https://files.pythonhosted.org/packages/07/1e/1cacaf5d838869432e96ece1580d0b51494ebb66351f0e8118b74b38d2f0/aiohttp-3.12.12-cp311-cp311-win32.whl", hash = "sha256:58ecd10fda6a44c311cd3742cfd2aea8c4c600338e9f27cb37434d9f5ca9ddaa", size = 427030, upload-time = "2025-06-10T05:19:42.152Z" }, - { url = "https://files.pythonhosted.org/packages/30/dd/e89c1d190da2c84e0ca03c2970b9988a9c56005d18db7f447cf62b3ae6d0/aiohttp-3.12.12-cp311-cp311-win_amd64.whl", hash = "sha256:b0066e88f30be00badffb5ef8f2281532b9a9020863d873ae15f7c147770b6ec", size = 451419, upload-time = "2025-06-10T05:19:44.176Z" }, - { url = "https://files.pythonhosted.org/packages/df/e6/df14ec151942818ecc5e685fa8a4b07d3d3d8a9e4a7d2701047c89290551/aiohttp-3.12.12-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:98451ce9ce229d092f278a74a7c2a06b3aa72984673c87796126d7ccade893e9", size = 700494, upload-time = "2025-06-10T05:19:46.18Z" }, - { url = "https://files.pythonhosted.org/packages/4f/dc/7bc6e17adcd7a82b0d0317ad3e792ac22c93fb672077f0eade93e8d70182/aiohttp-3.12.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:adbac7286d89245e1aff42e948503fdc6edf6d5d65c8e305a67c40f6a8fb95f4", size = 475095, upload-time = "2025-06-10T05:19:48.246Z" }, - { url = "https://files.pythonhosted.org/packages/80/fd/c4e8846ad9d9ecdb7d5ba96de65b7bf2c1582f0b2732f2023080c1c05255/aiohttp-3.12.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0728882115bfa85cbd8d0f664c8ccc0cfd5bd3789dd837596785450ae52fac31", size = 467929, upload-time = "2025-06-10T05:19:50.79Z" }, - { url = "https://files.pythonhosted.org/packages/70/40/abebcf5c81f5e65b4379c05929773be2731ce12414264d3e0fe09ee241eb/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf3b9d9e767f9d0e09fb1a31516410fc741a62cc08754578c40abc497d09540", size = 1714729, upload-time = "2025-06-10T05:19:52.989Z" }, - { url = "https://files.pythonhosted.org/packages/8e/67/4c4f96ef6f16405e7c5205ab3c28852c7e904493b6ddc1c744dda1c97a81/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c944860e86b9f77a462321a440ccf6fa10f5719bb9d026f6b0b11307b1c96c7b", size = 1697380, upload-time = "2025-06-10T05:19:55.832Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a2/dae9ebea4caa8030170c0237e55fa0960df44b3596a849ab9ea621964054/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b1979e1f0c98c06fd0cd940988833b102fa3aa56751f6c40ffe85cabc51f6fd", size = 1752474, upload-time = "2025-06-10T05:19:58.007Z" }, - { url = "https://files.pythonhosted.org/packages/31/ef/f3d9073565ac7ad5257aaa1490ebfc2f182dfc817d3ccfd38c8ab35b2247/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:120b7dd084e96cfdad85acea2ce1e7708c70a26db913eabb8d7b417c728f5d84", size = 1798631, upload-time = "2025-06-10T05:20:00.393Z" }, - { url = "https://files.pythonhosted.org/packages/8b/0b/8b1978662274c80c8e4a739d9be1ae9ef25e5ce42b55838d6a9d1a4e3497/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e58f5ae79649ffa247081c2e8c85e31d29623cf2a3137dda985ae05c9478aae", size = 1718071, upload-time = "2025-06-10T05:20:02.812Z" }, - { url = "https://files.pythonhosted.org/packages/56/aa/35786137db867901b41cb3d2c19c0f4c56dfe581694dba99dec2683d8f8d/aiohttp-3.12.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aa5f049e3e2745b0141f13e5a64e7c48b1a1427ed18bbb7957b348f282fee56", size = 1633871, upload-time = "2025-06-10T05:20:05.127Z" }, - { url = "https://files.pythonhosted.org/packages/63/1d/34d45497dd04d08d662ecda875c44e91d271bbc5d21f4c9e4cbd3ddf7ae2/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7163cc9cf3722d90f1822f8a38b211e3ae2fc651c63bb55449f03dc1b3ff1d44", size = 1694933, upload-time = "2025-06-10T05:20:07.431Z" }, - { url = "https://files.pythonhosted.org/packages/29/c7/41e09a4517449eabbb0a7fe6d60f584fe5b21d4bff761197eb0b81e70034/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ef97c4d035b721de6607f3980fa3e4ef0ec3aca76474b5789b7fac286a8c4e23", size = 1716386, upload-time = "2025-06-10T05:20:09.787Z" }, - { url = "https://files.pythonhosted.org/packages/3a/32/907bd2010b51b70de5314ad707dfc4e898ea0011ff3d678cdf43d6f8980a/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1c14448d6a86acadc3f7b2f4cc385d1fb390acb6f37dce27f86fe629410d92e3", size = 1657039, upload-time = "2025-06-10T05:20:12.198Z" }, - { url = "https://files.pythonhosted.org/packages/60/27/8d87344a33346dcd39273adc33060aeb135e0ef70d1d6e71a3b03894a8e9/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a1b6df6255cfc493454c79221183d64007dd5080bcda100db29b7ff181b8832c", size = 1736599, upload-time = "2025-06-10T05:20:14.519Z" }, - { url = "https://files.pythonhosted.org/packages/ca/45/57c7ef1af694a6d0906abab6edde03787c8c6b0cf5d8359b69d1eb0679df/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:60fc7338dfb0626c2927bfbac4785de3ea2e2bbe3d328ba5f3ece123edda4977", size = 1764575, upload-time = "2025-06-10T05:20:16.993Z" }, - { url = "https://files.pythonhosted.org/packages/2a/cc/b1f918cd702efa9ead9d41f89214e9225cda4e5d013d6eed7f1915c17d0a/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d2afc72207ef4c9d4ca9fcd00689a6a37ef2d625600c3d757b5c2b80c9d0cf9a", size = 1724184, upload-time = "2025-06-10T05:20:19.296Z" }, - { url = "https://files.pythonhosted.org/packages/47/55/089762ee32c2a2e0f523d9ab38c9da2a344cac0e0cc8d16ecf206517ef7e/aiohttp-3.12.12-cp312-cp312-win32.whl", hash = "sha256:8098a48f93b2cbcdb5778e7c9a0e0375363e40ad692348e6e65c3b70d593b27c", size = 421762, upload-time = "2025-06-10T05:20:22.063Z" }, - { url = "https://files.pythonhosted.org/packages/ab/47/151f657e429972916f61399bd52b410e9072d5a2cae1b794f890930e5797/aiohttp-3.12.12-cp312-cp312-win_amd64.whl", hash = "sha256:d1c1879b2e0fc337d7a1b63fe950553c2b9e93c071cf95928aeea1902d441403", size = 447863, upload-time = "2025-06-10T05:20:24.326Z" }, - { url = "https://files.pythonhosted.org/packages/ee/3e/396a7d1c47aa7a74612b186dc716857506c61afac72337a7a96215c2a124/aiohttp-3.12.12-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ea5d604318234427929d486954e3199aded65f41593ac57aa0241ab93dda3d15", size = 694901, upload-time = "2025-06-10T05:20:26.58Z" }, - { url = "https://files.pythonhosted.org/packages/cc/97/235e48eadf73a1854b4d4da29b88d00049309d897d55a511e1cbe4412603/aiohttp-3.12.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e03ff38250b8b572dce6fcd7b6fb6ee398bb8a59e6aa199009c5322d721df4fc", size = 472552, upload-time = "2025-06-10T05:20:28.957Z" }, - { url = "https://files.pythonhosted.org/packages/6b/73/cd7c9439e8cab4113650541017c6524bd0e675b219dfdbbf945a78305e3f/aiohttp-3.12.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:71125b1fc2b6a94bccc63bbece620906a4dead336d2051f8af9cbf04480bc5af", size = 464853, upload-time = "2025-06-10T05:20:31.652Z" }, - { url = "https://files.pythonhosted.org/packages/d1/33/eea88ee55ed4b3f74732d9fc773e6fcf134a2971a19c7ecc49a291e7e57f/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:784a66f9f853a22c6b8c2bd0ff157f9b879700f468d6d72cfa99167df08c5c9c", size = 1703671, upload-time = "2025-06-10T05:20:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/2a/e3/a67ecf9c154b13bad9e2a86ea3782a4b73e889343ffde8c1aadcf9099c09/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a5be0b58670b54301404bd1840e4902570a1c3be00358e2700919cb1ea73c438", size = 1684934, upload-time = "2025-06-10T05:20:36.721Z" }, - { url = "https://files.pythonhosted.org/packages/89/f0/3aaea866531be2f2fcf3a87607e1f55fa72e6ce5acd6b058941a4fc35e15/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8f13566fc7bf5a728275b434bc3bdea87a7ed3ad5f734102b02ca59d9b510f", size = 1737004, upload-time = "2025-06-10T05:20:39.533Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/15867a4c7d39d8fd9bd02191cf60b1d06415fc407bbd4ff2f9660845f1cb/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d736e57d1901683bc9be648aa308cb73e646252c74b4c639c35dcd401ed385ea", size = 1786378, upload-time = "2025-06-10T05:20:42.03Z" }, - { url = "https://files.pythonhosted.org/packages/bd/61/82b15f87088b35705e01fce55806241b45a1099b3470bbca0bed8ee98662/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2007eaa7aae9102f211c519d1ec196bd3cecb1944a095db19eeaf132b798738", size = 1708707, upload-time = "2025-06-10T05:20:44.474Z" }, - { url = "https://files.pythonhosted.org/packages/28/f2/aed0786d5a1c2ed1f5a13ff2a98baacc27206b81d93812da28fc49d8a5d0/aiohttp-3.12.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a813e61583cab6d5cdbaa34bc28863acdb92f9f46e11de1b3b9251a1e8238f6", size = 1622410, upload-time = "2025-06-10T05:20:46.957Z" }, - { url = "https://files.pythonhosted.org/packages/17/54/8305f49a960376136ada977be1370fddb584c63d40bd1b9bef59469f28c7/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e408293aa910b0aea48b86a28eace41d497a85ba16c20f619f0c604597ef996c", size = 1675435, upload-time = "2025-06-10T05:20:49.379Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dc/0a55350025bc297265cfa6c6b1b1f7508f4226ca3238697cbe5e772a7d76/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f3d31faf290f5a30acba46b388465b67c6dbe8655d183e9efe2f6a1d594e6d9d", size = 1707099, upload-time = "2025-06-10T05:20:51.974Z" }, - { url = "https://files.pythonhosted.org/packages/d8/70/d949a1612b996e49d540c10ed77a0a1465c482a590e9a59c1c7897746119/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0b84731697325b023902aa643bd1726d999f5bc7854bc28b17ff410a81151d4b", size = 1649693, upload-time = "2025-06-10T05:20:54.973Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ea/fb87beb7135e25576a1e6fbe98106c037d9fcf1543f19108f9ceb73c192c/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a324c6852b6e327811748446e56cc9bb6eaa58710557922183175816e82a4234", size = 1725825, upload-time = "2025-06-10T05:20:57.433Z" }, - { url = "https://files.pythonhosted.org/packages/f1/1f/adbeb3e440d49b733cef499ace94723ab1fe9fb516425e219379e03b7c9a/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:22fd867fbd72612dcf670c90486dbcbaf702cb807fb0b42bc0b7a142a573574a", size = 1759300, upload-time = "2025-06-10T05:21:00.444Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c1/2fe007ad930f409d0d7fd9916cd55ec9b78b6a611a237424266ed71da48b/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3e092f1a970223794a4bf620a26c0e4e4e8e36bccae9b0b5da35e6d8ee598a03", size = 1708189, upload-time = "2025-06-10T05:21:02.969Z" }, - { url = "https://files.pythonhosted.org/packages/85/5e/ed3ed640fafae3972eae6cd26f66240108cf62452ac8128d59970d538cb1/aiohttp-3.12.12-cp313-cp313-win32.whl", hash = "sha256:7f5f5eb8717ef8ba15ab35fcde5a70ad28bbdc34157595d1cddd888a985f5aae", size = 420783, upload-time = "2025-06-10T05:21:06.287Z" }, - { url = "https://files.pythonhosted.org/packages/a6/db/57d2bb4af52dd0c6f62c42c7d34b82495b2902e50440134f70bfb7ee0fdd/aiohttp-3.12.12-cp313-cp313-win_amd64.whl", hash = "sha256:ace2499bdd03c329c054dc4b47361f2b19d5aa470f7db5c7e0e989336761b33c", size = 446721, upload-time = "2025-06-10T05:21:08.738Z" }, -] - -[[package]] -name = "aiosignal" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, -] - -[[package]] -name = "async-timeout" -version = "5.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, -] - -[[package]] -name = "attrs" -version = "25.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, -] - -[[package]] -name = "bitarray" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/0d/15826c7c2d49a4518a1b24b0d432f1ecad2e0b68168f942058b5de498498/bitarray-3.4.2.tar.gz", hash = "sha256:78ed2b911aabede3a31e3329b1de8abdc8104bd5e0545184ddbd9c7f668f4059", size = 143756, upload-time = "2025-05-21T16:21:44.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/61/fa3a06d74bfba1dc591efa9f4f5ad2e5645f06a8c4d113cf12d18b5ac25b/bitarray-3.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:42b552f885c5629182928c79237b375a92bcf1bc1e725b1c8a5e8eab28ea300d", size = 141280, upload-time = "2025-05-21T16:18:02.593Z" }, - { url = "https://files.pythonhosted.org/packages/17/ba/7eb30374c0e4c4b732a3ca3457d9fb0e44165ae4c5af9758597b03211a28/bitarray-3.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3e16d6184f349587b6a5045bcf073baf763a86273aab454485ba437d0bca82e8", size = 138031, upload-time = "2025-05-21T16:18:05.616Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6d/91582b0a232b54e910add5d0db34a926d0bdfdd1447685b8750349c71958/bitarray-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ecf456f0dee61bd818011e290d922e3e3b1aeb0544f6f19c4da9c5fc2e52818", size = 306437, upload-time = "2025-05-21T16:18:06.793Z" }, - { url = "https://files.pythonhosted.org/packages/b8/23/113ccc20f6324d517ef6210c8fc6ae300346eb481c5a0483735e19b4deea/bitarray-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8bbe8249ae90dc0cd78b21d5d5d27a614e15bf30737ae6e8a0e2e60cc492acc", size = 322335, upload-time = "2025-05-21T16:18:07.925Z" }, - { url = "https://files.pythonhosted.org/packages/6d/89/bf5a36e05ac3d77bdccbe9ba0eea4c47253411c2616379de0f181c27ecee/bitarray-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe7706f75f3b86e7afa516452bed9757ee301b59aea580c551c32a5e1cef082c", size = 314137, upload-time = "2025-05-21T16:18:09.333Z" }, - { url = "https://files.pythonhosted.org/packages/66/a6/bed287f9095a2a266fc68ee42d6ee2815ff500783f973876d86a6d37a434/bitarray-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c60c8d30bb6efd2c04cf82d077df6449964234aeca996f6f1df317a08feffc0", size = 307963, upload-time = "2025-05-21T16:18:10.618Z" }, - { url = "https://files.pythonhosted.org/packages/2f/50/3ca2adaf0da034e6c1a2ed60a3781b065672dd282e67f88593290c3990a7/bitarray-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b4cb5c22706d411010c7ce5efc0a4cc99f755a30fc7f6770eb1b1a0c0962bbb", size = 295182, upload-time = "2025-05-21T16:18:11.932Z" }, - { url = "https://files.pythonhosted.org/packages/90/de/8c3d96e273bc51e4912185bd809fc6a9ec14a09e607336892c149e0c57c5/bitarray-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0fd60137a9474ce53bdace68c718a7c538f9df01d390452cc984f1ee78d7bcdb", size = 300063, upload-time = "2025-05-21T16:18:13.221Z" }, - { url = "https://files.pythonhosted.org/packages/9d/71/34f0ea6ac5b2cbdd84f3e6283b5b796628cef616e786cb442cefce0fe224/bitarray-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cd514a8e27d0751f0254861df60335edabacccfcb2457793ff30c8b2ed8f799d", size = 292053, upload-time = "2025-05-21T16:18:14.802Z" }, - { url = "https://files.pythonhosted.org/packages/77/99/6ef41312536d2c37f14f0f7173aa1a012e9675d62900c10afa7641b47f75/bitarray-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6c8f7447cdf2faff1d176c5dd207f0134f05cfa2a238d3d3944dc5019dc41593", size = 317007, upload-time = "2025-05-21T16:18:16.117Z" }, - { url = "https://files.pythonhosted.org/packages/22/f9/cc4e73f54698bcdd1e0f1ea582da7e005464651e8116291a226deab95e1b/bitarray-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:75040a2a1abe4ccd40236f4ba0d39abde981d23f3ce7691b3b3f2137f134b99b", size = 319402, upload-time = "2025-05-21T16:18:18.097Z" }, - { url = "https://files.pythonhosted.org/packages/55/40/c23dd5726107cbbc5e698b3fcca5ffac83d29146ef469f27f5277d18c2d7/bitarray-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ba15725cd9040b9b1b2650edb33253cb2ba7b68d087974e296e5ff082198952f", size = 299456, upload-time = "2025-05-21T16:18:20.029Z" }, - { url = "https://files.pythonhosted.org/packages/21/31/6bfd9fda776f8d98512d5484fcb55fbb25e60796e7b5d3b9a3a300e8bc1c/bitarray-3.4.2-cp310-cp310-win32.whl", hash = "sha256:2959dfc61d963546e97220cfcaab7dfc489276c6e00092b57710522e68712b28", size = 134279, upload-time = "2025-05-21T16:18:21.609Z" }, - { url = "https://files.pythonhosted.org/packages/82/9d/7067f6548b470beb86d83f7ac6c45cac3b9c28cf77fa0f9f3e67353d69d3/bitarray-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:97077fa0ec3b7eed57cd8d1cb0eb75d670423d20b7e4901482347a81efe2f6fd", size = 141360, upload-time = "2025-05-21T16:18:23.197Z" }, - { url = "https://files.pythonhosted.org/packages/94/ba/508ba6a3ea16eb6c21baae33cd1b7bf6e299d21a496a1f90b8203a22d6d0/bitarray-3.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90ca8e260b75a7ac0c542093e5f29154e51fd0d2d0fa5041c038cb2b58415eeb", size = 141425, upload-time = "2025-05-21T16:18:24.452Z" }, - { url = "https://files.pythonhosted.org/packages/eb/a1/44d9b88cd3daee3734ea98dac691acc2c935a3bfbd5bfc38267a59bd986d/bitarray-3.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549dabcae78fb8f9133e3138b9473c7648d6054bb6fec84d28d3861aaec5ddd1", size = 138172, upload-time = "2025-05-21T16:18:25.601Z" }, - { url = "https://files.pythonhosted.org/packages/5f/aa/5a8c33ab39e8a894978d42427ad0a1ba2d5c9cb61c8480101be555c0e3a7/bitarray-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3da536ac84e6911cbc8e86be0baf1cab0d4f4ccb80c0f39b4fa28509f2db1a", size = 313373, upload-time = "2025-05-21T16:18:26.796Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/b0d28e21d91ec5c0477a320b9443096ddc816fbc59778b367f9e49094532/bitarray-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a5e84d6b737de2d773ab1bd538e6f37fa7f667ea734f00a48d9a973b181c751", size = 329657, upload-time = "2025-05-21T16:18:28.097Z" }, - { url = "https://files.pythonhosted.org/packages/bd/d5/1f858bd559568286435a460e7a169a5185b2b29184684e6c6fa303af3ca9/bitarray-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e265c5eede8316ba64bb6029832f282f6284a557b625bb3207a7680fd5da7925", size = 321873, upload-time = "2025-05-21T16:18:29.511Z" }, - { url = "https://files.pythonhosted.org/packages/e8/c8/23df4174142cccf6a8bd114651b8e9bf965005ab1ef741d37c9f72e8d2eb/bitarray-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63fb45c60c7ab7a724aa64203305e56f344489e12d41619bdc9d7887d6562e01", size = 314796, upload-time = "2025-05-21T16:18:31.2Z" }, - { url = "https://files.pythonhosted.org/packages/8f/21/329178b165f1aaf3f2ace3eb24aca5ad197febae908d7b41e552a69043e9/bitarray-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:083c2a9234dacf3e4e166a5844256da2a397941d3f6397e5b919bffca638f6ef", size = 302724, upload-time = "2025-05-21T16:18:32.729Z" }, - { url = "https://files.pythonhosted.org/packages/26/a8/a66d3c0d3410d01f51824f8476b060f96b3353db7d6b45c87dba6d1aa0e0/bitarray-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e72606adb2438002873cb0e8e81c3fce926386a59bbafa82fea07cdb2a6d8a05", size = 307434, upload-time = "2025-05-21T16:18:34.394Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ac/3052386e7ff80c80eb2549a22c890f511e9f9f7fbbe6244b04255adae031/bitarray-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dc994d22a3a563e1d402dc2f64c61e60605a1a3e66dd8aea7636f607b99f03cb", size = 299232, upload-time = "2025-05-21T16:18:35.708Z" }, - { url = "https://files.pythonhosted.org/packages/9d/46/91a32ccd39d40371ed7404d96a6f3cf1e381eaf36be5390c6bff5034f344/bitarray-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:214468391680ba1c831872a7949f1b563ab3cd832d10adc52df4f36e0af24446", size = 324056, upload-time = "2025-05-21T16:18:37.536Z" }, - { url = "https://files.pythonhosted.org/packages/39/0e/cb824f0e0302cd08809f67b35b3ae21b47af5dd122e99740bfe6bde1c824/bitarray-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c7483b97807bb018a7cd7f9741800c714c9c56ba4e5a7e962c5f956c4b858f3c", size = 327058, upload-time = "2025-05-21T16:18:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/09/01/845e977d490e4e261179785540d1fdeff966c99296f503adc0e5407fc257/bitarray-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5774bf14ec451d5ac311cfcfe0b0cf2a1a9fa74b6ca81dfbc4f56a98872a5541", size = 306629, upload-time = "2025-05-21T16:18:40.211Z" }, - { url = "https://files.pythonhosted.org/packages/29/ef/33ee8533ff1b2a8cd0b9e84fd81b2a90d66c2774544c861e281c5361eaa2/bitarray-3.4.2-cp311-cp311-win32.whl", hash = "sha256:e6f35567347ddb8b9e8b6bf6ab7d64be88bdb6b6c107b8edbb2c3d426c1590a0", size = 134450, upload-time = "2025-05-21T16:18:42.435Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/069c255d067319a9695c93369641d7f5539625069c1cf3ded2becff1bfbc/bitarray-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae5b0a8d3caf6284220232738dc7c05af81ec3a9f93d4a462295462dd0a492b2", size = 141596, upload-time = "2025-05-21T16:18:43.743Z" }, - { url = "https://files.pythonhosted.org/packages/05/57/0b2b50eb3f50c3144f705d0994171f17fda00ee3a72d563ba764ea235f66/bitarray-3.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a0e498563e0eefa96a1b92461d083de11256f6510b7706d5f2e6473cd9b7137a", size = 141191, upload-time = "2025-05-21T16:18:45.436Z" }, - { url = "https://files.pythonhosted.org/packages/81/c3/1d9ce4d0041c10ce90d924b8cea63afdda84a64623179045c0c67998922c/bitarray-3.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:114870ab71a0ebdac211aa0a120a54206c333b74b99fdf4b58fbe904979e1fef", size = 138158, upload-time = "2025-05-21T16:18:46.685Z" }, - { url = "https://files.pythonhosted.org/packages/5d/dd/a8653dac671ba97b1c68ee73b08a0eb2042f24e5e31f51b86afc09588c06/bitarray-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fbf6121978cba4313c31f7cc5961e481242def2b8ddfea34ca27ba9da52c9c1", size = 315834, upload-time = "2025-05-21T16:18:47.926Z" }, - { url = "https://files.pythonhosted.org/packages/3d/a2/30547bea0a35f9f953e99f5157749d56304d3f3a96b01a982dd604a9dc48/bitarray-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:423bb4e1bec0bc5d63969e12bcc5cc0081cc5aec4d7b62a6cd8240342aa36107", size = 331317, upload-time = "2025-05-21T16:18:49.169Z" }, - { url = "https://files.pythonhosted.org/packages/2d/b9/1789476280f46455a9a30bcd252fda6fd995583d97d1b919ec0296393e2a/bitarray-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ef80a96487c82477e8def69a58a218491794f7989b3e191cbaaa7b450315a5c", size = 324416, upload-time = "2025-05-21T16:18:50.917Z" }, - { url = "https://files.pythonhosted.org/packages/84/89/519c829ca641a3e7b8c9be56d177aaa05572b7e15e4298df4a77959b6a1e/bitarray-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35f5c69a79047e50bc1d54a777541b0a86b213e23559b1ac3d76fa9a42cc5522", size = 317634, upload-time = "2025-05-21T16:18:52.718Z" }, - { url = "https://files.pythonhosted.org/packages/0d/39/ebb6a6539261279c0994836b40b99384fa5e27ec239e70b203e310343f80/bitarray-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:002f7b128ed9d18d3ecb51ca78aeea5afffbe8e80d6be4ff2984d045b1c4b937", size = 305392, upload-time = "2025-05-21T16:18:54.888Z" }, - { url = "https://files.pythonhosted.org/packages/83/04/0ee0d57b2a60fdf881346f196fd92b824f44f4736026da1d8c7970745266/bitarray-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:999bccc72704afcf4a3d9868db4d149c032cdf910f9f7d91e30166978530af7f", size = 309740, upload-time = "2025-05-21T16:18:56.76Z" }, - { url = "https://files.pythonhosted.org/packages/f6/39/5ab0339e93097f2a2631ea281a6386c31707011499d5cf68b4e0e37ba124/bitarray-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2e44cfe2bc161cde3b11604f279e3048ef7bd3413837aadbd2ca30b5233c82cb", size = 301607, upload-time = "2025-05-21T16:18:58.144Z" }, - { url = "https://files.pythonhosted.org/packages/e8/bb/b8f697ba6a16c1e393afe75029d069e2dd457e62b112c3cb26768d2e65eb/bitarray-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f408ba3e6f706a0eabae405d1906ceb539f34a318562a91ab9799c5e1712e18c", size = 325942, upload-time = "2025-05-21T16:18:59.471Z" }, - { url = "https://files.pythonhosted.org/packages/64/ec/77d866a96909c09c5a34f1716f015386f9d9bbbf4b5dc7219f642b8043e2/bitarray-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bf94513ae559b2525e6218e41b03790f866d75df5404490420f2c25e42cf55e7", size = 329491, upload-time = "2025-05-21T16:19:01.205Z" }, - { url = "https://files.pythonhosted.org/packages/37/6e/633b7d392a39df655c92035da9ee52f7332bb165ae72038692a33a6def6c/bitarray-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f2c88c792815d2755c49a3a1fca256e142c4adfadf1a2142b5a3a37e4d4b871", size = 309566, upload-time = "2025-05-21T16:19:02.762Z" }, - { url = "https://files.pythonhosted.org/packages/ab/38/9d7ad6eca72e09b81097176dd66eed3aeaabdea4c24cf6ce25609599ce7b/bitarray-3.4.2-cp312-cp312-win32.whl", hash = "sha256:f4dac6b942c4d7ae5f6eb555ee3993de1432bf9c8f46e3caf74b6671ac5571a3", size = 134600, upload-time = "2025-05-21T16:19:04.057Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d3/c83ec3d912be73861a064f1a705436f270b8c5b5926350a875bd6c06b6df/bitarray-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:6c37e6814633041307f0df281651a86372b0ccdb1e4768247a87e83e2b68f9b9", size = 141844, upload-time = "2025-05-21T16:19:05.254Z" }, - { url = "https://files.pythonhosted.org/packages/f2/22/973d377477e1f27cf64f9e3292343219577136e32665a52667589380100d/bitarray-3.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:16263bdbb05ce379e7b8e9a9f3e0a61a9204a06a037bbc91322d2939b3079fd5", size = 141162, upload-time = "2025-05-21T16:19:06.488Z" }, - { url = "https://files.pythonhosted.org/packages/eb/53/65541b94fb6df1e8aa9a7359ac68f469c3243d8bc7302c5fb8ff8936dab2/bitarray-3.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:41fdc6fb8c3aabfcfe0073302c69fef0c74d6499491f133ba58755c3f2afb3d0", size = 138162, upload-time = "2025-05-21T16:19:07.688Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b2/83d587965f7969a5016a5bf5c9295a0651a34b668df41fa089d7c924ac08/bitarray-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c2571337b11c69206e339170516f3e72b4ec16250876c4f2bbb6e82b9caa15", size = 315760, upload-time = "2025-05-21T16:19:09.834Z" }, - { url = "https://files.pythonhosted.org/packages/4f/f5/2b2924181809debdb644143aa33d16facdce5763d5ff17e5301ecdaf89dc/bitarray-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0e3d5f37217dde9b206418c37c4d86e173f072a892670e9714e6bb20b228e95", size = 331250, upload-time = "2025-05-21T16:19:11.449Z" }, - { url = "https://files.pythonhosted.org/packages/00/2b/8ed4eeb947e05ef54614feff4cc4badd03e29ec35d46aa0218513cc9f8ac/bitarray-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83202735f21fc781f27228daeae94b6c7df1a9f673b9dd6a1c0b3764d92b8e50", size = 324299, upload-time = "2025-05-21T16:19:13.236Z" }, - { url = "https://files.pythonhosted.org/packages/05/27/d7f1b15c079cbeffad76f97c41c27635873be4d5600f6896b2bbc4f5caff/bitarray-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b3f8c35812d85a299d6c0ff097f93e18dfb7a324c129e20a4ec0ecfc4ba995", size = 317522, upload-time = "2025-05-21T16:19:14.832Z" }, - { url = "https://files.pythonhosted.org/packages/a5/db/e6a857a23222360dbc0b0d177e6060ecd88d63a1d6a3c2b52333c21a9683/bitarray-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef3f2e8ba5d6e0f38b57960d1bfb72aa9e2115f7cdca48561fadced652798d49", size = 305290, upload-time = "2025-05-21T16:19:16.57Z" }, - { url = "https://files.pythonhosted.org/packages/16/12/3b945e415233889c57c26f95a9a6a245da546e2c8d1de09991332cb796ff/bitarray-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:508ec6547bdd9f0c435c322fbb127a3dfd74c943a6c7f77fa5dfcb3e9ce1de66", size = 309764, upload-time = "2025-05-21T16:19:18.34Z" }, - { url = "https://files.pythonhosted.org/packages/6c/0e/9effb83e23ef5495c9078bdbac948df4fe2b202fb0ac5b33412848ab4b1e/bitarray-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1a3a08cc920f601258ea33d97b4454cd7cb04d17930e0a3bc7328ba3d732f8b0", size = 301690, upload-time = "2025-05-21T16:19:19.694Z" }, - { url = "https://files.pythonhosted.org/packages/cb/67/9a73476c8cd6a67ff5ab9c5c1d916307e4fb9178d76ee2781552451c995c/bitarray-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:60189130ae1ebaadbab27e3ad0a7d7ed44f5d9456bbfae07c72138501ce59053", size = 326049, upload-time = "2025-05-21T16:19:21.371Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b1/2a81f5f96c1ccc033d8c63b4584aedbd9e27499cf2276fc70d4f87ad673b/bitarray-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9e425eaf21a8d7b76531630029441c6d61f6064cbf4dd592af1607c79eb2e4d0", size = 329565, upload-time = "2025-05-21T16:19:22.88Z" }, - { url = "https://files.pythonhosted.org/packages/2e/30/670efe7771944b4b7d0aacdc076969adc9428c9d0939ee70230bdf4c8aed/bitarray-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:952cc40c593f663ba083be76d1ccdb6dc9dafab8fb6d949056405636b2e720f3", size = 309661, upload-time = "2025-05-21T16:19:24.574Z" }, - { url = "https://files.pythonhosted.org/packages/ee/2e/b2d8e842fe484d7d18fcd137289e396c7784b8484e0ec7e94ffe4bb7e8f9/bitarray-3.4.2-cp313-cp313-win32.whl", hash = "sha256:158f6b1a315eaf971f88e66f9b93431c3b580b46d2121c6a1166e7b761408fdf", size = 134614, upload-time = "2025-05-21T16:19:25.914Z" }, - { url = "https://files.pythonhosted.org/packages/0c/50/0ec25a51197410a66146eea7950e3597baedb000f2f2e2458bb6d5306b0a/bitarray-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:2d24658ac96a82beb4da2f5c71bef9790f3dcabadbe8ead8dda742ab207fe2f9", size = 141851, upload-time = "2025-05-21T16:19:27.388Z" }, - { url = "https://files.pythonhosted.org/packages/e7/03/77eca3d93f162c0982f370e6459d1fcb6ff51e84f80adb34c43256653bda/bitarray-3.4.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9c02f3234b1ec391aa235b265a3649e8078d814cdd6b42bc5aee267cc370b0c8", size = 135778, upload-time = "2025-05-21T16:20:58.492Z" }, - { url = "https://files.pythonhosted.org/packages/68/fd/5b148fb07e2b74e1cd17db7b940abdb1c7af6ac3a024810a5931db6e436b/bitarray-3.4.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:e19e5a35f53c0eaf4516cfa3f80de110eb831fd3d9785aa8b8f4a8a8c0d99523", size = 132826, upload-time = "2025-05-21T16:21:00.901Z" }, - { url = "https://files.pythonhosted.org/packages/e5/50/8cfb459218cd074a3af7121f6509ac55be2d6ac5a0a048b188934976f589/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f633d1e92fdc6a039b118d67f23d17b9ac4046a629bde04e178b770fe83a618f", size = 141592, upload-time = "2025-05-21T16:21:02.4Z" }, - { url = "https://files.pythonhosted.org/packages/43/c0/a70a212ecfd4256e7281456beee5330945ea09cec8fb0be3f99ed6828a08/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c08bc2ec3f15fbb3a99923ef1b16b621af45ab9d5146a06f970c0f0d7cab22ba", size = 142502, upload-time = "2025-05-21T16:21:08.366Z" }, - { url = "https://files.pythonhosted.org/packages/1e/8e/9fc84001701ef1fd7f18b0254bf08d594adaed34fe0b5770d8c032b4d53a/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eed46fa39af8440b1cff09a9805d65449583d524006efa29e5262bea9e08787e", size = 143930, upload-time = "2025-05-21T16:21:09.819Z" }, - { url = "https://files.pythonhosted.org/packages/f7/05/2f6753d75282033e66e0a9626ef4209500cd7a08aa8f92cc70fa49681cf3/bitarray-3.4.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9cf23c13c84c1559ed28bd211a6290b7326c2011f6c30c82cee052b254ac09f0", size = 140275, upload-time = "2025-05-21T16:21:11.481Z" }, -] - -[[package]] -name = "blinker" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, -] - -[[package]] -name = "certifi" -version = "2025.4.26" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9b/892a8c8af9110935e5adcbb06d9c6fe741b6bb02608c6513983048ba1a18/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd", size = 144649, upload-time = "2025-05-02T08:31:48.889Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a5/4179abd063ff6414223575e008593861d62abfc22455b5d1a44995b7c101/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6", size = 155045, upload-time = "2025-05-02T08:31:50.757Z" }, - { url = "https://files.pythonhosted.org/packages/3b/95/bc08c7dfeddd26b4be8c8287b9bb055716f31077c8b0ea1cd09553794665/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d", size = 147356, upload-time = "2025-05-02T08:31:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/7a5b635aa65284bf3eab7653e8b4151ab420ecbae918d3e359d1947b4d61/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86", size = 149471, upload-time = "2025-05-02T08:31:56.207Z" }, - { url = "https://files.pythonhosted.org/packages/ae/38/51fc6ac74251fd331a8cfdb7ec57beba8c23fd5493f1050f71c87ef77ed0/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c", size = 151317, upload-time = "2025-05-02T08:31:57.613Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/edee1e32215ee6e9e46c3e482645b46575a44a2d72c7dfd49e49f60ce6bf/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0", size = 146368, upload-time = "2025-05-02T08:31:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/26/2c/ea3e66f2b5f21fd00b2825c94cafb8c326ea6240cd80a91eb09e4a285830/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef", size = 154491, upload-time = "2025-05-02T08:32:01.219Z" }, - { url = "https://files.pythonhosted.org/packages/52/47/7be7fa972422ad062e909fd62460d45c3ef4c141805b7078dbab15904ff7/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6", size = 157695, upload-time = "2025-05-02T08:32:03.045Z" }, - { url = "https://files.pythonhosted.org/packages/2f/42/9f02c194da282b2b340f28e5fb60762de1151387a36842a92b533685c61e/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366", size = 154849, upload-time = "2025-05-02T08:32:04.651Z" }, - { url = "https://files.pythonhosted.org/packages/67/44/89cacd6628f31fb0b63201a618049be4be2a7435a31b55b5eb1c3674547a/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db", size = 150091, upload-time = "2025-05-02T08:32:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/1f/79/4b8da9f712bc079c0f16b6d67b099b0b8d808c2292c937f267d816ec5ecc/charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a", size = 98445, upload-time = "2025-05-02T08:32:08.66Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d7/96970afb4fb66497a40761cdf7bd4f6fca0fc7bafde3a84f836c1f57a926/charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509", size = 105782, upload-time = "2025-05-02T08:32:10.46Z" }, - { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" }, - { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" }, - { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" }, - { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" }, - { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" }, - { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, -] - -[[package]] -name = "ckzg" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/55/df/f6db8e83bd4594c1ea685cd37fb81d5399e55765aae16d1a8a9502598f4e/ckzg-2.1.1.tar.gz", hash = "sha256:d6b306b7ec93a24e4346aa53d07f7f75053bc0afc7398e35fa649e5f9d48fcc4", size = 1120500, upload-time = "2025-03-31T21:24:12.324Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/4b/cd25e857cdf46a752e97c530fe2582fae77c4d16c29fff5a15b7a998e2fd/ckzg-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b9825a1458219e8b4b023012b8ef027ef1f47e903f9541cbca4615f80132730", size = 116377, upload-time = "2025-03-31T21:22:26.952Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bc/5dfef36589545f797245ecacb54ed2acfa75507f63cfe12182d1277a88f1/ckzg-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2a40a3ba65cca4b52825d26829e6f7eb464aa27a9e9efb6b8b2ce183442c741", size = 100208, upload-time = "2025-03-31T21:22:28.04Z" }, - { url = "https://files.pythonhosted.org/packages/b7/52/96f0e3affbed321dc52b9b4ca13e0fb594da572d1f8edc47378fe48d8e9a/ckzg-2.1.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1d753fbe85be7c21602eddc2d40e0915e25fce10329f4f801a0002a4f886cc7", size = 174800, upload-time = "2025-03-31T21:22:29.719Z" }, - { url = "https://files.pythonhosted.org/packages/dc/21/b1bc07cc8e5ed32817e89b054e2399d38775d92ff2d55e24bf233f537c02/ckzg-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d76b50527f1d12430bf118aff6fa4051e9860eada43f29177258b8d399448ea", size = 160847, upload-time = "2025-03-31T21:22:30.973Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5a/97b173d4ff9bce798031beb12b340c4f1729eaaddd07f69f368f843db28e/ckzg-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44c8603e43c021d100f355f50189183135d1df3cbbddb8881552d57fbf421dde", size = 169712, upload-time = "2025-03-31T21:22:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/7b/52/48be78c07f362438e189e2fbea7df8543290c3ee99845442549c8dc5405b/ckzg-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:38707a638c9d715b3c30b29352b969f78d8fc10faed7db5faf517f04359895c0", size = 172942, upload-time = "2025-03-31T21:22:32.8Z" }, - { url = "https://files.pythonhosted.org/packages/13/42/3cfcd6cbdfb9030b9071d5e413a458f93883e47ad4a7d8d4c1d57608e57d/ckzg-2.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:52c4d257bdcbe822d20c5cd24c8154ec5aac33c49a8f5a19e716d9107a1c8785", size = 187707, upload-time = "2025-03-31T21:22:33.673Z" }, - { url = "https://files.pythonhosted.org/packages/eb/54/d43bc3a2de486fb8be29ffedc3ec80f5726765ee4fa78beabe2ab2440f93/ckzg-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1507f7bfb9bcf51d816db5d8d0f0ed53c8289605137820d437b69daea8333e16", size = 182505, upload-time = "2025-03-31T21:22:34.563Z" }, - { url = "https://files.pythonhosted.org/packages/21/43/5bcd2b7630732b532006572fbb8d64a29f69530c630ae4811167a2a0dc3b/ckzg-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d02eaaf4f841910133552b3a051dea53bcfe60cd98199fc4cf80b27609d8baa2", size = 98822, upload-time = "2025-03-31T21:22:35.786Z" }, - { url = "https://files.pythonhosted.org/packages/95/2c/44120b2d9dcb0246d67a1f28b9eaa625c499014d4d42561467e28eedd285/ckzg-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:465e2b71cf9dc383f66f1979269420a0da9274a3a9e98b1a4455e84927dfe491", size = 116378, upload-time = "2025-03-31T21:22:36.96Z" }, - { url = "https://files.pythonhosted.org/packages/23/88/c5b89ba9a730fee5e089be9e0c7048fb6707c1a0e4b6c30fcf725c3eef44/ckzg-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ee2f26f17a64ad0aab833d637b276f28486b82a29e34f32cf54b237b8f8ab72d", size = 100202, upload-time = "2025-03-31T21:22:37.799Z" }, - { url = "https://files.pythonhosted.org/packages/ee/11/b0a473e80346db52ad9a629bc9fd8f773c718ed78932ea3a70392306ffc3/ckzg-2.1.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99cc2c4e9fb8c62e3e0862c7f4df9142f07ba640da17fded5f6e0fd09f75909f", size = 175595, upload-time = "2025-03-31T21:22:39.013Z" }, - { url = "https://files.pythonhosted.org/packages/52/fa/17a7e125d07a96dd6dce4db7262231f7583856b2be5d5b7df59e04bfa188/ckzg-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773dd016693d74aca1f5d7982db2bad7dde2e147563aeb16a783f7e5f69c01fe", size = 161681, upload-time = "2025-03-31T21:22:40.257Z" }, - { url = "https://files.pythonhosted.org/packages/57/bd/46d6b90bf53da732f9adab7593d132a0834ed4f2f7659b4c7414d8f78d39/ckzg-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af2b2144f87ba218d8db01382a961b3ecbdde5ede4fa0d9428d35f8c8a595ba", size = 170471, upload-time = "2025-03-31T21:22:41.513Z" }, - { url = "https://files.pythonhosted.org/packages/9d/98/113c7704749d037d75f23240ffc5c46dfe8416de574b946438587835715f/ckzg-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f55e63d3f7c934a2cb53728ed1d815479e177aca8c84efe991c2920977cff6", size = 173595, upload-time = "2025-03-31T21:22:42.534Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d5/05fca6dcb5a19327be491157794eafc3d7498daf615c2ff5a5b745852945/ckzg-2.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ecb42aaa0ffa427ff14a9dde9356ba69e5ae6014650b397af55b31bdae7a9b6e", size = 188417, upload-time = "2025-03-31T21:22:43.466Z" }, - { url = "https://files.pythonhosted.org/packages/72/36/131ae2dfc82d0fdc98fae8e3bbfe71ff14265bb434b23bd07b585afc6d61/ckzg-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5a01514239f12fb1a7ad9009c20062a4496e13b09541c1a65f97e295da648c70", size = 183286, upload-time = "2025-03-31T21:22:44.732Z" }, - { url = "https://files.pythonhosted.org/packages/c5/6a/d371b27024422b25228fc11fa57b1ba7756a94cc9fb0c75da292c235fdaa/ckzg-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:6516b9684aae262c85cf7fddd8b585b8139ad20e08ec03994e219663abbb0916", size = 98819, upload-time = "2025-03-31T21:22:45.57Z" }, - { url = "https://files.pythonhosted.org/packages/93/a1/9c07513dd0ea01e5db727e67bd2660f3b300a4511281cdb8d5e04afa1cfd/ckzg-2.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c60e8903344ce98ce036f0fabacce952abb714cad4607198b2f0961c28b8aa72", size = 116421, upload-time = "2025-03-31T21:22:46.434Z" }, - { url = "https://files.pythonhosted.org/packages/27/04/b69a0dfbb2722a14c98a52973f276679151ec56a14178cb48e6f2e1697bc/ckzg-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4299149dd72448e5a8d2d1cc6cc7472c92fc9d9f00b1377f5b017c089d9cd92", size = 100216, upload-time = "2025-03-31T21:22:47.633Z" }, - { url = "https://files.pythonhosted.org/packages/2e/24/9cc850d0b8ead395ad5064de67c7c91adacaf31b6b35292ab53fbd93270b/ckzg-2.1.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:025dd31ffdcc799f3ff842570a2a6683b6c5b01567da0109c0c05d11768729c4", size = 175764, upload-time = "2025-03-31T21:22:48.768Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c1/eb13ba399082a98b932f10b230ec08e6456051c0ce3886b3f6d8548d11ab/ckzg-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b42ab8385c273f40a693657c09d2bba40cb4f4666141e263906ba2e519e80bd", size = 161885, upload-time = "2025-03-31T21:22:50.05Z" }, - { url = "https://files.pythonhosted.org/packages/57/c7/58baa64199781950c5a8c6139a46e1acff0f057a36e56769817400eb87fb/ckzg-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be3890fc1543f4fcfc0063e4baf5c036eb14bcf736dabdc6171ab017e0f1671", size = 170757, upload-time = "2025-03-31T21:22:51.282Z" }, - { url = "https://files.pythonhosted.org/packages/65/bd/4b8e1c70972c98829371b7004dc750a45268c5d3442d602e1b62f13ca867/ckzg-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b754210ded172968b201e2d7252573af6bf52d6ad127ddd13d0b9a45a51dae7b", size = 173761, upload-time = "2025-03-31T21:22:52.6Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/c3fd1002f97ba3e0c5b1d9ab2c8fb7a6f475fa9b80ed9c4fa55975501a54/ckzg-2.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2f8fda87865897a269c4e951e3826c2e814427a6cdfed6731cccfe548f12b36", size = 188666, upload-time = "2025-03-31T21:22:53.47Z" }, - { url = "https://files.pythonhosted.org/packages/e2/d9/91cf5a8169ee60c9397c975163cbca34432571f94facec5f8c0086bb47d8/ckzg-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:98e70b5923d77c7359432490145e9d1ab0bf873eb5de56ec53f4a551d7eaec79", size = 183652, upload-time = "2025-03-31T21:22:54.351Z" }, - { url = "https://files.pythonhosted.org/packages/25/d4/8c9f6b852f99926862344b29f0c59681916ccfec2ac60a85952a369e0bca/ckzg-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:42af7bde4ca45469cd93a96c3d15d69d51d40e7f0d30e3a20711ebd639465fcb", size = 98816, upload-time = "2025-03-31T21:22:55.23Z" }, - { url = "https://files.pythonhosted.org/packages/b7/9a/fa698b12e97452d11dd314e0335aae759725284ef6e1c1665aed56b1cd3e/ckzg-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e4edfdaf87825ff43b9885fabfdea408737a714f4ce5467100d9d1d0a03b673", size = 116426, upload-time = "2025-03-31T21:22:56.108Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/8cccd308bd11b49b40eecad6900b5769da117951cac33e880dd25e851ef7/ckzg-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:815fd2a87d6d6c57d669fda30c150bc9bf387d47e67d84535aa42b909fdc28ea", size = 100219, upload-time = "2025-03-31T21:22:56.982Z" }, - { url = "https://files.pythonhosted.org/packages/30/0e/63573d816c1292b9a4d70eb6a7366b3593d29a977794039e926805a76ca0/ckzg-2.1.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32466e809b1ab3ff01d3b0bb0b9912f61dcf72957885615595f75e3f7cc10e5", size = 175725, upload-time = "2025-03-31T21:22:58.213Z" }, - { url = "https://files.pythonhosted.org/packages/86/f6/a279609516695ad3fb8b201098c669ba3b2844cbf4fa0d83a0f02b9bb29b/ckzg-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f11b73ccf37b12993f39a7dbace159c6d580aacacde6ee17282848476550ddbc", size = 161835, upload-time = "2025-03-31T21:22:59.448Z" }, - { url = "https://files.pythonhosted.org/packages/39/e4/8cf7aef7dc05a777cb221e94046f947c6fe5317159a8dae2cd7090d52ef2/ckzg-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3b9433a1f2604bd9ac1646d3c83ad84a850d454d3ac589fe8e70c94b38a6b0", size = 170759, upload-time = "2025-03-31T21:23:01.022Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/b34e3c08eb36bc67e338b114f289b2595e581b8bdc09a8f12299a1db5d2f/ckzg-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b7d7e1b5ea06234558cd95c483666fd785a629b720a7f1622b3cbffebdc62033", size = 173787, upload-time = "2025-03-31T21:23:01.974Z" }, - { url = "https://files.pythonhosted.org/packages/2e/f0/aff87c3ed80713453cb6c84fe6fbb7582d86a7a5e4460fda2a497d47f489/ckzg-2.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9f5556e6675866040cc4335907be6c537051e7f668da289fa660fdd8a30c9ddb", size = 188722, upload-time = "2025-03-31T21:23:02.966Z" }, - { url = "https://files.pythonhosted.org/packages/44/d9/1f08bfb8fd1cbb8c7513e7ad3fb76bbb5c3fb446238c1eba582276e4d905/ckzg-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55b2ba30c5c9daac0c55f1aac851f1b7bf1f7aa0028c2db4440e963dd5b866d6", size = 183686, upload-time = "2025-03-31T21:23:03.905Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ff/434f6d2893cbdfad00c20d17e9a52d426ca042f5e980d5c3db96bc6b6e15/ckzg-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:10d201601fc8f28c0e8cec3406676797024dd374c367bbeec5a7a9eac9147237", size = 98817, upload-time = "2025-03-31T21:23:05.2Z" }, - { url = "https://files.pythonhosted.org/packages/30/b3/a0c7d7ba6e669cf04605dc0329173db62fc1fe3c488761755cc01e5e1b4d/ckzg-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:375918e25eafb9bafe5215ab91698504cba3fe51b4fe92f5896af6c5663f50c6", size = 113191, upload-time = "2025-03-31T21:23:40.646Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b9/a6cf403b8528d18d7d9154e28381a397bf466c86aa8e0b3327cffdde5749/ckzg-2.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:38b3b7802c76d4ad015db2b7a79a49c193babae50ee5f77e9ac2865c9e9ddb09", size = 96207, upload-time = "2025-03-31T21:23:41.596Z" }, - { url = "https://files.pythonhosted.org/packages/63/6b/5ddd713d97886becb8450e3e13db891199125f722366d30d087ad5438390/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438a5009fd254ace0bc1ad974d524547f1a41e6aa5e778c5cd41f4ee3106bcd6", size = 126160, upload-time = "2025-03-31T21:23:42.553Z" }, - { url = "https://files.pythonhosted.org/packages/c7/dd/e05aecc01e62108a7579f8df5e5d38536841f50e12172f8a84677edac0fa/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce11cc163a2e0dab3af7455aca7053f9d5bb8d157f231acc7665fd230565d48", size = 102811, upload-time = "2025-03-31T21:23:43.494Z" }, - { url = "https://files.pythonhosted.org/packages/c6/81/6cdadd8626ac11290af3f58ae5dcffe38bd2c8f8c798dacee7475e244aac/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b53964c07f6a076e97eaa1ef35045e935d7040aff14f80bae7e9105717702d05", size = 111328, upload-time = "2025-03-31T21:23:44.449Z" }, - { url = "https://files.pythonhosted.org/packages/36/b7/b129ff6955cd264c6ab3dbd52dd1b2759d1b121c09c03f9991e4c722c72f/ckzg-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cf085f15ae52ab2599c9b5a3d5842794bcf5613b7f58661fbfb0c5d9eac988b9", size = 98846, upload-time = "2025-03-31T21:23:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ba/7d9c1f9cec7e0e382653c72165896194a05743e589b1dae2aa80236aa87f/ckzg-2.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4b0c850bd6cad22ac79b2a2ab884e0e7cd2b54a67d643cd616c145ebdb535a11", size = 113188, upload-time = "2025-03-31T21:23:46.337Z" }, - { url = "https://files.pythonhosted.org/packages/2f/92/9728f5ccc1c5e87c6c5ae7941250a447b61fd5a63aadbc15249e29c21bcf/ckzg-2.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:26951f36bb60c9150bbd38110f5e1625596f9779dad54d1d492d8ec38bc84e3a", size = 96208, upload-time = "2025-03-31T21:23:47.255Z" }, - { url = "https://files.pythonhosted.org/packages/39/63/5e27d587bd224fee70cb66b022e7c4ef95d0e091e08ee76c25ec12094b0d/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbe12445e49c4bee67746b7b958e90a973b0de116d0390749b0df351d94e9a8c", size = 126158, upload-time = "2025-03-31T21:23:48.195Z" }, - { url = "https://files.pythonhosted.org/packages/43/98/e0a45946575a7b823d8ee0b47afb104b6017e54e1208f07da2529bc01900/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c5d4f66f09de4a99271acac74d2acb3559a77de77a366b34a91e99e8822667", size = 102812, upload-time = "2025-03-31T21:23:49.16Z" }, - { url = "https://files.pythonhosted.org/packages/cb/50/718ca7b03e4b89b18cdf99cc3038050105b0acbf9b612c23cd513093c6de/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42673c1d007372a4e8b48f6ef8f0ce31a9688a463317a98539757d1e2fb1ecc7", size = 111327, upload-time = "2025-03-31T21:23:50.126Z" }, - { url = "https://files.pythonhosted.org/packages/29/c5/80e5a0c6967d02d801150104320484a258e5a49bd191e198643e74039320/ckzg-2.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:57a7dc41ec6b69c1d9117eb61cf001295e6b4f67a736020442e71fb4367fb1a5", size = 98847, upload-time = "2025-03-31T21:23:51.084Z" }, -] - -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "cytoolz" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "toolz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/f9/3243eed3a6545c2a33a21f74f655e3fcb5d2192613cd3db81a93369eb339/cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6", size = 626652, upload-time = "2024-12-13T05:47:36.672Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d9/f13d66c16cff1fa1cb6c234698029877c456f35f577ef274aba3b86e7c51/cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042", size = 403515, upload-time = "2024-12-13T05:44:27.845Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2d/4cdf848a69300c7d44984f2ebbebb3b8576e5449c8dea157298f3bdc4da3/cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608", size = 383936, upload-time = "2024-12-13T05:44:29.5Z" }, - { url = "https://files.pythonhosted.org/packages/72/a4/ccfdd3f0ed9cc818f734b424261f6018fc61e3ec833bf85225a9aca0d994/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90124bdc42ff58b88cdea1d24a6bc5f776414a314cc4d94f25c88badb3a16d1", size = 1934569, upload-time = "2024-12-13T05:44:30.799Z" }, - { url = "https://files.pythonhosted.org/packages/50/fc/38d5344fa595683ad10dc819cfc1d8b9d2b3391ccf3e8cb7bab4899a01f5/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e74801b751e28f7c5cc3ad264c123954a051f546f2fdfe089f5aa7a12ccfa6da", size = 2015129, upload-time = "2024-12-13T05:44:32.297Z" }, - { url = "https://files.pythonhosted.org/packages/28/29/75261748dc54a20a927f33641f4e9aac674cfc6d3fbd4f332e10d0b37639/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582dad4545ddfb5127494ef23f3fa4855f1673a35d50c66f7638e9fb49805089", size = 2000506, upload-time = "2024-12-13T05:44:34.403Z" }, - { url = "https://files.pythonhosted.org/packages/00/ae/e4ead004cc2698281d153c4a5388638d67cdb5544d6d6cc1e5b3db2bd2a3/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7bd0618e16efe03bd12f19c2a26a27e6e6b75d7105adb7be1cd2a53fa755d8", size = 1957537, upload-time = "2024-12-13T05:44:39.499Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ff/4f3aa07f4f47701f7f63df60ce0a5669fa09c256c3d4a33503a9414ea5cc/cytoolz-1.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d74cca6acf1c4af58b2e4a89cc565ed61c5e201de2e434748c93e5a0f5c541a5", size = 1863331, upload-time = "2024-12-13T05:44:42.61Z" }, - { url = "https://files.pythonhosted.org/packages/a2/29/654f57f2a9b8e9765a4ab876765f64f94530b61fc6471a07feea42ece6d4/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:823a3763828d8d457f542b2a45d75d6b4ced5e470b5c7cf2ed66a02f508ed442", size = 1849938, upload-time = "2024-12-13T05:44:45.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/7b/11f457db6b291060a98315ab2c7198077d8bddeeebe5f7126d9dad98cc54/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:51633a14e6844c61db1d68c1ffd077cf949f5c99c60ed5f1e265b9e2966f1b52", size = 1852345, upload-time = "2024-12-13T05:44:47.994Z" }, - { url = "https://files.pythonhosted.org/packages/6b/92/0dccc96ce0323be236d404f5084479b79b747fa0e74e43a270e95868b5f9/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3ec9b01c45348f1d0d712507d54c2bfd69c62fbd7c9ef555c9d8298693c2432", size = 1989877, upload-time = "2024-12-13T05:44:51.514Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c8/1c5203a81200bae51aa8f7b5fad613f695bf1afa03f16251ca23ecb2ef9f/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1855022b712a9c7a5bce354517ab4727a38095f81e2d23d3eabaf1daeb6a3b3c", size = 1994492, upload-time = "2024-12-13T05:44:52.922Z" }, - { url = "https://files.pythonhosted.org/packages/e2/8a/04bc193c4d7ced8ef6bb62cdcd0bf40b5e5eb26586ed2cfb4433ec7dfd0a/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9930f7288c4866a1dc1cc87174f0c6ff4cad1671eb1f6306808aa6c445857d78", size = 1896077, upload-time = "2024-12-13T05:44:56.118Z" }, - { url = "https://files.pythonhosted.org/packages/21/a5/bee63a58f51d2c74856db66e6119a014464ff8cb1c9387fa4bd2d94e49b0/cytoolz-1.0.1-cp310-cp310-win32.whl", hash = "sha256:a9baad795d72fadc3445ccd0f122abfdbdf94269157e6d6d4835636dad318804", size = 322135, upload-time = "2024-12-13T05:44:57.695Z" }, - { url = "https://files.pythonhosted.org/packages/e8/16/7abfb1685e8b7f2838264551ee33651748994813f566ac4c3d737dfe90e5/cytoolz-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad95b386a84e18e1f6136f6d343d2509d4c3aae9f5a536f3dc96808fcc56a8cf", size = 363599, upload-time = "2024-12-13T05:44:58.875Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ea/8131ae39119820b8867cddc23716fa9f681f2b3bbce6f693e68dfb36b55b/cytoolz-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d958d4f04d9d7018e5c1850790d9d8e68b31c9a2deebca74b903706fdddd2b6", size = 406162, upload-time = "2024-12-13T05:45:01.196Z" }, - { url = "https://files.pythonhosted.org/packages/26/18/3d9bd4c146f6ea6e51300c242b20cb416966b21d481dac230e1304f1e54b/cytoolz-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0f445b8b731fc0ecb1865b8e68a070084eb95d735d04f5b6c851db2daf3048ab", size = 384961, upload-time = "2024-12-13T05:45:02.387Z" }, - { url = "https://files.pythonhosted.org/packages/e4/73/9034827907c7f85c7c484c9494e905d022fb8174526004e9ef332570349e/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f546a96460a7e28eb2ec439f4664fa646c9b3e51c6ebad9a59d3922bbe65e30", size = 2091698, upload-time = "2024-12-13T05:45:04.353Z" }, - { url = "https://files.pythonhosted.org/packages/74/af/d5c2733b0fde1a08254ff1a8a8d567874040c9eb1606363cfebc0713c73f/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0317681dd065532d21836f860b0563b199ee716f55d0c1f10de3ce7100c78a3b", size = 2188452, upload-time = "2024-12-13T05:45:05.748Z" }, - { url = "https://files.pythonhosted.org/packages/6a/bb/77c71fa9c217260b4056a732d754748903423c2cdd82a673d6064741e375/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0ef52febd5a7821a3fd8d10f21d460d1a3d2992f724ba9c91fbd7a96745d41", size = 2174203, upload-time = "2024-12-13T05:45:07.777Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a9/a5b4a3ff5d22faa1b60293bfe97362e2caf4a830c26d37ab5557f60d04b2/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebaf419acf2de73b643cf96108702b8aef8e825cf4f63209ceb078d5fbbbfd", size = 2099831, upload-time = "2024-12-13T05:45:11.477Z" }, - { url = "https://files.pythonhosted.org/packages/35/08/7f6869ea1ff31ce5289a7d58d0e7090acfe7058baa2764473048ff61ea3c/cytoolz-1.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f7f04eeb4088947585c92d6185a618b25ad4a0f8f66ea30c8db83cf94a425e3", size = 1996744, upload-time = "2024-12-13T05:45:14.172Z" }, - { url = "https://files.pythonhosted.org/packages/46/b4/9ac424c994b51763fd1bbed62d95f8fba8fa0e45c8c3c583904fdaf8f51d/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f61928803bb501c17914b82d457c6f50fe838b173fb40d39c38d5961185bd6c7", size = 2013733, upload-time = "2024-12-13T05:45:16.912Z" }, - { url = "https://files.pythonhosted.org/packages/3e/99/03009765c4b87d742d5b5a8670abb56a8c7ede033c2cdaa4be8662d3b001/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d2960cb4fa01ccb985ad1280db41f90dc97a80b397af970a15d5a5de403c8c61", size = 1994850, upload-time = "2024-12-13T05:45:18.414Z" }, - { url = "https://files.pythonhosted.org/packages/40/9a/8458af9a5557e177ea42f8cf7e477bede518b0bbef564e28c4151feaa52c/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2b407cc3e9defa8df5eb46644f6f136586f70ba49eba96f43de67b9a0984fd3", size = 2155352, upload-time = "2024-12-13T05:45:19.763Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5c/2a701423e001fcbec288b4f3fc2bf67557d114c2388237fc1ae67e1e2686/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8245f929144d4d3bd7b972c9593300195c6cea246b81b4c46053c48b3f044580", size = 2163515, upload-time = "2024-12-13T05:45:21.08Z" }, - { url = "https://files.pythonhosted.org/packages/36/16/ee2e06e65d9d533bc05cd52a0b355ba9072fc8f60d77289e529c6d2e3750/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37385db03af65763933befe89fa70faf25301effc3b0485fec1c15d4ce4f052", size = 2054431, upload-time = "2024-12-13T05:45:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d5/2fac8315f210fa1bc7106e27c19e1211580aa25bb7fa17dfd79505e5baf2/cytoolz-1.0.1-cp311-cp311-win32.whl", hash = "sha256:50f9c530f83e3e574fc95c264c3350adde8145f4f8fc8099f65f00cc595e5ead", size = 322004, upload-time = "2024-12-13T05:45:24.048Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9e/0b70b641850a95f9ff90adde9d094a4b1d81ec54dadfd97fec0a2aaf440e/cytoolz-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b7f6b617454b4326af7bd3c7c49b0fc80767f134eb9fd6449917a058d17a0e3c", size = 365358, upload-time = "2024-12-13T05:45:25.383Z" }, - { url = "https://files.pythonhosted.org/packages/d8/e8/218098344ed2cb5f8441fade9b2428e435e7073962374a9c71e59ac141a7/cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4", size = 414121, upload-time = "2024-12-13T05:45:26.588Z" }, - { url = "https://files.pythonhosted.org/packages/de/27/4d729a5653718109262b758fec1a959aa9facb74c15460d9074dc76d6635/cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662", size = 390904, upload-time = "2024-12-13T05:45:27.718Z" }, - { url = "https://files.pythonhosted.org/packages/72/c0/cbabfa788bab9c6038953bf9478adaec06e88903a726946ea7c88092f5c4/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3", size = 2090734, upload-time = "2024-12-13T05:45:30.515Z" }, - { url = "https://files.pythonhosted.org/packages/c3/66/369262c60f9423c2da82a60864a259c852f1aa122aced4acd2c679af58c0/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1", size = 2155933, upload-time = "2024-12-13T05:45:32.721Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4e/ee55186802f8d24b5fbf9a11405ccd1203b30eded07cc17750618219b94e/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8", size = 2171903, upload-time = "2024-12-13T05:45:34.205Z" }, - { url = "https://files.pythonhosted.org/packages/a1/96/bd1a9f3396e9b7f618db8cd08d15630769ce3c8b7d0534f92cd639c977ae/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d", size = 2125270, upload-time = "2024-12-13T05:45:36.982Z" }, - { url = "https://files.pythonhosted.org/packages/28/48/2a3762873091c88a69e161111cfbc6c222ff145d57ff011a642b169f04f1/cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f", size = 1973967, upload-time = "2024-12-13T05:45:39.505Z" }, - { url = "https://files.pythonhosted.org/packages/e4/50/500bd69774bdc49a4d78ec8779eb6ac7c1a9d706bfd91cf2a1dba604373a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7", size = 2021695, upload-time = "2024-12-13T05:45:40.911Z" }, - { url = "https://files.pythonhosted.org/packages/e4/4e/ba5a0ce34869495eb50653de8d676847490cf13a2cac1760fc4d313e78de/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126", size = 2010177, upload-time = "2024-12-13T05:45:42.48Z" }, - { url = "https://files.pythonhosted.org/packages/87/57/615c630b3089a13adb15351d958d227430cf624f03b1dd39eb52c34c1f59/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0", size = 2154321, upload-time = "2024-12-13T05:45:43.979Z" }, - { url = "https://files.pythonhosted.org/packages/7f/0f/fe1aa2d931e3b35ecc05215bd75da945ea7346095b3b6f6027164e602d5a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b", size = 2188374, upload-time = "2024-12-13T05:45:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/de/fa/fd363d97a641b6d0e2fd1d5c35b8fd41d9ccaeb4df56302f53bf23a58e3a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d", size = 2077911, upload-time = "2024-12-13T05:45:48.219Z" }, - { url = "https://files.pythonhosted.org/packages/d9/68/0a22946b98ae5201b54ccb4e651295285c0fb79406022b6ee8b2f791940c/cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9", size = 321903, upload-time = "2024-12-13T05:45:50.3Z" }, - { url = "https://files.pythonhosted.org/packages/62/1a/f3903197956055032f8cb297342e2dff07e50f83991aebfe5b4c4fcb55e4/cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b", size = 364490, upload-time = "2024-12-13T05:45:51.494Z" }, - { url = "https://files.pythonhosted.org/packages/aa/2e/a9f069db0107749e9e72baf6c21abe3f006841a3bcfdc9b8420e22ef31eb/cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0", size = 407365, upload-time = "2024-12-13T05:45:52.803Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9b/5e87dd0e31f54c778b4f9f34cc14c1162d3096c8d746b0f8be97d70dd73c/cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a", size = 385233, upload-time = "2024-12-13T05:45:53.994Z" }, - { url = "https://files.pythonhosted.org/packages/63/00/2fd32b16284cdb97cfe092822179bc0c3bcdd5e927dd39f986169a517642/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242", size = 2062903, upload-time = "2024-12-13T05:45:55.202Z" }, - { url = "https://files.pythonhosted.org/packages/85/39/b3cbb5a9847ba59584a263772ad4f8ca2dbfd2a0e11efd09211d1219804c/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296", size = 2139517, upload-time = "2024-12-13T05:45:56.804Z" }, - { url = "https://files.pythonhosted.org/packages/ea/39/bfcab4a46d50c467e36fe704f19d8904efead417787806ee210327f68390/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b", size = 2154849, upload-time = "2024-12-13T05:45:58.814Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/3bc6ee61b0aa47e1cb40819adc1a456d7efa809f0dea9faddacb43fdde8f/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b", size = 2102302, upload-time = "2024-12-13T05:46:00.181Z" }, - { url = "https://files.pythonhosted.org/packages/00/66/3f636c6ddea7b18026b90a8c238af472e423b86e427b11df02213689b012/cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266", size = 1960872, upload-time = "2024-12-13T05:46:01.612Z" }, - { url = "https://files.pythonhosted.org/packages/40/36/cb3b7cdd651007b69f9c48e9d104cec7cb8dc53afa1d6a720e5ad08022fa/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5", size = 2014430, upload-time = "2024-12-13T05:46:03.022Z" }, - { url = "https://files.pythonhosted.org/packages/88/3f/2e9bd2a16cfd269808922147551dcb2d8b68ba54a2c4deca2fa6a6cd0d5f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3", size = 2003127, upload-time = "2024-12-13T05:46:04.401Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7d/08604ff940aa784df8343c387fdf2489b948b714a6afb587775ae94da912/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296", size = 2142369, upload-time = "2024-12-13T05:46:06.004Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c6/39919a0645bdbdf720e97cae107f959ea9d1267fbc3b0d94fc6e1d12ac8f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140", size = 2180427, upload-time = "2024-12-13T05:46:07.526Z" }, - { url = "https://files.pythonhosted.org/packages/d8/03/dbb9d47556ee54337e7e0ac209d17ceff2d2a197c34de08005abc7a7449b/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581", size = 2069785, upload-time = "2024-12-13T05:46:10.122Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f8/11bb7b8947002231faae3ec2342df5896afbc19eb783a332cce6d219ff79/cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9", size = 320685, upload-time = "2024-12-13T05:46:11.553Z" }, - { url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297", size = 362898, upload-time = "2024-12-13T05:46:12.771Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f7/ef2a10daaec5c0f7d781d50758c6187eee484256e356ae8ef178d6c48497/cytoolz-1.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:83d19d55738ad9c60763b94f3f6d3c6e4de979aeb8d76841c1401081e0e58d96", size = 345702, upload-time = "2024-12-13T05:47:09.266Z" }, - { url = "https://files.pythonhosted.org/packages/c8/14/53c84adddedb67ff1546abb86fea04d26e24298c3ceab8436d20122ed0b9/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f112a71fad6ea824578e6393765ce5c054603afe1471a5c753ff6c67fd872d10", size = 385695, upload-time = "2024-12-13T05:47:11.011Z" }, - { url = "https://files.pythonhosted.org/packages/bd/80/3ae356c5e7b8d7dc7d1adb52f6932fee85cd748ed4e1217c269d2dfd610f/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a515df8f8aa6e1eaaf397761a6e4aff2eef73b5f920aedf271416d5471ae5ee", size = 406261, upload-time = "2024-12-13T05:47:12.24Z" }, - { url = "https://files.pythonhosted.org/packages/0c/31/8e43761ffc82d90bf9cab7e0959712eedcd1e33c211397e143dd42d7af57/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c398e7b7023460bea2edffe5fcd0a76029580f06c3f6938ac3d198b47156f3", size = 397207, upload-time = "2024-12-13T05:47:13.561Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b9/fe9da37090b6444c65f848a83e390f87d8cb43d6a4df46de1556ad7e5ceb/cytoolz-1.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3237e56211e03b13df47435b2369f5df281e02b04ad80a948ebd199b7bc10a47", size = 343358, upload-time = "2024-12-13T05:47:16.291Z" }, -] - -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - -[[package]] -name = "email-validator" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, -] - -[[package]] -name = "eth-abi" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "parsimonious" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/71/d9e1380bd77fd22f98b534699af564f189b56d539cc2b9dab908d4e4c242/eth_abi-5.2.0.tar.gz", hash = "sha256:178703fa98c07d8eecd5ae569e7e8d159e493ebb6eeb534a8fe973fbc4e40ef0", size = 49797, upload-time = "2025-01-14T16:29:34.629Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/b4/2f3982c4cbcbf5eeb6aec62df1533c0e63c653b3021ff338d44944405676/eth_abi-5.2.0-py3-none-any.whl", hash = "sha256:17abe47560ad753f18054f5b3089fcb588f3e3a092136a416b6c1502cb7e8877", size = 28511, upload-time = "2025-01-14T16:29:31.862Z" }, -] - -[[package]] -name = "eth-account" -version = "0.13.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bitarray" }, - { name = "ckzg" }, - { name = "eth-abi" }, - { name = "eth-keyfile" }, - { name = "eth-keys" }, - { name = "eth-rlp" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "rlp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/cf/20f76a29be97339c969fd765f1237154286a565a1d61be98e76bb7af946a/eth_account-0.13.7.tar.gz", hash = "sha256:5853ecbcbb22e65411176f121f5f24b8afeeaf13492359d254b16d8b18c77a46", size = 935998, upload-time = "2025-04-21T21:11:21.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/18/088fb250018cbe665bc2111974301b2d59f294a565aff7564c4df6878da2/eth_account-0.13.7-py3-none-any.whl", hash = "sha256:39727de8c94d004ff61d10da7587509c04d2dc7eac71e04830135300bdfc6d24", size = 587452, upload-time = "2025-04-21T21:11:18.346Z" }, -] - -[[package]] -name = "eth-hash" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/38/577b7bc9380ef9dff0f1dffefe0c9a1ded2385e7a06c306fd95afb6f9451/eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5", size = 12227, upload-time = "2025-01-13T21:29:21.765Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/db/f8775490669d28aca24871c67dd56b3e72105cb3bcae9a4ec65dd70859b3/eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a", size = 8028, upload-time = "2025-01-13T21:29:19.365Z" }, -] - -[package.optional-dependencies] -pycryptodome = [ - { name = "pycryptodome" }, -] - -[[package]] -name = "eth-keyfile" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-keys" }, - { name = "eth-utils" }, - { name = "pycryptodome" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/66/dd823b1537befefbbff602e2ada88f1477c5b40ec3731e3d9bc676c5f716/eth_keyfile-0.8.1.tar.gz", hash = "sha256:9708bc31f386b52cca0969238ff35b1ac72bd7a7186f2a84b86110d3c973bec1", size = 12267, upload-time = "2024-04-23T20:28:53.862Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/fc/48a586175f847dd9e05e5b8994d2fe8336098781ec2e9836a2ad94280281/eth_keyfile-0.8.1-py3-none-any.whl", hash = "sha256:65387378b82fe7e86d7cb9f8d98e6d639142661b2f6f490629da09fddbef6d64", size = 7510, upload-time = "2024-04-23T20:28:51.063Z" }, -] - -[[package]] -name = "eth-keys" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/11/1ed831c50bd74f57829aa06e58bd82a809c37e070ee501c953b9ac1f1552/eth_keys-0.7.0.tar.gz", hash = "sha256:79d24fd876201df67741de3e3fefb3f4dbcbb6ace66e47e6fe662851a4547814", size = 30166, upload-time = "2025-04-07T17:40:21.697Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/25/0ae00f2b0095e559d61ad3dc32171bd5a29dfd95ab04b4edd641f7c75f72/eth_keys-0.7.0-py3-none-any.whl", hash = "sha256:b0cdda8ffe8e5ba69c7c5ca33f153828edcace844f67aabd4542d7de38b159cf", size = 20656, upload-time = "2025-04-07T17:40:20.441Z" }, -] - -[[package]] -name = "eth-rlp" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "rlp" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7f/ea/ad39d001fa9fed07fad66edb00af701e29b48be0ed44a3bcf58cb3adf130/eth_rlp-2.2.0.tar.gz", hash = "sha256:5e4b2eb1b8213e303d6a232dfe35ab8c29e2d3051b86e8d359def80cd21db83d", size = 7720, upload-time = "2025-02-04T21:51:08.134Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/3b/57efe2bc2df0980680d57c01a36516cd3171d2319ceb30e675de19fc2cc5/eth_rlp-2.2.0-py3-none-any.whl", hash = "sha256:5692d595a741fbaef1203db6a2fedffbd2506d31455a6ad378c8449ee5985c47", size = 4446, upload-time = "2025-02-04T21:51:05.823Z" }, -] - -[[package]] -name = "eth-typing" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/54/62aa24b9cc708f06316167ee71c362779c8ed21fc8234a5cd94a8f53b623/eth_typing-5.2.1.tar.gz", hash = "sha256:7557300dbf02a93c70fa44af352b5c4a58f94e997a0fd6797fb7d1c29d9538ee", size = 21806, upload-time = "2025-04-14T20:39:28.217Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/72/c370bbe4c53da7bf998d3523f5a0f38867654923a82192df88d0705013d3/eth_typing-5.2.1-py3-none-any.whl", hash = "sha256:b0c2812ff978267563b80e9d701f487dd926f1d376d674f3b535cfe28b665d3d", size = 19163, upload-time = "2025-04-14T20:39:26.571Z" }, -] - -[[package]] -name = "eth-utils" -version = "5.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cytoolz", marker = "implementation_name == 'cpython'" }, - { name = "eth-hash" }, - { name = "eth-typing" }, - { name = "pydantic" }, - { name = "toolz", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0d/49/bee95f16d2ef068097afeeffbd6c67738107001ee57ad7bcdd4fc4d3c6a7/eth_utils-5.3.0.tar.gz", hash = "sha256:1f096867ac6be895f456fa3acb26e9573ae66e753abad9208f316d24d6178156", size = 123753, upload-time = "2025-04-14T19:35:56.431Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/c6/0417a92e6a3fc9b85f5a8380d9f9d43b69ba836a90e45f79f9ae74d41e53/eth_utils-5.3.0-py3-none-any.whl", hash = "sha256:ac184883ab299d923428bbe25dae5e356979a3993e0ef695a864db0a20bc262d", size = 102531, upload-time = "2025-04-14T19:35:55.176Z" }, -] - -[[package]] -name = "exceptiongroup" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, -] - -[[package]] -name = "fastapi" -version = "0.115.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236, upload-time = "2025-03-23T22:55:43.822Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164, upload-time = "2025-03-23T22:55:42.101Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, - { name = "httpx" }, - { name = "jinja2" }, - { name = "python-multipart" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cli" -version = "0.0.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "rich-toolkit" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/73/82a5831fbbf8ed75905bacf5b2d9d3dfd6f04d6968b29fe6f72a5ae9ceb1/fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e", size = 16753, upload-time = "2024-12-15T14:28:10.028Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705, upload-time = "2024-12-15T14:28:06.18Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "flask" -version = "3.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "blinker" }, - { name = "click" }, - { name = "itsdangerous" }, - { name = "jinja2" }, - { name = "markupsafe" }, - { name = "werkzeug" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/de/e47735752347f4128bcf354e0da07ef311a78244eba9e3dc1d4a5ab21a98/flask-3.1.1.tar.gz", hash = "sha256:284c7b8f2f58cb737f0cf1c30fd7eaf0ccfcde196099d24ecede3fc2005aa59e", size = 753440, upload-time = "2025-05-13T15:01:17.447Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl", hash = "sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c", size = 103305, upload-time = "2025-05-13T15:01:15.591Z" }, -] - -[[package]] -name = "frozenlist" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, - { url = "https://files.pythonhosted.org/packages/77/f0/77c11d13d39513b298e267b22eb6cb559c103d56f155aa9a49097221f0b6/frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61", size = 47735, upload-time = "2025-06-09T22:59:48.133Z" }, - { url = "https://files.pythonhosted.org/packages/37/12/9d07fa18971a44150593de56b2f2947c46604819976784bcf6ea0d5db43b/frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d", size = 46775, upload-time = "2025-06-09T22:59:49.564Z" }, - { url = "https://files.pythonhosted.org/packages/70/34/f73539227e06288fcd1f8a76853e755b2b48bca6747e99e283111c18bcd4/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e", size = 224644, upload-time = "2025-06-09T22:59:51.35Z" }, - { url = "https://files.pythonhosted.org/packages/fb/68/c1d9c2f4a6e438e14613bad0f2973567586610cc22dcb1e1241da71de9d3/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9", size = 222125, upload-time = "2025-06-09T22:59:52.884Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d0/98e8f9a515228d708344d7c6986752be3e3192d1795f748c24bcf154ad99/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c", size = 233455, upload-time = "2025-06-09T22:59:54.74Z" }, - { url = "https://files.pythonhosted.org/packages/79/df/8a11bcec5600557f40338407d3e5bea80376ed1c01a6c0910fcfdc4b8993/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981", size = 227339, upload-time = "2025-06-09T22:59:56.187Z" }, - { url = "https://files.pythonhosted.org/packages/50/82/41cb97d9c9a5ff94438c63cc343eb7980dac4187eb625a51bdfdb7707314/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615", size = 212969, upload-time = "2025-06-09T22:59:57.604Z" }, - { url = "https://files.pythonhosted.org/packages/13/47/f9179ee5ee4f55629e4f28c660b3fdf2775c8bfde8f9c53f2de2d93f52a9/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50", size = 222862, upload-time = "2025-06-09T22:59:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/df81e41ec6b953902c8b7e3a83bee48b195cb0e5ec2eabae5d8330c78038/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa", size = 222492, upload-time = "2025-06-09T23:00:01.026Z" }, - { url = "https://files.pythonhosted.org/packages/84/17/30d6ea87fa95a9408245a948604b82c1a4b8b3e153cea596421a2aef2754/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577", size = 238250, upload-time = "2025-06-09T23:00:03.401Z" }, - { url = "https://files.pythonhosted.org/packages/8f/00/ecbeb51669e3c3df76cf2ddd66ae3e48345ec213a55e3887d216eb4fbab3/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59", size = 218720, upload-time = "2025-06-09T23:00:05.282Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c0/c224ce0e0eb31cc57f67742071bb470ba8246623c1823a7530be0e76164c/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e", size = 232585, upload-time = "2025-06-09T23:00:07.962Z" }, - { url = "https://files.pythonhosted.org/packages/55/3c/34cb694abf532f31f365106deebdeac9e45c19304d83cf7d51ebbb4ca4d1/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd", size = 234248, upload-time = "2025-06-09T23:00:09.428Z" }, - { url = "https://files.pythonhosted.org/packages/98/c0/2052d8b6cecda2e70bd81299e3512fa332abb6dcd2969b9c80dfcdddbf75/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718", size = 221621, upload-time = "2025-06-09T23:00:11.32Z" }, - { url = "https://files.pythonhosted.org/packages/c5/bf/7dcebae315436903b1d98ffb791a09d674c88480c158aa171958a3ac07f0/frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e", size = 39578, upload-time = "2025-06-09T23:00:13.526Z" }, - { url = "https://files.pythonhosted.org/packages/8f/5f/f69818f017fa9a3d24d1ae39763e29b7f60a59e46d5f91b9c6b21622f4cd/frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464", size = 43830, upload-time = "2025-06-09T23:00:14.98Z" }, - { url = "https://files.pythonhosted.org/packages/34/7e/803dde33760128acd393a27eb002f2020ddb8d99d30a44bfbaab31c5f08a/frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a", size = 82251, upload-time = "2025-06-09T23:00:16.279Z" }, - { url = "https://files.pythonhosted.org/packages/75/a9/9c2c5760b6ba45eae11334db454c189d43d34a4c0b489feb2175e5e64277/frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750", size = 48183, upload-time = "2025-06-09T23:00:17.698Z" }, - { url = "https://files.pythonhosted.org/packages/47/be/4038e2d869f8a2da165f35a6befb9158c259819be22eeaf9c9a8f6a87771/frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd", size = 47107, upload-time = "2025-06-09T23:00:18.952Z" }, - { url = "https://files.pythonhosted.org/packages/79/26/85314b8a83187c76a37183ceed886381a5f992975786f883472fcb6dc5f2/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2", size = 237333, upload-time = "2025-06-09T23:00:20.275Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fd/e5b64f7d2c92a41639ffb2ad44a6a82f347787abc0c7df5f49057cf11770/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f", size = 231724, upload-time = "2025-06-09T23:00:21.705Z" }, - { url = "https://files.pythonhosted.org/packages/20/fb/03395c0a43a5976af4bf7534759d214405fbbb4c114683f434dfdd3128ef/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30", size = 245842, upload-time = "2025-06-09T23:00:23.148Z" }, - { url = "https://files.pythonhosted.org/packages/d0/15/c01c8e1dffdac5d9803507d824f27aed2ba76b6ed0026fab4d9866e82f1f/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98", size = 239767, upload-time = "2025-06-09T23:00:25.103Z" }, - { url = "https://files.pythonhosted.org/packages/14/99/3f4c6fe882c1f5514b6848aa0a69b20cb5e5d8e8f51a339d48c0e9305ed0/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86", size = 224130, upload-time = "2025-06-09T23:00:27.061Z" }, - { url = "https://files.pythonhosted.org/packages/4d/83/220a374bd7b2aeba9d0725130665afe11de347d95c3620b9b82cc2fcab97/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae", size = 235301, upload-time = "2025-06-09T23:00:29.02Z" }, - { url = "https://files.pythonhosted.org/packages/03/3c/3e3390d75334a063181625343e8daab61b77e1b8214802cc4e8a1bb678fc/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8", size = 234606, upload-time = "2025-06-09T23:00:30.514Z" }, - { url = "https://files.pythonhosted.org/packages/23/1e/58232c19608b7a549d72d9903005e2d82488f12554a32de2d5fb59b9b1ba/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31", size = 248372, upload-time = "2025-06-09T23:00:31.966Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a4/e4a567e01702a88a74ce8a324691e62a629bf47d4f8607f24bf1c7216e7f/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7", size = 229860, upload-time = "2025-06-09T23:00:33.375Z" }, - { url = "https://files.pythonhosted.org/packages/73/a6/63b3374f7d22268b41a9db73d68a8233afa30ed164c46107b33c4d18ecdd/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5", size = 245893, upload-time = "2025-06-09T23:00:35.002Z" }, - { url = "https://files.pythonhosted.org/packages/6d/eb/d18b3f6e64799a79673c4ba0b45e4cfbe49c240edfd03a68be20002eaeaa/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898", size = 246323, upload-time = "2025-06-09T23:00:36.468Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f5/720f3812e3d06cd89a1d5db9ff6450088b8f5c449dae8ffb2971a44da506/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56", size = 233149, upload-time = "2025-06-09T23:00:37.963Z" }, - { url = "https://files.pythonhosted.org/packages/69/68/03efbf545e217d5db8446acfd4c447c15b7c8cf4dbd4a58403111df9322d/frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7", size = 39565, upload-time = "2025-06-09T23:00:39.753Z" }, - { url = "https://files.pythonhosted.org/packages/58/17/fe61124c5c333ae87f09bb67186d65038834a47d974fc10a5fadb4cc5ae1/frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d", size = 44019, upload-time = "2025-06-09T23:00:40.988Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, - { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, - { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, - { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, - { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, - { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, - { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, - { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, - { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, - { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" }, - { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" }, - { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" }, - { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" }, - { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" }, - { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" }, - { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" }, - { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" }, - { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" }, - { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" }, - { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" }, - { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" }, - { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" }, - { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" }, - { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" }, - { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" }, - { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" }, - { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" }, - { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" }, - { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" }, - { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" }, - { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" }, - { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" }, - { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" }, - { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" }, - { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" }, - { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" }, - { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" }, - { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" }, - { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" }, - { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" }, - { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "hexbytes" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/87/adf4635b4b8c050283d74e6db9a81496063229c9263e6acc1903ab79fbec/hexbytes-1.3.1.tar.gz", hash = "sha256:a657eebebdfe27254336f98d8af6e2236f3f83aed164b87466b6cf6c5f5a4765", size = 8633, upload-time = "2025-05-14T16:45:17.5Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/e0/3b31492b1c89da3c5a846680517871455b30c54738486fc57ac79a5761bd/hexbytes-1.3.1-py3-none-any.whl", hash = "sha256:da01ff24a1a9a2b1881c4b85f0e9f9b0f51b526b379ffa23832ae7899d29c2c7", size = 5074, upload-time = "2025-05-14T16:45:16.179Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httptools" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/17c672b4bc5c7ba7f201eada4e96c71d0a59fbc185e60e42580093a86f21/httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da", size = 103297, upload-time = "2024-10-16T19:44:08.129Z" }, - { url = "https://files.pythonhosted.org/packages/92/5e/b4a826fe91971a0b68e8c2bd4e7db3e7519882f5a8ccdb1194be2b3ab98f/httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1", size = 443130, upload-time = "2024-10-16T19:44:09.45Z" }, - { url = "https://files.pythonhosted.org/packages/b0/51/ce61e531e40289a681a463e1258fa1e05e0be54540e40d91d065a264cd8f/httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50", size = 442148, upload-time = "2024-10-16T19:44:11.539Z" }, - { url = "https://files.pythonhosted.org/packages/ea/9e/270b7d767849b0c96f275c695d27ca76c30671f8eb8cc1bab6ced5c5e1d0/httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959", size = 415949, upload-time = "2024-10-16T19:44:13.388Z" }, - { url = "https://files.pythonhosted.org/packages/81/86/ced96e3179c48c6f656354e106934e65c8963d48b69be78f355797f0e1b3/httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4", size = 417591, upload-time = "2024-10-16T19:44:15.258Z" }, - { url = "https://files.pythonhosted.org/packages/75/73/187a3f620ed3175364ddb56847d7a608a6fc42d551e133197098c0143eca/httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c", size = 88344, upload-time = "2024-10-16T19:44:16.54Z" }, - { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029, upload-time = "2024-10-16T19:44:18.427Z" }, - { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492, upload-time = "2024-10-16T19:44:19.515Z" }, - { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891, upload-time = "2024-10-16T19:44:21.067Z" }, - { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788, upload-time = "2024-10-16T19:44:22.958Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214, upload-time = "2024-10-16T19:44:24.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120, upload-time = "2024-10-16T19:44:26.295Z" }, - { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565, upload-time = "2024-10-16T19:44:29.188Z" }, - { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683, upload-time = "2024-10-16T19:44:30.175Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337, upload-time = "2024-10-16T19:44:31.786Z" }, - { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796, upload-time = "2024-10-16T19:44:32.825Z" }, - { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837, upload-time = "2024-10-16T19:44:33.974Z" }, - { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289, upload-time = "2024-10-16T19:44:35.111Z" }, - { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779, upload-time = "2024-10-16T19:44:36.253Z" }, - { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634, upload-time = "2024-10-16T19:44:37.357Z" }, - { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" }, - { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" }, - { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" }, - { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" }, - { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" }, - { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "itsdangerous" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "multidict" -version = "6.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/2f/a3470242707058fe856fe59241eee5635d79087100b7042a867368863a27/multidict-6.4.4.tar.gz", hash = "sha256:69ee9e6ba214b5245031b76233dd95408a0fd57fdb019ddcc1ead4790932a8e8", size = 90183, upload-time = "2025-05-19T14:16:37.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/92/0926a5baafa164b5d0ade3cd7932be39310375d7e25c9d7ceca05cb26a45/multidict-6.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8adee3ac041145ffe4488ea73fa0a622b464cc25340d98be76924d0cda8545ff", size = 66052, upload-time = "2025-05-19T14:13:49.944Z" }, - { url = "https://files.pythonhosted.org/packages/b2/54/8a857ae4f8f643ec444d91f419fdd49cc7a90a2ca0e42d86482b604b63bd/multidict-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b61e98c3e2a861035aaccd207da585bdcacef65fe01d7a0d07478efac005e028", size = 38867, upload-time = "2025-05-19T14:13:51.92Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5f/63add9069f945c19bc8b217ea6b0f8a1ad9382eab374bb44fae4354b3baf/multidict-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75493f28dbadecdbb59130e74fe935288813301a8554dc32f0c631b6bdcdf8b0", size = 38138, upload-time = "2025-05-19T14:13:53.778Z" }, - { url = "https://files.pythonhosted.org/packages/97/8b/fbd9c0fc13966efdb4a47f5bcffff67a4f2a3189fbeead5766eaa4250b20/multidict-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc3c6a37e048b5395ee235e4a2a0d639c2349dffa32d9367a42fc20d399772", size = 220433, upload-time = "2025-05-19T14:13:55.346Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c4/5132b2d75b3ea2daedb14d10f91028f09f74f5b4d373b242c1b8eec47571/multidict-6.4.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87cb72263946b301570b0f63855569a24ee8758aaae2cd182aae7d95fbc92ca7", size = 218059, upload-time = "2025-05-19T14:13:56.993Z" }, - { url = "https://files.pythonhosted.org/packages/1a/70/f1e818c7a29b908e2d7b4fafb1d7939a41c64868e79de2982eea0a13193f/multidict-6.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bbf7bd39822fd07e3609b6b4467af4c404dd2b88ee314837ad1830a7f4a8299", size = 231120, upload-time = "2025-05-19T14:13:58.333Z" }, - { url = "https://files.pythonhosted.org/packages/b4/7e/95a194d85f27d5ef9cbe48dff9ded722fc6d12fedf641ec6e1e680890be7/multidict-6.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1f7cbd4f1f44ddf5fd86a8675b7679176eae770f2fc88115d6dddb6cefb59bc", size = 227457, upload-time = "2025-05-19T14:13:59.663Z" }, - { url = "https://files.pythonhosted.org/packages/25/2b/590ad220968d1babb42f265debe7be5c5c616df6c5688c995a06d8a9b025/multidict-6.4.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb5ac9e5bfce0e6282e7f59ff7b7b9a74aa8e5c60d38186a4637f5aa764046ad", size = 219111, upload-time = "2025-05-19T14:14:01.019Z" }, - { url = "https://files.pythonhosted.org/packages/e0/f0/b07682b995d3fb5313f339b59d7de02db19ba0c02d1f77c27bdf8212d17c/multidict-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4efc31dfef8c4eeb95b6b17d799eedad88c4902daba39ce637e23a17ea078915", size = 213012, upload-time = "2025-05-19T14:14:02.396Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/c77b5f36feef2ec92f1119756e468ac9c3eebc35aa8a4c9e51df664cbbc9/multidict-6.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9fcad2945b1b91c29ef2b4050f590bfcb68d8ac8e0995a74e659aa57e8d78e01", size = 225408, upload-time = "2025-05-19T14:14:04.826Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b3/e8189b82af9b198b47bc637766208fc917189eea91d674bad417e657bbdf/multidict-6.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d877447e7368c7320832acb7159557e49b21ea10ffeb135c1077dbbc0816b598", size = 214396, upload-time = "2025-05-19T14:14:06.187Z" }, - { url = "https://files.pythonhosted.org/packages/20/e0/200d14c84e35ae13ee99fd65dc106e1a1acb87a301f15e906fc7d5b30c17/multidict-6.4.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:33a12ebac9f380714c298cbfd3e5b9c0c4e89c75fe612ae496512ee51028915f", size = 222237, upload-time = "2025-05-19T14:14:07.778Z" }, - { url = "https://files.pythonhosted.org/packages/13/f3/bb3df40045ca8262694a3245298732ff431dc781414a89a6a364ebac6840/multidict-6.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0f14ea68d29b43a9bf37953881b1e3eb75b2739e896ba4a6aa4ad4c5b9ffa145", size = 231425, upload-time = "2025-05-19T14:14:09.516Z" }, - { url = "https://files.pythonhosted.org/packages/85/3b/538563dc18514384dac169bcba938753ad9ab4d4c8d49b55d6ae49fb2579/multidict-6.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0327ad2c747a6600e4797d115d3c38a220fdb28e54983abe8964fd17e95ae83c", size = 226251, upload-time = "2025-05-19T14:14:10.82Z" }, - { url = "https://files.pythonhosted.org/packages/56/79/77e1a65513f09142358f1beb1d4cbc06898590b34a7de2e47023e3c5a3a2/multidict-6.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d1a20707492db9719a05fc62ee215fd2c29b22b47c1b1ba347f9abc831e26683", size = 220363, upload-time = "2025-05-19T14:14:12.638Z" }, - { url = "https://files.pythonhosted.org/packages/16/57/67b0516c3e348f8daaa79c369b3de4359a19918320ab82e2e586a1c624ef/multidict-6.4.4-cp310-cp310-win32.whl", hash = "sha256:d83f18315b9fca5db2452d1881ef20f79593c4aa824095b62cb280019ef7aa3d", size = 35175, upload-time = "2025-05-19T14:14:14.805Z" }, - { url = "https://files.pythonhosted.org/packages/86/5a/4ed8fec642d113fa653777cda30ef67aa5c8a38303c091e24c521278a6c6/multidict-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:9c17341ee04545fd962ae07330cb5a39977294c883485c8d74634669b1f7fe04", size = 38678, upload-time = "2025-05-19T14:14:16.949Z" }, - { url = "https://files.pythonhosted.org/packages/19/1b/4c6e638195851524a63972c5773c7737bea7e47b1ba402186a37773acee2/multidict-6.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f5f29794ac0e73d2a06ac03fd18870adc0135a9d384f4a306a951188ed02f95", size = 65515, upload-time = "2025-05-19T14:14:19.767Z" }, - { url = "https://files.pythonhosted.org/packages/25/d5/10e6bca9a44b8af3c7f920743e5fc0c2bcf8c11bf7a295d4cfe00b08fb46/multidict-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c04157266344158ebd57b7120d9b0b35812285d26d0e78193e17ef57bfe2979a", size = 38609, upload-time = "2025-05-19T14:14:21.538Z" }, - { url = "https://files.pythonhosted.org/packages/26/b4/91fead447ccff56247edc7f0535fbf140733ae25187a33621771ee598a18/multidict-6.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb61ffd3ab8310d93427e460f565322c44ef12769f51f77277b4abad7b6f7223", size = 37871, upload-time = "2025-05-19T14:14:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/3b/37/cbc977cae59277e99d15bbda84cc53b5e0c4929ffd91d958347200a42ad0/multidict-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e0ba18a9afd495f17c351d08ebbc4284e9c9f7971d715f196b79636a4d0de44", size = 226661, upload-time = "2025-05-19T14:14:24.124Z" }, - { url = "https://files.pythonhosted.org/packages/15/cd/7e0b57fbd4dc2fc105169c4ecce5be1a63970f23bb4ec8c721b67e11953d/multidict-6.4.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9faf1b1dcaadf9f900d23a0e6d6c8eadd6a95795a0e57fcca73acce0eb912065", size = 223422, upload-time = "2025-05-19T14:14:25.437Z" }, - { url = "https://files.pythonhosted.org/packages/f1/01/1de268da121bac9f93242e30cd3286f6a819e5f0b8896511162d6ed4bf8d/multidict-6.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4d1cb1327c6082c4fce4e2a438483390964c02213bc6b8d782cf782c9b1471f", size = 235447, upload-time = "2025-05-19T14:14:26.793Z" }, - { url = "https://files.pythonhosted.org/packages/d2/8c/8b9a5e4aaaf4f2de14e86181a3a3d7b105077f668b6a06f043ec794f684c/multidict-6.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:941f1bec2f5dbd51feeb40aea654c2747f811ab01bdd3422a48a4e4576b7d76a", size = 231455, upload-time = "2025-05-19T14:14:28.149Z" }, - { url = "https://files.pythonhosted.org/packages/35/db/e1817dcbaa10b319c412769cf999b1016890849245d38905b73e9c286862/multidict-6.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5f8a146184da7ea12910a4cec51ef85e44f6268467fb489c3caf0cd512f29c2", size = 223666, upload-time = "2025-05-19T14:14:29.584Z" }, - { url = "https://files.pythonhosted.org/packages/4a/e1/66e8579290ade8a00e0126b3d9a93029033ffd84f0e697d457ed1814d0fc/multidict-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:232b7237e57ec3c09be97206bfb83a0aa1c5d7d377faa019c68a210fa35831f1", size = 217392, upload-time = "2025-05-19T14:14:30.961Z" }, - { url = "https://files.pythonhosted.org/packages/7b/6f/f8639326069c24a48c7747c2a5485d37847e142a3f741ff3340c88060a9a/multidict-6.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:55ae0721c1513e5e3210bca4fc98456b980b0c2c016679d3d723119b6b202c42", size = 228969, upload-time = "2025-05-19T14:14:32.672Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c3/3d58182f76b960eeade51c89fcdce450f93379340457a328e132e2f8f9ed/multidict-6.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d662c072579f63137919d7bb8fc250655ce79f00c82ecf11cab678f335062e", size = 217433, upload-time = "2025-05-19T14:14:34.016Z" }, - { url = "https://files.pythonhosted.org/packages/e1/4b/f31a562906f3bd375f3d0e83ce314e4a660c01b16c2923e8229b53fba5d7/multidict-6.4.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0e05c39962baa0bb19a6b210e9b1422c35c093b651d64246b6c2e1a7e242d9fd", size = 225418, upload-time = "2025-05-19T14:14:35.376Z" }, - { url = "https://files.pythonhosted.org/packages/99/89/78bb95c89c496d64b5798434a3deee21996114d4d2c28dd65850bf3a691e/multidict-6.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b1cc3ab8c31d9ebf0faa6e3540fb91257590da330ffe6d2393d4208e638925", size = 235042, upload-time = "2025-05-19T14:14:36.723Z" }, - { url = "https://files.pythonhosted.org/packages/74/91/8780a6e5885a8770442a8f80db86a0887c4becca0e5a2282ba2cae702bc4/multidict-6.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:93ec84488a384cd7b8a29c2c7f467137d8a73f6fe38bb810ecf29d1ade011a7c", size = 230280, upload-time = "2025-05-19T14:14:38.194Z" }, - { url = "https://files.pythonhosted.org/packages/68/c1/fcf69cabd542eb6f4b892469e033567ee6991d361d77abdc55e3a0f48349/multidict-6.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b308402608493638763abc95f9dc0030bbd6ac6aff784512e8ac3da73a88af08", size = 223322, upload-time = "2025-05-19T14:14:40.015Z" }, - { url = "https://files.pythonhosted.org/packages/b8/85/5b80bf4b83d8141bd763e1d99142a9cdfd0db83f0739b4797172a4508014/multidict-6.4.4-cp311-cp311-win32.whl", hash = "sha256:343892a27d1a04d6ae455ecece12904d242d299ada01633d94c4f431d68a8c49", size = 35070, upload-time = "2025-05-19T14:14:41.904Z" }, - { url = "https://files.pythonhosted.org/packages/09/66/0bed198ffd590ab86e001f7fa46b740d58cf8ff98c2f254e4a36bf8861ad/multidict-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:73484a94f55359780c0f458bbd3c39cb9cf9c182552177d2136e828269dee529", size = 38667, upload-time = "2025-05-19T14:14:43.534Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b5/5675377da23d60875fe7dae6be841787755878e315e2f517235f22f59e18/multidict-6.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc388f75a1c00000824bf28b7633e40854f4127ede80512b44c3cfeeea1839a2", size = 64293, upload-time = "2025-05-19T14:14:44.724Z" }, - { url = "https://files.pythonhosted.org/packages/34/a7/be384a482754bb8c95d2bbe91717bf7ccce6dc38c18569997a11f95aa554/multidict-6.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:98af87593a666f739d9dba5d0ae86e01b0e1a9cfcd2e30d2d361fbbbd1a9162d", size = 38096, upload-time = "2025-05-19T14:14:45.95Z" }, - { url = "https://files.pythonhosted.org/packages/66/6d/d59854bb4352306145bdfd1704d210731c1bb2c890bfee31fb7bbc1c4c7f/multidict-6.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aff4cafea2d120327d55eadd6b7f1136a8e5a0ecf6fb3b6863e8aca32cd8e50a", size = 37214, upload-time = "2025-05-19T14:14:47.158Z" }, - { url = "https://files.pythonhosted.org/packages/99/e0/c29d9d462d7cfc5fc8f9bf24f9c6843b40e953c0b55e04eba2ad2cf54fba/multidict-6.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:169c4ba7858176b797fe551d6e99040c531c775d2d57b31bcf4de6d7a669847f", size = 224686, upload-time = "2025-05-19T14:14:48.366Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4a/da99398d7fd8210d9de068f9a1b5f96dfaf67d51e3f2521f17cba4ee1012/multidict-6.4.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9eb4c59c54421a32b3273d4239865cb14ead53a606db066d7130ac80cc8ec93", size = 231061, upload-time = "2025-05-19T14:14:49.952Z" }, - { url = "https://files.pythonhosted.org/packages/21/f5/ac11add39a0f447ac89353e6ca46666847051103649831c08a2800a14455/multidict-6.4.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cf3bd54c56aa16fdb40028d545eaa8d051402b61533c21e84046e05513d5780", size = 232412, upload-time = "2025-05-19T14:14:51.812Z" }, - { url = "https://files.pythonhosted.org/packages/d9/11/4b551e2110cded705a3c13a1d4b6a11f73891eb5a1c449f1b2b6259e58a6/multidict-6.4.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f682c42003c7264134bfe886376299db4cc0c6cd06a3295b41b347044bcb5482", size = 231563, upload-time = "2025-05-19T14:14:53.262Z" }, - { url = "https://files.pythonhosted.org/packages/4c/02/751530c19e78fe73b24c3da66618eda0aa0d7f6e7aa512e46483de6be210/multidict-6.4.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920f9cf2abdf6e493c519492d892c362007f113c94da4c239ae88429835bad1", size = 223811, upload-time = "2025-05-19T14:14:55.232Z" }, - { url = "https://files.pythonhosted.org/packages/c7/cb/2be8a214643056289e51ca356026c7b2ce7225373e7a1f8c8715efee8988/multidict-6.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:530d86827a2df6504526106b4c104ba19044594f8722d3e87714e847c74a0275", size = 216524, upload-time = "2025-05-19T14:14:57.226Z" }, - { url = "https://files.pythonhosted.org/packages/19/f3/6d5011ec375c09081f5250af58de85f172bfcaafebff286d8089243c4bd4/multidict-6.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ecde56ea2439b96ed8a8d826b50c57364612ddac0438c39e473fafad7ae1c23b", size = 229012, upload-time = "2025-05-19T14:14:58.597Z" }, - { url = "https://files.pythonhosted.org/packages/67/9c/ca510785df5cf0eaf5b2a8132d7d04c1ce058dcf2c16233e596ce37a7f8e/multidict-6.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:dc8c9736d8574b560634775ac0def6bdc1661fc63fa27ffdfc7264c565bcb4f2", size = 226765, upload-time = "2025-05-19T14:15:00.048Z" }, - { url = "https://files.pythonhosted.org/packages/36/c8/ca86019994e92a0f11e642bda31265854e6ea7b235642f0477e8c2e25c1f/multidict-6.4.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7f3d3b3c34867579ea47cbd6c1f2ce23fbfd20a273b6f9e3177e256584f1eacc", size = 222888, upload-time = "2025-05-19T14:15:01.568Z" }, - { url = "https://files.pythonhosted.org/packages/c6/67/bc25a8e8bd522935379066950ec4e2277f9b236162a73548a2576d4b9587/multidict-6.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:87a728af265e08f96b6318ebe3c0f68b9335131f461efab2fc64cc84a44aa6ed", size = 234041, upload-time = "2025-05-19T14:15:03.759Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a0/70c4c2d12857fccbe607b334b7ee28b6b5326c322ca8f73ee54e70d76484/multidict-6.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9f193eeda1857f8e8d3079a4abd258f42ef4a4bc87388452ed1e1c4d2b0c8740", size = 231046, upload-time = "2025-05-19T14:15:05.698Z" }, - { url = "https://files.pythonhosted.org/packages/c1/0f/52954601d02d39742aab01d6b92f53c1dd38b2392248154c50797b4df7f1/multidict-6.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be06e73c06415199200e9a2324a11252a3d62030319919cde5e6950ffeccf72e", size = 227106, upload-time = "2025-05-19T14:15:07.124Z" }, - { url = "https://files.pythonhosted.org/packages/af/24/679d83ec4379402d28721790dce818e5d6b9f94ce1323a556fb17fa9996c/multidict-6.4.4-cp312-cp312-win32.whl", hash = "sha256:622f26ea6a7e19b7c48dd9228071f571b2fbbd57a8cd71c061e848f281550e6b", size = 35351, upload-time = "2025-05-19T14:15:08.556Z" }, - { url = "https://files.pythonhosted.org/packages/52/ef/40d98bc5f986f61565f9b345f102409534e29da86a6454eb6b7c00225a13/multidict-6.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:5e2bcda30d5009996ff439e02a9f2b5c3d64a20151d34898c000a6281faa3781", size = 38791, upload-time = "2025-05-19T14:15:09.825Z" }, - { url = "https://files.pythonhosted.org/packages/df/2a/e166d2ffbf4b10131b2d5b0e458f7cee7d986661caceae0de8753042d4b2/multidict-6.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:82ffabefc8d84c2742ad19c37f02cde5ec2a1ee172d19944d380f920a340e4b9", size = 64123, upload-time = "2025-05-19T14:15:11.044Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/e200e379ae5b6f95cbae472e0199ea98913f03d8c9a709f42612a432932c/multidict-6.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6a2f58a66fe2c22615ad26156354005391e26a2f3721c3621504cd87c1ea87bf", size = 38049, upload-time = "2025-05-19T14:15:12.902Z" }, - { url = "https://files.pythonhosted.org/packages/75/fb/47afd17b83f6a8c7fa863c6d23ac5ba6a0e6145ed8a6bcc8da20b2b2c1d2/multidict-6.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5883d6ee0fd9d8a48e9174df47540b7545909841ac82354c7ae4cbe9952603bd", size = 37078, upload-time = "2025-05-19T14:15:14.282Z" }, - { url = "https://files.pythonhosted.org/packages/fa/70/1af3143000eddfb19fd5ca5e78393985ed988ac493bb859800fe0914041f/multidict-6.4.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9abcf56a9511653fa1d052bfc55fbe53dbee8f34e68bd6a5a038731b0ca42d15", size = 224097, upload-time = "2025-05-19T14:15:15.566Z" }, - { url = "https://files.pythonhosted.org/packages/b1/39/d570c62b53d4fba844e0378ffbcd02ac25ca423d3235047013ba2f6f60f8/multidict-6.4.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6ed5ae5605d4ad5a049fad2a28bb7193400700ce2f4ae484ab702d1e3749c3f9", size = 230768, upload-time = "2025-05-19T14:15:17.308Z" }, - { url = "https://files.pythonhosted.org/packages/fd/f8/ed88f2c4d06f752b015933055eb291d9bc184936903752c66f68fb3c95a7/multidict-6.4.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbfcb60396f9bcfa63e017a180c3105b8c123a63e9d1428a36544e7d37ca9e20", size = 231331, upload-time = "2025-05-19T14:15:18.73Z" }, - { url = "https://files.pythonhosted.org/packages/9c/6f/8e07cffa32f483ab887b0d56bbd8747ac2c1acd00dc0af6fcf265f4a121e/multidict-6.4.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0f1987787f5f1e2076b59692352ab29a955b09ccc433c1f6b8e8e18666f608b", size = 230169, upload-time = "2025-05-19T14:15:20.179Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2b/5dcf173be15e42f330110875a2668ddfc208afc4229097312212dc9c1236/multidict-6.4.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0121ccce8c812047d8d43d691a1ad7641f72c4f730474878a5aeae1b8ead8c", size = 222947, upload-time = "2025-05-19T14:15:21.714Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/4ddcbcebe5ebcd6faa770b629260d15840a5fc07ce8ad295a32e14993726/multidict-6.4.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83ec4967114295b8afd120a8eec579920c882831a3e4c3331d591a8e5bfbbc0f", size = 215761, upload-time = "2025-05-19T14:15:23.242Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c9/55e998ae45ff15c5608e384206aa71a11e1b7f48b64d166db400b14a3433/multidict-6.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:995f985e2e268deaf17867801b859a282e0448633f1310e3704b30616d269d69", size = 227605, upload-time = "2025-05-19T14:15:24.763Z" }, - { url = "https://files.pythonhosted.org/packages/04/49/c2404eac74497503c77071bd2e6f88c7e94092b8a07601536b8dbe99be50/multidict-6.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d832c608f94b9f92a0ec8b7e949be7792a642b6e535fcf32f3e28fab69eeb046", size = 226144, upload-time = "2025-05-19T14:15:26.249Z" }, - { url = "https://files.pythonhosted.org/packages/62/c5/0cd0c3c6f18864c40846aa2252cd69d308699cb163e1c0d989ca301684da/multidict-6.4.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d21c1212171cf7da703c5b0b7a0e85be23b720818aef502ad187d627316d5645", size = 221100, upload-time = "2025-05-19T14:15:28.303Z" }, - { url = "https://files.pythonhosted.org/packages/71/7b/f2f3887bea71739a046d601ef10e689528d4f911d84da873b6be9194ffea/multidict-6.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:cbebaa076aaecad3d4bb4c008ecc73b09274c952cf6a1b78ccfd689e51f5a5b0", size = 232731, upload-time = "2025-05-19T14:15:30.263Z" }, - { url = "https://files.pythonhosted.org/packages/e5/b3/d9de808349df97fa75ec1372758701b5800ebad3c46ae377ad63058fbcc6/multidict-6.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c93a6fb06cc8e5d3628b2b5fda215a5db01e8f08fc15fadd65662d9b857acbe4", size = 229637, upload-time = "2025-05-19T14:15:33.337Z" }, - { url = "https://files.pythonhosted.org/packages/5e/57/13207c16b615eb4f1745b44806a96026ef8e1b694008a58226c2d8f5f0a5/multidict-6.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8cd8f81f1310182362fb0c7898145ea9c9b08a71081c5963b40ee3e3cac589b1", size = 225594, upload-time = "2025-05-19T14:15:34.832Z" }, - { url = "https://files.pythonhosted.org/packages/3a/e4/d23bec2f70221604f5565000632c305fc8f25ba953e8ce2d8a18842b9841/multidict-6.4.4-cp313-cp313-win32.whl", hash = "sha256:3e9f1cd61a0ab857154205fb0b1f3d3ace88d27ebd1409ab7af5096e409614cd", size = 35359, upload-time = "2025-05-19T14:15:36.246Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/cfe1a47632be861b627f46f642c1d031704cc1c0f5c0efbde2ad44aa34bd/multidict-6.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373", size = 38903, upload-time = "2025-05-19T14:15:37.507Z" }, - { url = "https://files.pythonhosted.org/packages/68/7b/15c259b0ab49938a0a1c8f3188572802704a779ddb294edc1b2a72252e7c/multidict-6.4.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6a602151dbf177be2450ef38966f4be3467d41a86c6a845070d12e17c858a156", size = 68895, upload-time = "2025-05-19T14:15:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/f1/7d/168b5b822bccd88142e0a3ce985858fea612404edd228698f5af691020c9/multidict-6.4.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d2b9712211b860d123815a80b859075d86a4d54787e247d7fbee9db6832cf1c", size = 40183, upload-time = "2025-05-19T14:15:40.197Z" }, - { url = "https://files.pythonhosted.org/packages/e0/b7/d4b8d98eb850ef28a4922ba508c31d90715fd9b9da3801a30cea2967130b/multidict-6.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d2fa86af59f8fc1972e121ade052145f6da22758f6996a197d69bb52f8204e7e", size = 39592, upload-time = "2025-05-19T14:15:41.508Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/a554678898a19583548e742080cf55d169733baf57efc48c2f0273a08583/multidict-6.4.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50855d03e9e4d66eab6947ba688ffb714616f985838077bc4b490e769e48da51", size = 226071, upload-time = "2025-05-19T14:15:42.877Z" }, - { url = "https://files.pythonhosted.org/packages/ee/dc/7ba6c789d05c310e294f85329efac1bf5b450338d2542498db1491a264df/multidict-6.4.4-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5bce06b83be23225be1905dcdb6b789064fae92499fbc458f59a8c0e68718601", size = 222597, upload-time = "2025-05-19T14:15:44.412Z" }, - { url = "https://files.pythonhosted.org/packages/24/4f/34eadbbf401b03768dba439be0fb94b0d187facae9142821a3d5599ccb3b/multidict-6.4.4-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66ed0731f8e5dfd8369a883b6e564aca085fb9289aacabd9decd70568b9a30de", size = 228253, upload-time = "2025-05-19T14:15:46.474Z" }, - { url = "https://files.pythonhosted.org/packages/c0/e6/493225a3cdb0d8d80d43a94503fc313536a07dae54a3f030d279e629a2bc/multidict-6.4.4-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:329ae97fc2f56f44d91bc47fe0972b1f52d21c4b7a2ac97040da02577e2daca2", size = 226146, upload-time = "2025-05-19T14:15:48.003Z" }, - { url = "https://files.pythonhosted.org/packages/2f/70/e411a7254dc3bff6f7e6e004303b1b0591358e9f0b7c08639941e0de8bd6/multidict-6.4.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c27e5dcf520923d6474d98b96749e6805f7677e93aaaf62656005b8643f907ab", size = 220585, upload-time = "2025-05-19T14:15:49.546Z" }, - { url = "https://files.pythonhosted.org/packages/08/8f/beb3ae7406a619100d2b1fb0022c3bb55a8225ab53c5663648ba50dfcd56/multidict-6.4.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:058cc59b9e9b143cc56715e59e22941a5d868c322242278d28123a5d09cdf6b0", size = 212080, upload-time = "2025-05-19T14:15:51.151Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ec/355124e9d3d01cf8edb072fd14947220f357e1c5bc79c88dff89297e9342/multidict-6.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:69133376bc9a03f8c47343d33f91f74a99c339e8b58cea90433d8e24bb298031", size = 226558, upload-time = "2025-05-19T14:15:52.665Z" }, - { url = "https://files.pythonhosted.org/packages/fd/22/d2b95cbebbc2ada3be3812ea9287dcc9712d7f1a012fad041770afddb2ad/multidict-6.4.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d6b15c55721b1b115c5ba178c77104123745b1417527ad9641a4c5e2047450f0", size = 212168, upload-time = "2025-05-19T14:15:55.279Z" }, - { url = "https://files.pythonhosted.org/packages/4d/c5/62bfc0b2f9ce88326dbe7179f9824a939c6c7775b23b95de777267b9725c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a887b77f51d3d41e6e1a63cf3bc7ddf24de5939d9ff69441387dfefa58ac2e26", size = 217970, upload-time = "2025-05-19T14:15:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/79/74/977cea1aadc43ff1c75d23bd5bc4768a8fac98c14e5878d6ee8d6bab743c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:632a3bf8f1787f7ef7d3c2f68a7bde5be2f702906f8b5842ad6da9d974d0aab3", size = 226980, upload-time = "2025-05-19T14:15:58.313Z" }, - { url = "https://files.pythonhosted.org/packages/48/fc/cc4a1a2049df2eb84006607dc428ff237af38e0fcecfdb8a29ca47b1566c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a145c550900deb7540973c5cdb183b0d24bed6b80bf7bddf33ed8f569082535e", size = 220641, upload-time = "2025-05-19T14:15:59.866Z" }, - { url = "https://files.pythonhosted.org/packages/3b/6a/a7444d113ab918701988d4abdde373dbdfd2def7bd647207e2bf645c7eac/multidict-6.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc5d83c6619ca5c9672cb78b39ed8542f1975a803dee2cda114ff73cbb076edd", size = 221728, upload-time = "2025-05-19T14:16:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b0/fdf4c73ad1c55e0f4dbbf2aa59dd37037334091f9a4961646d2b7ac91a86/multidict-6.4.4-cp313-cp313t-win32.whl", hash = "sha256:3312f63261b9df49be9d57aaa6abf53a6ad96d93b24f9cc16cf979956355ce6e", size = 41913, upload-time = "2025-05-19T14:16:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/8e/92/27989ecca97e542c0d01d05a98a5ae12198a243a9ee12563a0313291511f/multidict-6.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:ba852168d814b2c73333073e1c7116d9395bea69575a01b0b3c89d2d5a87c8fb", size = 46112, upload-time = "2025-05-19T14:16:04.909Z" }, - { url = "https://files.pythonhosted.org/packages/84/5d/e17845bb0fa76334477d5de38654d27946d5b5d3695443987a094a71b440/multidict-6.4.4-py3-none-any.whl", hash = "sha256:bd4557071b561a8b3b6075c3ce93cf9bfb6182cb241805c3d66ced3b75eff4ac", size = 10481, upload-time = "2025-05-19T14:16:36.024Z" }, -] - -[[package]] -name = "parsimonious" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7b/91/abdc50c4ef06fdf8d047f60ee777ca9b2a7885e1a9cea81343fbecda52d7/parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c", size = 52172, upload-time = "2022-09-03T17:01:17.004Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/0f/c8b64d9b54ea631fcad4e9e3c8dbe8c11bb32a623be94f22974c88e71eaf/parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f", size = 48427, upload-time = "2022-09-03T17:01:13.814Z" }, -] - -[[package]] -name = "propcache" -version = "0.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4e/ad52a7925ff01c1325653a730c7ec3175a23f948f08626a534133427dcff/propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3", size = 43133, upload-time = "2025-06-09T22:53:41.965Z" }, - { url = "https://files.pythonhosted.org/packages/63/7c/e9399ba5da7780871db4eac178e9c2e204c23dd3e7d32df202092a1ed400/propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3", size = 43039, upload-time = "2025-06-09T22:53:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/22/e1/58da211eb8fdc6fc854002387d38f415a6ca5f5c67c1315b204a5d3e9d7a/propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e", size = 201903, upload-time = "2025-06-09T22:53:44.872Z" }, - { url = "https://files.pythonhosted.org/packages/c4/0a/550ea0f52aac455cb90111c8bab995208443e46d925e51e2f6ebdf869525/propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220", size = 213362, upload-time = "2025-06-09T22:53:46.707Z" }, - { url = "https://files.pythonhosted.org/packages/5a/af/9893b7d878deda9bb69fcf54600b247fba7317761b7db11fede6e0f28bd0/propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb", size = 210525, upload-time = "2025-06-09T22:53:48.547Z" }, - { url = "https://files.pythonhosted.org/packages/7c/bb/38fd08b278ca85cde36d848091ad2b45954bc5f15cce494bb300b9285831/propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614", size = 198283, upload-time = "2025-06-09T22:53:50.067Z" }, - { url = "https://files.pythonhosted.org/packages/78/8c/9fe55bd01d362bafb413dfe508c48753111a1e269737fa143ba85693592c/propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50", size = 191872, upload-time = "2025-06-09T22:53:51.438Z" }, - { url = "https://files.pythonhosted.org/packages/54/14/4701c33852937a22584e08abb531d654c8bcf7948a8f87ad0a4822394147/propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339", size = 199452, upload-time = "2025-06-09T22:53:53.229Z" }, - { url = "https://files.pythonhosted.org/packages/16/44/447f2253d859602095356007657ee535e0093215ea0b3d1d6a41d16e5201/propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0", size = 191567, upload-time = "2025-06-09T22:53:54.541Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/e4756258749bb2d3b46defcff606a2f47410bab82be5824a67e84015b267/propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2", size = 193015, upload-time = "2025-06-09T22:53:56.44Z" }, - { url = "https://files.pythonhosted.org/packages/1e/df/e6d3c7574233164b6330b9fd697beeac402afd367280e6dc377bb99b43d9/propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7", size = 204660, upload-time = "2025-06-09T22:53:57.839Z" }, - { url = "https://files.pythonhosted.org/packages/b2/53/e4d31dd5170b4a0e2e6b730f2385a96410633b4833dc25fe5dffd1f73294/propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b", size = 206105, upload-time = "2025-06-09T22:53:59.638Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fe/74d54cf9fbe2a20ff786e5f7afcfde446588f0cf15fb2daacfbc267b866c/propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c", size = 196980, upload-time = "2025-06-09T22:54:01.071Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/c469c9d59dada8a7679625e0440b544fe72e99311a4679c279562051f6fc/propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70", size = 37679, upload-time = "2025-06-09T22:54:03.003Z" }, - { url = "https://files.pythonhosted.org/packages/38/35/07a471371ac89d418f8d0b699c75ea6dca2041fbda360823de21f6a9ce0a/propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9", size = 41459, upload-time = "2025-06-09T22:54:04.134Z" }, - { url = "https://files.pythonhosted.org/packages/80/8d/e8b436717ab9c2cfc23b116d2c297305aa4cd8339172a456d61ebf5669b8/propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be", size = 74207, upload-time = "2025-06-09T22:54:05.399Z" }, - { url = "https://files.pythonhosted.org/packages/d6/29/1e34000e9766d112171764b9fa3226fa0153ab565d0c242c70e9945318a7/propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f", size = 43648, upload-time = "2025-06-09T22:54:08.023Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/1ad5af0df781e76988897da39b5f086c2bf0f028b7f9bd1f409bb05b6874/propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9", size = 43496, upload-time = "2025-06-09T22:54:09.228Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ce/e96392460f9fb68461fabab3e095cb00c8ddf901205be4eae5ce246e5b7e/propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf", size = 217288, upload-time = "2025-06-09T22:54:10.466Z" }, - { url = "https://files.pythonhosted.org/packages/c5/2a/866726ea345299f7ceefc861a5e782b045545ae6940851930a6adaf1fca6/propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9", size = 227456, upload-time = "2025-06-09T22:54:11.828Z" }, - { url = "https://files.pythonhosted.org/packages/de/03/07d992ccb6d930398689187e1b3c718339a1c06b8b145a8d9650e4726166/propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66", size = 225429, upload-time = "2025-06-09T22:54:13.823Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/116ba39448753b1330f48ab8ba927dcd6cf0baea8a0ccbc512dfb49ba670/propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df", size = 213472, upload-time = "2025-06-09T22:54:15.232Z" }, - { url = "https://files.pythonhosted.org/packages/a6/85/f01f5d97e54e428885a5497ccf7f54404cbb4f906688a1690cd51bf597dc/propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2", size = 204480, upload-time = "2025-06-09T22:54:17.104Z" }, - { url = "https://files.pythonhosted.org/packages/e3/79/7bf5ab9033b8b8194cc3f7cf1aaa0e9c3256320726f64a3e1f113a812dce/propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7", size = 214530, upload-time = "2025-06-09T22:54:18.512Z" }, - { url = "https://files.pythonhosted.org/packages/31/0b/bd3e0c00509b609317df4a18e6b05a450ef2d9a963e1d8bc9c9415d86f30/propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95", size = 205230, upload-time = "2025-06-09T22:54:19.947Z" }, - { url = "https://files.pythonhosted.org/packages/7a/23/fae0ff9b54b0de4e819bbe559508da132d5683c32d84d0dc2ccce3563ed4/propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e", size = 206754, upload-time = "2025-06-09T22:54:21.716Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7f/ad6a3c22630aaa5f618b4dc3c3598974a72abb4c18e45a50b3cdd091eb2f/propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e", size = 218430, upload-time = "2025-06-09T22:54:23.17Z" }, - { url = "https://files.pythonhosted.org/packages/5b/2c/ba4f1c0e8a4b4c75910742f0d333759d441f65a1c7f34683b4a74c0ee015/propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf", size = 223884, upload-time = "2025-06-09T22:54:25.539Z" }, - { url = "https://files.pythonhosted.org/packages/88/e4/ebe30fc399e98572019eee82ad0caf512401661985cbd3da5e3140ffa1b0/propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e", size = 211480, upload-time = "2025-06-09T22:54:26.892Z" }, - { url = "https://files.pythonhosted.org/packages/96/0a/7d5260b914e01d1d0906f7f38af101f8d8ed0dc47426219eeaf05e8ea7c2/propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897", size = 37757, upload-time = "2025-06-09T22:54:28.241Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2d/89fe4489a884bc0da0c3278c552bd4ffe06a1ace559db5ef02ef24ab446b/propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39", size = 41500, upload-time = "2025-06-09T22:54:29.4Z" }, - { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, - { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, - { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, - { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, - { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, - { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, - { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, - { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, - { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, - { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, - { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, - { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, - { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, - { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, - { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, - { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, - { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, - { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, - { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, - { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, - { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, - { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, - { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, - { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, - { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, - { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, - { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, - { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, - { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, -] - -[[package]] -name = "pycryptodome" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" }, - { url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" }, - { url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" }, - { url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" }, - { url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" }, - { url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" }, - { url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" }, - { url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" }, - { url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" }, - { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, - { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, - { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, - { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, - { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, - { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, - { url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886, upload-time = "2025-05-17T17:21:20.614Z" }, - { url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151, upload-time = "2025-05-17T17:21:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461, upload-time = "2025-05-17T17:21:25.225Z" }, - { url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440, upload-time = "2025-05-17T17:21:27.991Z" }, - { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, -] - -[[package]] -name = "pydantic" -version = "2.10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/70/7e/fb60e6fee04d0ef8f15e4e01ff187a196fa976eb0f0ab524af4599e5754c/pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06", size = 762094, upload-time = "2024-12-18T17:09:24.84Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/26/3e1bbe954fde7ee22a6e7d31582c642aad9e84ffe4b5fb61e63b87cd326f/pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", size = 431765, upload-time = "2024-12-18T17:09:21.953Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.27.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443, upload-time = "2024-12-18T11:31:54.917Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938, upload-time = "2024-12-18T11:27:14.406Z" }, - { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684, upload-time = "2024-12-18T11:27:16.489Z" }, - { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169, upload-time = "2024-12-18T11:27:22.16Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227, upload-time = "2024-12-18T11:27:25.097Z" }, - { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695, upload-time = "2024-12-18T11:27:28.656Z" }, - { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662, upload-time = "2024-12-18T11:27:30.798Z" }, - { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370, upload-time = "2024-12-18T11:27:33.692Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813, upload-time = "2024-12-18T11:27:37.111Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287, upload-time = "2024-12-18T11:27:40.566Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414, upload-time = "2024-12-18T11:27:43.757Z" }, - { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301, upload-time = "2024-12-18T11:27:47.36Z" }, - { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685, upload-time = "2024-12-18T11:27:50.508Z" }, - { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876, upload-time = "2024-12-18T11:27:53.54Z" }, - { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421, upload-time = "2024-12-18T11:27:55.409Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998, upload-time = "2024-12-18T11:27:57.252Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167, upload-time = "2024-12-18T11:27:59.146Z" }, - { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071, upload-time = "2024-12-18T11:28:02.625Z" }, - { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244, upload-time = "2024-12-18T11:28:04.442Z" }, - { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470, upload-time = "2024-12-18T11:28:07.679Z" }, - { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291, upload-time = "2024-12-18T11:28:10.297Z" }, - { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613, upload-time = "2024-12-18T11:28:13.362Z" }, - { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355, upload-time = "2024-12-18T11:28:16.587Z" }, - { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661, upload-time = "2024-12-18T11:28:18.407Z" }, - { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261, upload-time = "2024-12-18T11:28:21.471Z" }, - { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361, upload-time = "2024-12-18T11:28:23.53Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484, upload-time = "2024-12-18T11:28:25.391Z" }, - { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102, upload-time = "2024-12-18T11:28:28.593Z" }, - { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127, upload-time = "2024-12-18T11:28:30.346Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340, upload-time = "2024-12-18T11:28:32.521Z" }, - { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900, upload-time = "2024-12-18T11:28:34.507Z" }, - { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177, upload-time = "2024-12-18T11:28:36.488Z" }, - { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046, upload-time = "2024-12-18T11:28:39.409Z" }, - { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386, upload-time = "2024-12-18T11:28:41.221Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060, upload-time = "2024-12-18T11:28:44.709Z" }, - { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870, upload-time = "2024-12-18T11:28:46.839Z" }, - { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822, upload-time = "2024-12-18T11:28:48.896Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364, upload-time = "2024-12-18T11:28:50.755Z" }, - { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303, upload-time = "2024-12-18T11:28:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064, upload-time = "2024-12-18T11:28:56.074Z" }, - { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046, upload-time = "2024-12-18T11:28:58.107Z" }, - { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092, upload-time = "2024-12-18T11:29:01.335Z" }, - { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709, upload-time = "2024-12-18T11:29:03.193Z" }, - { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273, upload-time = "2024-12-18T11:29:05.306Z" }, - { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027, upload-time = "2024-12-18T11:29:07.294Z" }, - { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888, upload-time = "2024-12-18T11:29:09.249Z" }, - { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738, upload-time = "2024-12-18T11:29:11.23Z" }, - { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138, upload-time = "2024-12-18T11:29:16.396Z" }, - { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025, upload-time = "2024-12-18T11:29:20.25Z" }, - { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633, upload-time = "2024-12-18T11:29:23.877Z" }, - { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404, upload-time = "2024-12-18T11:29:25.872Z" }, - { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130, upload-time = "2024-12-18T11:29:29.252Z" }, - { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946, upload-time = "2024-12-18T11:29:31.338Z" }, - { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387, upload-time = "2024-12-18T11:29:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453, upload-time = "2024-12-18T11:29:35.533Z" }, - { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186, upload-time = "2024-12-18T11:29:37.649Z" }, - { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159, upload-time = "2024-12-18T11:30:54.382Z" }, - { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331, upload-time = "2024-12-18T11:30:58.178Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467, upload-time = "2024-12-18T11:31:00.6Z" }, - { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797, upload-time = "2024-12-18T11:31:07.243Z" }, - { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839, upload-time = "2024-12-18T11:31:09.775Z" }, - { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861, upload-time = "2024-12-18T11:31:13.469Z" }, - { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582, upload-time = "2024-12-18T11:31:17.423Z" }, - { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985, upload-time = "2024-12-18T11:31:19.901Z" }, - { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715, upload-time = "2024-12-18T11:31:22.821Z" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234, upload-time = "2025-04-18T16:44:48.265Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356, upload-time = "2025-04-18T16:44:46.617Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920, upload-time = "2025-03-25T10:14:56.835Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256, upload-time = "2025-03-25T10:14:55.034Z" }, -] - -[[package]] -name = "python-multipart" -version = "0.0.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, -] - -[[package]] -name = "pyunormalize" -version = "16.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/08/568036c725dac746ecb267bb749ef930fb7907454fe69fce83c8557287fb/pyunormalize-16.0.0.tar.gz", hash = "sha256:2e1dfbb4a118154ae26f70710426a52a364b926c9191f764601f5a8cb12761f7", size = 49968, upload-time = "2024-09-17T17:08:18.245Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/f9/9d86e56f716e0651194a5ad58be9c146fcaf1de6901ac6f3cd3affeeb74e/pyunormalize-16.0.0-py3-none-any.whl", hash = "sha256:c647d95e5d1e2ea9a2f448d1d95d8518348df24eab5c3fd32d2b5c3300a49152", size = 49173, upload-time = "2024-09-17T17:08:17.078Z" }, -] - -[[package]] -name = "pywin32" -version = "310" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, - { url = "https://files.pythonhosted.org/packages/3c/84/1a8e3d7a15490d28a5d816efa229ecb4999cdc51a7c30dd8914f669093b8/pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213", size = 8522963, upload-time = "2025-03-17T00:55:50.969Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b1/68aa2986129fb1011dabbe95f0136f44509afaf072b12b8f815905a39f33/pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd", size = 8784284, upload-time = "2025-03-17T00:55:53.124Z" }, - { url = "https://files.pythonhosted.org/packages/b3/bd/d1592635992dd8db5bb8ace0551bc3a769de1ac8850200cfa517e72739fb/pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c", size = 9520748, upload-time = "2025-03-17T00:55:55.203Z" }, - { url = "https://files.pythonhosted.org/packages/90/b1/ac8b1ffce6603849eb45a91cf126c0fa5431f186c2e768bf56889c46f51c/pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582", size = 8455941, upload-time = "2025-03-17T00:55:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, - { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384, upload-time = "2025-03-17T00:56:04.383Z" }, - { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039, upload-time = "2025-03-17T00:56:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152, upload-time = "2025-03-17T00:56:07.819Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" }, - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, - { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669, upload-time = "2024-11-06T20:09:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684, upload-time = "2024-11-06T20:09:32.915Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589, upload-time = "2024-11-06T20:09:35.504Z" }, - { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121, upload-time = "2024-11-06T20:09:37.701Z" }, - { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275, upload-time = "2024-11-06T20:09:40.371Z" }, - { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257, upload-time = "2024-11-06T20:09:43.059Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727, upload-time = "2024-11-06T20:09:48.19Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667, upload-time = "2024-11-06T20:09:49.828Z" }, - { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963, upload-time = "2024-11-06T20:09:51.819Z" }, - { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700, upload-time = "2024-11-06T20:09:53.982Z" }, - { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592, upload-time = "2024-11-06T20:09:56.222Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929, upload-time = "2024-11-06T20:09:58.642Z" }, - { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213, upload-time = "2024-11-06T20:10:00.867Z" }, - { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734, upload-time = "2024-11-06T20:10:03.361Z" }, - { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052, upload-time = "2024-11-06T20:10:05.179Z" }, - { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, - { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, - { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, - { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, - { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, - { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, - { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, - { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, - { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, - { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, - { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, - { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, - { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, - { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, - { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, - { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, - { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, - { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, - { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, - { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, - { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, - { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, - { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, - { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, -] - -[[package]] -name = "requests" -version = "2.32.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, -] - -[[package]] -name = "rich" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, -] - -[[package]] -name = "rich-toolkit" -version = "0.14.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/7a/cb48b7024b247631ce39b1f14a0f1abedf311fb27b892b0e0387d809d4b5/rich_toolkit-0.14.7.tar.gz", hash = "sha256:6cca5a68850cc5778915f528eb785662c27ba3b4b2624612cce8340fa9701c5e", size = 104977, upload-time = "2025-05-27T15:48:09.377Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/2e/95fde5b818dac9a37683ea064096323f593442d0f6358923c5f635974393/rich_toolkit-0.14.7-py3-none-any.whl", hash = "sha256:def05cc6e0f1176d6263b6a26648f16a62c4563b277ca2f8538683acdba1e0da", size = 24870, upload-time = "2025-05-27T15:48:07.942Z" }, -] - -[[package]] -name = "rlp" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/2d/439b0728a92964a04d9c88ea1ca9ebb128893fbbd5834faa31f987f2fd4c/rlp-4.1.0.tar.gz", hash = "sha256:be07564270a96f3e225e2c107db263de96b5bc1f27722d2855bd3459a08e95a9", size = 33429, upload-time = "2025-02-04T22:05:59.089Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/fb/e4c0ced9893b84ac95b7181d69a9786ce5879aeb3bbbcbba80a164f85d6a/rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f", size = 19973, upload-time = "2025-02-04T22:05:57.05Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "starlette" -version = "0.46.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, -] - -[[package]] -name = "toolz" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790, upload-time = "2024-10-04T16:17:04.001Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383, upload-time = "2024-10-04T16:17:01.533Z" }, -] - -[[package]] -name = "typer" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, -] - -[[package]] -name = "types-requests" -version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/7f/73b3a04a53b0fd2a911d4ec517940ecd6600630b559e4505cc7b68beb5a0/types_requests-2.32.4.20250611.tar.gz", hash = "sha256:741c8777ed6425830bf51e54d6abe245f79b4dcb9019f1622b773463946bf826", size = 23118, upload-time = "2025-06-11T03:11:41.272Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/ea/0be9258c5a4fa1ba2300111aa5a0767ee6d18eb3fd20e91616c12082284d/types_requests-2.32.4.20250611-py3-none-any.whl", hash = "sha256:ad2fe5d3b0cb3c2c902c8815a70e7fb2302c4b8c1f77bdcd738192cdb3878072", size = 20643, upload-time = "2025-06-11T03:11:40.186Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, -] - -[[package]] -name = "urllib3" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, -] - -[[package]] -name = "uvicorn" -version = "0.34.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631, upload-time = "2025-06-01T07:48:17.531Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431, upload-time = "2025-06-01T07:48:15.664Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, - { url = "https://files.pythonhosted.org/packages/35/5a/62d5800358a78cc25c8a6c72ef8b10851bdb8cca22e14d9c74167b7f86da/uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d", size = 801898, upload-time = "2024-10-14T23:37:22.663Z" }, - { url = "https://files.pythonhosted.org/packages/f3/96/63695e0ebd7da6c741ccd4489b5947394435e198a1382349c17b1146bb97/uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26", size = 3827735, upload-time = "2024-10-14T23:37:25.129Z" }, - { url = "https://files.pythonhosted.org/packages/61/e0/f0f8ec84979068ffae132c58c79af1de9cceeb664076beea86d941af1a30/uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb", size = 3825126, upload-time = "2024-10-14T23:37:27.59Z" }, - { url = "https://files.pythonhosted.org/packages/bf/fe/5e94a977d058a54a19df95f12f7161ab6e323ad49f4dabc28822eb2df7ea/uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f", size = 3705789, upload-time = "2024-10-14T23:37:29.385Z" }, - { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523, upload-time = "2024-10-14T23:37:32.048Z" }, - { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410, upload-time = "2024-10-14T23:37:33.612Z" }, - { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476, upload-time = "2024-10-14T23:37:36.11Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855, upload-time = "2024-10-14T23:37:37.683Z" }, - { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185, upload-time = "2024-10-14T23:37:40.226Z" }, - { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256, upload-time = "2024-10-14T23:37:42.839Z" }, - { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323, upload-time = "2024-10-14T23:37:45.337Z" }, - { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284, upload-time = "2024-10-14T23:37:47.833Z" }, - { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349, upload-time = "2024-10-14T23:37:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089, upload-time = "2024-10-14T23:37:51.703Z" }, - { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770, upload-time = "2024-10-14T23:37:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321, upload-time = "2024-10-14T23:37:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022, upload-time = "2024-10-14T23:37:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" }, - { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" }, - { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" }, - { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" }, - { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" }, - { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" }, -] - -[[package]] -name = "watchfiles" -version = "1.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/e2/8ed598c42057de7aa5d97c472254af4906ff0a59a66699d426fc9ef795d7/watchfiles-1.0.5.tar.gz", hash = "sha256:b7529b5dcc114679d43827d8c35a07c493ad6f083633d573d81c660abc5979e9", size = 94537, upload-time = "2025-04-08T10:36:26.722Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/4d/d02e6ea147bb7fff5fd109c694a95109612f419abed46548a930e7f7afa3/watchfiles-1.0.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5c40fe7dd9e5f81e0847b1ea64e1f5dd79dd61afbedb57759df06767ac719b40", size = 405632, upload-time = "2025-04-08T10:34:41.832Z" }, - { url = "https://files.pythonhosted.org/packages/60/31/9ee50e29129d53a9a92ccf1d3992751dc56fc3c8f6ee721be1c7b9c81763/watchfiles-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c0db396e6003d99bb2d7232c957b5f0b5634bbd1b24e381a5afcc880f7373fb", size = 395734, upload-time = "2025-04-08T10:34:44.236Z" }, - { url = "https://files.pythonhosted.org/packages/ad/8c/759176c97195306f028024f878e7f1c776bda66ccc5c68fa51e699cf8f1d/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b551d4fb482fc57d852b4541f911ba28957d051c8776e79c3b4a51eb5e2a1b11", size = 455008, upload-time = "2025-04-08T10:34:45.617Z" }, - { url = "https://files.pythonhosted.org/packages/55/1a/5e977250c795ee79a0229e3b7f5e3a1b664e4e450756a22da84d2f4979fe/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:830aa432ba5c491d52a15b51526c29e4a4b92bf4f92253787f9726fe01519487", size = 459029, upload-time = "2025-04-08T10:34:46.814Z" }, - { url = "https://files.pythonhosted.org/packages/e6/17/884cf039333605c1d6e296cf5be35fad0836953c3dfd2adb71b72f9dbcd0/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a16512051a822a416b0d477d5f8c0e67b67c1a20d9acecb0aafa3aa4d6e7d256", size = 488916, upload-time = "2025-04-08T10:34:48.571Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e0/bcb6e64b45837056c0a40f3a2db3ef51c2ced19fda38484fa7508e00632c/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe0cbc787770e52a96c6fda6726ace75be7f840cb327e1b08d7d54eadc3bc85", size = 523763, upload-time = "2025-04-08T10:34:50.268Z" }, - { url = "https://files.pythonhosted.org/packages/24/e9/f67e9199f3bb35c1837447ecf07e9830ec00ff5d35a61e08c2cd67217949/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d363152c5e16b29d66cbde8fa614f9e313e6f94a8204eaab268db52231fe5358", size = 502891, upload-time = "2025-04-08T10:34:51.419Z" }, - { url = "https://files.pythonhosted.org/packages/23/ed/a6cf815f215632f5c8065e9c41fe872025ffea35aa1f80499f86eae922db/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee32c9a9bee4d0b7bd7cbeb53cb185cf0b622ac761efaa2eba84006c3b3a614", size = 454921, upload-time = "2025-04-08T10:34:52.67Z" }, - { url = "https://files.pythonhosted.org/packages/92/4c/e14978599b80cde8486ab5a77a821e8a982ae8e2fcb22af7b0886a033ec8/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29c7fd632ccaf5517c16a5188e36f6612d6472ccf55382db6c7fe3fcccb7f59f", size = 631422, upload-time = "2025-04-08T10:34:53.985Z" }, - { url = "https://files.pythonhosted.org/packages/b2/1a/9263e34c3458f7614b657f974f4ee61fd72f58adce8b436e16450e054efd/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e637810586e6fe380c8bc1b3910accd7f1d3a9a7262c8a78d4c8fb3ba6a2b3d", size = 625675, upload-time = "2025-04-08T10:34:55.173Z" }, - { url = "https://files.pythonhosted.org/packages/96/1f/1803a18bd6ab04a0766386a19bcfe64641381a04939efdaa95f0e3b0eb58/watchfiles-1.0.5-cp310-cp310-win32.whl", hash = "sha256:cd47d063fbeabd4c6cae1d4bcaa38f0902f8dc5ed168072874ea11d0c7afc1ff", size = 277921, upload-time = "2025-04-08T10:34:56.318Z" }, - { url = "https://files.pythonhosted.org/packages/c2/3b/29a89de074a7d6e8b4dc67c26e03d73313e4ecf0d6e97e942a65fa7c195e/watchfiles-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:86c0df05b47a79d80351cd179893f2f9c1b1cae49d96e8b3290c7f4bd0ca0a92", size = 291526, upload-time = "2025-04-08T10:34:57.95Z" }, - { url = "https://files.pythonhosted.org/packages/39/f4/41b591f59021786ef517e1cdc3b510383551846703e03f204827854a96f8/watchfiles-1.0.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:237f9be419e977a0f8f6b2e7b0475ababe78ff1ab06822df95d914a945eac827", size = 405336, upload-time = "2025-04-08T10:34:59.359Z" }, - { url = "https://files.pythonhosted.org/packages/ae/06/93789c135be4d6d0e4f63e96eea56dc54050b243eacc28439a26482b5235/watchfiles-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0da39ff917af8b27a4bdc5a97ac577552a38aac0d260a859c1517ea3dc1a7c4", size = 395977, upload-time = "2025-04-08T10:35:00.522Z" }, - { url = "https://files.pythonhosted.org/packages/d2/db/1cd89bd83728ca37054512d4d35ab69b5f12b8aa2ac9be3b0276b3bf06cc/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cfcb3952350e95603f232a7a15f6c5f86c5375e46f0bd4ae70d43e3e063c13d", size = 455232, upload-time = "2025-04-08T10:35:01.698Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/d8a4d44ffe960517e487c9c04f77b06b8abf05eb680bed71c82b5f2cad62/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b2dddba7a4e6151384e252a5632efcaa9bc5d1c4b567f3cb621306b2ca9f63", size = 459151, upload-time = "2025-04-08T10:35:03.358Z" }, - { url = "https://files.pythonhosted.org/packages/6c/da/267a1546f26465dead1719caaba3ce660657f83c9d9c052ba98fb8856e13/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95cf944fcfc394c5f9de794ce581914900f82ff1f855326f25ebcf24d5397418", size = 489054, upload-time = "2025-04-08T10:35:04.561Z" }, - { url = "https://files.pythonhosted.org/packages/b1/31/33850dfd5c6efb6f27d2465cc4c6b27c5a6f5ed53c6fa63b7263cf5f60f6/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecf6cd9f83d7c023b1aba15d13f705ca7b7d38675c121f3cc4a6e25bd0857ee9", size = 523955, upload-time = "2025-04-08T10:35:05.786Z" }, - { url = "https://files.pythonhosted.org/packages/09/84/b7d7b67856efb183a421f1416b44ca975cb2ea6c4544827955dfb01f7dc2/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:852de68acd6212cd6d33edf21e6f9e56e5d98c6add46f48244bd479d97c967c6", size = 502234, upload-time = "2025-04-08T10:35:07.187Z" }, - { url = "https://files.pythonhosted.org/packages/71/87/6dc5ec6882a2254cfdd8b0718b684504e737273903b65d7338efaba08b52/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5730f3aa35e646103b53389d5bc77edfbf578ab6dab2e005142b5b80a35ef25", size = 454750, upload-time = "2025-04-08T10:35:08.859Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6c/3786c50213451a0ad15170d091570d4a6554976cf0df19878002fc96075a/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:18b3bd29954bc4abeeb4e9d9cf0b30227f0f206c86657674f544cb032296acd5", size = 631591, upload-time = "2025-04-08T10:35:10.64Z" }, - { url = "https://files.pythonhosted.org/packages/1b/b3/1427425ade4e359a0deacce01a47a26024b2ccdb53098f9d64d497f6684c/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ba5552a1b07c8edbf197055bc9d518b8f0d98a1c6a73a293bc0726dce068ed01", size = 625370, upload-time = "2025-04-08T10:35:12.412Z" }, - { url = "https://files.pythonhosted.org/packages/15/ba/f60e053b0b5b8145d682672024aa91370a29c5c921a88977eb565de34086/watchfiles-1.0.5-cp311-cp311-win32.whl", hash = "sha256:2f1fefb2e90e89959447bc0420fddd1e76f625784340d64a2f7d5983ef9ad246", size = 277791, upload-time = "2025-04-08T10:35:13.719Z" }, - { url = "https://files.pythonhosted.org/packages/50/ed/7603c4e164225c12c0d4e8700b64bb00e01a6c4eeea372292a3856be33a4/watchfiles-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:b6e76ceb1dd18c8e29c73f47d41866972e891fc4cc7ba014f487def72c1cf096", size = 291622, upload-time = "2025-04-08T10:35:15.071Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c2/99bb7c96b4450e36877fde33690ded286ff555b5a5c1d925855d556968a1/watchfiles-1.0.5-cp311-cp311-win_arm64.whl", hash = "sha256:266710eb6fddc1f5e51843c70e3bebfb0f5e77cf4f27129278c70554104d19ed", size = 283699, upload-time = "2025-04-08T10:35:16.732Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8c/4f0b9bdb75a1bfbd9c78fad7d8854369283f74fe7cf03eb16be77054536d/watchfiles-1.0.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5eb568c2aa6018e26da9e6c86f3ec3fd958cee7f0311b35c2630fa4217d17f2", size = 401511, upload-time = "2025-04-08T10:35:17.956Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4e/7e15825def77f8bd359b6d3f379f0c9dac4eb09dd4ddd58fd7d14127179c/watchfiles-1.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a04059f4923ce4e856b4b4e5e783a70f49d9663d22a4c3b3298165996d1377f", size = 392715, upload-time = "2025-04-08T10:35:19.202Z" }, - { url = "https://files.pythonhosted.org/packages/58/65/b72fb817518728e08de5840d5d38571466c1b4a3f724d190cec909ee6f3f/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e380c89983ce6e6fe2dd1e1921b9952fb4e6da882931abd1824c092ed495dec", size = 454138, upload-time = "2025-04-08T10:35:20.586Z" }, - { url = "https://files.pythonhosted.org/packages/3e/a4/86833fd2ea2e50ae28989f5950b5c3f91022d67092bfec08f8300d8b347b/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe43139b2c0fdc4a14d4f8d5b5d967f7a2777fd3d38ecf5b1ec669b0d7e43c21", size = 458592, upload-time = "2025-04-08T10:35:21.87Z" }, - { url = "https://files.pythonhosted.org/packages/38/7e/42cb8df8be9a37e50dd3a818816501cf7a20d635d76d6bd65aae3dbbff68/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee0822ce1b8a14fe5a066f93edd20aada932acfe348bede8aa2149f1a4489512", size = 487532, upload-time = "2025-04-08T10:35:23.143Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/13d26721c85d7f3df6169d8b495fcac8ab0dc8f0945ebea8845de4681dab/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0dbcb1c2d8f2ab6e0a81c6699b236932bd264d4cef1ac475858d16c403de74d", size = 522865, upload-time = "2025-04-08T10:35:24.702Z" }, - { url = "https://files.pythonhosted.org/packages/a1/0d/7f9ae243c04e96c5455d111e21b09087d0eeaf9a1369e13a01c7d3d82478/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2014a2b18ad3ca53b1f6c23f8cd94a18ce930c1837bd891262c182640eb40a6", size = 499887, upload-time = "2025-04-08T10:35:25.969Z" }, - { url = "https://files.pythonhosted.org/packages/8e/0f/a257766998e26aca4b3acf2ae97dff04b57071e991a510857d3799247c67/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6ae86d5cb647bf58f9f655fcf577f713915a5d69057a0371bc257e2553234", size = 454498, upload-time = "2025-04-08T10:35:27.353Z" }, - { url = "https://files.pythonhosted.org/packages/81/79/8bf142575a03e0af9c3d5f8bcae911ee6683ae93a625d349d4ecf4c8f7df/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1a7bac2bde1d661fb31f4d4e8e539e178774b76db3c2c17c4bb3e960a5de07a2", size = 630663, upload-time = "2025-04-08T10:35:28.685Z" }, - { url = "https://files.pythonhosted.org/packages/f1/80/abe2e79f610e45c63a70d271caea90c49bbf93eb00fa947fa9b803a1d51f/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ab626da2fc1ac277bbf752446470b367f84b50295264d2d313e28dc4405d663", size = 625410, upload-time = "2025-04-08T10:35:30.42Z" }, - { url = "https://files.pythonhosted.org/packages/91/6f/bc7fbecb84a41a9069c2c6eb6319f7f7df113adf113e358c57fc1aff7ff5/watchfiles-1.0.5-cp312-cp312-win32.whl", hash = "sha256:9f4571a783914feda92018ef3901dab8caf5b029325b5fe4558c074582815249", size = 277965, upload-time = "2025-04-08T10:35:32.023Z" }, - { url = "https://files.pythonhosted.org/packages/99/a5/bf1c297ea6649ec59e935ab311f63d8af5faa8f0b86993e3282b984263e3/watchfiles-1.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:360a398c3a19672cf93527f7e8d8b60d8275119c5d900f2e184d32483117a705", size = 291693, upload-time = "2025-04-08T10:35:33.225Z" }, - { url = "https://files.pythonhosted.org/packages/7f/7b/fd01087cc21db5c47e5beae507b87965db341cce8a86f9eb12bf5219d4e0/watchfiles-1.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:1a2902ede862969077b97523987c38db28abbe09fb19866e711485d9fbf0d417", size = 283287, upload-time = "2025-04-08T10:35:34.568Z" }, - { url = "https://files.pythonhosted.org/packages/c7/62/435766874b704f39b2fecd8395a29042db2b5ec4005bd34523415e9bd2e0/watchfiles-1.0.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0b289572c33a0deae62daa57e44a25b99b783e5f7aed81b314232b3d3c81a11d", size = 401531, upload-time = "2025-04-08T10:35:35.792Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a6/e52a02c05411b9cb02823e6797ef9bbba0bfaf1bb627da1634d44d8af833/watchfiles-1.0.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a056c2f692d65bf1e99c41045e3bdcaea3cb9e6b5a53dcaf60a5f3bd95fc9763", size = 392417, upload-time = "2025-04-08T10:35:37.048Z" }, - { url = "https://files.pythonhosted.org/packages/3f/53/c4af6819770455932144e0109d4854437769672d7ad897e76e8e1673435d/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9dca99744991fc9850d18015c4f0438865414e50069670f5f7eee08340d8b40", size = 453423, upload-time = "2025-04-08T10:35:38.357Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d1/8e88df58bbbf819b8bc5cfbacd3c79e01b40261cad0fc84d1e1ebd778a07/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:894342d61d355446d02cd3988a7326af344143eb33a2fd5d38482a92072d9563", size = 458185, upload-time = "2025-04-08T10:35:39.708Z" }, - { url = "https://files.pythonhosted.org/packages/ff/70/fffaa11962dd5429e47e478a18736d4e42bec42404f5ee3b92ef1b87ad60/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab44e1580924d1ffd7b3938e02716d5ad190441965138b4aa1d1f31ea0877f04", size = 486696, upload-time = "2025-04-08T10:35:41.469Z" }, - { url = "https://files.pythonhosted.org/packages/39/db/723c0328e8b3692d53eb273797d9a08be6ffb1d16f1c0ba2bdbdc2a3852c/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6f9367b132078b2ceb8d066ff6c93a970a18c3029cea37bfd7b2d3dd2e5db8f", size = 522327, upload-time = "2025-04-08T10:35:43.289Z" }, - { url = "https://files.pythonhosted.org/packages/cd/05/9fccc43c50c39a76b68343484b9da7b12d42d0859c37c61aec018c967a32/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2e55a9b162e06e3f862fb61e399fe9f05d908d019d87bf5b496a04ef18a970a", size = 499741, upload-time = "2025-04-08T10:35:44.574Z" }, - { url = "https://files.pythonhosted.org/packages/23/14/499e90c37fa518976782b10a18b18db9f55ea73ca14641615056f8194bb3/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0125f91f70e0732a9f8ee01e49515c35d38ba48db507a50c5bdcad9503af5827", size = 453995, upload-time = "2025-04-08T10:35:46.336Z" }, - { url = "https://files.pythonhosted.org/packages/61/d9/f75d6840059320df5adecd2c687fbc18960a7f97b55c300d20f207d48aef/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:13bb21f8ba3248386337c9fa51c528868e6c34a707f729ab041c846d52a0c69a", size = 629693, upload-time = "2025-04-08T10:35:48.161Z" }, - { url = "https://files.pythonhosted.org/packages/fc/17/180ca383f5061b61406477218c55d66ec118e6c0c51f02d8142895fcf0a9/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:839ebd0df4a18c5b3c1b890145b5a3f5f64063c2a0d02b13c76d78fe5de34936", size = 624677, upload-time = "2025-04-08T10:35:49.65Z" }, - { url = "https://files.pythonhosted.org/packages/bf/15/714d6ef307f803f236d69ee9d421763707899d6298d9f3183e55e366d9af/watchfiles-1.0.5-cp313-cp313-win32.whl", hash = "sha256:4a8ec1e4e16e2d5bafc9ba82f7aaecfeec990ca7cd27e84fb6f191804ed2fcfc", size = 277804, upload-time = "2025-04-08T10:35:51.093Z" }, - { url = "https://files.pythonhosted.org/packages/a8/b4/c57b99518fadf431f3ef47a610839e46e5f8abf9814f969859d1c65c02c7/watchfiles-1.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:f436601594f15bf406518af922a89dcaab416568edb6f65c4e5bbbad1ea45c11", size = 291087, upload-time = "2025-04-08T10:35:52.458Z" }, - { url = "https://files.pythonhosted.org/packages/1a/03/81f9fcc3963b3fc415cd4b0b2b39ee8cc136c42fb10a36acf38745e9d283/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f59b870db1f1ae5a9ac28245707d955c8721dd6565e7f411024fa374b5362d1d", size = 405947, upload-time = "2025-04-08T10:36:13.721Z" }, - { url = "https://files.pythonhosted.org/packages/54/97/8c4213a852feb64807ec1d380f42d4fc8bfaef896bdbd94318f8fd7f3e4e/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9475b0093767e1475095f2aeb1d219fb9664081d403d1dff81342df8cd707034", size = 397276, upload-time = "2025-04-08T10:36:15.131Z" }, - { url = "https://files.pythonhosted.org/packages/78/12/d4464d19860cb9672efa45eec1b08f8472c478ed67dcd30647c51ada7aef/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc533aa50664ebd6c628b2f30591956519462f5d27f951ed03d6c82b2dfd9965", size = 455550, upload-time = "2025-04-08T10:36:16.635Z" }, - { url = "https://files.pythonhosted.org/packages/90/fb/b07bcdf1034d8edeaef4c22f3e9e3157d37c5071b5f9492ffdfa4ad4bed7/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed1cd825158dcaae36acce7b2db33dcbfd12b30c34317a88b8ed80f0541cc57", size = 455542, upload-time = "2025-04-08T10:36:18.655Z" }, -] - -[[package]] -name = "web3" -version = "7.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "eth-abi" }, - { name = "eth-account" }, - { name = "eth-hash", extra = ["pycryptodome"] }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "pyunormalize" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "requests" }, - { name = "types-requests" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7d/1e/fc1f5b5a12615cbdca57d35014cdb9823db7392d73b730fa0d89d6a13f6a/web3-7.12.0.tar.gz", hash = "sha256:08fbe79a2e2503c9820132ebad24ba0372831588cabac5f467999c97ace7dda3", size = 2195693, upload-time = "2025-05-22T21:06:05.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/df/0ccf18f244b96a93ba2710f7ce696da1f8dd44ef1126e3603dfb65cd68fe/web3-7.12.0-py3-none-any.whl", hash = "sha256:c7e2b9c1db5a379ef53b45fe8a19bdc2d47ad262039fbf6675794bc40f74bf06", size = 1369328, upload-time = "2025-05-22T21:06:03.124Z" }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, - { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, - { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, - { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, - { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, - { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, - { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, - { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, - { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - -[[package]] -name = "werkzeug" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, -] - -[[package]] -name = "x402" -version = "1.0.0" -source = { editable = "../../../../../python/legacy" } -dependencies = [ - { name = "eth-account" }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "fastapi", extra = ["standard"] }, - { name = "flask" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "web3" }, -] - -[package.metadata] -requires-dist = [ - { name = "eth-account", specifier = ">=0.13.7" }, - { name = "eth-typing", specifier = ">=4.0.0" }, - { name = "eth-utils", specifier = ">=3.0.0" }, - { name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" }, - { name = "flask", specifier = ">=3.0.0" }, - { name = "pydantic", specifier = ">=2.10.3" }, - { name = "pydantic-settings", specifier = ">=2.2.1" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "web3", specifier = ">=6.0.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.5" }, - { name = "pytest-asyncio", specifier = ">=1.0.0" }, - { name = "ruff", specifier = ">=0.11.9" }, -] - -[[package]] -name = "x402-fastapi-example" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "fastapi" }, - { name = "python-dotenv" }, - { name = "uvicorn" }, - { name = "x402" }, -] - -[package.metadata] -requires-dist = [ - { name = "fastapi", specifier = ">=0.109.0" }, - { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "uvicorn", specifier = ">=0.27.0" }, - { name = "x402", editable = "../../../../../python/legacy" }, -] - -[[package]] -name = "yarl" -version = "1.20.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/65/7fed0d774abf47487c64be14e9223749468922817b5e8792b8a64792a1bb/yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4", size = 132910, upload-time = "2025-06-10T00:42:31.108Z" }, - { url = "https://files.pythonhosted.org/packages/8a/7b/988f55a52da99df9e56dc733b8e4e5a6ae2090081dc2754fc8fd34e60aa0/yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a", size = 90644, upload-time = "2025-06-10T00:42:33.851Z" }, - { url = "https://files.pythonhosted.org/packages/f7/de/30d98f03e95d30c7e3cc093759982d038c8833ec2451001d45ef4854edc1/yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed", size = 89322, upload-time = "2025-06-10T00:42:35.688Z" }, - { url = "https://files.pythonhosted.org/packages/e0/7a/f2f314f5ebfe9200724b0b748de2186b927acb334cf964fd312eb86fc286/yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e", size = 323786, upload-time = "2025-06-10T00:42:37.817Z" }, - { url = "https://files.pythonhosted.org/packages/15/3f/718d26f189db96d993d14b984ce91de52e76309d0fd1d4296f34039856aa/yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73", size = 319627, upload-time = "2025-06-10T00:42:39.937Z" }, - { url = "https://files.pythonhosted.org/packages/a5/76/8fcfbf5fa2369157b9898962a4a7d96764b287b085b5b3d9ffae69cdefd1/yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e", size = 339149, upload-time = "2025-06-10T00:42:42.627Z" }, - { url = "https://files.pythonhosted.org/packages/3c/95/d7fc301cc4661785967acc04f54a4a42d5124905e27db27bb578aac49b5c/yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8", size = 333327, upload-time = "2025-06-10T00:42:44.842Z" }, - { url = "https://files.pythonhosted.org/packages/65/94/e21269718349582eee81efc5c1c08ee71c816bfc1585b77d0ec3f58089eb/yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23", size = 326054, upload-time = "2025-06-10T00:42:47.149Z" }, - { url = "https://files.pythonhosted.org/packages/32/ae/8616d1f07853704523519f6131d21f092e567c5af93de7e3e94b38d7f065/yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70", size = 315035, upload-time = "2025-06-10T00:42:48.852Z" }, - { url = "https://files.pythonhosted.org/packages/48/aa/0ace06280861ef055855333707db5e49c6e3a08840a7ce62682259d0a6c0/yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb", size = 338962, upload-time = "2025-06-10T00:42:51.024Z" }, - { url = "https://files.pythonhosted.org/packages/20/52/1e9d0e6916f45a8fb50e6844f01cb34692455f1acd548606cbda8134cd1e/yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2", size = 335399, upload-time = "2025-06-10T00:42:53.007Z" }, - { url = "https://files.pythonhosted.org/packages/f2/65/60452df742952c630e82f394cd409de10610481d9043aa14c61bf846b7b1/yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30", size = 338649, upload-time = "2025-06-10T00:42:54.964Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f5/6cd4ff38dcde57a70f23719a838665ee17079640c77087404c3d34da6727/yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309", size = 358563, upload-time = "2025-06-10T00:42:57.28Z" }, - { url = "https://files.pythonhosted.org/packages/d1/90/c42eefd79d0d8222cb3227bdd51b640c0c1d0aa33fe4cc86c36eccba77d3/yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24", size = 357609, upload-time = "2025-06-10T00:42:59.055Z" }, - { url = "https://files.pythonhosted.org/packages/03/c8/cea6b232cb4617514232e0f8a718153a95b5d82b5290711b201545825532/yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13", size = 350224, upload-time = "2025-06-10T00:43:01.248Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a3/eaa0ab9712f1f3d01faf43cf6f1f7210ce4ea4a7e9b28b489a2261ca8db9/yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8", size = 81753, upload-time = "2025-06-10T00:43:03.486Z" }, - { url = "https://files.pythonhosted.org/packages/8f/34/e4abde70a9256465fe31c88ed02c3f8502b7b5dead693a4f350a06413f28/yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16", size = 86817, upload-time = "2025-06-10T00:43:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b1/18/893b50efc2350e47a874c5c2d67e55a0ea5df91186b2a6f5ac52eff887cd/yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e", size = 133833, upload-time = "2025-06-10T00:43:07.393Z" }, - { url = "https://files.pythonhosted.org/packages/89/ed/b8773448030e6fc47fa797f099ab9eab151a43a25717f9ac043844ad5ea3/yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b", size = 91070, upload-time = "2025-06-10T00:43:09.538Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e3/409bd17b1e42619bf69f60e4f031ce1ccb29bd7380117a55529e76933464/yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b", size = 89818, upload-time = "2025-06-10T00:43:11.575Z" }, - { url = "https://files.pythonhosted.org/packages/f8/77/64d8431a4d77c856eb2d82aa3de2ad6741365245a29b3a9543cd598ed8c5/yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4", size = 347003, upload-time = "2025-06-10T00:43:14.088Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d2/0c7e4def093dcef0bd9fa22d4d24b023788b0a33b8d0088b51aa51e21e99/yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1", size = 336537, upload-time = "2025-06-10T00:43:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f3/fc514f4b2cf02cb59d10cbfe228691d25929ce8f72a38db07d3febc3f706/yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833", size = 362358, upload-time = "2025-06-10T00:43:18.704Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6d/a313ac8d8391381ff9006ac05f1d4331cee3b1efaa833a53d12253733255/yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d", size = 357362, upload-time = "2025-06-10T00:43:20.888Z" }, - { url = "https://files.pythonhosted.org/packages/00/70/8f78a95d6935a70263d46caa3dd18e1f223cf2f2ff2037baa01a22bc5b22/yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8", size = 348979, upload-time = "2025-06-10T00:43:23.169Z" }, - { url = "https://files.pythonhosted.org/packages/cb/05/42773027968968f4f15143553970ee36ead27038d627f457cc44bbbeecf3/yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf", size = 337274, upload-time = "2025-06-10T00:43:27.111Z" }, - { url = "https://files.pythonhosted.org/packages/05/be/665634aa196954156741ea591d2f946f1b78ceee8bb8f28488bf28c0dd62/yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e", size = 363294, upload-time = "2025-06-10T00:43:28.96Z" }, - { url = "https://files.pythonhosted.org/packages/eb/90/73448401d36fa4e210ece5579895731f190d5119c4b66b43b52182e88cd5/yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389", size = 358169, upload-time = "2025-06-10T00:43:30.701Z" }, - { url = "https://files.pythonhosted.org/packages/c3/b0/fce922d46dc1eb43c811f1889f7daa6001b27a4005587e94878570300881/yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f", size = 362776, upload-time = "2025-06-10T00:43:32.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/0d/b172628fce039dae8977fd22caeff3eeebffd52e86060413f5673767c427/yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845", size = 381341, upload-time = "2025-06-10T00:43:34.543Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9b/5b886d7671f4580209e855974fe1cecec409aa4a89ea58b8f0560dc529b1/yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1", size = 379988, upload-time = "2025-06-10T00:43:36.489Z" }, - { url = "https://files.pythonhosted.org/packages/73/be/75ef5fd0fcd8f083a5d13f78fd3f009528132a1f2a1d7c925c39fa20aa79/yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e", size = 371113, upload-time = "2025-06-10T00:43:38.592Z" }, - { url = "https://files.pythonhosted.org/packages/50/4f/62faab3b479dfdcb741fe9e3f0323e2a7d5cd1ab2edc73221d57ad4834b2/yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773", size = 81485, upload-time = "2025-06-10T00:43:41.038Z" }, - { url = "https://files.pythonhosted.org/packages/f0/09/d9c7942f8f05c32ec72cd5c8e041c8b29b5807328b68b4801ff2511d4d5e/yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e", size = 86686, upload-time = "2025-06-10T00:43:42.692Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, - { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, - { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, - { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, - { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, - { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, - { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, - { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, - { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, - { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, - { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, - { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, - { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, - { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, - { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, - { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, - { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, - { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, - { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, - { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, - { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, - { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, - { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, - { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, - { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, - { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, - { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, - { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, - { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, - { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, - { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, - { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, - { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, - { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, - { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, - { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, - { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, -] diff --git a/examples/python/legacy/fullstack/flask/.env-local b/examples/python/legacy/fullstack/flask/.env-local deleted file mode 100644 index 8b7902c216..0000000000 --- a/examples/python/legacy/fullstack/flask/.env-local +++ /dev/null @@ -1,7 +0,0 @@ -NETWORK=base-sepolia -ADDRESS= -CDP_API_KEY_ID= -CDP_API_KEY_SECRET= - -# Optional: -CDP_CLIENT_KEY= \ No newline at end of file diff --git a/examples/python/legacy/fullstack/flask/README.md b/examples/python/legacy/fullstack/flask/README.md deleted file mode 100644 index 79dd701bff..0000000000 --- a/examples/python/legacy/fullstack/flask/README.md +++ /dev/null @@ -1,55 +0,0 @@ -# x402 Flask Example Server - -This is an example Flask server that demonstrates how to use the x402 `flask` middleware to implement paywall functionality in your API endpoints. - -## Prerequisites - -- Python 3.10+ -- A valid Ethereum address for receiving payments -- Optional: CDP API Client Key (requires a Coinbase Developer Platform account) - -## Setup - -1. Copy `.env-local` to `.env` and add your Ethereum address to receive payments: - -```bash -cp .env-local .env -``` - -2. Install dependencies: - -```bash -uv sync -``` - -3. Run the server: - -```bash -uv run python main.py -``` - -The server will start on http://localhost:4021 - -## Extending the Example - -To add more paid endpoints, follow this pattern: - -```python -# First, initialize the payment middleware -payment_middleware = PaymentMiddleware(app) - -# Then add payment configurations for your routes -payment_middleware.add( - path="/your-endpoint", - price="$0.10", - pay_to_address=ADDRESS, - network=NETWORK, -) - -# Then define your routes as normal -@app.route("/your-endpoint") -def your_endpoint(): - return jsonify({ - # Your response data - }) -``` diff --git a/examples/python/legacy/fullstack/flask/main.py b/examples/python/legacy/fullstack/flask/main.py deleted file mode 100644 index 7adf42dcdf..0000000000 --- a/examples/python/legacy/fullstack/flask/main.py +++ /dev/null @@ -1,53 +0,0 @@ -import os -from waitress import serve - -from dotenv import load_dotenv -from flask import Flask, send_from_directory -from x402.flask.middleware import PaymentMiddleware -from x402.types import PaywallConfig - -# Load environment variables -load_dotenv() - -# Get configuration from environment -NETWORK = os.getenv("NETWORK", "base-sepolia") -ADDRESS = os.getenv("ADDRESS") -CDP_CLIENT_KEY = os.getenv("CDP_CLIENT_KEY") - -if not ADDRESS: - raise ValueError("Missing required environment variables") - -app = Flask(__name__) - - -# Configure Flask to serve static files -@app.route("/static/") -def serve_static(filename): - return send_from_directory("static", filename) - - -# Initialize payment middleware -payment_middleware = PaymentMiddleware(app) - -# Apply payment middleware to premium routes with paywall config -payment_middleware.add( - path="/premium/*", - price="$0.01", - pay_to_address=ADDRESS, - network=NETWORK, - paywall_config=PaywallConfig( - cdp_client_key=CDP_CLIENT_KEY or "", - app_name="x402 Python Example", - app_logo="/static/x402.png", - ), -) - - -@app.route("/premium/content") -def get_premium_content(): - return send_from_directory("static", "premium.html") - - -if __name__ == "__main__": - print("Starting server on http://0.0.0.0:4021") - serve(app, host="0.0.0.0", port=4021) diff --git a/examples/python/legacy/fullstack/flask/pyproject.toml b/examples/python/legacy/fullstack/flask/pyproject.toml deleted file mode 100644 index 829ff02aa0..0000000000 --- a/examples/python/legacy/fullstack/flask/pyproject.toml +++ /dev/null @@ -1,28 +0,0 @@ -[project] -name = "x402-mainnet-example" -version = "0.1.0" -description = "Example of using a fastapi server with x402 middleware" -requires-python = ">=3.10" -dependencies = [ - "x402", - "cdp-sdk>=1.15.0", - "Flask>=3.1.1", - "waitress>=2.1.2", - "python-dotenv>=1.0.0" -] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -packages = ["."] - -[tool.hatch.metadata] -allow-direct-references = true - -[tool.uv] -package = false - -[tool.uv.sources] -x402 = { path = "../../../../../python/legacy", editable = true } diff --git a/examples/python/legacy/fullstack/flask/static/premium.html b/examples/python/legacy/fullstack/flask/static/premium.html deleted file mode 100644 index e28735d6b8..0000000000 --- a/examples/python/legacy/fullstack/flask/static/premium.html +++ /dev/null @@ -1,46 +0,0 @@ - - - - - - Protected Content - - - - -
-
-

Premium Content

-

- Your payment was successful! Enjoy this banger song. -

- - -
-
- - diff --git a/examples/python/legacy/fullstack/flask/static/x402.png b/examples/python/legacy/fullstack/flask/static/x402.png deleted file mode 100644 index 88254d78cd..0000000000 Binary files a/examples/python/legacy/fullstack/flask/static/x402.png and /dev/null differ diff --git a/examples/python/legacy/fullstack/flask/uv.lock b/examples/python/legacy/fullstack/flask/uv.lock deleted file mode 100644 index bd090bcc44..0000000000 --- a/examples/python/legacy/fullstack/flask/uv.lock +++ /dev/null @@ -1,2242 +0,0 @@ -version = 1 -revision = 2 -requires-python = ">=3.10" - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, -] - -[[package]] -name = "aiohttp" -version = "3.11.16" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f1/d9/1c4721d143e14af753f2bf5e3b681883e1f24b592c0482df6fa6e33597fa/aiohttp-3.11.16.tar.gz", hash = "sha256:16f8a2c9538c14a557b4d309ed4d0a7c60f0253e8ed7b6c9a2859a7582f8b1b8", size = 7676826, upload-time = "2025-04-02T02:17:44.74Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/21/6bd4cb580a323b64cda3b11fcb3f68deba77568e97806727a858de57349d/aiohttp-3.11.16-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:fb46bb0f24813e6cede6cc07b1961d4b04f331f7112a23b5e21f567da4ee50aa", size = 708259, upload-time = "2025-04-02T02:15:15.439Z" }, - { url = "https://files.pythonhosted.org/packages/96/8c/7b4b9debe90ffc31931b85ee8612a5c83f34d8fdc6d90ee3eb27b43639e4/aiohttp-3.11.16-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:54eb3aead72a5c19fad07219acd882c1643a1027fbcdefac9b502c267242f955", size = 468886, upload-time = "2025-04-02T02:15:17.025Z" }, - { url = "https://files.pythonhosted.org/packages/13/da/a7fcd68e62acacf0a1930060afd2c970826f989265893082b6fb9eb25cb5/aiohttp-3.11.16-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:38bea84ee4fe24ebcc8edeb7b54bf20f06fd53ce4d2cc8b74344c5b9620597fd", size = 455846, upload-time = "2025-04-02T02:15:18.662Z" }, - { url = "https://files.pythonhosted.org/packages/5d/12/b73d9423253f4c872d276a3771decb0722cb5f962352593bd617445977ba/aiohttp-3.11.16-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d0666afbe984f6933fe72cd1f1c3560d8c55880a0bdd728ad774006eb4241ecd", size = 1587183, upload-time = "2025-04-02T02:15:20.048Z" }, - { url = "https://files.pythonhosted.org/packages/75/d3/291b57d54719d996e6cb8c1db8b13d01bdb24dca90434815ac7e6a70393f/aiohttp-3.11.16-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7ba92a2d9ace559a0a14b03d87f47e021e4fa7681dc6970ebbc7b447c7d4b7cd", size = 1634937, upload-time = "2025-04-02T02:15:22.156Z" }, - { url = "https://files.pythonhosted.org/packages/be/85/4229eba92b433173065b0b459ab677ca11ead4a179f76ccfe55d8738b188/aiohttp-3.11.16-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3ad1d59fd7114e6a08c4814983bb498f391c699f3c78712770077518cae63ff7", size = 1667980, upload-time = "2025-04-02T02:15:23.843Z" }, - { url = "https://files.pythonhosted.org/packages/2b/0d/d2423936962e3c711fafd5bb9172a99e6b07dd63e086515aa957d8a991fd/aiohttp-3.11.16-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98b88a2bf26965f2015a771381624dd4b0839034b70d406dc74fd8be4cc053e3", size = 1590365, upload-time = "2025-04-02T02:15:25.809Z" }, - { url = "https://files.pythonhosted.org/packages/ea/93/04209affc20834982c1ef4214b1afc07743667998a9975d69413e9c1e1c1/aiohttp-3.11.16-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:576f5ca28d1b3276026f7df3ec841ae460e0fc3aac2a47cbf72eabcfc0f102e1", size = 1547614, upload-time = "2025-04-02T02:15:27.544Z" }, - { url = "https://files.pythonhosted.org/packages/f6/fb/194ad4e4cae98023ae19556e576347f402ce159e80d74cc0713d460c4a39/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:a2a450bcce4931b295fc0848f384834c3f9b00edfc2150baafb4488c27953de6", size = 1532815, upload-time = "2025-04-02T02:15:28.985Z" }, - { url = "https://files.pythonhosted.org/packages/33/6d/a4da7adbac90188bf1228c73b6768a607dd279c146721a9ff7dcb75c5ac6/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:37dcee4906454ae377be5937ab2a66a9a88377b11dd7c072df7a7c142b63c37c", size = 1559005, upload-time = "2025-04-02T02:15:30.406Z" }, - { url = "https://files.pythonhosted.org/packages/7e/88/2fa9fbfd23fc16cb2cfdd1f290343e085e7e327438041e9c6aa0208a854d/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:4d0c970c0d602b1017e2067ff3b7dac41c98fef4f7472ec2ea26fd8a4e8c2149", size = 1535231, upload-time = "2025-04-02T02:15:32.468Z" }, - { url = "https://files.pythonhosted.org/packages/f5/8f/9623cd2558e3e182d02dcda8b480643e1c48a0550a86e3050210e98dba27/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:004511d3413737700835e949433536a2fe95a7d0297edd911a1e9705c5b5ea43", size = 1609985, upload-time = "2025-04-02T02:15:33.899Z" }, - { url = "https://files.pythonhosted.org/packages/f8/a2/53a8d1bfc67130710f1c8091f623cdefe7f85cd5d09e14637ed2ed6e1a6d/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:c15b2271c44da77ee9d822552201180779e5e942f3a71fb74e026bf6172ff287", size = 1628842, upload-time = "2025-04-02T02:15:35.396Z" }, - { url = "https://files.pythonhosted.org/packages/49/3a/35fb43d07489573c6c1f8c6a3e6c657196124a63223705b7feeddaea06f1/aiohttp-3.11.16-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ad9509ffb2396483ceacb1eee9134724443ee45b92141105a4645857244aecc8", size = 1566929, upload-time = "2025-04-02T02:15:36.863Z" }, - { url = "https://files.pythonhosted.org/packages/d5/82/bb3f4f2cc7677e790ba4c040db7dd8445c234a810ef893a858e217647d38/aiohttp-3.11.16-cp310-cp310-win32.whl", hash = "sha256:634d96869be6c4dc232fc503e03e40c42d32cfaa51712aee181e922e61d74814", size = 416935, upload-time = "2025-04-02T02:15:38.337Z" }, - { url = "https://files.pythonhosted.org/packages/df/ad/a64db1c18063569d6dff474c46a7d4de7ab85ff55e2a35839b149b1850ea/aiohttp-3.11.16-cp310-cp310-win_amd64.whl", hash = "sha256:938f756c2b9374bbcc262a37eea521d8a0e6458162f2a9c26329cc87fdf06534", size = 442168, upload-time = "2025-04-02T02:15:39.757Z" }, - { url = "https://files.pythonhosted.org/packages/b1/98/be30539cd84260d9f3ea1936d50445e25aa6029a4cb9707f3b64cfd710f7/aiohttp-3.11.16-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:8cb0688a8d81c63d716e867d59a9ccc389e97ac7037ebef904c2b89334407180", size = 708664, upload-time = "2025-04-02T02:15:41.433Z" }, - { url = "https://files.pythonhosted.org/packages/e6/27/d51116ce18bdfdea7a2244b55ad38d7b01a4298af55765eed7e8431f013d/aiohttp-3.11.16-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0ad1fb47da60ae1ddfb316f0ff16d1f3b8e844d1a1e154641928ea0583d486ed", size = 468953, upload-time = "2025-04-02T02:15:43.118Z" }, - { url = "https://files.pythonhosted.org/packages/34/23/eedf80ec42865ea5355b46265a2433134138eff9a4fea17e1348530fa4ae/aiohttp-3.11.16-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:df7db76400bf46ec6a0a73192b14c8295bdb9812053f4fe53f4e789f3ea66bbb", size = 456065, upload-time = "2025-04-02T02:15:44.994Z" }, - { url = "https://files.pythonhosted.org/packages/36/23/4a5b1ef6cff994936bf96d981dd817b487d9db755457a0d1c2939920d620/aiohttp-3.11.16-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc3a145479a76ad0ed646434d09216d33d08eef0d8c9a11f5ae5cdc37caa3540", size = 1687976, upload-time = "2025-04-02T02:15:46.632Z" }, - { url = "https://files.pythonhosted.org/packages/d0/5d/c7474b4c3069bb35276d54c82997dff4f7575e4b73f0a7b1b08a39ece1eb/aiohttp-3.11.16-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d007aa39a52d62373bd23428ba4a2546eed0e7643d7bf2e41ddcefd54519842c", size = 1752711, upload-time = "2025-04-02T02:15:48.276Z" }, - { url = "https://files.pythonhosted.org/packages/64/4c/ee416987b6729558f2eb1b727c60196580aafdb141e83bd78bb031d1c000/aiohttp-3.11.16-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6ddd90d9fb4b501c97a4458f1c1720e42432c26cb76d28177c5b5ad4e332601", size = 1791305, upload-time = "2025-04-02T02:15:49.965Z" }, - { url = "https://files.pythonhosted.org/packages/58/28/3e1e1884070b95f1f69c473a1995852a6f8516670bb1c29d6cb2dbb73e1c/aiohttp-3.11.16-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a2f451849e6b39e5c226803dcacfa9c7133e9825dcefd2f4e837a2ec5a3bb98", size = 1674499, upload-time = "2025-04-02T02:15:51.718Z" }, - { url = "https://files.pythonhosted.org/packages/ad/55/a032b32fa80a662d25d9eb170ed1e2c2be239304ca114ec66c89dc40f37f/aiohttp-3.11.16-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8df6612df74409080575dca38a5237282865408016e65636a76a2eb9348c2567", size = 1622313, upload-time = "2025-04-02T02:15:53.377Z" }, - { url = "https://files.pythonhosted.org/packages/b1/df/ca775605f72abbda4e4746e793c408c84373ca2c6ce7a106a09f853f1e89/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:78e6e23b954644737e385befa0deb20233e2dfddf95dd11e9db752bdd2a294d3", size = 1658274, upload-time = "2025-04-02T02:15:55.035Z" }, - { url = "https://files.pythonhosted.org/packages/cc/6c/21c45b66124df5b4b0ab638271ecd8c6402b702977120cb4d5be6408e15d/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:696ef00e8a1f0cec5e30640e64eca75d8e777933d1438f4facc9c0cdf288a810", size = 1666704, upload-time = "2025-04-02T02:15:56.581Z" }, - { url = "https://files.pythonhosted.org/packages/1d/e2/7d92adc03e3458edd18a21da2575ab84e58f16b1672ae98529e4eeee45ab/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:e3538bc9fe1b902bef51372462e3d7c96fce2b566642512138a480b7adc9d508", size = 1652815, upload-time = "2025-04-02T02:15:58.126Z" }, - { url = "https://files.pythonhosted.org/packages/3a/52/7549573cd654ad651e3c5786ec3946d8f0ee379023e22deb503ff856b16c/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3ab3367bb7f61ad18793fea2ef71f2d181c528c87948638366bf1de26e239183", size = 1735669, upload-time = "2025-04-02T02:16:00.313Z" }, - { url = "https://files.pythonhosted.org/packages/d5/54/dcd24a23c7a5a2922123e07a296a5f79ea87ce605f531be068415c326de6/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:56a3443aca82abda0e07be2e1ecb76a050714faf2be84256dae291182ba59049", size = 1760422, upload-time = "2025-04-02T02:16:02.233Z" }, - { url = "https://files.pythonhosted.org/packages/a7/53/87327fe982fa310944e1450e97bf7b2a28015263771931372a1dfe682c58/aiohttp-3.11.16-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:61c721764e41af907c9d16b6daa05a458f066015abd35923051be8705108ed17", size = 1694457, upload-time = "2025-04-02T02:16:04.233Z" }, - { url = "https://files.pythonhosted.org/packages/ce/6d/c5ccf41059267bcf89853d3db9d8d217dacf0a04f4086cb6bf278323011f/aiohttp-3.11.16-cp311-cp311-win32.whl", hash = "sha256:3e061b09f6fa42997cf627307f220315e313ece74907d35776ec4373ed718b86", size = 416817, upload-time = "2025-04-02T02:16:06.268Z" }, - { url = "https://files.pythonhosted.org/packages/e7/dd/01f6fe028e054ef4f909c9d63e3a2399e77021bb2e1bb51d56ca8b543989/aiohttp-3.11.16-cp311-cp311-win_amd64.whl", hash = "sha256:745f1ed5e2c687baefc3c5e7b4304e91bf3e2f32834d07baaee243e349624b24", size = 442986, upload-time = "2025-04-02T02:16:07.712Z" }, - { url = "https://files.pythonhosted.org/packages/db/38/100d01cbc60553743baf0fba658cb125f8ad674a8a771f765cdc155a890d/aiohttp-3.11.16-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:911a6e91d08bb2c72938bc17f0a2d97864c531536b7832abee6429d5296e5b27", size = 704881, upload-time = "2025-04-02T02:16:09.26Z" }, - { url = "https://files.pythonhosted.org/packages/21/ed/b4102bb6245e36591209e29f03fe87e7956e54cb604ee12e20f7eb47f994/aiohttp-3.11.16-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac13b71761e49d5f9e4d05d33683bbafef753e876e8e5a7ef26e937dd766713", size = 464564, upload-time = "2025-04-02T02:16:10.781Z" }, - { url = "https://files.pythonhosted.org/packages/3b/e1/a9ab6c47b62ecee080eeb33acd5352b40ecad08fb2d0779bcc6739271745/aiohttp-3.11.16-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:fd36c119c5d6551bce374fcb5c19269638f8d09862445f85a5a48596fd59f4bb", size = 456548, upload-time = "2025-04-02T02:16:12.764Z" }, - { url = "https://files.pythonhosted.org/packages/80/ad/216c6f71bdff2becce6c8776f0aa32cb0fa5d83008d13b49c3208d2e4016/aiohttp-3.11.16-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d489d9778522fbd0f8d6a5c6e48e3514f11be81cb0a5954bdda06f7e1594b321", size = 1691749, upload-time = "2025-04-02T02:16:14.304Z" }, - { url = "https://files.pythonhosted.org/packages/bd/ea/7df7bcd3f4e734301605f686ffc87993f2d51b7acb6bcc9b980af223f297/aiohttp-3.11.16-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:69a2cbd61788d26f8f1e626e188044834f37f6ae3f937bd9f08b65fc9d7e514e", size = 1736874, upload-time = "2025-04-02T02:16:16.538Z" }, - { url = "https://files.pythonhosted.org/packages/51/41/c7724b9c87a29b7cfd1202ec6446bae8524a751473d25e2ff438bc9a02bf/aiohttp-3.11.16-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:cd464ba806e27ee24a91362ba3621bfc39dbbb8b79f2e1340201615197370f7c", size = 1786885, upload-time = "2025-04-02T02:16:18.268Z" }, - { url = "https://files.pythonhosted.org/packages/86/b3/f61f8492fa6569fa87927ad35a40c159408862f7e8e70deaaead349e2fba/aiohttp-3.11.16-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ce63ae04719513dd2651202352a2beb9f67f55cb8490c40f056cea3c5c355ce", size = 1698059, upload-time = "2025-04-02T02:16:20.234Z" }, - { url = "https://files.pythonhosted.org/packages/ce/be/7097cf860a9ce8bbb0e8960704e12869e111abcd3fbd245153373079ccec/aiohttp-3.11.16-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:09b00dd520d88eac9d1768439a59ab3d145065c91a8fab97f900d1b5f802895e", size = 1626527, upload-time = "2025-04-02T02:16:22.092Z" }, - { url = "https://files.pythonhosted.org/packages/1d/1d/aaa841c340e8c143a8d53a1f644c2a2961c58cfa26e7b398d6bf75cf5d23/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7f6428fee52d2bcf96a8aa7b62095b190ee341ab0e6b1bcf50c615d7966fd45b", size = 1644036, upload-time = "2025-04-02T02:16:23.707Z" }, - { url = "https://files.pythonhosted.org/packages/2c/88/59d870f76e9345e2b149f158074e78db457985c2b4da713038d9da3020a8/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:13ceac2c5cdcc3f64b9015710221ddf81c900c5febc505dbd8f810e770011540", size = 1685270, upload-time = "2025-04-02T02:16:25.874Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b1/c6686948d4c79c3745595efc469a9f8a43cab3c7efc0b5991be65d9e8cb8/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:fadbb8f1d4140825069db3fedbbb843290fd5f5bc0a5dbd7eaf81d91bf1b003b", size = 1650852, upload-time = "2025-04-02T02:16:27.556Z" }, - { url = "https://files.pythonhosted.org/packages/fe/94/3e42a6916fd3441721941e0f1b8438e1ce2a4c49af0e28e0d3c950c9b3c9/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:6a792ce34b999fbe04a7a71a90c74f10c57ae4c51f65461a411faa70e154154e", size = 1704481, upload-time = "2025-04-02T02:16:29.573Z" }, - { url = "https://files.pythonhosted.org/packages/b1/6d/6ab5854ff59b27075c7a8c610597d2b6c38945f9a1284ee8758bc3720ff6/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:f4065145bf69de124accdd17ea5f4dc770da0a6a6e440c53f6e0a8c27b3e635c", size = 1735370, upload-time = "2025-04-02T02:16:31.191Z" }, - { url = "https://files.pythonhosted.org/packages/73/2a/08a68eec3c99a6659067d271d7553e4d490a0828d588e1daa3970dc2b771/aiohttp-3.11.16-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:fa73e8c2656a3653ae6c307b3f4e878a21f87859a9afab228280ddccd7369d71", size = 1697619, upload-time = "2025-04-02T02:16:32.873Z" }, - { url = "https://files.pythonhosted.org/packages/61/d5/fea8dbbfb0cd68fbb56f0ae913270a79422d9a41da442a624febf72d2aaf/aiohttp-3.11.16-cp312-cp312-win32.whl", hash = "sha256:f244b8e541f414664889e2c87cac11a07b918cb4b540c36f7ada7bfa76571ea2", size = 411710, upload-time = "2025-04-02T02:16:34.525Z" }, - { url = "https://files.pythonhosted.org/packages/33/fb/41cde15fbe51365024550bf77b95a4fc84ef41365705c946da0421f0e1e0/aiohttp-3.11.16-cp312-cp312-win_amd64.whl", hash = "sha256:23a15727fbfccab973343b6d1b7181bfb0b4aa7ae280f36fd2f90f5476805682", size = 438012, upload-time = "2025-04-02T02:16:36.103Z" }, - { url = "https://files.pythonhosted.org/packages/52/52/7c712b2d9fb4d5e5fd6d12f9ab76e52baddfee71e3c8203ca7a7559d7f51/aiohttp-3.11.16-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a3814760a1a700f3cfd2f977249f1032301d0a12c92aba74605cfa6ce9f78489", size = 698005, upload-time = "2025-04-02T02:16:37.923Z" }, - { url = "https://files.pythonhosted.org/packages/51/3e/61057814f7247666d43ac538abcd6335b022869ade2602dab9bf33f607d2/aiohttp-3.11.16-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9b751a6306f330801665ae69270a8a3993654a85569b3469662efaad6cf5cc50", size = 461106, upload-time = "2025-04-02T02:16:39.961Z" }, - { url = "https://files.pythonhosted.org/packages/4f/85/6b79fb0ea6e913d596d5b949edc2402b20803f51b1a59e1bbc5bb7ba7569/aiohttp-3.11.16-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:ad497f38a0d6c329cb621774788583ee12321863cd4bd9feee1effd60f2ad133", size = 453394, upload-time = "2025-04-02T02:16:41.562Z" }, - { url = "https://files.pythonhosted.org/packages/4b/04/e1bb3fcfbd2c26753932c759593a32299aff8625eaa0bf8ff7d9c0c34a36/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ca37057625693d097543bd88076ceebeb248291df9d6ca8481349efc0b05dcd0", size = 1666643, upload-time = "2025-04-02T02:16:43.62Z" }, - { url = "https://files.pythonhosted.org/packages/0e/27/97bc0fdd1f439b8f060beb3ba8fb47b908dc170280090801158381ad7942/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a5abcbba9f4b463a45c8ca8b7720891200658f6f46894f79517e6cd11f3405ca", size = 1721948, upload-time = "2025-04-02T02:16:45.617Z" }, - { url = "https://files.pythonhosted.org/packages/2c/4f/bc4c5119e75c05ef15c5670ef1563bbe25d4ed4893b76c57b0184d815e8b/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f420bfe862fb357a6d76f2065447ef6f484bc489292ac91e29bc65d2d7a2c84d", size = 1774454, upload-time = "2025-04-02T02:16:48.562Z" }, - { url = "https://files.pythonhosted.org/packages/73/5b/54b42b2150bb26fdf795464aa55ceb1a49c85f84e98e6896d211eabc6670/aiohttp-3.11.16-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:58ede86453a6cf2d6ce40ef0ca15481677a66950e73b0a788917916f7e35a0bb", size = 1677785, upload-time = "2025-04-02T02:16:50.367Z" }, - { url = "https://files.pythonhosted.org/packages/10/ee/a0fe68916d3f82eae199b8535624cf07a9c0a0958c7a76e56dd21140487a/aiohttp-3.11.16-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6fdec0213244c39973674ca2a7f5435bf74369e7d4e104d6c7473c81c9bcc8c4", size = 1608456, upload-time = "2025-04-02T02:16:52.158Z" }, - { url = "https://files.pythonhosted.org/packages/8b/48/83afd779242b7cf7e1ceed2ff624a86d3221e17798061cf9a79e0b246077/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:72b1b03fb4655c1960403c131740755ec19c5898c82abd3961c364c2afd59fe7", size = 1622424, upload-time = "2025-04-02T02:16:54.386Z" }, - { url = "https://files.pythonhosted.org/packages/6f/27/452f1d5fca1f516f9f731539b7f5faa9e9d3bf8a3a6c3cd7c4b031f20cbd/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:780df0d837276276226a1ff803f8d0fa5f8996c479aeef52eb040179f3156cbd", size = 1660943, upload-time = "2025-04-02T02:16:56.887Z" }, - { url = "https://files.pythonhosted.org/packages/d6/e1/5c7d63143b8d00c83b958b9e78e7048c4a69903c760c1e329bf02bac57a1/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ecdb8173e6c7aa09eee342ac62e193e6904923bd232e76b4157ac0bfa670609f", size = 1622797, upload-time = "2025-04-02T02:16:58.676Z" }, - { url = "https://files.pythonhosted.org/packages/46/9e/2ac29cca2746ee8e449e73cd2fcb3d454467393ec03a269d50e49af743f1/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a6db7458ab89c7d80bc1f4e930cc9df6edee2200127cfa6f6e080cf619eddfbd", size = 1687162, upload-time = "2025-04-02T02:17:01.076Z" }, - { url = "https://files.pythonhosted.org/packages/ad/6b/eaa6768e02edebaf37d77f4ffb74dd55f5cbcbb6a0dbf798ccec7b0ac23b/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:2540ddc83cc724b13d1838026f6a5ad178510953302a49e6d647f6e1de82bc34", size = 1718518, upload-time = "2025-04-02T02:17:03.388Z" }, - { url = "https://files.pythonhosted.org/packages/e5/18/dda87cbad29472a51fa058d6d8257dfce168289adaeb358b86bd93af3b20/aiohttp-3.11.16-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3b4e6db8dc4879015b9955778cfb9881897339c8fab7b3676f8433f849425913", size = 1675254, upload-time = "2025-04-02T02:17:05.579Z" }, - { url = "https://files.pythonhosted.org/packages/32/d9/d2fb08c614df401d92c12fcbc60e6e879608d5e8909ef75c5ad8d4ad8aa7/aiohttp-3.11.16-cp313-cp313-win32.whl", hash = "sha256:493910ceb2764f792db4dc6e8e4b375dae1b08f72e18e8f10f18b34ca17d0979", size = 410698, upload-time = "2025-04-02T02:17:07.499Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ed/853e36d5a33c24544cfa46585895547de152dfef0b5c79fa675f6e4b7b87/aiohttp-3.11.16-cp313-cp313-win_amd64.whl", hash = "sha256:42864e70a248f5f6a49fdaf417d9bc62d6e4d8ee9695b24c5916cb4bb666c802", size = 436395, upload-time = "2025-04-02T02:17:09.566Z" }, -] - -[[package]] -name = "aiohttp-retry" -version = "2.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9d/61/ebda4d8e3d8cfa1fd3db0fb428db2dd7461d5742cea35178277ad180b033/aiohttp_retry-2.9.1.tar.gz", hash = "sha256:8eb75e904ed4ee5c2ec242fefe85bf04240f685391c4879d8f541d6028ff01f1", size = 13608, upload-time = "2024-11-06T10:44:54.574Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1a/99/84ba7273339d0f3dfa57901b846489d2e5c2cd731470167757f1935fffbd/aiohttp_retry-2.9.1-py3-none-any.whl", hash = "sha256:66d2759d1921838256a05a3f80ad7e724936f083e35be5abb5e16eed6be6dc54", size = 9981, upload-time = "2024-11-06T10:44:52.917Z" }, -] - -[[package]] -name = "aiosignal" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, -] - -[[package]] -name = "async-timeout" -version = "5.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, -] - -[[package]] -name = "attrs" -version = "25.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, -] - -[[package]] -name = "base58" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/45/8ae61209bb9015f516102fa559a2914178da1d5868428bd86a1b4421141d/base58-2.1.1.tar.gz", hash = "sha256:c5d0cb3f5b6e81e8e35da5754388ddcc6d0d14b6c6a132cb93d69ed580a7278c", size = 6528, upload-time = "2021-10-30T22:12:17.858Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/45/ec96b29162a402fc4c1c5512d114d7b3787b9d1c2ec241d9568b4816ee23/base58-2.1.1-py3-none-any.whl", hash = "sha256:11a36f4d3ce51dfc1043f3218591ac4eb1ceb172919cebe05b52a5bcc8d245c2", size = 5621, upload-time = "2021-10-30T22:12:16.658Z" }, -] - -[[package]] -name = "bitarray" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/0d/15826c7c2d49a4518a1b24b0d432f1ecad2e0b68168f942058b5de498498/bitarray-3.4.2.tar.gz", hash = "sha256:78ed2b911aabede3a31e3329b1de8abdc8104bd5e0545184ddbd9c7f668f4059", size = 143756, upload-time = "2025-05-21T16:21:44.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/61/fa3a06d74bfba1dc591efa9f4f5ad2e5645f06a8c4d113cf12d18b5ac25b/bitarray-3.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:42b552f885c5629182928c79237b375a92bcf1bc1e725b1c8a5e8eab28ea300d", size = 141280, upload-time = "2025-05-21T16:18:02.593Z" }, - { url = "https://files.pythonhosted.org/packages/17/ba/7eb30374c0e4c4b732a3ca3457d9fb0e44165ae4c5af9758597b03211a28/bitarray-3.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3e16d6184f349587b6a5045bcf073baf763a86273aab454485ba437d0bca82e8", size = 138031, upload-time = "2025-05-21T16:18:05.616Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6d/91582b0a232b54e910add5d0db34a926d0bdfdd1447685b8750349c71958/bitarray-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ecf456f0dee61bd818011e290d922e3e3b1aeb0544f6f19c4da9c5fc2e52818", size = 306437, upload-time = "2025-05-21T16:18:06.793Z" }, - { url = "https://files.pythonhosted.org/packages/b8/23/113ccc20f6324d517ef6210c8fc6ae300346eb481c5a0483735e19b4deea/bitarray-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8bbe8249ae90dc0cd78b21d5d5d27a614e15bf30737ae6e8a0e2e60cc492acc", size = 322335, upload-time = "2025-05-21T16:18:07.925Z" }, - { url = "https://files.pythonhosted.org/packages/6d/89/bf5a36e05ac3d77bdccbe9ba0eea4c47253411c2616379de0f181c27ecee/bitarray-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe7706f75f3b86e7afa516452bed9757ee301b59aea580c551c32a5e1cef082c", size = 314137, upload-time = "2025-05-21T16:18:09.333Z" }, - { url = "https://files.pythonhosted.org/packages/66/a6/bed287f9095a2a266fc68ee42d6ee2815ff500783f973876d86a6d37a434/bitarray-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c60c8d30bb6efd2c04cf82d077df6449964234aeca996f6f1df317a08feffc0", size = 307963, upload-time = "2025-05-21T16:18:10.618Z" }, - { url = "https://files.pythonhosted.org/packages/2f/50/3ca2adaf0da034e6c1a2ed60a3781b065672dd282e67f88593290c3990a7/bitarray-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b4cb5c22706d411010c7ce5efc0a4cc99f755a30fc7f6770eb1b1a0c0962bbb", size = 295182, upload-time = "2025-05-21T16:18:11.932Z" }, - { url = "https://files.pythonhosted.org/packages/90/de/8c3d96e273bc51e4912185bd809fc6a9ec14a09e607336892c149e0c57c5/bitarray-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0fd60137a9474ce53bdace68c718a7c538f9df01d390452cc984f1ee78d7bcdb", size = 300063, upload-time = "2025-05-21T16:18:13.221Z" }, - { url = "https://files.pythonhosted.org/packages/9d/71/34f0ea6ac5b2cbdd84f3e6283b5b796628cef616e786cb442cefce0fe224/bitarray-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cd514a8e27d0751f0254861df60335edabacccfcb2457793ff30c8b2ed8f799d", size = 292053, upload-time = "2025-05-21T16:18:14.802Z" }, - { url = "https://files.pythonhosted.org/packages/77/99/6ef41312536d2c37f14f0f7173aa1a012e9675d62900c10afa7641b47f75/bitarray-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6c8f7447cdf2faff1d176c5dd207f0134f05cfa2a238d3d3944dc5019dc41593", size = 317007, upload-time = "2025-05-21T16:18:16.117Z" }, - { url = "https://files.pythonhosted.org/packages/22/f9/cc4e73f54698bcdd1e0f1ea582da7e005464651e8116291a226deab95e1b/bitarray-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:75040a2a1abe4ccd40236f4ba0d39abde981d23f3ce7691b3b3f2137f134b99b", size = 319402, upload-time = "2025-05-21T16:18:18.097Z" }, - { url = "https://files.pythonhosted.org/packages/55/40/c23dd5726107cbbc5e698b3fcca5ffac83d29146ef469f27f5277d18c2d7/bitarray-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ba15725cd9040b9b1b2650edb33253cb2ba7b68d087974e296e5ff082198952f", size = 299456, upload-time = "2025-05-21T16:18:20.029Z" }, - { url = "https://files.pythonhosted.org/packages/21/31/6bfd9fda776f8d98512d5484fcb55fbb25e60796e7b5d3b9a3a300e8bc1c/bitarray-3.4.2-cp310-cp310-win32.whl", hash = "sha256:2959dfc61d963546e97220cfcaab7dfc489276c6e00092b57710522e68712b28", size = 134279, upload-time = "2025-05-21T16:18:21.609Z" }, - { url = "https://files.pythonhosted.org/packages/82/9d/7067f6548b470beb86d83f7ac6c45cac3b9c28cf77fa0f9f3e67353d69d3/bitarray-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:97077fa0ec3b7eed57cd8d1cb0eb75d670423d20b7e4901482347a81efe2f6fd", size = 141360, upload-time = "2025-05-21T16:18:23.197Z" }, - { url = "https://files.pythonhosted.org/packages/94/ba/508ba6a3ea16eb6c21baae33cd1b7bf6e299d21a496a1f90b8203a22d6d0/bitarray-3.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90ca8e260b75a7ac0c542093e5f29154e51fd0d2d0fa5041c038cb2b58415eeb", size = 141425, upload-time = "2025-05-21T16:18:24.452Z" }, - { url = "https://files.pythonhosted.org/packages/eb/a1/44d9b88cd3daee3734ea98dac691acc2c935a3bfbd5bfc38267a59bd986d/bitarray-3.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549dabcae78fb8f9133e3138b9473c7648d6054bb6fec84d28d3861aaec5ddd1", size = 138172, upload-time = "2025-05-21T16:18:25.601Z" }, - { url = "https://files.pythonhosted.org/packages/5f/aa/5a8c33ab39e8a894978d42427ad0a1ba2d5c9cb61c8480101be555c0e3a7/bitarray-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3da536ac84e6911cbc8e86be0baf1cab0d4f4ccb80c0f39b4fa28509f2db1a", size = 313373, upload-time = "2025-05-21T16:18:26.796Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/b0d28e21d91ec5c0477a320b9443096ddc816fbc59778b367f9e49094532/bitarray-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a5e84d6b737de2d773ab1bd538e6f37fa7f667ea734f00a48d9a973b181c751", size = 329657, upload-time = "2025-05-21T16:18:28.097Z" }, - { url = "https://files.pythonhosted.org/packages/bd/d5/1f858bd559568286435a460e7a169a5185b2b29184684e6c6fa303af3ca9/bitarray-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e265c5eede8316ba64bb6029832f282f6284a557b625bb3207a7680fd5da7925", size = 321873, upload-time = "2025-05-21T16:18:29.511Z" }, - { url = "https://files.pythonhosted.org/packages/e8/c8/23df4174142cccf6a8bd114651b8e9bf965005ab1ef741d37c9f72e8d2eb/bitarray-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63fb45c60c7ab7a724aa64203305e56f344489e12d41619bdc9d7887d6562e01", size = 314796, upload-time = "2025-05-21T16:18:31.2Z" }, - { url = "https://files.pythonhosted.org/packages/8f/21/329178b165f1aaf3f2ace3eb24aca5ad197febae908d7b41e552a69043e9/bitarray-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:083c2a9234dacf3e4e166a5844256da2a397941d3f6397e5b919bffca638f6ef", size = 302724, upload-time = "2025-05-21T16:18:32.729Z" }, - { url = "https://files.pythonhosted.org/packages/26/a8/a66d3c0d3410d01f51824f8476b060f96b3353db7d6b45c87dba6d1aa0e0/bitarray-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e72606adb2438002873cb0e8e81c3fce926386a59bbafa82fea07cdb2a6d8a05", size = 307434, upload-time = "2025-05-21T16:18:34.394Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ac/3052386e7ff80c80eb2549a22c890f511e9f9f7fbbe6244b04255adae031/bitarray-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dc994d22a3a563e1d402dc2f64c61e60605a1a3e66dd8aea7636f607b99f03cb", size = 299232, upload-time = "2025-05-21T16:18:35.708Z" }, - { url = "https://files.pythonhosted.org/packages/9d/46/91a32ccd39d40371ed7404d96a6f3cf1e381eaf36be5390c6bff5034f344/bitarray-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:214468391680ba1c831872a7949f1b563ab3cd832d10adc52df4f36e0af24446", size = 324056, upload-time = "2025-05-21T16:18:37.536Z" }, - { url = "https://files.pythonhosted.org/packages/39/0e/cb824f0e0302cd08809f67b35b3ae21b47af5dd122e99740bfe6bde1c824/bitarray-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c7483b97807bb018a7cd7f9741800c714c9c56ba4e5a7e962c5f956c4b858f3c", size = 327058, upload-time = "2025-05-21T16:18:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/09/01/845e977d490e4e261179785540d1fdeff966c99296f503adc0e5407fc257/bitarray-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5774bf14ec451d5ac311cfcfe0b0cf2a1a9fa74b6ca81dfbc4f56a98872a5541", size = 306629, upload-time = "2025-05-21T16:18:40.211Z" }, - { url = "https://files.pythonhosted.org/packages/29/ef/33ee8533ff1b2a8cd0b9e84fd81b2a90d66c2774544c861e281c5361eaa2/bitarray-3.4.2-cp311-cp311-win32.whl", hash = "sha256:e6f35567347ddb8b9e8b6bf6ab7d64be88bdb6b6c107b8edbb2c3d426c1590a0", size = 134450, upload-time = "2025-05-21T16:18:42.435Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/069c255d067319a9695c93369641d7f5539625069c1cf3ded2becff1bfbc/bitarray-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae5b0a8d3caf6284220232738dc7c05af81ec3a9f93d4a462295462dd0a492b2", size = 141596, upload-time = "2025-05-21T16:18:43.743Z" }, - { url = "https://files.pythonhosted.org/packages/05/57/0b2b50eb3f50c3144f705d0994171f17fda00ee3a72d563ba764ea235f66/bitarray-3.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a0e498563e0eefa96a1b92461d083de11256f6510b7706d5f2e6473cd9b7137a", size = 141191, upload-time = "2025-05-21T16:18:45.436Z" }, - { url = "https://files.pythonhosted.org/packages/81/c3/1d9ce4d0041c10ce90d924b8cea63afdda84a64623179045c0c67998922c/bitarray-3.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:114870ab71a0ebdac211aa0a120a54206c333b74b99fdf4b58fbe904979e1fef", size = 138158, upload-time = "2025-05-21T16:18:46.685Z" }, - { url = "https://files.pythonhosted.org/packages/5d/dd/a8653dac671ba97b1c68ee73b08a0eb2042f24e5e31f51b86afc09588c06/bitarray-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fbf6121978cba4313c31f7cc5961e481242def2b8ddfea34ca27ba9da52c9c1", size = 315834, upload-time = "2025-05-21T16:18:47.926Z" }, - { url = "https://files.pythonhosted.org/packages/3d/a2/30547bea0a35f9f953e99f5157749d56304d3f3a96b01a982dd604a9dc48/bitarray-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:423bb4e1bec0bc5d63969e12bcc5cc0081cc5aec4d7b62a6cd8240342aa36107", size = 331317, upload-time = "2025-05-21T16:18:49.169Z" }, - { url = "https://files.pythonhosted.org/packages/2d/b9/1789476280f46455a9a30bcd252fda6fd995583d97d1b919ec0296393e2a/bitarray-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ef80a96487c82477e8def69a58a218491794f7989b3e191cbaaa7b450315a5c", size = 324416, upload-time = "2025-05-21T16:18:50.917Z" }, - { url = "https://files.pythonhosted.org/packages/84/89/519c829ca641a3e7b8c9be56d177aaa05572b7e15e4298df4a77959b6a1e/bitarray-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35f5c69a79047e50bc1d54a777541b0a86b213e23559b1ac3d76fa9a42cc5522", size = 317634, upload-time = "2025-05-21T16:18:52.718Z" }, - { url = "https://files.pythonhosted.org/packages/0d/39/ebb6a6539261279c0994836b40b99384fa5e27ec239e70b203e310343f80/bitarray-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:002f7b128ed9d18d3ecb51ca78aeea5afffbe8e80d6be4ff2984d045b1c4b937", size = 305392, upload-time = "2025-05-21T16:18:54.888Z" }, - { url = "https://files.pythonhosted.org/packages/83/04/0ee0d57b2a60fdf881346f196fd92b824f44f4736026da1d8c7970745266/bitarray-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:999bccc72704afcf4a3d9868db4d149c032cdf910f9f7d91e30166978530af7f", size = 309740, upload-time = "2025-05-21T16:18:56.76Z" }, - { url = "https://files.pythonhosted.org/packages/f6/39/5ab0339e93097f2a2631ea281a6386c31707011499d5cf68b4e0e37ba124/bitarray-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2e44cfe2bc161cde3b11604f279e3048ef7bd3413837aadbd2ca30b5233c82cb", size = 301607, upload-time = "2025-05-21T16:18:58.144Z" }, - { url = "https://files.pythonhosted.org/packages/e8/bb/b8f697ba6a16c1e393afe75029d069e2dd457e62b112c3cb26768d2e65eb/bitarray-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f408ba3e6f706a0eabae405d1906ceb539f34a318562a91ab9799c5e1712e18c", size = 325942, upload-time = "2025-05-21T16:18:59.471Z" }, - { url = "https://files.pythonhosted.org/packages/64/ec/77d866a96909c09c5a34f1716f015386f9d9bbbf4b5dc7219f642b8043e2/bitarray-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bf94513ae559b2525e6218e41b03790f866d75df5404490420f2c25e42cf55e7", size = 329491, upload-time = "2025-05-21T16:19:01.205Z" }, - { url = "https://files.pythonhosted.org/packages/37/6e/633b7d392a39df655c92035da9ee52f7332bb165ae72038692a33a6def6c/bitarray-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f2c88c792815d2755c49a3a1fca256e142c4adfadf1a2142b5a3a37e4d4b871", size = 309566, upload-time = "2025-05-21T16:19:02.762Z" }, - { url = "https://files.pythonhosted.org/packages/ab/38/9d7ad6eca72e09b81097176dd66eed3aeaabdea4c24cf6ce25609599ce7b/bitarray-3.4.2-cp312-cp312-win32.whl", hash = "sha256:f4dac6b942c4d7ae5f6eb555ee3993de1432bf9c8f46e3caf74b6671ac5571a3", size = 134600, upload-time = "2025-05-21T16:19:04.057Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d3/c83ec3d912be73861a064f1a705436f270b8c5b5926350a875bd6c06b6df/bitarray-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:6c37e6814633041307f0df281651a86372b0ccdb1e4768247a87e83e2b68f9b9", size = 141844, upload-time = "2025-05-21T16:19:05.254Z" }, - { url = "https://files.pythonhosted.org/packages/f2/22/973d377477e1f27cf64f9e3292343219577136e32665a52667589380100d/bitarray-3.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:16263bdbb05ce379e7b8e9a9f3e0a61a9204a06a037bbc91322d2939b3079fd5", size = 141162, upload-time = "2025-05-21T16:19:06.488Z" }, - { url = "https://files.pythonhosted.org/packages/eb/53/65541b94fb6df1e8aa9a7359ac68f469c3243d8bc7302c5fb8ff8936dab2/bitarray-3.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:41fdc6fb8c3aabfcfe0073302c69fef0c74d6499491f133ba58755c3f2afb3d0", size = 138162, upload-time = "2025-05-21T16:19:07.688Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b2/83d587965f7969a5016a5bf5c9295a0651a34b668df41fa089d7c924ac08/bitarray-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c2571337b11c69206e339170516f3e72b4ec16250876c4f2bbb6e82b9caa15", size = 315760, upload-time = "2025-05-21T16:19:09.834Z" }, - { url = "https://files.pythonhosted.org/packages/4f/f5/2b2924181809debdb644143aa33d16facdce5763d5ff17e5301ecdaf89dc/bitarray-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0e3d5f37217dde9b206418c37c4d86e173f072a892670e9714e6bb20b228e95", size = 331250, upload-time = "2025-05-21T16:19:11.449Z" }, - { url = "https://files.pythonhosted.org/packages/00/2b/8ed4eeb947e05ef54614feff4cc4badd03e29ec35d46aa0218513cc9f8ac/bitarray-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83202735f21fc781f27228daeae94b6c7df1a9f673b9dd6a1c0b3764d92b8e50", size = 324299, upload-time = "2025-05-21T16:19:13.236Z" }, - { url = "https://files.pythonhosted.org/packages/05/27/d7f1b15c079cbeffad76f97c41c27635873be4d5600f6896b2bbc4f5caff/bitarray-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b3f8c35812d85a299d6c0ff097f93e18dfb7a324c129e20a4ec0ecfc4ba995", size = 317522, upload-time = "2025-05-21T16:19:14.832Z" }, - { url = "https://files.pythonhosted.org/packages/a5/db/e6a857a23222360dbc0b0d177e6060ecd88d63a1d6a3c2b52333c21a9683/bitarray-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef3f2e8ba5d6e0f38b57960d1bfb72aa9e2115f7cdca48561fadced652798d49", size = 305290, upload-time = "2025-05-21T16:19:16.57Z" }, - { url = "https://files.pythonhosted.org/packages/16/12/3b945e415233889c57c26f95a9a6a245da546e2c8d1de09991332cb796ff/bitarray-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:508ec6547bdd9f0c435c322fbb127a3dfd74c943a6c7f77fa5dfcb3e9ce1de66", size = 309764, upload-time = "2025-05-21T16:19:18.34Z" }, - { url = "https://files.pythonhosted.org/packages/6c/0e/9effb83e23ef5495c9078bdbac948df4fe2b202fb0ac5b33412848ab4b1e/bitarray-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1a3a08cc920f601258ea33d97b4454cd7cb04d17930e0a3bc7328ba3d732f8b0", size = 301690, upload-time = "2025-05-21T16:19:19.694Z" }, - { url = "https://files.pythonhosted.org/packages/cb/67/9a73476c8cd6a67ff5ab9c5c1d916307e4fb9178d76ee2781552451c995c/bitarray-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:60189130ae1ebaadbab27e3ad0a7d7ed44f5d9456bbfae07c72138501ce59053", size = 326049, upload-time = "2025-05-21T16:19:21.371Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b1/2a81f5f96c1ccc033d8c63b4584aedbd9e27499cf2276fc70d4f87ad673b/bitarray-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9e425eaf21a8d7b76531630029441c6d61f6064cbf4dd592af1607c79eb2e4d0", size = 329565, upload-time = "2025-05-21T16:19:22.88Z" }, - { url = "https://files.pythonhosted.org/packages/2e/30/670efe7771944b4b7d0aacdc076969adc9428c9d0939ee70230bdf4c8aed/bitarray-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:952cc40c593f663ba083be76d1ccdb6dc9dafab8fb6d949056405636b2e720f3", size = 309661, upload-time = "2025-05-21T16:19:24.574Z" }, - { url = "https://files.pythonhosted.org/packages/ee/2e/b2d8e842fe484d7d18fcd137289e396c7784b8484e0ec7e94ffe4bb7e8f9/bitarray-3.4.2-cp313-cp313-win32.whl", hash = "sha256:158f6b1a315eaf971f88e66f9b93431c3b580b46d2121c6a1166e7b761408fdf", size = 134614, upload-time = "2025-05-21T16:19:25.914Z" }, - { url = "https://files.pythonhosted.org/packages/0c/50/0ec25a51197410a66146eea7950e3597baedb000f2f2e2458bb6d5306b0a/bitarray-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:2d24658ac96a82beb4da2f5c71bef9790f3dcabadbe8ead8dda742ab207fe2f9", size = 141851, upload-time = "2025-05-21T16:19:27.388Z" }, - { url = "https://files.pythonhosted.org/packages/e7/03/77eca3d93f162c0982f370e6459d1fcb6ff51e84f80adb34c43256653bda/bitarray-3.4.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9c02f3234b1ec391aa235b265a3649e8078d814cdd6b42bc5aee267cc370b0c8", size = 135778, upload-time = "2025-05-21T16:20:58.492Z" }, - { url = "https://files.pythonhosted.org/packages/68/fd/5b148fb07e2b74e1cd17db7b940abdb1c7af6ac3a024810a5931db6e436b/bitarray-3.4.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:e19e5a35f53c0eaf4516cfa3f80de110eb831fd3d9785aa8b8f4a8a8c0d99523", size = 132826, upload-time = "2025-05-21T16:21:00.901Z" }, - { url = "https://files.pythonhosted.org/packages/e5/50/8cfb459218cd074a3af7121f6509ac55be2d6ac5a0a048b188934976f589/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f633d1e92fdc6a039b118d67f23d17b9ac4046a629bde04e178b770fe83a618f", size = 141592, upload-time = "2025-05-21T16:21:02.4Z" }, - { url = "https://files.pythonhosted.org/packages/43/c0/a70a212ecfd4256e7281456beee5330945ea09cec8fb0be3f99ed6828a08/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c08bc2ec3f15fbb3a99923ef1b16b621af45ab9d5146a06f970c0f0d7cab22ba", size = 142502, upload-time = "2025-05-21T16:21:08.366Z" }, - { url = "https://files.pythonhosted.org/packages/1e/8e/9fc84001701ef1fd7f18b0254bf08d594adaed34fe0b5770d8c032b4d53a/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eed46fa39af8440b1cff09a9805d65449583d524006efa29e5262bea9e08787e", size = 143930, upload-time = "2025-05-21T16:21:09.819Z" }, - { url = "https://files.pythonhosted.org/packages/f7/05/2f6753d75282033e66e0a9626ef4209500cd7a08aa8f92cc70fa49681cf3/bitarray-3.4.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9cf23c13c84c1559ed28bd211a6290b7326c2011f6c30c82cee052b254ac09f0", size = 140275, upload-time = "2025-05-21T16:21:11.481Z" }, -] - -[[package]] -name = "blinker" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, -] - -[[package]] -name = "cdp-sdk" -version = "1.15.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "aiohttp-retry" }, - { name = "base58" }, - { name = "cryptography" }, - { name = "nest-asyncio" }, - { name = "pydantic" }, - { name = "pyjwt" }, - { name = "python-dateutil" }, - { name = "solana" }, - { name = "solders" }, - { name = "urllib3" }, - { name = "web3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ac/2c/76bb57aeb63443b3e1ba23eeb31cdb5d70b8103fc348100a898b629d177e/cdp_sdk-1.15.0.tar.gz", hash = "sha256:df8f077b43eea611287343267ac1887cd43e65684d798c8ea9b005d8c2979e21", size = 210028, upload-time = "2025-06-18T21:22:48.444Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/63/6fd015f2b33cc3ffb3fb2ec0c8e7a99661a146e28e68f42a57a6c8d6da21/cdp_sdk-1.15.0-py3-none-any.whl", hash = "sha256:6d5f32438c91dbbcaecab7d737b5220f4fdd3574958905d469d470a3be13964d", size = 473528, upload-time = "2025-06-18T21:22:46.505Z" }, -] - -[[package]] -name = "certifi" -version = "2025.4.26" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, -] - -[[package]] -name = "cffi" -version = "1.17.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pycparser" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/97/c783634659c2920c3fc70419e3af40972dbaf758daa229a7d6ea6135c90d/cffi-1.17.1.tar.gz", hash = "sha256:1c39c6016c32bc48dd54561950ebd6836e1670f2ae46128f67cf49e789c52824", size = 516621, upload-time = "2024-09-04T20:45:21.852Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/90/07/f44ca684db4e4f08a3fdc6eeb9a0d15dc6883efc7b8c90357fdbf74e186c/cffi-1.17.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:df8b1c11f177bc2313ec4b2d46baec87a5f3e71fc8b45dab2ee7cae86d9aba14", size = 182191, upload-time = "2024-09-04T20:43:30.027Z" }, - { url = "https://files.pythonhosted.org/packages/08/fd/cc2fedbd887223f9f5d170c96e57cbf655df9831a6546c1727ae13fa977a/cffi-1.17.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8f2cdc858323644ab277e9bb925ad72ae0e67f69e804f4898c070998d50b1a67", size = 178592, upload-time = "2024-09-04T20:43:32.108Z" }, - { url = "https://files.pythonhosted.org/packages/de/cc/4635c320081c78d6ffc2cab0a76025b691a91204f4aa317d568ff9280a2d/cffi-1.17.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:edae79245293e15384b51f88b00613ba9f7198016a5948b5dddf4917d4d26382", size = 426024, upload-time = "2024-09-04T20:43:34.186Z" }, - { url = "https://files.pythonhosted.org/packages/b6/7b/3b2b250f3aab91abe5f8a51ada1b717935fdaec53f790ad4100fe2ec64d1/cffi-1.17.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:45398b671ac6d70e67da8e4224a065cec6a93541bb7aebe1b198a61b58c7b702", size = 448188, upload-time = "2024-09-04T20:43:36.286Z" }, - { url = "https://files.pythonhosted.org/packages/d3/48/1b9283ebbf0ec065148d8de05d647a986c5f22586b18120020452fff8f5d/cffi-1.17.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ad9413ccdeda48c5afdae7e4fa2192157e991ff761e7ab8fdd8926f40b160cc3", size = 455571, upload-time = "2024-09-04T20:43:38.586Z" }, - { url = "https://files.pythonhosted.org/packages/40/87/3b8452525437b40f39ca7ff70276679772ee7e8b394934ff60e63b7b090c/cffi-1.17.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5da5719280082ac6bd9aa7becb3938dc9f9cbd57fac7d2871717b1feb0902ab6", size = 436687, upload-time = "2024-09-04T20:43:40.084Z" }, - { url = "https://files.pythonhosted.org/packages/8d/fb/4da72871d177d63649ac449aec2e8a29efe0274035880c7af59101ca2232/cffi-1.17.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bb1a08b8008b281856e5971307cc386a8e9c5b625ac297e853d36da6efe9c17", size = 446211, upload-time = "2024-09-04T20:43:41.526Z" }, - { url = "https://files.pythonhosted.org/packages/ab/a0/62f00bcb411332106c02b663b26f3545a9ef136f80d5df746c05878f8c4b/cffi-1.17.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:045d61c734659cc045141be4bae381a41d89b741f795af1dd018bfb532fd0df8", size = 461325, upload-time = "2024-09-04T20:43:43.117Z" }, - { url = "https://files.pythonhosted.org/packages/36/83/76127035ed2e7e27b0787604d99da630ac3123bfb02d8e80c633f218a11d/cffi-1.17.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:6883e737d7d9e4899a8a695e00ec36bd4e5e4f18fabe0aca0efe0a4b44cdb13e", size = 438784, upload-time = "2024-09-04T20:43:45.256Z" }, - { url = "https://files.pythonhosted.org/packages/21/81/a6cd025db2f08ac88b901b745c163d884641909641f9b826e8cb87645942/cffi-1.17.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:6b8b4a92e1c65048ff98cfe1f735ef8f1ceb72e3d5f0c25fdb12087a23da22be", size = 461564, upload-time = "2024-09-04T20:43:46.779Z" }, - { url = "https://files.pythonhosted.org/packages/f8/fe/4d41c2f200c4a457933dbd98d3cf4e911870877bd94d9656cc0fcb390681/cffi-1.17.1-cp310-cp310-win32.whl", hash = "sha256:c9c3d058ebabb74db66e431095118094d06abf53284d9c81f27300d0e0d8bc7c", size = 171804, upload-time = "2024-09-04T20:43:48.186Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b6/0b0f5ab93b0df4acc49cae758c81fe4e5ef26c3ae2e10cc69249dfd8b3ab/cffi-1.17.1-cp310-cp310-win_amd64.whl", hash = "sha256:0f048dcf80db46f0098ccac01132761580d28e28bc0f78ae0d58048063317e15", size = 181299, upload-time = "2024-09-04T20:43:49.812Z" }, - { url = "https://files.pythonhosted.org/packages/6b/f4/927e3a8899e52a27fa57a48607ff7dc91a9ebe97399b357b85a0c7892e00/cffi-1.17.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:a45e3c6913c5b87b3ff120dcdc03f6131fa0065027d0ed7ee6190736a74cd401", size = 182264, upload-time = "2024-09-04T20:43:51.124Z" }, - { url = "https://files.pythonhosted.org/packages/6c/f5/6c3a8efe5f503175aaddcbea6ad0d2c96dad6f5abb205750d1b3df44ef29/cffi-1.17.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:30c5e0cb5ae493c04c8b42916e52ca38079f1b235c2f8ae5f4527b963c401caf", size = 178651, upload-time = "2024-09-04T20:43:52.872Z" }, - { url = "https://files.pythonhosted.org/packages/94/dd/a3f0118e688d1b1a57553da23b16bdade96d2f9bcda4d32e7d2838047ff7/cffi-1.17.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f75c7ab1f9e4aca5414ed4d8e5c0e303a34f4421f8a0d47a4d019ceff0ab6af4", size = 445259, upload-time = "2024-09-04T20:43:56.123Z" }, - { url = "https://files.pythonhosted.org/packages/2e/ea/70ce63780f096e16ce8588efe039d3c4f91deb1dc01e9c73a287939c79a6/cffi-1.17.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a1ed2dd2972641495a3ec98445e09766f077aee98a1c896dcb4ad0d303628e41", size = 469200, upload-time = "2024-09-04T20:43:57.891Z" }, - { url = "https://files.pythonhosted.org/packages/1c/a0/a4fa9f4f781bda074c3ddd57a572b060fa0df7655d2a4247bbe277200146/cffi-1.17.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:46bf43160c1a35f7ec506d254e5c890f3c03648a4dbac12d624e4490a7046cd1", size = 477235, upload-time = "2024-09-04T20:44:00.18Z" }, - { url = "https://files.pythonhosted.org/packages/62/12/ce8710b5b8affbcdd5c6e367217c242524ad17a02fe5beec3ee339f69f85/cffi-1.17.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a24ed04c8ffd54b0729c07cee15a81d964e6fee0e3d4d342a27b020d22959dc6", size = 459721, upload-time = "2024-09-04T20:44:01.585Z" }, - { url = "https://files.pythonhosted.org/packages/ff/6b/d45873c5e0242196f042d555526f92aa9e0c32355a1be1ff8c27f077fd37/cffi-1.17.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:610faea79c43e44c71e1ec53a554553fa22321b65fae24889706c0a84d4ad86d", size = 467242, upload-time = "2024-09-04T20:44:03.467Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/d9a0e523a572fbccf2955f5abe883cfa8bcc570d7faeee06336fbd50c9fc/cffi-1.17.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a9b15d491f3ad5d692e11f6b71f7857e7835eb677955c00cc0aefcd0669adaf6", size = 477999, upload-time = "2024-09-04T20:44:05.023Z" }, - { url = "https://files.pythonhosted.org/packages/44/74/f2a2460684a1a2d00ca799ad880d54652841a780c4c97b87754f660c7603/cffi-1.17.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:de2ea4b5833625383e464549fec1bc395c1bdeeb5f25c4a3a82b5a8c756ec22f", size = 454242, upload-time = "2024-09-04T20:44:06.444Z" }, - { url = "https://files.pythonhosted.org/packages/f8/4a/34599cac7dfcd888ff54e801afe06a19c17787dfd94495ab0c8d35fe99fb/cffi-1.17.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fc48c783f9c87e60831201f2cce7f3b2e4846bf4d8728eabe54d60700b318a0b", size = 478604, upload-time = "2024-09-04T20:44:08.206Z" }, - { url = "https://files.pythonhosted.org/packages/34/33/e1b8a1ba29025adbdcda5fb3a36f94c03d771c1b7b12f726ff7fef2ebe36/cffi-1.17.1-cp311-cp311-win32.whl", hash = "sha256:85a950a4ac9c359340d5963966e3e0a94a676bd6245a4b55bc43949eee26a655", size = 171727, upload-time = "2024-09-04T20:44:09.481Z" }, - { url = "https://files.pythonhosted.org/packages/3d/97/50228be003bb2802627d28ec0627837ac0bf35c90cf769812056f235b2d1/cffi-1.17.1-cp311-cp311-win_amd64.whl", hash = "sha256:caaf0640ef5f5517f49bc275eca1406b0ffa6aa184892812030f04c2abf589a0", size = 181400, upload-time = "2024-09-04T20:44:10.873Z" }, - { url = "https://files.pythonhosted.org/packages/5a/84/e94227139ee5fb4d600a7a4927f322e1d4aea6fdc50bd3fca8493caba23f/cffi-1.17.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:805b4371bf7197c329fcb3ead37e710d1bca9da5d583f5073b799d5c5bd1eee4", size = 183178, upload-time = "2024-09-04T20:44:12.232Z" }, - { url = "https://files.pythonhosted.org/packages/da/ee/fb72c2b48656111c4ef27f0f91da355e130a923473bf5ee75c5643d00cca/cffi-1.17.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:733e99bc2df47476e3848417c5a4540522f234dfd4ef3ab7fafdf555b082ec0c", size = 178840, upload-time = "2024-09-04T20:44:13.739Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b6/db007700f67d151abadf508cbfd6a1884f57eab90b1bb985c4c8c02b0f28/cffi-1.17.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1257bdabf294dceb59f5e70c64a3e2f462c30c7ad68092d01bbbfb1c16b1ba36", size = 454803, upload-time = "2024-09-04T20:44:15.231Z" }, - { url = "https://files.pythonhosted.org/packages/1a/df/f8d151540d8c200eb1c6fba8cd0dfd40904f1b0682ea705c36e6c2e97ab3/cffi-1.17.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da95af8214998d77a98cc14e3a3bd00aa191526343078b530ceb0bd710fb48a5", size = 478850, upload-time = "2024-09-04T20:44:17.188Z" }, - { url = "https://files.pythonhosted.org/packages/28/c0/b31116332a547fd2677ae5b78a2ef662dfc8023d67f41b2a83f7c2aa78b1/cffi-1.17.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d63afe322132c194cf832bfec0dc69a99fb9bb6bbd550f161a49e9e855cc78ff", size = 485729, upload-time = "2024-09-04T20:44:18.688Z" }, - { url = "https://files.pythonhosted.org/packages/91/2b/9a1ddfa5c7f13cab007a2c9cc295b70fbbda7cb10a286aa6810338e60ea1/cffi-1.17.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f79fc4fc25f1c8698ff97788206bb3c2598949bfe0fef03d299eb1b5356ada99", size = 471256, upload-time = "2024-09-04T20:44:20.248Z" }, - { url = "https://files.pythonhosted.org/packages/b2/d5/da47df7004cb17e4955df6a43d14b3b4ae77737dff8bf7f8f333196717bf/cffi-1.17.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b62ce867176a75d03a665bad002af8e6d54644fad99a3c70905c543130e39d93", size = 479424, upload-time = "2024-09-04T20:44:21.673Z" }, - { url = "https://files.pythonhosted.org/packages/0b/ac/2a28bcf513e93a219c8a4e8e125534f4f6db03e3179ba1c45e949b76212c/cffi-1.17.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:386c8bf53c502fff58903061338ce4f4950cbdcb23e2902d86c0f722b786bbe3", size = 484568, upload-time = "2024-09-04T20:44:23.245Z" }, - { url = "https://files.pythonhosted.org/packages/d4/38/ca8a4f639065f14ae0f1d9751e70447a261f1a30fa7547a828ae08142465/cffi-1.17.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ceb10419a9adf4460ea14cfd6bc43d08701f0835e979bf821052f1805850fe8", size = 488736, upload-time = "2024-09-04T20:44:24.757Z" }, - { url = "https://files.pythonhosted.org/packages/86/c5/28b2d6f799ec0bdecf44dced2ec5ed43e0eb63097b0f58c293583b406582/cffi-1.17.1-cp312-cp312-win32.whl", hash = "sha256:a08d7e755f8ed21095a310a693525137cfe756ce62d066e53f502a83dc550f65", size = 172448, upload-time = "2024-09-04T20:44:26.208Z" }, - { url = "https://files.pythonhosted.org/packages/50/b9/db34c4755a7bd1cb2d1603ac3863f22bcecbd1ba29e5ee841a4bc510b294/cffi-1.17.1-cp312-cp312-win_amd64.whl", hash = "sha256:51392eae71afec0d0c8fb1a53b204dbb3bcabcb3c9b807eedf3e1e6ccf2de903", size = 181976, upload-time = "2024-09-04T20:44:27.578Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f8/dd6c246b148639254dad4d6803eb6a54e8c85c6e11ec9df2cffa87571dbe/cffi-1.17.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:f3a2b4222ce6b60e2e8b337bb9596923045681d71e5a082783484d845390938e", size = 182989, upload-time = "2024-09-04T20:44:28.956Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f1/672d303ddf17c24fc83afd712316fda78dc6fce1cd53011b839483e1ecc8/cffi-1.17.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:0984a4925a435b1da406122d4d7968dd861c1385afe3b45ba82b750f229811e2", size = 178802, upload-time = "2024-09-04T20:44:30.289Z" }, - { url = "https://files.pythonhosted.org/packages/0e/2d/eab2e858a91fdff70533cab61dcff4a1f55ec60425832ddfdc9cd36bc8af/cffi-1.17.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d01b12eeeb4427d3110de311e1774046ad344f5b1a7403101878976ecd7a10f3", size = 454792, upload-time = "2024-09-04T20:44:32.01Z" }, - { url = "https://files.pythonhosted.org/packages/75/b2/fbaec7c4455c604e29388d55599b99ebcc250a60050610fadde58932b7ee/cffi-1.17.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:706510fe141c86a69c8ddc029c7910003a17353970cff3b904ff0686a5927683", size = 478893, upload-time = "2024-09-04T20:44:33.606Z" }, - { url = "https://files.pythonhosted.org/packages/4f/b7/6e4a2162178bf1935c336d4da8a9352cccab4d3a5d7914065490f08c0690/cffi-1.17.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:de55b766c7aa2e2a3092c51e0483d700341182f08e67c63630d5b6f200bb28e5", size = 485810, upload-time = "2024-09-04T20:44:35.191Z" }, - { url = "https://files.pythonhosted.org/packages/c7/8a/1d0e4a9c26e54746dc08c2c6c037889124d4f59dffd853a659fa545f1b40/cffi-1.17.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c59d6e989d07460165cc5ad3c61f9fd8f1b4796eacbd81cee78957842b834af4", size = 471200, upload-time = "2024-09-04T20:44:36.743Z" }, - { url = "https://files.pythonhosted.org/packages/26/9f/1aab65a6c0db35f43c4d1b4f580e8df53914310afc10ae0397d29d697af4/cffi-1.17.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd398dbc6773384a17fe0d3e7eeb8d1a21c2200473ee6806bb5e6a8e62bb73dd", size = 479447, upload-time = "2024-09-04T20:44:38.492Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e4/fb8b3dd8dc0e98edf1135ff067ae070bb32ef9d509d6cb0f538cd6f7483f/cffi-1.17.1-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:3edc8d958eb099c634dace3c7e16560ae474aa3803a5df240542b305d14e14ed", size = 484358, upload-time = "2024-09-04T20:44:40.046Z" }, - { url = "https://files.pythonhosted.org/packages/f1/47/d7145bf2dc04684935d57d67dff9d6d795b2ba2796806bb109864be3a151/cffi-1.17.1-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:72e72408cad3d5419375fc87d289076ee319835bdfa2caad331e377589aebba9", size = 488469, upload-time = "2024-09-04T20:44:41.616Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ee/f94057fa6426481d663b88637a9a10e859e492c73d0384514a17d78ee205/cffi-1.17.1-cp313-cp313-win32.whl", hash = "sha256:e03eab0a8677fa80d646b5ddece1cbeaf556c313dcfac435ba11f107ba117b5d", size = 172475, upload-time = "2024-09-04T20:44:43.733Z" }, - { url = "https://files.pythonhosted.org/packages/7c/fc/6a8cb64e5f0324877d503c854da15d76c1e50eb722e320b15345c4d0c6de/cffi-1.17.1-cp313-cp313-win_amd64.whl", hash = "sha256:f6a16c31041f09ead72d69f583767292f750d24913dadacf5756b966aacb3f1a", size = 182009, upload-time = "2024-09-04T20:44:45.309Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9b/892a8c8af9110935e5adcbb06d9c6fe741b6bb02608c6513983048ba1a18/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd", size = 144649, upload-time = "2025-05-02T08:31:48.889Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a5/4179abd063ff6414223575e008593861d62abfc22455b5d1a44995b7c101/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6", size = 155045, upload-time = "2025-05-02T08:31:50.757Z" }, - { url = "https://files.pythonhosted.org/packages/3b/95/bc08c7dfeddd26b4be8c8287b9bb055716f31077c8b0ea1cd09553794665/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d", size = 147356, upload-time = "2025-05-02T08:31:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/7a5b635aa65284bf3eab7653e8b4151ab420ecbae918d3e359d1947b4d61/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86", size = 149471, upload-time = "2025-05-02T08:31:56.207Z" }, - { url = "https://files.pythonhosted.org/packages/ae/38/51fc6ac74251fd331a8cfdb7ec57beba8c23fd5493f1050f71c87ef77ed0/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c", size = 151317, upload-time = "2025-05-02T08:31:57.613Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/edee1e32215ee6e9e46c3e482645b46575a44a2d72c7dfd49e49f60ce6bf/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0", size = 146368, upload-time = "2025-05-02T08:31:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/26/2c/ea3e66f2b5f21fd00b2825c94cafb8c326ea6240cd80a91eb09e4a285830/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef", size = 154491, upload-time = "2025-05-02T08:32:01.219Z" }, - { url = "https://files.pythonhosted.org/packages/52/47/7be7fa972422ad062e909fd62460d45c3ef4c141805b7078dbab15904ff7/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6", size = 157695, upload-time = "2025-05-02T08:32:03.045Z" }, - { url = "https://files.pythonhosted.org/packages/2f/42/9f02c194da282b2b340f28e5fb60762de1151387a36842a92b533685c61e/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366", size = 154849, upload-time = "2025-05-02T08:32:04.651Z" }, - { url = "https://files.pythonhosted.org/packages/67/44/89cacd6628f31fb0b63201a618049be4be2a7435a31b55b5eb1c3674547a/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db", size = 150091, upload-time = "2025-05-02T08:32:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/1f/79/4b8da9f712bc079c0f16b6d67b099b0b8d808c2292c937f267d816ec5ecc/charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a", size = 98445, upload-time = "2025-05-02T08:32:08.66Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d7/96970afb4fb66497a40761cdf7bd4f6fca0fc7bafde3a84f836c1f57a926/charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509", size = 105782, upload-time = "2025-05-02T08:32:10.46Z" }, - { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" }, - { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" }, - { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" }, - { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" }, - { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" }, - { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, -] - -[[package]] -name = "ckzg" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/55/df/f6db8e83bd4594c1ea685cd37fb81d5399e55765aae16d1a8a9502598f4e/ckzg-2.1.1.tar.gz", hash = "sha256:d6b306b7ec93a24e4346aa53d07f7f75053bc0afc7398e35fa649e5f9d48fcc4", size = 1120500, upload-time = "2025-03-31T21:24:12.324Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/4b/cd25e857cdf46a752e97c530fe2582fae77c4d16c29fff5a15b7a998e2fd/ckzg-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b9825a1458219e8b4b023012b8ef027ef1f47e903f9541cbca4615f80132730", size = 116377, upload-time = "2025-03-31T21:22:26.952Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bc/5dfef36589545f797245ecacb54ed2acfa75507f63cfe12182d1277a88f1/ckzg-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2a40a3ba65cca4b52825d26829e6f7eb464aa27a9e9efb6b8b2ce183442c741", size = 100208, upload-time = "2025-03-31T21:22:28.04Z" }, - { url = "https://files.pythonhosted.org/packages/b7/52/96f0e3affbed321dc52b9b4ca13e0fb594da572d1f8edc47378fe48d8e9a/ckzg-2.1.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1d753fbe85be7c21602eddc2d40e0915e25fce10329f4f801a0002a4f886cc7", size = 174800, upload-time = "2025-03-31T21:22:29.719Z" }, - { url = "https://files.pythonhosted.org/packages/dc/21/b1bc07cc8e5ed32817e89b054e2399d38775d92ff2d55e24bf233f537c02/ckzg-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d76b50527f1d12430bf118aff6fa4051e9860eada43f29177258b8d399448ea", size = 160847, upload-time = "2025-03-31T21:22:30.973Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5a/97b173d4ff9bce798031beb12b340c4f1729eaaddd07f69f368f843db28e/ckzg-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44c8603e43c021d100f355f50189183135d1df3cbbddb8881552d57fbf421dde", size = 169712, upload-time = "2025-03-31T21:22:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/7b/52/48be78c07f362438e189e2fbea7df8543290c3ee99845442549c8dc5405b/ckzg-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:38707a638c9d715b3c30b29352b969f78d8fc10faed7db5faf517f04359895c0", size = 172942, upload-time = "2025-03-31T21:22:32.8Z" }, - { url = "https://files.pythonhosted.org/packages/13/42/3cfcd6cbdfb9030b9071d5e413a458f93883e47ad4a7d8d4c1d57608e57d/ckzg-2.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:52c4d257bdcbe822d20c5cd24c8154ec5aac33c49a8f5a19e716d9107a1c8785", size = 187707, upload-time = "2025-03-31T21:22:33.673Z" }, - { url = "https://files.pythonhosted.org/packages/eb/54/d43bc3a2de486fb8be29ffedc3ec80f5726765ee4fa78beabe2ab2440f93/ckzg-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1507f7bfb9bcf51d816db5d8d0f0ed53c8289605137820d437b69daea8333e16", size = 182505, upload-time = "2025-03-31T21:22:34.563Z" }, - { url = "https://files.pythonhosted.org/packages/21/43/5bcd2b7630732b532006572fbb8d64a29f69530c630ae4811167a2a0dc3b/ckzg-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d02eaaf4f841910133552b3a051dea53bcfe60cd98199fc4cf80b27609d8baa2", size = 98822, upload-time = "2025-03-31T21:22:35.786Z" }, - { url = "https://files.pythonhosted.org/packages/95/2c/44120b2d9dcb0246d67a1f28b9eaa625c499014d4d42561467e28eedd285/ckzg-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:465e2b71cf9dc383f66f1979269420a0da9274a3a9e98b1a4455e84927dfe491", size = 116378, upload-time = "2025-03-31T21:22:36.96Z" }, - { url = "https://files.pythonhosted.org/packages/23/88/c5b89ba9a730fee5e089be9e0c7048fb6707c1a0e4b6c30fcf725c3eef44/ckzg-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ee2f26f17a64ad0aab833d637b276f28486b82a29e34f32cf54b237b8f8ab72d", size = 100202, upload-time = "2025-03-31T21:22:37.799Z" }, - { url = "https://files.pythonhosted.org/packages/ee/11/b0a473e80346db52ad9a629bc9fd8f773c718ed78932ea3a70392306ffc3/ckzg-2.1.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99cc2c4e9fb8c62e3e0862c7f4df9142f07ba640da17fded5f6e0fd09f75909f", size = 175595, upload-time = "2025-03-31T21:22:39.013Z" }, - { url = "https://files.pythonhosted.org/packages/52/fa/17a7e125d07a96dd6dce4db7262231f7583856b2be5d5b7df59e04bfa188/ckzg-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773dd016693d74aca1f5d7982db2bad7dde2e147563aeb16a783f7e5f69c01fe", size = 161681, upload-time = "2025-03-31T21:22:40.257Z" }, - { url = "https://files.pythonhosted.org/packages/57/bd/46d6b90bf53da732f9adab7593d132a0834ed4f2f7659b4c7414d8f78d39/ckzg-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af2b2144f87ba218d8db01382a961b3ecbdde5ede4fa0d9428d35f8c8a595ba", size = 170471, upload-time = "2025-03-31T21:22:41.513Z" }, - { url = "https://files.pythonhosted.org/packages/9d/98/113c7704749d037d75f23240ffc5c46dfe8416de574b946438587835715f/ckzg-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f55e63d3f7c934a2cb53728ed1d815479e177aca8c84efe991c2920977cff6", size = 173595, upload-time = "2025-03-31T21:22:42.534Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d5/05fca6dcb5a19327be491157794eafc3d7498daf615c2ff5a5b745852945/ckzg-2.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ecb42aaa0ffa427ff14a9dde9356ba69e5ae6014650b397af55b31bdae7a9b6e", size = 188417, upload-time = "2025-03-31T21:22:43.466Z" }, - { url = "https://files.pythonhosted.org/packages/72/36/131ae2dfc82d0fdc98fae8e3bbfe71ff14265bb434b23bd07b585afc6d61/ckzg-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5a01514239f12fb1a7ad9009c20062a4496e13b09541c1a65f97e295da648c70", size = 183286, upload-time = "2025-03-31T21:22:44.732Z" }, - { url = "https://files.pythonhosted.org/packages/c5/6a/d371b27024422b25228fc11fa57b1ba7756a94cc9fb0c75da292c235fdaa/ckzg-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:6516b9684aae262c85cf7fddd8b585b8139ad20e08ec03994e219663abbb0916", size = 98819, upload-time = "2025-03-31T21:22:45.57Z" }, - { url = "https://files.pythonhosted.org/packages/93/a1/9c07513dd0ea01e5db727e67bd2660f3b300a4511281cdb8d5e04afa1cfd/ckzg-2.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c60e8903344ce98ce036f0fabacce952abb714cad4607198b2f0961c28b8aa72", size = 116421, upload-time = "2025-03-31T21:22:46.434Z" }, - { url = "https://files.pythonhosted.org/packages/27/04/b69a0dfbb2722a14c98a52973f276679151ec56a14178cb48e6f2e1697bc/ckzg-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4299149dd72448e5a8d2d1cc6cc7472c92fc9d9f00b1377f5b017c089d9cd92", size = 100216, upload-time = "2025-03-31T21:22:47.633Z" }, - { url = "https://files.pythonhosted.org/packages/2e/24/9cc850d0b8ead395ad5064de67c7c91adacaf31b6b35292ab53fbd93270b/ckzg-2.1.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:025dd31ffdcc799f3ff842570a2a6683b6c5b01567da0109c0c05d11768729c4", size = 175764, upload-time = "2025-03-31T21:22:48.768Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c1/eb13ba399082a98b932f10b230ec08e6456051c0ce3886b3f6d8548d11ab/ckzg-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b42ab8385c273f40a693657c09d2bba40cb4f4666141e263906ba2e519e80bd", size = 161885, upload-time = "2025-03-31T21:22:50.05Z" }, - { url = "https://files.pythonhosted.org/packages/57/c7/58baa64199781950c5a8c6139a46e1acff0f057a36e56769817400eb87fb/ckzg-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be3890fc1543f4fcfc0063e4baf5c036eb14bcf736dabdc6171ab017e0f1671", size = 170757, upload-time = "2025-03-31T21:22:51.282Z" }, - { url = "https://files.pythonhosted.org/packages/65/bd/4b8e1c70972c98829371b7004dc750a45268c5d3442d602e1b62f13ca867/ckzg-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b754210ded172968b201e2d7252573af6bf52d6ad127ddd13d0b9a45a51dae7b", size = 173761, upload-time = "2025-03-31T21:22:52.6Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/c3fd1002f97ba3e0c5b1d9ab2c8fb7a6f475fa9b80ed9c4fa55975501a54/ckzg-2.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2f8fda87865897a269c4e951e3826c2e814427a6cdfed6731cccfe548f12b36", size = 188666, upload-time = "2025-03-31T21:22:53.47Z" }, - { url = "https://files.pythonhosted.org/packages/e2/d9/91cf5a8169ee60c9397c975163cbca34432571f94facec5f8c0086bb47d8/ckzg-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:98e70b5923d77c7359432490145e9d1ab0bf873eb5de56ec53f4a551d7eaec79", size = 183652, upload-time = "2025-03-31T21:22:54.351Z" }, - { url = "https://files.pythonhosted.org/packages/25/d4/8c9f6b852f99926862344b29f0c59681916ccfec2ac60a85952a369e0bca/ckzg-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:42af7bde4ca45469cd93a96c3d15d69d51d40e7f0d30e3a20711ebd639465fcb", size = 98816, upload-time = "2025-03-31T21:22:55.23Z" }, - { url = "https://files.pythonhosted.org/packages/b7/9a/fa698b12e97452d11dd314e0335aae759725284ef6e1c1665aed56b1cd3e/ckzg-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e4edfdaf87825ff43b9885fabfdea408737a714f4ce5467100d9d1d0a03b673", size = 116426, upload-time = "2025-03-31T21:22:56.108Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/8cccd308bd11b49b40eecad6900b5769da117951cac33e880dd25e851ef7/ckzg-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:815fd2a87d6d6c57d669fda30c150bc9bf387d47e67d84535aa42b909fdc28ea", size = 100219, upload-time = "2025-03-31T21:22:56.982Z" }, - { url = "https://files.pythonhosted.org/packages/30/0e/63573d816c1292b9a4d70eb6a7366b3593d29a977794039e926805a76ca0/ckzg-2.1.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32466e809b1ab3ff01d3b0bb0b9912f61dcf72957885615595f75e3f7cc10e5", size = 175725, upload-time = "2025-03-31T21:22:58.213Z" }, - { url = "https://files.pythonhosted.org/packages/86/f6/a279609516695ad3fb8b201098c669ba3b2844cbf4fa0d83a0f02b9bb29b/ckzg-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f11b73ccf37b12993f39a7dbace159c6d580aacacde6ee17282848476550ddbc", size = 161835, upload-time = "2025-03-31T21:22:59.448Z" }, - { url = "https://files.pythonhosted.org/packages/39/e4/8cf7aef7dc05a777cb221e94046f947c6fe5317159a8dae2cd7090d52ef2/ckzg-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3b9433a1f2604bd9ac1646d3c83ad84a850d454d3ac589fe8e70c94b38a6b0", size = 170759, upload-time = "2025-03-31T21:23:01.022Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/b34e3c08eb36bc67e338b114f289b2595e581b8bdc09a8f12299a1db5d2f/ckzg-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b7d7e1b5ea06234558cd95c483666fd785a629b720a7f1622b3cbffebdc62033", size = 173787, upload-time = "2025-03-31T21:23:01.974Z" }, - { url = "https://files.pythonhosted.org/packages/2e/f0/aff87c3ed80713453cb6c84fe6fbb7582d86a7a5e4460fda2a497d47f489/ckzg-2.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9f5556e6675866040cc4335907be6c537051e7f668da289fa660fdd8a30c9ddb", size = 188722, upload-time = "2025-03-31T21:23:02.966Z" }, - { url = "https://files.pythonhosted.org/packages/44/d9/1f08bfb8fd1cbb8c7513e7ad3fb76bbb5c3fb446238c1eba582276e4d905/ckzg-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55b2ba30c5c9daac0c55f1aac851f1b7bf1f7aa0028c2db4440e963dd5b866d6", size = 183686, upload-time = "2025-03-31T21:23:03.905Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ff/434f6d2893cbdfad00c20d17e9a52d426ca042f5e980d5c3db96bc6b6e15/ckzg-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:10d201601fc8f28c0e8cec3406676797024dd374c367bbeec5a7a9eac9147237", size = 98817, upload-time = "2025-03-31T21:23:05.2Z" }, - { url = "https://files.pythonhosted.org/packages/30/b3/a0c7d7ba6e669cf04605dc0329173db62fc1fe3c488761755cc01e5e1b4d/ckzg-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:375918e25eafb9bafe5215ab91698504cba3fe51b4fe92f5896af6c5663f50c6", size = 113191, upload-time = "2025-03-31T21:23:40.646Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b9/a6cf403b8528d18d7d9154e28381a397bf466c86aa8e0b3327cffdde5749/ckzg-2.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:38b3b7802c76d4ad015db2b7a79a49c193babae50ee5f77e9ac2865c9e9ddb09", size = 96207, upload-time = "2025-03-31T21:23:41.596Z" }, - { url = "https://files.pythonhosted.org/packages/63/6b/5ddd713d97886becb8450e3e13db891199125f722366d30d087ad5438390/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438a5009fd254ace0bc1ad974d524547f1a41e6aa5e778c5cd41f4ee3106bcd6", size = 126160, upload-time = "2025-03-31T21:23:42.553Z" }, - { url = "https://files.pythonhosted.org/packages/c7/dd/e05aecc01e62108a7579f8df5e5d38536841f50e12172f8a84677edac0fa/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce11cc163a2e0dab3af7455aca7053f9d5bb8d157f231acc7665fd230565d48", size = 102811, upload-time = "2025-03-31T21:23:43.494Z" }, - { url = "https://files.pythonhosted.org/packages/c6/81/6cdadd8626ac11290af3f58ae5dcffe38bd2c8f8c798dacee7475e244aac/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b53964c07f6a076e97eaa1ef35045e935d7040aff14f80bae7e9105717702d05", size = 111328, upload-time = "2025-03-31T21:23:44.449Z" }, - { url = "https://files.pythonhosted.org/packages/36/b7/b129ff6955cd264c6ab3dbd52dd1b2759d1b121c09c03f9991e4c722c72f/ckzg-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cf085f15ae52ab2599c9b5a3d5842794bcf5613b7f58661fbfb0c5d9eac988b9", size = 98846, upload-time = "2025-03-31T21:23:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ba/7d9c1f9cec7e0e382653c72165896194a05743e589b1dae2aa80236aa87f/ckzg-2.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4b0c850bd6cad22ac79b2a2ab884e0e7cd2b54a67d643cd616c145ebdb535a11", size = 113188, upload-time = "2025-03-31T21:23:46.337Z" }, - { url = "https://files.pythonhosted.org/packages/2f/92/9728f5ccc1c5e87c6c5ae7941250a447b61fd5a63aadbc15249e29c21bcf/ckzg-2.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:26951f36bb60c9150bbd38110f5e1625596f9779dad54d1d492d8ec38bc84e3a", size = 96208, upload-time = "2025-03-31T21:23:47.255Z" }, - { url = "https://files.pythonhosted.org/packages/39/63/5e27d587bd224fee70cb66b022e7c4ef95d0e091e08ee76c25ec12094b0d/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbe12445e49c4bee67746b7b958e90a973b0de116d0390749b0df351d94e9a8c", size = 126158, upload-time = "2025-03-31T21:23:48.195Z" }, - { url = "https://files.pythonhosted.org/packages/43/98/e0a45946575a7b823d8ee0b47afb104b6017e54e1208f07da2529bc01900/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c5d4f66f09de4a99271acac74d2acb3559a77de77a366b34a91e99e8822667", size = 102812, upload-time = "2025-03-31T21:23:49.16Z" }, - { url = "https://files.pythonhosted.org/packages/cb/50/718ca7b03e4b89b18cdf99cc3038050105b0acbf9b612c23cd513093c6de/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42673c1d007372a4e8b48f6ef8f0ce31a9688a463317a98539757d1e2fb1ecc7", size = 111327, upload-time = "2025-03-31T21:23:50.126Z" }, - { url = "https://files.pythonhosted.org/packages/29/c5/80e5a0c6967d02d801150104320484a258e5a49bd191e198643e74039320/ckzg-2.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:57a7dc41ec6b69c1d9117eb61cf001295e6b4f67a736020442e71fb4367fb1a5", size = 98847, upload-time = "2025-03-31T21:23:51.084Z" }, -] - -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "construct" -version = "2.10.68" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e0/b7/a4a032e94bcfdff481f2e6fecd472794d9da09f474a2185ed33b2c7cad64/construct-2.10.68.tar.gz", hash = "sha256:7b2a3fd8e5f597a5aa1d614c3bd516fa065db01704c72a1efaaeec6ef23d8b45", size = 57856, upload-time = "2022-02-21T23:09:15.1Z" } - -[[package]] -name = "construct-typing" -version = "0.6.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "construct" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f1/13/c609e60a687252813aa4b69f989f42754ccd5e217717216fc852eefedfd7/construct-typing-0.6.2.tar.gz", hash = "sha256:948e998cfc003681dc34f2d071c3a688cf35b805cbe107febbc488ef967ccba1", size = 22029, upload-time = "2023-08-03T07:31:06.205Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b2/0b/ab3ce2b27dd74b6a6703065bd304ea8211ff4de3b1c304446ed95234177b/construct_typing-0.6.2-py3-none-any.whl", hash = "sha256:ebea6989ac622d0c4eb457092cef0c7bfbcfa110bd018670fea7064d0bc09e47", size = 23298, upload-time = "2023-08-03T07:31:04.545Z" }, -] - -[[package]] -name = "cryptography" -version = "45.0.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/c8/a2a376a8711c1e11708b9c9972e0c3223f5fc682552c82d8db844393d6ce/cryptography-45.0.4.tar.gz", hash = "sha256:7405ade85c83c37682c8fe65554759800a4a8c54b2d96e0f8ad114d31b808d57", size = 744890, upload-time = "2025-06-10T00:03:51.297Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cc/1c/92637793de053832523b410dbe016d3f5c11b41d0cf6eef8787aabb51d41/cryptography-45.0.4-cp311-abi3-macosx_10_9_universal2.whl", hash = "sha256:425a9a6ac2823ee6e46a76a21a4e8342d8fa5c01e08b823c1f19a8b74f096069", size = 7055712, upload-time = "2025-06-10T00:02:38.826Z" }, - { url = "https://files.pythonhosted.org/packages/ba/14/93b69f2af9ba832ad6618a03f8a034a5851dc9a3314336a3d71c252467e1/cryptography-45.0.4-cp311-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:680806cf63baa0039b920f4976f5f31b10e772de42f16310a6839d9f21a26b0d", size = 4205335, upload-time = "2025-06-10T00:02:41.64Z" }, - { url = "https://files.pythonhosted.org/packages/67/30/fae1000228634bf0b647fca80403db5ca9e3933b91dd060570689f0bd0f7/cryptography-45.0.4-cp311-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:4ca0f52170e821bc8da6fc0cc565b7bb8ff8d90d36b5e9fdd68e8a86bdf72036", size = 4431487, upload-time = "2025-06-10T00:02:43.696Z" }, - { url = "https://files.pythonhosted.org/packages/6d/5a/7dffcf8cdf0cb3c2430de7404b327e3db64735747d641fc492539978caeb/cryptography-45.0.4-cp311-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:f3fe7a5ae34d5a414957cc7f457e2b92076e72938423ac64d215722f6cf49a9e", size = 4208922, upload-time = "2025-06-10T00:02:45.334Z" }, - { url = "https://files.pythonhosted.org/packages/c6/f3/528729726eb6c3060fa3637253430547fbaaea95ab0535ea41baa4a6fbd8/cryptography-45.0.4-cp311-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:25eb4d4d3e54595dc8adebc6bbd5623588991d86591a78c2548ffb64797341e2", size = 3900433, upload-time = "2025-06-10T00:02:47.359Z" }, - { url = "https://files.pythonhosted.org/packages/d9/4a/67ba2e40f619e04d83c32f7e1d484c1538c0800a17c56a22ff07d092ccc1/cryptography-45.0.4-cp311-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:ce1678a2ccbe696cf3af15a75bb72ee008d7ff183c9228592ede9db467e64f1b", size = 4464163, upload-time = "2025-06-10T00:02:49.412Z" }, - { url = "https://files.pythonhosted.org/packages/7e/9a/b4d5aa83661483ac372464809c4b49b5022dbfe36b12fe9e323ca8512420/cryptography-45.0.4-cp311-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:49fe9155ab32721b9122975e168a6760d8ce4cffe423bcd7ca269ba41b5dfac1", size = 4208687, upload-time = "2025-06-10T00:02:50.976Z" }, - { url = "https://files.pythonhosted.org/packages/db/b7/a84bdcd19d9c02ec5807f2ec2d1456fd8451592c5ee353816c09250e3561/cryptography-45.0.4-cp311-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:2882338b2a6e0bd337052e8b9007ced85c637da19ef9ecaf437744495c8c2999", size = 4463623, upload-time = "2025-06-10T00:02:52.542Z" }, - { url = "https://files.pythonhosted.org/packages/d8/84/69707d502d4d905021cac3fb59a316344e9f078b1da7fb43ecde5e10840a/cryptography-45.0.4-cp311-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:23b9c3ea30c3ed4db59e7b9619272e94891f8a3a5591d0b656a7582631ccf750", size = 4332447, upload-time = "2025-06-10T00:02:54.63Z" }, - { url = "https://files.pythonhosted.org/packages/f3/ee/d4f2ab688e057e90ded24384e34838086a9b09963389a5ba6854b5876598/cryptography-45.0.4-cp311-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:b0a97c927497e3bc36b33987abb99bf17a9a175a19af38a892dc4bbb844d7ee2", size = 4572830, upload-time = "2025-06-10T00:02:56.689Z" }, - { url = "https://files.pythonhosted.org/packages/70/d4/994773a261d7ff98034f72c0e8251fe2755eac45e2265db4c866c1c6829c/cryptography-45.0.4-cp311-abi3-win32.whl", hash = "sha256:e00a6c10a5c53979d6242f123c0a97cff9f3abed7f064fc412c36dc521b5f257", size = 2932769, upload-time = "2025-06-10T00:02:58.467Z" }, - { url = "https://files.pythonhosted.org/packages/5a/42/c80bd0b67e9b769b364963b5252b17778a397cefdd36fa9aa4a5f34c599a/cryptography-45.0.4-cp311-abi3-win_amd64.whl", hash = "sha256:817ee05c6c9f7a69a16200f0c90ab26d23a87701e2a284bd15156783e46dbcc8", size = 3410441, upload-time = "2025-06-10T00:03:00.14Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0b/2488c89f3a30bc821c9d96eeacfcab6ff3accc08a9601ba03339c0fd05e5/cryptography-45.0.4-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:964bcc28d867e0f5491a564b7debb3ffdd8717928d315d12e0d7defa9e43b723", size = 7031836, upload-time = "2025-06-10T00:03:01.726Z" }, - { url = "https://files.pythonhosted.org/packages/fe/51/8c584ed426093aac257462ae62d26ad61ef1cbf5b58d8b67e6e13c39960e/cryptography-45.0.4-cp37-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:6a5bf57554e80f75a7db3d4b1dacaa2764611ae166ab42ea9a72bcdb5d577637", size = 4195746, upload-time = "2025-06-10T00:03:03.94Z" }, - { url = "https://files.pythonhosted.org/packages/5c/7d/4b0ca4d7af95a704eef2f8f80a8199ed236aaf185d55385ae1d1610c03c2/cryptography-45.0.4-cp37-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:46cf7088bf91bdc9b26f9c55636492c1cce3e7aaf8041bbf0243f5e5325cfb2d", size = 4424456, upload-time = "2025-06-10T00:03:05.589Z" }, - { url = "https://files.pythonhosted.org/packages/1d/45/5fabacbc6e76ff056f84d9f60eeac18819badf0cefc1b6612ee03d4ab678/cryptography-45.0.4-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:7bedbe4cc930fa4b100fc845ea1ea5788fcd7ae9562e669989c11618ae8d76ee", size = 4198495, upload-time = "2025-06-10T00:03:09.172Z" }, - { url = "https://files.pythonhosted.org/packages/55/b7/ffc9945b290eb0a5d4dab9b7636706e3b5b92f14ee5d9d4449409d010d54/cryptography-45.0.4-cp37-abi3-manylinux_2_28_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:eaa3e28ea2235b33220b949c5a0d6cf79baa80eab2eb5607ca8ab7525331b9ff", size = 3885540, upload-time = "2025-06-10T00:03:10.835Z" }, - { url = "https://files.pythonhosted.org/packages/7f/e3/57b010282346980475e77d414080acdcb3dab9a0be63071efc2041a2c6bd/cryptography-45.0.4-cp37-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:7ef2dde4fa9408475038fc9aadfc1fb2676b174e68356359632e980c661ec8f6", size = 4452052, upload-time = "2025-06-10T00:03:12.448Z" }, - { url = "https://files.pythonhosted.org/packages/37/e6/ddc4ac2558bf2ef517a358df26f45bc774a99bf4653e7ee34b5e749c03e3/cryptography-45.0.4-cp37-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:6a3511ae33f09094185d111160fd192c67aa0a2a8d19b54d36e4c78f651dc5ad", size = 4198024, upload-time = "2025-06-10T00:03:13.976Z" }, - { url = "https://files.pythonhosted.org/packages/3a/c0/85fa358ddb063ec588aed4a6ea1df57dc3e3bc1712d87c8fa162d02a65fc/cryptography-45.0.4-cp37-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:06509dc70dd71fa56eaa138336244e2fbaf2ac164fc9b5e66828fccfd2b680d6", size = 4451442, upload-time = "2025-06-10T00:03:16.248Z" }, - { url = "https://files.pythonhosted.org/packages/33/67/362d6ec1492596e73da24e669a7fbbaeb1c428d6bf49a29f7a12acffd5dc/cryptography-45.0.4-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:5f31e6b0a5a253f6aa49be67279be4a7e5a4ef259a9f33c69f7d1b1191939872", size = 4325038, upload-time = "2025-06-10T00:03:18.4Z" }, - { url = "https://files.pythonhosted.org/packages/53/75/82a14bf047a96a1b13ebb47fb9811c4f73096cfa2e2b17c86879687f9027/cryptography-45.0.4-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:944e9ccf67a9594137f942d5b52c8d238b1b4e46c7a0c2891b7ae6e01e7c80a4", size = 4560964, upload-time = "2025-06-10T00:03:20.06Z" }, - { url = "https://files.pythonhosted.org/packages/cd/37/1a3cba4c5a468ebf9b95523a5ef5651244693dc712001e276682c278fc00/cryptography-45.0.4-cp37-abi3-win32.whl", hash = "sha256:c22fe01e53dc65edd1945a2e6f0015e887f84ced233acecb64b4daadb32f5c97", size = 2924557, upload-time = "2025-06-10T00:03:22.563Z" }, - { url = "https://files.pythonhosted.org/packages/2a/4b/3256759723b7e66380397d958ca07c59cfc3fb5c794fb5516758afd05d41/cryptography-45.0.4-cp37-abi3-win_amd64.whl", hash = "sha256:627ba1bc94f6adf0b0a2e35d87020285ead22d9f648c7e75bb64f367375f3b22", size = 3395508, upload-time = "2025-06-10T00:03:24.586Z" }, - { url = "https://files.pythonhosted.org/packages/16/33/b38e9d372afde56906a23839302c19abdac1c505bfb4776c1e4b07c3e145/cryptography-45.0.4-pp310-pypy310_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a77c6fb8d76e9c9f99f2f3437c1a4ac287b34eaf40997cfab1e9bd2be175ac39", size = 3580103, upload-time = "2025-06-10T00:03:26.207Z" }, - { url = "https://files.pythonhosted.org/packages/c4/b9/357f18064ec09d4807800d05a48f92f3b369056a12f995ff79549fbb31f1/cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:7aad98a25ed8ac917fdd8a9c1e706e5a0956e06c498be1f713b61734333a4507", size = 4143732, upload-time = "2025-06-10T00:03:27.896Z" }, - { url = "https://files.pythonhosted.org/packages/c4/9c/7f7263b03d5db329093617648b9bd55c953de0b245e64e866e560f9aac07/cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:3530382a43a0e524bc931f187fc69ef4c42828cf7d7f592f7f249f602b5a4ab0", size = 4385424, upload-time = "2025-06-10T00:03:29.992Z" }, - { url = "https://files.pythonhosted.org/packages/a6/5a/6aa9d8d5073d5acc0e04e95b2860ef2684b2bd2899d8795fc443013e263b/cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:6b613164cb8425e2f8db5849ffb84892e523bf6d26deb8f9bb76ae86181fa12b", size = 4142438, upload-time = "2025-06-10T00:03:31.782Z" }, - { url = "https://files.pythonhosted.org/packages/42/1c/71c638420f2cdd96d9c2b287fec515faf48679b33a2b583d0f1eda3a3375/cryptography-45.0.4-pp310-pypy310_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:96d4819e25bf3b685199b304a0029ce4a3caf98947ce8a066c9137cc78ad2c58", size = 4384622, upload-time = "2025-06-10T00:03:33.491Z" }, - { url = "https://files.pythonhosted.org/packages/ef/ab/e3a055c34e97deadbf0d846e189237d3385dca99e1a7e27384c3b2292041/cryptography-45.0.4-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:b97737a3ffbea79eebb062eb0d67d72307195035332501722a9ca86bab9e3ab2", size = 3328911, upload-time = "2025-06-10T00:03:35.035Z" }, - { url = "https://files.pythonhosted.org/packages/ea/ba/cf442ae99ef363855ed84b39e0fb3c106ac66b7a7703f3c9c9cfe05412cb/cryptography-45.0.4-pp311-pypy311_pp73-macosx_10_9_x86_64.whl", hash = "sha256:4828190fb6c4bcb6ebc6331f01fe66ae838bb3bd58e753b59d4b22eb444b996c", size = 3590512, upload-time = "2025-06-10T00:03:36.982Z" }, - { url = "https://files.pythonhosted.org/packages/28/9a/a7d5bb87d149eb99a5abdc69a41e4e47b8001d767e5f403f78bfaafc7aa7/cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_28_aarch64.whl", hash = "sha256:03dbff8411206713185b8cebe31bc5c0eb544799a50c09035733716b386e61a4", size = 4146899, upload-time = "2025-06-10T00:03:38.659Z" }, - { url = "https://files.pythonhosted.org/packages/17/11/9361c2c71c42cc5c465cf294c8030e72fb0c87752bacbd7a3675245e3db3/cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_28_x86_64.whl", hash = "sha256:51dfbd4d26172d31150d84c19bbe06c68ea4b7f11bbc7b3a5e146b367c311349", size = 4388900, upload-time = "2025-06-10T00:03:40.233Z" }, - { url = "https://files.pythonhosted.org/packages/c0/76/f95b83359012ee0e670da3e41c164a0c256aeedd81886f878911581d852f/cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_34_aarch64.whl", hash = "sha256:0339a692de47084969500ee455e42c58e449461e0ec845a34a6a9b9bf7df7fb8", size = 4146422, upload-time = "2025-06-10T00:03:41.827Z" }, - { url = "https://files.pythonhosted.org/packages/09/ad/5429fcc4def93e577a5407988f89cf15305e64920203d4ac14601a9dc876/cryptography-45.0.4-pp311-pypy311_pp73-manylinux_2_34_x86_64.whl", hash = "sha256:0cf13c77d710131d33e63626bd55ae7c0efb701ebdc2b3a7952b9b23a0412862", size = 4388475, upload-time = "2025-06-10T00:03:43.493Z" }, - { url = "https://files.pythonhosted.org/packages/99/49/0ab9774f64555a1b50102757811508f5ace451cf5dc0a2d074a4b9deca6a/cryptography-45.0.4-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:bbc505d1dc469ac12a0a064214879eac6294038d6b24ae9f71faae1448a9608d", size = 3337594, upload-time = "2025-06-10T00:03:45.523Z" }, -] - -[[package]] -name = "cytoolz" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "toolz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/f9/3243eed3a6545c2a33a21f74f655e3fcb5d2192613cd3db81a93369eb339/cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6", size = 626652, upload-time = "2024-12-13T05:47:36.672Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d9/f13d66c16cff1fa1cb6c234698029877c456f35f577ef274aba3b86e7c51/cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042", size = 403515, upload-time = "2024-12-13T05:44:27.845Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2d/4cdf848a69300c7d44984f2ebbebb3b8576e5449c8dea157298f3bdc4da3/cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608", size = 383936, upload-time = "2024-12-13T05:44:29.5Z" }, - { url = "https://files.pythonhosted.org/packages/72/a4/ccfdd3f0ed9cc818f734b424261f6018fc61e3ec833bf85225a9aca0d994/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90124bdc42ff58b88cdea1d24a6bc5f776414a314cc4d94f25c88badb3a16d1", size = 1934569, upload-time = "2024-12-13T05:44:30.799Z" }, - { url = "https://files.pythonhosted.org/packages/50/fc/38d5344fa595683ad10dc819cfc1d8b9d2b3391ccf3e8cb7bab4899a01f5/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e74801b751e28f7c5cc3ad264c123954a051f546f2fdfe089f5aa7a12ccfa6da", size = 2015129, upload-time = "2024-12-13T05:44:32.297Z" }, - { url = "https://files.pythonhosted.org/packages/28/29/75261748dc54a20a927f33641f4e9aac674cfc6d3fbd4f332e10d0b37639/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582dad4545ddfb5127494ef23f3fa4855f1673a35d50c66f7638e9fb49805089", size = 2000506, upload-time = "2024-12-13T05:44:34.403Z" }, - { url = "https://files.pythonhosted.org/packages/00/ae/e4ead004cc2698281d153c4a5388638d67cdb5544d6d6cc1e5b3db2bd2a3/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7bd0618e16efe03bd12f19c2a26a27e6e6b75d7105adb7be1cd2a53fa755d8", size = 1957537, upload-time = "2024-12-13T05:44:39.499Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ff/4f3aa07f4f47701f7f63df60ce0a5669fa09c256c3d4a33503a9414ea5cc/cytoolz-1.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d74cca6acf1c4af58b2e4a89cc565ed61c5e201de2e434748c93e5a0f5c541a5", size = 1863331, upload-time = "2024-12-13T05:44:42.61Z" }, - { url = "https://files.pythonhosted.org/packages/a2/29/654f57f2a9b8e9765a4ab876765f64f94530b61fc6471a07feea42ece6d4/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:823a3763828d8d457f542b2a45d75d6b4ced5e470b5c7cf2ed66a02f508ed442", size = 1849938, upload-time = "2024-12-13T05:44:45.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/7b/11f457db6b291060a98315ab2c7198077d8bddeeebe5f7126d9dad98cc54/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:51633a14e6844c61db1d68c1ffd077cf949f5c99c60ed5f1e265b9e2966f1b52", size = 1852345, upload-time = "2024-12-13T05:44:47.994Z" }, - { url = "https://files.pythonhosted.org/packages/6b/92/0dccc96ce0323be236d404f5084479b79b747fa0e74e43a270e95868b5f9/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3ec9b01c45348f1d0d712507d54c2bfd69c62fbd7c9ef555c9d8298693c2432", size = 1989877, upload-time = "2024-12-13T05:44:51.514Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c8/1c5203a81200bae51aa8f7b5fad613f695bf1afa03f16251ca23ecb2ef9f/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1855022b712a9c7a5bce354517ab4727a38095f81e2d23d3eabaf1daeb6a3b3c", size = 1994492, upload-time = "2024-12-13T05:44:52.922Z" }, - { url = "https://files.pythonhosted.org/packages/e2/8a/04bc193c4d7ced8ef6bb62cdcd0bf40b5e5eb26586ed2cfb4433ec7dfd0a/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9930f7288c4866a1dc1cc87174f0c6ff4cad1671eb1f6306808aa6c445857d78", size = 1896077, upload-time = "2024-12-13T05:44:56.118Z" }, - { url = "https://files.pythonhosted.org/packages/21/a5/bee63a58f51d2c74856db66e6119a014464ff8cb1c9387fa4bd2d94e49b0/cytoolz-1.0.1-cp310-cp310-win32.whl", hash = "sha256:a9baad795d72fadc3445ccd0f122abfdbdf94269157e6d6d4835636dad318804", size = 322135, upload-time = "2024-12-13T05:44:57.695Z" }, - { url = "https://files.pythonhosted.org/packages/e8/16/7abfb1685e8b7f2838264551ee33651748994813f566ac4c3d737dfe90e5/cytoolz-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad95b386a84e18e1f6136f6d343d2509d4c3aae9f5a536f3dc96808fcc56a8cf", size = 363599, upload-time = "2024-12-13T05:44:58.875Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ea/8131ae39119820b8867cddc23716fa9f681f2b3bbce6f693e68dfb36b55b/cytoolz-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d958d4f04d9d7018e5c1850790d9d8e68b31c9a2deebca74b903706fdddd2b6", size = 406162, upload-time = "2024-12-13T05:45:01.196Z" }, - { url = "https://files.pythonhosted.org/packages/26/18/3d9bd4c146f6ea6e51300c242b20cb416966b21d481dac230e1304f1e54b/cytoolz-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0f445b8b731fc0ecb1865b8e68a070084eb95d735d04f5b6c851db2daf3048ab", size = 384961, upload-time = "2024-12-13T05:45:02.387Z" }, - { url = "https://files.pythonhosted.org/packages/e4/73/9034827907c7f85c7c484c9494e905d022fb8174526004e9ef332570349e/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f546a96460a7e28eb2ec439f4664fa646c9b3e51c6ebad9a59d3922bbe65e30", size = 2091698, upload-time = "2024-12-13T05:45:04.353Z" }, - { url = "https://files.pythonhosted.org/packages/74/af/d5c2733b0fde1a08254ff1a8a8d567874040c9eb1606363cfebc0713c73f/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0317681dd065532d21836f860b0563b199ee716f55d0c1f10de3ce7100c78a3b", size = 2188452, upload-time = "2024-12-13T05:45:05.748Z" }, - { url = "https://files.pythonhosted.org/packages/6a/bb/77c71fa9c217260b4056a732d754748903423c2cdd82a673d6064741e375/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0ef52febd5a7821a3fd8d10f21d460d1a3d2992f724ba9c91fbd7a96745d41", size = 2174203, upload-time = "2024-12-13T05:45:07.777Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a9/a5b4a3ff5d22faa1b60293bfe97362e2caf4a830c26d37ab5557f60d04b2/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebaf419acf2de73b643cf96108702b8aef8e825cf4f63209ceb078d5fbbbfd", size = 2099831, upload-time = "2024-12-13T05:45:11.477Z" }, - { url = "https://files.pythonhosted.org/packages/35/08/7f6869ea1ff31ce5289a7d58d0e7090acfe7058baa2764473048ff61ea3c/cytoolz-1.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f7f04eeb4088947585c92d6185a618b25ad4a0f8f66ea30c8db83cf94a425e3", size = 1996744, upload-time = "2024-12-13T05:45:14.172Z" }, - { url = "https://files.pythonhosted.org/packages/46/b4/9ac424c994b51763fd1bbed62d95f8fba8fa0e45c8c3c583904fdaf8f51d/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f61928803bb501c17914b82d457c6f50fe838b173fb40d39c38d5961185bd6c7", size = 2013733, upload-time = "2024-12-13T05:45:16.912Z" }, - { url = "https://files.pythonhosted.org/packages/3e/99/03009765c4b87d742d5b5a8670abb56a8c7ede033c2cdaa4be8662d3b001/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d2960cb4fa01ccb985ad1280db41f90dc97a80b397af970a15d5a5de403c8c61", size = 1994850, upload-time = "2024-12-13T05:45:18.414Z" }, - { url = "https://files.pythonhosted.org/packages/40/9a/8458af9a5557e177ea42f8cf7e477bede518b0bbef564e28c4151feaa52c/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2b407cc3e9defa8df5eb46644f6f136586f70ba49eba96f43de67b9a0984fd3", size = 2155352, upload-time = "2024-12-13T05:45:19.763Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5c/2a701423e001fcbec288b4f3fc2bf67557d114c2388237fc1ae67e1e2686/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8245f929144d4d3bd7b972c9593300195c6cea246b81b4c46053c48b3f044580", size = 2163515, upload-time = "2024-12-13T05:45:21.08Z" }, - { url = "https://files.pythonhosted.org/packages/36/16/ee2e06e65d9d533bc05cd52a0b355ba9072fc8f60d77289e529c6d2e3750/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37385db03af65763933befe89fa70faf25301effc3b0485fec1c15d4ce4f052", size = 2054431, upload-time = "2024-12-13T05:45:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d5/2fac8315f210fa1bc7106e27c19e1211580aa25bb7fa17dfd79505e5baf2/cytoolz-1.0.1-cp311-cp311-win32.whl", hash = "sha256:50f9c530f83e3e574fc95c264c3350adde8145f4f8fc8099f65f00cc595e5ead", size = 322004, upload-time = "2024-12-13T05:45:24.048Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9e/0b70b641850a95f9ff90adde9d094a4b1d81ec54dadfd97fec0a2aaf440e/cytoolz-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b7f6b617454b4326af7bd3c7c49b0fc80767f134eb9fd6449917a058d17a0e3c", size = 365358, upload-time = "2024-12-13T05:45:25.383Z" }, - { url = "https://files.pythonhosted.org/packages/d8/e8/218098344ed2cb5f8441fade9b2428e435e7073962374a9c71e59ac141a7/cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4", size = 414121, upload-time = "2024-12-13T05:45:26.588Z" }, - { url = "https://files.pythonhosted.org/packages/de/27/4d729a5653718109262b758fec1a959aa9facb74c15460d9074dc76d6635/cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662", size = 390904, upload-time = "2024-12-13T05:45:27.718Z" }, - { url = "https://files.pythonhosted.org/packages/72/c0/cbabfa788bab9c6038953bf9478adaec06e88903a726946ea7c88092f5c4/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3", size = 2090734, upload-time = "2024-12-13T05:45:30.515Z" }, - { url = "https://files.pythonhosted.org/packages/c3/66/369262c60f9423c2da82a60864a259c852f1aa122aced4acd2c679af58c0/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1", size = 2155933, upload-time = "2024-12-13T05:45:32.721Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4e/ee55186802f8d24b5fbf9a11405ccd1203b30eded07cc17750618219b94e/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8", size = 2171903, upload-time = "2024-12-13T05:45:34.205Z" }, - { url = "https://files.pythonhosted.org/packages/a1/96/bd1a9f3396e9b7f618db8cd08d15630769ce3c8b7d0534f92cd639c977ae/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d", size = 2125270, upload-time = "2024-12-13T05:45:36.982Z" }, - { url = "https://files.pythonhosted.org/packages/28/48/2a3762873091c88a69e161111cfbc6c222ff145d57ff011a642b169f04f1/cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f", size = 1973967, upload-time = "2024-12-13T05:45:39.505Z" }, - { url = "https://files.pythonhosted.org/packages/e4/50/500bd69774bdc49a4d78ec8779eb6ac7c1a9d706bfd91cf2a1dba604373a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7", size = 2021695, upload-time = "2024-12-13T05:45:40.911Z" }, - { url = "https://files.pythonhosted.org/packages/e4/4e/ba5a0ce34869495eb50653de8d676847490cf13a2cac1760fc4d313e78de/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126", size = 2010177, upload-time = "2024-12-13T05:45:42.48Z" }, - { url = "https://files.pythonhosted.org/packages/87/57/615c630b3089a13adb15351d958d227430cf624f03b1dd39eb52c34c1f59/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0", size = 2154321, upload-time = "2024-12-13T05:45:43.979Z" }, - { url = "https://files.pythonhosted.org/packages/7f/0f/fe1aa2d931e3b35ecc05215bd75da945ea7346095b3b6f6027164e602d5a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b", size = 2188374, upload-time = "2024-12-13T05:45:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/de/fa/fd363d97a641b6d0e2fd1d5c35b8fd41d9ccaeb4df56302f53bf23a58e3a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d", size = 2077911, upload-time = "2024-12-13T05:45:48.219Z" }, - { url = "https://files.pythonhosted.org/packages/d9/68/0a22946b98ae5201b54ccb4e651295285c0fb79406022b6ee8b2f791940c/cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9", size = 321903, upload-time = "2024-12-13T05:45:50.3Z" }, - { url = "https://files.pythonhosted.org/packages/62/1a/f3903197956055032f8cb297342e2dff07e50f83991aebfe5b4c4fcb55e4/cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b", size = 364490, upload-time = "2024-12-13T05:45:51.494Z" }, - { url = "https://files.pythonhosted.org/packages/aa/2e/a9f069db0107749e9e72baf6c21abe3f006841a3bcfdc9b8420e22ef31eb/cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0", size = 407365, upload-time = "2024-12-13T05:45:52.803Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9b/5e87dd0e31f54c778b4f9f34cc14c1162d3096c8d746b0f8be97d70dd73c/cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a", size = 385233, upload-time = "2024-12-13T05:45:53.994Z" }, - { url = "https://files.pythonhosted.org/packages/63/00/2fd32b16284cdb97cfe092822179bc0c3bcdd5e927dd39f986169a517642/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242", size = 2062903, upload-time = "2024-12-13T05:45:55.202Z" }, - { url = "https://files.pythonhosted.org/packages/85/39/b3cbb5a9847ba59584a263772ad4f8ca2dbfd2a0e11efd09211d1219804c/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296", size = 2139517, upload-time = "2024-12-13T05:45:56.804Z" }, - { url = "https://files.pythonhosted.org/packages/ea/39/bfcab4a46d50c467e36fe704f19d8904efead417787806ee210327f68390/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b", size = 2154849, upload-time = "2024-12-13T05:45:58.814Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/3bc6ee61b0aa47e1cb40819adc1a456d7efa809f0dea9faddacb43fdde8f/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b", size = 2102302, upload-time = "2024-12-13T05:46:00.181Z" }, - { url = "https://files.pythonhosted.org/packages/00/66/3f636c6ddea7b18026b90a8c238af472e423b86e427b11df02213689b012/cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266", size = 1960872, upload-time = "2024-12-13T05:46:01.612Z" }, - { url = "https://files.pythonhosted.org/packages/40/36/cb3b7cdd651007b69f9c48e9d104cec7cb8dc53afa1d6a720e5ad08022fa/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5", size = 2014430, upload-time = "2024-12-13T05:46:03.022Z" }, - { url = "https://files.pythonhosted.org/packages/88/3f/2e9bd2a16cfd269808922147551dcb2d8b68ba54a2c4deca2fa6a6cd0d5f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3", size = 2003127, upload-time = "2024-12-13T05:46:04.401Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7d/08604ff940aa784df8343c387fdf2489b948b714a6afb587775ae94da912/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296", size = 2142369, upload-time = "2024-12-13T05:46:06.004Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c6/39919a0645bdbdf720e97cae107f959ea9d1267fbc3b0d94fc6e1d12ac8f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140", size = 2180427, upload-time = "2024-12-13T05:46:07.526Z" }, - { url = "https://files.pythonhosted.org/packages/d8/03/dbb9d47556ee54337e7e0ac209d17ceff2d2a197c34de08005abc7a7449b/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581", size = 2069785, upload-time = "2024-12-13T05:46:10.122Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f8/11bb7b8947002231faae3ec2342df5896afbc19eb783a332cce6d219ff79/cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9", size = 320685, upload-time = "2024-12-13T05:46:11.553Z" }, - { url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297", size = 362898, upload-time = "2024-12-13T05:46:12.771Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f7/ef2a10daaec5c0f7d781d50758c6187eee484256e356ae8ef178d6c48497/cytoolz-1.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:83d19d55738ad9c60763b94f3f6d3c6e4de979aeb8d76841c1401081e0e58d96", size = 345702, upload-time = "2024-12-13T05:47:09.266Z" }, - { url = "https://files.pythonhosted.org/packages/c8/14/53c84adddedb67ff1546abb86fea04d26e24298c3ceab8436d20122ed0b9/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f112a71fad6ea824578e6393765ce5c054603afe1471a5c753ff6c67fd872d10", size = 385695, upload-time = "2024-12-13T05:47:11.011Z" }, - { url = "https://files.pythonhosted.org/packages/bd/80/3ae356c5e7b8d7dc7d1adb52f6932fee85cd748ed4e1217c269d2dfd610f/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a515df8f8aa6e1eaaf397761a6e4aff2eef73b5f920aedf271416d5471ae5ee", size = 406261, upload-time = "2024-12-13T05:47:12.24Z" }, - { url = "https://files.pythonhosted.org/packages/0c/31/8e43761ffc82d90bf9cab7e0959712eedcd1e33c211397e143dd42d7af57/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c398e7b7023460bea2edffe5fcd0a76029580f06c3f6938ac3d198b47156f3", size = 397207, upload-time = "2024-12-13T05:47:13.561Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b9/fe9da37090b6444c65f848a83e390f87d8cb43d6a4df46de1556ad7e5ceb/cytoolz-1.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3237e56211e03b13df47435b2369f5df281e02b04ad80a948ebd199b7bc10a47", size = 343358, upload-time = "2024-12-13T05:47:16.291Z" }, -] - -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - -[[package]] -name = "email-validator" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, -] - -[[package]] -name = "eth-abi" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "parsimonious" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/71/d9e1380bd77fd22f98b534699af564f189b56d539cc2b9dab908d4e4c242/eth_abi-5.2.0.tar.gz", hash = "sha256:178703fa98c07d8eecd5ae569e7e8d159e493ebb6eeb534a8fe973fbc4e40ef0", size = 49797, upload-time = "2025-01-14T16:29:34.629Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/b4/2f3982c4cbcbf5eeb6aec62df1533c0e63c653b3021ff338d44944405676/eth_abi-5.2.0-py3-none-any.whl", hash = "sha256:17abe47560ad753f18054f5b3089fcb588f3e3a092136a416b6c1502cb7e8877", size = 28511, upload-time = "2025-01-14T16:29:31.862Z" }, -] - -[[package]] -name = "eth-account" -version = "0.13.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bitarray" }, - { name = "ckzg" }, - { name = "eth-abi" }, - { name = "eth-keyfile" }, - { name = "eth-keys" }, - { name = "eth-rlp" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "rlp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/cf/20f76a29be97339c969fd765f1237154286a565a1d61be98e76bb7af946a/eth_account-0.13.7.tar.gz", hash = "sha256:5853ecbcbb22e65411176f121f5f24b8afeeaf13492359d254b16d8b18c77a46", size = 935998, upload-time = "2025-04-21T21:11:21.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/18/088fb250018cbe665bc2111974301b2d59f294a565aff7564c4df6878da2/eth_account-0.13.7-py3-none-any.whl", hash = "sha256:39727de8c94d004ff61d10da7587509c04d2dc7eac71e04830135300bdfc6d24", size = 587452, upload-time = "2025-04-21T21:11:18.346Z" }, -] - -[[package]] -name = "eth-hash" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/38/577b7bc9380ef9dff0f1dffefe0c9a1ded2385e7a06c306fd95afb6f9451/eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5", size = 12227, upload-time = "2025-01-13T21:29:21.765Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/db/f8775490669d28aca24871c67dd56b3e72105cb3bcae9a4ec65dd70859b3/eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a", size = 8028, upload-time = "2025-01-13T21:29:19.365Z" }, -] - -[package.optional-dependencies] -pycryptodome = [ - { name = "pycryptodome" }, -] - -[[package]] -name = "eth-keyfile" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-keys" }, - { name = "eth-utils" }, - { name = "pycryptodome" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/66/dd823b1537befefbbff602e2ada88f1477c5b40ec3731e3d9bc676c5f716/eth_keyfile-0.8.1.tar.gz", hash = "sha256:9708bc31f386b52cca0969238ff35b1ac72bd7a7186f2a84b86110d3c973bec1", size = 12267, upload-time = "2024-04-23T20:28:53.862Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/fc/48a586175f847dd9e05e5b8994d2fe8336098781ec2e9836a2ad94280281/eth_keyfile-0.8.1-py3-none-any.whl", hash = "sha256:65387378b82fe7e86d7cb9f8d98e6d639142661b2f6f490629da09fddbef6d64", size = 7510, upload-time = "2024-04-23T20:28:51.063Z" }, -] - -[[package]] -name = "eth-keys" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/11/1ed831c50bd74f57829aa06e58bd82a809c37e070ee501c953b9ac1f1552/eth_keys-0.7.0.tar.gz", hash = "sha256:79d24fd876201df67741de3e3fefb3f4dbcbb6ace66e47e6fe662851a4547814", size = 30166, upload-time = "2025-04-07T17:40:21.697Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/25/0ae00f2b0095e559d61ad3dc32171bd5a29dfd95ab04b4edd641f7c75f72/eth_keys-0.7.0-py3-none-any.whl", hash = "sha256:b0cdda8ffe8e5ba69c7c5ca33f153828edcace844f67aabd4542d7de38b159cf", size = 20656, upload-time = "2025-04-07T17:40:20.441Z" }, -] - -[[package]] -name = "eth-rlp" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "rlp" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7f/ea/ad39d001fa9fed07fad66edb00af701e29b48be0ed44a3bcf58cb3adf130/eth_rlp-2.2.0.tar.gz", hash = "sha256:5e4b2eb1b8213e303d6a232dfe35ab8c29e2d3051b86e8d359def80cd21db83d", size = 7720, upload-time = "2025-02-04T21:51:08.134Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/3b/57efe2bc2df0980680d57c01a36516cd3171d2319ceb30e675de19fc2cc5/eth_rlp-2.2.0-py3-none-any.whl", hash = "sha256:5692d595a741fbaef1203db6a2fedffbd2506d31455a6ad378c8449ee5985c47", size = 4446, upload-time = "2025-02-04T21:51:05.823Z" }, -] - -[[package]] -name = "eth-typing" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/54/62aa24b9cc708f06316167ee71c362779c8ed21fc8234a5cd94a8f53b623/eth_typing-5.2.1.tar.gz", hash = "sha256:7557300dbf02a93c70fa44af352b5c4a58f94e997a0fd6797fb7d1c29d9538ee", size = 21806, upload-time = "2025-04-14T20:39:28.217Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/72/c370bbe4c53da7bf998d3523f5a0f38867654923a82192df88d0705013d3/eth_typing-5.2.1-py3-none-any.whl", hash = "sha256:b0c2812ff978267563b80e9d701f487dd926f1d376d674f3b535cfe28b665d3d", size = 19163, upload-time = "2025-04-14T20:39:26.571Z" }, -] - -[[package]] -name = "eth-utils" -version = "5.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cytoolz", marker = "implementation_name == 'cpython'" }, - { name = "eth-hash" }, - { name = "eth-typing" }, - { name = "pydantic" }, - { name = "toolz", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0d/49/bee95f16d2ef068097afeeffbd6c67738107001ee57ad7bcdd4fc4d3c6a7/eth_utils-5.3.0.tar.gz", hash = "sha256:1f096867ac6be895f456fa3acb26e9573ae66e753abad9208f316d24d6178156", size = 123753, upload-time = "2025-04-14T19:35:56.431Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/c6/0417a92e6a3fc9b85f5a8380d9f9d43b69ba836a90e45f79f9ae74d41e53/eth_utils-5.3.0-py3-none-any.whl", hash = "sha256:ac184883ab299d923428bbe25dae5e356979a3993e0ef695a864db0a20bc262d", size = 102531, upload-time = "2025-04-14T19:35:55.176Z" }, -] - -[[package]] -name = "exceptiongroup" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, -] - -[[package]] -name = "fastapi" -version = "0.115.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236, upload-time = "2025-03-23T22:55:43.822Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164, upload-time = "2025-03-23T22:55:42.101Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, - { name = "httpx" }, - { name = "jinja2" }, - { name = "python-multipart" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cli" -version = "0.0.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "rich-toolkit" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/73/82a5831fbbf8ed75905bacf5b2d9d3dfd6f04d6968b29fe6f72a5ae9ceb1/fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e", size = 16753, upload-time = "2024-12-15T14:28:10.028Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705, upload-time = "2024-12-15T14:28:06.18Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "flask" -version = "3.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "blinker" }, - { name = "click" }, - { name = "itsdangerous" }, - { name = "jinja2" }, - { name = "markupsafe" }, - { name = "werkzeug" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/de/e47735752347f4128bcf354e0da07ef311a78244eba9e3dc1d4a5ab21a98/flask-3.1.1.tar.gz", hash = "sha256:284c7b8f2f58cb737f0cf1c30fd7eaf0ccfcde196099d24ecede3fc2005aa59e", size = 753440, upload-time = "2025-05-13T15:01:17.447Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl", hash = "sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c", size = 103305, upload-time = "2025-05-13T15:01:15.591Z" }, -] - -[[package]] -name = "frozenlist" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, - { url = "https://files.pythonhosted.org/packages/77/f0/77c11d13d39513b298e267b22eb6cb559c103d56f155aa9a49097221f0b6/frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61", size = 47735, upload-time = "2025-06-09T22:59:48.133Z" }, - { url = "https://files.pythonhosted.org/packages/37/12/9d07fa18971a44150593de56b2f2947c46604819976784bcf6ea0d5db43b/frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d", size = 46775, upload-time = "2025-06-09T22:59:49.564Z" }, - { url = "https://files.pythonhosted.org/packages/70/34/f73539227e06288fcd1f8a76853e755b2b48bca6747e99e283111c18bcd4/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e", size = 224644, upload-time = "2025-06-09T22:59:51.35Z" }, - { url = "https://files.pythonhosted.org/packages/fb/68/c1d9c2f4a6e438e14613bad0f2973567586610cc22dcb1e1241da71de9d3/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9", size = 222125, upload-time = "2025-06-09T22:59:52.884Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d0/98e8f9a515228d708344d7c6986752be3e3192d1795f748c24bcf154ad99/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c", size = 233455, upload-time = "2025-06-09T22:59:54.74Z" }, - { url = "https://files.pythonhosted.org/packages/79/df/8a11bcec5600557f40338407d3e5bea80376ed1c01a6c0910fcfdc4b8993/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981", size = 227339, upload-time = "2025-06-09T22:59:56.187Z" }, - { url = "https://files.pythonhosted.org/packages/50/82/41cb97d9c9a5ff94438c63cc343eb7980dac4187eb625a51bdfdb7707314/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615", size = 212969, upload-time = "2025-06-09T22:59:57.604Z" }, - { url = "https://files.pythonhosted.org/packages/13/47/f9179ee5ee4f55629e4f28c660b3fdf2775c8bfde8f9c53f2de2d93f52a9/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50", size = 222862, upload-time = "2025-06-09T22:59:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/df81e41ec6b953902c8b7e3a83bee48b195cb0e5ec2eabae5d8330c78038/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa", size = 222492, upload-time = "2025-06-09T23:00:01.026Z" }, - { url = "https://files.pythonhosted.org/packages/84/17/30d6ea87fa95a9408245a948604b82c1a4b8b3e153cea596421a2aef2754/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577", size = 238250, upload-time = "2025-06-09T23:00:03.401Z" }, - { url = "https://files.pythonhosted.org/packages/8f/00/ecbeb51669e3c3df76cf2ddd66ae3e48345ec213a55e3887d216eb4fbab3/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59", size = 218720, upload-time = "2025-06-09T23:00:05.282Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c0/c224ce0e0eb31cc57f67742071bb470ba8246623c1823a7530be0e76164c/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e", size = 232585, upload-time = "2025-06-09T23:00:07.962Z" }, - { url = "https://files.pythonhosted.org/packages/55/3c/34cb694abf532f31f365106deebdeac9e45c19304d83cf7d51ebbb4ca4d1/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd", size = 234248, upload-time = "2025-06-09T23:00:09.428Z" }, - { url = "https://files.pythonhosted.org/packages/98/c0/2052d8b6cecda2e70bd81299e3512fa332abb6dcd2969b9c80dfcdddbf75/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718", size = 221621, upload-time = "2025-06-09T23:00:11.32Z" }, - { url = "https://files.pythonhosted.org/packages/c5/bf/7dcebae315436903b1d98ffb791a09d674c88480c158aa171958a3ac07f0/frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e", size = 39578, upload-time = "2025-06-09T23:00:13.526Z" }, - { url = "https://files.pythonhosted.org/packages/8f/5f/f69818f017fa9a3d24d1ae39763e29b7f60a59e46d5f91b9c6b21622f4cd/frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464", size = 43830, upload-time = "2025-06-09T23:00:14.98Z" }, - { url = "https://files.pythonhosted.org/packages/34/7e/803dde33760128acd393a27eb002f2020ddb8d99d30a44bfbaab31c5f08a/frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a", size = 82251, upload-time = "2025-06-09T23:00:16.279Z" }, - { url = "https://files.pythonhosted.org/packages/75/a9/9c2c5760b6ba45eae11334db454c189d43d34a4c0b489feb2175e5e64277/frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750", size = 48183, upload-time = "2025-06-09T23:00:17.698Z" }, - { url = "https://files.pythonhosted.org/packages/47/be/4038e2d869f8a2da165f35a6befb9158c259819be22eeaf9c9a8f6a87771/frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd", size = 47107, upload-time = "2025-06-09T23:00:18.952Z" }, - { url = "https://files.pythonhosted.org/packages/79/26/85314b8a83187c76a37183ceed886381a5f992975786f883472fcb6dc5f2/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2", size = 237333, upload-time = "2025-06-09T23:00:20.275Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fd/e5b64f7d2c92a41639ffb2ad44a6a82f347787abc0c7df5f49057cf11770/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f", size = 231724, upload-time = "2025-06-09T23:00:21.705Z" }, - { url = "https://files.pythonhosted.org/packages/20/fb/03395c0a43a5976af4bf7534759d214405fbbb4c114683f434dfdd3128ef/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30", size = 245842, upload-time = "2025-06-09T23:00:23.148Z" }, - { url = "https://files.pythonhosted.org/packages/d0/15/c01c8e1dffdac5d9803507d824f27aed2ba76b6ed0026fab4d9866e82f1f/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98", size = 239767, upload-time = "2025-06-09T23:00:25.103Z" }, - { url = "https://files.pythonhosted.org/packages/14/99/3f4c6fe882c1f5514b6848aa0a69b20cb5e5d8e8f51a339d48c0e9305ed0/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86", size = 224130, upload-time = "2025-06-09T23:00:27.061Z" }, - { url = "https://files.pythonhosted.org/packages/4d/83/220a374bd7b2aeba9d0725130665afe11de347d95c3620b9b82cc2fcab97/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae", size = 235301, upload-time = "2025-06-09T23:00:29.02Z" }, - { url = "https://files.pythonhosted.org/packages/03/3c/3e3390d75334a063181625343e8daab61b77e1b8214802cc4e8a1bb678fc/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8", size = 234606, upload-time = "2025-06-09T23:00:30.514Z" }, - { url = "https://files.pythonhosted.org/packages/23/1e/58232c19608b7a549d72d9903005e2d82488f12554a32de2d5fb59b9b1ba/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31", size = 248372, upload-time = "2025-06-09T23:00:31.966Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a4/e4a567e01702a88a74ce8a324691e62a629bf47d4f8607f24bf1c7216e7f/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7", size = 229860, upload-time = "2025-06-09T23:00:33.375Z" }, - { url = "https://files.pythonhosted.org/packages/73/a6/63b3374f7d22268b41a9db73d68a8233afa30ed164c46107b33c4d18ecdd/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5", size = 245893, upload-time = "2025-06-09T23:00:35.002Z" }, - { url = "https://files.pythonhosted.org/packages/6d/eb/d18b3f6e64799a79673c4ba0b45e4cfbe49c240edfd03a68be20002eaeaa/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898", size = 246323, upload-time = "2025-06-09T23:00:36.468Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f5/720f3812e3d06cd89a1d5db9ff6450088b8f5c449dae8ffb2971a44da506/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56", size = 233149, upload-time = "2025-06-09T23:00:37.963Z" }, - { url = "https://files.pythonhosted.org/packages/69/68/03efbf545e217d5db8446acfd4c447c15b7c8cf4dbd4a58403111df9322d/frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7", size = 39565, upload-time = "2025-06-09T23:00:39.753Z" }, - { url = "https://files.pythonhosted.org/packages/58/17/fe61124c5c333ae87f09bb67186d65038834a47d974fc10a5fadb4cc5ae1/frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d", size = 44019, upload-time = "2025-06-09T23:00:40.988Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, - { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, - { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, - { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, - { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, - { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, - { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, - { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, - { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, - { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" }, - { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" }, - { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" }, - { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" }, - { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" }, - { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" }, - { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" }, - { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" }, - { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" }, - { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" }, - { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" }, - { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" }, - { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" }, - { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" }, - { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" }, - { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" }, - { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" }, - { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" }, - { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" }, - { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" }, - { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" }, - { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" }, - { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" }, - { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" }, - { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" }, - { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" }, - { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" }, - { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" }, - { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" }, - { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" }, - { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" }, - { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "hexbytes" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/87/adf4635b4b8c050283d74e6db9a81496063229c9263e6acc1903ab79fbec/hexbytes-1.3.1.tar.gz", hash = "sha256:a657eebebdfe27254336f98d8af6e2236f3f83aed164b87466b6cf6c5f5a4765", size = 8633, upload-time = "2025-05-14T16:45:17.5Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/e0/3b31492b1c89da3c5a846680517871455b30c54738486fc57ac79a5761bd/hexbytes-1.3.1-py3-none-any.whl", hash = "sha256:da01ff24a1a9a2b1881c4b85f0e9f9b0f51b526b379ffa23832ae7899d29c2c7", size = 5074, upload-time = "2025-05-14T16:45:16.179Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httptools" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/17c672b4bc5c7ba7f201eada4e96c71d0a59fbc185e60e42580093a86f21/httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da", size = 103297, upload-time = "2024-10-16T19:44:08.129Z" }, - { url = "https://files.pythonhosted.org/packages/92/5e/b4a826fe91971a0b68e8c2bd4e7db3e7519882f5a8ccdb1194be2b3ab98f/httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1", size = 443130, upload-time = "2024-10-16T19:44:09.45Z" }, - { url = "https://files.pythonhosted.org/packages/b0/51/ce61e531e40289a681a463e1258fa1e05e0be54540e40d91d065a264cd8f/httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50", size = 442148, upload-time = "2024-10-16T19:44:11.539Z" }, - { url = "https://files.pythonhosted.org/packages/ea/9e/270b7d767849b0c96f275c695d27ca76c30671f8eb8cc1bab6ced5c5e1d0/httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959", size = 415949, upload-time = "2024-10-16T19:44:13.388Z" }, - { url = "https://files.pythonhosted.org/packages/81/86/ced96e3179c48c6f656354e106934e65c8963d48b69be78f355797f0e1b3/httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4", size = 417591, upload-time = "2024-10-16T19:44:15.258Z" }, - { url = "https://files.pythonhosted.org/packages/75/73/187a3f620ed3175364ddb56847d7a608a6fc42d551e133197098c0143eca/httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c", size = 88344, upload-time = "2024-10-16T19:44:16.54Z" }, - { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029, upload-time = "2024-10-16T19:44:18.427Z" }, - { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492, upload-time = "2024-10-16T19:44:19.515Z" }, - { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891, upload-time = "2024-10-16T19:44:21.067Z" }, - { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788, upload-time = "2024-10-16T19:44:22.958Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214, upload-time = "2024-10-16T19:44:24.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120, upload-time = "2024-10-16T19:44:26.295Z" }, - { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565, upload-time = "2024-10-16T19:44:29.188Z" }, - { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683, upload-time = "2024-10-16T19:44:30.175Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337, upload-time = "2024-10-16T19:44:31.786Z" }, - { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796, upload-time = "2024-10-16T19:44:32.825Z" }, - { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837, upload-time = "2024-10-16T19:44:33.974Z" }, - { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289, upload-time = "2024-10-16T19:44:35.111Z" }, - { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779, upload-time = "2024-10-16T19:44:36.253Z" }, - { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634, upload-time = "2024-10-16T19:44:37.357Z" }, - { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" }, - { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" }, - { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" }, - { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" }, - { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" }, - { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "itsdangerous" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "jsonalias" -version = "0.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ec/45/ee7e17002cb7f3264f755ff6a1a72c55d1830e07808d643167d2a2277c4f/jsonalias-0.1.1.tar.gz", hash = "sha256:64f04d935397d579fc94509e1fcb6212f2d081235d9d6395bd10baedf760a769", size = 1095, upload-time = "2022-10-28T22:57:56.224Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/41/ed/05aebce69f78c104feff2ffcdd5a6f9d668a208aba3a8bf56e3750809fd8/jsonalias-0.1.1-py3-none-any.whl", hash = "sha256:a56d2888e6397812c606156504e861e8ec00e188005af149f003c787db3d3f18", size = 1312, upload-time = "2022-10-28T22:57:54.763Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "multidict" -version = "6.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/2f/a3470242707058fe856fe59241eee5635d79087100b7042a867368863a27/multidict-6.4.4.tar.gz", hash = "sha256:69ee9e6ba214b5245031b76233dd95408a0fd57fdb019ddcc1ead4790932a8e8", size = 90183, upload-time = "2025-05-19T14:16:37.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/92/0926a5baafa164b5d0ade3cd7932be39310375d7e25c9d7ceca05cb26a45/multidict-6.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8adee3ac041145ffe4488ea73fa0a622b464cc25340d98be76924d0cda8545ff", size = 66052, upload-time = "2025-05-19T14:13:49.944Z" }, - { url = "https://files.pythonhosted.org/packages/b2/54/8a857ae4f8f643ec444d91f419fdd49cc7a90a2ca0e42d86482b604b63bd/multidict-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b61e98c3e2a861035aaccd207da585bdcacef65fe01d7a0d07478efac005e028", size = 38867, upload-time = "2025-05-19T14:13:51.92Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5f/63add9069f945c19bc8b217ea6b0f8a1ad9382eab374bb44fae4354b3baf/multidict-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75493f28dbadecdbb59130e74fe935288813301a8554dc32f0c631b6bdcdf8b0", size = 38138, upload-time = "2025-05-19T14:13:53.778Z" }, - { url = "https://files.pythonhosted.org/packages/97/8b/fbd9c0fc13966efdb4a47f5bcffff67a4f2a3189fbeead5766eaa4250b20/multidict-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc3c6a37e048b5395ee235e4a2a0d639c2349dffa32d9367a42fc20d399772", size = 220433, upload-time = "2025-05-19T14:13:55.346Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c4/5132b2d75b3ea2daedb14d10f91028f09f74f5b4d373b242c1b8eec47571/multidict-6.4.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87cb72263946b301570b0f63855569a24ee8758aaae2cd182aae7d95fbc92ca7", size = 218059, upload-time = "2025-05-19T14:13:56.993Z" }, - { url = "https://files.pythonhosted.org/packages/1a/70/f1e818c7a29b908e2d7b4fafb1d7939a41c64868e79de2982eea0a13193f/multidict-6.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bbf7bd39822fd07e3609b6b4467af4c404dd2b88ee314837ad1830a7f4a8299", size = 231120, upload-time = "2025-05-19T14:13:58.333Z" }, - { url = "https://files.pythonhosted.org/packages/b4/7e/95a194d85f27d5ef9cbe48dff9ded722fc6d12fedf641ec6e1e680890be7/multidict-6.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1f7cbd4f1f44ddf5fd86a8675b7679176eae770f2fc88115d6dddb6cefb59bc", size = 227457, upload-time = "2025-05-19T14:13:59.663Z" }, - { url = "https://files.pythonhosted.org/packages/25/2b/590ad220968d1babb42f265debe7be5c5c616df6c5688c995a06d8a9b025/multidict-6.4.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb5ac9e5bfce0e6282e7f59ff7b7b9a74aa8e5c60d38186a4637f5aa764046ad", size = 219111, upload-time = "2025-05-19T14:14:01.019Z" }, - { url = "https://files.pythonhosted.org/packages/e0/f0/b07682b995d3fb5313f339b59d7de02db19ba0c02d1f77c27bdf8212d17c/multidict-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4efc31dfef8c4eeb95b6b17d799eedad88c4902daba39ce637e23a17ea078915", size = 213012, upload-time = "2025-05-19T14:14:02.396Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/c77b5f36feef2ec92f1119756e468ac9c3eebc35aa8a4c9e51df664cbbc9/multidict-6.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9fcad2945b1b91c29ef2b4050f590bfcb68d8ac8e0995a74e659aa57e8d78e01", size = 225408, upload-time = "2025-05-19T14:14:04.826Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b3/e8189b82af9b198b47bc637766208fc917189eea91d674bad417e657bbdf/multidict-6.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d877447e7368c7320832acb7159557e49b21ea10ffeb135c1077dbbc0816b598", size = 214396, upload-time = "2025-05-19T14:14:06.187Z" }, - { url = "https://files.pythonhosted.org/packages/20/e0/200d14c84e35ae13ee99fd65dc106e1a1acb87a301f15e906fc7d5b30c17/multidict-6.4.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:33a12ebac9f380714c298cbfd3e5b9c0c4e89c75fe612ae496512ee51028915f", size = 222237, upload-time = "2025-05-19T14:14:07.778Z" }, - { url = "https://files.pythonhosted.org/packages/13/f3/bb3df40045ca8262694a3245298732ff431dc781414a89a6a364ebac6840/multidict-6.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0f14ea68d29b43a9bf37953881b1e3eb75b2739e896ba4a6aa4ad4c5b9ffa145", size = 231425, upload-time = "2025-05-19T14:14:09.516Z" }, - { url = "https://files.pythonhosted.org/packages/85/3b/538563dc18514384dac169bcba938753ad9ab4d4c8d49b55d6ae49fb2579/multidict-6.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0327ad2c747a6600e4797d115d3c38a220fdb28e54983abe8964fd17e95ae83c", size = 226251, upload-time = "2025-05-19T14:14:10.82Z" }, - { url = "https://files.pythonhosted.org/packages/56/79/77e1a65513f09142358f1beb1d4cbc06898590b34a7de2e47023e3c5a3a2/multidict-6.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d1a20707492db9719a05fc62ee215fd2c29b22b47c1b1ba347f9abc831e26683", size = 220363, upload-time = "2025-05-19T14:14:12.638Z" }, - { url = "https://files.pythonhosted.org/packages/16/57/67b0516c3e348f8daaa79c369b3de4359a19918320ab82e2e586a1c624ef/multidict-6.4.4-cp310-cp310-win32.whl", hash = "sha256:d83f18315b9fca5db2452d1881ef20f79593c4aa824095b62cb280019ef7aa3d", size = 35175, upload-time = "2025-05-19T14:14:14.805Z" }, - { url = "https://files.pythonhosted.org/packages/86/5a/4ed8fec642d113fa653777cda30ef67aa5c8a38303c091e24c521278a6c6/multidict-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:9c17341ee04545fd962ae07330cb5a39977294c883485c8d74634669b1f7fe04", size = 38678, upload-time = "2025-05-19T14:14:16.949Z" }, - { url = "https://files.pythonhosted.org/packages/19/1b/4c6e638195851524a63972c5773c7737bea7e47b1ba402186a37773acee2/multidict-6.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f5f29794ac0e73d2a06ac03fd18870adc0135a9d384f4a306a951188ed02f95", size = 65515, upload-time = "2025-05-19T14:14:19.767Z" }, - { url = "https://files.pythonhosted.org/packages/25/d5/10e6bca9a44b8af3c7f920743e5fc0c2bcf8c11bf7a295d4cfe00b08fb46/multidict-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c04157266344158ebd57b7120d9b0b35812285d26d0e78193e17ef57bfe2979a", size = 38609, upload-time = "2025-05-19T14:14:21.538Z" }, - { url = "https://files.pythonhosted.org/packages/26/b4/91fead447ccff56247edc7f0535fbf140733ae25187a33621771ee598a18/multidict-6.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb61ffd3ab8310d93427e460f565322c44ef12769f51f77277b4abad7b6f7223", size = 37871, upload-time = "2025-05-19T14:14:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/3b/37/cbc977cae59277e99d15bbda84cc53b5e0c4929ffd91d958347200a42ad0/multidict-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e0ba18a9afd495f17c351d08ebbc4284e9c9f7971d715f196b79636a4d0de44", size = 226661, upload-time = "2025-05-19T14:14:24.124Z" }, - { url = "https://files.pythonhosted.org/packages/15/cd/7e0b57fbd4dc2fc105169c4ecce5be1a63970f23bb4ec8c721b67e11953d/multidict-6.4.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9faf1b1dcaadf9f900d23a0e6d6c8eadd6a95795a0e57fcca73acce0eb912065", size = 223422, upload-time = "2025-05-19T14:14:25.437Z" }, - { url = "https://files.pythonhosted.org/packages/f1/01/1de268da121bac9f93242e30cd3286f6a819e5f0b8896511162d6ed4bf8d/multidict-6.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4d1cb1327c6082c4fce4e2a438483390964c02213bc6b8d782cf782c9b1471f", size = 235447, upload-time = "2025-05-19T14:14:26.793Z" }, - { url = "https://files.pythonhosted.org/packages/d2/8c/8b9a5e4aaaf4f2de14e86181a3a3d7b105077f668b6a06f043ec794f684c/multidict-6.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:941f1bec2f5dbd51feeb40aea654c2747f811ab01bdd3422a48a4e4576b7d76a", size = 231455, upload-time = "2025-05-19T14:14:28.149Z" }, - { url = "https://files.pythonhosted.org/packages/35/db/e1817dcbaa10b319c412769cf999b1016890849245d38905b73e9c286862/multidict-6.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5f8a146184da7ea12910a4cec51ef85e44f6268467fb489c3caf0cd512f29c2", size = 223666, upload-time = "2025-05-19T14:14:29.584Z" }, - { url = "https://files.pythonhosted.org/packages/4a/e1/66e8579290ade8a00e0126b3d9a93029033ffd84f0e697d457ed1814d0fc/multidict-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:232b7237e57ec3c09be97206bfb83a0aa1c5d7d377faa019c68a210fa35831f1", size = 217392, upload-time = "2025-05-19T14:14:30.961Z" }, - { url = "https://files.pythonhosted.org/packages/7b/6f/f8639326069c24a48c7747c2a5485d37847e142a3f741ff3340c88060a9a/multidict-6.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:55ae0721c1513e5e3210bca4fc98456b980b0c2c016679d3d723119b6b202c42", size = 228969, upload-time = "2025-05-19T14:14:32.672Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c3/3d58182f76b960eeade51c89fcdce450f93379340457a328e132e2f8f9ed/multidict-6.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d662c072579f63137919d7bb8fc250655ce79f00c82ecf11cab678f335062e", size = 217433, upload-time = "2025-05-19T14:14:34.016Z" }, - { url = "https://files.pythonhosted.org/packages/e1/4b/f31a562906f3bd375f3d0e83ce314e4a660c01b16c2923e8229b53fba5d7/multidict-6.4.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0e05c39962baa0bb19a6b210e9b1422c35c093b651d64246b6c2e1a7e242d9fd", size = 225418, upload-time = "2025-05-19T14:14:35.376Z" }, - { url = "https://files.pythonhosted.org/packages/99/89/78bb95c89c496d64b5798434a3deee21996114d4d2c28dd65850bf3a691e/multidict-6.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b1cc3ab8c31d9ebf0faa6e3540fb91257590da330ffe6d2393d4208e638925", size = 235042, upload-time = "2025-05-19T14:14:36.723Z" }, - { url = "https://files.pythonhosted.org/packages/74/91/8780a6e5885a8770442a8f80db86a0887c4becca0e5a2282ba2cae702bc4/multidict-6.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:93ec84488a384cd7b8a29c2c7f467137d8a73f6fe38bb810ecf29d1ade011a7c", size = 230280, upload-time = "2025-05-19T14:14:38.194Z" }, - { url = "https://files.pythonhosted.org/packages/68/c1/fcf69cabd542eb6f4b892469e033567ee6991d361d77abdc55e3a0f48349/multidict-6.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b308402608493638763abc95f9dc0030bbd6ac6aff784512e8ac3da73a88af08", size = 223322, upload-time = "2025-05-19T14:14:40.015Z" }, - { url = "https://files.pythonhosted.org/packages/b8/85/5b80bf4b83d8141bd763e1d99142a9cdfd0db83f0739b4797172a4508014/multidict-6.4.4-cp311-cp311-win32.whl", hash = "sha256:343892a27d1a04d6ae455ecece12904d242d299ada01633d94c4f431d68a8c49", size = 35070, upload-time = "2025-05-19T14:14:41.904Z" }, - { url = "https://files.pythonhosted.org/packages/09/66/0bed198ffd590ab86e001f7fa46b740d58cf8ff98c2f254e4a36bf8861ad/multidict-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:73484a94f55359780c0f458bbd3c39cb9cf9c182552177d2136e828269dee529", size = 38667, upload-time = "2025-05-19T14:14:43.534Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b5/5675377da23d60875fe7dae6be841787755878e315e2f517235f22f59e18/multidict-6.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc388f75a1c00000824bf28b7633e40854f4127ede80512b44c3cfeeea1839a2", size = 64293, upload-time = "2025-05-19T14:14:44.724Z" }, - { url = "https://files.pythonhosted.org/packages/34/a7/be384a482754bb8c95d2bbe91717bf7ccce6dc38c18569997a11f95aa554/multidict-6.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:98af87593a666f739d9dba5d0ae86e01b0e1a9cfcd2e30d2d361fbbbd1a9162d", size = 38096, upload-time = "2025-05-19T14:14:45.95Z" }, - { url = "https://files.pythonhosted.org/packages/66/6d/d59854bb4352306145bdfd1704d210731c1bb2c890bfee31fb7bbc1c4c7f/multidict-6.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aff4cafea2d120327d55eadd6b7f1136a8e5a0ecf6fb3b6863e8aca32cd8e50a", size = 37214, upload-time = "2025-05-19T14:14:47.158Z" }, - { url = "https://files.pythonhosted.org/packages/99/e0/c29d9d462d7cfc5fc8f9bf24f9c6843b40e953c0b55e04eba2ad2cf54fba/multidict-6.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:169c4ba7858176b797fe551d6e99040c531c775d2d57b31bcf4de6d7a669847f", size = 224686, upload-time = "2025-05-19T14:14:48.366Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4a/da99398d7fd8210d9de068f9a1b5f96dfaf67d51e3f2521f17cba4ee1012/multidict-6.4.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9eb4c59c54421a32b3273d4239865cb14ead53a606db066d7130ac80cc8ec93", size = 231061, upload-time = "2025-05-19T14:14:49.952Z" }, - { url = "https://files.pythonhosted.org/packages/21/f5/ac11add39a0f447ac89353e6ca46666847051103649831c08a2800a14455/multidict-6.4.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cf3bd54c56aa16fdb40028d545eaa8d051402b61533c21e84046e05513d5780", size = 232412, upload-time = "2025-05-19T14:14:51.812Z" }, - { url = "https://files.pythonhosted.org/packages/d9/11/4b551e2110cded705a3c13a1d4b6a11f73891eb5a1c449f1b2b6259e58a6/multidict-6.4.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f682c42003c7264134bfe886376299db4cc0c6cd06a3295b41b347044bcb5482", size = 231563, upload-time = "2025-05-19T14:14:53.262Z" }, - { url = "https://files.pythonhosted.org/packages/4c/02/751530c19e78fe73b24c3da66618eda0aa0d7f6e7aa512e46483de6be210/multidict-6.4.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920f9cf2abdf6e493c519492d892c362007f113c94da4c239ae88429835bad1", size = 223811, upload-time = "2025-05-19T14:14:55.232Z" }, - { url = "https://files.pythonhosted.org/packages/c7/cb/2be8a214643056289e51ca356026c7b2ce7225373e7a1f8c8715efee8988/multidict-6.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:530d86827a2df6504526106b4c104ba19044594f8722d3e87714e847c74a0275", size = 216524, upload-time = "2025-05-19T14:14:57.226Z" }, - { url = "https://files.pythonhosted.org/packages/19/f3/6d5011ec375c09081f5250af58de85f172bfcaafebff286d8089243c4bd4/multidict-6.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ecde56ea2439b96ed8a8d826b50c57364612ddac0438c39e473fafad7ae1c23b", size = 229012, upload-time = "2025-05-19T14:14:58.597Z" }, - { url = "https://files.pythonhosted.org/packages/67/9c/ca510785df5cf0eaf5b2a8132d7d04c1ce058dcf2c16233e596ce37a7f8e/multidict-6.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:dc8c9736d8574b560634775ac0def6bdc1661fc63fa27ffdfc7264c565bcb4f2", size = 226765, upload-time = "2025-05-19T14:15:00.048Z" }, - { url = "https://files.pythonhosted.org/packages/36/c8/ca86019994e92a0f11e642bda31265854e6ea7b235642f0477e8c2e25c1f/multidict-6.4.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7f3d3b3c34867579ea47cbd6c1f2ce23fbfd20a273b6f9e3177e256584f1eacc", size = 222888, upload-time = "2025-05-19T14:15:01.568Z" }, - { url = "https://files.pythonhosted.org/packages/c6/67/bc25a8e8bd522935379066950ec4e2277f9b236162a73548a2576d4b9587/multidict-6.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:87a728af265e08f96b6318ebe3c0f68b9335131f461efab2fc64cc84a44aa6ed", size = 234041, upload-time = "2025-05-19T14:15:03.759Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a0/70c4c2d12857fccbe607b334b7ee28b6b5326c322ca8f73ee54e70d76484/multidict-6.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9f193eeda1857f8e8d3079a4abd258f42ef4a4bc87388452ed1e1c4d2b0c8740", size = 231046, upload-time = "2025-05-19T14:15:05.698Z" }, - { url = "https://files.pythonhosted.org/packages/c1/0f/52954601d02d39742aab01d6b92f53c1dd38b2392248154c50797b4df7f1/multidict-6.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be06e73c06415199200e9a2324a11252a3d62030319919cde5e6950ffeccf72e", size = 227106, upload-time = "2025-05-19T14:15:07.124Z" }, - { url = "https://files.pythonhosted.org/packages/af/24/679d83ec4379402d28721790dce818e5d6b9f94ce1323a556fb17fa9996c/multidict-6.4.4-cp312-cp312-win32.whl", hash = "sha256:622f26ea6a7e19b7c48dd9228071f571b2fbbd57a8cd71c061e848f281550e6b", size = 35351, upload-time = "2025-05-19T14:15:08.556Z" }, - { url = "https://files.pythonhosted.org/packages/52/ef/40d98bc5f986f61565f9b345f102409534e29da86a6454eb6b7c00225a13/multidict-6.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:5e2bcda30d5009996ff439e02a9f2b5c3d64a20151d34898c000a6281faa3781", size = 38791, upload-time = "2025-05-19T14:15:09.825Z" }, - { url = "https://files.pythonhosted.org/packages/df/2a/e166d2ffbf4b10131b2d5b0e458f7cee7d986661caceae0de8753042d4b2/multidict-6.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:82ffabefc8d84c2742ad19c37f02cde5ec2a1ee172d19944d380f920a340e4b9", size = 64123, upload-time = "2025-05-19T14:15:11.044Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/e200e379ae5b6f95cbae472e0199ea98913f03d8c9a709f42612a432932c/multidict-6.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6a2f58a66fe2c22615ad26156354005391e26a2f3721c3621504cd87c1ea87bf", size = 38049, upload-time = "2025-05-19T14:15:12.902Z" }, - { url = "https://files.pythonhosted.org/packages/75/fb/47afd17b83f6a8c7fa863c6d23ac5ba6a0e6145ed8a6bcc8da20b2b2c1d2/multidict-6.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5883d6ee0fd9d8a48e9174df47540b7545909841ac82354c7ae4cbe9952603bd", size = 37078, upload-time = "2025-05-19T14:15:14.282Z" }, - { url = "https://files.pythonhosted.org/packages/fa/70/1af3143000eddfb19fd5ca5e78393985ed988ac493bb859800fe0914041f/multidict-6.4.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9abcf56a9511653fa1d052bfc55fbe53dbee8f34e68bd6a5a038731b0ca42d15", size = 224097, upload-time = "2025-05-19T14:15:15.566Z" }, - { url = "https://files.pythonhosted.org/packages/b1/39/d570c62b53d4fba844e0378ffbcd02ac25ca423d3235047013ba2f6f60f8/multidict-6.4.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6ed5ae5605d4ad5a049fad2a28bb7193400700ce2f4ae484ab702d1e3749c3f9", size = 230768, upload-time = "2025-05-19T14:15:17.308Z" }, - { url = "https://files.pythonhosted.org/packages/fd/f8/ed88f2c4d06f752b015933055eb291d9bc184936903752c66f68fb3c95a7/multidict-6.4.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbfcb60396f9bcfa63e017a180c3105b8c123a63e9d1428a36544e7d37ca9e20", size = 231331, upload-time = "2025-05-19T14:15:18.73Z" }, - { url = "https://files.pythonhosted.org/packages/9c/6f/8e07cffa32f483ab887b0d56bbd8747ac2c1acd00dc0af6fcf265f4a121e/multidict-6.4.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0f1987787f5f1e2076b59692352ab29a955b09ccc433c1f6b8e8e18666f608b", size = 230169, upload-time = "2025-05-19T14:15:20.179Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2b/5dcf173be15e42f330110875a2668ddfc208afc4229097312212dc9c1236/multidict-6.4.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0121ccce8c812047d8d43d691a1ad7641f72c4f730474878a5aeae1b8ead8c", size = 222947, upload-time = "2025-05-19T14:15:21.714Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/4ddcbcebe5ebcd6faa770b629260d15840a5fc07ce8ad295a32e14993726/multidict-6.4.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83ec4967114295b8afd120a8eec579920c882831a3e4c3331d591a8e5bfbbc0f", size = 215761, upload-time = "2025-05-19T14:15:23.242Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c9/55e998ae45ff15c5608e384206aa71a11e1b7f48b64d166db400b14a3433/multidict-6.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:995f985e2e268deaf17867801b859a282e0448633f1310e3704b30616d269d69", size = 227605, upload-time = "2025-05-19T14:15:24.763Z" }, - { url = "https://files.pythonhosted.org/packages/04/49/c2404eac74497503c77071bd2e6f88c7e94092b8a07601536b8dbe99be50/multidict-6.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d832c608f94b9f92a0ec8b7e949be7792a642b6e535fcf32f3e28fab69eeb046", size = 226144, upload-time = "2025-05-19T14:15:26.249Z" }, - { url = "https://files.pythonhosted.org/packages/62/c5/0cd0c3c6f18864c40846aa2252cd69d308699cb163e1c0d989ca301684da/multidict-6.4.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d21c1212171cf7da703c5b0b7a0e85be23b720818aef502ad187d627316d5645", size = 221100, upload-time = "2025-05-19T14:15:28.303Z" }, - { url = "https://files.pythonhosted.org/packages/71/7b/f2f3887bea71739a046d601ef10e689528d4f911d84da873b6be9194ffea/multidict-6.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:cbebaa076aaecad3d4bb4c008ecc73b09274c952cf6a1b78ccfd689e51f5a5b0", size = 232731, upload-time = "2025-05-19T14:15:30.263Z" }, - { url = "https://files.pythonhosted.org/packages/e5/b3/d9de808349df97fa75ec1372758701b5800ebad3c46ae377ad63058fbcc6/multidict-6.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c93a6fb06cc8e5d3628b2b5fda215a5db01e8f08fc15fadd65662d9b857acbe4", size = 229637, upload-time = "2025-05-19T14:15:33.337Z" }, - { url = "https://files.pythonhosted.org/packages/5e/57/13207c16b615eb4f1745b44806a96026ef8e1b694008a58226c2d8f5f0a5/multidict-6.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8cd8f81f1310182362fb0c7898145ea9c9b08a71081c5963b40ee3e3cac589b1", size = 225594, upload-time = "2025-05-19T14:15:34.832Z" }, - { url = "https://files.pythonhosted.org/packages/3a/e4/d23bec2f70221604f5565000632c305fc8f25ba953e8ce2d8a18842b9841/multidict-6.4.4-cp313-cp313-win32.whl", hash = "sha256:3e9f1cd61a0ab857154205fb0b1f3d3ace88d27ebd1409ab7af5096e409614cd", size = 35359, upload-time = "2025-05-19T14:15:36.246Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/cfe1a47632be861b627f46f642c1d031704cc1c0f5c0efbde2ad44aa34bd/multidict-6.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373", size = 38903, upload-time = "2025-05-19T14:15:37.507Z" }, - { url = "https://files.pythonhosted.org/packages/68/7b/15c259b0ab49938a0a1c8f3188572802704a779ddb294edc1b2a72252e7c/multidict-6.4.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6a602151dbf177be2450ef38966f4be3467d41a86c6a845070d12e17c858a156", size = 68895, upload-time = "2025-05-19T14:15:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/f1/7d/168b5b822bccd88142e0a3ce985858fea612404edd228698f5af691020c9/multidict-6.4.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d2b9712211b860d123815a80b859075d86a4d54787e247d7fbee9db6832cf1c", size = 40183, upload-time = "2025-05-19T14:15:40.197Z" }, - { url = "https://files.pythonhosted.org/packages/e0/b7/d4b8d98eb850ef28a4922ba508c31d90715fd9b9da3801a30cea2967130b/multidict-6.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d2fa86af59f8fc1972e121ade052145f6da22758f6996a197d69bb52f8204e7e", size = 39592, upload-time = "2025-05-19T14:15:41.508Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/a554678898a19583548e742080cf55d169733baf57efc48c2f0273a08583/multidict-6.4.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50855d03e9e4d66eab6947ba688ffb714616f985838077bc4b490e769e48da51", size = 226071, upload-time = "2025-05-19T14:15:42.877Z" }, - { url = "https://files.pythonhosted.org/packages/ee/dc/7ba6c789d05c310e294f85329efac1bf5b450338d2542498db1491a264df/multidict-6.4.4-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5bce06b83be23225be1905dcdb6b789064fae92499fbc458f59a8c0e68718601", size = 222597, upload-time = "2025-05-19T14:15:44.412Z" }, - { url = "https://files.pythonhosted.org/packages/24/4f/34eadbbf401b03768dba439be0fb94b0d187facae9142821a3d5599ccb3b/multidict-6.4.4-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66ed0731f8e5dfd8369a883b6e564aca085fb9289aacabd9decd70568b9a30de", size = 228253, upload-time = "2025-05-19T14:15:46.474Z" }, - { url = "https://files.pythonhosted.org/packages/c0/e6/493225a3cdb0d8d80d43a94503fc313536a07dae54a3f030d279e629a2bc/multidict-6.4.4-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:329ae97fc2f56f44d91bc47fe0972b1f52d21c4b7a2ac97040da02577e2daca2", size = 226146, upload-time = "2025-05-19T14:15:48.003Z" }, - { url = "https://files.pythonhosted.org/packages/2f/70/e411a7254dc3bff6f7e6e004303b1b0591358e9f0b7c08639941e0de8bd6/multidict-6.4.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c27e5dcf520923d6474d98b96749e6805f7677e93aaaf62656005b8643f907ab", size = 220585, upload-time = "2025-05-19T14:15:49.546Z" }, - { url = "https://files.pythonhosted.org/packages/08/8f/beb3ae7406a619100d2b1fb0022c3bb55a8225ab53c5663648ba50dfcd56/multidict-6.4.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:058cc59b9e9b143cc56715e59e22941a5d868c322242278d28123a5d09cdf6b0", size = 212080, upload-time = "2025-05-19T14:15:51.151Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ec/355124e9d3d01cf8edb072fd14947220f357e1c5bc79c88dff89297e9342/multidict-6.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:69133376bc9a03f8c47343d33f91f74a99c339e8b58cea90433d8e24bb298031", size = 226558, upload-time = "2025-05-19T14:15:52.665Z" }, - { url = "https://files.pythonhosted.org/packages/fd/22/d2b95cbebbc2ada3be3812ea9287dcc9712d7f1a012fad041770afddb2ad/multidict-6.4.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d6b15c55721b1b115c5ba178c77104123745b1417527ad9641a4c5e2047450f0", size = 212168, upload-time = "2025-05-19T14:15:55.279Z" }, - { url = "https://files.pythonhosted.org/packages/4d/c5/62bfc0b2f9ce88326dbe7179f9824a939c6c7775b23b95de777267b9725c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a887b77f51d3d41e6e1a63cf3bc7ddf24de5939d9ff69441387dfefa58ac2e26", size = 217970, upload-time = "2025-05-19T14:15:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/79/74/977cea1aadc43ff1c75d23bd5bc4768a8fac98c14e5878d6ee8d6bab743c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:632a3bf8f1787f7ef7d3c2f68a7bde5be2f702906f8b5842ad6da9d974d0aab3", size = 226980, upload-time = "2025-05-19T14:15:58.313Z" }, - { url = "https://files.pythonhosted.org/packages/48/fc/cc4a1a2049df2eb84006607dc428ff237af38e0fcecfdb8a29ca47b1566c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a145c550900deb7540973c5cdb183b0d24bed6b80bf7bddf33ed8f569082535e", size = 220641, upload-time = "2025-05-19T14:15:59.866Z" }, - { url = "https://files.pythonhosted.org/packages/3b/6a/a7444d113ab918701988d4abdde373dbdfd2def7bd647207e2bf645c7eac/multidict-6.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc5d83c6619ca5c9672cb78b39ed8542f1975a803dee2cda114ff73cbb076edd", size = 221728, upload-time = "2025-05-19T14:16:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b0/fdf4c73ad1c55e0f4dbbf2aa59dd37037334091f9a4961646d2b7ac91a86/multidict-6.4.4-cp313-cp313t-win32.whl", hash = "sha256:3312f63261b9df49be9d57aaa6abf53a6ad96d93b24f9cc16cf979956355ce6e", size = 41913, upload-time = "2025-05-19T14:16:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/8e/92/27989ecca97e542c0d01d05a98a5ae12198a243a9ee12563a0313291511f/multidict-6.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:ba852168d814b2c73333073e1c7116d9395bea69575a01b0b3c89d2d5a87c8fb", size = 46112, upload-time = "2025-05-19T14:16:04.909Z" }, - { url = "https://files.pythonhosted.org/packages/84/5d/e17845bb0fa76334477d5de38654d27946d5b5d3695443987a094a71b440/multidict-6.4.4-py3-none-any.whl", hash = "sha256:bd4557071b561a8b3b6075c3ce93cf9bfb6182cb241805c3d66ced3b75eff4ac", size = 10481, upload-time = "2025-05-19T14:16:36.024Z" }, -] - -[[package]] -name = "nest-asyncio" -version = "1.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/83/f8/51569ac65d696c8ecbee95938f89d4abf00f47d58d48f6fbabfe8f0baefe/nest_asyncio-1.6.0.tar.gz", hash = "sha256:6f172d5449aca15afd6c646851f4e31e02c598d553a667e38cafa997cfec55fe", size = 7418, upload-time = "2024-01-21T14:25:19.227Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a0/c4/c2971a3ba4c6103a3d10c4b0f24f461ddc027f0f09763220cf35ca1401b3/nest_asyncio-1.6.0-py3-none-any.whl", hash = "sha256:87af6efd6b5e897c81050477ef65c62e2b2f35d51703cae01aff2905b1852e1c", size = 5195, upload-time = "2024-01-21T14:25:17.223Z" }, -] - -[[package]] -name = "parsimonious" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7b/91/abdc50c4ef06fdf8d047f60ee777ca9b2a7885e1a9cea81343fbecda52d7/parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c", size = 52172, upload-time = "2022-09-03T17:01:17.004Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/0f/c8b64d9b54ea631fcad4e9e3c8dbe8c11bb32a623be94f22974c88e71eaf/parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f", size = 48427, upload-time = "2022-09-03T17:01:13.814Z" }, -] - -[[package]] -name = "propcache" -version = "0.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4e/ad52a7925ff01c1325653a730c7ec3175a23f948f08626a534133427dcff/propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3", size = 43133, upload-time = "2025-06-09T22:53:41.965Z" }, - { url = "https://files.pythonhosted.org/packages/63/7c/e9399ba5da7780871db4eac178e9c2e204c23dd3e7d32df202092a1ed400/propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3", size = 43039, upload-time = "2025-06-09T22:53:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/22/e1/58da211eb8fdc6fc854002387d38f415a6ca5f5c67c1315b204a5d3e9d7a/propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e", size = 201903, upload-time = "2025-06-09T22:53:44.872Z" }, - { url = "https://files.pythonhosted.org/packages/c4/0a/550ea0f52aac455cb90111c8bab995208443e46d925e51e2f6ebdf869525/propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220", size = 213362, upload-time = "2025-06-09T22:53:46.707Z" }, - { url = "https://files.pythonhosted.org/packages/5a/af/9893b7d878deda9bb69fcf54600b247fba7317761b7db11fede6e0f28bd0/propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb", size = 210525, upload-time = "2025-06-09T22:53:48.547Z" }, - { url = "https://files.pythonhosted.org/packages/7c/bb/38fd08b278ca85cde36d848091ad2b45954bc5f15cce494bb300b9285831/propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614", size = 198283, upload-time = "2025-06-09T22:53:50.067Z" }, - { url = "https://files.pythonhosted.org/packages/78/8c/9fe55bd01d362bafb413dfe508c48753111a1e269737fa143ba85693592c/propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50", size = 191872, upload-time = "2025-06-09T22:53:51.438Z" }, - { url = "https://files.pythonhosted.org/packages/54/14/4701c33852937a22584e08abb531d654c8bcf7948a8f87ad0a4822394147/propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339", size = 199452, upload-time = "2025-06-09T22:53:53.229Z" }, - { url = "https://files.pythonhosted.org/packages/16/44/447f2253d859602095356007657ee535e0093215ea0b3d1d6a41d16e5201/propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0", size = 191567, upload-time = "2025-06-09T22:53:54.541Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/e4756258749bb2d3b46defcff606a2f47410bab82be5824a67e84015b267/propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2", size = 193015, upload-time = "2025-06-09T22:53:56.44Z" }, - { url = "https://files.pythonhosted.org/packages/1e/df/e6d3c7574233164b6330b9fd697beeac402afd367280e6dc377bb99b43d9/propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7", size = 204660, upload-time = "2025-06-09T22:53:57.839Z" }, - { url = "https://files.pythonhosted.org/packages/b2/53/e4d31dd5170b4a0e2e6b730f2385a96410633b4833dc25fe5dffd1f73294/propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b", size = 206105, upload-time = "2025-06-09T22:53:59.638Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fe/74d54cf9fbe2a20ff786e5f7afcfde446588f0cf15fb2daacfbc267b866c/propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c", size = 196980, upload-time = "2025-06-09T22:54:01.071Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/c469c9d59dada8a7679625e0440b544fe72e99311a4679c279562051f6fc/propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70", size = 37679, upload-time = "2025-06-09T22:54:03.003Z" }, - { url = "https://files.pythonhosted.org/packages/38/35/07a471371ac89d418f8d0b699c75ea6dca2041fbda360823de21f6a9ce0a/propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9", size = 41459, upload-time = "2025-06-09T22:54:04.134Z" }, - { url = "https://files.pythonhosted.org/packages/80/8d/e8b436717ab9c2cfc23b116d2c297305aa4cd8339172a456d61ebf5669b8/propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be", size = 74207, upload-time = "2025-06-09T22:54:05.399Z" }, - { url = "https://files.pythonhosted.org/packages/d6/29/1e34000e9766d112171764b9fa3226fa0153ab565d0c242c70e9945318a7/propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f", size = 43648, upload-time = "2025-06-09T22:54:08.023Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/1ad5af0df781e76988897da39b5f086c2bf0f028b7f9bd1f409bb05b6874/propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9", size = 43496, upload-time = "2025-06-09T22:54:09.228Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ce/e96392460f9fb68461fabab3e095cb00c8ddf901205be4eae5ce246e5b7e/propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf", size = 217288, upload-time = "2025-06-09T22:54:10.466Z" }, - { url = "https://files.pythonhosted.org/packages/c5/2a/866726ea345299f7ceefc861a5e782b045545ae6940851930a6adaf1fca6/propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9", size = 227456, upload-time = "2025-06-09T22:54:11.828Z" }, - { url = "https://files.pythonhosted.org/packages/de/03/07d992ccb6d930398689187e1b3c718339a1c06b8b145a8d9650e4726166/propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66", size = 225429, upload-time = "2025-06-09T22:54:13.823Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/116ba39448753b1330f48ab8ba927dcd6cf0baea8a0ccbc512dfb49ba670/propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df", size = 213472, upload-time = "2025-06-09T22:54:15.232Z" }, - { url = "https://files.pythonhosted.org/packages/a6/85/f01f5d97e54e428885a5497ccf7f54404cbb4f906688a1690cd51bf597dc/propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2", size = 204480, upload-time = "2025-06-09T22:54:17.104Z" }, - { url = "https://files.pythonhosted.org/packages/e3/79/7bf5ab9033b8b8194cc3f7cf1aaa0e9c3256320726f64a3e1f113a812dce/propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7", size = 214530, upload-time = "2025-06-09T22:54:18.512Z" }, - { url = "https://files.pythonhosted.org/packages/31/0b/bd3e0c00509b609317df4a18e6b05a450ef2d9a963e1d8bc9c9415d86f30/propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95", size = 205230, upload-time = "2025-06-09T22:54:19.947Z" }, - { url = "https://files.pythonhosted.org/packages/7a/23/fae0ff9b54b0de4e819bbe559508da132d5683c32d84d0dc2ccce3563ed4/propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e", size = 206754, upload-time = "2025-06-09T22:54:21.716Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7f/ad6a3c22630aaa5f618b4dc3c3598974a72abb4c18e45a50b3cdd091eb2f/propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e", size = 218430, upload-time = "2025-06-09T22:54:23.17Z" }, - { url = "https://files.pythonhosted.org/packages/5b/2c/ba4f1c0e8a4b4c75910742f0d333759d441f65a1c7f34683b4a74c0ee015/propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf", size = 223884, upload-time = "2025-06-09T22:54:25.539Z" }, - { url = "https://files.pythonhosted.org/packages/88/e4/ebe30fc399e98572019eee82ad0caf512401661985cbd3da5e3140ffa1b0/propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e", size = 211480, upload-time = "2025-06-09T22:54:26.892Z" }, - { url = "https://files.pythonhosted.org/packages/96/0a/7d5260b914e01d1d0906f7f38af101f8d8ed0dc47426219eeaf05e8ea7c2/propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897", size = 37757, upload-time = "2025-06-09T22:54:28.241Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2d/89fe4489a884bc0da0c3278c552bd4ffe06a1ace559db5ef02ef24ab446b/propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39", size = 41500, upload-time = "2025-06-09T22:54:29.4Z" }, - { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, - { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, - { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, - { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, - { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, - { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, - { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, - { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, - { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, - { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, - { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, - { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, - { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, - { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, - { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, - { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, - { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, - { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, - { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, - { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, - { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, - { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, - { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, - { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, - { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, - { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, - { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, - { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, - { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, -] - -[[package]] -name = "pycparser" -version = "2.22" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/1d/b2/31537cf4b1ca988837256c910a668b553fceb8f069bedc4b1c826024b52c/pycparser-2.22.tar.gz", hash = "sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6", size = 172736, upload-time = "2024-03-30T13:22:22.564Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/13/a3/a812df4e2dd5696d1f351d58b8fe16a405b234ad2886a0dab9183fb78109/pycparser-2.22-py3-none-any.whl", hash = "sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc", size = 117552, upload-time = "2024-03-30T13:22:20.476Z" }, -] - -[[package]] -name = "pycryptodome" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" }, - { url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" }, - { url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" }, - { url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" }, - { url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" }, - { url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" }, - { url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" }, - { url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" }, - { url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" }, - { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, - { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, - { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, - { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, - { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, - { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, - { url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886, upload-time = "2025-05-17T17:21:20.614Z" }, - { url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151, upload-time = "2025-05-17T17:21:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461, upload-time = "2025-05-17T17:21:25.225Z" }, - { url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440, upload-time = "2025-05-17T17:21:27.991Z" }, - { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, -] - -[[package]] -name = "pydantic" -version = "2.10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/70/7e/fb60e6fee04d0ef8f15e4e01ff187a196fa976eb0f0ab524af4599e5754c/pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06", size = 762094, upload-time = "2024-12-18T17:09:24.84Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/26/3e1bbe954fde7ee22a6e7d31582c642aad9e84ffe4b5fb61e63b87cd326f/pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", size = 431765, upload-time = "2024-12-18T17:09:21.953Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.27.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443, upload-time = "2024-12-18T11:31:54.917Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938, upload-time = "2024-12-18T11:27:14.406Z" }, - { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684, upload-time = "2024-12-18T11:27:16.489Z" }, - { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169, upload-time = "2024-12-18T11:27:22.16Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227, upload-time = "2024-12-18T11:27:25.097Z" }, - { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695, upload-time = "2024-12-18T11:27:28.656Z" }, - { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662, upload-time = "2024-12-18T11:27:30.798Z" }, - { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370, upload-time = "2024-12-18T11:27:33.692Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813, upload-time = "2024-12-18T11:27:37.111Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287, upload-time = "2024-12-18T11:27:40.566Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414, upload-time = "2024-12-18T11:27:43.757Z" }, - { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301, upload-time = "2024-12-18T11:27:47.36Z" }, - { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685, upload-time = "2024-12-18T11:27:50.508Z" }, - { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876, upload-time = "2024-12-18T11:27:53.54Z" }, - { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421, upload-time = "2024-12-18T11:27:55.409Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998, upload-time = "2024-12-18T11:27:57.252Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167, upload-time = "2024-12-18T11:27:59.146Z" }, - { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071, upload-time = "2024-12-18T11:28:02.625Z" }, - { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244, upload-time = "2024-12-18T11:28:04.442Z" }, - { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470, upload-time = "2024-12-18T11:28:07.679Z" }, - { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291, upload-time = "2024-12-18T11:28:10.297Z" }, - { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613, upload-time = "2024-12-18T11:28:13.362Z" }, - { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355, upload-time = "2024-12-18T11:28:16.587Z" }, - { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661, upload-time = "2024-12-18T11:28:18.407Z" }, - { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261, upload-time = "2024-12-18T11:28:21.471Z" }, - { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361, upload-time = "2024-12-18T11:28:23.53Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484, upload-time = "2024-12-18T11:28:25.391Z" }, - { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102, upload-time = "2024-12-18T11:28:28.593Z" }, - { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127, upload-time = "2024-12-18T11:28:30.346Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340, upload-time = "2024-12-18T11:28:32.521Z" }, - { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900, upload-time = "2024-12-18T11:28:34.507Z" }, - { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177, upload-time = "2024-12-18T11:28:36.488Z" }, - { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046, upload-time = "2024-12-18T11:28:39.409Z" }, - { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386, upload-time = "2024-12-18T11:28:41.221Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060, upload-time = "2024-12-18T11:28:44.709Z" }, - { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870, upload-time = "2024-12-18T11:28:46.839Z" }, - { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822, upload-time = "2024-12-18T11:28:48.896Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364, upload-time = "2024-12-18T11:28:50.755Z" }, - { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303, upload-time = "2024-12-18T11:28:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064, upload-time = "2024-12-18T11:28:56.074Z" }, - { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046, upload-time = "2024-12-18T11:28:58.107Z" }, - { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092, upload-time = "2024-12-18T11:29:01.335Z" }, - { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709, upload-time = "2024-12-18T11:29:03.193Z" }, - { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273, upload-time = "2024-12-18T11:29:05.306Z" }, - { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027, upload-time = "2024-12-18T11:29:07.294Z" }, - { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888, upload-time = "2024-12-18T11:29:09.249Z" }, - { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738, upload-time = "2024-12-18T11:29:11.23Z" }, - { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138, upload-time = "2024-12-18T11:29:16.396Z" }, - { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025, upload-time = "2024-12-18T11:29:20.25Z" }, - { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633, upload-time = "2024-12-18T11:29:23.877Z" }, - { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404, upload-time = "2024-12-18T11:29:25.872Z" }, - { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130, upload-time = "2024-12-18T11:29:29.252Z" }, - { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946, upload-time = "2024-12-18T11:29:31.338Z" }, - { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387, upload-time = "2024-12-18T11:29:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453, upload-time = "2024-12-18T11:29:35.533Z" }, - { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186, upload-time = "2024-12-18T11:29:37.649Z" }, - { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159, upload-time = "2024-12-18T11:30:54.382Z" }, - { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331, upload-time = "2024-12-18T11:30:58.178Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467, upload-time = "2024-12-18T11:31:00.6Z" }, - { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797, upload-time = "2024-12-18T11:31:07.243Z" }, - { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839, upload-time = "2024-12-18T11:31:09.775Z" }, - { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861, upload-time = "2024-12-18T11:31:13.469Z" }, - { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582, upload-time = "2024-12-18T11:31:17.423Z" }, - { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985, upload-time = "2024-12-18T11:31:19.901Z" }, - { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715, upload-time = "2024-12-18T11:31:22.821Z" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234, upload-time = "2025-04-18T16:44:48.265Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356, upload-time = "2025-04-18T16:44:46.617Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, -] - -[[package]] -name = "pyjwt" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e7/46/bd74733ff231675599650d3e47f361794b22ef3e3770998dda30d3b63726/pyjwt-2.10.1.tar.gz", hash = "sha256:3cc5772eb20009233caf06e9d8a0577824723b44e6648ee0a2aedb6cf9381953", size = 87785, upload-time = "2024-11-28T03:43:29.933Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/61/ad/689f02752eeec26aed679477e80e632ef1b682313be70793d798c1d5fc8f/PyJWT-2.10.1-py3-none-any.whl", hash = "sha256:dcdd193e30abefd5debf142f9adfcdd2b58004e644f25406ffaebd50bd98dacb", size = 22997, upload-time = "2024-11-28T03:43:27.893Z" }, -] - -[[package]] -name = "python-dateutil" -version = "2.9.0.post0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "six" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/66/c0/0c8b6ad9f17a802ee498c46e004a0eb49bc148f2fd230864601a86dcf6db/python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3", size = 342432, upload-time = "2024-03-01T18:36:20.211Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920, upload-time = "2025-03-25T10:14:56.835Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256, upload-time = "2025-03-25T10:14:55.034Z" }, -] - -[[package]] -name = "python-multipart" -version = "0.0.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, -] - -[[package]] -name = "pyunormalize" -version = "16.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/08/568036c725dac746ecb267bb749ef930fb7907454fe69fce83c8557287fb/pyunormalize-16.0.0.tar.gz", hash = "sha256:2e1dfbb4a118154ae26f70710426a52a364b926c9191f764601f5a8cb12761f7", size = 49968, upload-time = "2024-09-17T17:08:18.245Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/f9/9d86e56f716e0651194a5ad58be9c146fcaf1de6901ac6f3cd3affeeb74e/pyunormalize-16.0.0-py3-none-any.whl", hash = "sha256:c647d95e5d1e2ea9a2f448d1d95d8518348df24eab5c3fd32d2b5c3300a49152", size = 49173, upload-time = "2024-09-17T17:08:17.078Z" }, -] - -[[package]] -name = "pywin32" -version = "310" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, - { url = "https://files.pythonhosted.org/packages/3c/84/1a8e3d7a15490d28a5d816efa229ecb4999cdc51a7c30dd8914f669093b8/pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213", size = 8522963, upload-time = "2025-03-17T00:55:50.969Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b1/68aa2986129fb1011dabbe95f0136f44509afaf072b12b8f815905a39f33/pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd", size = 8784284, upload-time = "2025-03-17T00:55:53.124Z" }, - { url = "https://files.pythonhosted.org/packages/b3/bd/d1592635992dd8db5bb8ace0551bc3a769de1ac8850200cfa517e72739fb/pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c", size = 9520748, upload-time = "2025-03-17T00:55:55.203Z" }, - { url = "https://files.pythonhosted.org/packages/90/b1/ac8b1ffce6603849eb45a91cf126c0fa5431f186c2e768bf56889c46f51c/pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582", size = 8455941, upload-time = "2025-03-17T00:55:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, - { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384, upload-time = "2025-03-17T00:56:04.383Z" }, - { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039, upload-time = "2025-03-17T00:56:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152, upload-time = "2025-03-17T00:56:07.819Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" }, - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, - { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669, upload-time = "2024-11-06T20:09:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684, upload-time = "2024-11-06T20:09:32.915Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589, upload-time = "2024-11-06T20:09:35.504Z" }, - { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121, upload-time = "2024-11-06T20:09:37.701Z" }, - { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275, upload-time = "2024-11-06T20:09:40.371Z" }, - { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257, upload-time = "2024-11-06T20:09:43.059Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727, upload-time = "2024-11-06T20:09:48.19Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667, upload-time = "2024-11-06T20:09:49.828Z" }, - { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963, upload-time = "2024-11-06T20:09:51.819Z" }, - { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700, upload-time = "2024-11-06T20:09:53.982Z" }, - { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592, upload-time = "2024-11-06T20:09:56.222Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929, upload-time = "2024-11-06T20:09:58.642Z" }, - { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213, upload-time = "2024-11-06T20:10:00.867Z" }, - { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734, upload-time = "2024-11-06T20:10:03.361Z" }, - { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052, upload-time = "2024-11-06T20:10:05.179Z" }, - { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, - { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, - { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, - { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, - { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, - { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, - { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, - { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, - { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, - { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, - { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, - { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, - { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, - { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, - { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, - { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, - { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, - { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, - { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, - { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, - { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, - { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, - { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, - { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, -] - -[[package]] -name = "requests" -version = "2.32.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, -] - -[[package]] -name = "rich" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, -] - -[[package]] -name = "rich-toolkit" -version = "0.14.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/7a/cb48b7024b247631ce39b1f14a0f1abedf311fb27b892b0e0387d809d4b5/rich_toolkit-0.14.7.tar.gz", hash = "sha256:6cca5a68850cc5778915f528eb785662c27ba3b4b2624612cce8340fa9701c5e", size = 104977, upload-time = "2025-05-27T15:48:09.377Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/2e/95fde5b818dac9a37683ea064096323f593442d0f6358923c5f635974393/rich_toolkit-0.14.7-py3-none-any.whl", hash = "sha256:def05cc6e0f1176d6263b6a26648f16a62c4563b277ca2f8538683acdba1e0da", size = 24870, upload-time = "2025-05-27T15:48:07.942Z" }, -] - -[[package]] -name = "rlp" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/2d/439b0728a92964a04d9c88ea1ca9ebb128893fbbd5834faa31f987f2fd4c/rlp-4.1.0.tar.gz", hash = "sha256:be07564270a96f3e225e2c107db263de96b5bc1f27722d2855bd3459a08e95a9", size = 33429, upload-time = "2025-02-04T22:05:59.089Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/fb/e4c0ced9893b84ac95b7181d69a9786ce5879aeb3bbbcbba80a164f85d6a/rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f", size = 19973, upload-time = "2025-02-04T22:05:57.05Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[package]] -name = "six" -version = "1.17.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/94/e7/b2c673351809dca68a0e064b6af791aa332cf192da575fd474ed7d6f16a2/six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81", size = 34031, upload-time = "2024-12-04T17:35:28.174Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b7/ce/149a00dd41f10bc29e5921b496af8b574d8413afcd5e30dfa0ed46c2cc5e/six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274", size = 11050, upload-time = "2024-12-04T17:35:26.475Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "solana" -version = "0.36.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "construct-typing" }, - { name = "httpx" }, - { name = "solders" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/05/92/c55cd7258699d8536d5f7ed6b8f9b3fbeebd340373f9ec493a67a934b6d2/solana-0.36.7.tar.gz", hash = "sha256:71def6a0e54ed38b232e8778493878f7621bed34aa932770189dcbce6e0390d3", size = 52344, upload-time = "2025-06-05T03:45:15.295Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f6/63/f2e252d9d41d38686b3596989423c892b361857f63f6124e51a1b8c15255/solana-0.36.7-py3-none-any.whl", hash = "sha256:7f3200d4c33c67aa23c39b1141fb9487a0a551edb26e8d3fe22d8156d2ed58df", size = 62490, upload-time = "2025-06-05T03:45:14.248Z" }, -] - -[[package]] -name = "solders" -version = "0.26.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "jsonalias" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/87/96/23ad2e43e2676b78834064fe051e3db3ce1899336ecd4797f92fcd06113a/solders-0.26.0.tar.gz", hash = "sha256:057533892d6fa432c1ce1e2f5e3428802964666c10b57d3d1bcaab86295f046c", size = 181123, upload-time = "2025-02-18T19:23:57.734Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a5/ce/58bbb4d2c696e770cdd37e5f6dc2891ef7610c0c085bf400f9c42dcff1ad/solders-0.26.0-cp37-abi3-macosx_10_12_x86_64.macosx_11_0_arm64.macosx_10_12_universal2.whl", hash = "sha256:9c1a0ef5daa1a05934af5fb6e7e32eab7c42cede406c80067fee006f461ffc4a", size = 24344472, upload-time = "2025-02-18T19:23:30.273Z" }, - { url = "https://files.pythonhosted.org/packages/5a/35/221cec0e5900c2202833e7e9110c3405a2d96ed25e110b247f88b8782e29/solders-0.26.0-cp37-abi3-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:1b964efbd7c0b38aef3bf4293ea5938517ae649b9a23e7cd147d889931775aab", size = 6674734, upload-time = "2025-02-18T19:23:35.15Z" }, - { url = "https://files.pythonhosted.org/packages/41/33/d17b7dbc92672351d59fc65cdb93b8924fc682deba09f6d96f25440187ae/solders-0.26.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36e6a769c5298b887b7588edb171d93709a89302aef75913fe893d11c653739d", size = 13472961, upload-time = "2025-02-18T19:23:38.582Z" }, - { url = "https://files.pythonhosted.org/packages/bb/e7/533367d815ab000587ccc37d89e154132f63347f02dcaaac5df72bd851de/solders-0.26.0-cp37-abi3-manylinux_2_28_aarch64.whl", hash = "sha256:b3cc55b971ec6ed1b4466fa7e7e09eee9baba492b8cd9e3204e3e1a0c5a0c4aa", size = 6886198, upload-time = "2025-02-18T19:23:41.453Z" }, - { url = "https://files.pythonhosted.org/packages/52/e0/ab41ab3df5fdf3b0e55613be93a43c2fe58b15a6ea8ceca26d3fba02e3c6/solders-0.26.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3e3973074c17265921c70246a17bcf80972c5b96a3e1ed7f5049101f11865092", size = 7319170, upload-time = "2025-02-18T19:23:43.758Z" }, - { url = "https://files.pythonhosted.org/packages/7d/34/5174ce592607e0ac020aff203217f2f113a55eec49af3db12945fea42d89/solders-0.26.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:59b52419452602f697e659199a25acacda8365971c376ef3c0687aecdd929e07", size = 7134977, upload-time = "2025-02-18T19:23:46.157Z" }, - { url = "https://files.pythonhosted.org/packages/ba/5e/822faabda0d473c29bdf59fe8869a411fd436af8ca6f5d6e89f7513f682f/solders-0.26.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:5946ec3f2a340afa9ce5c2b8ab628ae1dea2ad2235551b1297cafdd7e3e5c51a", size = 6984222, upload-time = "2025-02-18T19:23:49.429Z" }, - { url = "https://files.pythonhosted.org/packages/23/e8/dc992f677762ea2de44b7768120d95887ef39fab10d6f29fb53e6a9882c1/solders-0.26.0-cp37-abi3-win_amd64.whl", hash = "sha256:5466616610170aab08c627ae01724e425bcf90085bc574da682e9f3bd954900b", size = 5480492, upload-time = "2025-02-18T19:23:53.285Z" }, -] - -[[package]] -name = "starlette" -version = "0.46.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, -] - -[[package]] -name = "toolz" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790, upload-time = "2024-10-04T16:17:04.001Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383, upload-time = "2024-10-04T16:17:01.533Z" }, -] - -[[package]] -name = "typer" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, -] - -[[package]] -name = "types-requests" -version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/7f/73b3a04a53b0fd2a911d4ec517940ecd6600630b559e4505cc7b68beb5a0/types_requests-2.32.4.20250611.tar.gz", hash = "sha256:741c8777ed6425830bf51e54d6abe245f79b4dcb9019f1622b773463946bf826", size = 23118, upload-time = "2025-06-11T03:11:41.272Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/ea/0be9258c5a4fa1ba2300111aa5a0767ee6d18eb3fd20e91616c12082284d/types_requests-2.32.4.20250611-py3-none-any.whl", hash = "sha256:ad2fe5d3b0cb3c2c902c8815a70e7fb2302c4b8c1f77bdcd738192cdb3878072", size = 20643, upload-time = "2025-06-11T03:11:40.186Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, -] - -[[package]] -name = "urllib3" -version = "2.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/aa/63/e53da845320b757bf29ef6a9062f5c669fe997973f966045cb019c3f4b66/urllib3-2.3.0.tar.gz", hash = "sha256:f8c5449b3cf0861679ce7e0503c7b44b5ec981bec0d1d3795a07f1ba96f0204d", size = 307268, upload-time = "2024-12-22T07:47:30.032Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c8/19/4ec628951a74043532ca2cf5d97b7b14863931476d117c471e8e2b1eb39f/urllib3-2.3.0-py3-none-any.whl", hash = "sha256:1cee9ad369867bfdbbb48b7dd50374c0967a0bb7710050facf0dd6911440e3df", size = 128369, upload-time = "2024-12-22T07:47:28.074Z" }, -] - -[[package]] -name = "uvicorn" -version = "0.34.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631, upload-time = "2025-06-01T07:48:17.531Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431, upload-time = "2025-06-01T07:48:15.664Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, - { url = "https://files.pythonhosted.org/packages/35/5a/62d5800358a78cc25c8a6c72ef8b10851bdb8cca22e14d9c74167b7f86da/uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d", size = 801898, upload-time = "2024-10-14T23:37:22.663Z" }, - { url = "https://files.pythonhosted.org/packages/f3/96/63695e0ebd7da6c741ccd4489b5947394435e198a1382349c17b1146bb97/uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26", size = 3827735, upload-time = "2024-10-14T23:37:25.129Z" }, - { url = "https://files.pythonhosted.org/packages/61/e0/f0f8ec84979068ffae132c58c79af1de9cceeb664076beea86d941af1a30/uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb", size = 3825126, upload-time = "2024-10-14T23:37:27.59Z" }, - { url = "https://files.pythonhosted.org/packages/bf/fe/5e94a977d058a54a19df95f12f7161ab6e323ad49f4dabc28822eb2df7ea/uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f", size = 3705789, upload-time = "2024-10-14T23:37:29.385Z" }, - { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523, upload-time = "2024-10-14T23:37:32.048Z" }, - { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410, upload-time = "2024-10-14T23:37:33.612Z" }, - { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476, upload-time = "2024-10-14T23:37:36.11Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855, upload-time = "2024-10-14T23:37:37.683Z" }, - { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185, upload-time = "2024-10-14T23:37:40.226Z" }, - { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256, upload-time = "2024-10-14T23:37:42.839Z" }, - { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323, upload-time = "2024-10-14T23:37:45.337Z" }, - { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284, upload-time = "2024-10-14T23:37:47.833Z" }, - { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349, upload-time = "2024-10-14T23:37:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089, upload-time = "2024-10-14T23:37:51.703Z" }, - { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770, upload-time = "2024-10-14T23:37:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321, upload-time = "2024-10-14T23:37:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022, upload-time = "2024-10-14T23:37:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" }, - { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" }, - { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" }, - { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" }, - { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" }, - { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" }, -] - -[[package]] -name = "waitress" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/bf/cb/04ddb054f45faa306a230769e868c28b8065ea196891f09004ebace5b184/waitress-3.0.2.tar.gz", hash = "sha256:682aaaf2af0c44ada4abfb70ded36393f0e307f4ab9456a215ce0020baefc31f", size = 179901, upload-time = "2024-11-16T20:02:35.195Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/57/a27182528c90ef38d82b636a11f606b0cbb0e17588ed205435f8affe3368/waitress-3.0.2-py3-none-any.whl", hash = "sha256:c56d67fd6e87c2ee598b76abdd4e96cfad1f24cacdea5078d382b1f9d7b5ed2e", size = 56232, upload-time = "2024-11-16T20:02:33.858Z" }, -] - -[[package]] -name = "watchfiles" -version = "1.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/e2/8ed598c42057de7aa5d97c472254af4906ff0a59a66699d426fc9ef795d7/watchfiles-1.0.5.tar.gz", hash = "sha256:b7529b5dcc114679d43827d8c35a07c493ad6f083633d573d81c660abc5979e9", size = 94537, upload-time = "2025-04-08T10:36:26.722Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/4d/d02e6ea147bb7fff5fd109c694a95109612f419abed46548a930e7f7afa3/watchfiles-1.0.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5c40fe7dd9e5f81e0847b1ea64e1f5dd79dd61afbedb57759df06767ac719b40", size = 405632, upload-time = "2025-04-08T10:34:41.832Z" }, - { url = "https://files.pythonhosted.org/packages/60/31/9ee50e29129d53a9a92ccf1d3992751dc56fc3c8f6ee721be1c7b9c81763/watchfiles-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c0db396e6003d99bb2d7232c957b5f0b5634bbd1b24e381a5afcc880f7373fb", size = 395734, upload-time = "2025-04-08T10:34:44.236Z" }, - { url = "https://files.pythonhosted.org/packages/ad/8c/759176c97195306f028024f878e7f1c776bda66ccc5c68fa51e699cf8f1d/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b551d4fb482fc57d852b4541f911ba28957d051c8776e79c3b4a51eb5e2a1b11", size = 455008, upload-time = "2025-04-08T10:34:45.617Z" }, - { url = "https://files.pythonhosted.org/packages/55/1a/5e977250c795ee79a0229e3b7f5e3a1b664e4e450756a22da84d2f4979fe/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:830aa432ba5c491d52a15b51526c29e4a4b92bf4f92253787f9726fe01519487", size = 459029, upload-time = "2025-04-08T10:34:46.814Z" }, - { url = "https://files.pythonhosted.org/packages/e6/17/884cf039333605c1d6e296cf5be35fad0836953c3dfd2adb71b72f9dbcd0/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a16512051a822a416b0d477d5f8c0e67b67c1a20d9acecb0aafa3aa4d6e7d256", size = 488916, upload-time = "2025-04-08T10:34:48.571Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e0/bcb6e64b45837056c0a40f3a2db3ef51c2ced19fda38484fa7508e00632c/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe0cbc787770e52a96c6fda6726ace75be7f840cb327e1b08d7d54eadc3bc85", size = 523763, upload-time = "2025-04-08T10:34:50.268Z" }, - { url = "https://files.pythonhosted.org/packages/24/e9/f67e9199f3bb35c1837447ecf07e9830ec00ff5d35a61e08c2cd67217949/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d363152c5e16b29d66cbde8fa614f9e313e6f94a8204eaab268db52231fe5358", size = 502891, upload-time = "2025-04-08T10:34:51.419Z" }, - { url = "https://files.pythonhosted.org/packages/23/ed/a6cf815f215632f5c8065e9c41fe872025ffea35aa1f80499f86eae922db/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee32c9a9bee4d0b7bd7cbeb53cb185cf0b622ac761efaa2eba84006c3b3a614", size = 454921, upload-time = "2025-04-08T10:34:52.67Z" }, - { url = "https://files.pythonhosted.org/packages/92/4c/e14978599b80cde8486ab5a77a821e8a982ae8e2fcb22af7b0886a033ec8/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29c7fd632ccaf5517c16a5188e36f6612d6472ccf55382db6c7fe3fcccb7f59f", size = 631422, upload-time = "2025-04-08T10:34:53.985Z" }, - { url = "https://files.pythonhosted.org/packages/b2/1a/9263e34c3458f7614b657f974f4ee61fd72f58adce8b436e16450e054efd/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e637810586e6fe380c8bc1b3910accd7f1d3a9a7262c8a78d4c8fb3ba6a2b3d", size = 625675, upload-time = "2025-04-08T10:34:55.173Z" }, - { url = "https://files.pythonhosted.org/packages/96/1f/1803a18bd6ab04a0766386a19bcfe64641381a04939efdaa95f0e3b0eb58/watchfiles-1.0.5-cp310-cp310-win32.whl", hash = "sha256:cd47d063fbeabd4c6cae1d4bcaa38f0902f8dc5ed168072874ea11d0c7afc1ff", size = 277921, upload-time = "2025-04-08T10:34:56.318Z" }, - { url = "https://files.pythonhosted.org/packages/c2/3b/29a89de074a7d6e8b4dc67c26e03d73313e4ecf0d6e97e942a65fa7c195e/watchfiles-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:86c0df05b47a79d80351cd179893f2f9c1b1cae49d96e8b3290c7f4bd0ca0a92", size = 291526, upload-time = "2025-04-08T10:34:57.95Z" }, - { url = "https://files.pythonhosted.org/packages/39/f4/41b591f59021786ef517e1cdc3b510383551846703e03f204827854a96f8/watchfiles-1.0.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:237f9be419e977a0f8f6b2e7b0475ababe78ff1ab06822df95d914a945eac827", size = 405336, upload-time = "2025-04-08T10:34:59.359Z" }, - { url = "https://files.pythonhosted.org/packages/ae/06/93789c135be4d6d0e4f63e96eea56dc54050b243eacc28439a26482b5235/watchfiles-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0da39ff917af8b27a4bdc5a97ac577552a38aac0d260a859c1517ea3dc1a7c4", size = 395977, upload-time = "2025-04-08T10:35:00.522Z" }, - { url = "https://files.pythonhosted.org/packages/d2/db/1cd89bd83728ca37054512d4d35ab69b5f12b8aa2ac9be3b0276b3bf06cc/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cfcb3952350e95603f232a7a15f6c5f86c5375e46f0bd4ae70d43e3e063c13d", size = 455232, upload-time = "2025-04-08T10:35:01.698Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/d8a4d44ffe960517e487c9c04f77b06b8abf05eb680bed71c82b5f2cad62/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b2dddba7a4e6151384e252a5632efcaa9bc5d1c4b567f3cb621306b2ca9f63", size = 459151, upload-time = "2025-04-08T10:35:03.358Z" }, - { url = "https://files.pythonhosted.org/packages/6c/da/267a1546f26465dead1719caaba3ce660657f83c9d9c052ba98fb8856e13/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95cf944fcfc394c5f9de794ce581914900f82ff1f855326f25ebcf24d5397418", size = 489054, upload-time = "2025-04-08T10:35:04.561Z" }, - { url = "https://files.pythonhosted.org/packages/b1/31/33850dfd5c6efb6f27d2465cc4c6b27c5a6f5ed53c6fa63b7263cf5f60f6/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecf6cd9f83d7c023b1aba15d13f705ca7b7d38675c121f3cc4a6e25bd0857ee9", size = 523955, upload-time = "2025-04-08T10:35:05.786Z" }, - { url = "https://files.pythonhosted.org/packages/09/84/b7d7b67856efb183a421f1416b44ca975cb2ea6c4544827955dfb01f7dc2/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:852de68acd6212cd6d33edf21e6f9e56e5d98c6add46f48244bd479d97c967c6", size = 502234, upload-time = "2025-04-08T10:35:07.187Z" }, - { url = "https://files.pythonhosted.org/packages/71/87/6dc5ec6882a2254cfdd8b0718b684504e737273903b65d7338efaba08b52/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5730f3aa35e646103b53389d5bc77edfbf578ab6dab2e005142b5b80a35ef25", size = 454750, upload-time = "2025-04-08T10:35:08.859Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6c/3786c50213451a0ad15170d091570d4a6554976cf0df19878002fc96075a/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:18b3bd29954bc4abeeb4e9d9cf0b30227f0f206c86657674f544cb032296acd5", size = 631591, upload-time = "2025-04-08T10:35:10.64Z" }, - { url = "https://files.pythonhosted.org/packages/1b/b3/1427425ade4e359a0deacce01a47a26024b2ccdb53098f9d64d497f6684c/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ba5552a1b07c8edbf197055bc9d518b8f0d98a1c6a73a293bc0726dce068ed01", size = 625370, upload-time = "2025-04-08T10:35:12.412Z" }, - { url = "https://files.pythonhosted.org/packages/15/ba/f60e053b0b5b8145d682672024aa91370a29c5c921a88977eb565de34086/watchfiles-1.0.5-cp311-cp311-win32.whl", hash = "sha256:2f1fefb2e90e89959447bc0420fddd1e76f625784340d64a2f7d5983ef9ad246", size = 277791, upload-time = "2025-04-08T10:35:13.719Z" }, - { url = "https://files.pythonhosted.org/packages/50/ed/7603c4e164225c12c0d4e8700b64bb00e01a6c4eeea372292a3856be33a4/watchfiles-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:b6e76ceb1dd18c8e29c73f47d41866972e891fc4cc7ba014f487def72c1cf096", size = 291622, upload-time = "2025-04-08T10:35:15.071Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c2/99bb7c96b4450e36877fde33690ded286ff555b5a5c1d925855d556968a1/watchfiles-1.0.5-cp311-cp311-win_arm64.whl", hash = "sha256:266710eb6fddc1f5e51843c70e3bebfb0f5e77cf4f27129278c70554104d19ed", size = 283699, upload-time = "2025-04-08T10:35:16.732Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8c/4f0b9bdb75a1bfbd9c78fad7d8854369283f74fe7cf03eb16be77054536d/watchfiles-1.0.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5eb568c2aa6018e26da9e6c86f3ec3fd958cee7f0311b35c2630fa4217d17f2", size = 401511, upload-time = "2025-04-08T10:35:17.956Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4e/7e15825def77f8bd359b6d3f379f0c9dac4eb09dd4ddd58fd7d14127179c/watchfiles-1.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a04059f4923ce4e856b4b4e5e783a70f49d9663d22a4c3b3298165996d1377f", size = 392715, upload-time = "2025-04-08T10:35:19.202Z" }, - { url = "https://files.pythonhosted.org/packages/58/65/b72fb817518728e08de5840d5d38571466c1b4a3f724d190cec909ee6f3f/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e380c89983ce6e6fe2dd1e1921b9952fb4e6da882931abd1824c092ed495dec", size = 454138, upload-time = "2025-04-08T10:35:20.586Z" }, - { url = "https://files.pythonhosted.org/packages/3e/a4/86833fd2ea2e50ae28989f5950b5c3f91022d67092bfec08f8300d8b347b/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe43139b2c0fdc4a14d4f8d5b5d967f7a2777fd3d38ecf5b1ec669b0d7e43c21", size = 458592, upload-time = "2025-04-08T10:35:21.87Z" }, - { url = "https://files.pythonhosted.org/packages/38/7e/42cb8df8be9a37e50dd3a818816501cf7a20d635d76d6bd65aae3dbbff68/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee0822ce1b8a14fe5a066f93edd20aada932acfe348bede8aa2149f1a4489512", size = 487532, upload-time = "2025-04-08T10:35:23.143Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/13d26721c85d7f3df6169d8b495fcac8ab0dc8f0945ebea8845de4681dab/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0dbcb1c2d8f2ab6e0a81c6699b236932bd264d4cef1ac475858d16c403de74d", size = 522865, upload-time = "2025-04-08T10:35:24.702Z" }, - { url = "https://files.pythonhosted.org/packages/a1/0d/7f9ae243c04e96c5455d111e21b09087d0eeaf9a1369e13a01c7d3d82478/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2014a2b18ad3ca53b1f6c23f8cd94a18ce930c1837bd891262c182640eb40a6", size = 499887, upload-time = "2025-04-08T10:35:25.969Z" }, - { url = "https://files.pythonhosted.org/packages/8e/0f/a257766998e26aca4b3acf2ae97dff04b57071e991a510857d3799247c67/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6ae86d5cb647bf58f9f655fcf577f713915a5d69057a0371bc257e2553234", size = 454498, upload-time = "2025-04-08T10:35:27.353Z" }, - { url = "https://files.pythonhosted.org/packages/81/79/8bf142575a03e0af9c3d5f8bcae911ee6683ae93a625d349d4ecf4c8f7df/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1a7bac2bde1d661fb31f4d4e8e539e178774b76db3c2c17c4bb3e960a5de07a2", size = 630663, upload-time = "2025-04-08T10:35:28.685Z" }, - { url = "https://files.pythonhosted.org/packages/f1/80/abe2e79f610e45c63a70d271caea90c49bbf93eb00fa947fa9b803a1d51f/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ab626da2fc1ac277bbf752446470b367f84b50295264d2d313e28dc4405d663", size = 625410, upload-time = "2025-04-08T10:35:30.42Z" }, - { url = "https://files.pythonhosted.org/packages/91/6f/bc7fbecb84a41a9069c2c6eb6319f7f7df113adf113e358c57fc1aff7ff5/watchfiles-1.0.5-cp312-cp312-win32.whl", hash = "sha256:9f4571a783914feda92018ef3901dab8caf5b029325b5fe4558c074582815249", size = 277965, upload-time = "2025-04-08T10:35:32.023Z" }, - { url = "https://files.pythonhosted.org/packages/99/a5/bf1c297ea6649ec59e935ab311f63d8af5faa8f0b86993e3282b984263e3/watchfiles-1.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:360a398c3a19672cf93527f7e8d8b60d8275119c5d900f2e184d32483117a705", size = 291693, upload-time = "2025-04-08T10:35:33.225Z" }, - { url = "https://files.pythonhosted.org/packages/7f/7b/fd01087cc21db5c47e5beae507b87965db341cce8a86f9eb12bf5219d4e0/watchfiles-1.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:1a2902ede862969077b97523987c38db28abbe09fb19866e711485d9fbf0d417", size = 283287, upload-time = "2025-04-08T10:35:34.568Z" }, - { url = "https://files.pythonhosted.org/packages/c7/62/435766874b704f39b2fecd8395a29042db2b5ec4005bd34523415e9bd2e0/watchfiles-1.0.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0b289572c33a0deae62daa57e44a25b99b783e5f7aed81b314232b3d3c81a11d", size = 401531, upload-time = "2025-04-08T10:35:35.792Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a6/e52a02c05411b9cb02823e6797ef9bbba0bfaf1bb627da1634d44d8af833/watchfiles-1.0.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a056c2f692d65bf1e99c41045e3bdcaea3cb9e6b5a53dcaf60a5f3bd95fc9763", size = 392417, upload-time = "2025-04-08T10:35:37.048Z" }, - { url = "https://files.pythonhosted.org/packages/3f/53/c4af6819770455932144e0109d4854437769672d7ad897e76e8e1673435d/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9dca99744991fc9850d18015c4f0438865414e50069670f5f7eee08340d8b40", size = 453423, upload-time = "2025-04-08T10:35:38.357Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d1/8e88df58bbbf819b8bc5cfbacd3c79e01b40261cad0fc84d1e1ebd778a07/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:894342d61d355446d02cd3988a7326af344143eb33a2fd5d38482a92072d9563", size = 458185, upload-time = "2025-04-08T10:35:39.708Z" }, - { url = "https://files.pythonhosted.org/packages/ff/70/fffaa11962dd5429e47e478a18736d4e42bec42404f5ee3b92ef1b87ad60/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab44e1580924d1ffd7b3938e02716d5ad190441965138b4aa1d1f31ea0877f04", size = 486696, upload-time = "2025-04-08T10:35:41.469Z" }, - { url = "https://files.pythonhosted.org/packages/39/db/723c0328e8b3692d53eb273797d9a08be6ffb1d16f1c0ba2bdbdc2a3852c/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6f9367b132078b2ceb8d066ff6c93a970a18c3029cea37bfd7b2d3dd2e5db8f", size = 522327, upload-time = "2025-04-08T10:35:43.289Z" }, - { url = "https://files.pythonhosted.org/packages/cd/05/9fccc43c50c39a76b68343484b9da7b12d42d0859c37c61aec018c967a32/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2e55a9b162e06e3f862fb61e399fe9f05d908d019d87bf5b496a04ef18a970a", size = 499741, upload-time = "2025-04-08T10:35:44.574Z" }, - { url = "https://files.pythonhosted.org/packages/23/14/499e90c37fa518976782b10a18b18db9f55ea73ca14641615056f8194bb3/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0125f91f70e0732a9f8ee01e49515c35d38ba48db507a50c5bdcad9503af5827", size = 453995, upload-time = "2025-04-08T10:35:46.336Z" }, - { url = "https://files.pythonhosted.org/packages/61/d9/f75d6840059320df5adecd2c687fbc18960a7f97b55c300d20f207d48aef/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:13bb21f8ba3248386337c9fa51c528868e6c34a707f729ab041c846d52a0c69a", size = 629693, upload-time = "2025-04-08T10:35:48.161Z" }, - { url = "https://files.pythonhosted.org/packages/fc/17/180ca383f5061b61406477218c55d66ec118e6c0c51f02d8142895fcf0a9/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:839ebd0df4a18c5b3c1b890145b5a3f5f64063c2a0d02b13c76d78fe5de34936", size = 624677, upload-time = "2025-04-08T10:35:49.65Z" }, - { url = "https://files.pythonhosted.org/packages/bf/15/714d6ef307f803f236d69ee9d421763707899d6298d9f3183e55e366d9af/watchfiles-1.0.5-cp313-cp313-win32.whl", hash = "sha256:4a8ec1e4e16e2d5bafc9ba82f7aaecfeec990ca7cd27e84fb6f191804ed2fcfc", size = 277804, upload-time = "2025-04-08T10:35:51.093Z" }, - { url = "https://files.pythonhosted.org/packages/a8/b4/c57b99518fadf431f3ef47a610839e46e5f8abf9814f969859d1c65c02c7/watchfiles-1.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:f436601594f15bf406518af922a89dcaab416568edb6f65c4e5bbbad1ea45c11", size = 291087, upload-time = "2025-04-08T10:35:52.458Z" }, - { url = "https://files.pythonhosted.org/packages/1a/03/81f9fcc3963b3fc415cd4b0b2b39ee8cc136c42fb10a36acf38745e9d283/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f59b870db1f1ae5a9ac28245707d955c8721dd6565e7f411024fa374b5362d1d", size = 405947, upload-time = "2025-04-08T10:36:13.721Z" }, - { url = "https://files.pythonhosted.org/packages/54/97/8c4213a852feb64807ec1d380f42d4fc8bfaef896bdbd94318f8fd7f3e4e/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9475b0093767e1475095f2aeb1d219fb9664081d403d1dff81342df8cd707034", size = 397276, upload-time = "2025-04-08T10:36:15.131Z" }, - { url = "https://files.pythonhosted.org/packages/78/12/d4464d19860cb9672efa45eec1b08f8472c478ed67dcd30647c51ada7aef/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc533aa50664ebd6c628b2f30591956519462f5d27f951ed03d6c82b2dfd9965", size = 455550, upload-time = "2025-04-08T10:36:16.635Z" }, - { url = "https://files.pythonhosted.org/packages/90/fb/b07bcdf1034d8edeaef4c22f3e9e3157d37c5071b5f9492ffdfa4ad4bed7/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed1cd825158dcaae36acce7b2db33dcbfd12b30c34317a88b8ed80f0541cc57", size = 455542, upload-time = "2025-04-08T10:36:18.655Z" }, -] - -[[package]] -name = "web3" -version = "7.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "eth-abi" }, - { name = "eth-account" }, - { name = "eth-hash", extra = ["pycryptodome"] }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "pyunormalize" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "requests" }, - { name = "types-requests" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/19/c1e213dd87ead2ace55ff1dd179df6050bcf5d9006440c9153969c7d6863/web3-7.10.0.tar.gz", hash = "sha256:0cace05ea14f800a4497649ecd99332ca4e85c8a90ea577e05ae909cb08902b9", size = 2193725, upload-time = "2025-03-27T17:02:27.919Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4c/c5/a8e25e3ff51c7cd6d2bdecf75da2afb2923b29eba28e5dfe4fde72ad2322/web3-7.10.0-py3-none-any.whl", hash = "sha256:06fcab920554450e9f7d108da5e6b9d29c0d1a981a59a5551cc82d2cb2233b34", size = 1365880, upload-time = "2025-03-27T17:02:25.04Z" }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, - { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, - { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, - { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, - { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, - { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, - { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, - { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, - { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - -[[package]] -name = "werkzeug" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, -] - -[[package]] -name = "x402" -version = "1.0.0" -source = { editable = "../../../../../python/legacy" } -dependencies = [ - { name = "eth-account" }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "fastapi", extra = ["standard"] }, - { name = "flask" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "web3" }, -] - -[package.metadata] -requires-dist = [ - { name = "eth-account", specifier = ">=0.13.7" }, - { name = "eth-typing", specifier = ">=4.0.0" }, - { name = "eth-utils", specifier = ">=3.0.0" }, - { name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" }, - { name = "flask", specifier = ">=3.0.0" }, - { name = "pydantic", specifier = ">=2.10.3" }, - { name = "pydantic-settings", specifier = ">=2.2.1" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "web3", specifier = ">=6.0.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.5" }, - { name = "pytest-asyncio", specifier = ">=1.0.0" }, - { name = "ruff", specifier = ">=0.11.9" }, -] - -[[package]] -name = "x402-mainnet-example" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "cdp-sdk" }, - { name = "flask" }, - { name = "python-dotenv" }, - { name = "waitress" }, - { name = "x402" }, -] - -[package.metadata] -requires-dist = [ - { name = "cdp-sdk", specifier = ">=1.15.0" }, - { name = "flask", specifier = ">=3.1.1" }, - { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "waitress", specifier = ">=2.1.2" }, - { name = "x402", editable = "../../../../../python/legacy" }, -] - -[[package]] -name = "yarl" -version = "1.20.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/65/7fed0d774abf47487c64be14e9223749468922817b5e8792b8a64792a1bb/yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4", size = 132910, upload-time = "2025-06-10T00:42:31.108Z" }, - { url = "https://files.pythonhosted.org/packages/8a/7b/988f55a52da99df9e56dc733b8e4e5a6ae2090081dc2754fc8fd34e60aa0/yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a", size = 90644, upload-time = "2025-06-10T00:42:33.851Z" }, - { url = "https://files.pythonhosted.org/packages/f7/de/30d98f03e95d30c7e3cc093759982d038c8833ec2451001d45ef4854edc1/yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed", size = 89322, upload-time = "2025-06-10T00:42:35.688Z" }, - { url = "https://files.pythonhosted.org/packages/e0/7a/f2f314f5ebfe9200724b0b748de2186b927acb334cf964fd312eb86fc286/yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e", size = 323786, upload-time = "2025-06-10T00:42:37.817Z" }, - { url = "https://files.pythonhosted.org/packages/15/3f/718d26f189db96d993d14b984ce91de52e76309d0fd1d4296f34039856aa/yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73", size = 319627, upload-time = "2025-06-10T00:42:39.937Z" }, - { url = "https://files.pythonhosted.org/packages/a5/76/8fcfbf5fa2369157b9898962a4a7d96764b287b085b5b3d9ffae69cdefd1/yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e", size = 339149, upload-time = "2025-06-10T00:42:42.627Z" }, - { url = "https://files.pythonhosted.org/packages/3c/95/d7fc301cc4661785967acc04f54a4a42d5124905e27db27bb578aac49b5c/yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8", size = 333327, upload-time = "2025-06-10T00:42:44.842Z" }, - { url = "https://files.pythonhosted.org/packages/65/94/e21269718349582eee81efc5c1c08ee71c816bfc1585b77d0ec3f58089eb/yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23", size = 326054, upload-time = "2025-06-10T00:42:47.149Z" }, - { url = "https://files.pythonhosted.org/packages/32/ae/8616d1f07853704523519f6131d21f092e567c5af93de7e3e94b38d7f065/yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70", size = 315035, upload-time = "2025-06-10T00:42:48.852Z" }, - { url = "https://files.pythonhosted.org/packages/48/aa/0ace06280861ef055855333707db5e49c6e3a08840a7ce62682259d0a6c0/yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb", size = 338962, upload-time = "2025-06-10T00:42:51.024Z" }, - { url = "https://files.pythonhosted.org/packages/20/52/1e9d0e6916f45a8fb50e6844f01cb34692455f1acd548606cbda8134cd1e/yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2", size = 335399, upload-time = "2025-06-10T00:42:53.007Z" }, - { url = "https://files.pythonhosted.org/packages/f2/65/60452df742952c630e82f394cd409de10610481d9043aa14c61bf846b7b1/yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30", size = 338649, upload-time = "2025-06-10T00:42:54.964Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f5/6cd4ff38dcde57a70f23719a838665ee17079640c77087404c3d34da6727/yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309", size = 358563, upload-time = "2025-06-10T00:42:57.28Z" }, - { url = "https://files.pythonhosted.org/packages/d1/90/c42eefd79d0d8222cb3227bdd51b640c0c1d0aa33fe4cc86c36eccba77d3/yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24", size = 357609, upload-time = "2025-06-10T00:42:59.055Z" }, - { url = "https://files.pythonhosted.org/packages/03/c8/cea6b232cb4617514232e0f8a718153a95b5d82b5290711b201545825532/yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13", size = 350224, upload-time = "2025-06-10T00:43:01.248Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a3/eaa0ab9712f1f3d01faf43cf6f1f7210ce4ea4a7e9b28b489a2261ca8db9/yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8", size = 81753, upload-time = "2025-06-10T00:43:03.486Z" }, - { url = "https://files.pythonhosted.org/packages/8f/34/e4abde70a9256465fe31c88ed02c3f8502b7b5dead693a4f350a06413f28/yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16", size = 86817, upload-time = "2025-06-10T00:43:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b1/18/893b50efc2350e47a874c5c2d67e55a0ea5df91186b2a6f5ac52eff887cd/yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e", size = 133833, upload-time = "2025-06-10T00:43:07.393Z" }, - { url = "https://files.pythonhosted.org/packages/89/ed/b8773448030e6fc47fa797f099ab9eab151a43a25717f9ac043844ad5ea3/yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b", size = 91070, upload-time = "2025-06-10T00:43:09.538Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e3/409bd17b1e42619bf69f60e4f031ce1ccb29bd7380117a55529e76933464/yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b", size = 89818, upload-time = "2025-06-10T00:43:11.575Z" }, - { url = "https://files.pythonhosted.org/packages/f8/77/64d8431a4d77c856eb2d82aa3de2ad6741365245a29b3a9543cd598ed8c5/yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4", size = 347003, upload-time = "2025-06-10T00:43:14.088Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d2/0c7e4def093dcef0bd9fa22d4d24b023788b0a33b8d0088b51aa51e21e99/yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1", size = 336537, upload-time = "2025-06-10T00:43:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f3/fc514f4b2cf02cb59d10cbfe228691d25929ce8f72a38db07d3febc3f706/yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833", size = 362358, upload-time = "2025-06-10T00:43:18.704Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6d/a313ac8d8391381ff9006ac05f1d4331cee3b1efaa833a53d12253733255/yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d", size = 357362, upload-time = "2025-06-10T00:43:20.888Z" }, - { url = "https://files.pythonhosted.org/packages/00/70/8f78a95d6935a70263d46caa3dd18e1f223cf2f2ff2037baa01a22bc5b22/yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8", size = 348979, upload-time = "2025-06-10T00:43:23.169Z" }, - { url = "https://files.pythonhosted.org/packages/cb/05/42773027968968f4f15143553970ee36ead27038d627f457cc44bbbeecf3/yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf", size = 337274, upload-time = "2025-06-10T00:43:27.111Z" }, - { url = "https://files.pythonhosted.org/packages/05/be/665634aa196954156741ea591d2f946f1b78ceee8bb8f28488bf28c0dd62/yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e", size = 363294, upload-time = "2025-06-10T00:43:28.96Z" }, - { url = "https://files.pythonhosted.org/packages/eb/90/73448401d36fa4e210ece5579895731f190d5119c4b66b43b52182e88cd5/yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389", size = 358169, upload-time = "2025-06-10T00:43:30.701Z" }, - { url = "https://files.pythonhosted.org/packages/c3/b0/fce922d46dc1eb43c811f1889f7daa6001b27a4005587e94878570300881/yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f", size = 362776, upload-time = "2025-06-10T00:43:32.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/0d/b172628fce039dae8977fd22caeff3eeebffd52e86060413f5673767c427/yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845", size = 381341, upload-time = "2025-06-10T00:43:34.543Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9b/5b886d7671f4580209e855974fe1cecec409aa4a89ea58b8f0560dc529b1/yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1", size = 379988, upload-time = "2025-06-10T00:43:36.489Z" }, - { url = "https://files.pythonhosted.org/packages/73/be/75ef5fd0fcd8f083a5d13f78fd3f009528132a1f2a1d7c925c39fa20aa79/yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e", size = 371113, upload-time = "2025-06-10T00:43:38.592Z" }, - { url = "https://files.pythonhosted.org/packages/50/4f/62faab3b479dfdcb741fe9e3f0323e2a7d5cd1ab2edc73221d57ad4834b2/yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773", size = 81485, upload-time = "2025-06-10T00:43:41.038Z" }, - { url = "https://files.pythonhosted.org/packages/f0/09/d9c7942f8f05c32ec72cd5c8e041c8b29b5807328b68b4801ff2511d4d5e/yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e", size = 86686, upload-time = "2025-06-10T00:43:42.692Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, - { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, - { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, - { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, - { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, - { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, - { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, - { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, - { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, - { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, - { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, - { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, - { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, - { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, - { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, - { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, - { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, - { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, - { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, - { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, - { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, - { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, - { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, - { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, - { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, - { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, - { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, - { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, - { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, - { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, - { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, - { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, - { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, - { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, - { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, - { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, - { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, -] diff --git a/examples/python/legacy/servers/advanced/.env-local b/examples/python/legacy/servers/advanced/.env-local deleted file mode 100644 index 3ccb3f00b2..0000000000 --- a/examples/python/legacy/servers/advanced/.env-local +++ /dev/null @@ -1,7 +0,0 @@ -FACILITATOR_URL=https://x402.org/facilitator -NETWORK=base-sepolia -PAY_TO_ADDRESS= - -# required if using the Base mainnet facilitator -CDP_API_KEY_ID="Coinbase Developer Platform Key" -CDP_API_KEY_SECRET="Coinbase Developer Platform Key Secret" \ No newline at end of file diff --git a/examples/python/legacy/servers/advanced/README.md b/examples/python/legacy/servers/advanced/README.md deleted file mode 100644 index eca541841e..0000000000 --- a/examples/python/legacy/servers/advanced/README.md +++ /dev/null @@ -1,245 +0,0 @@ -# x402 Advanced Resource Server Example (Python) - -This is an advanced Python example using FastAPI that demonstrates how to implement paywall functionality without using middleware. This approach is useful for more complex scenarios, such as: - -- Asynchronous payment settlement -- Custom payment validation logic -- Complex routing requirements -- Integration with existing authentication systems - -## Prerequisites - -- Python 3.10+ -- uv ([https://github.com/astral-sh/uv](https://github.com/astral-sh/uv?tab=readme-ov-file#installation)) -- A valid Ethereum address for receiving payments -- Coinbase Developer Platform API Key & Secret (if accepting payments on Base mainnet) - - Get them here: [https://portal.cdp.coinbase.com/projects](https://portal.cdp.coinbase.com/projects) - -## Setup - -1. Copy `.env-local` to `.env` and add your Ethereum address: - -```bash -cp .env-local .env -``` - -2. Install dependencies: -```bash -uv sync -``` - -3. Run the server: -```bash -uv run python main.py -``` - -The server will start on http://localhost:4021 - -## Implementation Overview - -This advanced implementation provides a structured approach to handling payments with: - -1. Helper functions for creating payment requirements and verifying payments -2. Support for delayed payment settlement -3. Dynamic pricing capabilities -4. Multiple payment requirement options -5. Proper error handling and response formatting -6. Integration with the x402 facilitator service - -## Usage examples: - -```python -# USD price (automatically converts to USDC) -payment_req = create_exact_payment_requirements( - price="$0.001", - network="base-sepolia", - resource="https://api.example.com/weather", - description="Weather data access" -) - -# Specific token amount -payment_req = create_exact_payment_requirements( - price=TokenAmount( - amount="1000", - asset=TokenAsset( - address="0x036CbD53842c5426634e7929541eC2318f3dCF7e", - decimals=6, - eip712=EIP712Domain(name="USDC", version="2"), - ), - ), - network="base-sepolia", - resource="https://api.example.com/weather" -) -``` - -### verify_payment() - -Handles payment verification and returns appropriate error responses: - -```python -async def verify_payment( - request: Request, - payment_requirements: list[PaymentRequirements], -) -> tuple[bool, JSONResponse]: -``` - -## Testing the Server - -You can test the server using one of the example Python clients: - -### Using the httpx Client -```bash -cd ../../clients/httpx -# Ensure .env is set up -uv sync -uv run python main.py -``` - -### Using the requests Client -```bash -cd ../../clients/requests -# Ensure .env is set up -uv sync -uv run python main.py -``` - -## Example Endpoints - -The server includes example endpoints that demonstrate different payment scenarios: - -### Delayed Settlement -- `/delayed-settlement` - Demonstrates asynchronous payment processing -- Returns the weather data immediately without waiting for payment settlement -- Processes payment asynchronously in the background using `asyncio.create_task()` -- Useful for scenarios where immediate response is critical and payment settlement can be handled later - -### Dynamic Pricing -- `/dynamic-price` - Shows how to implement variable pricing based on request parameters -- Accepts a `multiplier` query parameter to adjust the base price -- Demonstrates how to calculate and validate payments with dynamic amounts -- Useful for implementing tiered pricing or demand-based pricing models - -### Multiple Payment Requirements -- `/multiple-payment-requirements` - Illustrates how to accept multiple payment options -- Allows clients to pay using different assets (e.g., USDC or custom tokens) -- Supports multiple networks (e.g., Base and Base Sepolia) -- Useful for providing flexibility in payment methods and networks - -## Response Format - -### Payment Required (402) -```json5 -{ - "x402Version": 1, - "error": "X-PAYMENT header is required", - "accepts": [ - { - "scheme": "exact", - "network": "base-sepolia", - "maxAmountRequired": "1000", - "resource": "http://localhost:4021/weather", - "description": "Access to weather data", - "mimeType": "application/json", - "payTo": "0xYourAddress", - "maxTimeoutSeconds": 60, - "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", - "outputSchema": null, - "extra": { - "name": "USD Coin", - "version": "2" - } - } - ] -} -``` - -### Successful Response -```json5 -// Body -{ - "report": { - "weather": "sunny", - "temperature": 70 - } -} -// Headers -{ - "X-PAYMENT-RESPONSE": "..." // Encoded response object -} -``` - -## Extending the Example - -To add more paid endpoints with delayed payment settlement, you can follow this pattern: - -```python -@app.get("/your-endpoint") -async def your_endpoint(request: Request) -> Dict[str, Any]: - resource = str(request.url) - payment_requirements = [ - create_exact_payment_requirements( - price="$0.001", # Your price - network="base-sepolia", # Your network - resource=resource, - description="Description of your resource" - ) - ] - - is_valid, error_response = await verify_payment(request, payment_requirements) - if not is_valid: - raise HTTPException(status_code=402, detail=error_response.body) - - # Return your protected resource immediately - response_data = { - # Your response data - } - - # Process payment asynchronously - async def process_payment_async(): - try: - x_payment = request.headers.get("X-PAYMENT") - if not x_payment: - logger.error("X-PAYMENT header missing in async processing") - return - - decoded_payment_dict = decode_payment(x_payment) - decoded_payment = PaymentPayload(**decoded_payment_dict) - - settle_response = await facilitator.settle(decoded_payment, payment_requirements[0]) - response_header = settle_response_header(settle_response) - - # In a real application, you would store this response header - # and associate it with the payment for later verification - logger.info(f"Payment settled: {response_header}") - except Exception as e: - logger.error(f"Payment settlement failed: {e}") - # In a real application, you would handle the failed payment - # by marking it for retry or notifying the user - - # Start background task - asyncio.create_task(process_payment_async()) - - return response_data -``` - -For endpoints that need to set response headers (like the X-PAYMENT-RESPONSE header), use the `Response` parameter: - -```python -@app.get("/your-endpoint") -async def your_endpoint(request: Request, response: Response) -> Dict[str, Any]: - # ... payment verification logic ... - - # Process payment synchronously - settle_response = await facilitator.settle(decoded_payment, payment_requirements[0]) - response_header = settle_response_header(settle_response) - - # Set the payment response header - response.headers["X-PAYMENT-RESPONSE"] = response_header - - # Return your data - return { - "your": "data" - } -``` - -For dynamic pricing or multiple payment requirements, refer to the `/dynamic-price` and `/multiple-payment-requirements` endpoints in the example code for implementation details. diff --git a/examples/python/legacy/servers/advanced/main.py b/examples/python/legacy/servers/advanced/main.py deleted file mode 100644 index bf3ebd4869..0000000000 --- a/examples/python/legacy/servers/advanced/main.py +++ /dev/null @@ -1,375 +0,0 @@ -import os -import asyncio -import logging -from typing import Any, Dict - -from dotenv import load_dotenv -from fastapi import FastAPI, Request, Response -from fastapi.responses import JSONResponse -from x402.common import process_price_to_atomic_amount, x402_VERSION -from x402.exact import decode_payment -from x402.facilitator import FacilitatorClient, FacilitatorConfig -from x402.encoding import safe_base64_encode -from x402.common import find_matching_payment_requirements -from x402.types import ( - PaymentPayload, - PaymentRequirements, - Price, - SupportedNetworks, - TokenAmount, - TokenAsset, - EIP712Domain, - x402PaymentRequiredResponse, - SettleResponse, -) - -# Load environment variables -load_dotenv() - -# Configure logging -logging.basicConfig(level=logging.INFO) -logger = logging.getLogger(__name__) - -# Get configuration from environment -FACILITATOR_URL = os.getenv("FACILITATOR_URL") -PAY_TO_ADDRESS = os.getenv("PAY_TO_ADDRESS") - -if not FACILITATOR_URL: - raise ValueError("Missing required environment variable: FACILITATOR_URL") - -if not PAY_TO_ADDRESS: - raise ValueError("Missing required environment variable: PAY_TO_ADDRESS") - - -app = FastAPI(title="x402 Advanced Server Example") - -# Initialize facilitator client -facilitator_config: FacilitatorConfig = {"url": FACILITATOR_URL} -facilitator = FacilitatorClient(facilitator_config) - - -class PaymentRequiredException(Exception): - """Custom exception for payment required responses""" - - def __init__(self, error_data: dict): - self.error_data = error_data - super().__init__(error_data.get("error", "Payment required")) - - -@app.exception_handler(PaymentRequiredException) -async def payment_required_handler(request: Request, exc: PaymentRequiredException): - """Handle payment required exceptions with proper 402 responses""" - return JSONResponse( - status_code=402, - content=exc.error_data, - headers={"Content-Type": "application/json"}, - ) - - -def create_exact_payment_requirements( - price: Price, - network: SupportedNetworks, - resource: str, - description: str = "", - mime_type: str = "application/json", - max_timeout_seconds: int = 60, -) -> PaymentRequirements: - """ - Creates payment requirements for a given price and network. - - This handles both USD string prices (e.g., "$0.001") and TokenAmount objects. - - Args: - price: The price to be paid for the resource (USD string or TokenAmount) - network: The blockchain network to use for payment - resource: The resource being accessed - description: Optional description of the payment - mime_type: MIME type of the resource - max_timeout_seconds: Maximum timeout for the payment - - Returns: - PaymentRequirements object - - Raises: - ValueError: If price format is invalid - """ - try: - max_amount_required, asset_address, eip712_domain = ( - process_price_to_atomic_amount(price, network) - ) - except Exception as e: - raise ValueError(f"Invalid price: {price}. Error: {e}") - - return PaymentRequirements( - scheme="exact", - network=network, - max_amount_required=max_amount_required, - resource=resource, - description=description, - mime_type=mime_type, - pay_to=str(PAY_TO_ADDRESS), - max_timeout_seconds=max_timeout_seconds, - asset=asset_address, - output_schema=None, - extra=eip712_domain, - ) - - -async def verify_payment( - request: Request, - payment_requirements: list[PaymentRequirements], -) -> bool: - """ - Verifies a payment and raises PaymentRequiredException if invalid. - - Args: - request: The FastAPI request object - payment_requirements: List of payment requirements to verify against - - Returns: - True if payment is valid - - Raises: - PaymentRequiredException: If payment is required or invalid - """ - x_payment = request.headers.get("X-PAYMENT") - if not x_payment: - error_data = x402PaymentRequiredResponse( - x402_version=x402_VERSION, - error="X-PAYMENT header is required", - accepts=payment_requirements, - ).model_dump(by_alias=True) - raise PaymentRequiredException(error_data) - - try: - decoded_payment_dict = decode_payment(x_payment) - decoded_payment_dict["x402Version"] = x402_VERSION - decoded_payment = PaymentPayload(**decoded_payment_dict) - except Exception as e: - error_data = x402PaymentRequiredResponse( - x402_version=x402_VERSION, - error=str(e) or "Invalid or malformed payment header", - accepts=payment_requirements, - ).model_dump(by_alias=True) - raise PaymentRequiredException(error_data) - - try: - selected_payment_requirement = ( - find_matching_payment_requirements(payment_requirements, decoded_payment) - or payment_requirements[0] - ) - verify_response = await facilitator.verify( - decoded_payment, selected_payment_requirement - ) - if not verify_response.is_valid: - error_data = x402PaymentRequiredResponse( - x402_version=x402_VERSION, - error=verify_response.invalid_reason or "Payment verification failed", - accepts=payment_requirements, - ).model_dump(by_alias=True) - raise PaymentRequiredException(error_data) - except Exception as e: - error_data = x402PaymentRequiredResponse( - x402_version=x402_VERSION, - error=str(e), - accepts=payment_requirements, - ).model_dump(by_alias=True) - raise PaymentRequiredException(error_data) - - return True - - -def settle_response_header(response: SettleResponse) -> str: - """ - Creates a settlement response header. - - It base64 encodes the settlement response for use in the X-PAYMENT-RESPONSE header. - - Args: - response: The settlement response from the facilitator - - Returns: - A base64 encoded string containing the settlement response - """ - return safe_base64_encode(response.model_dump_json(by_alias=True)) - - -# Delayed settlement example endpoint -@app.get("/delayed-settlement") -async def delayed_settlement(request: Request) -> Dict[str, Any]: - """ - Demonstrates asynchronous payment processing. - Returns the weather data immediately without waiting for payment settlement. - Processes payment asynchronously in the background. - """ - resource = str(request.url) - payment_requirements = [ - create_exact_payment_requirements( - price="$0.001", - network="base-sepolia", - resource=resource, - description="Access to weather data (async)", - ) - ] - - await verify_payment(request, payment_requirements) - - # Return weather data immediately - response_data = { - "report": { - "weather": "sunny", - "temperature": 70, - } - } - - # Process payment asynchronously in the background - async def process_payment_async(): - try: - x_payment = request.headers.get("X-PAYMENT") - if not x_payment: - logger.error("X-PAYMENT header missing in async processing") - return - - decoded_payment_dict = decode_payment(x_payment) - decoded_payment = PaymentPayload(**decoded_payment_dict) - - settle_response = await facilitator.settle( - decoded_payment, payment_requirements[0] - ) - response_header = settle_response_header(settle_response) - - # In a real application, you would store this response header - # and associate it with the payment for later verification - logger.info(f"Payment settled: {response_header}") - except Exception as e: - logger.error(f"Payment settlement failed: {e}") - # In a real application, you would handle the failed payment - # by marking it for retry or notifying the user - - # Start background task - asyncio.create_task(process_payment_async()) - - return response_data - - -# Dynamic price example endpoint -@app.get("/dynamic-price") -async def dynamic_price(request: Request, response: Response) -> Dict[str, Any]: - """ - Shows how to implement variable pricing based on request parameters. - Accepts a 'multiplier' query parameter to adjust the base price. - """ - # Use query params, body, or external factors to determine pricing - multiplier = int(request.query_params.get("multiplier", "1")) - # Adjust pricing based on impact from inputs - base_price = 0.001 - dynamic_price_value = base_price * multiplier - - resource = str(request.url) - payment_requirements = [ - create_exact_payment_requirements( - price=f"${dynamic_price_value}", - network="base-sepolia", - resource=resource, - description="Access to weather data", - ) - ] - - await verify_payment(request, payment_requirements) - - # Process payment synchronously - x_payment = request.headers.get("X-PAYMENT") - if not x_payment: - raise ValueError("X-PAYMENT header is required") - - decoded_payment_dict = decode_payment(x_payment) - decoded_payment = PaymentPayload(**decoded_payment_dict) - - settle_response = await facilitator.settle(decoded_payment, payment_requirements[0]) - response_header = settle_response_header(settle_response) - - # Set the payment response header - response.headers["X-PAYMENT-RESPONSE"] = response_header - - # Return the weather data - return { - "report": { - "success": "sunny", - "temperature": 70, - } - } - - -# Multiple payment requirements example endpoint -@app.get("/multiple-payment-requirements") -async def multiple_payment_requirements( - request: Request, response: Response -) -> Dict[str, Any]: - """ - Illustrates how to accept multiple payment options. - Allows clients to pay using different assets (e.g., USDC or custom tokens). - """ - resource = str(request.url) - - # Payment requirements is a list. You can mix and match tokens, prices, and networks. - payment_requirements = [ - # Option 1: USD price (automatically converts to USDC) - create_exact_payment_requirements( - price="$0.001", - network="base", - resource=resource, - description="Access to weather data (USDC)", - ), - # Option 2: Specific token amount - create_exact_payment_requirements( - price=TokenAmount( - amount="1000", - asset=TokenAsset( - address="0x036CbD53842c5426634e7929541eC2318f3dCF7e", # USDC on Base Sepolia - decimals=6, - eip712=EIP712Domain(name="USDC", version="2"), - ), - ), - network="base-sepolia", - resource=resource, - description="Access to weather data (Custom Token)", - ), - ] - - await verify_payment(request, payment_requirements) - - # Process payment synchronously - x_payment = request.headers.get("X-PAYMENT") - if not x_payment: - raise ValueError("X-PAYMENT header is required") - - decoded_payment_dict = decode_payment(x_payment) - decoded_payment = PaymentPayload(**decoded_payment_dict) - - # Find the matching payment requirement - selected_payment_requirement = ( - find_matching_payment_requirements(payment_requirements, decoded_payment) - or payment_requirements[0] - ) - - settle_response = await facilitator.settle( - decoded_payment, selected_payment_requirement - ) - response_header = settle_response_header(settle_response) - - # Set the payment response header - response.headers["X-PAYMENT-RESPONSE"] = response_header - - # Return the weather data - return { - "report": { - "success": "sunny", - "temperature": 70, - } - } - - -if __name__ == "__main__": - import uvicorn - - uvicorn.run(app, host="0.0.0.0", port=4021) diff --git a/examples/python/legacy/servers/advanced/pyproject.toml b/examples/python/legacy/servers/advanced/pyproject.toml deleted file mode 100644 index b66e9ea10e..0000000000 --- a/examples/python/legacy/servers/advanced/pyproject.toml +++ /dev/null @@ -1,27 +0,0 @@ -[project] -name = "x402-advanced-server-example" -version = "0.1.0" -description = "Advanced example of using FastAPI server with x402 payment handling without middleware" -requires-python = ">=3.10" -dependencies = [ - "x402", - "fastapi>=0.109.0", - "uvicorn>=0.27.0", - "python-dotenv>=1.0.0" -] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -packages = ["."] - -[tool.hatch.metadata] -allow-direct-references = true - -[tool.uv] -package = false - -[tool.uv.sources] -x402 = { path = "../../../../../python/legacy", editable = true } diff --git a/examples/python/legacy/servers/advanced/uv.lock b/examples/python/legacy/servers/advanced/uv.lock deleted file mode 100644 index eb92278407..0000000000 --- a/examples/python/legacy/servers/advanced/uv.lock +++ /dev/null @@ -1,2162 +0,0 @@ -version = 1 -revision = 2 -requires-python = ">=3.10" - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, -] - -[[package]] -name = "aiohttp" -version = "3.12.14" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e6/0b/e39ad954107ebf213a2325038a3e7a506be3d98e1435e1f82086eec4cde2/aiohttp-3.12.14.tar.gz", hash = "sha256:6e06e120e34d93100de448fd941522e11dafa78ef1a893c179901b7d66aa29f2", size = 7822921, upload-time = "2025-07-10T13:05:33.968Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0c/88/f161f429f9de391eee6a5c2cffa54e2ecd5b7122ae99df247f7734dfefcb/aiohttp-3.12.14-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:906d5075b5ba0dd1c66fcaaf60eb09926a9fef3ca92d912d2a0bbdbecf8b1248", size = 702641, upload-time = "2025-07-10T13:02:38.98Z" }, - { url = "https://files.pythonhosted.org/packages/fe/b5/24fa382a69a25d242e2baa3e56d5ea5227d1b68784521aaf3a1a8b34c9a4/aiohttp-3.12.14-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c875bf6fc2fd1a572aba0e02ef4e7a63694778c5646cdbda346ee24e630d30fb", size = 479005, upload-time = "2025-07-10T13:02:42.714Z" }, - { url = "https://files.pythonhosted.org/packages/09/67/fda1bc34adbfaa950d98d934a23900918f9d63594928c70e55045838c943/aiohttp-3.12.14-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fbb284d15c6a45fab030740049d03c0ecd60edad9cd23b211d7e11d3be8d56fd", size = 466781, upload-time = "2025-07-10T13:02:44.639Z" }, - { url = "https://files.pythonhosted.org/packages/36/96/3ce1ea96d3cf6928b87cfb8cdd94650367f5c2f36e686a1f5568f0f13754/aiohttp-3.12.14-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38e360381e02e1a05d36b223ecab7bc4a6e7b5ab15760022dc92589ee1d4238c", size = 1648841, upload-time = "2025-07-10T13:02:46.356Z" }, - { url = "https://files.pythonhosted.org/packages/be/04/ddea06cb4bc7d8db3745cf95e2c42f310aad485ca075bd685f0e4f0f6b65/aiohttp-3.12.14-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:aaf90137b5e5d84a53632ad95ebee5c9e3e7468f0aab92ba3f608adcb914fa95", size = 1622896, upload-time = "2025-07-10T13:02:48.422Z" }, - { url = "https://files.pythonhosted.org/packages/73/66/63942f104d33ce6ca7871ac6c1e2ebab48b88f78b2b7680c37de60f5e8cd/aiohttp-3.12.14-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e532a25e4a0a2685fa295a31acf65e027fbe2bea7a4b02cdfbbba8a064577663", size = 1695302, upload-time = "2025-07-10T13:02:50.078Z" }, - { url = "https://files.pythonhosted.org/packages/20/00/aab615742b953f04b48cb378ee72ada88555b47b860b98c21c458c030a23/aiohttp-3.12.14-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eab9762c4d1b08ae04a6c77474e6136da722e34fdc0e6d6eab5ee93ac29f35d1", size = 1737617, upload-time = "2025-07-10T13:02:52.123Z" }, - { url = "https://files.pythonhosted.org/packages/d6/4f/ef6d9f77225cf27747368c37b3d69fac1f8d6f9d3d5de2d410d155639524/aiohttp-3.12.14-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:abe53c3812b2899889a7fca763cdfaeee725f5be68ea89905e4275476ffd7e61", size = 1642282, upload-time = "2025-07-10T13:02:53.899Z" }, - { url = "https://files.pythonhosted.org/packages/37/e1/e98a43c15aa52e9219a842f18c59cbae8bbe2d50c08d298f17e9e8bafa38/aiohttp-3.12.14-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5760909b7080aa2ec1d320baee90d03b21745573780a072b66ce633eb77a8656", size = 1582406, upload-time = "2025-07-10T13:02:55.515Z" }, - { url = "https://files.pythonhosted.org/packages/71/5c/29c6dfb49323bcdb0239bf3fc97ffcf0eaf86d3a60426a3287ec75d67721/aiohttp-3.12.14-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:02fcd3f69051467bbaa7f84d7ec3267478c7df18d68b2e28279116e29d18d4f3", size = 1626255, upload-time = "2025-07-10T13:02:57.343Z" }, - { url = "https://files.pythonhosted.org/packages/79/60/ec90782084090c4a6b459790cfd8d17be2c5662c9c4b2d21408b2f2dc36c/aiohttp-3.12.14-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4dcd1172cd6794884c33e504d3da3c35648b8be9bfa946942d353b939d5f1288", size = 1637041, upload-time = "2025-07-10T13:02:59.008Z" }, - { url = "https://files.pythonhosted.org/packages/22/89/205d3ad30865c32bc472ac13f94374210745b05bd0f2856996cb34d53396/aiohttp-3.12.14-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:224d0da41355b942b43ad08101b1b41ce633a654128ee07e36d75133443adcda", size = 1612494, upload-time = "2025-07-10T13:03:00.618Z" }, - { url = "https://files.pythonhosted.org/packages/48/ae/2f66edaa8bd6db2a4cba0386881eb92002cdc70834e2a93d1d5607132c7e/aiohttp-3.12.14-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:e387668724f4d734e865c1776d841ed75b300ee61059aca0b05bce67061dcacc", size = 1692081, upload-time = "2025-07-10T13:03:02.154Z" }, - { url = "https://files.pythonhosted.org/packages/08/3a/fa73bfc6e21407ea57f7906a816f0dc73663d9549da703be05dbd76d2dc3/aiohttp-3.12.14-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:dec9cde5b5a24171e0b0a4ca064b1414950904053fb77c707efd876a2da525d8", size = 1715318, upload-time = "2025-07-10T13:03:04.322Z" }, - { url = "https://files.pythonhosted.org/packages/e3/b3/751124b8ceb0831c17960d06ee31a4732cb4a6a006fdbfa1153d07c52226/aiohttp-3.12.14-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:bbad68a2af4877cc103cd94af9160e45676fc6f0c14abb88e6e092b945c2c8e3", size = 1643660, upload-time = "2025-07-10T13:03:06.406Z" }, - { url = "https://files.pythonhosted.org/packages/81/3c/72477a1d34edb8ab8ce8013086a41526d48b64f77e381c8908d24e1c18f5/aiohttp-3.12.14-cp310-cp310-win32.whl", hash = "sha256:ee580cb7c00bd857b3039ebca03c4448e84700dc1322f860cf7a500a6f62630c", size = 428289, upload-time = "2025-07-10T13:03:08.274Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c4/8aec4ccf1b822ec78e7982bd5cf971113ecce5f773f04039c76a083116fc/aiohttp-3.12.14-cp310-cp310-win_amd64.whl", hash = "sha256:cf4f05b8cea571e2ccc3ca744e35ead24992d90a72ca2cf7ab7a2efbac6716db", size = 451328, upload-time = "2025-07-10T13:03:10.146Z" }, - { url = "https://files.pythonhosted.org/packages/53/e1/8029b29316971c5fa89cec170274582619a01b3d82dd1036872acc9bc7e8/aiohttp-3.12.14-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f4552ff7b18bcec18b60a90c6982049cdb9dac1dba48cf00b97934a06ce2e597", size = 709960, upload-time = "2025-07-10T13:03:11.936Z" }, - { url = "https://files.pythonhosted.org/packages/96/bd/4f204cf1e282041f7b7e8155f846583b19149e0872752711d0da5e9cc023/aiohttp-3.12.14-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8283f42181ff6ccbcf25acaae4e8ab2ff7e92b3ca4a4ced73b2c12d8cd971393", size = 482235, upload-time = "2025-07-10T13:03:14.118Z" }, - { url = "https://files.pythonhosted.org/packages/d6/0f/2a580fcdd113fe2197a3b9df30230c7e85bb10bf56f7915457c60e9addd9/aiohttp-3.12.14-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:040afa180ea514495aaff7ad34ec3d27826eaa5d19812730fe9e529b04bb2179", size = 470501, upload-time = "2025-07-10T13:03:16.153Z" }, - { url = "https://files.pythonhosted.org/packages/38/78/2c1089f6adca90c3dd74915bafed6d6d8a87df5e3da74200f6b3a8b8906f/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b413c12f14c1149f0ffd890f4141a7471ba4b41234fe4fd4a0ff82b1dc299dbb", size = 1740696, upload-time = "2025-07-10T13:03:18.4Z" }, - { url = "https://files.pythonhosted.org/packages/4a/c8/ce6c7a34d9c589f007cfe064da2d943b3dee5aabc64eaecd21faf927ab11/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:1d6f607ce2e1a93315414e3d448b831238f1874b9968e1195b06efaa5c87e245", size = 1689365, upload-time = "2025-07-10T13:03:20.629Z" }, - { url = "https://files.pythonhosted.org/packages/18/10/431cd3d089de700756a56aa896faf3ea82bee39d22f89db7ddc957580308/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:565e70d03e924333004ed101599902bba09ebb14843c8ea39d657f037115201b", size = 1788157, upload-time = "2025-07-10T13:03:22.44Z" }, - { url = "https://files.pythonhosted.org/packages/fa/b2/26f4524184e0f7ba46671c512d4b03022633bcf7d32fa0c6f1ef49d55800/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4699979560728b168d5ab63c668a093c9570af2c7a78ea24ca5212c6cdc2b641", size = 1827203, upload-time = "2025-07-10T13:03:24.628Z" }, - { url = "https://files.pythonhosted.org/packages/e0/30/aadcdf71b510a718e3d98a7bfeaea2396ac847f218b7e8edb241b09bd99a/aiohttp-3.12.14-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ad5fdf6af93ec6c99bf800eba3af9a43d8bfd66dce920ac905c817ef4a712afe", size = 1729664, upload-time = "2025-07-10T13:03:26.412Z" }, - { url = "https://files.pythonhosted.org/packages/67/7f/7ccf11756ae498fdedc3d689a0c36ace8fc82f9d52d3517da24adf6e9a74/aiohttp-3.12.14-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4ac76627c0b7ee0e80e871bde0d376a057916cb008a8f3ffc889570a838f5cc7", size = 1666741, upload-time = "2025-07-10T13:03:28.167Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4d/35ebc170b1856dd020c92376dbfe4297217625ef4004d56587024dc2289c/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:798204af1180885651b77bf03adc903743a86a39c7392c472891649610844635", size = 1715013, upload-time = "2025-07-10T13:03:30.018Z" }, - { url = "https://files.pythonhosted.org/packages/7b/24/46dc0380146f33e2e4aa088b92374b598f5bdcde1718c77e8d1a0094f1a4/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:4f1205f97de92c37dd71cf2d5bcfb65fdaed3c255d246172cce729a8d849b4da", size = 1710172, upload-time = "2025-07-10T13:03:31.821Z" }, - { url = "https://files.pythonhosted.org/packages/2f/0a/46599d7d19b64f4d0fe1b57bdf96a9a40b5c125f0ae0d8899bc22e91fdce/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:76ae6f1dd041f85065d9df77c6bc9c9703da9b5c018479d20262acc3df97d419", size = 1690355, upload-time = "2025-07-10T13:03:34.754Z" }, - { url = "https://files.pythonhosted.org/packages/08/86/b21b682e33d5ca317ef96bd21294984f72379454e689d7da584df1512a19/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:a194ace7bc43ce765338ca2dfb5661489317db216ea7ea700b0332878b392cab", size = 1783958, upload-time = "2025-07-10T13:03:36.53Z" }, - { url = "https://files.pythonhosted.org/packages/4f/45/f639482530b1396c365f23c5e3b1ae51c9bc02ba2b2248ca0c855a730059/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:16260e8e03744a6fe3fcb05259eeab8e08342c4c33decf96a9dad9f1187275d0", size = 1804423, upload-time = "2025-07-10T13:03:38.504Z" }, - { url = "https://files.pythonhosted.org/packages/7e/e5/39635a9e06eed1d73671bd4079a3caf9cf09a49df08490686f45a710b80e/aiohttp-3.12.14-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:8c779e5ebbf0e2e15334ea404fcce54009dc069210164a244d2eac8352a44b28", size = 1717479, upload-time = "2025-07-10T13:03:40.158Z" }, - { url = "https://files.pythonhosted.org/packages/51/e1/7f1c77515d369b7419c5b501196526dad3e72800946c0099594c1f0c20b4/aiohttp-3.12.14-cp311-cp311-win32.whl", hash = "sha256:a289f50bf1bd5be227376c067927f78079a7bdeccf8daa6a9e65c38bae14324b", size = 427907, upload-time = "2025-07-10T13:03:41.801Z" }, - { url = "https://files.pythonhosted.org/packages/06/24/a6bf915c85b7a5b07beba3d42b3282936b51e4578b64a51e8e875643c276/aiohttp-3.12.14-cp311-cp311-win_amd64.whl", hash = "sha256:0b8a69acaf06b17e9c54151a6c956339cf46db4ff72b3ac28516d0f7068f4ced", size = 452334, upload-time = "2025-07-10T13:03:43.485Z" }, - { url = "https://files.pythonhosted.org/packages/c3/0d/29026524e9336e33d9767a1e593ae2b24c2b8b09af7c2bd8193762f76b3e/aiohttp-3.12.14-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:a0ecbb32fc3e69bc25efcda7d28d38e987d007096cbbeed04f14a6662d0eee22", size = 701055, upload-time = "2025-07-10T13:03:45.59Z" }, - { url = "https://files.pythonhosted.org/packages/0a/b8/a5e8e583e6c8c1056f4b012b50a03c77a669c2e9bf012b7cf33d6bc4b141/aiohttp-3.12.14-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:0400f0ca9bb3e0b02f6466421f253797f6384e9845820c8b05e976398ac1d81a", size = 475670, upload-time = "2025-07-10T13:03:47.249Z" }, - { url = "https://files.pythonhosted.org/packages/29/e8/5202890c9e81a4ec2c2808dd90ffe024952e72c061729e1d49917677952f/aiohttp-3.12.14-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a56809fed4c8a830b5cae18454b7464e1529dbf66f71c4772e3cfa9cbec0a1ff", size = 468513, upload-time = "2025-07-10T13:03:49.377Z" }, - { url = "https://files.pythonhosted.org/packages/23/e5/d11db8c23d8923d3484a27468a40737d50f05b05eebbb6288bafcb467356/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:27f2e373276e4755691a963e5d11756d093e346119f0627c2d6518208483fb6d", size = 1715309, upload-time = "2025-07-10T13:03:51.556Z" }, - { url = "https://files.pythonhosted.org/packages/53/44/af6879ca0eff7a16b1b650b7ea4a827301737a350a464239e58aa7c387ef/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:ca39e433630e9a16281125ef57ece6817afd1d54c9f1bf32e901f38f16035869", size = 1697961, upload-time = "2025-07-10T13:03:53.511Z" }, - { url = "https://files.pythonhosted.org/packages/bb/94/18457f043399e1ec0e59ad8674c0372f925363059c276a45a1459e17f423/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9c748b3f8b14c77720132b2510a7d9907a03c20ba80f469e58d5dfd90c079a1c", size = 1753055, upload-time = "2025-07-10T13:03:55.368Z" }, - { url = "https://files.pythonhosted.org/packages/26/d9/1d3744dc588fafb50ff8a6226d58f484a2242b5dd93d8038882f55474d41/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0a568abe1b15ce69d4cc37e23020720423f0728e3cb1f9bcd3f53420ec3bfe7", size = 1799211, upload-time = "2025-07-10T13:03:57.216Z" }, - { url = "https://files.pythonhosted.org/packages/73/12/2530fb2b08773f717ab2d249ca7a982ac66e32187c62d49e2c86c9bba9b4/aiohttp-3.12.14-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9888e60c2c54eaf56704b17feb558c7ed6b7439bca1e07d4818ab878f2083660", size = 1718649, upload-time = "2025-07-10T13:03:59.469Z" }, - { url = "https://files.pythonhosted.org/packages/b9/34/8d6015a729f6571341a311061b578e8b8072ea3656b3d72329fa0faa2c7c/aiohttp-3.12.14-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3006a1dc579b9156de01e7916d38c63dc1ea0679b14627a37edf6151bc530088", size = 1634452, upload-time = "2025-07-10T13:04:01.698Z" }, - { url = "https://files.pythonhosted.org/packages/ff/4b/08b83ea02595a582447aeb0c1986792d0de35fe7a22fb2125d65091cbaf3/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:aa8ec5c15ab80e5501a26719eb48a55f3c567da45c6ea5bb78c52c036b2655c7", size = 1695511, upload-time = "2025-07-10T13:04:04.165Z" }, - { url = "https://files.pythonhosted.org/packages/b5/66/9c7c31037a063eec13ecf1976185c65d1394ded4a5120dd5965e3473cb21/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:39b94e50959aa07844c7fe2206b9f75d63cc3ad1c648aaa755aa257f6f2498a9", size = 1716967, upload-time = "2025-07-10T13:04:06.132Z" }, - { url = "https://files.pythonhosted.org/packages/ba/02/84406e0ad1acb0fb61fd617651ab6de760b2d6a31700904bc0b33bd0894d/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:04c11907492f416dad9885d503fbfc5dcb6768d90cad8639a771922d584609d3", size = 1657620, upload-time = "2025-07-10T13:04:07.944Z" }, - { url = "https://files.pythonhosted.org/packages/07/53/da018f4013a7a179017b9a274b46b9a12cbeb387570f116964f498a6f211/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:88167bd9ab69bb46cee91bd9761db6dfd45b6e76a0438c7e884c3f8160ff21eb", size = 1737179, upload-time = "2025-07-10T13:04:10.182Z" }, - { url = "https://files.pythonhosted.org/packages/49/e8/ca01c5ccfeaafb026d85fa4f43ceb23eb80ea9c1385688db0ef322c751e9/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:791504763f25e8f9f251e4688195e8b455f8820274320204f7eafc467e609425", size = 1765156, upload-time = "2025-07-10T13:04:12.029Z" }, - { url = "https://files.pythonhosted.org/packages/22/32/5501ab525a47ba23c20613e568174d6c63aa09e2caa22cded5c6ea8e3ada/aiohttp-3.12.14-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2785b112346e435dd3a1a67f67713a3fe692d288542f1347ad255683f066d8e0", size = 1724766, upload-time = "2025-07-10T13:04:13.961Z" }, - { url = "https://files.pythonhosted.org/packages/06/af/28e24574801fcf1657945347ee10df3892311c2829b41232be6089e461e7/aiohttp-3.12.14-cp312-cp312-win32.whl", hash = "sha256:15f5f4792c9c999a31d8decf444e79fcfd98497bf98e94284bf390a7bb8c1729", size = 422641, upload-time = "2025-07-10T13:04:16.018Z" }, - { url = "https://files.pythonhosted.org/packages/98/d5/7ac2464aebd2eecac38dbe96148c9eb487679c512449ba5215d233755582/aiohttp-3.12.14-cp312-cp312-win_amd64.whl", hash = "sha256:3b66e1a182879f579b105a80d5c4bd448b91a57e8933564bf41665064796a338", size = 449316, upload-time = "2025-07-10T13:04:18.289Z" }, - { url = "https://files.pythonhosted.org/packages/06/48/e0d2fa8ac778008071e7b79b93ab31ef14ab88804d7ba71b5c964a7c844e/aiohttp-3.12.14-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:3143a7893d94dc82bc409f7308bc10d60285a3cd831a68faf1aa0836c5c3c767", size = 695471, upload-time = "2025-07-10T13:04:20.124Z" }, - { url = "https://files.pythonhosted.org/packages/8d/e7/f73206afa33100804f790b71092888f47df65fd9a4cd0e6800d7c6826441/aiohttp-3.12.14-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3d62ac3d506cef54b355bd34c2a7c230eb693880001dfcda0bf88b38f5d7af7e", size = 473128, upload-time = "2025-07-10T13:04:21.928Z" }, - { url = "https://files.pythonhosted.org/packages/df/e2/4dd00180be551a6e7ee979c20fc7c32727f4889ee3fd5b0586e0d47f30e1/aiohttp-3.12.14-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:48e43e075c6a438937c4de48ec30fa8ad8e6dfef122a038847456bfe7b947b63", size = 465426, upload-time = "2025-07-10T13:04:24.071Z" }, - { url = "https://files.pythonhosted.org/packages/de/dd/525ed198a0bb674a323e93e4d928443a680860802c44fa7922d39436b48b/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:077b4488411a9724cecc436cbc8c133e0d61e694995b8de51aaf351c7578949d", size = 1704252, upload-time = "2025-07-10T13:04:26.049Z" }, - { url = "https://files.pythonhosted.org/packages/d8/b1/01e542aed560a968f692ab4fc4323286e8bc4daae83348cd63588e4f33e3/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:d8c35632575653f297dcbc9546305b2c1133391089ab925a6a3706dfa775ccab", size = 1685514, upload-time = "2025-07-10T13:04:28.186Z" }, - { url = "https://files.pythonhosted.org/packages/b3/06/93669694dc5fdabdc01338791e70452d60ce21ea0946a878715688d5a191/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6b8ce87963f0035c6834b28f061df90cf525ff7c9b6283a8ac23acee6502afd4", size = 1737586, upload-time = "2025-07-10T13:04:30.195Z" }, - { url = "https://files.pythonhosted.org/packages/a5/3a/18991048ffc1407ca51efb49ba8bcc1645961f97f563a6c480cdf0286310/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f0a2cf66e32a2563bb0766eb24eae7e9a269ac0dc48db0aae90b575dc9583026", size = 1786958, upload-time = "2025-07-10T13:04:32.482Z" }, - { url = "https://files.pythonhosted.org/packages/30/a8/81e237f89a32029f9b4a805af6dffc378f8459c7b9942712c809ff9e76e5/aiohttp-3.12.14-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:cdea089caf6d5cde975084a884c72d901e36ef9c2fd972c9f51efbbc64e96fbd", size = 1709287, upload-time = "2025-07-10T13:04:34.493Z" }, - { url = "https://files.pythonhosted.org/packages/8c/e3/bd67a11b0fe7fc12c6030473afd9e44223d456f500f7cf526dbaa259ae46/aiohttp-3.12.14-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8a7865f27db67d49e81d463da64a59365ebd6b826e0e4847aa111056dcb9dc88", size = 1622990, upload-time = "2025-07-10T13:04:36.433Z" }, - { url = "https://files.pythonhosted.org/packages/83/ba/e0cc8e0f0d9ce0904e3cf2d6fa41904e379e718a013c721b781d53dcbcca/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0ab5b38a6a39781d77713ad930cb5e7feea6f253de656a5f9f281a8f5931b086", size = 1676015, upload-time = "2025-07-10T13:04:38.958Z" }, - { url = "https://files.pythonhosted.org/packages/d8/b3/1e6c960520bda094c48b56de29a3d978254637ace7168dd97ddc273d0d6c/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:9b3b15acee5c17e8848d90a4ebc27853f37077ba6aec4d8cb4dbbea56d156933", size = 1707678, upload-time = "2025-07-10T13:04:41.275Z" }, - { url = "https://files.pythonhosted.org/packages/0a/19/929a3eb8c35b7f9f076a462eaa9830b32c7f27d3395397665caa5e975614/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e4c972b0bdaac167c1e53e16a16101b17c6d0ed7eac178e653a07b9f7fad7151", size = 1650274, upload-time = "2025-07-10T13:04:43.483Z" }, - { url = "https://files.pythonhosted.org/packages/22/e5/81682a6f20dd1b18ce3d747de8eba11cbef9b270f567426ff7880b096b48/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:7442488b0039257a3bdbc55f7209587911f143fca11df9869578db6c26feeeb8", size = 1726408, upload-time = "2025-07-10T13:04:45.577Z" }, - { url = "https://files.pythonhosted.org/packages/8c/17/884938dffaa4048302985483f77dfce5ac18339aad9b04ad4aaa5e32b028/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f68d3067eecb64c5e9bab4a26aa11bd676f4c70eea9ef6536b0a4e490639add3", size = 1759879, upload-time = "2025-07-10T13:04:47.663Z" }, - { url = "https://files.pythonhosted.org/packages/95/78/53b081980f50b5cf874359bde707a6eacd6c4be3f5f5c93937e48c9d0025/aiohttp-3.12.14-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f88d3704c8b3d598a08ad17d06006cb1ca52a1182291f04979e305c8be6c9758", size = 1708770, upload-time = "2025-07-10T13:04:49.944Z" }, - { url = "https://files.pythonhosted.org/packages/ed/91/228eeddb008ecbe3ffa6c77b440597fdf640307162f0c6488e72c5a2d112/aiohttp-3.12.14-cp313-cp313-win32.whl", hash = "sha256:a3c99ab19c7bf375c4ae3debd91ca5d394b98b6089a03231d4c580ef3c2ae4c5", size = 421688, upload-time = "2025-07-10T13:04:51.993Z" }, - { url = "https://files.pythonhosted.org/packages/66/5f/8427618903343402fdafe2850738f735fd1d9409d2a8f9bcaae5e630d3ba/aiohttp-3.12.14-cp313-cp313-win_amd64.whl", hash = "sha256:3f8aad695e12edc9d571f878c62bedc91adf30c760c8632f09663e5f564f4baa", size = 448098, upload-time = "2025-07-10T13:04:53.999Z" }, -] - -[[package]] -name = "aiosignal" -version = "1.4.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/61/62/06741b579156360248d1ec624842ad0edf697050bbaf7c3e46394e106ad1/aiosignal-1.4.0.tar.gz", hash = "sha256:f47eecd9468083c2029cc99945502cb7708b082c232f9aca65da147157b251c7", size = 25007, upload-time = "2025-07-03T22:54:43.528Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/76/641ae371508676492379f16e2fa48f4e2c11741bd63c48be4b12a6b09cba/aiosignal-1.4.0-py3-none-any.whl", hash = "sha256:053243f8b92b990551949e63930a839ff0cf0b0ebbe0597b0f3fb19e1a0fe82e", size = 7490, upload-time = "2025-07-03T22:54:42.156Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, -] - -[[package]] -name = "async-timeout" -version = "5.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, -] - -[[package]] -name = "attrs" -version = "25.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, -] - -[[package]] -name = "bitarray" -version = "3.5.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/e9/be1722981d43341ec1da6370255c414ec00ba23a99e01fc315dbe4c5c9f4/bitarray-3.5.1.tar.gz", hash = "sha256:b03c49d1a2eb753cc6090053f1c675ada71e1c3ea02011f1996cf4c2b6e9d6d6", size = 148859, upload-time = "2025-07-14T22:05:46.73Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fb/3c/0e4fd841dbf38792845e080c007f0aa8fd255d7dd14d8026427fb4de3284/bitarray-3.5.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d0af817f8440fd382414773fe75da0d6cac69d3e784bec106bae540b9de9b020", size = 145269, upload-time = "2025-07-14T22:02:25.525Z" }, - { url = "https://files.pythonhosted.org/packages/34/f2/bfd3cff3257171343d30535d3c9f078ed8a8b9154aa6a6fb4088f3b1a92d/bitarray-3.5.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b1a383e25820643dcfaa5647e430ac990007f0163c525f98fc90e88d0a332662", size = 141891, upload-time = "2025-07-14T22:02:27.766Z" }, - { url = "https://files.pythonhosted.org/packages/64/a6/b360e8baf4b61e3152c5dc93622a358ed0b8b53ddbc6bd1223686f265ac6/bitarray-3.5.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:202d769109fc81066eed80e936c1c1e2864547e81830c8578a4b90e530118c15", size = 311200, upload-time = "2025-07-14T22:02:29.209Z" }, - { url = "https://files.pythonhosted.org/packages/4d/a2/aaca748379ad9c2f8832a05fed4a0f3edcb278ed2a7875e6fa9cbf8dbaf1/bitarray-3.5.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a9e5be9949ee1cf60382d976f25980d61421387655c28be1571b607bd33578bb", size = 327132, upload-time = "2025-07-14T22:02:30.585Z" }, - { url = "https://files.pythonhosted.org/packages/0b/2b/18b3d810f5d428d1df572a3a563e62daa015dbb512dd8e9a3c0c1fe0e588/bitarray-3.5.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9450d6579da0d8d087694623307cfbd6cfd13a49c221ead5ff1975309956ae28", size = 319427, upload-time = "2025-07-14T22:02:31.894Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c4/fa33dda834e75cce7d36fec0f8609aaba4ee3c43b9bb6bd33cb84563f459/bitarray-3.5.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d11c79c1edd86ac4fc68bd14947d8f57746afbc326288930e8202d93906443af", size = 312728, upload-time = "2025-07-14T22:02:33.536Z" }, - { url = "https://files.pythonhosted.org/packages/48/cb/4535a9bcffc9265c8bc2fd7285b419e8ca68c121cf4bec66c160dc87075e/bitarray-3.5.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9e789bfa751deec734fc7f9fabc82f03fc680fa26196a417b69a101a3d672dfa", size = 300288, upload-time = "2025-07-14T22:02:36.096Z" }, - { url = "https://files.pythonhosted.org/packages/f1/78/e8e69bbd45f1d4a27b770bd77e1956171f9bdbdecbcf19c8439706f2d9d9/bitarray-3.5.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:6c7af1e0b02d54875060b15db85f9634bcd2f45d306508dbf8ceeb157f64fdac", size = 305351, upload-time = "2025-07-14T22:02:37.285Z" }, - { url = "https://files.pythonhosted.org/packages/7c/c0/31750c88321367718c4fbf63a68fe62c79d0511807add583176934a9926e/bitarray-3.5.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:1d82bdf87186adfb23336c7f2f6c4c54c1e3f26c1dc6ec0b5fbbb6cba3a46266", size = 296893, upload-time = "2025-07-14T22:02:38.497Z" }, - { url = "https://files.pythonhosted.org/packages/bf/f6/5f1ff2569effba20d65423e38c2390d00ab305bd59d2d749ddda0bae0811/bitarray-3.5.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:65cbee9dfc85ad88ceea21c669b48f5b90dd40181c12e5fc097cf9863d04bfb1", size = 322137, upload-time = "2025-07-14T22:02:39.836Z" }, - { url = "https://files.pythonhosted.org/packages/0d/06/1d7465046828dcc637378f23b3dbb2bed35ce22a0022da2f3b568d8f97d7/bitarray-3.5.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:6167f48ff31f8153090c2f75f60f6032adb7d2d3c0dfc61eb96f6e654f66c860", size = 324659, upload-time = "2025-07-14T22:02:41.512Z" }, - { url = "https://files.pythonhosted.org/packages/cf/fe/18afc129abcc870bb6d9f7bbe184b9782736d5759c023306f75a828b11cc/bitarray-3.5.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b230d1bd0b0fd4264165220a267479f97e18bb856734375e678ff77d3d63e25f", size = 304264, upload-time = "2025-07-14T22:02:42.745Z" }, - { url = "https://files.pythonhosted.org/packages/35/82/795fe160473ddb816781cc15eed1e60c91157c786c9fa07320f700ef97e3/bitarray-3.5.1-cp310-cp310-win32.whl", hash = "sha256:224739107aa0e7590a5166c52866a2c69412546469f7a71bfb5b89d38cb7d0d5", size = 138740, upload-time = "2025-07-14T22:02:43.911Z" }, - { url = "https://files.pythonhosted.org/packages/d6/00/8858efb2b6c489e864b9650f03fae9391e9a25614c7941e08604c24f48c7/bitarray-3.5.1-cp310-cp310-win_amd64.whl", hash = "sha256:f404a0f6f37ade9aba1ca18d0f0ca76c729bb36a7ddd42f62fb899f6b99e3b4b", size = 145323, upload-time = "2025-07-14T22:02:45.382Z" }, - { url = "https://files.pythonhosted.org/packages/fb/c5/3559e72a879452d5bb6bd78315b6eff0add2aad8a04e9a82a44d6240c8f3/bitarray-3.5.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:26db9776442fc60a7883c55624cdf1a0446814e9516622c81c32fe84a83596d0", size = 145268, upload-time = "2025-07-14T22:02:47.46Z" }, - { url = "https://files.pythonhosted.org/packages/b0/19/1e1eaf0739d302cb50313080adfc548f4fdcdb421a1ac8102096e375e601/bitarray-3.5.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:97e89468fe8dae7cabddd3e49487fc977e191734708cdf720d0887a53a1601fb", size = 141893, upload-time = "2025-07-14T22:02:48.952Z" }, - { url = "https://files.pythonhosted.org/packages/02/91/6d6aa58ca745c70b5655f5d7188c2e195c5267312becaf8c9dd4b7c215dc/bitarray-3.5.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1e412a62386d64926ab411bc882a6847dc187742a0a01da624a9aabe378ce2f5", size = 318852, upload-time = "2025-07-14T22:02:50.08Z" }, - { url = "https://files.pythonhosted.org/packages/cc/d0/659e1c9b092cdee915ecefacdb5450975cd965c002229daf1e091209e1dd/bitarray-3.5.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c6ce16b3c7bec57686e6cb00b0a6d7b5357fa37cf2f67fa8221b774876512800", size = 335179, upload-time = "2025-07-14T22:02:51.25Z" }, - { url = "https://files.pythonhosted.org/packages/f8/fb/c7860b11304fc6f5971ec9fe5a56d2f00ab67b4fd7749f5cd0887fff8b78/bitarray-3.5.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00ca03adfdfc0999c5b715ccebf26a7c396b79ccd9c7c00e78e6a44cca5405a0", size = 328153, upload-time = "2025-07-14T22:02:52.731Z" }, - { url = "https://files.pythonhosted.org/packages/5c/eb/0accf6da6dcc80a968c1ab53afc9235242283fbc853248bdf073c0e463f0/bitarray-3.5.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76c34e1c61888a36dc7ae1cc9b9b7c901a28900779697666a280191fdd06986a", size = 320546, upload-time = "2025-07-14T22:02:53.901Z" }, - { url = "https://files.pythonhosted.org/packages/1a/07/64c868bd8399b7ad118fe94b39b70c8f68fd3c1003aca8f637bcc18baa0c/bitarray-3.5.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:df1d12414c8e1f52995b1079755b49d1902c333789a12e550d28e0ab991bdaaa", size = 308421, upload-time = "2025-07-14T22:02:55.16Z" }, - { url = "https://files.pythonhosted.org/packages/c6/f5/042f16d77d13ddd3d3dedaf3913454b718287f889fa6ff26b45a9d6bc7ab/bitarray-3.5.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:b1e573f6b8efb41716411a00ea2dedc69f22305a46b107c764b2b50a545c2b53", size = 313451, upload-time = "2025-07-14T22:02:56.931Z" }, - { url = "https://files.pythonhosted.org/packages/cf/9b/7ea1caa21640f85c1d102c1b2a325c5705cff30cbd748b2f7c8e61bab988/bitarray-3.5.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:3cb3cbaa3ae3894888c6c3f21f6586b0733de6a53ea38a67a27a89a49703d9c1", size = 304573, upload-time = "2025-07-14T22:02:58.635Z" }, - { url = "https://files.pythonhosted.org/packages/de/62/03e234169dab7b02bd4be80a55aafc216713b5732f4c408b5ebc4d255a91/bitarray-3.5.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fd9d24c033ccf4776ecf3c31288e98a5656f8f63a944508a7a6afd2f41fd57eb", size = 329973, upload-time = "2025-07-14T22:03:00.288Z" }, - { url = "https://files.pythonhosted.org/packages/6d/fb/bdaf7653c8e9bef38b4315779d98c436fa08d9408d9c71347c424ec02dc5/bitarray-3.5.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:79ff7a768da4d9e99a07208f318378ef63c06673712371f2433fd54ea3f41772", size = 332840, upload-time = "2025-07-14T22:03:01.495Z" }, - { url = "https://files.pythonhosted.org/packages/34/c7/f1d94b19ce623d63b3cb86045843e57da49bf1a18e793112c1743cc0c625/bitarray-3.5.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:792c9851472ae0fbe870b0c06c413ab2ab8d495b53c146bc7828be8d716f7a1e", size = 312417, upload-time = "2025-07-14T22:03:02.956Z" }, - { url = "https://files.pythonhosted.org/packages/f6/5f/25715f4080f4a9758ed59c0e3b03a9ea04db04323ed01bf96a47939c85de/bitarray-3.5.1-cp311-cp311-win32.whl", hash = "sha256:2a5a5ca31fee5871387d636d50fdef6f5d232170d539dc19022add2eedf363a5", size = 138915, upload-time = "2025-07-14T22:03:04.397Z" }, - { url = "https://files.pythonhosted.org/packages/e5/d2/a7aefc2e5e0144a9981b35eb335f5dbffc575ad4ed60167752e503504e9a/bitarray-3.5.1-cp311-cp311-win_amd64.whl", hash = "sha256:0f14f1e64784260d01503553b39b8731d5f8e0e101b6fcc72e5558d07d6ad39d", size = 145542, upload-time = "2025-07-14T22:03:05.636Z" }, - { url = "https://files.pythonhosted.org/packages/d6/d1/510f11b59b5d3def3ff6d80534246f3676c71f521b222a54865313be5771/bitarray-3.5.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6cbe639f19993fa73eb6464b6dfd5bd9f19951b56eca7fcafc6ca59c9686fea4", size = 144993, upload-time = "2025-07-14T22:03:06.78Z" }, - { url = "https://files.pythonhosted.org/packages/10/75/e78381421de90ffd5a2f33f6611c72f88f86f600f97a878441fbf35d130c/bitarray-3.5.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:37d00d0dc4d5df12ac1a2f7c7f954b23a9cfa43daf88a2a89d871668ed495cd8", size = 141873, upload-time = "2025-07-14T22:03:07.924Z" }, - { url = "https://files.pythonhosted.org/packages/1f/3a/61e792211051e52863e7cb2097bdc05d0af0ea6aba9a2858f9726595688d/bitarray-3.5.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5350ecdf7138fb62298d893044023792925031188dcb8127406c670bb07736e", size = 321578, upload-time = "2025-07-14T22:03:09.533Z" }, - { url = "https://files.pythonhosted.org/packages/9e/4b/36a007d864c366bf6640e7ae55e48feddcbb0bd1f01ec2b579d9ef23ebce/bitarray-3.5.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1699973ca9c9056785261a0cad6f83b8ad61f0e410b1ca9969c81a34d241a5c2", size = 337140, upload-time = "2025-07-14T22:03:11.202Z" }, - { url = "https://files.pythonhosted.org/packages/8b/a7/6dc760f4e8d070c658eb1f0fbc981d95994594ec8c380ec3ec482afd4b71/bitarray-3.5.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280e34073ce57afe8f530e99e70e3b929843ad43138f87aeb7dc3090630c0eb2", size = 330751, upload-time = "2025-07-14T22:03:12.421Z" }, - { url = "https://files.pythonhosted.org/packages/39/d3/e71f1531ee07ce1e47c2c61bdc87fe78c27ef0059d7f055d10488bf9b579/bitarray-3.5.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b04b802fa9e1d8b0ed2d2448430ff0ce6a3232e69b48b62962507297af65853a", size = 323649, upload-time = "2025-07-14T22:03:13.756Z" }, - { url = "https://files.pythonhosted.org/packages/a9/a4/60d4d15e86b7232f8cc538b98e89cd1a10f285a173eefdf86330c3f287fb/bitarray-3.5.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8fa5f1836cff442660632c65d73caa572ce10124cecdf366b64a74541e660b4e", size = 311011, upload-time = "2025-07-14T22:03:15.332Z" }, - { url = "https://files.pythonhosted.org/packages/7e/9a/2b6c66b09b3dd45c0075935e0a1d52344ccffbc6d48a33ff219978fa1411/bitarray-3.5.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:efc78327e34e062797a6b6645d9d861e0aaeec4cd8da4d7221ce8c72df20e0bd", size = 315687, upload-time = "2025-07-14T22:03:16.96Z" }, - { url = "https://files.pythonhosted.org/packages/c2/f0/6b638b889889c4ba96d4f255d21a29349627a0a5d2e2852b419913425c6e/bitarray-3.5.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:45c959c8739a9cb7078d03295d7e6be8e89a4300dda9ccb4063cced6852748d5", size = 307433, upload-time = "2025-07-14T22:03:18.676Z" }, - { url = "https://files.pythonhosted.org/packages/33/9a/0a93a936911836611f881f805876d0231c499202e8c8121b56e30c4ef4c0/bitarray-3.5.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:bd4ecba34031cb8d463f67dfb9537326758a0a32d8b62057d5a48eba8d015357", size = 331941, upload-time = "2025-07-14T22:03:19.967Z" }, - { url = "https://files.pythonhosted.org/packages/34/d7/6528c843a5abb8bc38cfa82f76ddab5a6cd136a06cbc0ec2342f2eba7723/bitarray-3.5.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:edd138938be91cc3e99387529b59c93683e1c8a96ad38c4b920be7a29a80d076", size = 335596, upload-time = "2025-07-14T22:03:21.561Z" }, - { url = "https://files.pythonhosted.org/packages/7d/3d/53dfe0258739f0ede9f0506a111b30373ec8f3b7f0ec126e4fc7cf498201/bitarray-3.5.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bcb10270a33deb2fd6ed10a922536db5323444c51f0d961a7eac39af23f7761d", size = 315566, upload-time = "2025-07-14T22:03:22.758Z" }, - { url = "https://files.pythonhosted.org/packages/a6/35/655cdf157d86a1b0032f6a7d6d33dac50516d1cd1585c0c383a1a399625d/bitarray-3.5.1-cp312-cp312-win32.whl", hash = "sha256:fb0f196f70e8a1c0546b6f877e0f495701aa7168073f9f6beb3cea7b7d439981", size = 138950, upload-time = "2025-07-14T22:03:24.021Z" }, - { url = "https://files.pythonhosted.org/packages/bb/37/7cd6b9685d68c55e43cf25a90c2437edbdefc7a40e98c38556c83bac4925/bitarray-3.5.1-cp312-cp312-win_amd64.whl", hash = "sha256:c43d4ebf2d9e82fbb191f55979dabbb99949e41b9c5db5557a8cd0753863a7ae", size = 145757, upload-time = "2025-07-14T22:03:25.553Z" }, - { url = "https://files.pythonhosted.org/packages/0a/a8/8fd41a4da5a3c36fbd3119626c6b06e2f735330d3dee1fe05dc861166966/bitarray-3.5.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:3aa0e412eda251690b0a187ce9abaadf05a4a8481efd51efd3dffc594c6070ad", size = 144976, upload-time = "2025-07-14T22:03:26.75Z" }, - { url = "https://files.pythonhosted.org/packages/ec/c4/b7cf035661ef40015320fbcd7c3a1e03c1467a9d83ec68441f708b00994d/bitarray-3.5.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:609ec6c1139ff75c9abcaab88e9d9351412aaeebe15f66db44e00c58aa08bee5", size = 141870, upload-time = "2025-07-14T22:03:28.383Z" }, - { url = "https://files.pythonhosted.org/packages/37/24/321644a8bbe55a96abc61c24dbc6622acec7e78f58cf76a26da6cbc21b82/bitarray-3.5.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b052f546b7519c5974ed733ef4895e56eed67e2cae6c48b0d87d6aa096c1265e", size = 321510, upload-time = "2025-07-14T22:03:29.687Z" }, - { url = "https://files.pythonhosted.org/packages/3b/80/09491433107e98c91cb73262c3a18e88f8e573070f885428b96acb339475/bitarray-3.5.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2753cd31b382dbddba8acac1e5bdcfe9d44e404c583889bd268816b5d241d68e", size = 337023, upload-time = "2025-07-14T22:03:30.987Z" }, - { url = "https://files.pythonhosted.org/packages/80/5a/21b9416d9af68ca5d85688a0024bf4cc6b88aedd570afa1829b5f52d52ce/bitarray-3.5.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:c47b1bb5c2c6b2720ae1148862d5d8c74d10b1104cb62ba5085f1baf9eaf5cc4", size = 330604, upload-time = "2025-07-14T22:03:32.306Z" }, - { url = "https://files.pythonhosted.org/packages/ee/80/e121335da48ee927a0a4b97ff0ab7175e1f59721640e5116f77f2185c449/bitarray-3.5.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af501232f8a914535e66b1d49f59c736792345fb47fe11d21009fcd0927d34da", size = 323539, upload-time = "2025-07-14T22:03:33.611Z" }, - { url = "https://files.pythonhosted.org/packages/23/28/9541b4e8c52c8eb3bec3fbeda69d2dca1b507fbdd4561424af94e1866bda/bitarray-3.5.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fb6c976df1fce6c60c4bd403df2e477da5b038770f10ad5d38135e166f9052c7", size = 310866, upload-time = "2025-07-14T22:03:34.963Z" }, - { url = "https://files.pythonhosted.org/packages/85/9a/5dadbd3a76119d5c021653517e07d56a75112282edda3a701f8082af0de7/bitarray-3.5.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:fa357072eb27b573aa6b4ff48e963261e1bf27e50fc50dbe232fed3273600a39", size = 315694, upload-time = "2025-07-14T22:03:36.333Z" }, - { url = "https://files.pythonhosted.org/packages/58/18/66e16adb6f7b03b715a5d1ccd5dbb74ff364ddd65702a1661894572e38e1/bitarray-3.5.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d2196f20ccb878e23233c76a47fe7ef523b96361be3e257a5b10105a1f818289", size = 307452, upload-time = "2025-07-14T22:03:37.674Z" }, - { url = "https://files.pythonhosted.org/packages/0c/db/97eed08e63ab752bdfa326b89e987e05b383a1c5d7aee5b6a3c748625108/bitarray-3.5.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:8c18212e1cadc38003438907062e24742cc0979134923070b54042a71ead06a0", size = 331943, upload-time = "2025-07-14T22:03:39.319Z" }, - { url = "https://files.pythonhosted.org/packages/bd/94/ed5c358156595adb37967dc85ef565774905ffdd8ebe383e2741f0ac564d/bitarray-3.5.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:6834bf89530ad4cd8d80af9e89c7ae47ee376ff96b829fed6d818e417aab4b8a", size = 335566, upload-time = "2025-07-14T22:03:41.093Z" }, - { url = "https://files.pythonhosted.org/packages/1b/93/174735954c25b1ea93e52ee5646ea8ac4cc06f38ae0a707dfe28af5ac868/bitarray-3.5.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:ab3cd324e4643d43b7227af5eb332ef28dbc123e68f36557ca1e8631bf292012", size = 315593, upload-time = "2025-07-14T22:03:42.911Z" }, - { url = "https://files.pythonhosted.org/packages/49/3f/2a39a67604f06988d437f9830f44a434b43794a5269d1f1ee34c645d8e7d/bitarray-3.5.1-cp313-cp313-win32.whl", hash = "sha256:09fed8c5e4584f498c2e1310edbbc370f85f131e71cd9a1d75f00412bb580767", size = 138958, upload-time = "2025-07-14T22:03:44.144Z" }, - { url = "https://files.pythonhosted.org/packages/b5/54/da42bc87dedb20dd9c8b0127f504fd2dd974c598cc6b854f5da27b5a913b/bitarray-3.5.1-cp313-cp313-win_amd64.whl", hash = "sha256:287029b18624c9dc75af521e1aec4c673d4707d64833375c478eeb22155a3ba9", size = 145819, upload-time = "2025-07-14T22:03:45.356Z" }, - { url = "https://files.pythonhosted.org/packages/0d/d6/315120866d9842e9a17952db2a91a931dd5cc91cb513b7fdf115459841c3/bitarray-3.5.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:c4e862295ad3e3eb728138315dd3e2e2255a5f1a75d234a0990d073dc0905936", size = 140312, upload-time = "2025-07-14T22:05:11.974Z" }, - { url = "https://files.pythonhosted.org/packages/33/ec/3716031414f5ec87e94371242f9261c19459abc935059358a0c1f1dd793b/bitarray-3.5.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:983be82cfde6c59204f7862ee71c87b999163f366a4ac649121c257f0b73442c", size = 137234, upload-time = "2025-07-14T22:05:13.311Z" }, - { url = "https://files.pythonhosted.org/packages/3d/dd/0c07e8515e52e462b22ab6760f75fbfe8beb5b8a673dfa938ae1d6e55345/bitarray-3.5.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ae197e132d347096ce58c8dee3fa462ace2cc3261286fc63e5a36f843ef2074c", size = 145927, upload-time = "2025-07-14T22:05:14.645Z" }, - { url = "https://files.pythonhosted.org/packages/56/d8/7011ea2a7d672e66aa2893009229fe10e0da4cf35cba71a5fa95b4d596d0/bitarray-3.5.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2d76b6a3c7a8e44607c9bdc3291a95086652068e60e1c9311993b3decad14e38", size = 146683, upload-time = "2025-07-14T22:05:16.384Z" }, - { url = "https://files.pythonhosted.org/packages/d5/c5/c5c932c001e0764e1e4ca4d62dbd1b4c6dccae9c6ed8da3ac977e4993999/bitarray-3.5.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7dd8a6627b55d9ac9224890c678b1d57d4fefa87118717428fd8c4bd2761c20b", size = 148234, upload-time = "2025-07-14T22:05:17.735Z" }, - { url = "https://files.pythonhosted.org/packages/2e/7f/c6fb356af46e954e3f362d97b8cc19dec4e79bdd373234e8feae309896c3/bitarray-3.5.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:33233ee4c4245b7da2c395468a44473c834eeea7cd53fe97dc419451bf8e6e9a", size = 144113, upload-time = "2025-07-14T22:05:19.095Z" }, -] - -[[package]] -name = "blinker" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, -] - -[[package]] -name = "certifi" -version = "2025.7.14" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/76/52c535bcebe74590f296d6c77c86dabf761c41980e1347a2422e4aa2ae41/certifi-2025.7.14.tar.gz", hash = "sha256:8ea99dbdfaaf2ba2f9bac77b9249ef62ec5218e7c2b2e903378ed5fccf765995", size = 163981, upload-time = "2025-07-14T03:29:28.449Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4f/52/34c6cf5bb9285074dc3531c437b3919e825d976fde097a7a73f79e726d03/certifi-2025.7.14-py3-none-any.whl", hash = "sha256:6b31f564a415d79ee77df69d757bb49a5bb53bd9f756cbbe24394ffd6fc1f4b2", size = 162722, upload-time = "2025-07-14T03:29:26.863Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9b/892a8c8af9110935e5adcbb06d9c6fe741b6bb02608c6513983048ba1a18/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd", size = 144649, upload-time = "2025-05-02T08:31:48.889Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a5/4179abd063ff6414223575e008593861d62abfc22455b5d1a44995b7c101/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6", size = 155045, upload-time = "2025-05-02T08:31:50.757Z" }, - { url = "https://files.pythonhosted.org/packages/3b/95/bc08c7dfeddd26b4be8c8287b9bb055716f31077c8b0ea1cd09553794665/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d", size = 147356, upload-time = "2025-05-02T08:31:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/7a5b635aa65284bf3eab7653e8b4151ab420ecbae918d3e359d1947b4d61/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86", size = 149471, upload-time = "2025-05-02T08:31:56.207Z" }, - { url = "https://files.pythonhosted.org/packages/ae/38/51fc6ac74251fd331a8cfdb7ec57beba8c23fd5493f1050f71c87ef77ed0/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c", size = 151317, upload-time = "2025-05-02T08:31:57.613Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/edee1e32215ee6e9e46c3e482645b46575a44a2d72c7dfd49e49f60ce6bf/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0", size = 146368, upload-time = "2025-05-02T08:31:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/26/2c/ea3e66f2b5f21fd00b2825c94cafb8c326ea6240cd80a91eb09e4a285830/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef", size = 154491, upload-time = "2025-05-02T08:32:01.219Z" }, - { url = "https://files.pythonhosted.org/packages/52/47/7be7fa972422ad062e909fd62460d45c3ef4c141805b7078dbab15904ff7/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6", size = 157695, upload-time = "2025-05-02T08:32:03.045Z" }, - { url = "https://files.pythonhosted.org/packages/2f/42/9f02c194da282b2b340f28e5fb60762de1151387a36842a92b533685c61e/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366", size = 154849, upload-time = "2025-05-02T08:32:04.651Z" }, - { url = "https://files.pythonhosted.org/packages/67/44/89cacd6628f31fb0b63201a618049be4be2a7435a31b55b5eb1c3674547a/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db", size = 150091, upload-time = "2025-05-02T08:32:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/1f/79/4b8da9f712bc079c0f16b6d67b099b0b8d808c2292c937f267d816ec5ecc/charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a", size = 98445, upload-time = "2025-05-02T08:32:08.66Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d7/96970afb4fb66497a40761cdf7bd4f6fca0fc7bafde3a84f836c1f57a926/charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509", size = 105782, upload-time = "2025-05-02T08:32:10.46Z" }, - { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" }, - { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" }, - { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" }, - { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" }, - { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" }, - { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, -] - -[[package]] -name = "ckzg" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/55/df/f6db8e83bd4594c1ea685cd37fb81d5399e55765aae16d1a8a9502598f4e/ckzg-2.1.1.tar.gz", hash = "sha256:d6b306b7ec93a24e4346aa53d07f7f75053bc0afc7398e35fa649e5f9d48fcc4", size = 1120500, upload-time = "2025-03-31T21:24:12.324Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/4b/cd25e857cdf46a752e97c530fe2582fae77c4d16c29fff5a15b7a998e2fd/ckzg-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b9825a1458219e8b4b023012b8ef027ef1f47e903f9541cbca4615f80132730", size = 116377, upload-time = "2025-03-31T21:22:26.952Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bc/5dfef36589545f797245ecacb54ed2acfa75507f63cfe12182d1277a88f1/ckzg-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2a40a3ba65cca4b52825d26829e6f7eb464aa27a9e9efb6b8b2ce183442c741", size = 100208, upload-time = "2025-03-31T21:22:28.04Z" }, - { url = "https://files.pythonhosted.org/packages/b7/52/96f0e3affbed321dc52b9b4ca13e0fb594da572d1f8edc47378fe48d8e9a/ckzg-2.1.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1d753fbe85be7c21602eddc2d40e0915e25fce10329f4f801a0002a4f886cc7", size = 174800, upload-time = "2025-03-31T21:22:29.719Z" }, - { url = "https://files.pythonhosted.org/packages/dc/21/b1bc07cc8e5ed32817e89b054e2399d38775d92ff2d55e24bf233f537c02/ckzg-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d76b50527f1d12430bf118aff6fa4051e9860eada43f29177258b8d399448ea", size = 160847, upload-time = "2025-03-31T21:22:30.973Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5a/97b173d4ff9bce798031beb12b340c4f1729eaaddd07f69f368f843db28e/ckzg-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44c8603e43c021d100f355f50189183135d1df3cbbddb8881552d57fbf421dde", size = 169712, upload-time = "2025-03-31T21:22:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/7b/52/48be78c07f362438e189e2fbea7df8543290c3ee99845442549c8dc5405b/ckzg-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:38707a638c9d715b3c30b29352b969f78d8fc10faed7db5faf517f04359895c0", size = 172942, upload-time = "2025-03-31T21:22:32.8Z" }, - { url = "https://files.pythonhosted.org/packages/13/42/3cfcd6cbdfb9030b9071d5e413a458f93883e47ad4a7d8d4c1d57608e57d/ckzg-2.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:52c4d257bdcbe822d20c5cd24c8154ec5aac33c49a8f5a19e716d9107a1c8785", size = 187707, upload-time = "2025-03-31T21:22:33.673Z" }, - { url = "https://files.pythonhosted.org/packages/eb/54/d43bc3a2de486fb8be29ffedc3ec80f5726765ee4fa78beabe2ab2440f93/ckzg-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1507f7bfb9bcf51d816db5d8d0f0ed53c8289605137820d437b69daea8333e16", size = 182505, upload-time = "2025-03-31T21:22:34.563Z" }, - { url = "https://files.pythonhosted.org/packages/21/43/5bcd2b7630732b532006572fbb8d64a29f69530c630ae4811167a2a0dc3b/ckzg-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d02eaaf4f841910133552b3a051dea53bcfe60cd98199fc4cf80b27609d8baa2", size = 98822, upload-time = "2025-03-31T21:22:35.786Z" }, - { url = "https://files.pythonhosted.org/packages/95/2c/44120b2d9dcb0246d67a1f28b9eaa625c499014d4d42561467e28eedd285/ckzg-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:465e2b71cf9dc383f66f1979269420a0da9274a3a9e98b1a4455e84927dfe491", size = 116378, upload-time = "2025-03-31T21:22:36.96Z" }, - { url = "https://files.pythonhosted.org/packages/23/88/c5b89ba9a730fee5e089be9e0c7048fb6707c1a0e4b6c30fcf725c3eef44/ckzg-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ee2f26f17a64ad0aab833d637b276f28486b82a29e34f32cf54b237b8f8ab72d", size = 100202, upload-time = "2025-03-31T21:22:37.799Z" }, - { url = "https://files.pythonhosted.org/packages/ee/11/b0a473e80346db52ad9a629bc9fd8f773c718ed78932ea3a70392306ffc3/ckzg-2.1.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99cc2c4e9fb8c62e3e0862c7f4df9142f07ba640da17fded5f6e0fd09f75909f", size = 175595, upload-time = "2025-03-31T21:22:39.013Z" }, - { url = "https://files.pythonhosted.org/packages/52/fa/17a7e125d07a96dd6dce4db7262231f7583856b2be5d5b7df59e04bfa188/ckzg-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773dd016693d74aca1f5d7982db2bad7dde2e147563aeb16a783f7e5f69c01fe", size = 161681, upload-time = "2025-03-31T21:22:40.257Z" }, - { url = "https://files.pythonhosted.org/packages/57/bd/46d6b90bf53da732f9adab7593d132a0834ed4f2f7659b4c7414d8f78d39/ckzg-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af2b2144f87ba218d8db01382a961b3ecbdde5ede4fa0d9428d35f8c8a595ba", size = 170471, upload-time = "2025-03-31T21:22:41.513Z" }, - { url = "https://files.pythonhosted.org/packages/9d/98/113c7704749d037d75f23240ffc5c46dfe8416de574b946438587835715f/ckzg-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f55e63d3f7c934a2cb53728ed1d815479e177aca8c84efe991c2920977cff6", size = 173595, upload-time = "2025-03-31T21:22:42.534Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d5/05fca6dcb5a19327be491157794eafc3d7498daf615c2ff5a5b745852945/ckzg-2.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ecb42aaa0ffa427ff14a9dde9356ba69e5ae6014650b397af55b31bdae7a9b6e", size = 188417, upload-time = "2025-03-31T21:22:43.466Z" }, - { url = "https://files.pythonhosted.org/packages/72/36/131ae2dfc82d0fdc98fae8e3bbfe71ff14265bb434b23bd07b585afc6d61/ckzg-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5a01514239f12fb1a7ad9009c20062a4496e13b09541c1a65f97e295da648c70", size = 183286, upload-time = "2025-03-31T21:22:44.732Z" }, - { url = "https://files.pythonhosted.org/packages/c5/6a/d371b27024422b25228fc11fa57b1ba7756a94cc9fb0c75da292c235fdaa/ckzg-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:6516b9684aae262c85cf7fddd8b585b8139ad20e08ec03994e219663abbb0916", size = 98819, upload-time = "2025-03-31T21:22:45.57Z" }, - { url = "https://files.pythonhosted.org/packages/93/a1/9c07513dd0ea01e5db727e67bd2660f3b300a4511281cdb8d5e04afa1cfd/ckzg-2.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c60e8903344ce98ce036f0fabacce952abb714cad4607198b2f0961c28b8aa72", size = 116421, upload-time = "2025-03-31T21:22:46.434Z" }, - { url = "https://files.pythonhosted.org/packages/27/04/b69a0dfbb2722a14c98a52973f276679151ec56a14178cb48e6f2e1697bc/ckzg-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4299149dd72448e5a8d2d1cc6cc7472c92fc9d9f00b1377f5b017c089d9cd92", size = 100216, upload-time = "2025-03-31T21:22:47.633Z" }, - { url = "https://files.pythonhosted.org/packages/2e/24/9cc850d0b8ead395ad5064de67c7c91adacaf31b6b35292ab53fbd93270b/ckzg-2.1.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:025dd31ffdcc799f3ff842570a2a6683b6c5b01567da0109c0c05d11768729c4", size = 175764, upload-time = "2025-03-31T21:22:48.768Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c1/eb13ba399082a98b932f10b230ec08e6456051c0ce3886b3f6d8548d11ab/ckzg-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b42ab8385c273f40a693657c09d2bba40cb4f4666141e263906ba2e519e80bd", size = 161885, upload-time = "2025-03-31T21:22:50.05Z" }, - { url = "https://files.pythonhosted.org/packages/57/c7/58baa64199781950c5a8c6139a46e1acff0f057a36e56769817400eb87fb/ckzg-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be3890fc1543f4fcfc0063e4baf5c036eb14bcf736dabdc6171ab017e0f1671", size = 170757, upload-time = "2025-03-31T21:22:51.282Z" }, - { url = "https://files.pythonhosted.org/packages/65/bd/4b8e1c70972c98829371b7004dc750a45268c5d3442d602e1b62f13ca867/ckzg-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b754210ded172968b201e2d7252573af6bf52d6ad127ddd13d0b9a45a51dae7b", size = 173761, upload-time = "2025-03-31T21:22:52.6Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/c3fd1002f97ba3e0c5b1d9ab2c8fb7a6f475fa9b80ed9c4fa55975501a54/ckzg-2.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2f8fda87865897a269c4e951e3826c2e814427a6cdfed6731cccfe548f12b36", size = 188666, upload-time = "2025-03-31T21:22:53.47Z" }, - { url = "https://files.pythonhosted.org/packages/e2/d9/91cf5a8169ee60c9397c975163cbca34432571f94facec5f8c0086bb47d8/ckzg-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:98e70b5923d77c7359432490145e9d1ab0bf873eb5de56ec53f4a551d7eaec79", size = 183652, upload-time = "2025-03-31T21:22:54.351Z" }, - { url = "https://files.pythonhosted.org/packages/25/d4/8c9f6b852f99926862344b29f0c59681916ccfec2ac60a85952a369e0bca/ckzg-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:42af7bde4ca45469cd93a96c3d15d69d51d40e7f0d30e3a20711ebd639465fcb", size = 98816, upload-time = "2025-03-31T21:22:55.23Z" }, - { url = "https://files.pythonhosted.org/packages/b7/9a/fa698b12e97452d11dd314e0335aae759725284ef6e1c1665aed56b1cd3e/ckzg-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e4edfdaf87825ff43b9885fabfdea408737a714f4ce5467100d9d1d0a03b673", size = 116426, upload-time = "2025-03-31T21:22:56.108Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/8cccd308bd11b49b40eecad6900b5769da117951cac33e880dd25e851ef7/ckzg-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:815fd2a87d6d6c57d669fda30c150bc9bf387d47e67d84535aa42b909fdc28ea", size = 100219, upload-time = "2025-03-31T21:22:56.982Z" }, - { url = "https://files.pythonhosted.org/packages/30/0e/63573d816c1292b9a4d70eb6a7366b3593d29a977794039e926805a76ca0/ckzg-2.1.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32466e809b1ab3ff01d3b0bb0b9912f61dcf72957885615595f75e3f7cc10e5", size = 175725, upload-time = "2025-03-31T21:22:58.213Z" }, - { url = "https://files.pythonhosted.org/packages/86/f6/a279609516695ad3fb8b201098c669ba3b2844cbf4fa0d83a0f02b9bb29b/ckzg-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f11b73ccf37b12993f39a7dbace159c6d580aacacde6ee17282848476550ddbc", size = 161835, upload-time = "2025-03-31T21:22:59.448Z" }, - { url = "https://files.pythonhosted.org/packages/39/e4/8cf7aef7dc05a777cb221e94046f947c6fe5317159a8dae2cd7090d52ef2/ckzg-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3b9433a1f2604bd9ac1646d3c83ad84a850d454d3ac589fe8e70c94b38a6b0", size = 170759, upload-time = "2025-03-31T21:23:01.022Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/b34e3c08eb36bc67e338b114f289b2595e581b8bdc09a8f12299a1db5d2f/ckzg-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b7d7e1b5ea06234558cd95c483666fd785a629b720a7f1622b3cbffebdc62033", size = 173787, upload-time = "2025-03-31T21:23:01.974Z" }, - { url = "https://files.pythonhosted.org/packages/2e/f0/aff87c3ed80713453cb6c84fe6fbb7582d86a7a5e4460fda2a497d47f489/ckzg-2.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9f5556e6675866040cc4335907be6c537051e7f668da289fa660fdd8a30c9ddb", size = 188722, upload-time = "2025-03-31T21:23:02.966Z" }, - { url = "https://files.pythonhosted.org/packages/44/d9/1f08bfb8fd1cbb8c7513e7ad3fb76bbb5c3fb446238c1eba582276e4d905/ckzg-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55b2ba30c5c9daac0c55f1aac851f1b7bf1f7aa0028c2db4440e963dd5b866d6", size = 183686, upload-time = "2025-03-31T21:23:03.905Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ff/434f6d2893cbdfad00c20d17e9a52d426ca042f5e980d5c3db96bc6b6e15/ckzg-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:10d201601fc8f28c0e8cec3406676797024dd374c367bbeec5a7a9eac9147237", size = 98817, upload-time = "2025-03-31T21:23:05.2Z" }, - { url = "https://files.pythonhosted.org/packages/30/b3/a0c7d7ba6e669cf04605dc0329173db62fc1fe3c488761755cc01e5e1b4d/ckzg-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:375918e25eafb9bafe5215ab91698504cba3fe51b4fe92f5896af6c5663f50c6", size = 113191, upload-time = "2025-03-31T21:23:40.646Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b9/a6cf403b8528d18d7d9154e28381a397bf466c86aa8e0b3327cffdde5749/ckzg-2.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:38b3b7802c76d4ad015db2b7a79a49c193babae50ee5f77e9ac2865c9e9ddb09", size = 96207, upload-time = "2025-03-31T21:23:41.596Z" }, - { url = "https://files.pythonhosted.org/packages/63/6b/5ddd713d97886becb8450e3e13db891199125f722366d30d087ad5438390/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438a5009fd254ace0bc1ad974d524547f1a41e6aa5e778c5cd41f4ee3106bcd6", size = 126160, upload-time = "2025-03-31T21:23:42.553Z" }, - { url = "https://files.pythonhosted.org/packages/c7/dd/e05aecc01e62108a7579f8df5e5d38536841f50e12172f8a84677edac0fa/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce11cc163a2e0dab3af7455aca7053f9d5bb8d157f231acc7665fd230565d48", size = 102811, upload-time = "2025-03-31T21:23:43.494Z" }, - { url = "https://files.pythonhosted.org/packages/c6/81/6cdadd8626ac11290af3f58ae5dcffe38bd2c8f8c798dacee7475e244aac/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b53964c07f6a076e97eaa1ef35045e935d7040aff14f80bae7e9105717702d05", size = 111328, upload-time = "2025-03-31T21:23:44.449Z" }, - { url = "https://files.pythonhosted.org/packages/36/b7/b129ff6955cd264c6ab3dbd52dd1b2759d1b121c09c03f9991e4c722c72f/ckzg-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cf085f15ae52ab2599c9b5a3d5842794bcf5613b7f58661fbfb0c5d9eac988b9", size = 98846, upload-time = "2025-03-31T21:23:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ba/7d9c1f9cec7e0e382653c72165896194a05743e589b1dae2aa80236aa87f/ckzg-2.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4b0c850bd6cad22ac79b2a2ab884e0e7cd2b54a67d643cd616c145ebdb535a11", size = 113188, upload-time = "2025-03-31T21:23:46.337Z" }, - { url = "https://files.pythonhosted.org/packages/2f/92/9728f5ccc1c5e87c6c5ae7941250a447b61fd5a63aadbc15249e29c21bcf/ckzg-2.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:26951f36bb60c9150bbd38110f5e1625596f9779dad54d1d492d8ec38bc84e3a", size = 96208, upload-time = "2025-03-31T21:23:47.255Z" }, - { url = "https://files.pythonhosted.org/packages/39/63/5e27d587bd224fee70cb66b022e7c4ef95d0e091e08ee76c25ec12094b0d/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbe12445e49c4bee67746b7b958e90a973b0de116d0390749b0df351d94e9a8c", size = 126158, upload-time = "2025-03-31T21:23:48.195Z" }, - { url = "https://files.pythonhosted.org/packages/43/98/e0a45946575a7b823d8ee0b47afb104b6017e54e1208f07da2529bc01900/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c5d4f66f09de4a99271acac74d2acb3559a77de77a366b34a91e99e8822667", size = 102812, upload-time = "2025-03-31T21:23:49.16Z" }, - { url = "https://files.pythonhosted.org/packages/cb/50/718ca7b03e4b89b18cdf99cc3038050105b0acbf9b612c23cd513093c6de/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42673c1d007372a4e8b48f6ef8f0ce31a9688a463317a98539757d1e2fb1ecc7", size = 111327, upload-time = "2025-03-31T21:23:50.126Z" }, - { url = "https://files.pythonhosted.org/packages/29/c5/80e5a0c6967d02d801150104320484a258e5a49bd191e198643e74039320/ckzg-2.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:57a7dc41ec6b69c1d9117eb61cf001295e6b4f67a736020442e71fb4367fb1a5", size = 98847, upload-time = "2025-03-31T21:23:51.084Z" }, -] - -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "cytoolz" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "toolz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/f9/3243eed3a6545c2a33a21f74f655e3fcb5d2192613cd3db81a93369eb339/cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6", size = 626652, upload-time = "2024-12-13T05:47:36.672Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d9/f13d66c16cff1fa1cb6c234698029877c456f35f577ef274aba3b86e7c51/cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042", size = 403515, upload-time = "2024-12-13T05:44:27.845Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2d/4cdf848a69300c7d44984f2ebbebb3b8576e5449c8dea157298f3bdc4da3/cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608", size = 383936, upload-time = "2024-12-13T05:44:29.5Z" }, - { url = "https://files.pythonhosted.org/packages/72/a4/ccfdd3f0ed9cc818f734b424261f6018fc61e3ec833bf85225a9aca0d994/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90124bdc42ff58b88cdea1d24a6bc5f776414a314cc4d94f25c88badb3a16d1", size = 1934569, upload-time = "2024-12-13T05:44:30.799Z" }, - { url = "https://files.pythonhosted.org/packages/50/fc/38d5344fa595683ad10dc819cfc1d8b9d2b3391ccf3e8cb7bab4899a01f5/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e74801b751e28f7c5cc3ad264c123954a051f546f2fdfe089f5aa7a12ccfa6da", size = 2015129, upload-time = "2024-12-13T05:44:32.297Z" }, - { url = "https://files.pythonhosted.org/packages/28/29/75261748dc54a20a927f33641f4e9aac674cfc6d3fbd4f332e10d0b37639/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582dad4545ddfb5127494ef23f3fa4855f1673a35d50c66f7638e9fb49805089", size = 2000506, upload-time = "2024-12-13T05:44:34.403Z" }, - { url = "https://files.pythonhosted.org/packages/00/ae/e4ead004cc2698281d153c4a5388638d67cdb5544d6d6cc1e5b3db2bd2a3/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7bd0618e16efe03bd12f19c2a26a27e6e6b75d7105adb7be1cd2a53fa755d8", size = 1957537, upload-time = "2024-12-13T05:44:39.499Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ff/4f3aa07f4f47701f7f63df60ce0a5669fa09c256c3d4a33503a9414ea5cc/cytoolz-1.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d74cca6acf1c4af58b2e4a89cc565ed61c5e201de2e434748c93e5a0f5c541a5", size = 1863331, upload-time = "2024-12-13T05:44:42.61Z" }, - { url = "https://files.pythonhosted.org/packages/a2/29/654f57f2a9b8e9765a4ab876765f64f94530b61fc6471a07feea42ece6d4/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:823a3763828d8d457f542b2a45d75d6b4ced5e470b5c7cf2ed66a02f508ed442", size = 1849938, upload-time = "2024-12-13T05:44:45.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/7b/11f457db6b291060a98315ab2c7198077d8bddeeebe5f7126d9dad98cc54/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:51633a14e6844c61db1d68c1ffd077cf949f5c99c60ed5f1e265b9e2966f1b52", size = 1852345, upload-time = "2024-12-13T05:44:47.994Z" }, - { url = "https://files.pythonhosted.org/packages/6b/92/0dccc96ce0323be236d404f5084479b79b747fa0e74e43a270e95868b5f9/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3ec9b01c45348f1d0d712507d54c2bfd69c62fbd7c9ef555c9d8298693c2432", size = 1989877, upload-time = "2024-12-13T05:44:51.514Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c8/1c5203a81200bae51aa8f7b5fad613f695bf1afa03f16251ca23ecb2ef9f/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1855022b712a9c7a5bce354517ab4727a38095f81e2d23d3eabaf1daeb6a3b3c", size = 1994492, upload-time = "2024-12-13T05:44:52.922Z" }, - { url = "https://files.pythonhosted.org/packages/e2/8a/04bc193c4d7ced8ef6bb62cdcd0bf40b5e5eb26586ed2cfb4433ec7dfd0a/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9930f7288c4866a1dc1cc87174f0c6ff4cad1671eb1f6306808aa6c445857d78", size = 1896077, upload-time = "2024-12-13T05:44:56.118Z" }, - { url = "https://files.pythonhosted.org/packages/21/a5/bee63a58f51d2c74856db66e6119a014464ff8cb1c9387fa4bd2d94e49b0/cytoolz-1.0.1-cp310-cp310-win32.whl", hash = "sha256:a9baad795d72fadc3445ccd0f122abfdbdf94269157e6d6d4835636dad318804", size = 322135, upload-time = "2024-12-13T05:44:57.695Z" }, - { url = "https://files.pythonhosted.org/packages/e8/16/7abfb1685e8b7f2838264551ee33651748994813f566ac4c3d737dfe90e5/cytoolz-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad95b386a84e18e1f6136f6d343d2509d4c3aae9f5a536f3dc96808fcc56a8cf", size = 363599, upload-time = "2024-12-13T05:44:58.875Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ea/8131ae39119820b8867cddc23716fa9f681f2b3bbce6f693e68dfb36b55b/cytoolz-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d958d4f04d9d7018e5c1850790d9d8e68b31c9a2deebca74b903706fdddd2b6", size = 406162, upload-time = "2024-12-13T05:45:01.196Z" }, - { url = "https://files.pythonhosted.org/packages/26/18/3d9bd4c146f6ea6e51300c242b20cb416966b21d481dac230e1304f1e54b/cytoolz-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0f445b8b731fc0ecb1865b8e68a070084eb95d735d04f5b6c851db2daf3048ab", size = 384961, upload-time = "2024-12-13T05:45:02.387Z" }, - { url = "https://files.pythonhosted.org/packages/e4/73/9034827907c7f85c7c484c9494e905d022fb8174526004e9ef332570349e/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f546a96460a7e28eb2ec439f4664fa646c9b3e51c6ebad9a59d3922bbe65e30", size = 2091698, upload-time = "2024-12-13T05:45:04.353Z" }, - { url = "https://files.pythonhosted.org/packages/74/af/d5c2733b0fde1a08254ff1a8a8d567874040c9eb1606363cfebc0713c73f/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0317681dd065532d21836f860b0563b199ee716f55d0c1f10de3ce7100c78a3b", size = 2188452, upload-time = "2024-12-13T05:45:05.748Z" }, - { url = "https://files.pythonhosted.org/packages/6a/bb/77c71fa9c217260b4056a732d754748903423c2cdd82a673d6064741e375/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0ef52febd5a7821a3fd8d10f21d460d1a3d2992f724ba9c91fbd7a96745d41", size = 2174203, upload-time = "2024-12-13T05:45:07.777Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a9/a5b4a3ff5d22faa1b60293bfe97362e2caf4a830c26d37ab5557f60d04b2/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebaf419acf2de73b643cf96108702b8aef8e825cf4f63209ceb078d5fbbbfd", size = 2099831, upload-time = "2024-12-13T05:45:11.477Z" }, - { url = "https://files.pythonhosted.org/packages/35/08/7f6869ea1ff31ce5289a7d58d0e7090acfe7058baa2764473048ff61ea3c/cytoolz-1.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f7f04eeb4088947585c92d6185a618b25ad4a0f8f66ea30c8db83cf94a425e3", size = 1996744, upload-time = "2024-12-13T05:45:14.172Z" }, - { url = "https://files.pythonhosted.org/packages/46/b4/9ac424c994b51763fd1bbed62d95f8fba8fa0e45c8c3c583904fdaf8f51d/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f61928803bb501c17914b82d457c6f50fe838b173fb40d39c38d5961185bd6c7", size = 2013733, upload-time = "2024-12-13T05:45:16.912Z" }, - { url = "https://files.pythonhosted.org/packages/3e/99/03009765c4b87d742d5b5a8670abb56a8c7ede033c2cdaa4be8662d3b001/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d2960cb4fa01ccb985ad1280db41f90dc97a80b397af970a15d5a5de403c8c61", size = 1994850, upload-time = "2024-12-13T05:45:18.414Z" }, - { url = "https://files.pythonhosted.org/packages/40/9a/8458af9a5557e177ea42f8cf7e477bede518b0bbef564e28c4151feaa52c/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2b407cc3e9defa8df5eb46644f6f136586f70ba49eba96f43de67b9a0984fd3", size = 2155352, upload-time = "2024-12-13T05:45:19.763Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5c/2a701423e001fcbec288b4f3fc2bf67557d114c2388237fc1ae67e1e2686/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8245f929144d4d3bd7b972c9593300195c6cea246b81b4c46053c48b3f044580", size = 2163515, upload-time = "2024-12-13T05:45:21.08Z" }, - { url = "https://files.pythonhosted.org/packages/36/16/ee2e06e65d9d533bc05cd52a0b355ba9072fc8f60d77289e529c6d2e3750/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37385db03af65763933befe89fa70faf25301effc3b0485fec1c15d4ce4f052", size = 2054431, upload-time = "2024-12-13T05:45:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d5/2fac8315f210fa1bc7106e27c19e1211580aa25bb7fa17dfd79505e5baf2/cytoolz-1.0.1-cp311-cp311-win32.whl", hash = "sha256:50f9c530f83e3e574fc95c264c3350adde8145f4f8fc8099f65f00cc595e5ead", size = 322004, upload-time = "2024-12-13T05:45:24.048Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9e/0b70b641850a95f9ff90adde9d094a4b1d81ec54dadfd97fec0a2aaf440e/cytoolz-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b7f6b617454b4326af7bd3c7c49b0fc80767f134eb9fd6449917a058d17a0e3c", size = 365358, upload-time = "2024-12-13T05:45:25.383Z" }, - { url = "https://files.pythonhosted.org/packages/d8/e8/218098344ed2cb5f8441fade9b2428e435e7073962374a9c71e59ac141a7/cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4", size = 414121, upload-time = "2024-12-13T05:45:26.588Z" }, - { url = "https://files.pythonhosted.org/packages/de/27/4d729a5653718109262b758fec1a959aa9facb74c15460d9074dc76d6635/cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662", size = 390904, upload-time = "2024-12-13T05:45:27.718Z" }, - { url = "https://files.pythonhosted.org/packages/72/c0/cbabfa788bab9c6038953bf9478adaec06e88903a726946ea7c88092f5c4/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3", size = 2090734, upload-time = "2024-12-13T05:45:30.515Z" }, - { url = "https://files.pythonhosted.org/packages/c3/66/369262c60f9423c2da82a60864a259c852f1aa122aced4acd2c679af58c0/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1", size = 2155933, upload-time = "2024-12-13T05:45:32.721Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4e/ee55186802f8d24b5fbf9a11405ccd1203b30eded07cc17750618219b94e/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8", size = 2171903, upload-time = "2024-12-13T05:45:34.205Z" }, - { url = "https://files.pythonhosted.org/packages/a1/96/bd1a9f3396e9b7f618db8cd08d15630769ce3c8b7d0534f92cd639c977ae/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d", size = 2125270, upload-time = "2024-12-13T05:45:36.982Z" }, - { url = "https://files.pythonhosted.org/packages/28/48/2a3762873091c88a69e161111cfbc6c222ff145d57ff011a642b169f04f1/cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f", size = 1973967, upload-time = "2024-12-13T05:45:39.505Z" }, - { url = "https://files.pythonhosted.org/packages/e4/50/500bd69774bdc49a4d78ec8779eb6ac7c1a9d706bfd91cf2a1dba604373a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7", size = 2021695, upload-time = "2024-12-13T05:45:40.911Z" }, - { url = "https://files.pythonhosted.org/packages/e4/4e/ba5a0ce34869495eb50653de8d676847490cf13a2cac1760fc4d313e78de/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126", size = 2010177, upload-time = "2024-12-13T05:45:42.48Z" }, - { url = "https://files.pythonhosted.org/packages/87/57/615c630b3089a13adb15351d958d227430cf624f03b1dd39eb52c34c1f59/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0", size = 2154321, upload-time = "2024-12-13T05:45:43.979Z" }, - { url = "https://files.pythonhosted.org/packages/7f/0f/fe1aa2d931e3b35ecc05215bd75da945ea7346095b3b6f6027164e602d5a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b", size = 2188374, upload-time = "2024-12-13T05:45:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/de/fa/fd363d97a641b6d0e2fd1d5c35b8fd41d9ccaeb4df56302f53bf23a58e3a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d", size = 2077911, upload-time = "2024-12-13T05:45:48.219Z" }, - { url = "https://files.pythonhosted.org/packages/d9/68/0a22946b98ae5201b54ccb4e651295285c0fb79406022b6ee8b2f791940c/cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9", size = 321903, upload-time = "2024-12-13T05:45:50.3Z" }, - { url = "https://files.pythonhosted.org/packages/62/1a/f3903197956055032f8cb297342e2dff07e50f83991aebfe5b4c4fcb55e4/cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b", size = 364490, upload-time = "2024-12-13T05:45:51.494Z" }, - { url = "https://files.pythonhosted.org/packages/aa/2e/a9f069db0107749e9e72baf6c21abe3f006841a3bcfdc9b8420e22ef31eb/cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0", size = 407365, upload-time = "2024-12-13T05:45:52.803Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9b/5e87dd0e31f54c778b4f9f34cc14c1162d3096c8d746b0f8be97d70dd73c/cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a", size = 385233, upload-time = "2024-12-13T05:45:53.994Z" }, - { url = "https://files.pythonhosted.org/packages/63/00/2fd32b16284cdb97cfe092822179bc0c3bcdd5e927dd39f986169a517642/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242", size = 2062903, upload-time = "2024-12-13T05:45:55.202Z" }, - { url = "https://files.pythonhosted.org/packages/85/39/b3cbb5a9847ba59584a263772ad4f8ca2dbfd2a0e11efd09211d1219804c/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296", size = 2139517, upload-time = "2024-12-13T05:45:56.804Z" }, - { url = "https://files.pythonhosted.org/packages/ea/39/bfcab4a46d50c467e36fe704f19d8904efead417787806ee210327f68390/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b", size = 2154849, upload-time = "2024-12-13T05:45:58.814Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/3bc6ee61b0aa47e1cb40819adc1a456d7efa809f0dea9faddacb43fdde8f/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b", size = 2102302, upload-time = "2024-12-13T05:46:00.181Z" }, - { url = "https://files.pythonhosted.org/packages/00/66/3f636c6ddea7b18026b90a8c238af472e423b86e427b11df02213689b012/cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266", size = 1960872, upload-time = "2024-12-13T05:46:01.612Z" }, - { url = "https://files.pythonhosted.org/packages/40/36/cb3b7cdd651007b69f9c48e9d104cec7cb8dc53afa1d6a720e5ad08022fa/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5", size = 2014430, upload-time = "2024-12-13T05:46:03.022Z" }, - { url = "https://files.pythonhosted.org/packages/88/3f/2e9bd2a16cfd269808922147551dcb2d8b68ba54a2c4deca2fa6a6cd0d5f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3", size = 2003127, upload-time = "2024-12-13T05:46:04.401Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7d/08604ff940aa784df8343c387fdf2489b948b714a6afb587775ae94da912/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296", size = 2142369, upload-time = "2024-12-13T05:46:06.004Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c6/39919a0645bdbdf720e97cae107f959ea9d1267fbc3b0d94fc6e1d12ac8f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140", size = 2180427, upload-time = "2024-12-13T05:46:07.526Z" }, - { url = "https://files.pythonhosted.org/packages/d8/03/dbb9d47556ee54337e7e0ac209d17ceff2d2a197c34de08005abc7a7449b/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581", size = 2069785, upload-time = "2024-12-13T05:46:10.122Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f8/11bb7b8947002231faae3ec2342df5896afbc19eb783a332cce6d219ff79/cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9", size = 320685, upload-time = "2024-12-13T05:46:11.553Z" }, - { url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297", size = 362898, upload-time = "2024-12-13T05:46:12.771Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f7/ef2a10daaec5c0f7d781d50758c6187eee484256e356ae8ef178d6c48497/cytoolz-1.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:83d19d55738ad9c60763b94f3f6d3c6e4de979aeb8d76841c1401081e0e58d96", size = 345702, upload-time = "2024-12-13T05:47:09.266Z" }, - { url = "https://files.pythonhosted.org/packages/c8/14/53c84adddedb67ff1546abb86fea04d26e24298c3ceab8436d20122ed0b9/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f112a71fad6ea824578e6393765ce5c054603afe1471a5c753ff6c67fd872d10", size = 385695, upload-time = "2024-12-13T05:47:11.011Z" }, - { url = "https://files.pythonhosted.org/packages/bd/80/3ae356c5e7b8d7dc7d1adb52f6932fee85cd748ed4e1217c269d2dfd610f/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a515df8f8aa6e1eaaf397761a6e4aff2eef73b5f920aedf271416d5471ae5ee", size = 406261, upload-time = "2024-12-13T05:47:12.24Z" }, - { url = "https://files.pythonhosted.org/packages/0c/31/8e43761ffc82d90bf9cab7e0959712eedcd1e33c211397e143dd42d7af57/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c398e7b7023460bea2edffe5fcd0a76029580f06c3f6938ac3d198b47156f3", size = 397207, upload-time = "2024-12-13T05:47:13.561Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b9/fe9da37090b6444c65f848a83e390f87d8cb43d6a4df46de1556ad7e5ceb/cytoolz-1.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3237e56211e03b13df47435b2369f5df281e02b04ad80a948ebd199b7bc10a47", size = 343358, upload-time = "2024-12-13T05:47:16.291Z" }, -] - -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - -[[package]] -name = "email-validator" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, -] - -[[package]] -name = "eth-abi" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "parsimonious" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/71/d9e1380bd77fd22f98b534699af564f189b56d539cc2b9dab908d4e4c242/eth_abi-5.2.0.tar.gz", hash = "sha256:178703fa98c07d8eecd5ae569e7e8d159e493ebb6eeb534a8fe973fbc4e40ef0", size = 49797, upload-time = "2025-01-14T16:29:34.629Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/b4/2f3982c4cbcbf5eeb6aec62df1533c0e63c653b3021ff338d44944405676/eth_abi-5.2.0-py3-none-any.whl", hash = "sha256:17abe47560ad753f18054f5b3089fcb588f3e3a092136a416b6c1502cb7e8877", size = 28511, upload-time = "2025-01-14T16:29:31.862Z" }, -] - -[[package]] -name = "eth-account" -version = "0.13.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bitarray" }, - { name = "ckzg" }, - { name = "eth-abi" }, - { name = "eth-keyfile" }, - { name = "eth-keys" }, - { name = "eth-rlp" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "rlp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/cf/20f76a29be97339c969fd765f1237154286a565a1d61be98e76bb7af946a/eth_account-0.13.7.tar.gz", hash = "sha256:5853ecbcbb22e65411176f121f5f24b8afeeaf13492359d254b16d8b18c77a46", size = 935998, upload-time = "2025-04-21T21:11:21.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/18/088fb250018cbe665bc2111974301b2d59f294a565aff7564c4df6878da2/eth_account-0.13.7-py3-none-any.whl", hash = "sha256:39727de8c94d004ff61d10da7587509c04d2dc7eac71e04830135300bdfc6d24", size = 587452, upload-time = "2025-04-21T21:11:18.346Z" }, -] - -[[package]] -name = "eth-hash" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/38/577b7bc9380ef9dff0f1dffefe0c9a1ded2385e7a06c306fd95afb6f9451/eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5", size = 12227, upload-time = "2025-01-13T21:29:21.765Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/db/f8775490669d28aca24871c67dd56b3e72105cb3bcae9a4ec65dd70859b3/eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a", size = 8028, upload-time = "2025-01-13T21:29:19.365Z" }, -] - -[package.optional-dependencies] -pycryptodome = [ - { name = "pycryptodome" }, -] - -[[package]] -name = "eth-keyfile" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-keys" }, - { name = "eth-utils" }, - { name = "pycryptodome" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/66/dd823b1537befefbbff602e2ada88f1477c5b40ec3731e3d9bc676c5f716/eth_keyfile-0.8.1.tar.gz", hash = "sha256:9708bc31f386b52cca0969238ff35b1ac72bd7a7186f2a84b86110d3c973bec1", size = 12267, upload-time = "2024-04-23T20:28:53.862Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/fc/48a586175f847dd9e05e5b8994d2fe8336098781ec2e9836a2ad94280281/eth_keyfile-0.8.1-py3-none-any.whl", hash = "sha256:65387378b82fe7e86d7cb9f8d98e6d639142661b2f6f490629da09fddbef6d64", size = 7510, upload-time = "2024-04-23T20:28:51.063Z" }, -] - -[[package]] -name = "eth-keys" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/11/1ed831c50bd74f57829aa06e58bd82a809c37e070ee501c953b9ac1f1552/eth_keys-0.7.0.tar.gz", hash = "sha256:79d24fd876201df67741de3e3fefb3f4dbcbb6ace66e47e6fe662851a4547814", size = 30166, upload-time = "2025-04-07T17:40:21.697Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/25/0ae00f2b0095e559d61ad3dc32171bd5a29dfd95ab04b4edd641f7c75f72/eth_keys-0.7.0-py3-none-any.whl", hash = "sha256:b0cdda8ffe8e5ba69c7c5ca33f153828edcace844f67aabd4542d7de38b159cf", size = 20656, upload-time = "2025-04-07T17:40:20.441Z" }, -] - -[[package]] -name = "eth-rlp" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "rlp" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7f/ea/ad39d001fa9fed07fad66edb00af701e29b48be0ed44a3bcf58cb3adf130/eth_rlp-2.2.0.tar.gz", hash = "sha256:5e4b2eb1b8213e303d6a232dfe35ab8c29e2d3051b86e8d359def80cd21db83d", size = 7720, upload-time = "2025-02-04T21:51:08.134Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/3b/57efe2bc2df0980680d57c01a36516cd3171d2319ceb30e675de19fc2cc5/eth_rlp-2.2.0-py3-none-any.whl", hash = "sha256:5692d595a741fbaef1203db6a2fedffbd2506d31455a6ad378c8449ee5985c47", size = 4446, upload-time = "2025-02-04T21:51:05.823Z" }, -] - -[[package]] -name = "eth-typing" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/54/62aa24b9cc708f06316167ee71c362779c8ed21fc8234a5cd94a8f53b623/eth_typing-5.2.1.tar.gz", hash = "sha256:7557300dbf02a93c70fa44af352b5c4a58f94e997a0fd6797fb7d1c29d9538ee", size = 21806, upload-time = "2025-04-14T20:39:28.217Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/72/c370bbe4c53da7bf998d3523f5a0f38867654923a82192df88d0705013d3/eth_typing-5.2.1-py3-none-any.whl", hash = "sha256:b0c2812ff978267563b80e9d701f487dd926f1d376d674f3b535cfe28b665d3d", size = 19163, upload-time = "2025-04-14T20:39:26.571Z" }, -] - -[[package]] -name = "eth-utils" -version = "5.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cytoolz", marker = "implementation_name == 'cpython'" }, - { name = "eth-hash" }, - { name = "eth-typing" }, - { name = "pydantic" }, - { name = "toolz", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0d/49/bee95f16d2ef068097afeeffbd6c67738107001ee57ad7bcdd4fc4d3c6a7/eth_utils-5.3.0.tar.gz", hash = "sha256:1f096867ac6be895f456fa3acb26e9573ae66e753abad9208f316d24d6178156", size = 123753, upload-time = "2025-04-14T19:35:56.431Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/c6/0417a92e6a3fc9b85f5a8380d9f9d43b69ba836a90e45f79f9ae74d41e53/eth_utils-5.3.0-py3-none-any.whl", hash = "sha256:ac184883ab299d923428bbe25dae5e356979a3993e0ef695a864db0a20bc262d", size = 102531, upload-time = "2025-04-14T19:35:55.176Z" }, -] - -[[package]] -name = "exceptiongroup" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, -] - -[[package]] -name = "fastapi" -version = "0.116.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/78/d7/6c8b3bfe33eeffa208183ec037fee0cce9f7f024089ab1c5d12ef04bd27c/fastapi-0.116.1.tar.gz", hash = "sha256:ed52cbf946abfd70c5a0dccb24673f0670deeb517a88b3544d03c2a6bf283143", size = 296485, upload-time = "2025-07-11T16:22:32.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/47/d63c60f59a59467fda0f93f46335c9d18526d7071f025cb5b89d5353ea42/fastapi-0.116.1-py3-none-any.whl", hash = "sha256:c46ac7c312df840f0c9e220f7964bada936781bc4e2e6eb71f1c4d7553786565", size = 95631, upload-time = "2025-07-11T16:22:30.485Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, - { name = "httpx" }, - { name = "jinja2" }, - { name = "python-multipart" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cli" -version = "0.0.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "rich-toolkit" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c6/94/3ef75d9c7c32936ecb539b9750ccbdc3d2568efd73b1cb913278375f4533/fastapi_cli-0.0.8.tar.gz", hash = "sha256:2360f2989b1ab4a3d7fc8b3a0b20e8288680d8af2e31de7c38309934d7f8a0ee", size = 16884, upload-time = "2025-07-07T14:44:09.326Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/3f/6ad3103c5f59208baf4c798526daea6a74085bb35d1c161c501863470476/fastapi_cli-0.0.8-py3-none-any.whl", hash = "sha256:0ea95d882c85b9219a75a65ab27e8da17dac02873e456850fa0a726e96e985eb", size = 10770, upload-time = "2025-07-07T14:44:08.255Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "fastapi-cloud-cli" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cloud-cli" -version = "0.1.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "httpx" }, - { name = "pydantic", extra = ["email"] }, - { name = "rich-toolkit" }, - { name = "rignore" }, - { name = "sentry-sdk" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/d7/4a987c3d73ddae4a7c93f5d2982ea5b1dd58d4cc1044568bb180227bd0f7/fastapi_cloud_cli-0.1.4.tar.gz", hash = "sha256:a0ab7633d71d864b4041896b3fe2f462de61546db7c52eb13e963f4d40af0eba", size = 22712, upload-time = "2025-07-11T14:15:25.667Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/cf/8635cd778b7d89714325b967a28c05865a2b6cab4c0b4b30561df4704f24/fastapi_cloud_cli-0.1.4-py3-none-any.whl", hash = "sha256:1db1ba757aa46a16a5e5dacf7cddc137ca0a3c42f65dba2b1cc6a8f24c41be42", size = 18957, upload-time = "2025-07-11T14:15:24.451Z" }, -] - -[[package]] -name = "flask" -version = "3.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "blinker" }, - { name = "click" }, - { name = "itsdangerous" }, - { name = "jinja2" }, - { name = "markupsafe" }, - { name = "werkzeug" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/de/e47735752347f4128bcf354e0da07ef311a78244eba9e3dc1d4a5ab21a98/flask-3.1.1.tar.gz", hash = "sha256:284c7b8f2f58cb737f0cf1c30fd7eaf0ccfcde196099d24ecede3fc2005aa59e", size = 753440, upload-time = "2025-05-13T15:01:17.447Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl", hash = "sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c", size = 103305, upload-time = "2025-05-13T15:01:15.591Z" }, -] - -[[package]] -name = "frozenlist" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, - { url = "https://files.pythonhosted.org/packages/77/f0/77c11d13d39513b298e267b22eb6cb559c103d56f155aa9a49097221f0b6/frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61", size = 47735, upload-time = "2025-06-09T22:59:48.133Z" }, - { url = "https://files.pythonhosted.org/packages/37/12/9d07fa18971a44150593de56b2f2947c46604819976784bcf6ea0d5db43b/frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d", size = 46775, upload-time = "2025-06-09T22:59:49.564Z" }, - { url = "https://files.pythonhosted.org/packages/70/34/f73539227e06288fcd1f8a76853e755b2b48bca6747e99e283111c18bcd4/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e", size = 224644, upload-time = "2025-06-09T22:59:51.35Z" }, - { url = "https://files.pythonhosted.org/packages/fb/68/c1d9c2f4a6e438e14613bad0f2973567586610cc22dcb1e1241da71de9d3/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9", size = 222125, upload-time = "2025-06-09T22:59:52.884Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d0/98e8f9a515228d708344d7c6986752be3e3192d1795f748c24bcf154ad99/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c", size = 233455, upload-time = "2025-06-09T22:59:54.74Z" }, - { url = "https://files.pythonhosted.org/packages/79/df/8a11bcec5600557f40338407d3e5bea80376ed1c01a6c0910fcfdc4b8993/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981", size = 227339, upload-time = "2025-06-09T22:59:56.187Z" }, - { url = "https://files.pythonhosted.org/packages/50/82/41cb97d9c9a5ff94438c63cc343eb7980dac4187eb625a51bdfdb7707314/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615", size = 212969, upload-time = "2025-06-09T22:59:57.604Z" }, - { url = "https://files.pythonhosted.org/packages/13/47/f9179ee5ee4f55629e4f28c660b3fdf2775c8bfde8f9c53f2de2d93f52a9/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50", size = 222862, upload-time = "2025-06-09T22:59:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/df81e41ec6b953902c8b7e3a83bee48b195cb0e5ec2eabae5d8330c78038/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa", size = 222492, upload-time = "2025-06-09T23:00:01.026Z" }, - { url = "https://files.pythonhosted.org/packages/84/17/30d6ea87fa95a9408245a948604b82c1a4b8b3e153cea596421a2aef2754/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577", size = 238250, upload-time = "2025-06-09T23:00:03.401Z" }, - { url = "https://files.pythonhosted.org/packages/8f/00/ecbeb51669e3c3df76cf2ddd66ae3e48345ec213a55e3887d216eb4fbab3/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59", size = 218720, upload-time = "2025-06-09T23:00:05.282Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c0/c224ce0e0eb31cc57f67742071bb470ba8246623c1823a7530be0e76164c/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e", size = 232585, upload-time = "2025-06-09T23:00:07.962Z" }, - { url = "https://files.pythonhosted.org/packages/55/3c/34cb694abf532f31f365106deebdeac9e45c19304d83cf7d51ebbb4ca4d1/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd", size = 234248, upload-time = "2025-06-09T23:00:09.428Z" }, - { url = "https://files.pythonhosted.org/packages/98/c0/2052d8b6cecda2e70bd81299e3512fa332abb6dcd2969b9c80dfcdddbf75/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718", size = 221621, upload-time = "2025-06-09T23:00:11.32Z" }, - { url = "https://files.pythonhosted.org/packages/c5/bf/7dcebae315436903b1d98ffb791a09d674c88480c158aa171958a3ac07f0/frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e", size = 39578, upload-time = "2025-06-09T23:00:13.526Z" }, - { url = "https://files.pythonhosted.org/packages/8f/5f/f69818f017fa9a3d24d1ae39763e29b7f60a59e46d5f91b9c6b21622f4cd/frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464", size = 43830, upload-time = "2025-06-09T23:00:14.98Z" }, - { url = "https://files.pythonhosted.org/packages/34/7e/803dde33760128acd393a27eb002f2020ddb8d99d30a44bfbaab31c5f08a/frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a", size = 82251, upload-time = "2025-06-09T23:00:16.279Z" }, - { url = "https://files.pythonhosted.org/packages/75/a9/9c2c5760b6ba45eae11334db454c189d43d34a4c0b489feb2175e5e64277/frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750", size = 48183, upload-time = "2025-06-09T23:00:17.698Z" }, - { url = "https://files.pythonhosted.org/packages/47/be/4038e2d869f8a2da165f35a6befb9158c259819be22eeaf9c9a8f6a87771/frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd", size = 47107, upload-time = "2025-06-09T23:00:18.952Z" }, - { url = "https://files.pythonhosted.org/packages/79/26/85314b8a83187c76a37183ceed886381a5f992975786f883472fcb6dc5f2/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2", size = 237333, upload-time = "2025-06-09T23:00:20.275Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fd/e5b64f7d2c92a41639ffb2ad44a6a82f347787abc0c7df5f49057cf11770/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f", size = 231724, upload-time = "2025-06-09T23:00:21.705Z" }, - { url = "https://files.pythonhosted.org/packages/20/fb/03395c0a43a5976af4bf7534759d214405fbbb4c114683f434dfdd3128ef/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30", size = 245842, upload-time = "2025-06-09T23:00:23.148Z" }, - { url = "https://files.pythonhosted.org/packages/d0/15/c01c8e1dffdac5d9803507d824f27aed2ba76b6ed0026fab4d9866e82f1f/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98", size = 239767, upload-time = "2025-06-09T23:00:25.103Z" }, - { url = "https://files.pythonhosted.org/packages/14/99/3f4c6fe882c1f5514b6848aa0a69b20cb5e5d8e8f51a339d48c0e9305ed0/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86", size = 224130, upload-time = "2025-06-09T23:00:27.061Z" }, - { url = "https://files.pythonhosted.org/packages/4d/83/220a374bd7b2aeba9d0725130665afe11de347d95c3620b9b82cc2fcab97/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae", size = 235301, upload-time = "2025-06-09T23:00:29.02Z" }, - { url = "https://files.pythonhosted.org/packages/03/3c/3e3390d75334a063181625343e8daab61b77e1b8214802cc4e8a1bb678fc/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8", size = 234606, upload-time = "2025-06-09T23:00:30.514Z" }, - { url = "https://files.pythonhosted.org/packages/23/1e/58232c19608b7a549d72d9903005e2d82488f12554a32de2d5fb59b9b1ba/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31", size = 248372, upload-time = "2025-06-09T23:00:31.966Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a4/e4a567e01702a88a74ce8a324691e62a629bf47d4f8607f24bf1c7216e7f/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7", size = 229860, upload-time = "2025-06-09T23:00:33.375Z" }, - { url = "https://files.pythonhosted.org/packages/73/a6/63b3374f7d22268b41a9db73d68a8233afa30ed164c46107b33c4d18ecdd/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5", size = 245893, upload-time = "2025-06-09T23:00:35.002Z" }, - { url = "https://files.pythonhosted.org/packages/6d/eb/d18b3f6e64799a79673c4ba0b45e4cfbe49c240edfd03a68be20002eaeaa/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898", size = 246323, upload-time = "2025-06-09T23:00:36.468Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f5/720f3812e3d06cd89a1d5db9ff6450088b8f5c449dae8ffb2971a44da506/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56", size = 233149, upload-time = "2025-06-09T23:00:37.963Z" }, - { url = "https://files.pythonhosted.org/packages/69/68/03efbf545e217d5db8446acfd4c447c15b7c8cf4dbd4a58403111df9322d/frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7", size = 39565, upload-time = "2025-06-09T23:00:39.753Z" }, - { url = "https://files.pythonhosted.org/packages/58/17/fe61124c5c333ae87f09bb67186d65038834a47d974fc10a5fadb4cc5ae1/frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d", size = 44019, upload-time = "2025-06-09T23:00:40.988Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, - { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, - { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, - { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, - { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, - { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, - { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, - { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, - { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, - { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" }, - { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" }, - { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" }, - { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" }, - { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" }, - { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" }, - { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" }, - { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" }, - { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" }, - { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" }, - { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" }, - { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" }, - { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" }, - { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" }, - { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" }, - { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" }, - { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" }, - { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" }, - { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" }, - { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" }, - { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" }, - { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" }, - { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" }, - { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" }, - { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" }, - { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" }, - { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" }, - { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" }, - { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" }, - { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" }, - { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" }, - { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "hexbytes" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/87/adf4635b4b8c050283d74e6db9a81496063229c9263e6acc1903ab79fbec/hexbytes-1.3.1.tar.gz", hash = "sha256:a657eebebdfe27254336f98d8af6e2236f3f83aed164b87466b6cf6c5f5a4765", size = 8633, upload-time = "2025-05-14T16:45:17.5Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/e0/3b31492b1c89da3c5a846680517871455b30c54738486fc57ac79a5761bd/hexbytes-1.3.1-py3-none-any.whl", hash = "sha256:da01ff24a1a9a2b1881c4b85f0e9f9b0f51b526b379ffa23832ae7899d29c2c7", size = 5074, upload-time = "2025-05-14T16:45:16.179Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httptools" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/17c672b4bc5c7ba7f201eada4e96c71d0a59fbc185e60e42580093a86f21/httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da", size = 103297, upload-time = "2024-10-16T19:44:08.129Z" }, - { url = "https://files.pythonhosted.org/packages/92/5e/b4a826fe91971a0b68e8c2bd4e7db3e7519882f5a8ccdb1194be2b3ab98f/httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1", size = 443130, upload-time = "2024-10-16T19:44:09.45Z" }, - { url = "https://files.pythonhosted.org/packages/b0/51/ce61e531e40289a681a463e1258fa1e05e0be54540e40d91d065a264cd8f/httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50", size = 442148, upload-time = "2024-10-16T19:44:11.539Z" }, - { url = "https://files.pythonhosted.org/packages/ea/9e/270b7d767849b0c96f275c695d27ca76c30671f8eb8cc1bab6ced5c5e1d0/httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959", size = 415949, upload-time = "2024-10-16T19:44:13.388Z" }, - { url = "https://files.pythonhosted.org/packages/81/86/ced96e3179c48c6f656354e106934e65c8963d48b69be78f355797f0e1b3/httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4", size = 417591, upload-time = "2024-10-16T19:44:15.258Z" }, - { url = "https://files.pythonhosted.org/packages/75/73/187a3f620ed3175364ddb56847d7a608a6fc42d551e133197098c0143eca/httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c", size = 88344, upload-time = "2024-10-16T19:44:16.54Z" }, - { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029, upload-time = "2024-10-16T19:44:18.427Z" }, - { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492, upload-time = "2024-10-16T19:44:19.515Z" }, - { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891, upload-time = "2024-10-16T19:44:21.067Z" }, - { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788, upload-time = "2024-10-16T19:44:22.958Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214, upload-time = "2024-10-16T19:44:24.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120, upload-time = "2024-10-16T19:44:26.295Z" }, - { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565, upload-time = "2024-10-16T19:44:29.188Z" }, - { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683, upload-time = "2024-10-16T19:44:30.175Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337, upload-time = "2024-10-16T19:44:31.786Z" }, - { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796, upload-time = "2024-10-16T19:44:32.825Z" }, - { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837, upload-time = "2024-10-16T19:44:33.974Z" }, - { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289, upload-time = "2024-10-16T19:44:35.111Z" }, - { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779, upload-time = "2024-10-16T19:44:36.253Z" }, - { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634, upload-time = "2024-10-16T19:44:37.357Z" }, - { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" }, - { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" }, - { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" }, - { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" }, - { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" }, - { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "itsdangerous" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "multidict" -version = "6.6.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3d/2c/5dad12e82fbdf7470f29bff2171484bf07cb3b16ada60a6589af8f376440/multidict-6.6.3.tar.gz", hash = "sha256:798a9eb12dab0a6c2e29c1de6f3468af5cb2da6053a20dfa3344907eed0937cc", size = 101006, upload-time = "2025-06-30T15:53:46.929Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/67/414933982bce2efce7cbcb3169eaaf901e0f25baec69432b4874dfb1f297/multidict-6.6.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:a2be5b7b35271f7fff1397204ba6708365e3d773579fe2a30625e16c4b4ce817", size = 77017, upload-time = "2025-06-30T15:50:58.931Z" }, - { url = "https://files.pythonhosted.org/packages/8a/fe/d8a3ee1fad37dc2ef4f75488b0d9d4f25bf204aad8306cbab63d97bff64a/multidict-6.6.3-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:12f4581d2930840295c461764b9a65732ec01250b46c6b2c510d7ee68872b140", size = 44897, upload-time = "2025-06-30T15:51:00.999Z" }, - { url = "https://files.pythonhosted.org/packages/1f/e0/265d89af8c98240265d82b8cbcf35897f83b76cd59ee3ab3879050fd8c45/multidict-6.6.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dd7793bab517e706c9ed9d7310b06c8672fd0aeee5781bfad612f56b8e0f7d14", size = 44574, upload-time = "2025-06-30T15:51:02.449Z" }, - { url = "https://files.pythonhosted.org/packages/e6/05/6b759379f7e8e04ccc97cfb2a5dcc5cdbd44a97f072b2272dc51281e6a40/multidict-6.6.3-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:72d8815f2cd3cf3df0f83cac3f3ef801d908b2d90409ae28102e0553af85545a", size = 225729, upload-time = "2025-06-30T15:51:03.794Z" }, - { url = "https://files.pythonhosted.org/packages/4e/f5/8d5a15488edd9a91fa4aad97228d785df208ed6298580883aa3d9def1959/multidict-6.6.3-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:531e331a2ee53543ab32b16334e2deb26f4e6b9b28e41f8e0c87e99a6c8e2d69", size = 242515, upload-time = "2025-06-30T15:51:05.002Z" }, - { url = "https://files.pythonhosted.org/packages/6e/b5/a8f317d47d0ac5bb746d6d8325885c8967c2a8ce0bb57be5399e3642cccb/multidict-6.6.3-cp310-cp310-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:42ca5aa9329a63be8dc49040f63817d1ac980e02eeddba763a9ae5b4027b9c9c", size = 222224, upload-time = "2025-06-30T15:51:06.148Z" }, - { url = "https://files.pythonhosted.org/packages/76/88/18b2a0d5e80515fa22716556061189c2853ecf2aa2133081ebbe85ebea38/multidict-6.6.3-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:208b9b9757060b9faa6f11ab4bc52846e4f3c2fb8b14d5680c8aac80af3dc751", size = 253124, upload-time = "2025-06-30T15:51:07.375Z" }, - { url = "https://files.pythonhosted.org/packages/62/bf/ebfcfd6b55a1b05ef16d0775ae34c0fe15e8dab570d69ca9941073b969e7/multidict-6.6.3-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:acf6b97bd0884891af6a8b43d0f586ab2fcf8e717cbd47ab4bdddc09e20652d8", size = 251529, upload-time = "2025-06-30T15:51:08.691Z" }, - { url = "https://files.pythonhosted.org/packages/44/11/780615a98fd3775fc309d0234d563941af69ade2df0bb82c91dda6ddaea1/multidict-6.6.3-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:68e9e12ed00e2089725669bdc88602b0b6f8d23c0c95e52b95f0bc69f7fe9b55", size = 241627, upload-time = "2025-06-30T15:51:10.605Z" }, - { url = "https://files.pythonhosted.org/packages/28/3d/35f33045e21034b388686213752cabc3a1b9d03e20969e6fa8f1b1d82db1/multidict-6.6.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:05db2f66c9addb10cfa226e1acb363450fab2ff8a6df73c622fefe2f5af6d4e7", size = 239351, upload-time = "2025-06-30T15:51:12.18Z" }, - { url = "https://files.pythonhosted.org/packages/6e/cc/ff84c03b95b430015d2166d9aae775a3985d757b94f6635010d0038d9241/multidict-6.6.3-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:0db58da8eafb514db832a1b44f8fa7906fdd102f7d982025f816a93ba45e3dcb", size = 233429, upload-time = "2025-06-30T15:51:13.533Z" }, - { url = "https://files.pythonhosted.org/packages/2e/f0/8cd49a0b37bdea673a4b793c2093f2f4ba8e7c9d6d7c9bd672fd6d38cd11/multidict-6.6.3-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:14117a41c8fdb3ee19c743b1c027da0736fdb79584d61a766da53d399b71176c", size = 243094, upload-time = "2025-06-30T15:51:14.815Z" }, - { url = "https://files.pythonhosted.org/packages/96/19/5d9a0cfdafe65d82b616a45ae950975820289069f885328e8185e64283c2/multidict-6.6.3-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:877443eaaabcd0b74ff32ebeed6f6176c71850feb7d6a1d2db65945256ea535c", size = 248957, upload-time = "2025-06-30T15:51:16.076Z" }, - { url = "https://files.pythonhosted.org/packages/e6/dc/c90066151da87d1e489f147b9b4327927241e65f1876702fafec6729c014/multidict-6.6.3-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:70b72e749a4f6e7ed8fb334fa8d8496384840319512746a5f42fa0aec79f4d61", size = 243590, upload-time = "2025-06-30T15:51:17.413Z" }, - { url = "https://files.pythonhosted.org/packages/ec/39/458afb0cccbb0ee9164365273be3e039efddcfcb94ef35924b7dbdb05db0/multidict-6.6.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:43571f785b86afd02b3855c5ac8e86ec921b760298d6f82ff2a61daf5a35330b", size = 237487, upload-time = "2025-06-30T15:51:19.039Z" }, - { url = "https://files.pythonhosted.org/packages/35/38/0016adac3990426610a081787011177e661875546b434f50a26319dc8372/multidict-6.6.3-cp310-cp310-win32.whl", hash = "sha256:20c5a0c3c13a15fd5ea86c42311859f970070e4e24de5a550e99d7c271d76318", size = 41390, upload-time = "2025-06-30T15:51:20.362Z" }, - { url = "https://files.pythonhosted.org/packages/f3/d2/17897a8f3f2c5363d969b4c635aa40375fe1f09168dc09a7826780bfb2a4/multidict-6.6.3-cp310-cp310-win_amd64.whl", hash = "sha256:ab0a34a007704c625e25a9116c6770b4d3617a071c8a7c30cd338dfbadfe6485", size = 45954, upload-time = "2025-06-30T15:51:21.383Z" }, - { url = "https://files.pythonhosted.org/packages/2d/5f/d4a717c1e457fe44072e33fa400d2b93eb0f2819c4d669381f925b7cba1f/multidict-6.6.3-cp310-cp310-win_arm64.whl", hash = "sha256:769841d70ca8bdd140a715746199fc6473414bd02efd678d75681d2d6a8986c5", size = 42981, upload-time = "2025-06-30T15:51:22.809Z" }, - { url = "https://files.pythonhosted.org/packages/08/f0/1a39863ced51f639c81a5463fbfa9eb4df59c20d1a8769ab9ef4ca57ae04/multidict-6.6.3-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:18f4eba0cbac3546b8ae31e0bbc55b02c801ae3cbaf80c247fcdd89b456ff58c", size = 76445, upload-time = "2025-06-30T15:51:24.01Z" }, - { url = "https://files.pythonhosted.org/packages/c9/0e/a7cfa451c7b0365cd844e90b41e21fab32edaa1e42fc0c9f68461ce44ed7/multidict-6.6.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ef43b5dd842382329e4797c46f10748d8c2b6e0614f46b4afe4aee9ac33159df", size = 44610, upload-time = "2025-06-30T15:51:25.158Z" }, - { url = "https://files.pythonhosted.org/packages/c6/bb/a14a4efc5ee748cc1904b0748be278c31b9295ce5f4d2ef66526f410b94d/multidict-6.6.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bf9bd1fd5eec01494e0f2e8e446a74a85d5e49afb63d75a9934e4a5423dba21d", size = 44267, upload-time = "2025-06-30T15:51:26.326Z" }, - { url = "https://files.pythonhosted.org/packages/c2/f8/410677d563c2d55e063ef74fe578f9d53fe6b0a51649597a5861f83ffa15/multidict-6.6.3-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:5bd8d6f793a787153956cd35e24f60485bf0651c238e207b9a54f7458b16d539", size = 230004, upload-time = "2025-06-30T15:51:27.491Z" }, - { url = "https://files.pythonhosted.org/packages/fd/df/2b787f80059314a98e1ec6a4cc7576244986df3e56b3c755e6fc7c99e038/multidict-6.6.3-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:1bf99b4daf908c73856bd87ee0a2499c3c9a3d19bb04b9c6025e66af3fd07462", size = 247196, upload-time = "2025-06-30T15:51:28.762Z" }, - { url = "https://files.pythonhosted.org/packages/05/f2/f9117089151b9a8ab39f9019620d10d9718eec2ac89e7ca9d30f3ec78e96/multidict-6.6.3-cp311-cp311-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:0b9e59946b49dafaf990fd9c17ceafa62976e8471a14952163d10a7a630413a9", size = 225337, upload-time = "2025-06-30T15:51:30.025Z" }, - { url = "https://files.pythonhosted.org/packages/93/2d/7115300ec5b699faa152c56799b089a53ed69e399c3c2d528251f0aeda1a/multidict-6.6.3-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:e2db616467070d0533832d204c54eea6836a5e628f2cb1e6dfd8cd6ba7277cb7", size = 257079, upload-time = "2025-06-30T15:51:31.716Z" }, - { url = "https://files.pythonhosted.org/packages/15/ea/ff4bab367623e39c20d3b07637225c7688d79e4f3cc1f3b9f89867677f9a/multidict-6.6.3-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:7394888236621f61dcdd25189b2768ae5cc280f041029a5bcf1122ac63df79f9", size = 255461, upload-time = "2025-06-30T15:51:33.029Z" }, - { url = "https://files.pythonhosted.org/packages/74/07/2c9246cda322dfe08be85f1b8739646f2c4c5113a1422d7a407763422ec4/multidict-6.6.3-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:f114d8478733ca7388e7c7e0ab34b72547476b97009d643644ac33d4d3fe1821", size = 246611, upload-time = "2025-06-30T15:51:34.47Z" }, - { url = "https://files.pythonhosted.org/packages/a8/62/279c13d584207d5697a752a66ffc9bb19355a95f7659140cb1b3cf82180e/multidict-6.6.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:cdf22e4db76d323bcdc733514bf732e9fb349707c98d341d40ebcc6e9318ef3d", size = 243102, upload-time = "2025-06-30T15:51:36.525Z" }, - { url = "https://files.pythonhosted.org/packages/69/cc/e06636f48c6d51e724a8bc8d9e1db5f136fe1df066d7cafe37ef4000f86a/multidict-6.6.3-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:e995a34c3d44ab511bfc11aa26869b9d66c2d8c799fa0e74b28a473a692532d6", size = 238693, upload-time = "2025-06-30T15:51:38.278Z" }, - { url = "https://files.pythonhosted.org/packages/89/a4/66c9d8fb9acf3b226cdd468ed009537ac65b520aebdc1703dd6908b19d33/multidict-6.6.3-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:766a4a5996f54361d8d5a9050140aa5362fe48ce51c755a50c0bc3706460c430", size = 246582, upload-time = "2025-06-30T15:51:39.709Z" }, - { url = "https://files.pythonhosted.org/packages/cf/01/c69e0317be556e46257826d5449feb4e6aa0d18573e567a48a2c14156f1f/multidict-6.6.3-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:3893a0d7d28a7fe6ca7a1f760593bc13038d1d35daf52199d431b61d2660602b", size = 253355, upload-time = "2025-06-30T15:51:41.013Z" }, - { url = "https://files.pythonhosted.org/packages/c0/da/9cc1da0299762d20e626fe0042e71b5694f9f72d7d3f9678397cbaa71b2b/multidict-6.6.3-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:934796c81ea996e61914ba58064920d6cad5d99140ac3167901eb932150e2e56", size = 247774, upload-time = "2025-06-30T15:51:42.291Z" }, - { url = "https://files.pythonhosted.org/packages/e6/91/b22756afec99cc31105ddd4a52f95ab32b1a4a58f4d417979c570c4a922e/multidict-6.6.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:9ed948328aec2072bc00f05d961ceadfd3e9bfc2966c1319aeaf7b7c21219183", size = 242275, upload-time = "2025-06-30T15:51:43.642Z" }, - { url = "https://files.pythonhosted.org/packages/be/f1/adcc185b878036a20399d5be5228f3cbe7f823d78985d101d425af35c800/multidict-6.6.3-cp311-cp311-win32.whl", hash = "sha256:9f5b28c074c76afc3e4c610c488e3493976fe0e596dd3db6c8ddfbb0134dcac5", size = 41290, upload-time = "2025-06-30T15:51:45.264Z" }, - { url = "https://files.pythonhosted.org/packages/e0/d4/27652c1c6526ea6b4f5ddd397e93f4232ff5de42bea71d339bc6a6cc497f/multidict-6.6.3-cp311-cp311-win_amd64.whl", hash = "sha256:bc7f6fbc61b1c16050a389c630da0b32fc6d4a3d191394ab78972bf5edc568c2", size = 45942, upload-time = "2025-06-30T15:51:46.377Z" }, - { url = "https://files.pythonhosted.org/packages/16/18/23f4932019804e56d3c2413e237f866444b774b0263bcb81df2fdecaf593/multidict-6.6.3-cp311-cp311-win_arm64.whl", hash = "sha256:d4e47d8faffaae822fb5cba20937c048d4f734f43572e7079298a6c39fb172cb", size = 42880, upload-time = "2025-06-30T15:51:47.561Z" }, - { url = "https://files.pythonhosted.org/packages/0e/a0/6b57988ea102da0623ea814160ed78d45a2645e4bbb499c2896d12833a70/multidict-6.6.3-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:056bebbeda16b2e38642d75e9e5310c484b7c24e3841dc0fb943206a72ec89d6", size = 76514, upload-time = "2025-06-30T15:51:48.728Z" }, - { url = "https://files.pythonhosted.org/packages/07/7a/d1e92665b0850c6c0508f101f9cf0410c1afa24973e1115fe9c6a185ebf7/multidict-6.6.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:e5f481cccb3c5c5e5de5d00b5141dc589c1047e60d07e85bbd7dea3d4580d63f", size = 45394, upload-time = "2025-06-30T15:51:49.986Z" }, - { url = "https://files.pythonhosted.org/packages/52/6f/dd104490e01be6ef8bf9573705d8572f8c2d2c561f06e3826b081d9e6591/multidict-6.6.3-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:10bea2ee839a759ee368b5a6e47787f399b41e70cf0c20d90dfaf4158dfb4e55", size = 43590, upload-time = "2025-06-30T15:51:51.331Z" }, - { url = "https://files.pythonhosted.org/packages/44/fe/06e0e01b1b0611e6581b7fd5a85b43dacc08b6cea3034f902f383b0873e5/multidict-6.6.3-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:2334cfb0fa9549d6ce2c21af2bfbcd3ac4ec3646b1b1581c88e3e2b1779ec92b", size = 237292, upload-time = "2025-06-30T15:51:52.584Z" }, - { url = "https://files.pythonhosted.org/packages/ce/71/4f0e558fb77696b89c233c1ee2d92f3e1d5459070a0e89153c9e9e804186/multidict-6.6.3-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b8fee016722550a2276ca2cb5bb624480e0ed2bd49125b2b73b7010b9090e888", size = 258385, upload-time = "2025-06-30T15:51:53.913Z" }, - { url = "https://files.pythonhosted.org/packages/e3/25/cca0e68228addad24903801ed1ab42e21307a1b4b6dd2cf63da5d3ae082a/multidict-6.6.3-cp312-cp312-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:e5511cb35f5c50a2db21047c875eb42f308c5583edf96bd8ebf7d770a9d68f6d", size = 242328, upload-time = "2025-06-30T15:51:55.672Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a3/46f2d420d86bbcb8fe660b26a10a219871a0fbf4d43cb846a4031533f3e0/multidict-6.6.3-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:712b348f7f449948e0a6c4564a21c7db965af900973a67db432d724619b3c680", size = 268057, upload-time = "2025-06-30T15:51:57.037Z" }, - { url = "https://files.pythonhosted.org/packages/9e/73/1c743542fe00794a2ec7466abd3f312ccb8fad8dff9f36d42e18fb1ec33e/multidict-6.6.3-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e4e15d2138ee2694e038e33b7c3da70e6b0ad8868b9f8094a72e1414aeda9c1a", size = 269341, upload-time = "2025-06-30T15:51:59.111Z" }, - { url = "https://files.pythonhosted.org/packages/a4/11/6ec9dcbe2264b92778eeb85407d1df18812248bf3506a5a1754bc035db0c/multidict-6.6.3-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8df25594989aebff8a130f7899fa03cbfcc5d2b5f4a461cf2518236fe6f15961", size = 256081, upload-time = "2025-06-30T15:52:00.533Z" }, - { url = "https://files.pythonhosted.org/packages/9b/2b/631b1e2afeb5f1696846d747d36cda075bfdc0bc7245d6ba5c319278d6c4/multidict-6.6.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:159ca68bfd284a8860f8d8112cf0521113bffd9c17568579e4d13d1f1dc76b65", size = 253581, upload-time = "2025-06-30T15:52:02.43Z" }, - { url = "https://files.pythonhosted.org/packages/bf/0e/7e3b93f79efeb6111d3bf9a1a69e555ba1d07ad1c11bceb56b7310d0d7ee/multidict-6.6.3-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:e098c17856a8c9ade81b4810888c5ad1914099657226283cab3062c0540b0643", size = 250750, upload-time = "2025-06-30T15:52:04.26Z" }, - { url = "https://files.pythonhosted.org/packages/ad/9e/086846c1d6601948e7de556ee464a2d4c85e33883e749f46b9547d7b0704/multidict-6.6.3-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:67c92ed673049dec52d7ed39f8cf9ebbadf5032c774058b4406d18c8f8fe7063", size = 251548, upload-time = "2025-06-30T15:52:06.002Z" }, - { url = "https://files.pythonhosted.org/packages/8c/7b/86ec260118e522f1a31550e87b23542294880c97cfbf6fb18cc67b044c66/multidict-6.6.3-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:bd0578596e3a835ef451784053cfd327d607fc39ea1a14812139339a18a0dbc3", size = 262718, upload-time = "2025-06-30T15:52:07.707Z" }, - { url = "https://files.pythonhosted.org/packages/8c/bd/22ce8f47abb0be04692c9fc4638508b8340987b18691aa7775d927b73f72/multidict-6.6.3-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:346055630a2df2115cd23ae271910b4cae40f4e336773550dca4889b12916e75", size = 259603, upload-time = "2025-06-30T15:52:09.58Z" }, - { url = "https://files.pythonhosted.org/packages/07/9c/91b7ac1691be95cd1f4a26e36a74b97cda6aa9820632d31aab4410f46ebd/multidict-6.6.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:555ff55a359302b79de97e0468e9ee80637b0de1fce77721639f7cd9440b3a10", size = 251351, upload-time = "2025-06-30T15:52:10.947Z" }, - { url = "https://files.pythonhosted.org/packages/6f/5c/4d7adc739884f7a9fbe00d1eac8c034023ef8bad71f2ebe12823ca2e3649/multidict-6.6.3-cp312-cp312-win32.whl", hash = "sha256:73ab034fb8d58ff85c2bcbadc470efc3fafeea8affcf8722855fb94557f14cc5", size = 41860, upload-time = "2025-06-30T15:52:12.334Z" }, - { url = "https://files.pythonhosted.org/packages/6a/a3/0fbc7afdf7cb1aa12a086b02959307848eb6bcc8f66fcb66c0cb57e2a2c1/multidict-6.6.3-cp312-cp312-win_amd64.whl", hash = "sha256:04cbcce84f63b9af41bad04a54d4cc4e60e90c35b9e6ccb130be2d75b71f8c17", size = 45982, upload-time = "2025-06-30T15:52:13.6Z" }, - { url = "https://files.pythonhosted.org/packages/b8/95/8c825bd70ff9b02462dc18d1295dd08d3e9e4eb66856d292ffa62cfe1920/multidict-6.6.3-cp312-cp312-win_arm64.whl", hash = "sha256:0f1130b896ecb52d2a1e615260f3ea2af55fa7dc3d7c3003ba0c3121a759b18b", size = 43210, upload-time = "2025-06-30T15:52:14.893Z" }, - { url = "https://files.pythonhosted.org/packages/52/1d/0bebcbbb4f000751fbd09957257903d6e002943fc668d841a4cf2fb7f872/multidict-6.6.3-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:540d3c06d48507357a7d57721e5094b4f7093399a0106c211f33540fdc374d55", size = 75843, upload-time = "2025-06-30T15:52:16.155Z" }, - { url = "https://files.pythonhosted.org/packages/07/8f/cbe241b0434cfe257f65c2b1bcf9e8d5fb52bc708c5061fb29b0fed22bdf/multidict-6.6.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9c19cea2a690f04247d43f366d03e4eb110a0dc4cd1bbeee4d445435428ed35b", size = 45053, upload-time = "2025-06-30T15:52:17.429Z" }, - { url = "https://files.pythonhosted.org/packages/32/d2/0b3b23f9dbad5b270b22a3ac3ea73ed0a50ef2d9a390447061178ed6bdb8/multidict-6.6.3-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7af039820cfd00effec86bda5d8debef711a3e86a1d3772e85bea0f243a4bd65", size = 43273, upload-time = "2025-06-30T15:52:19.346Z" }, - { url = "https://files.pythonhosted.org/packages/fd/fe/6eb68927e823999e3683bc49678eb20374ba9615097d085298fd5b386564/multidict-6.6.3-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:500b84f51654fdc3944e936f2922114349bf8fdcac77c3092b03449f0e5bc2b3", size = 237124, upload-time = "2025-06-30T15:52:20.773Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ab/320d8507e7726c460cb77117848b3834ea0d59e769f36fdae495f7669929/multidict-6.6.3-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:f3fc723ab8a5c5ed6c50418e9bfcd8e6dceba6c271cee6728a10a4ed8561520c", size = 256892, upload-time = "2025-06-30T15:52:22.242Z" }, - { url = "https://files.pythonhosted.org/packages/76/60/38ee422db515ac69834e60142a1a69111ac96026e76e8e9aa347fd2e4591/multidict-6.6.3-cp313-cp313-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:94c47ea3ade005b5976789baaed66d4de4480d0a0bf31cef6edaa41c1e7b56a6", size = 240547, upload-time = "2025-06-30T15:52:23.736Z" }, - { url = "https://files.pythonhosted.org/packages/27/fb/905224fde2dff042b030c27ad95a7ae744325cf54b890b443d30a789b80e/multidict-6.6.3-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:dbc7cf464cc6d67e83e136c9f55726da3a30176f020a36ead246eceed87f1cd8", size = 266223, upload-time = "2025-06-30T15:52:25.185Z" }, - { url = "https://files.pythonhosted.org/packages/76/35/dc38ab361051beae08d1a53965e3e1a418752fc5be4d3fb983c5582d8784/multidict-6.6.3-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:900eb9f9da25ada070f8ee4a23f884e0ee66fe4e1a38c3af644256a508ad81ca", size = 267262, upload-time = "2025-06-30T15:52:26.969Z" }, - { url = "https://files.pythonhosted.org/packages/1f/a3/0a485b7f36e422421b17e2bbb5a81c1af10eac1d4476f2ff92927c730479/multidict-6.6.3-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:7c6df517cf177da5d47ab15407143a89cd1a23f8b335f3a28d57e8b0a3dbb884", size = 254345, upload-time = "2025-06-30T15:52:28.467Z" }, - { url = "https://files.pythonhosted.org/packages/b4/59/bcdd52c1dab7c0e0d75ff19cac751fbd5f850d1fc39172ce809a74aa9ea4/multidict-6.6.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ef421045f13879e21c994b36e728d8e7d126c91a64b9185810ab51d474f27e7", size = 252248, upload-time = "2025-06-30T15:52:29.938Z" }, - { url = "https://files.pythonhosted.org/packages/bb/a4/2d96aaa6eae8067ce108d4acee6f45ced5728beda55c0f02ae1072c730d1/multidict-6.6.3-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:6c1e61bb4f80895c081790b6b09fa49e13566df8fbff817da3f85b3a8192e36b", size = 250115, upload-time = "2025-06-30T15:52:31.416Z" }, - { url = "https://files.pythonhosted.org/packages/25/d2/ed9f847fa5c7d0677d4f02ea2c163d5e48573de3f57bacf5670e43a5ffaa/multidict-6.6.3-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:e5e8523bb12d7623cd8300dbd91b9e439a46a028cd078ca695eb66ba31adee3c", size = 249649, upload-time = "2025-06-30T15:52:32.996Z" }, - { url = "https://files.pythonhosted.org/packages/1f/af/9155850372563fc550803d3f25373308aa70f59b52cff25854086ecb4a79/multidict-6.6.3-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:ef58340cc896219e4e653dade08fea5c55c6df41bcc68122e3be3e9d873d9a7b", size = 261203, upload-time = "2025-06-30T15:52:34.521Z" }, - { url = "https://files.pythonhosted.org/packages/36/2f/c6a728f699896252cf309769089568a33c6439626648843f78743660709d/multidict-6.6.3-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fc9dc435ec8699e7b602b94fe0cd4703e69273a01cbc34409af29e7820f777f1", size = 258051, upload-time = "2025-06-30T15:52:35.999Z" }, - { url = "https://files.pythonhosted.org/packages/d0/60/689880776d6b18fa2b70f6cc74ff87dd6c6b9b47bd9cf74c16fecfaa6ad9/multidict-6.6.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9e864486ef4ab07db5e9cb997bad2b681514158d6954dd1958dfb163b83d53e6", size = 249601, upload-time = "2025-06-30T15:52:37.473Z" }, - { url = "https://files.pythonhosted.org/packages/75/5e/325b11f2222a549019cf2ef879c1f81f94a0d40ace3ef55cf529915ba6cc/multidict-6.6.3-cp313-cp313-win32.whl", hash = "sha256:5633a82fba8e841bc5c5c06b16e21529573cd654f67fd833650a215520a6210e", size = 41683, upload-time = "2025-06-30T15:52:38.927Z" }, - { url = "https://files.pythonhosted.org/packages/b1/ad/cf46e73f5d6e3c775cabd2a05976547f3f18b39bee06260369a42501f053/multidict-6.6.3-cp313-cp313-win_amd64.whl", hash = "sha256:e93089c1570a4ad54c3714a12c2cef549dc9d58e97bcded193d928649cab78e9", size = 45811, upload-time = "2025-06-30T15:52:40.207Z" }, - { url = "https://files.pythonhosted.org/packages/c5/c9/2e3fe950db28fb7c62e1a5f46e1e38759b072e2089209bc033c2798bb5ec/multidict-6.6.3-cp313-cp313-win_arm64.whl", hash = "sha256:c60b401f192e79caec61f166da9c924e9f8bc65548d4246842df91651e83d600", size = 43056, upload-time = "2025-06-30T15:52:41.575Z" }, - { url = "https://files.pythonhosted.org/packages/3a/58/aaf8114cf34966e084a8cc9517771288adb53465188843d5a19862cb6dc3/multidict-6.6.3-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:02fd8f32d403a6ff13864b0851f1f523d4c988051eea0471d4f1fd8010f11134", size = 82811, upload-time = "2025-06-30T15:52:43.281Z" }, - { url = "https://files.pythonhosted.org/packages/71/af/5402e7b58a1f5b987a07ad98f2501fdba2a4f4b4c30cf114e3ce8db64c87/multidict-6.6.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:f3aa090106b1543f3f87b2041eef3c156c8da2aed90c63a2fbed62d875c49c37", size = 48304, upload-time = "2025-06-30T15:52:45.026Z" }, - { url = "https://files.pythonhosted.org/packages/39/65/ab3c8cafe21adb45b24a50266fd747147dec7847425bc2a0f6934b3ae9ce/multidict-6.6.3-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:e924fb978615a5e33ff644cc42e6aa241effcf4f3322c09d4f8cebde95aff5f8", size = 46775, upload-time = "2025-06-30T15:52:46.459Z" }, - { url = "https://files.pythonhosted.org/packages/49/ba/9fcc1b332f67cc0c0c8079e263bfab6660f87fe4e28a35921771ff3eea0d/multidict-6.6.3-cp313-cp313t-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:b9fe5a0e57c6dbd0e2ce81ca66272282c32cd11d31658ee9553849d91289e1c1", size = 229773, upload-time = "2025-06-30T15:52:47.88Z" }, - { url = "https://files.pythonhosted.org/packages/a4/14/0145a251f555f7c754ce2dcbcd012939bbd1f34f066fa5d28a50e722a054/multidict-6.6.3-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b24576f208793ebae00280c59927c3b7c2a3b1655e443a25f753c4611bc1c373", size = 250083, upload-time = "2025-06-30T15:52:49.366Z" }, - { url = "https://files.pythonhosted.org/packages/9e/d4/d5c0bd2bbb173b586c249a151a26d2fb3ec7d53c96e42091c9fef4e1f10c/multidict-6.6.3-cp313-cp313t-manylinux2014_armv7l.manylinux_2_17_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:135631cb6c58eac37d7ac0df380294fecdc026b28837fa07c02e459c7fb9c54e", size = 228980, upload-time = "2025-06-30T15:52:50.903Z" }, - { url = "https://files.pythonhosted.org/packages/21/32/c9a2d8444a50ec48c4733ccc67254100c10e1c8ae8e40c7a2d2183b59b97/multidict-6.6.3-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:274d416b0df887aef98f19f21578653982cfb8a05b4e187d4a17103322eeaf8f", size = 257776, upload-time = "2025-06-30T15:52:52.764Z" }, - { url = "https://files.pythonhosted.org/packages/68/d0/14fa1699f4ef629eae08ad6201c6b476098f5efb051b296f4c26be7a9fdf/multidict-6.6.3-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:e252017a817fad7ce05cafbe5711ed40faeb580e63b16755a3a24e66fa1d87c0", size = 256882, upload-time = "2025-06-30T15:52:54.596Z" }, - { url = "https://files.pythonhosted.org/packages/da/88/84a27570fbe303c65607d517a5f147cd2fc046c2d1da02b84b17b9bdc2aa/multidict-6.6.3-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:2e4cc8d848cd4fe1cdee28c13ea79ab0ed37fc2e89dd77bac86a2e7959a8c3bc", size = 247816, upload-time = "2025-06-30T15:52:56.175Z" }, - { url = "https://files.pythonhosted.org/packages/1c/60/dca352a0c999ce96a5d8b8ee0b2b9f729dcad2e0b0c195f8286269a2074c/multidict-6.6.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9e236a7094b9c4c1b7585f6b9cca34b9d833cf079f7e4c49e6a4a6ec9bfdc68f", size = 245341, upload-time = "2025-06-30T15:52:57.752Z" }, - { url = "https://files.pythonhosted.org/packages/50/ef/433fa3ed06028f03946f3993223dada70fb700f763f70c00079533c34578/multidict-6.6.3-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:e0cb0ab69915c55627c933f0b555a943d98ba71b4d1c57bc0d0a66e2567c7471", size = 235854, upload-time = "2025-06-30T15:52:59.74Z" }, - { url = "https://files.pythonhosted.org/packages/1b/1f/487612ab56fbe35715320905215a57fede20de7db40a261759690dc80471/multidict-6.6.3-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:81ef2f64593aba09c5212a3d0f8c906a0d38d710a011f2f42759704d4557d3f2", size = 243432, upload-time = "2025-06-30T15:53:01.602Z" }, - { url = "https://files.pythonhosted.org/packages/da/6f/ce8b79de16cd885c6f9052c96a3671373d00c59b3ee635ea93e6e81b8ccf/multidict-6.6.3-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:b9cbc60010de3562545fa198bfc6d3825df430ea96d2cc509c39bd71e2e7d648", size = 252731, upload-time = "2025-06-30T15:53:03.517Z" }, - { url = "https://files.pythonhosted.org/packages/bb/fe/a2514a6aba78e5abefa1624ca85ae18f542d95ac5cde2e3815a9fbf369aa/multidict-6.6.3-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:70d974eaaa37211390cd02ef93b7e938de564bbffa866f0b08d07e5e65da783d", size = 247086, upload-time = "2025-06-30T15:53:05.48Z" }, - { url = "https://files.pythonhosted.org/packages/8c/22/b788718d63bb3cce752d107a57c85fcd1a212c6c778628567c9713f9345a/multidict-6.6.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:3713303e4a6663c6d01d648a68f2848701001f3390a030edaaf3fc949c90bf7c", size = 243338, upload-time = "2025-06-30T15:53:07.522Z" }, - { url = "https://files.pythonhosted.org/packages/22/d6/fdb3d0670819f2228f3f7d9af613d5e652c15d170c83e5f1c94fbc55a25b/multidict-6.6.3-cp313-cp313t-win32.whl", hash = "sha256:639ecc9fe7cd73f2495f62c213e964843826f44505a3e5d82805aa85cac6f89e", size = 47812, upload-time = "2025-06-30T15:53:09.263Z" }, - { url = "https://files.pythonhosted.org/packages/b6/d6/a9d2c808f2c489ad199723197419207ecbfbc1776f6e155e1ecea9c883aa/multidict-6.6.3-cp313-cp313t-win_amd64.whl", hash = "sha256:9f97e181f344a0ef3881b573d31de8542cc0dbc559ec68c8f8b5ce2c2e91646d", size = 53011, upload-time = "2025-06-30T15:53:11.038Z" }, - { url = "https://files.pythonhosted.org/packages/f2/40/b68001cba8188dd267590a111f9661b6256debc327137667e832bf5d66e8/multidict-6.6.3-cp313-cp313t-win_arm64.whl", hash = "sha256:ce8b7693da41a3c4fde5871c738a81490cea5496c671d74374c8ab889e1834fb", size = 45254, upload-time = "2025-06-30T15:53:12.421Z" }, - { url = "https://files.pythonhosted.org/packages/d8/30/9aec301e9772b098c1f5c0ca0279237c9766d94b97802e9888010c64b0ed/multidict-6.6.3-py3-none-any.whl", hash = "sha256:8db10f29c7541fc5da4defd8cd697e1ca429db743fa716325f236079b96f775a", size = 12313, upload-time = "2025-06-30T15:53:45.437Z" }, -] - -[[package]] -name = "parsimonious" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7b/91/abdc50c4ef06fdf8d047f60ee777ca9b2a7885e1a9cea81343fbecda52d7/parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c", size = 52172, upload-time = "2022-09-03T17:01:17.004Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/0f/c8b64d9b54ea631fcad4e9e3c8dbe8c11bb32a623be94f22974c88e71eaf/parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f", size = 48427, upload-time = "2022-09-03T17:01:13.814Z" }, -] - -[[package]] -name = "propcache" -version = "0.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4e/ad52a7925ff01c1325653a730c7ec3175a23f948f08626a534133427dcff/propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3", size = 43133, upload-time = "2025-06-09T22:53:41.965Z" }, - { url = "https://files.pythonhosted.org/packages/63/7c/e9399ba5da7780871db4eac178e9c2e204c23dd3e7d32df202092a1ed400/propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3", size = 43039, upload-time = "2025-06-09T22:53:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/22/e1/58da211eb8fdc6fc854002387d38f415a6ca5f5c67c1315b204a5d3e9d7a/propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e", size = 201903, upload-time = "2025-06-09T22:53:44.872Z" }, - { url = "https://files.pythonhosted.org/packages/c4/0a/550ea0f52aac455cb90111c8bab995208443e46d925e51e2f6ebdf869525/propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220", size = 213362, upload-time = "2025-06-09T22:53:46.707Z" }, - { url = "https://files.pythonhosted.org/packages/5a/af/9893b7d878deda9bb69fcf54600b247fba7317761b7db11fede6e0f28bd0/propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb", size = 210525, upload-time = "2025-06-09T22:53:48.547Z" }, - { url = "https://files.pythonhosted.org/packages/7c/bb/38fd08b278ca85cde36d848091ad2b45954bc5f15cce494bb300b9285831/propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614", size = 198283, upload-time = "2025-06-09T22:53:50.067Z" }, - { url = "https://files.pythonhosted.org/packages/78/8c/9fe55bd01d362bafb413dfe508c48753111a1e269737fa143ba85693592c/propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50", size = 191872, upload-time = "2025-06-09T22:53:51.438Z" }, - { url = "https://files.pythonhosted.org/packages/54/14/4701c33852937a22584e08abb531d654c8bcf7948a8f87ad0a4822394147/propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339", size = 199452, upload-time = "2025-06-09T22:53:53.229Z" }, - { url = "https://files.pythonhosted.org/packages/16/44/447f2253d859602095356007657ee535e0093215ea0b3d1d6a41d16e5201/propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0", size = 191567, upload-time = "2025-06-09T22:53:54.541Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/e4756258749bb2d3b46defcff606a2f47410bab82be5824a67e84015b267/propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2", size = 193015, upload-time = "2025-06-09T22:53:56.44Z" }, - { url = "https://files.pythonhosted.org/packages/1e/df/e6d3c7574233164b6330b9fd697beeac402afd367280e6dc377bb99b43d9/propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7", size = 204660, upload-time = "2025-06-09T22:53:57.839Z" }, - { url = "https://files.pythonhosted.org/packages/b2/53/e4d31dd5170b4a0e2e6b730f2385a96410633b4833dc25fe5dffd1f73294/propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b", size = 206105, upload-time = "2025-06-09T22:53:59.638Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fe/74d54cf9fbe2a20ff786e5f7afcfde446588f0cf15fb2daacfbc267b866c/propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c", size = 196980, upload-time = "2025-06-09T22:54:01.071Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/c469c9d59dada8a7679625e0440b544fe72e99311a4679c279562051f6fc/propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70", size = 37679, upload-time = "2025-06-09T22:54:03.003Z" }, - { url = "https://files.pythonhosted.org/packages/38/35/07a471371ac89d418f8d0b699c75ea6dca2041fbda360823de21f6a9ce0a/propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9", size = 41459, upload-time = "2025-06-09T22:54:04.134Z" }, - { url = "https://files.pythonhosted.org/packages/80/8d/e8b436717ab9c2cfc23b116d2c297305aa4cd8339172a456d61ebf5669b8/propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be", size = 74207, upload-time = "2025-06-09T22:54:05.399Z" }, - { url = "https://files.pythonhosted.org/packages/d6/29/1e34000e9766d112171764b9fa3226fa0153ab565d0c242c70e9945318a7/propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f", size = 43648, upload-time = "2025-06-09T22:54:08.023Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/1ad5af0df781e76988897da39b5f086c2bf0f028b7f9bd1f409bb05b6874/propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9", size = 43496, upload-time = "2025-06-09T22:54:09.228Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ce/e96392460f9fb68461fabab3e095cb00c8ddf901205be4eae5ce246e5b7e/propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf", size = 217288, upload-time = "2025-06-09T22:54:10.466Z" }, - { url = "https://files.pythonhosted.org/packages/c5/2a/866726ea345299f7ceefc861a5e782b045545ae6940851930a6adaf1fca6/propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9", size = 227456, upload-time = "2025-06-09T22:54:11.828Z" }, - { url = "https://files.pythonhosted.org/packages/de/03/07d992ccb6d930398689187e1b3c718339a1c06b8b145a8d9650e4726166/propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66", size = 225429, upload-time = "2025-06-09T22:54:13.823Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/116ba39448753b1330f48ab8ba927dcd6cf0baea8a0ccbc512dfb49ba670/propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df", size = 213472, upload-time = "2025-06-09T22:54:15.232Z" }, - { url = "https://files.pythonhosted.org/packages/a6/85/f01f5d97e54e428885a5497ccf7f54404cbb4f906688a1690cd51bf597dc/propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2", size = 204480, upload-time = "2025-06-09T22:54:17.104Z" }, - { url = "https://files.pythonhosted.org/packages/e3/79/7bf5ab9033b8b8194cc3f7cf1aaa0e9c3256320726f64a3e1f113a812dce/propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7", size = 214530, upload-time = "2025-06-09T22:54:18.512Z" }, - { url = "https://files.pythonhosted.org/packages/31/0b/bd3e0c00509b609317df4a18e6b05a450ef2d9a963e1d8bc9c9415d86f30/propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95", size = 205230, upload-time = "2025-06-09T22:54:19.947Z" }, - { url = "https://files.pythonhosted.org/packages/7a/23/fae0ff9b54b0de4e819bbe559508da132d5683c32d84d0dc2ccce3563ed4/propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e", size = 206754, upload-time = "2025-06-09T22:54:21.716Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7f/ad6a3c22630aaa5f618b4dc3c3598974a72abb4c18e45a50b3cdd091eb2f/propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e", size = 218430, upload-time = "2025-06-09T22:54:23.17Z" }, - { url = "https://files.pythonhosted.org/packages/5b/2c/ba4f1c0e8a4b4c75910742f0d333759d441f65a1c7f34683b4a74c0ee015/propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf", size = 223884, upload-time = "2025-06-09T22:54:25.539Z" }, - { url = "https://files.pythonhosted.org/packages/88/e4/ebe30fc399e98572019eee82ad0caf512401661985cbd3da5e3140ffa1b0/propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e", size = 211480, upload-time = "2025-06-09T22:54:26.892Z" }, - { url = "https://files.pythonhosted.org/packages/96/0a/7d5260b914e01d1d0906f7f38af101f8d8ed0dc47426219eeaf05e8ea7c2/propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897", size = 37757, upload-time = "2025-06-09T22:54:28.241Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2d/89fe4489a884bc0da0c3278c552bd4ffe06a1ace559db5ef02ef24ab446b/propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39", size = 41500, upload-time = "2025-06-09T22:54:29.4Z" }, - { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, - { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, - { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, - { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, - { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, - { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, - { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, - { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, - { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, - { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, - { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, - { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, - { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, - { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, - { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, - { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, - { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, - { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, - { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, - { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, - { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, - { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, - { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, - { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, - { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, - { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, - { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, - { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, - { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, -] - -[[package]] -name = "pycryptodome" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" }, - { url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" }, - { url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" }, - { url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" }, - { url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" }, - { url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" }, - { url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" }, - { url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" }, - { url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" }, - { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, - { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, - { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, - { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, - { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, - { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, - { url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886, upload-time = "2025-05-17T17:21:20.614Z" }, - { url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151, upload-time = "2025-05-17T17:21:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461, upload-time = "2025-05-17T17:21:25.225Z" }, - { url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440, upload-time = "2025-05-17T17:21:27.991Z" }, - { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, -] - -[[package]] -name = "pydantic" -version = "2.11.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/dd/4325abf92c39ba8623b5af936ddb36ffcfe0beae70405d456ab1fb2f5b8c/pydantic-2.11.7.tar.gz", hash = "sha256:d989c3c6cb79469287b1569f7447a17848c998458d49ebe294e975b9baf0f0db", size = 788350, upload-time = "2025-06-14T08:33:17.137Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6a/c0/ec2b1c8712ca690e5d61979dee872603e92b8a32f94cc1b72d53beab008a/pydantic-2.11.7-py3-none-any.whl", hash = "sha256:dde5df002701f6de26248661f6835bbe296a47bf73990135c7d07ce741b9623b", size = 444782, upload-time = "2025-06-14T08:33:14.905Z" }, -] - -[package.optional-dependencies] -email = [ - { name = "email-validator" }, -] - -[[package]] -name = "pydantic-core" -version = "2.33.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ad/88/5f2260bdfae97aabf98f1778d43f69574390ad787afb646292a638c923d4/pydantic_core-2.33.2.tar.gz", hash = "sha256:7cb8bc3605c29176e1b105350d2e6474142d7c1bd1d9327c4a9bdb46bf827acc", size = 435195, upload-time = "2025-04-23T18:33:52.104Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e5/92/b31726561b5dae176c2d2c2dc43a9c5bfba5d32f96f8b4c0a600dd492447/pydantic_core-2.33.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2b3d326aaef0c0399d9afffeb6367d5e26ddc24d351dbc9c636840ac355dc5d8", size = 2028817, upload-time = "2025-04-23T18:30:43.919Z" }, - { url = "https://files.pythonhosted.org/packages/a3/44/3f0b95fafdaca04a483c4e685fe437c6891001bf3ce8b2fded82b9ea3aa1/pydantic_core-2.33.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0e5b2671f05ba48b94cb90ce55d8bdcaaedb8ba00cc5359f6810fc918713983d", size = 1861357, upload-time = "2025-04-23T18:30:46.372Z" }, - { url = "https://files.pythonhosted.org/packages/30/97/e8f13b55766234caae05372826e8e4b3b96e7b248be3157f53237682e43c/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0069c9acc3f3981b9ff4cdfaf088e98d83440a4c7ea1bc07460af3d4dc22e72d", size = 1898011, upload-time = "2025-04-23T18:30:47.591Z" }, - { url = "https://files.pythonhosted.org/packages/9b/a3/99c48cf7bafc991cc3ee66fd544c0aae8dc907b752f1dad2d79b1b5a471f/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:d53b22f2032c42eaaf025f7c40c2e3b94568ae077a606f006d206a463bc69572", size = 1982730, upload-time = "2025-04-23T18:30:49.328Z" }, - { url = "https://files.pythonhosted.org/packages/de/8e/a5b882ec4307010a840fb8b58bd9bf65d1840c92eae7534c7441709bf54b/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0405262705a123b7ce9f0b92f123334d67b70fd1f20a9372b907ce1080c7ba02", size = 2136178, upload-time = "2025-04-23T18:30:50.907Z" }, - { url = "https://files.pythonhosted.org/packages/e4/bb/71e35fc3ed05af6834e890edb75968e2802fe98778971ab5cba20a162315/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b25d91e288e2c4e0662b8038a28c6a07eaac3e196cfc4ff69de4ea3db992a1b", size = 2736462, upload-time = "2025-04-23T18:30:52.083Z" }, - { url = "https://files.pythonhosted.org/packages/31/0d/c8f7593e6bc7066289bbc366f2235701dcbebcd1ff0ef8e64f6f239fb47d/pydantic_core-2.33.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6bdfe4b3789761f3bcb4b1ddf33355a71079858958e3a552f16d5af19768fef2", size = 2005652, upload-time = "2025-04-23T18:30:53.389Z" }, - { url = "https://files.pythonhosted.org/packages/d2/7a/996d8bd75f3eda405e3dd219ff5ff0a283cd8e34add39d8ef9157e722867/pydantic_core-2.33.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:efec8db3266b76ef9607c2c4c419bdb06bf335ae433b80816089ea7585816f6a", size = 2113306, upload-time = "2025-04-23T18:30:54.661Z" }, - { url = "https://files.pythonhosted.org/packages/ff/84/daf2a6fb2db40ffda6578a7e8c5a6e9c8affb251a05c233ae37098118788/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:031c57d67ca86902726e0fae2214ce6770bbe2f710dc33063187a68744a5ecac", size = 2073720, upload-time = "2025-04-23T18:30:56.11Z" }, - { url = "https://files.pythonhosted.org/packages/77/fb/2258da019f4825128445ae79456a5499c032b55849dbd5bed78c95ccf163/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:f8de619080e944347f5f20de29a975c2d815d9ddd8be9b9b7268e2e3ef68605a", size = 2244915, upload-time = "2025-04-23T18:30:57.501Z" }, - { url = "https://files.pythonhosted.org/packages/d8/7a/925ff73756031289468326e355b6fa8316960d0d65f8b5d6b3a3e7866de7/pydantic_core-2.33.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:73662edf539e72a9440129f231ed3757faab89630d291b784ca99237fb94db2b", size = 2241884, upload-time = "2025-04-23T18:30:58.867Z" }, - { url = "https://files.pythonhosted.org/packages/0b/b0/249ee6d2646f1cdadcb813805fe76265745c4010cf20a8eba7b0e639d9b2/pydantic_core-2.33.2-cp310-cp310-win32.whl", hash = "sha256:0a39979dcbb70998b0e505fb1556a1d550a0781463ce84ebf915ba293ccb7e22", size = 1910496, upload-time = "2025-04-23T18:31:00.078Z" }, - { url = "https://files.pythonhosted.org/packages/66/ff/172ba8f12a42d4b552917aa65d1f2328990d3ccfc01d5b7c943ec084299f/pydantic_core-2.33.2-cp310-cp310-win_amd64.whl", hash = "sha256:b0379a2b24882fef529ec3b4987cb5d003b9cda32256024e6fe1586ac45fc640", size = 1955019, upload-time = "2025-04-23T18:31:01.335Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8d/71db63483d518cbbf290261a1fc2839d17ff89fce7089e08cad07ccfce67/pydantic_core-2.33.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:4c5b0a576fb381edd6d27f0a85915c6daf2f8138dc5c267a57c08a62900758c7", size = 2028584, upload-time = "2025-04-23T18:31:03.106Z" }, - { url = "https://files.pythonhosted.org/packages/24/2f/3cfa7244ae292dd850989f328722d2aef313f74ffc471184dc509e1e4e5a/pydantic_core-2.33.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e799c050df38a639db758c617ec771fd8fb7a5f8eaaa4b27b101f266b216a246", size = 1855071, upload-time = "2025-04-23T18:31:04.621Z" }, - { url = "https://files.pythonhosted.org/packages/b3/d3/4ae42d33f5e3f50dd467761304be2fa0a9417fbf09735bc2cce003480f2a/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dc46a01bf8d62f227d5ecee74178ffc448ff4e5197c756331f71efcc66dc980f", size = 1897823, upload-time = "2025-04-23T18:31:06.377Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f3/aa5976e8352b7695ff808599794b1fba2a9ae2ee954a3426855935799488/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a144d4f717285c6d9234a66778059f33a89096dfb9b39117663fd8413d582dcc", size = 1983792, upload-time = "2025-04-23T18:31:07.93Z" }, - { url = "https://files.pythonhosted.org/packages/d5/7a/cda9b5a23c552037717f2b2a5257e9b2bfe45e687386df9591eff7b46d28/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:73cf6373c21bc80b2e0dc88444f41ae60b2f070ed02095754eb5a01df12256de", size = 2136338, upload-time = "2025-04-23T18:31:09.283Z" }, - { url = "https://files.pythonhosted.org/packages/2b/9f/b8f9ec8dd1417eb9da784e91e1667d58a2a4a7b7b34cf4af765ef663a7e5/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:3dc625f4aa79713512d1976fe9f0bc99f706a9dee21dfd1810b4bbbf228d0e8a", size = 2730998, upload-time = "2025-04-23T18:31:11.7Z" }, - { url = "https://files.pythonhosted.org/packages/47/bc/cd720e078576bdb8255d5032c5d63ee5c0bf4b7173dd955185a1d658c456/pydantic_core-2.33.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:881b21b5549499972441da4758d662aeea93f1923f953e9cbaff14b8b9565aef", size = 2003200, upload-time = "2025-04-23T18:31:13.536Z" }, - { url = "https://files.pythonhosted.org/packages/ca/22/3602b895ee2cd29d11a2b349372446ae9727c32e78a94b3d588a40fdf187/pydantic_core-2.33.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:bdc25f3681f7b78572699569514036afe3c243bc3059d3942624e936ec93450e", size = 2113890, upload-time = "2025-04-23T18:31:15.011Z" }, - { url = "https://files.pythonhosted.org/packages/ff/e6/e3c5908c03cf00d629eb38393a98fccc38ee0ce8ecce32f69fc7d7b558a7/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:fe5b32187cbc0c862ee201ad66c30cf218e5ed468ec8dc1cf49dec66e160cc4d", size = 2073359, upload-time = "2025-04-23T18:31:16.393Z" }, - { url = "https://files.pythonhosted.org/packages/12/e7/6a36a07c59ebefc8777d1ffdaf5ae71b06b21952582e4b07eba88a421c79/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:bc7aee6f634a6f4a95676fcb5d6559a2c2a390330098dba5e5a5f28a2e4ada30", size = 2245883, upload-time = "2025-04-23T18:31:17.892Z" }, - { url = "https://files.pythonhosted.org/packages/16/3f/59b3187aaa6cc0c1e6616e8045b284de2b6a87b027cce2ffcea073adf1d2/pydantic_core-2.33.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:235f45e5dbcccf6bd99f9f472858849f73d11120d76ea8707115415f8e5ebebf", size = 2241074, upload-time = "2025-04-23T18:31:19.205Z" }, - { url = "https://files.pythonhosted.org/packages/e0/ed/55532bb88f674d5d8f67ab121a2a13c385df382de2a1677f30ad385f7438/pydantic_core-2.33.2-cp311-cp311-win32.whl", hash = "sha256:6368900c2d3ef09b69cb0b913f9f8263b03786e5b2a387706c5afb66800efd51", size = 1910538, upload-time = "2025-04-23T18:31:20.541Z" }, - { url = "https://files.pythonhosted.org/packages/fe/1b/25b7cccd4519c0b23c2dd636ad39d381abf113085ce4f7bec2b0dc755eb1/pydantic_core-2.33.2-cp311-cp311-win_amd64.whl", hash = "sha256:1e063337ef9e9820c77acc768546325ebe04ee38b08703244c1309cccc4f1bab", size = 1952909, upload-time = "2025-04-23T18:31:22.371Z" }, - { url = "https://files.pythonhosted.org/packages/49/a9/d809358e49126438055884c4366a1f6227f0f84f635a9014e2deb9b9de54/pydantic_core-2.33.2-cp311-cp311-win_arm64.whl", hash = "sha256:6b99022f1d19bc32a4c2a0d544fc9a76e3be90f0b3f4af413f87d38749300e65", size = 1897786, upload-time = "2025-04-23T18:31:24.161Z" }, - { url = "https://files.pythonhosted.org/packages/18/8a/2b41c97f554ec8c71f2a8a5f85cb56a8b0956addfe8b0efb5b3d77e8bdc3/pydantic_core-2.33.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:a7ec89dc587667f22b6a0b6579c249fca9026ce7c333fc142ba42411fa243cdc", size = 2009000, upload-time = "2025-04-23T18:31:25.863Z" }, - { url = "https://files.pythonhosted.org/packages/a1/02/6224312aacb3c8ecbaa959897af57181fb6cf3a3d7917fd44d0f2917e6f2/pydantic_core-2.33.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3c6db6e52c6d70aa0d00d45cdb9b40f0433b96380071ea80b09277dba021ddf7", size = 1847996, upload-time = "2025-04-23T18:31:27.341Z" }, - { url = "https://files.pythonhosted.org/packages/d6/46/6dcdf084a523dbe0a0be59d054734b86a981726f221f4562aed313dbcb49/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4e61206137cbc65e6d5256e1166f88331d3b6238e082d9f74613b9b765fb9025", size = 1880957, upload-time = "2025-04-23T18:31:28.956Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6b/1ec2c03837ac00886ba8160ce041ce4e325b41d06a034adbef11339ae422/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eb8c529b2819c37140eb51b914153063d27ed88e3bdc31b71198a198e921e011", size = 1964199, upload-time = "2025-04-23T18:31:31.025Z" }, - { url = "https://files.pythonhosted.org/packages/2d/1d/6bf34d6adb9debd9136bd197ca72642203ce9aaaa85cfcbfcf20f9696e83/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c52b02ad8b4e2cf14ca7b3d918f3eb0ee91e63b3167c32591e57c4317e134f8f", size = 2120296, upload-time = "2025-04-23T18:31:32.514Z" }, - { url = "https://files.pythonhosted.org/packages/e0/94/2bd0aaf5a591e974b32a9f7123f16637776c304471a0ab33cf263cf5591a/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:96081f1605125ba0855dfda83f6f3df5ec90c61195421ba72223de35ccfb2f88", size = 2676109, upload-time = "2025-04-23T18:31:33.958Z" }, - { url = "https://files.pythonhosted.org/packages/f9/41/4b043778cf9c4285d59742281a769eac371b9e47e35f98ad321349cc5d61/pydantic_core-2.33.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f57a69461af2a5fa6e6bbd7a5f60d3b7e6cebb687f55106933188e79ad155c1", size = 2002028, upload-time = "2025-04-23T18:31:39.095Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d5/7bb781bf2748ce3d03af04d5c969fa1308880e1dca35a9bd94e1a96a922e/pydantic_core-2.33.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:572c7e6c8bb4774d2ac88929e3d1f12bc45714ae5ee6d9a788a9fb35e60bb04b", size = 2100044, upload-time = "2025-04-23T18:31:41.034Z" }, - { url = "https://files.pythonhosted.org/packages/fe/36/def5e53e1eb0ad896785702a5bbfd25eed546cdcf4087ad285021a90ed53/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:db4b41f9bd95fbe5acd76d89920336ba96f03e149097365afe1cb092fceb89a1", size = 2058881, upload-time = "2025-04-23T18:31:42.757Z" }, - { url = "https://files.pythonhosted.org/packages/01/6c/57f8d70b2ee57fc3dc8b9610315949837fa8c11d86927b9bb044f8705419/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:fa854f5cf7e33842a892e5c73f45327760bc7bc516339fda888c75ae60edaeb6", size = 2227034, upload-time = "2025-04-23T18:31:44.304Z" }, - { url = "https://files.pythonhosted.org/packages/27/b9/9c17f0396a82b3d5cbea4c24d742083422639e7bb1d5bf600e12cb176a13/pydantic_core-2.33.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:5f483cfb75ff703095c59e365360cb73e00185e01aaea067cd19acffd2ab20ea", size = 2234187, upload-time = "2025-04-23T18:31:45.891Z" }, - { url = "https://files.pythonhosted.org/packages/b0/6a/adf5734ffd52bf86d865093ad70b2ce543415e0e356f6cacabbc0d9ad910/pydantic_core-2.33.2-cp312-cp312-win32.whl", hash = "sha256:9cb1da0f5a471435a7bc7e439b8a728e8b61e59784b2af70d7c169f8dd8ae290", size = 1892628, upload-time = "2025-04-23T18:31:47.819Z" }, - { url = "https://files.pythonhosted.org/packages/43/e4/5479fecb3606c1368d496a825d8411e126133c41224c1e7238be58b87d7e/pydantic_core-2.33.2-cp312-cp312-win_amd64.whl", hash = "sha256:f941635f2a3d96b2973e867144fde513665c87f13fe0e193c158ac51bfaaa7b2", size = 1955866, upload-time = "2025-04-23T18:31:49.635Z" }, - { url = "https://files.pythonhosted.org/packages/0d/24/8b11e8b3e2be9dd82df4b11408a67c61bb4dc4f8e11b5b0fc888b38118b5/pydantic_core-2.33.2-cp312-cp312-win_arm64.whl", hash = "sha256:cca3868ddfaccfbc4bfb1d608e2ccaaebe0ae628e1416aeb9c4d88c001bb45ab", size = 1888894, upload-time = "2025-04-23T18:31:51.609Z" }, - { url = "https://files.pythonhosted.org/packages/46/8c/99040727b41f56616573a28771b1bfa08a3d3fe74d3d513f01251f79f172/pydantic_core-2.33.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:1082dd3e2d7109ad8b7da48e1d4710c8d06c253cbc4a27c1cff4fbcaa97a9e3f", size = 2015688, upload-time = "2025-04-23T18:31:53.175Z" }, - { url = "https://files.pythonhosted.org/packages/3a/cc/5999d1eb705a6cefc31f0b4a90e9f7fc400539b1a1030529700cc1b51838/pydantic_core-2.33.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f517ca031dfc037a9c07e748cefd8d96235088b83b4f4ba8939105d20fa1dcd6", size = 1844808, upload-time = "2025-04-23T18:31:54.79Z" }, - { url = "https://files.pythonhosted.org/packages/6f/5e/a0a7b8885c98889a18b6e376f344da1ef323d270b44edf8174d6bce4d622/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a9f2c9dd19656823cb8250b0724ee9c60a82f3cdf68a080979d13092a3b0fef", size = 1885580, upload-time = "2025-04-23T18:31:57.393Z" }, - { url = "https://files.pythonhosted.org/packages/3b/2a/953581f343c7d11a304581156618c3f592435523dd9d79865903272c256a/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2b0a451c263b01acebe51895bfb0e1cc842a5c666efe06cdf13846c7418caa9a", size = 1973859, upload-time = "2025-04-23T18:31:59.065Z" }, - { url = "https://files.pythonhosted.org/packages/e6/55/f1a813904771c03a3f97f676c62cca0c0a4138654107c1b61f19c644868b/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ea40a64d23faa25e62a70ad163571c0b342b8bf66d5fa612ac0dec4f069d916", size = 2120810, upload-time = "2025-04-23T18:32:00.78Z" }, - { url = "https://files.pythonhosted.org/packages/aa/c3/053389835a996e18853ba107a63caae0b9deb4a276c6b472931ea9ae6e48/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fb2d542b4d66f9470e8065c5469ec676978d625a8b7a363f07d9a501a9cb36a", size = 2676498, upload-time = "2025-04-23T18:32:02.418Z" }, - { url = "https://files.pythonhosted.org/packages/eb/3c/f4abd740877a35abade05e437245b192f9d0ffb48bbbbd708df33d3cda37/pydantic_core-2.33.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9fdac5d6ffa1b5a83bca06ffe7583f5576555e6c8b3a91fbd25ea7780f825f7d", size = 2000611, upload-time = "2025-04-23T18:32:04.152Z" }, - { url = "https://files.pythonhosted.org/packages/59/a7/63ef2fed1837d1121a894d0ce88439fe3e3b3e48c7543b2a4479eb99c2bd/pydantic_core-2.33.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04a1a413977ab517154eebb2d326da71638271477d6ad87a769102f7c2488c56", size = 2107924, upload-time = "2025-04-23T18:32:06.129Z" }, - { url = "https://files.pythonhosted.org/packages/04/8f/2551964ef045669801675f1cfc3b0d74147f4901c3ffa42be2ddb1f0efc4/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:c8e7af2f4e0194c22b5b37205bfb293d166a7344a5b0d0eaccebc376546d77d5", size = 2063196, upload-time = "2025-04-23T18:32:08.178Z" }, - { url = "https://files.pythonhosted.org/packages/26/bd/d9602777e77fc6dbb0c7db9ad356e9a985825547dce5ad1d30ee04903918/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:5c92edd15cd58b3c2d34873597a1e20f13094f59cf88068adb18947df5455b4e", size = 2236389, upload-time = "2025-04-23T18:32:10.242Z" }, - { url = "https://files.pythonhosted.org/packages/42/db/0e950daa7e2230423ab342ae918a794964b053bec24ba8af013fc7c94846/pydantic_core-2.33.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:65132b7b4a1c0beded5e057324b7e16e10910c106d43675d9bd87d4f38dde162", size = 2239223, upload-time = "2025-04-23T18:32:12.382Z" }, - { url = "https://files.pythonhosted.org/packages/58/4d/4f937099c545a8a17eb52cb67fe0447fd9a373b348ccfa9a87f141eeb00f/pydantic_core-2.33.2-cp313-cp313-win32.whl", hash = "sha256:52fb90784e0a242bb96ec53f42196a17278855b0f31ac7c3cc6f5c1ec4811849", size = 1900473, upload-time = "2025-04-23T18:32:14.034Z" }, - { url = "https://files.pythonhosted.org/packages/a0/75/4a0a9bac998d78d889def5e4ef2b065acba8cae8c93696906c3a91f310ca/pydantic_core-2.33.2-cp313-cp313-win_amd64.whl", hash = "sha256:c083a3bdd5a93dfe480f1125926afcdbf2917ae714bdb80b36d34318b2bec5d9", size = 1955269, upload-time = "2025-04-23T18:32:15.783Z" }, - { url = "https://files.pythonhosted.org/packages/f9/86/1beda0576969592f1497b4ce8e7bc8cbdf614c352426271b1b10d5f0aa64/pydantic_core-2.33.2-cp313-cp313-win_arm64.whl", hash = "sha256:e80b087132752f6b3d714f041ccf74403799d3b23a72722ea2e6ba2e892555b9", size = 1893921, upload-time = "2025-04-23T18:32:18.473Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/e09391c2eebeab681df2b74bfe6c43422fffede8dc74187b2b0bf6fd7571/pydantic_core-2.33.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:61c18fba8e5e9db3ab908620af374db0ac1baa69f0f32df4f61ae23f15e586ac", size = 1806162, upload-time = "2025-04-23T18:32:20.188Z" }, - { url = "https://files.pythonhosted.org/packages/f1/3d/847b6b1fed9f8ed3bb95a9ad04fbd0b212e832d4f0f50ff4d9ee5a9f15cf/pydantic_core-2.33.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:95237e53bb015f67b63c91af7518a62a8660376a6a0db19b89acc77a4d6199f5", size = 1981560, upload-time = "2025-04-23T18:32:22.354Z" }, - { url = "https://files.pythonhosted.org/packages/6f/9a/e73262f6c6656262b5fdd723ad90f518f579b7bc8622e43a942eec53c938/pydantic_core-2.33.2-cp313-cp313t-win_amd64.whl", hash = "sha256:c2fc0a768ef76c15ab9238afa6da7f69895bb5d1ee83aeea2e3509af4472d0b9", size = 1935777, upload-time = "2025-04-23T18:32:25.088Z" }, - { url = "https://files.pythonhosted.org/packages/30/68/373d55e58b7e83ce371691f6eaa7175e3a24b956c44628eb25d7da007917/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:5c4aa4e82353f65e548c476b37e64189783aa5384903bfea4f41580f255fddfa", size = 2023982, upload-time = "2025-04-23T18:32:53.14Z" }, - { url = "https://files.pythonhosted.org/packages/a4/16/145f54ac08c96a63d8ed6442f9dec17b2773d19920b627b18d4f10a061ea/pydantic_core-2.33.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:d946c8bf0d5c24bf4fe333af284c59a19358aa3ec18cb3dc4370080da1e8ad29", size = 1858412, upload-time = "2025-04-23T18:32:55.52Z" }, - { url = "https://files.pythonhosted.org/packages/41/b1/c6dc6c3e2de4516c0bb2c46f6a373b91b5660312342a0cf5826e38ad82fa/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:87b31b6846e361ef83fedb187bb5b4372d0da3f7e28d85415efa92d6125d6e6d", size = 1892749, upload-time = "2025-04-23T18:32:57.546Z" }, - { url = "https://files.pythonhosted.org/packages/12/73/8cd57e20afba760b21b742106f9dbdfa6697f1570b189c7457a1af4cd8a0/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:aa9d91b338f2df0508606f7009fde642391425189bba6d8c653afd80fd6bb64e", size = 2067527, upload-time = "2025-04-23T18:32:59.771Z" }, - { url = "https://files.pythonhosted.org/packages/e3/d5/0bb5d988cc019b3cba4a78f2d4b3854427fc47ee8ec8e9eaabf787da239c/pydantic_core-2.33.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2058a32994f1fde4ca0480ab9d1e75a0e8c87c22b53a3ae66554f9af78f2fe8c", size = 2108225, upload-time = "2025-04-23T18:33:04.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/c5/00c02d1571913d496aabf146106ad8239dc132485ee22efe08085084ff7c/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:0e03262ab796d986f978f79c943fc5f620381be7287148b8010b4097f79a39ec", size = 2069490, upload-time = "2025-04-23T18:33:06.391Z" }, - { url = "https://files.pythonhosted.org/packages/22/a8/dccc38768274d3ed3a59b5d06f59ccb845778687652daa71df0cab4040d7/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:1a8695a8d00c73e50bff9dfda4d540b7dee29ff9b8053e38380426a85ef10052", size = 2237525, upload-time = "2025-04-23T18:33:08.44Z" }, - { url = "https://files.pythonhosted.org/packages/d4/e7/4f98c0b125dda7cf7ccd14ba936218397b44f50a56dd8c16a3091df116c3/pydantic_core-2.33.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:fa754d1850735a0b0e03bcffd9d4b4343eb417e47196e4485d9cca326073a42c", size = 2238446, upload-time = "2025-04-23T18:33:10.313Z" }, - { url = "https://files.pythonhosted.org/packages/ce/91/2ec36480fdb0b783cd9ef6795753c1dea13882f2e68e73bce76ae8c21e6a/pydantic_core-2.33.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:a11c8d26a50bfab49002947d3d237abe4d9e4b5bdc8846a63537b6488e197808", size = 2066678, upload-time = "2025-04-23T18:33:12.224Z" }, - { url = "https://files.pythonhosted.org/packages/7b/27/d4ae6487d73948d6f20dddcd94be4ea43e74349b56eba82e9bdee2d7494c/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:dd14041875d09cc0f9308e37a6f8b65f5585cf2598a53aa0123df8b129d481f8", size = 2025200, upload-time = "2025-04-23T18:33:14.199Z" }, - { url = "https://files.pythonhosted.org/packages/f1/b8/b3cb95375f05d33801024079b9392a5ab45267a63400bf1866e7ce0f0de4/pydantic_core-2.33.2-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:d87c561733f66531dced0da6e864f44ebf89a8fba55f31407b00c2f7f9449593", size = 1859123, upload-time = "2025-04-23T18:33:16.555Z" }, - { url = "https://files.pythonhosted.org/packages/05/bc/0d0b5adeda59a261cd30a1235a445bf55c7e46ae44aea28f7bd6ed46e091/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2f82865531efd18d6e07a04a17331af02cb7a651583c418df8266f17a63c6612", size = 1892852, upload-time = "2025-04-23T18:33:18.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/11/d37bdebbda2e449cb3f519f6ce950927b56d62f0b84fd9cb9e372a26a3d5/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2bfb5112df54209d820d7bf9317c7a6c9025ea52e49f46b6a2060104bba37de7", size = 2067484, upload-time = "2025-04-23T18:33:20.475Z" }, - { url = "https://files.pythonhosted.org/packages/8c/55/1f95f0a05ce72ecb02a8a8a1c3be0579bbc29b1d5ab68f1378b7bebc5057/pydantic_core-2.33.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:64632ff9d614e5eecfb495796ad51b0ed98c453e447a76bcbeeb69615079fc7e", size = 2108896, upload-time = "2025-04-23T18:33:22.501Z" }, - { url = "https://files.pythonhosted.org/packages/53/89/2b2de6c81fa131f423246a9109d7b2a375e83968ad0800d6e57d0574629b/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:f889f7a40498cc077332c7ab6b4608d296d852182211787d4f3ee377aaae66e8", size = 2069475, upload-time = "2025-04-23T18:33:24.528Z" }, - { url = "https://files.pythonhosted.org/packages/b8/e9/1f7efbe20d0b2b10f6718944b5d8ece9152390904f29a78e68d4e7961159/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:de4b83bb311557e439b9e186f733f6c645b9417c84e2eb8203f3f820a4b988bf", size = 2239013, upload-time = "2025-04-23T18:33:26.621Z" }, - { url = "https://files.pythonhosted.org/packages/3c/b2/5309c905a93811524a49b4e031e9851a6b00ff0fb668794472ea7746b448/pydantic_core-2.33.2-pp311-pypy311_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:82f68293f055f51b51ea42fafc74b6aad03e70e191799430b90c13d643059ebb", size = 2238715, upload-time = "2025-04-23T18:33:28.656Z" }, - { url = "https://files.pythonhosted.org/packages/32/56/8a7ca5d2cd2cda1d245d34b1c9a942920a718082ae8e54e5f3e5a58b7add/pydantic_core-2.33.2-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:329467cecfb529c925cf2bbd4d60d2c509bc2fb52a20c1045bf09bb70971a9c1", size = 2066757, upload-time = "2025-04-23T18:33:30.645Z" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.10.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/68/85/1ea668bbab3c50071ca613c6ab30047fb36ab0da1b92fa8f17bbc38fd36c/pydantic_settings-2.10.1.tar.gz", hash = "sha256:06f0062169818d0f5524420a360d632d5857b83cffd4d42fe29597807a1614ee", size = 172583, upload-time = "2025-06-24T13:26:46.841Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/58/f0/427018098906416f580e3cf1366d3b1abfb408a0652e9f31600c24a1903c/pydantic_settings-2.10.1-py3-none-any.whl", hash = "sha256:a60952460b99cf661dc25c29c0ef171721f98bfcb52ef8d9ea4c943d7c8cc796", size = 45235, upload-time = "2025-06-24T13:26:45.485Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b0/77/a5b8c569bf593b0140bde72ea885a803b82086995367bf2037de0159d924/pygments-2.19.2.tar.gz", hash = "sha256:636cb2477cec7f8952536970bc533bc43743542f70392ae026374600add5b887", size = 4968631, upload-time = "2025-06-21T13:39:12.283Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f6/b0/4bc07ccd3572a2f9df7e6782f52b0c6c90dcbb803ac4a167702d7d0dfe1e/python_dotenv-1.1.1.tar.gz", hash = "sha256:a8a6399716257f45be6a007360200409fce5cda2661e3dec71d23dc15f6189ab", size = 41978, upload-time = "2025-06-24T04:21:07.341Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/5f/ed/539768cf28c661b5b068d66d96a2f155c4971a5d55684a514c1a0e0dec2f/python_dotenv-1.1.1-py3-none-any.whl", hash = "sha256:31f23644fe2602f88ff55e1f5c79ba497e01224ee7737937930c448e4d0e24dc", size = 20556, upload-time = "2025-06-24T04:21:06.073Z" }, -] - -[[package]] -name = "python-multipart" -version = "0.0.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, -] - -[[package]] -name = "pyunormalize" -version = "16.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/08/568036c725dac746ecb267bb749ef930fb7907454fe69fce83c8557287fb/pyunormalize-16.0.0.tar.gz", hash = "sha256:2e1dfbb4a118154ae26f70710426a52a364b926c9191f764601f5a8cb12761f7", size = 49968, upload-time = "2024-09-17T17:08:18.245Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/f9/9d86e56f716e0651194a5ad58be9c146fcaf1de6901ac6f3cd3affeeb74e/pyunormalize-16.0.0-py3-none-any.whl", hash = "sha256:c647d95e5d1e2ea9a2f448d1d95d8518348df24eab5c3fd32d2b5c3300a49152", size = 49173, upload-time = "2024-09-17T17:08:17.078Z" }, -] - -[[package]] -name = "pywin32" -version = "311" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7b/40/44efbb0dfbd33aca6a6483191dae0716070ed99e2ecb0c53683f400a0b4f/pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3", size = 8760432, upload-time = "2025-07-14T20:13:05.9Z" }, - { url = "https://files.pythonhosted.org/packages/5e/bf/360243b1e953bd254a82f12653974be395ba880e7ec23e3731d9f73921cc/pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b", size = 9590103, upload-time = "2025-07-14T20:13:07.698Z" }, - { url = "https://files.pythonhosted.org/packages/57/38/d290720e6f138086fb3d5ffe0b6caa019a791dd57866940c82e4eeaf2012/pywin32-311-cp310-cp310-win_arm64.whl", hash = "sha256:0502d1facf1fed4839a9a51ccbcc63d952cf318f78ffc00a7e78528ac27d7a2b", size = 8778557, upload-time = "2025-07-14T20:13:11.11Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/449a6a91e5d6db51420875c54f6aff7c97a86a3b13a0b4f1a5c13b988de3/pywin32-311-cp311-cp311-win32.whl", hash = "sha256:184eb5e436dea364dcd3d2316d577d625c0351bf237c4e9a5fabbcfa5a58b151", size = 8697031, upload-time = "2025-07-14T20:13:13.266Z" }, - { url = "https://files.pythonhosted.org/packages/51/8f/9bb81dd5bb77d22243d33c8397f09377056d5c687aa6d4042bea7fbf8364/pywin32-311-cp311-cp311-win_amd64.whl", hash = "sha256:3ce80b34b22b17ccbd937a6e78e7225d80c52f5ab9940fe0506a1a16f3dab503", size = 9508308, upload-time = "2025-07-14T20:13:15.147Z" }, - { url = "https://files.pythonhosted.org/packages/44/7b/9c2ab54f74a138c491aba1b1cd0795ba61f144c711daea84a88b63dc0f6c/pywin32-311-cp311-cp311-win_arm64.whl", hash = "sha256:a733f1388e1a842abb67ffa8e7aad0e70ac519e09b0f6a784e65a136ec7cefd2", size = 8703930, upload-time = "2025-07-14T20:13:16.945Z" }, - { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, - { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, - { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, - { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, - { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, - { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, - { url = "https://files.pythonhosted.org/packages/c9/31/097f2e132c4f16d99a22bfb777e0fd88bd8e1c634304e102f313af69ace5/pywin32-311-cp314-cp314-win32.whl", hash = "sha256:b7a2c10b93f8986666d0c803ee19b5990885872a7de910fc460f9b0c2fbf92ee", size = 8840714, upload-time = "2025-07-14T20:13:32.449Z" }, - { url = "https://files.pythonhosted.org/packages/90/4b/07c77d8ba0e01349358082713400435347df8426208171ce297da32c313d/pywin32-311-cp314-cp314-win_amd64.whl", hash = "sha256:3aca44c046bd2ed8c90de9cb8427f581c479e594e99b5c0bb19b29c10fd6cb87", size = 9656800, upload-time = "2025-07-14T20:13:34.312Z" }, - { url = "https://files.pythonhosted.org/packages/c0/d2/21af5c535501a7233e734b8af901574572da66fcc254cb35d0609c9080dd/pywin32-311-cp314-cp314-win_arm64.whl", hash = "sha256:a508e2d9025764a8270f93111a970e1d0fbfc33f4153b388bb649b7eec4f9b42", size = 8932540, upload-time = "2025-07-14T20:13:36.379Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" }, - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, - { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669, upload-time = "2024-11-06T20:09:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684, upload-time = "2024-11-06T20:09:32.915Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589, upload-time = "2024-11-06T20:09:35.504Z" }, - { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121, upload-time = "2024-11-06T20:09:37.701Z" }, - { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275, upload-time = "2024-11-06T20:09:40.371Z" }, - { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257, upload-time = "2024-11-06T20:09:43.059Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727, upload-time = "2024-11-06T20:09:48.19Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667, upload-time = "2024-11-06T20:09:49.828Z" }, - { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963, upload-time = "2024-11-06T20:09:51.819Z" }, - { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700, upload-time = "2024-11-06T20:09:53.982Z" }, - { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592, upload-time = "2024-11-06T20:09:56.222Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929, upload-time = "2024-11-06T20:09:58.642Z" }, - { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213, upload-time = "2024-11-06T20:10:00.867Z" }, - { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734, upload-time = "2024-11-06T20:10:03.361Z" }, - { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052, upload-time = "2024-11-06T20:10:05.179Z" }, - { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, - { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, - { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, - { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, - { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, - { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, - { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, - { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, - { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, - { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, - { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, - { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, - { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, - { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, - { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, - { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, - { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, - { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, - { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, - { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, - { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, - { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, - { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, - { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, -] - -[[package]] -name = "requests" -version = "2.32.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, -] - -[[package]] -name = "rich" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, -] - -[[package]] -name = "rich-toolkit" -version = "0.14.8" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/de/d3d329d670bb271ee82e7bbc2946f985b2782f4cae2857138ed94be1335b/rich_toolkit-0.14.8.tar.gz", hash = "sha256:1f77b32e6c25d9e3644c1efbce00d8d90daf2457b3abdb4699e263c03b9ca6cf", size = 110926, upload-time = "2025-06-30T22:05:53.663Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/39/c0fd75955aa963a15c642dfe6fb2acdd1fd2114028ec5ff2e2fd26218ad7/rich_toolkit-0.14.8-py3-none-any.whl", hash = "sha256:c54bda82b93145a79bbae04c3e15352e6711787c470728ff41fdfa0c2f0c11ae", size = 24975, upload-time = "2025-06-30T22:05:52.153Z" }, -] - -[[package]] -name = "rignore" -version = "0.6.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/37/98/9d939a65c8c55fb3d30bf943918b4b7f0e33c31be4104264e4ebba2408eb/rignore-0.6.2.tar.gz", hash = "sha256:1fef5c83a18cbd2a45e2d568ad15c369e032170231fe7cd95e44e1c80fb65497", size = 11571, upload-time = "2025-07-13T11:59:04.736Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/6f/9cf728233cfd7de35ab173aefe729ea3c1369cc34a79c0b9a1a8cce5ed5a/rignore-0.6.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a87091687678b3537012f26707641386f11b92e78da6a407af39193fd74a1d96", size = 892394, upload-time = "2025-07-13T11:56:10.591Z" }, - { url = "https://files.pythonhosted.org/packages/aa/03/3f7c7ca1489c9bd8891ea989e7973b84251ffd9c0e31ade02743935bc0f0/rignore-0.6.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:2eb003ac18a0269f727ec4ad5d8d5da1ac66a1c75a01f1fbea31b826c89346ee", size = 872766, upload-time = "2025-07-13T11:56:27.463Z" }, - { url = "https://files.pythonhosted.org/packages/9e/4e/391e4d73dce76721b5e159ae354fe16646fdc55e089dee071eaf97461a83/rignore-0.6.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5cf62660a521b0f0b350205964aa20af6dc2d11a9ec694809714a09e005079b3", size = 1160543, upload-time = "2025-07-13T11:56:43.809Z" }, - { url = "https://files.pythonhosted.org/packages/27/4e/db9c4c135a3f2e3e2661f2611900bbf56f97d19a758e96b52a37b33ba033/rignore-0.6.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:48ca296c0dec4a2eff7e38812434f01cdea49339fa09def9b31a8c85f35ffc0f", size = 938670, upload-time = "2025-07-13T11:57:03.289Z" }, - { url = "https://files.pythonhosted.org/packages/8a/c1/dd5b0edc11ca0e401c8124f95ba9d7dd28eb4a056b904c5cb671414d5ae4/rignore-0.6.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c7224bdf715b24cc2166af01b8f1d79ad1af1bca1aa91310e5aa5933b41872", size = 950273, upload-time = "2025-07-13T11:57:34.043Z" }, - { url = "https://files.pythonhosted.org/packages/6b/c7/a6bf70f3427e0c0f0714513cf698d50950c6cc83e16903846320980550e6/rignore-0.6.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:178503a244e0823e9be94f36d42b238c500f44580adc26c17f6b05abc0fbbbb6", size = 976815, upload-time = "2025-07-13T11:57:20.008Z" }, - { url = "https://files.pythonhosted.org/packages/54/ac/f5ba51ba5e13f39c9558472e8f5e52667165e9f7ff27324cfcbc842850ce/rignore-0.6.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:09265fab1b913e636d743602d325d49e4304a36476a9f14727188476fa99f221", size = 1067632, upload-time = "2025-07-13T11:57:59.828Z" }, - { url = "https://files.pythonhosted.org/packages/39/6e/ae7ad5d4f8113fcad7e7796f437989702b26044cc866185b578231ac8444/rignore-0.6.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:24fa6a3f85b97b81f122fd744dfbbff8c05b35b4bf968a77374f4e9123463e7d", size = 1136305, upload-time = "2025-07-13T11:58:16.259Z" }, - { url = "https://files.pythonhosted.org/packages/41/4c/b1c9cfbe90f40a635313faa65fa35f441edc6b77a1a88374c4e05eedff05/rignore-0.6.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:7306cec150c8942507a540fa8ff417962e8aaf327135929be8270a33b645f218", size = 1111169, upload-time = "2025-07-13T11:58:32.657Z" }, - { url = "https://files.pythonhosted.org/packages/25/ef/e5627f436d33d1a046f2044e3b8042c14f69bae326615073762dd168c89c/rignore-0.6.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:84f24acef49f61289c4ac51fbdb418bc394e54267b86723bd5802d2bd388bf05", size = 1121047, upload-time = "2025-07-13T11:58:48.245Z" }, - { url = "https://files.pythonhosted.org/packages/a0/b7/3beeb4c5436aef9a9faee4f71d024bad9e44b2f51e87a211157fbb9d04eb/rignore-0.6.2-cp310-cp310-win32.whl", hash = "sha256:2fe22933bd498ec6bd16a9bdfd9fe42004b5b40d36b9dd0ff3bb45000a0a0761", size = 643126, upload-time = "2025-07-13T11:59:14.995Z" }, - { url = "https://files.pythonhosted.org/packages/53/7d/03745abcf3eb1696107095f5711279503638b8962212e4ee8d9fbdb3a9aa/rignore-0.6.2-cp310-cp310-win_amd64.whl", hash = "sha256:d91e1458c0c8142fc07ba1901d26c4413a4d0aa6f152eefd0dcab15e1a699c84", size = 721170, upload-time = "2025-07-13T11:59:05.792Z" }, - { url = "https://files.pythonhosted.org/packages/4e/db/8a9226283e65d7855699a365000aadeecc2a02b5c5bbc4551e76d244abfe/rignore-0.6.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:20da9a861a95ef82beebfbc9201896bb04f66ba0d4a52d65b956037c70a60590", size = 884512, upload-time = "2025-07-13T11:57:53.811Z" }, - { url = "https://files.pythonhosted.org/packages/3a/df/a3611ee0bf6d3906bfd16102c5996842f471fe88ed95ba7c2c1da1154704/rignore-0.6.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bd03d343ec059258269aaa6b4c51aab878e2b2ff92bf62269010d2f7bd584ab4", size = 824500, upload-time = "2025-07-13T11:57:47.991Z" }, - { url = "https://files.pythonhosted.org/packages/5c/36/e77b3b35977619b668f12eced8b083af9b7519f8656589b1a52a4142d307/rignore-0.6.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:29e7382c053eb62b916699ce6e4ccff335ecbcf14ce4c9d8786c096c236dd42d", size = 892500, upload-time = "2025-07-13T11:56:12.623Z" }, - { url = "https://files.pythonhosted.org/packages/5d/a0/cb1be880406187844db5d7b7f15058bab21615743820ae3e54bc5d97cf65/rignore-0.6.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a16c32b1845d41e4c39350c3392ed389053efd40659026e3aad927339e6cfb2c", size = 873198, upload-time = "2025-07-13T11:56:28.948Z" }, - { url = "https://files.pythonhosted.org/packages/e9/db/6dc8066c42940feffd1a91ee78de4270fe3dbd2758f33df1e78457807210/rignore-0.6.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8341122d2453867e793cd350412734f7d34d9ab4c6ce23062ea38450db46d758", size = 1160510, upload-time = "2025-07-13T11:56:46.263Z" }, - { url = "https://files.pythonhosted.org/packages/69/60/112a8983ce33e64c1bb204308298f8d818340af3c7f3cb50716de633d00c/rignore-0.6.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d286840b255f750b3abe5ecb265b9dab93f18a002da4f500d8b0088b01ab9140", size = 938767, upload-time = "2025-07-13T11:57:05.06Z" }, - { url = "https://files.pythonhosted.org/packages/71/98/b1cf5ecbdabc0bf697b2605bf2fc78d628171a00ce78b6136e2f2f8f4352/rignore-0.6.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:177c5ed48128a33d74c0c77bcf2d57e764ef1005f9ada63637b04075a9c75045", size = 950540, upload-time = "2025-07-13T11:57:35.61Z" }, - { url = "https://files.pythonhosted.org/packages/50/04/655a13e7eab74b14d507cab93c40ac445072cdcead7cb12d63260cd1b5de/rignore-0.6.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cb46444e2ed3cf340979967c6f83ebe3782d7e8882accb5cf0ef63d26c339c2a", size = 976778, upload-time = "2025-07-13T11:57:21.793Z" }, - { url = "https://files.pythonhosted.org/packages/83/18/b7274d1967c7b33030b111a60b433fc621fa5c0556a837c0a2b78ee7a454/rignore-0.6.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:1300c1b0827bb9bc0b343a9e4a42b73dfd2c2ded010b30ba13807f746e3e6f51", size = 1067741, upload-time = "2025-07-13T11:58:01.645Z" }, - { url = "https://files.pythonhosted.org/packages/99/f9/d11122ea9683d40df0d991dbd7cf06c66e1eb4d1cd476e752f67fb92981c/rignore-0.6.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:5dd7bce7f1feba0d828e34f63f5ab12b3f410590c0a55e3eec8658fa64cd7378", size = 1136495, upload-time = "2025-07-13T11:58:17.841Z" }, - { url = "https://files.pythonhosted.org/packages/1b/90/38bc08017a926b382713389c737597cb9e3368135d9ab165bf01e190662f/rignore-0.6.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:b0d7ace3b10d87a742e5665501c55978a593b6e0d510f6b53acc6b595923218a", size = 1111537, upload-time = "2025-07-13T11:58:34.177Z" }, - { url = "https://files.pythonhosted.org/packages/2d/ee/02e9708ed34b1a36bffb11259ed0e93c7742060f82a89c19ef2c372eacb7/rignore-0.6.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:aaf91280106c0c696148eeab83b1744caae7372d1f55570f82a6b7e480367b5e", size = 1121112, upload-time = "2025-07-13T11:58:49.757Z" }, - { url = "https://files.pythonhosted.org/packages/ae/e9/f2cd38032016a429ddd0befb029c67a9f05a502d2c460ec3ce9047b2d959/rignore-0.6.2-cp311-cp311-win32.whl", hash = "sha256:5dfee0390640d1b70c672e93e09a909088afd0f030098e46609e2ed6c72f735b", size = 643026, upload-time = "2025-07-13T11:59:16.468Z" }, - { url = "https://files.pythonhosted.org/packages/fc/b2/5d5869bdd429e78afc2097c9df9f325ae9b1220b14ee0a78eac213062b07/rignore-0.6.2-cp311-cp311-win_amd64.whl", hash = "sha256:b56afc3ad3114e7f6e592c2aef75a40548073c086e96a2686423e0f038113027", size = 721065, upload-time = "2025-07-13T11:59:07.289Z" }, - { url = "https://files.pythonhosted.org/packages/85/bb/44c4d112caf1cebc4da628806291b19afb89d9e4e293522150d1be448b4a/rignore-0.6.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d71f5e48aa1e16a0d56d76ffac93831918c84539d59ee0949f903e8eef97c7ba", size = 882080, upload-time = "2025-07-13T11:57:55.403Z" }, - { url = "https://files.pythonhosted.org/packages/80/5e/e16fbe1e933512aa311b6bb9bc440f337d01de30105ba42b4730c54df475/rignore-0.6.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:9ed1bfad40929b0922c127d4b812428b9283a3bb515b143c39ddb8e123caf764", size = 819794, upload-time = "2025-07-13T11:57:49.465Z" }, - { url = "https://files.pythonhosted.org/packages/9c/f0/9dee360523f6f0fd16c6b2a151b451af75e1d6dc0be31c41c37eec74d39c/rignore-0.6.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dd1ef10e348903209183cfa9639c78fcf48f3b97ec76f26df1f66d9e237aafa8", size = 892826, upload-time = "2025-07-13T11:56:14.073Z" }, - { url = "https://files.pythonhosted.org/packages/33/57/11dc610aecc309210aca8f10672b0959d29641b1e3f190b6e091dd824649/rignore-0.6.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:e91146dc5c3f04d57e8cda8fb72b132ee9b58402ecfd1387108f7b5c498b9584", size = 872167, upload-time = "2025-07-13T11:56:30.721Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ca/4f8be05539565a261dfcad655ba23a1cff34e72913bf73ff25f04e67f4a0/rignore-0.6.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8e9230cd680325fa5a37bb482ce4e6f019856ee63c46b88272bb3f246e2b83f8", size = 1163045, upload-time = "2025-07-13T11:56:47.932Z" }, - { url = "https://files.pythonhosted.org/packages/91/0e/aa3bd71f0dca646c0f47bd6d80f42f674626da50eabb02f4ab20b5f41bfc/rignore-0.6.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1e5defb13c328c7e7ccebc8f0179eb5d6306acef1339caa5f17785c1272e29da", size = 939842, upload-time = "2025-07-13T11:57:06.58Z" }, - { url = "https://files.pythonhosted.org/packages/f4/f1/ee885fe9df008ca7f554d0b28c0d8f8ab70878adfc9737acf968aa95dd04/rignore-0.6.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c269f543e922010e08ff48eaa0ff7dbf13f9f005f5f0e7a9a17afdac2d8c0e8", size = 949676, upload-time = "2025-07-13T11:57:37.059Z" }, - { url = "https://files.pythonhosted.org/packages/11/1a/90fda83d7592fe3daaa307af96ccd93243d2c4a05670b7d7bcc4f091487f/rignore-0.6.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:71042fdbd57255c82b2b4070b7fac8f6a78cbc9f27d3a74523d2966e8619d661", size = 975553, upload-time = "2025-07-13T11:57:23.331Z" }, - { url = "https://files.pythonhosted.org/packages/59/75/8cd5bf4d4c3c1b0f98450915e56a84fb1d2e8060827d9f2662ac78224803/rignore-0.6.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:83fc16b20b67d09f3e958b2b1c1fa51fedc9e177c398227b32799cb365fd6fe9", size = 1067778, upload-time = "2025-07-13T11:58:03.174Z" }, - { url = "https://files.pythonhosted.org/packages/20/c3/4f3cd443438c96c019288d61aa6b6babd5ba01c194d9c7ea14b06819b890/rignore-0.6.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:3b2a8c5e22ba99bc995db4337b4c2f3422696ffb61d17fffc2bad3bb3d0ca3c4", size = 1135015, upload-time = "2025-07-13T11:58:19.532Z" }, - { url = "https://files.pythonhosted.org/packages/68/34/418cd1a7e661a145bd02ddd24ed6dc54fc4decb2d3f40a8cda2b833b8950/rignore-0.6.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b5c1955b697c7f8f3ab156bae43197b7f85f993dc6865842b36fd7d7f32b1626", size = 1109724, upload-time = "2025-07-13T11:58:35.671Z" }, - { url = "https://files.pythonhosted.org/packages/17/30/1c8dfd945eeb92278598147d414da2cedfb479565ed09d4ddf688154ec6a/rignore-0.6.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:9280867b233076afbe467a8626f4cbf688549ef16d3a8661bd59991994b4c7ad", size = 1120559, upload-time = "2025-07-13T11:58:52.198Z" }, - { url = "https://files.pythonhosted.org/packages/a5/3f/89ffe5e29a71d6b899c3eef208c0ea2935a01ebe420bd9b102df2e42418a/rignore-0.6.2-cp312-cp312-win32.whl", hash = "sha256:68926e2467f595272214e568e93b187362d455839e5e0368934125bc9a2fab60", size = 642006, upload-time = "2025-07-13T11:59:18.433Z" }, - { url = "https://files.pythonhosted.org/packages/b6/27/aa0e4635bff0591ae99aba33d9dc95fae49bb3527a3e2ddf61a059f2eee1/rignore-0.6.2-cp312-cp312-win_amd64.whl", hash = "sha256:170d32f6a6bc628c0e8bc53daf95743537a90a90ccd58d28738928846ac0c99a", size = 720418, upload-time = "2025-07-13T11:59:08.8Z" }, - { url = "https://files.pythonhosted.org/packages/8c/d7/36c8e59bd3b7c6769c54311783844d48d4d873ff86b8c0fb1aae19eb2b02/rignore-0.6.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:b50d5221ca6f869d7622c228988609b6f82ce9e0368de23bbef67ea23b0000e2", size = 881681, upload-time = "2025-07-13T11:57:56.808Z" }, - { url = "https://files.pythonhosted.org/packages/9d/d1/6ede112d08e4cfa0923ee8aa756b00c2b8659e303839c4c0b1c8010eed32/rignore-0.6.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:9f9d7e302e36a2fe9188c4e5553b66cf814a0ba416dbe2f824962eda0ff92e90", size = 818804, upload-time = "2025-07-13T11:57:50.97Z" }, - { url = "https://files.pythonhosted.org/packages/eb/03/2d94e789336d9d50b5d93b762c0a9b64ba933f2089b57d1bd8feaefba24e/rignore-0.6.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38c5bdd8bb1900ff529fbefa1e2ca3eeb669a2fafc5a81be8213fd028182d2cf", size = 892050, upload-time = "2025-07-13T11:56:15.529Z" }, - { url = "https://files.pythonhosted.org/packages/3f/3f/480f87aaab0b2a562bc8fd7f397f07c81cc738a27f832372a2b6edbf401b/rignore-0.6.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:819963993c25d26474a807d615d07ca4d61ca5876dbb4c058cc0adb09bf3a363", size = 871512, upload-time = "2025-07-13T11:56:32.496Z" }, - { url = "https://files.pythonhosted.org/packages/1e/08/eb3c06fa08f59f4a299c127625c1217ce6cc24a002ccec8601db7f4fc73f/rignore-0.6.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:6c7af68bf559f5b0ab8c575b0097db7fbf58558581d5e5f44dba27fcae388149", size = 1160450, upload-time = "2025-07-13T11:56:49.846Z" }, - { url = "https://files.pythonhosted.org/packages/44/23/f5efe41d66d709d62166f53160aa102a035c65f8e709343ed8fdddcad9c1/rignore-0.6.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0fbbfdd5efed90757112c8b2587a57868882858e94311a57b08bbc24482eb966", size = 939887, upload-time = "2025-07-13T11:57:08.76Z" }, - { url = "https://files.pythonhosted.org/packages/3f/c7/3fd260203cd93da4d299f7469e45a0352c982d9f44612fc8ae4e73575d4d/rignore-0.6.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8cecfc7e406fdbbc0850dd8592e30f3fbb5f0ce485f7502ecb6ce432ad0af34", size = 949405, upload-time = "2025-07-13T11:57:38.526Z" }, - { url = "https://files.pythonhosted.org/packages/12/49/c3bc1831bdeb7a4f87468c55a0c07310bb584ae89f0ef2747d5e4206c628/rignore-0.6.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:3165f07a8e95bbda8203d30105754b68c30002d00cc970fbe78a588957b787b7", size = 974881, upload-time = "2025-07-13T11:57:25.127Z" }, - { url = "https://files.pythonhosted.org/packages/57/90/f3e58a2eb13a09b90fed46e0fe05c5806c140e60204f6bc13518f78f8e95/rignore-0.6.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:3b2eb202a83ac6ca8eedc6aab17c76fd593ffa26fd3e3a3b8055f54f0d6254cf", size = 1067258, upload-time = "2025-07-13T11:58:05.001Z" }, - { url = "https://files.pythonhosted.org/packages/db/55/548a57ce3af206755a958d4e4d90b3231851ff8377e303e5788d7911ea4c/rignore-0.6.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:3e639fe26d5457daaa7621bd67ad78035e4ca7af50a7c75dbd020b1f05661854", size = 1134442, upload-time = "2025-07-13T11:58:21.336Z" }, - { url = "https://files.pythonhosted.org/packages/a0/da/a076acd8751c3509c22911e6593f7c0b4e68f3e5631f004261ec091d42b1/rignore-0.6.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:fe3887178401c48452984ea540a7984cb0db8dc0bca03f8dd86e2c90fa4c8e97", size = 1109430, upload-time = "2025-07-13T11:58:37.187Z" }, - { url = "https://files.pythonhosted.org/packages/b6/3a/720acc1fe2e2e130bc01368918700468f426f2d765d9ec906297a8988124/rignore-0.6.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:17b15e6485b11dbba809836cca000fbaa6dd37305bbd35ef8b2d100f35fdb889", size = 1120420, upload-time = "2025-07-13T11:58:54.075Z" }, - { url = "https://files.pythonhosted.org/packages/93/e2/34d6e7971f18eabad4126fb7db67f44f1310f6ad3483d41882e88a7bd9cb/rignore-0.6.2-cp313-cp313-win32.whl", hash = "sha256:0b1e5e1606659a7d448d78a199b11eec4d8088379fea43536bcdf869fd629389", size = 641762, upload-time = "2025-07-13T11:59:19.884Z" }, - { url = "https://files.pythonhosted.org/packages/29/c2/90de756508239d6083cc995e96461c2e4d5174cc28c28b4e9bbbe472b6b3/rignore-0.6.2-cp313-cp313-win_amd64.whl", hash = "sha256:2f454ebd5ce3a4c5454b78ff8df26ed7b9e9e7fca9d691bbcd8e8b5a09c2d386", size = 719962, upload-time = "2025-07-13T11:59:10.293Z" }, - { url = "https://files.pythonhosted.org/packages/ca/49/18de14dd2ef7fcf47da8391a0436917ac0567f5cddaebae5dd7fd46a3f48/rignore-0.6.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:235972ac52d0e38be4bd81c5d4e07459af99ae2713ff5c6f7ec7593c18c7ef67", size = 891874, upload-time = "2025-07-13T11:56:16.949Z" }, - { url = "https://files.pythonhosted.org/packages/b8/a3/f9c2eab4ead9de0afa1285c3b633a9343bc120e5a43c30890e18d6ece7c4/rignore-0.6.2-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:763a1cac91430bad7c2ccaf6b032966448bbb44457a1915e7ad4765209928437", size = 871247, upload-time = "2025-07-13T11:56:34.529Z" }, - { url = "https://files.pythonhosted.org/packages/ae/ca/1607cc33f4dd1ddf46961210626ff504d57fb6cc12312ee6d1fa51abecb4/rignore-0.6.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c345a1ec8f508db7d6918961318382a26bca68d315f2e71c7a93be4182eaa82c", size = 1159842, upload-time = "2025-07-13T11:56:51.745Z" }, - { url = "https://files.pythonhosted.org/packages/d9/17/8431efab1fad268a7033f65decbdc538db4547e0b0a32fb712725bbbd74c/rignore-0.6.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d47b76d30e434052dbc54e408eb73341c7e702af78086e0f676f8afdcff9dc8", size = 939650, upload-time = "2025-07-13T11:57:10.307Z" }, - { url = "https://files.pythonhosted.org/packages/45/1e/4054303710ab30d85db903ff4acd7b8a220792ac2cbbf13e0ee27f4b1f5d/rignore-0.6.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:206f1753fa0b2921fcba36eba8d280242e088b010b5263def8856c29d3eeef34", size = 1066954, upload-time = "2025-07-13T11:58:06.653Z" }, - { url = "https://files.pythonhosted.org/packages/d5/d9/855f14b297b696827e7343bf17bd549162feb8d4621f901f4a9f7eff5e3a/rignore-0.6.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:8949da2148e1eb729a8ebc7725507a58a8bb0d0191eb7429c4cea2557945cfdd", size = 1134708, upload-time = "2025-07-13T11:58:23.51Z" }, - { url = "https://files.pythonhosted.org/packages/60/d9/be69de492b9508cb8824092d4df99c1fca2eada13ae22f20ba905c0c005e/rignore-0.6.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:fd8dd54b0d0decace1d154d29fc09e7069b7c1d92c250fc3ca8ec1a148b26ab5", size = 1108921, upload-time = "2025-07-13T11:58:38.727Z" }, - { url = "https://files.pythonhosted.org/packages/9c/4d/73afcb6efb0448fa28cf285714e84b06ee4670f0f10bdd0de3a73722894b/rignore-0.6.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:c7907763174c43b38525a490e2f9bc2b01534214e8af38f7737903e8fa195574", size = 1120238, upload-time = "2025-07-13T11:58:55.584Z" }, - { url = "https://files.pythonhosted.org/packages/eb/87/7f362fc0d19c57a124f7b41fa043cb9761a4eb41076b392e8c68568a9b84/rignore-0.6.2-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0c27e1e93ece4296a593ff44d4200acf1b8212e13f0d2c3f4e1ac81e790015fd", size = 949673, upload-time = "2025-07-13T11:57:40.001Z" }, - { url = "https://files.pythonhosted.org/packages/1d/9f/0f13511b27c3548372d9679637f1120e690370baf6ed890755eb73d9387b/rignore-0.6.2-cp314-cp314-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d2252d603550d529362c569b10401ab32536613517e7e1df0e4477fe65498245", size = 974567, upload-time = "2025-07-13T11:57:26.592Z" }, - { url = "https://files.pythonhosted.org/packages/6a/d2/dd66db542be2a396ea09829895614d14ed6ac7c4768881e6a601f709f5bb/rignore-0.6.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7d434f4c114ca1c8fa1ae52e4ee9f5db525c76d8d6516e35f27e3e7aca60117a", size = 895229, upload-time = "2025-07-13T11:56:22.522Z" }, - { url = "https://files.pythonhosted.org/packages/cf/a6/f220b1331d7d18bc94bd35169e00597af1ba9d2e05d72c977e5b332dbac4/rignore-0.6.2-pp310-pypy310_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:701f84035b2b9a42727a240118eedb9bdeebe5a887aa823587f5f9881cad1e7f", size = 872901, upload-time = "2025-07-13T11:56:39.107Z" }, - { url = "https://files.pythonhosted.org/packages/df/96/5dfe551f85f303f6ad838ae14fce4346db6591354ac6c201156c655c2124/rignore-0.6.2-pp310-pypy310_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:150e8d29ec2c9e3eb9c5fe92ec4e4d1f5c048ad3ae497f7aa62b63adde88ba6f", size = 1161956, upload-time = "2025-07-13T11:56:57.87Z" }, - { url = "https://files.pythonhosted.org/packages/ae/48/9a6aae123b173c475087c43c1d16cd1e6e185bdcdd217c372787cedbe1b6/rignore-0.6.2-pp310-pypy310_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f896d3a44cb395c89317d4920a1af459f63d2c467edd5d46461446647850454e", size = 940593, upload-time = "2025-07-13T11:57:15.305Z" }, - { url = "https://files.pythonhosted.org/packages/74/9a/a467b8b6dd251e149675f7280968802d3905ca29ef4ac2efd5911430f77d/rignore-0.6.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:679ea98f5796579fadc32542f7a345c0bb22bc872d8d3f3901999c344037cf2f", size = 951810, upload-time = "2025-07-13T11:57:44.973Z" }, - { url = "https://files.pythonhosted.org/packages/b3/9f/29fb3836dd936a34cb5b56a766bcb85839b96c8c06795fce0faa2f812467/rignore-0.6.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:285816d7f469dd0e240fd1897de41ec6bad6a30a768d81422c85613ef367addc", size = 976506, upload-time = "2025-07-13T11:57:31.017Z" }, - { url = "https://files.pythonhosted.org/packages/15/a8/f43b4944e31ff525f0017b36234dff98805c58387515c7df7e37f32fc355/rignore-0.6.2-pp310-pypy310_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:a73660be1dd5eba7f6be8ad4f6726d429d438e2f15edbd30e1e2ee2fdd674630", size = 1069905, upload-time = "2025-07-13T11:58:11.229Z" }, - { url = "https://files.pythonhosted.org/packages/dc/a6/9a7d3c267c2e0edb7fa946766545376423640688a1bb218e7ff4efbfc8e0/rignore-0.6.2-pp310-pypy310_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:3a3c532cedb25114022582465d66958dd8c793e96e17677b8660dcfe8239e1d6", size = 1136259, upload-time = "2025-07-13T11:58:28.011Z" }, - { url = "https://files.pythonhosted.org/packages/c5/aa/b446e4d88682aa3d535460161fc8aae3812dd528742991bf3d86a948debc/rignore-0.6.2-pp310-pypy310_pp73-musllinux_1_2_i686.whl", hash = "sha256:bd26826ea6077101f7f25c2968fce20d3c8a01a7a18665ced682ce89e64c68ed", size = 1111869, upload-time = "2025-07-13T11:58:43.507Z" }, - { url = "https://files.pythonhosted.org/packages/60/b2/d8aff59c6edcc9865571580c91483ee6c331773994486770293cd7014703/rignore-0.6.2-pp310-pypy310_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:2071f1b70b348a25195149c5e2c09486649b4127390c54349272668a7d895314", size = 1122783, upload-time = "2025-07-13T11:59:00.489Z" }, - { url = "https://files.pythonhosted.org/packages/96/ff/bad5a49b7825d144bcb0449f43a405d06e88017f2471f12670594deeb0b4/rignore-0.6.2-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ee1cb4eb60624a8b4cf3931b907de184a0ef963b2d76e7eb2a63fdd177fbf368", size = 895673, upload-time = "2025-07-13T11:56:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/42/a2/318afda713dd94bf2b47ebe91ceec555e0ef432818c0d4832f6272fc2658/rignore-0.6.2-pp311-pypy311_pp73-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:912319d741069fc371bb334f43bb541fa9dd825296956279d1b3544097945fc6", size = 872906, upload-time = "2025-07-13T11:56:40.503Z" }, - { url = "https://files.pythonhosted.org/packages/ad/7e/ee6cc7247b5a454d67fcfbd208f1505614a8e98c9e150db594891d36f34f/rignore-0.6.2-pp311-pypy311_pp73-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:618c3b01398b293320e401ce3eb70f9f191262a93d6414258e73e5e059efee3c", size = 1162146, upload-time = "2025-07-13T11:56:59.466Z" }, - { url = "https://files.pythonhosted.org/packages/b9/f5/70fe4059f7f9dd7f21a56953ab30f3e9ca89c3b1d64f7e1172cee1981e03/rignore-0.6.2-pp311-pypy311_pp73-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ca6d5016b0862848d2bd1b2491ba50b2ded0e578d0c7faea6bb475831d6a076b", size = 940333, upload-time = "2025-07-13T11:57:17.066Z" }, - { url = "https://files.pythonhosted.org/packages/9b/14/265a0a7c51a33f2c3bd61559c1cbf3061fc34a2b7fa437ecaab35afceb11/rignore-0.6.2-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbc82beee24d5fc82ca3872461da3d2ceb371acbf2b154da87db82995d18c613", size = 951537, upload-time = "2025-07-13T11:57:46.441Z" }, - { url = "https://files.pythonhosted.org/packages/30/34/7fd0a9100bc005b11b1dcee01e6738c0c35478b51639ef6d33af885776a6/rignore-0.6.2-pp311-pypy311_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5a91270cd3506129fb22a60f88c177dc185f49c07cf65de57515be5851ae53b8", size = 976880, upload-time = "2025-07-13T11:57:32.495Z" }, - { url = "https://files.pythonhosted.org/packages/82/fe/c394efe043a17c91e1a3667e72f206ee24fac4afe3d879731927d009cdec/rignore-0.6.2-pp311-pypy311_pp73-musllinux_1_2_aarch64.whl", hash = "sha256:1e314f9e95ff9a6b303591c4d5307c7f9267cee28be88d83e2f76e0acf3c4288", size = 1069845, upload-time = "2025-07-13T11:58:13.085Z" }, - { url = "https://files.pythonhosted.org/packages/a5/a9/15421a3448053e236a5f82deaab40d09612fda09bd1d225ecb511b6ac802/rignore-0.6.2-pp311-pypy311_pp73-musllinux_1_2_armv7l.whl", hash = "sha256:973794e2379b7b7bdb57d0862e5b49224d393bb6cc27455f423c768c8e84e2aa", size = 1136238, upload-time = "2025-07-13T11:58:29.552Z" }, - { url = "https://files.pythonhosted.org/packages/f2/33/b4cfe5d4cb40bf9abfbea410c15e61df3994cc2013d2047f2e6f63014cfa/rignore-0.6.2-pp311-pypy311_pp73-musllinux_1_2_i686.whl", hash = "sha256:8c362ff5067fb999e850be1db98a54b35791cea7aa2a037f7f9540383c617156", size = 1111857, upload-time = "2025-07-13T11:58:45.061Z" }, - { url = "https://files.pythonhosted.org/packages/3d/ab/f8db4231df14dcb7c8a3d6e28a9ea655a5016566f12ff64312f5f59b278c/rignore-0.6.2-pp311-pypy311_pp73-musllinux_1_2_x86_64.whl", hash = "sha256:5c4ccfa785284e1be08e58f77445c6a98b2ec6bce87031dd091ee03c4b9e31c6", size = 1122509, upload-time = "2025-07-13T11:59:01.981Z" }, -] - -[[package]] -name = "rlp" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/2d/439b0728a92964a04d9c88ea1ca9ebb128893fbbd5834faa31f987f2fd4c/rlp-4.1.0.tar.gz", hash = "sha256:be07564270a96f3e225e2c107db263de96b5bc1f27722d2855bd3459a08e95a9", size = 33429, upload-time = "2025-02-04T22:05:59.089Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/fb/e4c0ced9893b84ac95b7181d69a9786ce5879aeb3bbbcbba80a164f85d6a/rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f", size = 19973, upload-time = "2025-02-04T22:05:57.05Z" }, -] - -[[package]] -name = "sentry-sdk" -version = "2.32.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/10/59/eb90c45cb836cf8bec973bba10230ddad1c55e2b2e9ffa9d7d7368948358/sentry_sdk-2.32.0.tar.gz", hash = "sha256:9016c75d9316b0f6921ac14c8cd4fb938f26002430ac5be9945ab280f78bec6b", size = 334932, upload-time = "2025-06-27T08:10:02.89Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/01/a1/fc4856bd02d2097324fb7ce05b3021fb850f864b83ca765f6e37e92ff8ca/sentry_sdk-2.32.0-py2.py3-none-any.whl", hash = "sha256:6cf51521b099562d7ce3606da928c473643abe99b00ce4cb5626ea735f4ec345", size = 356122, upload-time = "2025-06-27T08:10:01.424Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "starlette" -version = "0.47.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0a/69/662169fdb92fb96ec3eaee218cf540a629d629c86d7993d9651226a6789b/starlette-0.47.1.tar.gz", hash = "sha256:aef012dd2b6be325ffa16698f9dc533614fb1cebd593a906b90dc1025529a79b", size = 2583072, upload-time = "2025-06-21T04:03:17.337Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/82/95/38ef0cd7fa11eaba6a99b3c4f5ac948d8bc6ff199aabd327a29cc000840c/starlette-0.47.1-py3-none-any.whl", hash = "sha256:5e11c9f5c7c3f24959edbf2dffdc01bba860228acf657129467d8a7468591527", size = 72747, upload-time = "2025-06-21T04:03:15.705Z" }, -] - -[[package]] -name = "toolz" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790, upload-time = "2024-10-04T16:17:04.001Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383, upload-time = "2024-10-04T16:17:01.533Z" }, -] - -[[package]] -name = "typer" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, -] - -[[package]] -name = "types-requests" -version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/7f/73b3a04a53b0fd2a911d4ec517940ecd6600630b559e4505cc7b68beb5a0/types_requests-2.32.4.20250611.tar.gz", hash = "sha256:741c8777ed6425830bf51e54d6abe245f79b4dcb9019f1622b773463946bf826", size = 23118, upload-time = "2025-06-11T03:11:41.272Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/ea/0be9258c5a4fa1ba2300111aa5a0767ee6d18eb3fd20e91616c12082284d/types_requests-2.32.4.20250611-py3-none-any.whl", hash = "sha256:ad2fe5d3b0cb3c2c902c8815a70e7fb2302c4b8c1f77bdcd738192cdb3878072", size = 20643, upload-time = "2025-06-11T03:11:40.186Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.14.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/98/5a/da40306b885cc8c09109dc2e1abd358d5684b1425678151cdaed4731c822/typing_extensions-4.14.1.tar.gz", hash = "sha256:38b39f4aeeab64884ce9f74c94263ef78f3c22467c8724005483154c26648d36", size = 107673, upload-time = "2025-07-04T13:28:34.16Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b5/00/d631e67a838026495268c2f6884f3711a15a9a2a96cd244fdaea53b823fb/typing_extensions-4.14.1-py3-none-any.whl", hash = "sha256:d1e1e3b58374dc93031d6eda2420a48ea44a36c2b4766a4fdeb3710755731d76", size = 43906, upload-time = "2025-07-04T13:28:32.743Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, -] - -[[package]] -name = "urllib3" -version = "2.5.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/15/22/9ee70a2574a4f4599c47dd506532914ce044817c7752a79b6a51286319bc/urllib3-2.5.0.tar.gz", hash = "sha256:3fc47733c7e419d4bc3f6b3dc2b4f890bb743906a30d56ba4a5bfa4bbff92760", size = 393185, upload-time = "2025-06-18T14:07:41.644Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a7/c2/fe1e52489ae3122415c51f387e221dd0773709bad6c6cdaa599e8a2c5185/urllib3-2.5.0-py3-none-any.whl", hash = "sha256:e6b01673c0fa6a13e374b50871808eb3bf7046c4b125b216f6bf1cc604cff0dc", size = 129795, upload-time = "2025-06-18T14:07:40.39Z" }, -] - -[[package]] -name = "uvicorn" -version = "0.35.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5e/42/e0e305207bb88c6b8d3061399c6a961ffe5fbb7e2aa63c9234df7259e9cd/uvicorn-0.35.0.tar.gz", hash = "sha256:bc662f087f7cf2ce11a1d7fd70b90c9f98ef2e2831556dd078d131b96cc94a01", size = 78473, upload-time = "2025-06-28T16:15:46.058Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d2/e2/dc81b1bd1dcfe91735810265e9d26bc8ec5da45b4c0f6237e286819194c3/uvicorn-0.35.0-py3-none-any.whl", hash = "sha256:197535216b25ff9b785e29a0b79199f55222193d47f820816e7da751e9bc8d4a", size = 66406, upload-time = "2025-06-28T16:15:44.816Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, - { url = "https://files.pythonhosted.org/packages/35/5a/62d5800358a78cc25c8a6c72ef8b10851bdb8cca22e14d9c74167b7f86da/uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d", size = 801898, upload-time = "2024-10-14T23:37:22.663Z" }, - { url = "https://files.pythonhosted.org/packages/f3/96/63695e0ebd7da6c741ccd4489b5947394435e198a1382349c17b1146bb97/uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26", size = 3827735, upload-time = "2024-10-14T23:37:25.129Z" }, - { url = "https://files.pythonhosted.org/packages/61/e0/f0f8ec84979068ffae132c58c79af1de9cceeb664076beea86d941af1a30/uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb", size = 3825126, upload-time = "2024-10-14T23:37:27.59Z" }, - { url = "https://files.pythonhosted.org/packages/bf/fe/5e94a977d058a54a19df95f12f7161ab6e323ad49f4dabc28822eb2df7ea/uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f", size = 3705789, upload-time = "2024-10-14T23:37:29.385Z" }, - { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523, upload-time = "2024-10-14T23:37:32.048Z" }, - { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410, upload-time = "2024-10-14T23:37:33.612Z" }, - { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476, upload-time = "2024-10-14T23:37:36.11Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855, upload-time = "2024-10-14T23:37:37.683Z" }, - { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185, upload-time = "2024-10-14T23:37:40.226Z" }, - { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256, upload-time = "2024-10-14T23:37:42.839Z" }, - { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323, upload-time = "2024-10-14T23:37:45.337Z" }, - { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284, upload-time = "2024-10-14T23:37:47.833Z" }, - { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349, upload-time = "2024-10-14T23:37:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089, upload-time = "2024-10-14T23:37:51.703Z" }, - { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770, upload-time = "2024-10-14T23:37:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321, upload-time = "2024-10-14T23:37:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022, upload-time = "2024-10-14T23:37:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" }, - { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" }, - { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" }, - { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" }, - { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" }, - { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" }, -] - -[[package]] -name = "watchfiles" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/2a/9a/d451fcc97d029f5812e898fd30a53fd8c15c7bbd058fd75cfc6beb9bd761/watchfiles-1.1.0.tar.gz", hash = "sha256:693ed7ec72cbfcee399e92c895362b6e66d63dac6b91e2c11ae03d10d503e575", size = 94406, upload-time = "2025-06-15T19:06:59.42Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b9/dd/579d1dc57f0f895426a1211c4ef3b0cb37eb9e642bb04bdcd962b5df206a/watchfiles-1.1.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:27f30e14aa1c1e91cb653f03a63445739919aef84c8d2517997a83155e7a2fcc", size = 405757, upload-time = "2025-06-15T19:04:51.058Z" }, - { url = "https://files.pythonhosted.org/packages/1c/a0/7a0318cd874393344d48c34d53b3dd419466adf59a29ba5b51c88dd18b86/watchfiles-1.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3366f56c272232860ab45c77c3ca7b74ee819c8e1f6f35a7125556b198bbc6df", size = 397511, upload-time = "2025-06-15T19:04:52.79Z" }, - { url = "https://files.pythonhosted.org/packages/06/be/503514656d0555ec2195f60d810eca29b938772e9bfb112d5cd5ad6f6a9e/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8412eacef34cae2836d891836a7fff7b754d6bcac61f6c12ba5ca9bc7e427b68", size = 450739, upload-time = "2025-06-15T19:04:54.203Z" }, - { url = "https://files.pythonhosted.org/packages/4e/0d/a05dd9e5f136cdc29751816d0890d084ab99f8c17b86f25697288ca09bc7/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:df670918eb7dd719642e05979fc84704af913d563fd17ed636f7c4783003fdcc", size = 458106, upload-time = "2025-06-15T19:04:55.607Z" }, - { url = "https://files.pythonhosted.org/packages/f1/fa/9cd16e4dfdb831072b7ac39e7bea986e52128526251038eb481effe9f48e/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d7642b9bc4827b5518ebdb3b82698ada8c14c7661ddec5fe719f3e56ccd13c97", size = 484264, upload-time = "2025-06-15T19:04:57.009Z" }, - { url = "https://files.pythonhosted.org/packages/32/04/1da8a637c7e2b70e750a0308e9c8e662ada0cca46211fa9ef24a23937e0b/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:199207b2d3eeaeb80ef4411875a6243d9ad8bc35b07fc42daa6b801cc39cc41c", size = 597612, upload-time = "2025-06-15T19:04:58.409Z" }, - { url = "https://files.pythonhosted.org/packages/30/01/109f2762e968d3e58c95731a206e5d7d2a7abaed4299dd8a94597250153c/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a479466da6db5c1e8754caee6c262cd373e6e6c363172d74394f4bff3d84d7b5", size = 477242, upload-time = "2025-06-15T19:04:59.786Z" }, - { url = "https://files.pythonhosted.org/packages/b5/b8/46f58cf4969d3b7bc3ca35a98e739fa4085b0657a1540ccc29a1a0bc016f/watchfiles-1.1.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:935f9edd022ec13e447e5723a7d14456c8af254544cefbc533f6dd276c9aa0d9", size = 453148, upload-time = "2025-06-15T19:05:01.103Z" }, - { url = "https://files.pythonhosted.org/packages/a5/cd/8267594263b1770f1eb76914940d7b2d03ee55eca212302329608208e061/watchfiles-1.1.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:8076a5769d6bdf5f673a19d51da05fc79e2bbf25e9fe755c47595785c06a8c72", size = 626574, upload-time = "2025-06-15T19:05:02.582Z" }, - { url = "https://files.pythonhosted.org/packages/a1/2f/7f2722e85899bed337cba715723e19185e288ef361360718973f891805be/watchfiles-1.1.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:86b1e28d4c37e89220e924305cd9f82866bb0ace666943a6e4196c5df4d58dcc", size = 624378, upload-time = "2025-06-15T19:05:03.719Z" }, - { url = "https://files.pythonhosted.org/packages/bf/20/64c88ec43d90a568234d021ab4b2a6f42a5230d772b987c3f9c00cc27b8b/watchfiles-1.1.0-cp310-cp310-win32.whl", hash = "sha256:d1caf40c1c657b27858f9774d5c0e232089bca9cb8ee17ce7478c6e9264d2587", size = 279829, upload-time = "2025-06-15T19:05:04.822Z" }, - { url = "https://files.pythonhosted.org/packages/39/5c/a9c1ed33de7af80935e4eac09570de679c6e21c07070aa99f74b4431f4d6/watchfiles-1.1.0-cp310-cp310-win_amd64.whl", hash = "sha256:a89c75a5b9bc329131115a409d0acc16e8da8dfd5867ba59f1dd66ae7ea8fa82", size = 292192, upload-time = "2025-06-15T19:05:06.348Z" }, - { url = "https://files.pythonhosted.org/packages/8b/78/7401154b78ab484ccaaeef970dc2af0cb88b5ba8a1b415383da444cdd8d3/watchfiles-1.1.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:c9649dfc57cc1f9835551deb17689e8d44666315f2e82d337b9f07bd76ae3aa2", size = 405751, upload-time = "2025-06-15T19:05:07.679Z" }, - { url = "https://files.pythonhosted.org/packages/76/63/e6c3dbc1f78d001589b75e56a288c47723de28c580ad715eb116639152b5/watchfiles-1.1.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:406520216186b99374cdb58bc48e34bb74535adec160c8459894884c983a149c", size = 397313, upload-time = "2025-06-15T19:05:08.764Z" }, - { url = "https://files.pythonhosted.org/packages/6c/a2/8afa359ff52e99af1632f90cbf359da46184207e893a5f179301b0c8d6df/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cb45350fd1dc75cd68d3d72c47f5b513cb0578da716df5fba02fff31c69d5f2d", size = 450792, upload-time = "2025-06-15T19:05:09.869Z" }, - { url = "https://files.pythonhosted.org/packages/1d/bf/7446b401667f5c64972a57a0233be1104157fc3abf72c4ef2666c1bd09b2/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:11ee4444250fcbeb47459a877e5e80ed994ce8e8d20283857fc128be1715dac7", size = 458196, upload-time = "2025-06-15T19:05:11.91Z" }, - { url = "https://files.pythonhosted.org/packages/58/2f/501ddbdfa3fa874ea5597c77eeea3d413579c29af26c1091b08d0c792280/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bda8136e6a80bdea23e5e74e09df0362744d24ffb8cd59c4a95a6ce3d142f79c", size = 484788, upload-time = "2025-06-15T19:05:13.373Z" }, - { url = "https://files.pythonhosted.org/packages/61/1e/9c18eb2eb5c953c96bc0e5f626f0e53cfef4bd19bd50d71d1a049c63a575/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b915daeb2d8c1f5cee4b970f2e2c988ce6514aace3c9296e58dd64dc9aa5d575", size = 597879, upload-time = "2025-06-15T19:05:14.725Z" }, - { url = "https://files.pythonhosted.org/packages/8b/6c/1467402e5185d89388b4486745af1e0325007af0017c3384cc786fff0542/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ed8fc66786de8d0376f9f913c09e963c66e90ced9aa11997f93bdb30f7c872a8", size = 477447, upload-time = "2025-06-15T19:05:15.775Z" }, - { url = "https://files.pythonhosted.org/packages/2b/a1/ec0a606bde4853d6c4a578f9391eeb3684a9aea736a8eb217e3e00aa89a1/watchfiles-1.1.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fe4371595edf78c41ef8ac8df20df3943e13defd0efcb732b2e393b5a8a7a71f", size = 453145, upload-time = "2025-06-15T19:05:17.17Z" }, - { url = "https://files.pythonhosted.org/packages/90/b9/ef6f0c247a6a35d689fc970dc7f6734f9257451aefb30def5d100d6246a5/watchfiles-1.1.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b7c5f6fe273291f4d414d55b2c80d33c457b8a42677ad14b4b47ff025d0893e4", size = 626539, upload-time = "2025-06-15T19:05:18.557Z" }, - { url = "https://files.pythonhosted.org/packages/34/44/6ffda5537085106ff5aaa762b0d130ac6c75a08015dd1621376f708c94de/watchfiles-1.1.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:7738027989881e70e3723c75921f1efa45225084228788fc59ea8c6d732eb30d", size = 624472, upload-time = "2025-06-15T19:05:19.588Z" }, - { url = "https://files.pythonhosted.org/packages/c3/e3/71170985c48028fa3f0a50946916a14055e741db11c2e7bc2f3b61f4d0e3/watchfiles-1.1.0-cp311-cp311-win32.whl", hash = "sha256:622d6b2c06be19f6e89b1d951485a232e3b59618def88dbeda575ed8f0d8dbf2", size = 279348, upload-time = "2025-06-15T19:05:20.856Z" }, - { url = "https://files.pythonhosted.org/packages/89/1b/3e39c68b68a7a171070f81fc2561d23ce8d6859659406842a0e4bebf3bba/watchfiles-1.1.0-cp311-cp311-win_amd64.whl", hash = "sha256:48aa25e5992b61debc908a61ab4d3f216b64f44fdaa71eb082d8b2de846b7d12", size = 292607, upload-time = "2025-06-15T19:05:21.937Z" }, - { url = "https://files.pythonhosted.org/packages/61/9f/2973b7539f2bdb6ea86d2c87f70f615a71a1fc2dba2911795cea25968aea/watchfiles-1.1.0-cp311-cp311-win_arm64.whl", hash = "sha256:00645eb79a3faa70d9cb15c8d4187bb72970b2470e938670240c7998dad9f13a", size = 285056, upload-time = "2025-06-15T19:05:23.12Z" }, - { url = "https://files.pythonhosted.org/packages/f6/b8/858957045a38a4079203a33aaa7d23ea9269ca7761c8a074af3524fbb240/watchfiles-1.1.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9dc001c3e10de4725c749d4c2f2bdc6ae24de5a88a339c4bce32300a31ede179", size = 402339, upload-time = "2025-06-15T19:05:24.516Z" }, - { url = "https://files.pythonhosted.org/packages/80/28/98b222cca751ba68e88521fabd79a4fab64005fc5976ea49b53fa205d1fa/watchfiles-1.1.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:d9ba68ec283153dead62cbe81872d28e053745f12335d037de9cbd14bd1877f5", size = 394409, upload-time = "2025-06-15T19:05:25.469Z" }, - { url = "https://files.pythonhosted.org/packages/86/50/dee79968566c03190677c26f7f47960aff738d32087087bdf63a5473e7df/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:130fc497b8ee68dce163e4254d9b0356411d1490e868bd8790028bc46c5cc297", size = 450939, upload-time = "2025-06-15T19:05:26.494Z" }, - { url = "https://files.pythonhosted.org/packages/40/45/a7b56fb129700f3cfe2594a01aa38d033b92a33dddce86c8dfdfc1247b72/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:50a51a90610d0845a5931a780d8e51d7bd7f309ebc25132ba975aca016b576a0", size = 457270, upload-time = "2025-06-15T19:05:27.466Z" }, - { url = "https://files.pythonhosted.org/packages/b5/c8/fa5ef9476b1d02dc6b5e258f515fcaaecf559037edf8b6feffcbc097c4b8/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dc44678a72ac0910bac46fa6a0de6af9ba1355669b3dfaf1ce5f05ca7a74364e", size = 483370, upload-time = "2025-06-15T19:05:28.548Z" }, - { url = "https://files.pythonhosted.org/packages/98/68/42cfcdd6533ec94f0a7aab83f759ec11280f70b11bfba0b0f885e298f9bd/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a543492513a93b001975ae283a51f4b67973662a375a403ae82f420d2c7205ee", size = 598654, upload-time = "2025-06-15T19:05:29.997Z" }, - { url = "https://files.pythonhosted.org/packages/d3/74/b2a1544224118cc28df7e59008a929e711f9c68ce7d554e171b2dc531352/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8ac164e20d17cc285f2b94dc31c384bc3aa3dd5e7490473b3db043dd70fbccfd", size = 478667, upload-time = "2025-06-15T19:05:31.172Z" }, - { url = "https://files.pythonhosted.org/packages/8c/77/e3362fe308358dc9f8588102481e599c83e1b91c2ae843780a7ded939a35/watchfiles-1.1.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7590d5a455321e53857892ab8879dce62d1f4b04748769f5adf2e707afb9d4f", size = 452213, upload-time = "2025-06-15T19:05:32.299Z" }, - { url = "https://files.pythonhosted.org/packages/6e/17/c8f1a36540c9a1558d4faf08e909399e8133599fa359bf52ec8fcee5be6f/watchfiles-1.1.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:37d3d3f7defb13f62ece99e9be912afe9dd8a0077b7c45ee5a57c74811d581a4", size = 626718, upload-time = "2025-06-15T19:05:33.415Z" }, - { url = "https://files.pythonhosted.org/packages/26/45/fb599be38b4bd38032643783d7496a26a6f9ae05dea1a42e58229a20ac13/watchfiles-1.1.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:7080c4bb3efd70a07b1cc2df99a7aa51d98685be56be6038c3169199d0a1c69f", size = 623098, upload-time = "2025-06-15T19:05:34.534Z" }, - { url = "https://files.pythonhosted.org/packages/a1/e7/fdf40e038475498e160cd167333c946e45d8563ae4dd65caf757e9ffe6b4/watchfiles-1.1.0-cp312-cp312-win32.whl", hash = "sha256:cbcf8630ef4afb05dc30107bfa17f16c0896bb30ee48fc24bf64c1f970f3b1fd", size = 279209, upload-time = "2025-06-15T19:05:35.577Z" }, - { url = "https://files.pythonhosted.org/packages/3f/d3/3ae9d5124ec75143bdf088d436cba39812122edc47709cd2caafeac3266f/watchfiles-1.1.0-cp312-cp312-win_amd64.whl", hash = "sha256:cbd949bdd87567b0ad183d7676feb98136cde5bb9025403794a4c0db28ed3a47", size = 292786, upload-time = "2025-06-15T19:05:36.559Z" }, - { url = "https://files.pythonhosted.org/packages/26/2f/7dd4fc8b5f2b34b545e19629b4a018bfb1de23b3a496766a2c1165ca890d/watchfiles-1.1.0-cp312-cp312-win_arm64.whl", hash = "sha256:0a7d40b77f07be87c6faa93d0951a0fcd8cbca1ddff60a1b65d741bac6f3a9f6", size = 284343, upload-time = "2025-06-15T19:05:37.5Z" }, - { url = "https://files.pythonhosted.org/packages/d3/42/fae874df96595556a9089ade83be34a2e04f0f11eb53a8dbf8a8a5e562b4/watchfiles-1.1.0-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:5007f860c7f1f8df471e4e04aaa8c43673429047d63205d1630880f7637bca30", size = 402004, upload-time = "2025-06-15T19:05:38.499Z" }, - { url = "https://files.pythonhosted.org/packages/fa/55/a77e533e59c3003d9803c09c44c3651224067cbe7fb5d574ddbaa31e11ca/watchfiles-1.1.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:20ecc8abbd957046f1fe9562757903f5eaf57c3bce70929fda6c7711bb58074a", size = 393671, upload-time = "2025-06-15T19:05:39.52Z" }, - { url = "https://files.pythonhosted.org/packages/05/68/b0afb3f79c8e832e6571022611adbdc36e35a44e14f129ba09709aa4bb7a/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2f0498b7d2a3c072766dba3274fe22a183dbea1f99d188f1c6c72209a1063dc", size = 449772, upload-time = "2025-06-15T19:05:40.897Z" }, - { url = "https://files.pythonhosted.org/packages/ff/05/46dd1f6879bc40e1e74c6c39a1b9ab9e790bf1f5a2fe6c08b463d9a807f4/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:239736577e848678e13b201bba14e89718f5c2133dfd6b1f7846fa1b58a8532b", size = 456789, upload-time = "2025-06-15T19:05:42.045Z" }, - { url = "https://files.pythonhosted.org/packages/8b/ca/0eeb2c06227ca7f12e50a47a3679df0cd1ba487ea19cf844a905920f8e95/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eff4b8d89f444f7e49136dc695599a591ff769300734446c0a86cba2eb2f9895", size = 482551, upload-time = "2025-06-15T19:05:43.781Z" }, - { url = "https://files.pythonhosted.org/packages/31/47/2cecbd8694095647406645f822781008cc524320466ea393f55fe70eed3b/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:12b0a02a91762c08f7264e2e79542f76870c3040bbc847fb67410ab81474932a", size = 597420, upload-time = "2025-06-15T19:05:45.244Z" }, - { url = "https://files.pythonhosted.org/packages/d9/7e/82abc4240e0806846548559d70f0b1a6dfdca75c1b4f9fa62b504ae9b083/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:29e7bc2eee15cbb339c68445959108803dc14ee0c7b4eea556400131a8de462b", size = 477950, upload-time = "2025-06-15T19:05:46.332Z" }, - { url = "https://files.pythonhosted.org/packages/25/0d/4d564798a49bf5482a4fa9416dea6b6c0733a3b5700cb8a5a503c4b15853/watchfiles-1.1.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d9481174d3ed982e269c090f780122fb59cee6c3796f74efe74e70f7780ed94c", size = 451706, upload-time = "2025-06-15T19:05:47.459Z" }, - { url = "https://files.pythonhosted.org/packages/81/b5/5516cf46b033192d544102ea07c65b6f770f10ed1d0a6d388f5d3874f6e4/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:80f811146831c8c86ab17b640801c25dc0a88c630e855e2bef3568f30434d52b", size = 625814, upload-time = "2025-06-15T19:05:48.654Z" }, - { url = "https://files.pythonhosted.org/packages/0c/dd/7c1331f902f30669ac3e754680b6edb9a0dd06dea5438e61128111fadd2c/watchfiles-1.1.0-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:60022527e71d1d1fda67a33150ee42869042bce3d0fcc9cc49be009a9cded3fb", size = 622820, upload-time = "2025-06-15T19:05:50.088Z" }, - { url = "https://files.pythonhosted.org/packages/1b/14/36d7a8e27cd128d7b1009e7715a7c02f6c131be9d4ce1e5c3b73d0e342d8/watchfiles-1.1.0-cp313-cp313-win32.whl", hash = "sha256:32d6d4e583593cb8576e129879ea0991660b935177c0f93c6681359b3654bfa9", size = 279194, upload-time = "2025-06-15T19:05:51.186Z" }, - { url = "https://files.pythonhosted.org/packages/25/41/2dd88054b849aa546dbeef5696019c58f8e0774f4d1c42123273304cdb2e/watchfiles-1.1.0-cp313-cp313-win_amd64.whl", hash = "sha256:f21af781a4a6fbad54f03c598ab620e3a77032c5878f3d780448421a6e1818c7", size = 292349, upload-time = "2025-06-15T19:05:52.201Z" }, - { url = "https://files.pythonhosted.org/packages/c8/cf/421d659de88285eb13941cf11a81f875c176f76a6d99342599be88e08d03/watchfiles-1.1.0-cp313-cp313-win_arm64.whl", hash = "sha256:5366164391873ed76bfdf618818c82084c9db7fac82b64a20c44d335eec9ced5", size = 283836, upload-time = "2025-06-15T19:05:53.265Z" }, - { url = "https://files.pythonhosted.org/packages/45/10/6faf6858d527e3599cc50ec9fcae73590fbddc1420bd4fdccfebffeedbc6/watchfiles-1.1.0-cp313-cp313t-macosx_10_12_x86_64.whl", hash = "sha256:17ab167cca6339c2b830b744eaf10803d2a5b6683be4d79d8475d88b4a8a4be1", size = 400343, upload-time = "2025-06-15T19:05:54.252Z" }, - { url = "https://files.pythonhosted.org/packages/03/20/5cb7d3966f5e8c718006d0e97dfe379a82f16fecd3caa7810f634412047a/watchfiles-1.1.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:328dbc9bff7205c215a7807da7c18dce37da7da718e798356212d22696404339", size = 392916, upload-time = "2025-06-15T19:05:55.264Z" }, - { url = "https://files.pythonhosted.org/packages/8c/07/d8f1176328fa9e9581b6f120b017e286d2a2d22ae3f554efd9515c8e1b49/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f7208ab6e009c627b7557ce55c465c98967e8caa8b11833531fdf95799372633", size = 449582, upload-time = "2025-06-15T19:05:56.317Z" }, - { url = "https://files.pythonhosted.org/packages/66/e8/80a14a453cf6038e81d072a86c05276692a1826471fef91df7537dba8b46/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:a8f6f72974a19efead54195bc9bed4d850fc047bb7aa971268fd9a8387c89011", size = 456752, upload-time = "2025-06-15T19:05:57.359Z" }, - { url = "https://files.pythonhosted.org/packages/5a/25/0853b3fe0e3c2f5af9ea60eb2e781eade939760239a72c2d38fc4cc335f6/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d181ef50923c29cf0450c3cd47e2f0557b62218c50b2ab8ce2ecaa02bd97e670", size = 481436, upload-time = "2025-06-15T19:05:58.447Z" }, - { url = "https://files.pythonhosted.org/packages/fe/9e/4af0056c258b861fbb29dcb36258de1e2b857be4a9509e6298abcf31e5c9/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:adb4167043d3a78280d5d05ce0ba22055c266cf8655ce942f2fb881262ff3cdf", size = 596016, upload-time = "2025-06-15T19:05:59.59Z" }, - { url = "https://files.pythonhosted.org/packages/c5/fa/95d604b58aa375e781daf350897aaaa089cff59d84147e9ccff2447c8294/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8c5701dc474b041e2934a26d31d39f90fac8a3dee2322b39f7729867f932b1d4", size = 476727, upload-time = "2025-06-15T19:06:01.086Z" }, - { url = "https://files.pythonhosted.org/packages/65/95/fe479b2664f19be4cf5ceeb21be05afd491d95f142e72d26a42f41b7c4f8/watchfiles-1.1.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b067915e3c3936966a8607f6fe5487df0c9c4afb85226613b520890049deea20", size = 451864, upload-time = "2025-06-15T19:06:02.144Z" }, - { url = "https://files.pythonhosted.org/packages/d3/8a/3c4af14b93a15ce55901cd7a92e1a4701910f1768c78fb30f61d2b79785b/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_aarch64.whl", hash = "sha256:9c733cda03b6d636b4219625a4acb5c6ffb10803338e437fb614fef9516825ef", size = 625626, upload-time = "2025-06-15T19:06:03.578Z" }, - { url = "https://files.pythonhosted.org/packages/da/f5/cf6aa047d4d9e128f4b7cde615236a915673775ef171ff85971d698f3c2c/watchfiles-1.1.0-cp313-cp313t-musllinux_1_1_x86_64.whl", hash = "sha256:cc08ef8b90d78bfac66f0def80240b0197008e4852c9f285907377b2947ffdcb", size = 622744, upload-time = "2025-06-15T19:06:05.066Z" }, - { url = "https://files.pythonhosted.org/packages/2c/00/70f75c47f05dea6fd30df90f047765f6fc2d6eb8b5a3921379b0b04defa2/watchfiles-1.1.0-cp314-cp314-macosx_10_12_x86_64.whl", hash = "sha256:9974d2f7dc561cce3bb88dfa8eb309dab64c729de85fba32e98d75cf24b66297", size = 402114, upload-time = "2025-06-15T19:06:06.186Z" }, - { url = "https://files.pythonhosted.org/packages/53/03/acd69c48db4a1ed1de26b349d94077cca2238ff98fd64393f3e97484cae6/watchfiles-1.1.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c68e9f1fcb4d43798ad8814c4c1b61547b014b667216cb754e606bfade587018", size = 393879, upload-time = "2025-06-15T19:06:07.369Z" }, - { url = "https://files.pythonhosted.org/packages/2f/c8/a9a2a6f9c8baa4eceae5887fecd421e1b7ce86802bcfc8b6a942e2add834/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:95ab1594377effac17110e1352989bdd7bdfca9ff0e5eeccd8c69c5389b826d0", size = 450026, upload-time = "2025-06-15T19:06:08.476Z" }, - { url = "https://files.pythonhosted.org/packages/fe/51/d572260d98388e6e2b967425c985e07d47ee6f62e6455cefb46a6e06eda5/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fba9b62da882c1be1280a7584ec4515d0a6006a94d6e5819730ec2eab60ffe12", size = 457917, upload-time = "2025-06-15T19:06:09.988Z" }, - { url = "https://files.pythonhosted.org/packages/c6/2d/4258e52917bf9f12909b6ec314ff9636276f3542f9d3807d143f27309104/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3434e401f3ce0ed6b42569128b3d1e3af773d7ec18751b918b89cd49c14eaafb", size = 483602, upload-time = "2025-06-15T19:06:11.088Z" }, - { url = "https://files.pythonhosted.org/packages/84/99/bee17a5f341a4345fe7b7972a475809af9e528deba056f8963d61ea49f75/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fa257a4d0d21fcbca5b5fcba9dca5a78011cb93c0323fb8855c6d2dfbc76eb77", size = 596758, upload-time = "2025-06-15T19:06:12.197Z" }, - { url = "https://files.pythonhosted.org/packages/40/76/e4bec1d59b25b89d2b0716b41b461ed655a9a53c60dc78ad5771fda5b3e6/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7fd1b3879a578a8ec2076c7961076df540b9af317123f84569f5a9ddee64ce92", size = 477601, upload-time = "2025-06-15T19:06:13.391Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fa/a514292956f4a9ce3c567ec0c13cce427c158e9f272062685a8a727d08fc/watchfiles-1.1.0-cp314-cp314-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62cc7a30eeb0e20ecc5f4bd113cd69dcdb745a07c68c0370cea919f373f65d9e", size = 451936, upload-time = "2025-06-15T19:06:14.656Z" }, - { url = "https://files.pythonhosted.org/packages/32/5d/c3bf927ec3bbeb4566984eba8dd7a8eb69569400f5509904545576741f88/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_aarch64.whl", hash = "sha256:891c69e027748b4a73847335d208e374ce54ca3c335907d381fde4e41661b13b", size = 626243, upload-time = "2025-06-15T19:06:16.232Z" }, - { url = "https://files.pythonhosted.org/packages/e6/65/6e12c042f1a68c556802a84d54bb06d35577c81e29fba14019562479159c/watchfiles-1.1.0-cp314-cp314-musllinux_1_1_x86_64.whl", hash = "sha256:12fe8eaffaf0faa7906895b4f8bb88264035b3f0243275e0bf24af0436b27259", size = 623073, upload-time = "2025-06-15T19:06:17.457Z" }, - { url = "https://files.pythonhosted.org/packages/89/ab/7f79d9bf57329e7cbb0a6fd4c7bd7d0cee1e4a8ef0041459f5409da3506c/watchfiles-1.1.0-cp314-cp314t-macosx_10_12_x86_64.whl", hash = "sha256:bfe3c517c283e484843cb2e357dd57ba009cff351edf45fb455b5fbd1f45b15f", size = 400872, upload-time = "2025-06-15T19:06:18.57Z" }, - { url = "https://files.pythonhosted.org/packages/df/d5/3f7bf9912798e9e6c516094db6b8932df53b223660c781ee37607030b6d3/watchfiles-1.1.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:a9ccbf1f129480ed3044f540c0fdbc4ee556f7175e5ab40fe077ff6baf286d4e", size = 392877, upload-time = "2025-06-15T19:06:19.55Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c5/54ec7601a2798604e01c75294770dbee8150e81c6e471445d7601610b495/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ba0e3255b0396cac3cc7bbace76404dd72b5438bf0d8e7cefa2f79a7f3649caa", size = 449645, upload-time = "2025-06-15T19:06:20.66Z" }, - { url = "https://files.pythonhosted.org/packages/0a/04/c2f44afc3b2fce21ca0b7802cbd37ed90a29874f96069ed30a36dfe57c2b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4281cd9fce9fc0a9dbf0fc1217f39bf9cf2b4d315d9626ef1d4e87b84699e7e8", size = 457424, upload-time = "2025-06-15T19:06:21.712Z" }, - { url = "https://files.pythonhosted.org/packages/9f/b0/eec32cb6c14d248095261a04f290636da3df3119d4040ef91a4a50b29fa5/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6d2404af8db1329f9a3c9b79ff63e0ae7131986446901582067d9304ae8aaf7f", size = 481584, upload-time = "2025-06-15T19:06:22.777Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e2/ca4bb71c68a937d7145aa25709e4f5d68eb7698a25ce266e84b55d591bbd/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e78b6ed8165996013165eeabd875c5dfc19d41b54f94b40e9fff0eb3193e5e8e", size = 596675, upload-time = "2025-06-15T19:06:24.226Z" }, - { url = "https://files.pythonhosted.org/packages/a1/dd/b0e4b7fb5acf783816bc950180a6cd7c6c1d2cf7e9372c0ea634e722712b/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:249590eb75ccc117f488e2fabd1bfa33c580e24b96f00658ad88e38844a040bb", size = 477363, upload-time = "2025-06-15T19:06:25.42Z" }, - { url = "https://files.pythonhosted.org/packages/69/c4/088825b75489cb5b6a761a4542645718893d395d8c530b38734f19da44d2/watchfiles-1.1.0-cp314-cp314t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d05686b5487cfa2e2c28ff1aa370ea3e6c5accfe6435944ddea1e10d93872147", size = 452240, upload-time = "2025-06-15T19:06:26.552Z" }, - { url = "https://files.pythonhosted.org/packages/10/8c/22b074814970eeef43b7c44df98c3e9667c1f7bf5b83e0ff0201b0bd43f9/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_aarch64.whl", hash = "sha256:d0e10e6f8f6dc5762adee7dece33b722282e1f59aa6a55da5d493a97282fedd8", size = 625607, upload-time = "2025-06-15T19:06:27.606Z" }, - { url = "https://files.pythonhosted.org/packages/32/fa/a4f5c2046385492b2273213ef815bf71a0d4c1943b784fb904e184e30201/watchfiles-1.1.0-cp314-cp314t-musllinux_1_1_x86_64.whl", hash = "sha256:af06c863f152005c7592df1d6a7009c836a247c9d8adb78fef8575a5a98699db", size = 623315, upload-time = "2025-06-15T19:06:29.076Z" }, - { url = "https://files.pythonhosted.org/packages/be/7c/a3d7c55cfa377c2f62c4ae3c6502b997186bc5e38156bafcb9b653de9a6d/watchfiles-1.1.0-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:3a6fd40bbb50d24976eb275ccb55cd1951dfb63dbc27cae3066a6ca5f4beabd5", size = 406748, upload-time = "2025-06-15T19:06:44.2Z" }, - { url = "https://files.pythonhosted.org/packages/38/d0/c46f1b2c0ca47f3667b144de6f0515f6d1c670d72f2ca29861cac78abaa1/watchfiles-1.1.0-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9f811079d2f9795b5d48b55a37aa7773680a5659afe34b54cc1d86590a51507d", size = 398801, upload-time = "2025-06-15T19:06:45.774Z" }, - { url = "https://files.pythonhosted.org/packages/70/9c/9a6a42e97f92eeed77c3485a43ea96723900aefa3ac739a8c73f4bff2cd7/watchfiles-1.1.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a2726d7bfd9f76158c84c10a409b77a320426540df8c35be172444394b17f7ea", size = 451528, upload-time = "2025-06-15T19:06:46.791Z" }, - { url = "https://files.pythonhosted.org/packages/51/7b/98c7f4f7ce7ff03023cf971cd84a3ee3b790021ae7584ffffa0eb2554b96/watchfiles-1.1.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:df32d59cb9780f66d165a9a7a26f19df2c7d24e3bd58713108b41d0ff4f929c6", size = 454095, upload-time = "2025-06-15T19:06:48.211Z" }, - { url = "https://files.pythonhosted.org/packages/8c/6b/686dcf5d3525ad17b384fd94708e95193529b460a1b7bf40851f1328ec6e/watchfiles-1.1.0-pp311-pypy311_pp73-macosx_10_12_x86_64.whl", hash = "sha256:0ece16b563b17ab26eaa2d52230c9a7ae46cf01759621f4fbbca280e438267b3", size = 406910, upload-time = "2025-06-15T19:06:49.335Z" }, - { url = "https://files.pythonhosted.org/packages/f3/d3/71c2dcf81dc1edcf8af9f4d8d63b1316fb0a2dd90cbfd427e8d9dd584a90/watchfiles-1.1.0-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:51b81e55d40c4b4aa8658427a3ee7ea847c591ae9e8b81ef94a90b668999353c", size = 398816, upload-time = "2025-06-15T19:06:50.433Z" }, - { url = "https://files.pythonhosted.org/packages/b8/fa/12269467b2fc006f8fce4cd6c3acfa77491dd0777d2a747415f28ccc8c60/watchfiles-1.1.0-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f2bcdc54ea267fe72bfc7d83c041e4eb58d7d8dc6f578dfddb52f037ce62f432", size = 451584, upload-time = "2025-06-15T19:06:51.834Z" }, - { url = "https://files.pythonhosted.org/packages/bd/d3/254cea30f918f489db09d6a8435a7de7047f8cb68584477a515f160541d6/watchfiles-1.1.0-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:923fec6e5461c42bd7e3fd5ec37492c6f3468be0499bc0707b4bbbc16ac21792", size = 454009, upload-time = "2025-06-15T19:06:52.896Z" }, -] - -[[package]] -name = "web3" -version = "7.12.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "eth-abi" }, - { name = "eth-account" }, - { name = "eth-hash", extra = ["pycryptodome"] }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "pyunormalize" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "requests" }, - { name = "types-requests" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7e/5e/1660d8d0f78e3391cc48833ddd7a2bcc7e02d5cf267a5ae5defa6d3e459d/web3-7.12.1.tar.gz", hash = "sha256:97f6a116ccaeb5907bb4cb6c771cc23bc942bf09528a840189e9b509b7b8347c", size = 2197920, upload-time = "2025-07-14T16:34:24.958Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/60/053fc9381fbdb8ac12b1af7b105d7de3f07b400761c335d2021f82fceddb/web3-7.12.1-py3-none-any.whl", hash = "sha256:eac9a0d4bba128a0811828312ae0faaaa122a258efffd77e1e7cf06a0629a043", size = 1369540, upload-time = "2025-07-14T16:34:22.239Z" }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, - { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, - { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, - { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, - { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, - { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, - { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, - { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, - { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - -[[package]] -name = "werkzeug" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, -] - -[[package]] -name = "x402" -version = "1.0.0" -source = { editable = "../../../../../python/legacy" } -dependencies = [ - { name = "eth-account" }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "fastapi", extra = ["standard"] }, - { name = "flask" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "web3" }, -] - -[package.metadata] -requires-dist = [ - { name = "eth-account", specifier = ">=0.13.7" }, - { name = "eth-typing", specifier = ">=4.0.0" }, - { name = "eth-utils", specifier = ">=3.0.0" }, - { name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" }, - { name = "flask", specifier = ">=3.0.0" }, - { name = "pydantic", specifier = ">=2.10.3" }, - { name = "pydantic-settings", specifier = ">=2.2.1" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "web3", specifier = ">=6.0.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.5" }, - { name = "pytest-asyncio", specifier = ">=1.0.0" }, - { name = "ruff", specifier = ">=0.11.9" }, -] - -[[package]] -name = "x402-advanced-server-example" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "fastapi" }, - { name = "python-dotenv" }, - { name = "uvicorn" }, - { name = "x402" }, -] - -[package.metadata] -requires-dist = [ - { name = "fastapi", specifier = ">=0.109.0" }, - { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "uvicorn", specifier = ">=0.27.0" }, - { name = "x402", editable = "../../../../../python/legacy" }, -] - -[[package]] -name = "yarl" -version = "1.20.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/65/7fed0d774abf47487c64be14e9223749468922817b5e8792b8a64792a1bb/yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4", size = 132910, upload-time = "2025-06-10T00:42:31.108Z" }, - { url = "https://files.pythonhosted.org/packages/8a/7b/988f55a52da99df9e56dc733b8e4e5a6ae2090081dc2754fc8fd34e60aa0/yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a", size = 90644, upload-time = "2025-06-10T00:42:33.851Z" }, - { url = "https://files.pythonhosted.org/packages/f7/de/30d98f03e95d30c7e3cc093759982d038c8833ec2451001d45ef4854edc1/yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed", size = 89322, upload-time = "2025-06-10T00:42:35.688Z" }, - { url = "https://files.pythonhosted.org/packages/e0/7a/f2f314f5ebfe9200724b0b748de2186b927acb334cf964fd312eb86fc286/yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e", size = 323786, upload-time = "2025-06-10T00:42:37.817Z" }, - { url = "https://files.pythonhosted.org/packages/15/3f/718d26f189db96d993d14b984ce91de52e76309d0fd1d4296f34039856aa/yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73", size = 319627, upload-time = "2025-06-10T00:42:39.937Z" }, - { url = "https://files.pythonhosted.org/packages/a5/76/8fcfbf5fa2369157b9898962a4a7d96764b287b085b5b3d9ffae69cdefd1/yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e", size = 339149, upload-time = "2025-06-10T00:42:42.627Z" }, - { url = "https://files.pythonhosted.org/packages/3c/95/d7fc301cc4661785967acc04f54a4a42d5124905e27db27bb578aac49b5c/yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8", size = 333327, upload-time = "2025-06-10T00:42:44.842Z" }, - { url = "https://files.pythonhosted.org/packages/65/94/e21269718349582eee81efc5c1c08ee71c816bfc1585b77d0ec3f58089eb/yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23", size = 326054, upload-time = "2025-06-10T00:42:47.149Z" }, - { url = "https://files.pythonhosted.org/packages/32/ae/8616d1f07853704523519f6131d21f092e567c5af93de7e3e94b38d7f065/yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70", size = 315035, upload-time = "2025-06-10T00:42:48.852Z" }, - { url = "https://files.pythonhosted.org/packages/48/aa/0ace06280861ef055855333707db5e49c6e3a08840a7ce62682259d0a6c0/yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb", size = 338962, upload-time = "2025-06-10T00:42:51.024Z" }, - { url = "https://files.pythonhosted.org/packages/20/52/1e9d0e6916f45a8fb50e6844f01cb34692455f1acd548606cbda8134cd1e/yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2", size = 335399, upload-time = "2025-06-10T00:42:53.007Z" }, - { url = "https://files.pythonhosted.org/packages/f2/65/60452df742952c630e82f394cd409de10610481d9043aa14c61bf846b7b1/yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30", size = 338649, upload-time = "2025-06-10T00:42:54.964Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f5/6cd4ff38dcde57a70f23719a838665ee17079640c77087404c3d34da6727/yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309", size = 358563, upload-time = "2025-06-10T00:42:57.28Z" }, - { url = "https://files.pythonhosted.org/packages/d1/90/c42eefd79d0d8222cb3227bdd51b640c0c1d0aa33fe4cc86c36eccba77d3/yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24", size = 357609, upload-time = "2025-06-10T00:42:59.055Z" }, - { url = "https://files.pythonhosted.org/packages/03/c8/cea6b232cb4617514232e0f8a718153a95b5d82b5290711b201545825532/yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13", size = 350224, upload-time = "2025-06-10T00:43:01.248Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a3/eaa0ab9712f1f3d01faf43cf6f1f7210ce4ea4a7e9b28b489a2261ca8db9/yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8", size = 81753, upload-time = "2025-06-10T00:43:03.486Z" }, - { url = "https://files.pythonhosted.org/packages/8f/34/e4abde70a9256465fe31c88ed02c3f8502b7b5dead693a4f350a06413f28/yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16", size = 86817, upload-time = "2025-06-10T00:43:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b1/18/893b50efc2350e47a874c5c2d67e55a0ea5df91186b2a6f5ac52eff887cd/yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e", size = 133833, upload-time = "2025-06-10T00:43:07.393Z" }, - { url = "https://files.pythonhosted.org/packages/89/ed/b8773448030e6fc47fa797f099ab9eab151a43a25717f9ac043844ad5ea3/yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b", size = 91070, upload-time = "2025-06-10T00:43:09.538Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e3/409bd17b1e42619bf69f60e4f031ce1ccb29bd7380117a55529e76933464/yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b", size = 89818, upload-time = "2025-06-10T00:43:11.575Z" }, - { url = "https://files.pythonhosted.org/packages/f8/77/64d8431a4d77c856eb2d82aa3de2ad6741365245a29b3a9543cd598ed8c5/yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4", size = 347003, upload-time = "2025-06-10T00:43:14.088Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d2/0c7e4def093dcef0bd9fa22d4d24b023788b0a33b8d0088b51aa51e21e99/yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1", size = 336537, upload-time = "2025-06-10T00:43:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f3/fc514f4b2cf02cb59d10cbfe228691d25929ce8f72a38db07d3febc3f706/yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833", size = 362358, upload-time = "2025-06-10T00:43:18.704Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6d/a313ac8d8391381ff9006ac05f1d4331cee3b1efaa833a53d12253733255/yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d", size = 357362, upload-time = "2025-06-10T00:43:20.888Z" }, - { url = "https://files.pythonhosted.org/packages/00/70/8f78a95d6935a70263d46caa3dd18e1f223cf2f2ff2037baa01a22bc5b22/yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8", size = 348979, upload-time = "2025-06-10T00:43:23.169Z" }, - { url = "https://files.pythonhosted.org/packages/cb/05/42773027968968f4f15143553970ee36ead27038d627f457cc44bbbeecf3/yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf", size = 337274, upload-time = "2025-06-10T00:43:27.111Z" }, - { url = "https://files.pythonhosted.org/packages/05/be/665634aa196954156741ea591d2f946f1b78ceee8bb8f28488bf28c0dd62/yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e", size = 363294, upload-time = "2025-06-10T00:43:28.96Z" }, - { url = "https://files.pythonhosted.org/packages/eb/90/73448401d36fa4e210ece5579895731f190d5119c4b66b43b52182e88cd5/yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389", size = 358169, upload-time = "2025-06-10T00:43:30.701Z" }, - { url = "https://files.pythonhosted.org/packages/c3/b0/fce922d46dc1eb43c811f1889f7daa6001b27a4005587e94878570300881/yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f", size = 362776, upload-time = "2025-06-10T00:43:32.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/0d/b172628fce039dae8977fd22caeff3eeebffd52e86060413f5673767c427/yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845", size = 381341, upload-time = "2025-06-10T00:43:34.543Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9b/5b886d7671f4580209e855974fe1cecec409aa4a89ea58b8f0560dc529b1/yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1", size = 379988, upload-time = "2025-06-10T00:43:36.489Z" }, - { url = "https://files.pythonhosted.org/packages/73/be/75ef5fd0fcd8f083a5d13f78fd3f009528132a1f2a1d7c925c39fa20aa79/yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e", size = 371113, upload-time = "2025-06-10T00:43:38.592Z" }, - { url = "https://files.pythonhosted.org/packages/50/4f/62faab3b479dfdcb741fe9e3f0323e2a7d5cd1ab2edc73221d57ad4834b2/yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773", size = 81485, upload-time = "2025-06-10T00:43:41.038Z" }, - { url = "https://files.pythonhosted.org/packages/f0/09/d9c7942f8f05c32ec72cd5c8e041c8b29b5807328b68b4801ff2511d4d5e/yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e", size = 86686, upload-time = "2025-06-10T00:43:42.692Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, - { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, - { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, - { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, - { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, - { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, - { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, - { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, - { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, - { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, - { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, - { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, - { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, - { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, - { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, - { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, - { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, - { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, - { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, - { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, - { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, - { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, - { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, - { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, - { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, - { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, - { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, - { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, - { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, - { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, - { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, - { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, - { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, - { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, - { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, - { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, - { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, -] diff --git a/examples/python/legacy/servers/fastapi/.env-local b/examples/python/legacy/servers/fastapi/.env-local deleted file mode 100644 index 459e595ede..0000000000 --- a/examples/python/legacy/servers/fastapi/.env-local +++ /dev/null @@ -1 +0,0 @@ -ADDRESS= diff --git a/examples/python/legacy/servers/fastapi/README.md b/examples/python/legacy/servers/fastapi/README.md deleted file mode 100644 index 3321d5c33e..0000000000 --- a/examples/python/legacy/servers/fastapi/README.md +++ /dev/null @@ -1,51 +0,0 @@ -# x402 fastapi Example Server - -This is an example FastAPI server that demonstrates how to use the x402 `fastapi` middleware to implement paywall functionality in your API endpoints. - -## Prerequisites - -- Python 3.10+ -- A valid Ethereum address for receiving payments - -## Setup - -1. Copy `.env-local` to `.env` and add your Ethereum address to receive payments: - -```bash -cp .env-local .env -``` - -2. Install dependencies: -```bash -uv sync -``` - -3. Run the server: -```bash -uv run python main.py -``` - -The server will start on http://localhost:4021 - -## Extending the Example - -To add more paid endpoints, follow this pattern: - -```python -# First, configure the payment middleware with your routes -app.middleware("http")( - require_payment( - path="/your-endpoint", - price="$0.10", - pay_to_address=ADDRESS, - network=NETWORK, - ) -) - -# Then define your routes as normal -@app.get("/your-endpoint") -async def your_endpoint(): - return { - # Your response data - } -``` diff --git a/examples/python/legacy/servers/fastapi/main.py b/examples/python/legacy/servers/fastapi/main.py deleted file mode 100644 index 40d554e366..0000000000 --- a/examples/python/legacy/servers/fastapi/main.py +++ /dev/null @@ -1,68 +0,0 @@ -import os -from typing import Any, Dict - -from dotenv import load_dotenv -from fastapi import FastAPI -from x402.fastapi.middleware import require_payment -from x402.types import EIP712Domain, TokenAmount, TokenAsset - -# Load environment variables -load_dotenv() - -# Get configuration from environment -ADDRESS = os.getenv("ADDRESS") - -if not ADDRESS: - raise ValueError("Missing required environment variables") - -app = FastAPI() - -# Apply payment middleware to specific routes -app.middleware("http")( - require_payment( - path="/weather", - price="$0.001", - pay_to_address=ADDRESS, - network="base-sepolia", - ) -) - -# Apply payment middleware to premium routes -app.middleware("http")( - require_payment( - path="/premium/*", - price=TokenAmount( - amount="10000", - asset=TokenAsset( - address="0x036CbD53842c5426634e7929541eC2318f3dCF7e", - decimals=6, - eip712=EIP712Domain(name="USDC", version="2"), - ), - ), - pay_to_address=ADDRESS, - network="base-sepolia", - ) -) - - -@app.get("/weather") -async def get_weather() -> Dict[str, Any]: - return { - "report": { - "weather": "sunny", - "temperature": 70, - } - } - - -@app.get("/premium/content") -async def get_premium_content() -> Dict[str, Any]: - return { - "content": "This is premium content", - } - - -if __name__ == "__main__": - import uvicorn - - uvicorn.run(app, host="0.0.0.0", port=4021) diff --git a/examples/python/legacy/servers/fastapi/pyproject.toml b/examples/python/legacy/servers/fastapi/pyproject.toml deleted file mode 100644 index ea47271053..0000000000 --- a/examples/python/legacy/servers/fastapi/pyproject.toml +++ /dev/null @@ -1,27 +0,0 @@ -[project] -name = "x402-fastapi-example" -version = "0.1.0" -description = "Example of using a fastapi server with x402 middleware" -requires-python = ">=3.10" -dependencies = [ - "x402", - "fastapi>=0.109.0", - "uvicorn>=0.27.0", - "python-dotenv>=1.0.0" -] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -packages = ["."] - -[tool.hatch.metadata] -allow-direct-references = true - -[tool.uv] -package = false - -[tool.uv.sources] -x402 = { path = "../../../../../python/legacy", editable = true } diff --git a/examples/python/legacy/servers/fastapi/uv.lock b/examples/python/legacy/servers/fastapi/uv.lock deleted file mode 100644 index f095f6960b..0000000000 --- a/examples/python/legacy/servers/fastapi/uv.lock +++ /dev/null @@ -1,1975 +0,0 @@ -version = 1 -revision = 2 -requires-python = ">=3.10" - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, -] - -[[package]] -name = "aiohttp" -version = "3.12.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f2/84/ea27e6ad14747d8c51afe201fb88a5c8282b6278256d30a6f71f730add88/aiohttp-3.12.12.tar.gz", hash = "sha256:05875595d2483d96cb61fa9f64e75262d7ac6251a7e3c811d8e26f7d721760bd", size = 7818643, upload-time = "2025-06-10T05:22:00.247Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/d9/cfde93b9cb75253c716b8b1c773565209e3d4dd0772dd3ce3a2adcaa4639/aiohttp-3.12.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6f25e9d274d6abbb15254f76f100c3984d6b9ad6e66263cc60a465dd5c7e48f5", size = 702071, upload-time = "2025-06-10T05:18:23.986Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/46e38b8bc0bc645317deec32612af922ad9bafd85a1df255a67c2f2305f6/aiohttp-3.12.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b8ec3c1a1c13d24941b5b913607e57b9364e4c0ea69d5363181467492c4b2ba6", size = 478436, upload-time = "2025-06-10T05:18:28.411Z" }, - { url = "https://files.pythonhosted.org/packages/8f/47/9c83db7f02ca71eb99a707ee13657fc24ba703b9babc59000c1f58ac1198/aiohttp-3.12.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81ef2f9253c327c211cb7b06ea2edd90e637cf21c347b894d540466b8d304e08", size = 466213, upload-time = "2025-06-10T05:18:30.706Z" }, - { url = "https://files.pythonhosted.org/packages/31/fe/4690c112e269e06c9182c32eeb43f3a95c4f203fdb095502717327993b80/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28ded835c3663fd41c9ad44685811b11e34e6ac9a7516a30bfce13f6abba4496", size = 1648258, upload-time = "2025-06-10T05:18:32.498Z" }, - { url = "https://files.pythonhosted.org/packages/c8/1f/dacca6c7bbe69c77d8535d7a672478803e7078cc20fd9993fe09aa5be880/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a4b78ccf254fc10605b263996949a94ca3f50e4f9100e05137d6583e266b711e", size = 1622316, upload-time = "2025-06-10T05:18:34.357Z" }, - { url = "https://files.pythonhosted.org/packages/ff/65/5ef47708f70524fcdecda735e0aea06e0feb7b8679e976e9bd1e7900f4c0/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f4a5af90d5232c41bb857568fe7d11ed84408653ec9da1ff999cc30258b9bd1", size = 1694723, upload-time = "2025-06-10T05:18:36.858Z" }, - { url = "https://files.pythonhosted.org/packages/18/62/ab32bfa59f61292e4096c383316863e10001eec30e5b4b314856ed7156e2/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffa5205c2f53f1120e93fdf2eca41b0f6344db131bc421246ee82c1e1038a14a", size = 1737037, upload-time = "2025-06-10T05:18:39.663Z" }, - { url = "https://files.pythonhosted.org/packages/c1/b9/8b8f793081311e4f63aea63003a519064048e406c627c0454d6ed09dbc99/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68301660f0d7a3eddfb84f959f78a8f9db98c76a49b5235508fa16edaad0f7c", size = 1641701, upload-time = "2025-06-10T05:18:41.666Z" }, - { url = "https://files.pythonhosted.org/packages/1a/5c/72f510d42d626463b526345dcb8d14b390de89a9ba27a4717b518460bcd4/aiohttp-3.12.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db874d3b0c92fdbb553751af9d2733b378c25cc83cd9dfba87f12fafd2dc9cd5", size = 1581824, upload-time = "2025-06-10T05:18:44.136Z" }, - { url = "https://files.pythonhosted.org/packages/61/6f/9378c9e1543d1c800ca040e21cd333b8f923ed051ae82b5a49ad96a6ac71/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5e53cf9c201b45838a2d07b1f2d5f7fec9666db7979240002ce64f9b8a1e0cf2", size = 1625674, upload-time = "2025-06-10T05:18:46.716Z" }, - { url = "https://files.pythonhosted.org/packages/bb/85/4eef9bd52b497a405c88469cc099f4d15d33b149b5746ca4ef8ec6ab6388/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:8687cc5f32b4e328c233acd387d09a1b477007896b2f03c1c823a0fd05f63883", size = 1636460, upload-time = "2025-06-10T05:18:49.305Z" }, - { url = "https://files.pythonhosted.org/packages/56/59/d8e954830b375fd658843cf7d88d27ca5e38dd5fcbfe62db3d1ba415d0fe/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ee537ad29de716a3d8dc46c609908de0c25ffeebf93cd94a03d64cdc07d66d0", size = 1611912, upload-time = "2025-06-10T05:18:51.694Z" }, - { url = "https://files.pythonhosted.org/packages/c3/5d/d0096a02f0515a38dff67db42d966273a12d17fc895e91466bfb4ab3875e/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:411f821be5af6af11dc5bed6c6c1dc6b6b25b91737d968ec2756f9baa75e5f9b", size = 1691498, upload-time = "2025-06-10T05:18:54.36Z" }, - { url = "https://files.pythonhosted.org/packages/87/8d/d3a02397a6345c06623ae4648e2aef18fced858510b4a89d7262cfa4c683/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f90319d94cf5f9786773237f24bd235a7b5959089f1af8ec1154580a3434b503", size = 1714737, upload-time = "2025-06-10T05:18:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/a9/40/b81000bf07c96db878703ea3dc561393d82441597729910459a8e06acc9a/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:73b148e606f34e9d513c451fd65efe1091772659ca5703338a396a99f60108ff", size = 1643078, upload-time = "2025-06-10T05:18:59.33Z" }, - { url = "https://files.pythonhosted.org/packages/41/e5/31830642ce2c6d3dba74ed8a94933213df5e1651c1e8b4efc81cc88105ab/aiohttp-3.12.12-cp310-cp310-win32.whl", hash = "sha256:d40e7bfd577fdc8a92b72f35dfbdd3ec90f1bc8a72a42037fefe34d4eca2d4a1", size = 427517, upload-time = "2025-06-10T05:19:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/55/9d/a4e5379d44679e5f8d7d7ebecb0dae8cafab95176c4e753da6bc4b4aebb5/aiohttp-3.12.12-cp310-cp310-win_amd64.whl", hash = "sha256:65c7804a2343893d6dea9fce69811aea0a9ac47f68312cf2e3ee1668cd9a387f", size = 450725, upload-time = "2025-06-10T05:19:03.874Z" }, - { url = "https://files.pythonhosted.org/packages/47/1f/b1b66e05dc3066a9ba7862d50e2e95b3871db82ccf9652568845f353eeba/aiohttp-3.12.12-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:38823fe0d8bc059b3eaedb263fe427d887c7032e72b4ef92c472953285f0e658", size = 709385, upload-time = "2025-06-10T05:19:05.763Z" }, - { url = "https://files.pythonhosted.org/packages/43/e6/3230e42af16438b450b1e193c537fd3d2d31771dafda3c2105a8d11af707/aiohttp-3.12.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:10237f2c34711215d04ed21da63852ce023608299554080a45c576215d9df81c", size = 481660, upload-time = "2025-06-10T05:19:08.332Z" }, - { url = "https://files.pythonhosted.org/packages/06/ba/cfa91fe5cc262535e1175b1522d8fcc09f9d6ad18b85241f4ee3be1d780f/aiohttp-3.12.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:563ec477c0dc6d56fc7f943a3475b5acdb399c7686c30f5a98ada24bb7562c7a", size = 469924, upload-time = "2025-06-10T05:19:10.342Z" }, - { url = "https://files.pythonhosted.org/packages/9a/f0/5c706cfddd4769b55c0cda466aa6034412d39e416f0b30dda81c4a24616f/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3d05c46a61aca7c47df74afff818bc06a251ab95d95ff80b53665edfe1e0bdf", size = 1740116, upload-time = "2025-06-10T05:19:12.783Z" }, - { url = "https://files.pythonhosted.org/packages/4d/9f/04dba2e1c8bee53c3c623d11a1f947c9e2712500f734dc0dfd06daad32ec/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:277c882916759b4a6b6dc7e2ceb124aad071b3c6456487808d9ab13e1b448d57", size = 1688784, upload-time = "2025-06-10T05:19:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/df/24/19d6d4c41fbf8304fe7c111fcc701e0aa5a2232ee3ac16272677a11f9cfe/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:216abf74b324b0f4e67041dd4fb2819613909a825904f8a51701fbcd40c09cd7", size = 1787575, upload-time = "2025-06-10T05:19:18.586Z" }, - { url = "https://files.pythonhosted.org/packages/0c/59/01f4c55a1f91ad3b5255b2498b3a22362a3fe6ee9bc9ba1af3cc668244da/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65d6cefad286459b68e7f867b9586a821fb7f121057b88f02f536ef570992329", size = 1826621, upload-time = "2025-06-10T05:19:21.284Z" }, - { url = "https://files.pythonhosted.org/packages/55/85/6357166918ff5025602a7cc41332c1ae7a5b57f2fe3da4d755ae30f24bd0/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feaaaff61966b5f4b4eae0b79fc79427f49484e4cfa5ab7d138ecd933ab540a8", size = 1729082, upload-time = "2025-06-10T05:19:23.307Z" }, - { url = "https://files.pythonhosted.org/packages/e3/ca/de3b5ccd5a2aa9352f6ec6f446565f6e1601ebb54860c94c686a9ff76660/aiohttp-3.12.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a05917780b7cad1755784b16cfaad806bc16029a93d15f063ca60185b7d9ba05", size = 1666159, upload-time = "2025-06-10T05:19:25.929Z" }, - { url = "https://files.pythonhosted.org/packages/d1/69/a1006021a1d3244c0872ee75cd8da150e0098b3b2ec6945c225754d11a60/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:082c5ec6d262c1b2ee01c63f4fb9152c17f11692bf16f0f100ad94a7a287d456", size = 1714433, upload-time = "2025-06-10T05:19:28.044Z" }, - { url = "https://files.pythonhosted.org/packages/d2/2a/15aa1179e9fbdd0d17cdf117b4296dedad098abb5a93f8e9c8ab4626f6ea/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:b265a3a8b379b38696ac78bdef943bdc4f4a5d6bed1a3fb5c75c6bab1ecea422", size = 1709590, upload-time = "2025-06-10T05:19:30.165Z" }, - { url = "https://files.pythonhosted.org/packages/a2/f0/95ed9e21250815f1d1a0cd3e868a3f39400a16010ae59f19ddd4ccc4e787/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2e0f2e208914ecbc4b2a3b7b4daa759d0c587d9a0b451bb0835ac47fae7fa735", size = 1689776, upload-time = "2025-06-10T05:19:32.965Z" }, - { url = "https://files.pythonhosted.org/packages/81/4d/370ecc133c648c98a85445f2d331c1272859c89cd52c29a293015bc352c7/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9923b025845b72f64d167bca221113377c8ffabd0a351dc18fb839d401ee8e22", size = 1783378, upload-time = "2025-06-10T05:19:35.14Z" }, - { url = "https://files.pythonhosted.org/packages/a8/86/414e3dae7e07caf6b02cd75d7148d0d8673d4c5077f407be3627d6e33fac/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1ebb213445900527831fecc70e185bf142fdfe5f2a691075f22d63c65ee3c35a", size = 1803841, upload-time = "2025-06-10T05:19:37.41Z" }, - { url = "https://files.pythonhosted.org/packages/88/df/486f10df681cd1a8c898acc8dc2edbd46ffb088b886757b71ae362bf44d3/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6fc369fb273a8328077d37798b77c1e65676709af5c182cb74bd169ca9defe81", size = 1716896, upload-time = "2025-06-10T05:19:40.172Z" }, - { url = "https://files.pythonhosted.org/packages/07/1e/1cacaf5d838869432e96ece1580d0b51494ebb66351f0e8118b74b38d2f0/aiohttp-3.12.12-cp311-cp311-win32.whl", hash = "sha256:58ecd10fda6a44c311cd3742cfd2aea8c4c600338e9f27cb37434d9f5ca9ddaa", size = 427030, upload-time = "2025-06-10T05:19:42.152Z" }, - { url = "https://files.pythonhosted.org/packages/30/dd/e89c1d190da2c84e0ca03c2970b9988a9c56005d18db7f447cf62b3ae6d0/aiohttp-3.12.12-cp311-cp311-win_amd64.whl", hash = "sha256:b0066e88f30be00badffb5ef8f2281532b9a9020863d873ae15f7c147770b6ec", size = 451419, upload-time = "2025-06-10T05:19:44.176Z" }, - { url = "https://files.pythonhosted.org/packages/df/e6/df14ec151942818ecc5e685fa8a4b07d3d3d8a9e4a7d2701047c89290551/aiohttp-3.12.12-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:98451ce9ce229d092f278a74a7c2a06b3aa72984673c87796126d7ccade893e9", size = 700494, upload-time = "2025-06-10T05:19:46.18Z" }, - { url = "https://files.pythonhosted.org/packages/4f/dc/7bc6e17adcd7a82b0d0317ad3e792ac22c93fb672077f0eade93e8d70182/aiohttp-3.12.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:adbac7286d89245e1aff42e948503fdc6edf6d5d65c8e305a67c40f6a8fb95f4", size = 475095, upload-time = "2025-06-10T05:19:48.246Z" }, - { url = "https://files.pythonhosted.org/packages/80/fd/c4e8846ad9d9ecdb7d5ba96de65b7bf2c1582f0b2732f2023080c1c05255/aiohttp-3.12.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0728882115bfa85cbd8d0f664c8ccc0cfd5bd3789dd837596785450ae52fac31", size = 467929, upload-time = "2025-06-10T05:19:50.79Z" }, - { url = "https://files.pythonhosted.org/packages/70/40/abebcf5c81f5e65b4379c05929773be2731ce12414264d3e0fe09ee241eb/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf3b9d9e767f9d0e09fb1a31516410fc741a62cc08754578c40abc497d09540", size = 1714729, upload-time = "2025-06-10T05:19:52.989Z" }, - { url = "https://files.pythonhosted.org/packages/8e/67/4c4f96ef6f16405e7c5205ab3c28852c7e904493b6ddc1c744dda1c97a81/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c944860e86b9f77a462321a440ccf6fa10f5719bb9d026f6b0b11307b1c96c7b", size = 1697380, upload-time = "2025-06-10T05:19:55.832Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a2/dae9ebea4caa8030170c0237e55fa0960df44b3596a849ab9ea621964054/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b1979e1f0c98c06fd0cd940988833b102fa3aa56751f6c40ffe85cabc51f6fd", size = 1752474, upload-time = "2025-06-10T05:19:58.007Z" }, - { url = "https://files.pythonhosted.org/packages/31/ef/f3d9073565ac7ad5257aaa1490ebfc2f182dfc817d3ccfd38c8ab35b2247/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:120b7dd084e96cfdad85acea2ce1e7708c70a26db913eabb8d7b417c728f5d84", size = 1798631, upload-time = "2025-06-10T05:20:00.393Z" }, - { url = "https://files.pythonhosted.org/packages/8b/0b/8b1978662274c80c8e4a739d9be1ae9ef25e5ce42b55838d6a9d1a4e3497/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e58f5ae79649ffa247081c2e8c85e31d29623cf2a3137dda985ae05c9478aae", size = 1718071, upload-time = "2025-06-10T05:20:02.812Z" }, - { url = "https://files.pythonhosted.org/packages/56/aa/35786137db867901b41cb3d2c19c0f4c56dfe581694dba99dec2683d8f8d/aiohttp-3.12.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aa5f049e3e2745b0141f13e5a64e7c48b1a1427ed18bbb7957b348f282fee56", size = 1633871, upload-time = "2025-06-10T05:20:05.127Z" }, - { url = "https://files.pythonhosted.org/packages/63/1d/34d45497dd04d08d662ecda875c44e91d271bbc5d21f4c9e4cbd3ddf7ae2/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7163cc9cf3722d90f1822f8a38b211e3ae2fc651c63bb55449f03dc1b3ff1d44", size = 1694933, upload-time = "2025-06-10T05:20:07.431Z" }, - { url = "https://files.pythonhosted.org/packages/29/c7/41e09a4517449eabbb0a7fe6d60f584fe5b21d4bff761197eb0b81e70034/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ef97c4d035b721de6607f3980fa3e4ef0ec3aca76474b5789b7fac286a8c4e23", size = 1716386, upload-time = "2025-06-10T05:20:09.787Z" }, - { url = "https://files.pythonhosted.org/packages/3a/32/907bd2010b51b70de5314ad707dfc4e898ea0011ff3d678cdf43d6f8980a/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1c14448d6a86acadc3f7b2f4cc385d1fb390acb6f37dce27f86fe629410d92e3", size = 1657039, upload-time = "2025-06-10T05:20:12.198Z" }, - { url = "https://files.pythonhosted.org/packages/60/27/8d87344a33346dcd39273adc33060aeb135e0ef70d1d6e71a3b03894a8e9/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a1b6df6255cfc493454c79221183d64007dd5080bcda100db29b7ff181b8832c", size = 1736599, upload-time = "2025-06-10T05:20:14.519Z" }, - { url = "https://files.pythonhosted.org/packages/ca/45/57c7ef1af694a6d0906abab6edde03787c8c6b0cf5d8359b69d1eb0679df/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:60fc7338dfb0626c2927bfbac4785de3ea2e2bbe3d328ba5f3ece123edda4977", size = 1764575, upload-time = "2025-06-10T05:20:16.993Z" }, - { url = "https://files.pythonhosted.org/packages/2a/cc/b1f918cd702efa9ead9d41f89214e9225cda4e5d013d6eed7f1915c17d0a/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d2afc72207ef4c9d4ca9fcd00689a6a37ef2d625600c3d757b5c2b80c9d0cf9a", size = 1724184, upload-time = "2025-06-10T05:20:19.296Z" }, - { url = "https://files.pythonhosted.org/packages/47/55/089762ee32c2a2e0f523d9ab38c9da2a344cac0e0cc8d16ecf206517ef7e/aiohttp-3.12.12-cp312-cp312-win32.whl", hash = "sha256:8098a48f93b2cbcdb5778e7c9a0e0375363e40ad692348e6e65c3b70d593b27c", size = 421762, upload-time = "2025-06-10T05:20:22.063Z" }, - { url = "https://files.pythonhosted.org/packages/ab/47/151f657e429972916f61399bd52b410e9072d5a2cae1b794f890930e5797/aiohttp-3.12.12-cp312-cp312-win_amd64.whl", hash = "sha256:d1c1879b2e0fc337d7a1b63fe950553c2b9e93c071cf95928aeea1902d441403", size = 447863, upload-time = "2025-06-10T05:20:24.326Z" }, - { url = "https://files.pythonhosted.org/packages/ee/3e/396a7d1c47aa7a74612b186dc716857506c61afac72337a7a96215c2a124/aiohttp-3.12.12-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ea5d604318234427929d486954e3199aded65f41593ac57aa0241ab93dda3d15", size = 694901, upload-time = "2025-06-10T05:20:26.58Z" }, - { url = "https://files.pythonhosted.org/packages/cc/97/235e48eadf73a1854b4d4da29b88d00049309d897d55a511e1cbe4412603/aiohttp-3.12.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e03ff38250b8b572dce6fcd7b6fb6ee398bb8a59e6aa199009c5322d721df4fc", size = 472552, upload-time = "2025-06-10T05:20:28.957Z" }, - { url = "https://files.pythonhosted.org/packages/6b/73/cd7c9439e8cab4113650541017c6524bd0e675b219dfdbbf945a78305e3f/aiohttp-3.12.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:71125b1fc2b6a94bccc63bbece620906a4dead336d2051f8af9cbf04480bc5af", size = 464853, upload-time = "2025-06-10T05:20:31.652Z" }, - { url = "https://files.pythonhosted.org/packages/d1/33/eea88ee55ed4b3f74732d9fc773e6fcf134a2971a19c7ecc49a291e7e57f/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:784a66f9f853a22c6b8c2bd0ff157f9b879700f468d6d72cfa99167df08c5c9c", size = 1703671, upload-time = "2025-06-10T05:20:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/2a/e3/a67ecf9c154b13bad9e2a86ea3782a4b73e889343ffde8c1aadcf9099c09/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a5be0b58670b54301404bd1840e4902570a1c3be00358e2700919cb1ea73c438", size = 1684934, upload-time = "2025-06-10T05:20:36.721Z" }, - { url = "https://files.pythonhosted.org/packages/89/f0/3aaea866531be2f2fcf3a87607e1f55fa72e6ce5acd6b058941a4fc35e15/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8f13566fc7bf5a728275b434bc3bdea87a7ed3ad5f734102b02ca59d9b510f", size = 1737004, upload-time = "2025-06-10T05:20:39.533Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/15867a4c7d39d8fd9bd02191cf60b1d06415fc407bbd4ff2f9660845f1cb/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d736e57d1901683bc9be648aa308cb73e646252c74b4c639c35dcd401ed385ea", size = 1786378, upload-time = "2025-06-10T05:20:42.03Z" }, - { url = "https://files.pythonhosted.org/packages/bd/61/82b15f87088b35705e01fce55806241b45a1099b3470bbca0bed8ee98662/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2007eaa7aae9102f211c519d1ec196bd3cecb1944a095db19eeaf132b798738", size = 1708707, upload-time = "2025-06-10T05:20:44.474Z" }, - { url = "https://files.pythonhosted.org/packages/28/f2/aed0786d5a1c2ed1f5a13ff2a98baacc27206b81d93812da28fc49d8a5d0/aiohttp-3.12.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a813e61583cab6d5cdbaa34bc28863acdb92f9f46e11de1b3b9251a1e8238f6", size = 1622410, upload-time = "2025-06-10T05:20:46.957Z" }, - { url = "https://files.pythonhosted.org/packages/17/54/8305f49a960376136ada977be1370fddb584c63d40bd1b9bef59469f28c7/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e408293aa910b0aea48b86a28eace41d497a85ba16c20f619f0c604597ef996c", size = 1675435, upload-time = "2025-06-10T05:20:49.379Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dc/0a55350025bc297265cfa6c6b1b1f7508f4226ca3238697cbe5e772a7d76/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f3d31faf290f5a30acba46b388465b67c6dbe8655d183e9efe2f6a1d594e6d9d", size = 1707099, upload-time = "2025-06-10T05:20:51.974Z" }, - { url = "https://files.pythonhosted.org/packages/d8/70/d949a1612b996e49d540c10ed77a0a1465c482a590e9a59c1c7897746119/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0b84731697325b023902aa643bd1726d999f5bc7854bc28b17ff410a81151d4b", size = 1649693, upload-time = "2025-06-10T05:20:54.973Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ea/fb87beb7135e25576a1e6fbe98106c037d9fcf1543f19108f9ceb73c192c/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a324c6852b6e327811748446e56cc9bb6eaa58710557922183175816e82a4234", size = 1725825, upload-time = "2025-06-10T05:20:57.433Z" }, - { url = "https://files.pythonhosted.org/packages/f1/1f/adbeb3e440d49b733cef499ace94723ab1fe9fb516425e219379e03b7c9a/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:22fd867fbd72612dcf670c90486dbcbaf702cb807fb0b42bc0b7a142a573574a", size = 1759300, upload-time = "2025-06-10T05:21:00.444Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c1/2fe007ad930f409d0d7fd9916cd55ec9b78b6a611a237424266ed71da48b/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3e092f1a970223794a4bf620a26c0e4e4e8e36bccae9b0b5da35e6d8ee598a03", size = 1708189, upload-time = "2025-06-10T05:21:02.969Z" }, - { url = "https://files.pythonhosted.org/packages/85/5e/ed3ed640fafae3972eae6cd26f66240108cf62452ac8128d59970d538cb1/aiohttp-3.12.12-cp313-cp313-win32.whl", hash = "sha256:7f5f5eb8717ef8ba15ab35fcde5a70ad28bbdc34157595d1cddd888a985f5aae", size = 420783, upload-time = "2025-06-10T05:21:06.287Z" }, - { url = "https://files.pythonhosted.org/packages/a6/db/57d2bb4af52dd0c6f62c42c7d34b82495b2902e50440134f70bfb7ee0fdd/aiohttp-3.12.12-cp313-cp313-win_amd64.whl", hash = "sha256:ace2499bdd03c329c054dc4b47361f2b19d5aa470f7db5c7e0e989336761b33c", size = 446721, upload-time = "2025-06-10T05:21:08.738Z" }, -] - -[[package]] -name = "aiosignal" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, -] - -[[package]] -name = "async-timeout" -version = "5.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, -] - -[[package]] -name = "attrs" -version = "25.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, -] - -[[package]] -name = "bitarray" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/0d/15826c7c2d49a4518a1b24b0d432f1ecad2e0b68168f942058b5de498498/bitarray-3.4.2.tar.gz", hash = "sha256:78ed2b911aabede3a31e3329b1de8abdc8104bd5e0545184ddbd9c7f668f4059", size = 143756, upload-time = "2025-05-21T16:21:44.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/61/fa3a06d74bfba1dc591efa9f4f5ad2e5645f06a8c4d113cf12d18b5ac25b/bitarray-3.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:42b552f885c5629182928c79237b375a92bcf1bc1e725b1c8a5e8eab28ea300d", size = 141280, upload-time = "2025-05-21T16:18:02.593Z" }, - { url = "https://files.pythonhosted.org/packages/17/ba/7eb30374c0e4c4b732a3ca3457d9fb0e44165ae4c5af9758597b03211a28/bitarray-3.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3e16d6184f349587b6a5045bcf073baf763a86273aab454485ba437d0bca82e8", size = 138031, upload-time = "2025-05-21T16:18:05.616Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6d/91582b0a232b54e910add5d0db34a926d0bdfdd1447685b8750349c71958/bitarray-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ecf456f0dee61bd818011e290d922e3e3b1aeb0544f6f19c4da9c5fc2e52818", size = 306437, upload-time = "2025-05-21T16:18:06.793Z" }, - { url = "https://files.pythonhosted.org/packages/b8/23/113ccc20f6324d517ef6210c8fc6ae300346eb481c5a0483735e19b4deea/bitarray-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8bbe8249ae90dc0cd78b21d5d5d27a614e15bf30737ae6e8a0e2e60cc492acc", size = 322335, upload-time = "2025-05-21T16:18:07.925Z" }, - { url = "https://files.pythonhosted.org/packages/6d/89/bf5a36e05ac3d77bdccbe9ba0eea4c47253411c2616379de0f181c27ecee/bitarray-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe7706f75f3b86e7afa516452bed9757ee301b59aea580c551c32a5e1cef082c", size = 314137, upload-time = "2025-05-21T16:18:09.333Z" }, - { url = "https://files.pythonhosted.org/packages/66/a6/bed287f9095a2a266fc68ee42d6ee2815ff500783f973876d86a6d37a434/bitarray-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c60c8d30bb6efd2c04cf82d077df6449964234aeca996f6f1df317a08feffc0", size = 307963, upload-time = "2025-05-21T16:18:10.618Z" }, - { url = "https://files.pythonhosted.org/packages/2f/50/3ca2adaf0da034e6c1a2ed60a3781b065672dd282e67f88593290c3990a7/bitarray-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b4cb5c22706d411010c7ce5efc0a4cc99f755a30fc7f6770eb1b1a0c0962bbb", size = 295182, upload-time = "2025-05-21T16:18:11.932Z" }, - { url = "https://files.pythonhosted.org/packages/90/de/8c3d96e273bc51e4912185bd809fc6a9ec14a09e607336892c149e0c57c5/bitarray-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0fd60137a9474ce53bdace68c718a7c538f9df01d390452cc984f1ee78d7bcdb", size = 300063, upload-time = "2025-05-21T16:18:13.221Z" }, - { url = "https://files.pythonhosted.org/packages/9d/71/34f0ea6ac5b2cbdd84f3e6283b5b796628cef616e786cb442cefce0fe224/bitarray-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cd514a8e27d0751f0254861df60335edabacccfcb2457793ff30c8b2ed8f799d", size = 292053, upload-time = "2025-05-21T16:18:14.802Z" }, - { url = "https://files.pythonhosted.org/packages/77/99/6ef41312536d2c37f14f0f7173aa1a012e9675d62900c10afa7641b47f75/bitarray-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6c8f7447cdf2faff1d176c5dd207f0134f05cfa2a238d3d3944dc5019dc41593", size = 317007, upload-time = "2025-05-21T16:18:16.117Z" }, - { url = "https://files.pythonhosted.org/packages/22/f9/cc4e73f54698bcdd1e0f1ea582da7e005464651e8116291a226deab95e1b/bitarray-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:75040a2a1abe4ccd40236f4ba0d39abde981d23f3ce7691b3b3f2137f134b99b", size = 319402, upload-time = "2025-05-21T16:18:18.097Z" }, - { url = "https://files.pythonhosted.org/packages/55/40/c23dd5726107cbbc5e698b3fcca5ffac83d29146ef469f27f5277d18c2d7/bitarray-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ba15725cd9040b9b1b2650edb33253cb2ba7b68d087974e296e5ff082198952f", size = 299456, upload-time = "2025-05-21T16:18:20.029Z" }, - { url = "https://files.pythonhosted.org/packages/21/31/6bfd9fda776f8d98512d5484fcb55fbb25e60796e7b5d3b9a3a300e8bc1c/bitarray-3.4.2-cp310-cp310-win32.whl", hash = "sha256:2959dfc61d963546e97220cfcaab7dfc489276c6e00092b57710522e68712b28", size = 134279, upload-time = "2025-05-21T16:18:21.609Z" }, - { url = "https://files.pythonhosted.org/packages/82/9d/7067f6548b470beb86d83f7ac6c45cac3b9c28cf77fa0f9f3e67353d69d3/bitarray-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:97077fa0ec3b7eed57cd8d1cb0eb75d670423d20b7e4901482347a81efe2f6fd", size = 141360, upload-time = "2025-05-21T16:18:23.197Z" }, - { url = "https://files.pythonhosted.org/packages/94/ba/508ba6a3ea16eb6c21baae33cd1b7bf6e299d21a496a1f90b8203a22d6d0/bitarray-3.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90ca8e260b75a7ac0c542093e5f29154e51fd0d2d0fa5041c038cb2b58415eeb", size = 141425, upload-time = "2025-05-21T16:18:24.452Z" }, - { url = "https://files.pythonhosted.org/packages/eb/a1/44d9b88cd3daee3734ea98dac691acc2c935a3bfbd5bfc38267a59bd986d/bitarray-3.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549dabcae78fb8f9133e3138b9473c7648d6054bb6fec84d28d3861aaec5ddd1", size = 138172, upload-time = "2025-05-21T16:18:25.601Z" }, - { url = "https://files.pythonhosted.org/packages/5f/aa/5a8c33ab39e8a894978d42427ad0a1ba2d5c9cb61c8480101be555c0e3a7/bitarray-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3da536ac84e6911cbc8e86be0baf1cab0d4f4ccb80c0f39b4fa28509f2db1a", size = 313373, upload-time = "2025-05-21T16:18:26.796Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/b0d28e21d91ec5c0477a320b9443096ddc816fbc59778b367f9e49094532/bitarray-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a5e84d6b737de2d773ab1bd538e6f37fa7f667ea734f00a48d9a973b181c751", size = 329657, upload-time = "2025-05-21T16:18:28.097Z" }, - { url = "https://files.pythonhosted.org/packages/bd/d5/1f858bd559568286435a460e7a169a5185b2b29184684e6c6fa303af3ca9/bitarray-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e265c5eede8316ba64bb6029832f282f6284a557b625bb3207a7680fd5da7925", size = 321873, upload-time = "2025-05-21T16:18:29.511Z" }, - { url = "https://files.pythonhosted.org/packages/e8/c8/23df4174142cccf6a8bd114651b8e9bf965005ab1ef741d37c9f72e8d2eb/bitarray-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63fb45c60c7ab7a724aa64203305e56f344489e12d41619bdc9d7887d6562e01", size = 314796, upload-time = "2025-05-21T16:18:31.2Z" }, - { url = "https://files.pythonhosted.org/packages/8f/21/329178b165f1aaf3f2ace3eb24aca5ad197febae908d7b41e552a69043e9/bitarray-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:083c2a9234dacf3e4e166a5844256da2a397941d3f6397e5b919bffca638f6ef", size = 302724, upload-time = "2025-05-21T16:18:32.729Z" }, - { url = "https://files.pythonhosted.org/packages/26/a8/a66d3c0d3410d01f51824f8476b060f96b3353db7d6b45c87dba6d1aa0e0/bitarray-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e72606adb2438002873cb0e8e81c3fce926386a59bbafa82fea07cdb2a6d8a05", size = 307434, upload-time = "2025-05-21T16:18:34.394Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ac/3052386e7ff80c80eb2549a22c890f511e9f9f7fbbe6244b04255adae031/bitarray-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dc994d22a3a563e1d402dc2f64c61e60605a1a3e66dd8aea7636f607b99f03cb", size = 299232, upload-time = "2025-05-21T16:18:35.708Z" }, - { url = "https://files.pythonhosted.org/packages/9d/46/91a32ccd39d40371ed7404d96a6f3cf1e381eaf36be5390c6bff5034f344/bitarray-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:214468391680ba1c831872a7949f1b563ab3cd832d10adc52df4f36e0af24446", size = 324056, upload-time = "2025-05-21T16:18:37.536Z" }, - { url = "https://files.pythonhosted.org/packages/39/0e/cb824f0e0302cd08809f67b35b3ae21b47af5dd122e99740bfe6bde1c824/bitarray-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c7483b97807bb018a7cd7f9741800c714c9c56ba4e5a7e962c5f956c4b858f3c", size = 327058, upload-time = "2025-05-21T16:18:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/09/01/845e977d490e4e261179785540d1fdeff966c99296f503adc0e5407fc257/bitarray-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5774bf14ec451d5ac311cfcfe0b0cf2a1a9fa74b6ca81dfbc4f56a98872a5541", size = 306629, upload-time = "2025-05-21T16:18:40.211Z" }, - { url = "https://files.pythonhosted.org/packages/29/ef/33ee8533ff1b2a8cd0b9e84fd81b2a90d66c2774544c861e281c5361eaa2/bitarray-3.4.2-cp311-cp311-win32.whl", hash = "sha256:e6f35567347ddb8b9e8b6bf6ab7d64be88bdb6b6c107b8edbb2c3d426c1590a0", size = 134450, upload-time = "2025-05-21T16:18:42.435Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/069c255d067319a9695c93369641d7f5539625069c1cf3ded2becff1bfbc/bitarray-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae5b0a8d3caf6284220232738dc7c05af81ec3a9f93d4a462295462dd0a492b2", size = 141596, upload-time = "2025-05-21T16:18:43.743Z" }, - { url = "https://files.pythonhosted.org/packages/05/57/0b2b50eb3f50c3144f705d0994171f17fda00ee3a72d563ba764ea235f66/bitarray-3.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a0e498563e0eefa96a1b92461d083de11256f6510b7706d5f2e6473cd9b7137a", size = 141191, upload-time = "2025-05-21T16:18:45.436Z" }, - { url = "https://files.pythonhosted.org/packages/81/c3/1d9ce4d0041c10ce90d924b8cea63afdda84a64623179045c0c67998922c/bitarray-3.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:114870ab71a0ebdac211aa0a120a54206c333b74b99fdf4b58fbe904979e1fef", size = 138158, upload-time = "2025-05-21T16:18:46.685Z" }, - { url = "https://files.pythonhosted.org/packages/5d/dd/a8653dac671ba97b1c68ee73b08a0eb2042f24e5e31f51b86afc09588c06/bitarray-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fbf6121978cba4313c31f7cc5961e481242def2b8ddfea34ca27ba9da52c9c1", size = 315834, upload-time = "2025-05-21T16:18:47.926Z" }, - { url = "https://files.pythonhosted.org/packages/3d/a2/30547bea0a35f9f953e99f5157749d56304d3f3a96b01a982dd604a9dc48/bitarray-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:423bb4e1bec0bc5d63969e12bcc5cc0081cc5aec4d7b62a6cd8240342aa36107", size = 331317, upload-time = "2025-05-21T16:18:49.169Z" }, - { url = "https://files.pythonhosted.org/packages/2d/b9/1789476280f46455a9a30bcd252fda6fd995583d97d1b919ec0296393e2a/bitarray-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ef80a96487c82477e8def69a58a218491794f7989b3e191cbaaa7b450315a5c", size = 324416, upload-time = "2025-05-21T16:18:50.917Z" }, - { url = "https://files.pythonhosted.org/packages/84/89/519c829ca641a3e7b8c9be56d177aaa05572b7e15e4298df4a77959b6a1e/bitarray-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35f5c69a79047e50bc1d54a777541b0a86b213e23559b1ac3d76fa9a42cc5522", size = 317634, upload-time = "2025-05-21T16:18:52.718Z" }, - { url = "https://files.pythonhosted.org/packages/0d/39/ebb6a6539261279c0994836b40b99384fa5e27ec239e70b203e310343f80/bitarray-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:002f7b128ed9d18d3ecb51ca78aeea5afffbe8e80d6be4ff2984d045b1c4b937", size = 305392, upload-time = "2025-05-21T16:18:54.888Z" }, - { url = "https://files.pythonhosted.org/packages/83/04/0ee0d57b2a60fdf881346f196fd92b824f44f4736026da1d8c7970745266/bitarray-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:999bccc72704afcf4a3d9868db4d149c032cdf910f9f7d91e30166978530af7f", size = 309740, upload-time = "2025-05-21T16:18:56.76Z" }, - { url = "https://files.pythonhosted.org/packages/f6/39/5ab0339e93097f2a2631ea281a6386c31707011499d5cf68b4e0e37ba124/bitarray-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2e44cfe2bc161cde3b11604f279e3048ef7bd3413837aadbd2ca30b5233c82cb", size = 301607, upload-time = "2025-05-21T16:18:58.144Z" }, - { url = "https://files.pythonhosted.org/packages/e8/bb/b8f697ba6a16c1e393afe75029d069e2dd457e62b112c3cb26768d2e65eb/bitarray-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f408ba3e6f706a0eabae405d1906ceb539f34a318562a91ab9799c5e1712e18c", size = 325942, upload-time = "2025-05-21T16:18:59.471Z" }, - { url = "https://files.pythonhosted.org/packages/64/ec/77d866a96909c09c5a34f1716f015386f9d9bbbf4b5dc7219f642b8043e2/bitarray-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bf94513ae559b2525e6218e41b03790f866d75df5404490420f2c25e42cf55e7", size = 329491, upload-time = "2025-05-21T16:19:01.205Z" }, - { url = "https://files.pythonhosted.org/packages/37/6e/633b7d392a39df655c92035da9ee52f7332bb165ae72038692a33a6def6c/bitarray-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f2c88c792815d2755c49a3a1fca256e142c4adfadf1a2142b5a3a37e4d4b871", size = 309566, upload-time = "2025-05-21T16:19:02.762Z" }, - { url = "https://files.pythonhosted.org/packages/ab/38/9d7ad6eca72e09b81097176dd66eed3aeaabdea4c24cf6ce25609599ce7b/bitarray-3.4.2-cp312-cp312-win32.whl", hash = "sha256:f4dac6b942c4d7ae5f6eb555ee3993de1432bf9c8f46e3caf74b6671ac5571a3", size = 134600, upload-time = "2025-05-21T16:19:04.057Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d3/c83ec3d912be73861a064f1a705436f270b8c5b5926350a875bd6c06b6df/bitarray-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:6c37e6814633041307f0df281651a86372b0ccdb1e4768247a87e83e2b68f9b9", size = 141844, upload-time = "2025-05-21T16:19:05.254Z" }, - { url = "https://files.pythonhosted.org/packages/f2/22/973d377477e1f27cf64f9e3292343219577136e32665a52667589380100d/bitarray-3.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:16263bdbb05ce379e7b8e9a9f3e0a61a9204a06a037bbc91322d2939b3079fd5", size = 141162, upload-time = "2025-05-21T16:19:06.488Z" }, - { url = "https://files.pythonhosted.org/packages/eb/53/65541b94fb6df1e8aa9a7359ac68f469c3243d8bc7302c5fb8ff8936dab2/bitarray-3.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:41fdc6fb8c3aabfcfe0073302c69fef0c74d6499491f133ba58755c3f2afb3d0", size = 138162, upload-time = "2025-05-21T16:19:07.688Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b2/83d587965f7969a5016a5bf5c9295a0651a34b668df41fa089d7c924ac08/bitarray-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c2571337b11c69206e339170516f3e72b4ec16250876c4f2bbb6e82b9caa15", size = 315760, upload-time = "2025-05-21T16:19:09.834Z" }, - { url = "https://files.pythonhosted.org/packages/4f/f5/2b2924181809debdb644143aa33d16facdce5763d5ff17e5301ecdaf89dc/bitarray-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0e3d5f37217dde9b206418c37c4d86e173f072a892670e9714e6bb20b228e95", size = 331250, upload-time = "2025-05-21T16:19:11.449Z" }, - { url = "https://files.pythonhosted.org/packages/00/2b/8ed4eeb947e05ef54614feff4cc4badd03e29ec35d46aa0218513cc9f8ac/bitarray-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83202735f21fc781f27228daeae94b6c7df1a9f673b9dd6a1c0b3764d92b8e50", size = 324299, upload-time = "2025-05-21T16:19:13.236Z" }, - { url = "https://files.pythonhosted.org/packages/05/27/d7f1b15c079cbeffad76f97c41c27635873be4d5600f6896b2bbc4f5caff/bitarray-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b3f8c35812d85a299d6c0ff097f93e18dfb7a324c129e20a4ec0ecfc4ba995", size = 317522, upload-time = "2025-05-21T16:19:14.832Z" }, - { url = "https://files.pythonhosted.org/packages/a5/db/e6a857a23222360dbc0b0d177e6060ecd88d63a1d6a3c2b52333c21a9683/bitarray-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef3f2e8ba5d6e0f38b57960d1bfb72aa9e2115f7cdca48561fadced652798d49", size = 305290, upload-time = "2025-05-21T16:19:16.57Z" }, - { url = "https://files.pythonhosted.org/packages/16/12/3b945e415233889c57c26f95a9a6a245da546e2c8d1de09991332cb796ff/bitarray-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:508ec6547bdd9f0c435c322fbb127a3dfd74c943a6c7f77fa5dfcb3e9ce1de66", size = 309764, upload-time = "2025-05-21T16:19:18.34Z" }, - { url = "https://files.pythonhosted.org/packages/6c/0e/9effb83e23ef5495c9078bdbac948df4fe2b202fb0ac5b33412848ab4b1e/bitarray-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1a3a08cc920f601258ea33d97b4454cd7cb04d17930e0a3bc7328ba3d732f8b0", size = 301690, upload-time = "2025-05-21T16:19:19.694Z" }, - { url = "https://files.pythonhosted.org/packages/cb/67/9a73476c8cd6a67ff5ab9c5c1d916307e4fb9178d76ee2781552451c995c/bitarray-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:60189130ae1ebaadbab27e3ad0a7d7ed44f5d9456bbfae07c72138501ce59053", size = 326049, upload-time = "2025-05-21T16:19:21.371Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b1/2a81f5f96c1ccc033d8c63b4584aedbd9e27499cf2276fc70d4f87ad673b/bitarray-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9e425eaf21a8d7b76531630029441c6d61f6064cbf4dd592af1607c79eb2e4d0", size = 329565, upload-time = "2025-05-21T16:19:22.88Z" }, - { url = "https://files.pythonhosted.org/packages/2e/30/670efe7771944b4b7d0aacdc076969adc9428c9d0939ee70230bdf4c8aed/bitarray-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:952cc40c593f663ba083be76d1ccdb6dc9dafab8fb6d949056405636b2e720f3", size = 309661, upload-time = "2025-05-21T16:19:24.574Z" }, - { url = "https://files.pythonhosted.org/packages/ee/2e/b2d8e842fe484d7d18fcd137289e396c7784b8484e0ec7e94ffe4bb7e8f9/bitarray-3.4.2-cp313-cp313-win32.whl", hash = "sha256:158f6b1a315eaf971f88e66f9b93431c3b580b46d2121c6a1166e7b761408fdf", size = 134614, upload-time = "2025-05-21T16:19:25.914Z" }, - { url = "https://files.pythonhosted.org/packages/0c/50/0ec25a51197410a66146eea7950e3597baedb000f2f2e2458bb6d5306b0a/bitarray-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:2d24658ac96a82beb4da2f5c71bef9790f3dcabadbe8ead8dda742ab207fe2f9", size = 141851, upload-time = "2025-05-21T16:19:27.388Z" }, - { url = "https://files.pythonhosted.org/packages/e7/03/77eca3d93f162c0982f370e6459d1fcb6ff51e84f80adb34c43256653bda/bitarray-3.4.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9c02f3234b1ec391aa235b265a3649e8078d814cdd6b42bc5aee267cc370b0c8", size = 135778, upload-time = "2025-05-21T16:20:58.492Z" }, - { url = "https://files.pythonhosted.org/packages/68/fd/5b148fb07e2b74e1cd17db7b940abdb1c7af6ac3a024810a5931db6e436b/bitarray-3.4.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:e19e5a35f53c0eaf4516cfa3f80de110eb831fd3d9785aa8b8f4a8a8c0d99523", size = 132826, upload-time = "2025-05-21T16:21:00.901Z" }, - { url = "https://files.pythonhosted.org/packages/e5/50/8cfb459218cd074a3af7121f6509ac55be2d6ac5a0a048b188934976f589/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f633d1e92fdc6a039b118d67f23d17b9ac4046a629bde04e178b770fe83a618f", size = 141592, upload-time = "2025-05-21T16:21:02.4Z" }, - { url = "https://files.pythonhosted.org/packages/43/c0/a70a212ecfd4256e7281456beee5330945ea09cec8fb0be3f99ed6828a08/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c08bc2ec3f15fbb3a99923ef1b16b621af45ab9d5146a06f970c0f0d7cab22ba", size = 142502, upload-time = "2025-05-21T16:21:08.366Z" }, - { url = "https://files.pythonhosted.org/packages/1e/8e/9fc84001701ef1fd7f18b0254bf08d594adaed34fe0b5770d8c032b4d53a/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eed46fa39af8440b1cff09a9805d65449583d524006efa29e5262bea9e08787e", size = 143930, upload-time = "2025-05-21T16:21:09.819Z" }, - { url = "https://files.pythonhosted.org/packages/f7/05/2f6753d75282033e66e0a9626ef4209500cd7a08aa8f92cc70fa49681cf3/bitarray-3.4.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9cf23c13c84c1559ed28bd211a6290b7326c2011f6c30c82cee052b254ac09f0", size = 140275, upload-time = "2025-05-21T16:21:11.481Z" }, -] - -[[package]] -name = "blinker" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, -] - -[[package]] -name = "certifi" -version = "2025.4.26" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9b/892a8c8af9110935e5adcbb06d9c6fe741b6bb02608c6513983048ba1a18/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd", size = 144649, upload-time = "2025-05-02T08:31:48.889Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a5/4179abd063ff6414223575e008593861d62abfc22455b5d1a44995b7c101/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6", size = 155045, upload-time = "2025-05-02T08:31:50.757Z" }, - { url = "https://files.pythonhosted.org/packages/3b/95/bc08c7dfeddd26b4be8c8287b9bb055716f31077c8b0ea1cd09553794665/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d", size = 147356, upload-time = "2025-05-02T08:31:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/7a5b635aa65284bf3eab7653e8b4151ab420ecbae918d3e359d1947b4d61/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86", size = 149471, upload-time = "2025-05-02T08:31:56.207Z" }, - { url = "https://files.pythonhosted.org/packages/ae/38/51fc6ac74251fd331a8cfdb7ec57beba8c23fd5493f1050f71c87ef77ed0/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c", size = 151317, upload-time = "2025-05-02T08:31:57.613Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/edee1e32215ee6e9e46c3e482645b46575a44a2d72c7dfd49e49f60ce6bf/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0", size = 146368, upload-time = "2025-05-02T08:31:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/26/2c/ea3e66f2b5f21fd00b2825c94cafb8c326ea6240cd80a91eb09e4a285830/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef", size = 154491, upload-time = "2025-05-02T08:32:01.219Z" }, - { url = "https://files.pythonhosted.org/packages/52/47/7be7fa972422ad062e909fd62460d45c3ef4c141805b7078dbab15904ff7/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6", size = 157695, upload-time = "2025-05-02T08:32:03.045Z" }, - { url = "https://files.pythonhosted.org/packages/2f/42/9f02c194da282b2b340f28e5fb60762de1151387a36842a92b533685c61e/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366", size = 154849, upload-time = "2025-05-02T08:32:04.651Z" }, - { url = "https://files.pythonhosted.org/packages/67/44/89cacd6628f31fb0b63201a618049be4be2a7435a31b55b5eb1c3674547a/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db", size = 150091, upload-time = "2025-05-02T08:32:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/1f/79/4b8da9f712bc079c0f16b6d67b099b0b8d808c2292c937f267d816ec5ecc/charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a", size = 98445, upload-time = "2025-05-02T08:32:08.66Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d7/96970afb4fb66497a40761cdf7bd4f6fca0fc7bafde3a84f836c1f57a926/charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509", size = 105782, upload-time = "2025-05-02T08:32:10.46Z" }, - { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" }, - { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" }, - { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" }, - { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" }, - { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" }, - { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, -] - -[[package]] -name = "ckzg" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/55/df/f6db8e83bd4594c1ea685cd37fb81d5399e55765aae16d1a8a9502598f4e/ckzg-2.1.1.tar.gz", hash = "sha256:d6b306b7ec93a24e4346aa53d07f7f75053bc0afc7398e35fa649e5f9d48fcc4", size = 1120500, upload-time = "2025-03-31T21:24:12.324Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/4b/cd25e857cdf46a752e97c530fe2582fae77c4d16c29fff5a15b7a998e2fd/ckzg-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b9825a1458219e8b4b023012b8ef027ef1f47e903f9541cbca4615f80132730", size = 116377, upload-time = "2025-03-31T21:22:26.952Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bc/5dfef36589545f797245ecacb54ed2acfa75507f63cfe12182d1277a88f1/ckzg-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2a40a3ba65cca4b52825d26829e6f7eb464aa27a9e9efb6b8b2ce183442c741", size = 100208, upload-time = "2025-03-31T21:22:28.04Z" }, - { url = "https://files.pythonhosted.org/packages/b7/52/96f0e3affbed321dc52b9b4ca13e0fb594da572d1f8edc47378fe48d8e9a/ckzg-2.1.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1d753fbe85be7c21602eddc2d40e0915e25fce10329f4f801a0002a4f886cc7", size = 174800, upload-time = "2025-03-31T21:22:29.719Z" }, - { url = "https://files.pythonhosted.org/packages/dc/21/b1bc07cc8e5ed32817e89b054e2399d38775d92ff2d55e24bf233f537c02/ckzg-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d76b50527f1d12430bf118aff6fa4051e9860eada43f29177258b8d399448ea", size = 160847, upload-time = "2025-03-31T21:22:30.973Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5a/97b173d4ff9bce798031beb12b340c4f1729eaaddd07f69f368f843db28e/ckzg-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44c8603e43c021d100f355f50189183135d1df3cbbddb8881552d57fbf421dde", size = 169712, upload-time = "2025-03-31T21:22:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/7b/52/48be78c07f362438e189e2fbea7df8543290c3ee99845442549c8dc5405b/ckzg-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:38707a638c9d715b3c30b29352b969f78d8fc10faed7db5faf517f04359895c0", size = 172942, upload-time = "2025-03-31T21:22:32.8Z" }, - { url = "https://files.pythonhosted.org/packages/13/42/3cfcd6cbdfb9030b9071d5e413a458f93883e47ad4a7d8d4c1d57608e57d/ckzg-2.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:52c4d257bdcbe822d20c5cd24c8154ec5aac33c49a8f5a19e716d9107a1c8785", size = 187707, upload-time = "2025-03-31T21:22:33.673Z" }, - { url = "https://files.pythonhosted.org/packages/eb/54/d43bc3a2de486fb8be29ffedc3ec80f5726765ee4fa78beabe2ab2440f93/ckzg-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1507f7bfb9bcf51d816db5d8d0f0ed53c8289605137820d437b69daea8333e16", size = 182505, upload-time = "2025-03-31T21:22:34.563Z" }, - { url = "https://files.pythonhosted.org/packages/21/43/5bcd2b7630732b532006572fbb8d64a29f69530c630ae4811167a2a0dc3b/ckzg-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d02eaaf4f841910133552b3a051dea53bcfe60cd98199fc4cf80b27609d8baa2", size = 98822, upload-time = "2025-03-31T21:22:35.786Z" }, - { url = "https://files.pythonhosted.org/packages/95/2c/44120b2d9dcb0246d67a1f28b9eaa625c499014d4d42561467e28eedd285/ckzg-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:465e2b71cf9dc383f66f1979269420a0da9274a3a9e98b1a4455e84927dfe491", size = 116378, upload-time = "2025-03-31T21:22:36.96Z" }, - { url = "https://files.pythonhosted.org/packages/23/88/c5b89ba9a730fee5e089be9e0c7048fb6707c1a0e4b6c30fcf725c3eef44/ckzg-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ee2f26f17a64ad0aab833d637b276f28486b82a29e34f32cf54b237b8f8ab72d", size = 100202, upload-time = "2025-03-31T21:22:37.799Z" }, - { url = "https://files.pythonhosted.org/packages/ee/11/b0a473e80346db52ad9a629bc9fd8f773c718ed78932ea3a70392306ffc3/ckzg-2.1.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99cc2c4e9fb8c62e3e0862c7f4df9142f07ba640da17fded5f6e0fd09f75909f", size = 175595, upload-time = "2025-03-31T21:22:39.013Z" }, - { url = "https://files.pythonhosted.org/packages/52/fa/17a7e125d07a96dd6dce4db7262231f7583856b2be5d5b7df59e04bfa188/ckzg-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773dd016693d74aca1f5d7982db2bad7dde2e147563aeb16a783f7e5f69c01fe", size = 161681, upload-time = "2025-03-31T21:22:40.257Z" }, - { url = "https://files.pythonhosted.org/packages/57/bd/46d6b90bf53da732f9adab7593d132a0834ed4f2f7659b4c7414d8f78d39/ckzg-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af2b2144f87ba218d8db01382a961b3ecbdde5ede4fa0d9428d35f8c8a595ba", size = 170471, upload-time = "2025-03-31T21:22:41.513Z" }, - { url = "https://files.pythonhosted.org/packages/9d/98/113c7704749d037d75f23240ffc5c46dfe8416de574b946438587835715f/ckzg-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f55e63d3f7c934a2cb53728ed1d815479e177aca8c84efe991c2920977cff6", size = 173595, upload-time = "2025-03-31T21:22:42.534Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d5/05fca6dcb5a19327be491157794eafc3d7498daf615c2ff5a5b745852945/ckzg-2.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ecb42aaa0ffa427ff14a9dde9356ba69e5ae6014650b397af55b31bdae7a9b6e", size = 188417, upload-time = "2025-03-31T21:22:43.466Z" }, - { url = "https://files.pythonhosted.org/packages/72/36/131ae2dfc82d0fdc98fae8e3bbfe71ff14265bb434b23bd07b585afc6d61/ckzg-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5a01514239f12fb1a7ad9009c20062a4496e13b09541c1a65f97e295da648c70", size = 183286, upload-time = "2025-03-31T21:22:44.732Z" }, - { url = "https://files.pythonhosted.org/packages/c5/6a/d371b27024422b25228fc11fa57b1ba7756a94cc9fb0c75da292c235fdaa/ckzg-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:6516b9684aae262c85cf7fddd8b585b8139ad20e08ec03994e219663abbb0916", size = 98819, upload-time = "2025-03-31T21:22:45.57Z" }, - { url = "https://files.pythonhosted.org/packages/93/a1/9c07513dd0ea01e5db727e67bd2660f3b300a4511281cdb8d5e04afa1cfd/ckzg-2.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c60e8903344ce98ce036f0fabacce952abb714cad4607198b2f0961c28b8aa72", size = 116421, upload-time = "2025-03-31T21:22:46.434Z" }, - { url = "https://files.pythonhosted.org/packages/27/04/b69a0dfbb2722a14c98a52973f276679151ec56a14178cb48e6f2e1697bc/ckzg-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4299149dd72448e5a8d2d1cc6cc7472c92fc9d9f00b1377f5b017c089d9cd92", size = 100216, upload-time = "2025-03-31T21:22:47.633Z" }, - { url = "https://files.pythonhosted.org/packages/2e/24/9cc850d0b8ead395ad5064de67c7c91adacaf31b6b35292ab53fbd93270b/ckzg-2.1.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:025dd31ffdcc799f3ff842570a2a6683b6c5b01567da0109c0c05d11768729c4", size = 175764, upload-time = "2025-03-31T21:22:48.768Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c1/eb13ba399082a98b932f10b230ec08e6456051c0ce3886b3f6d8548d11ab/ckzg-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b42ab8385c273f40a693657c09d2bba40cb4f4666141e263906ba2e519e80bd", size = 161885, upload-time = "2025-03-31T21:22:50.05Z" }, - { url = "https://files.pythonhosted.org/packages/57/c7/58baa64199781950c5a8c6139a46e1acff0f057a36e56769817400eb87fb/ckzg-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be3890fc1543f4fcfc0063e4baf5c036eb14bcf736dabdc6171ab017e0f1671", size = 170757, upload-time = "2025-03-31T21:22:51.282Z" }, - { url = "https://files.pythonhosted.org/packages/65/bd/4b8e1c70972c98829371b7004dc750a45268c5d3442d602e1b62f13ca867/ckzg-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b754210ded172968b201e2d7252573af6bf52d6ad127ddd13d0b9a45a51dae7b", size = 173761, upload-time = "2025-03-31T21:22:52.6Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/c3fd1002f97ba3e0c5b1d9ab2c8fb7a6f475fa9b80ed9c4fa55975501a54/ckzg-2.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2f8fda87865897a269c4e951e3826c2e814427a6cdfed6731cccfe548f12b36", size = 188666, upload-time = "2025-03-31T21:22:53.47Z" }, - { url = "https://files.pythonhosted.org/packages/e2/d9/91cf5a8169ee60c9397c975163cbca34432571f94facec5f8c0086bb47d8/ckzg-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:98e70b5923d77c7359432490145e9d1ab0bf873eb5de56ec53f4a551d7eaec79", size = 183652, upload-time = "2025-03-31T21:22:54.351Z" }, - { url = "https://files.pythonhosted.org/packages/25/d4/8c9f6b852f99926862344b29f0c59681916ccfec2ac60a85952a369e0bca/ckzg-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:42af7bde4ca45469cd93a96c3d15d69d51d40e7f0d30e3a20711ebd639465fcb", size = 98816, upload-time = "2025-03-31T21:22:55.23Z" }, - { url = "https://files.pythonhosted.org/packages/b7/9a/fa698b12e97452d11dd314e0335aae759725284ef6e1c1665aed56b1cd3e/ckzg-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e4edfdaf87825ff43b9885fabfdea408737a714f4ce5467100d9d1d0a03b673", size = 116426, upload-time = "2025-03-31T21:22:56.108Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/8cccd308bd11b49b40eecad6900b5769da117951cac33e880dd25e851ef7/ckzg-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:815fd2a87d6d6c57d669fda30c150bc9bf387d47e67d84535aa42b909fdc28ea", size = 100219, upload-time = "2025-03-31T21:22:56.982Z" }, - { url = "https://files.pythonhosted.org/packages/30/0e/63573d816c1292b9a4d70eb6a7366b3593d29a977794039e926805a76ca0/ckzg-2.1.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32466e809b1ab3ff01d3b0bb0b9912f61dcf72957885615595f75e3f7cc10e5", size = 175725, upload-time = "2025-03-31T21:22:58.213Z" }, - { url = "https://files.pythonhosted.org/packages/86/f6/a279609516695ad3fb8b201098c669ba3b2844cbf4fa0d83a0f02b9bb29b/ckzg-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f11b73ccf37b12993f39a7dbace159c6d580aacacde6ee17282848476550ddbc", size = 161835, upload-time = "2025-03-31T21:22:59.448Z" }, - { url = "https://files.pythonhosted.org/packages/39/e4/8cf7aef7dc05a777cb221e94046f947c6fe5317159a8dae2cd7090d52ef2/ckzg-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3b9433a1f2604bd9ac1646d3c83ad84a850d454d3ac589fe8e70c94b38a6b0", size = 170759, upload-time = "2025-03-31T21:23:01.022Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/b34e3c08eb36bc67e338b114f289b2595e581b8bdc09a8f12299a1db5d2f/ckzg-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b7d7e1b5ea06234558cd95c483666fd785a629b720a7f1622b3cbffebdc62033", size = 173787, upload-time = "2025-03-31T21:23:01.974Z" }, - { url = "https://files.pythonhosted.org/packages/2e/f0/aff87c3ed80713453cb6c84fe6fbb7582d86a7a5e4460fda2a497d47f489/ckzg-2.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9f5556e6675866040cc4335907be6c537051e7f668da289fa660fdd8a30c9ddb", size = 188722, upload-time = "2025-03-31T21:23:02.966Z" }, - { url = "https://files.pythonhosted.org/packages/44/d9/1f08bfb8fd1cbb8c7513e7ad3fb76bbb5c3fb446238c1eba582276e4d905/ckzg-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55b2ba30c5c9daac0c55f1aac851f1b7bf1f7aa0028c2db4440e963dd5b866d6", size = 183686, upload-time = "2025-03-31T21:23:03.905Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ff/434f6d2893cbdfad00c20d17e9a52d426ca042f5e980d5c3db96bc6b6e15/ckzg-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:10d201601fc8f28c0e8cec3406676797024dd374c367bbeec5a7a9eac9147237", size = 98817, upload-time = "2025-03-31T21:23:05.2Z" }, - { url = "https://files.pythonhosted.org/packages/30/b3/a0c7d7ba6e669cf04605dc0329173db62fc1fe3c488761755cc01e5e1b4d/ckzg-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:375918e25eafb9bafe5215ab91698504cba3fe51b4fe92f5896af6c5663f50c6", size = 113191, upload-time = "2025-03-31T21:23:40.646Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b9/a6cf403b8528d18d7d9154e28381a397bf466c86aa8e0b3327cffdde5749/ckzg-2.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:38b3b7802c76d4ad015db2b7a79a49c193babae50ee5f77e9ac2865c9e9ddb09", size = 96207, upload-time = "2025-03-31T21:23:41.596Z" }, - { url = "https://files.pythonhosted.org/packages/63/6b/5ddd713d97886becb8450e3e13db891199125f722366d30d087ad5438390/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438a5009fd254ace0bc1ad974d524547f1a41e6aa5e778c5cd41f4ee3106bcd6", size = 126160, upload-time = "2025-03-31T21:23:42.553Z" }, - { url = "https://files.pythonhosted.org/packages/c7/dd/e05aecc01e62108a7579f8df5e5d38536841f50e12172f8a84677edac0fa/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce11cc163a2e0dab3af7455aca7053f9d5bb8d157f231acc7665fd230565d48", size = 102811, upload-time = "2025-03-31T21:23:43.494Z" }, - { url = "https://files.pythonhosted.org/packages/c6/81/6cdadd8626ac11290af3f58ae5dcffe38bd2c8f8c798dacee7475e244aac/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b53964c07f6a076e97eaa1ef35045e935d7040aff14f80bae7e9105717702d05", size = 111328, upload-time = "2025-03-31T21:23:44.449Z" }, - { url = "https://files.pythonhosted.org/packages/36/b7/b129ff6955cd264c6ab3dbd52dd1b2759d1b121c09c03f9991e4c722c72f/ckzg-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cf085f15ae52ab2599c9b5a3d5842794bcf5613b7f58661fbfb0c5d9eac988b9", size = 98846, upload-time = "2025-03-31T21:23:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ba/7d9c1f9cec7e0e382653c72165896194a05743e589b1dae2aa80236aa87f/ckzg-2.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4b0c850bd6cad22ac79b2a2ab884e0e7cd2b54a67d643cd616c145ebdb535a11", size = 113188, upload-time = "2025-03-31T21:23:46.337Z" }, - { url = "https://files.pythonhosted.org/packages/2f/92/9728f5ccc1c5e87c6c5ae7941250a447b61fd5a63aadbc15249e29c21bcf/ckzg-2.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:26951f36bb60c9150bbd38110f5e1625596f9779dad54d1d492d8ec38bc84e3a", size = 96208, upload-time = "2025-03-31T21:23:47.255Z" }, - { url = "https://files.pythonhosted.org/packages/39/63/5e27d587bd224fee70cb66b022e7c4ef95d0e091e08ee76c25ec12094b0d/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbe12445e49c4bee67746b7b958e90a973b0de116d0390749b0df351d94e9a8c", size = 126158, upload-time = "2025-03-31T21:23:48.195Z" }, - { url = "https://files.pythonhosted.org/packages/43/98/e0a45946575a7b823d8ee0b47afb104b6017e54e1208f07da2529bc01900/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c5d4f66f09de4a99271acac74d2acb3559a77de77a366b34a91e99e8822667", size = 102812, upload-time = "2025-03-31T21:23:49.16Z" }, - { url = "https://files.pythonhosted.org/packages/cb/50/718ca7b03e4b89b18cdf99cc3038050105b0acbf9b612c23cd513093c6de/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42673c1d007372a4e8b48f6ef8f0ce31a9688a463317a98539757d1e2fb1ecc7", size = 111327, upload-time = "2025-03-31T21:23:50.126Z" }, - { url = "https://files.pythonhosted.org/packages/29/c5/80e5a0c6967d02d801150104320484a258e5a49bd191e198643e74039320/ckzg-2.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:57a7dc41ec6b69c1d9117eb61cf001295e6b4f67a736020442e71fb4367fb1a5", size = 98847, upload-time = "2025-03-31T21:23:51.084Z" }, -] - -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "cytoolz" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "toolz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/f9/3243eed3a6545c2a33a21f74f655e3fcb5d2192613cd3db81a93369eb339/cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6", size = 626652, upload-time = "2024-12-13T05:47:36.672Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d9/f13d66c16cff1fa1cb6c234698029877c456f35f577ef274aba3b86e7c51/cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042", size = 403515, upload-time = "2024-12-13T05:44:27.845Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2d/4cdf848a69300c7d44984f2ebbebb3b8576e5449c8dea157298f3bdc4da3/cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608", size = 383936, upload-time = "2024-12-13T05:44:29.5Z" }, - { url = "https://files.pythonhosted.org/packages/72/a4/ccfdd3f0ed9cc818f734b424261f6018fc61e3ec833bf85225a9aca0d994/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90124bdc42ff58b88cdea1d24a6bc5f776414a314cc4d94f25c88badb3a16d1", size = 1934569, upload-time = "2024-12-13T05:44:30.799Z" }, - { url = "https://files.pythonhosted.org/packages/50/fc/38d5344fa595683ad10dc819cfc1d8b9d2b3391ccf3e8cb7bab4899a01f5/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e74801b751e28f7c5cc3ad264c123954a051f546f2fdfe089f5aa7a12ccfa6da", size = 2015129, upload-time = "2024-12-13T05:44:32.297Z" }, - { url = "https://files.pythonhosted.org/packages/28/29/75261748dc54a20a927f33641f4e9aac674cfc6d3fbd4f332e10d0b37639/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582dad4545ddfb5127494ef23f3fa4855f1673a35d50c66f7638e9fb49805089", size = 2000506, upload-time = "2024-12-13T05:44:34.403Z" }, - { url = "https://files.pythonhosted.org/packages/00/ae/e4ead004cc2698281d153c4a5388638d67cdb5544d6d6cc1e5b3db2bd2a3/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7bd0618e16efe03bd12f19c2a26a27e6e6b75d7105adb7be1cd2a53fa755d8", size = 1957537, upload-time = "2024-12-13T05:44:39.499Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ff/4f3aa07f4f47701f7f63df60ce0a5669fa09c256c3d4a33503a9414ea5cc/cytoolz-1.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d74cca6acf1c4af58b2e4a89cc565ed61c5e201de2e434748c93e5a0f5c541a5", size = 1863331, upload-time = "2024-12-13T05:44:42.61Z" }, - { url = "https://files.pythonhosted.org/packages/a2/29/654f57f2a9b8e9765a4ab876765f64f94530b61fc6471a07feea42ece6d4/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:823a3763828d8d457f542b2a45d75d6b4ced5e470b5c7cf2ed66a02f508ed442", size = 1849938, upload-time = "2024-12-13T05:44:45.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/7b/11f457db6b291060a98315ab2c7198077d8bddeeebe5f7126d9dad98cc54/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:51633a14e6844c61db1d68c1ffd077cf949f5c99c60ed5f1e265b9e2966f1b52", size = 1852345, upload-time = "2024-12-13T05:44:47.994Z" }, - { url = "https://files.pythonhosted.org/packages/6b/92/0dccc96ce0323be236d404f5084479b79b747fa0e74e43a270e95868b5f9/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3ec9b01c45348f1d0d712507d54c2bfd69c62fbd7c9ef555c9d8298693c2432", size = 1989877, upload-time = "2024-12-13T05:44:51.514Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c8/1c5203a81200bae51aa8f7b5fad613f695bf1afa03f16251ca23ecb2ef9f/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1855022b712a9c7a5bce354517ab4727a38095f81e2d23d3eabaf1daeb6a3b3c", size = 1994492, upload-time = "2024-12-13T05:44:52.922Z" }, - { url = "https://files.pythonhosted.org/packages/e2/8a/04bc193c4d7ced8ef6bb62cdcd0bf40b5e5eb26586ed2cfb4433ec7dfd0a/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9930f7288c4866a1dc1cc87174f0c6ff4cad1671eb1f6306808aa6c445857d78", size = 1896077, upload-time = "2024-12-13T05:44:56.118Z" }, - { url = "https://files.pythonhosted.org/packages/21/a5/bee63a58f51d2c74856db66e6119a014464ff8cb1c9387fa4bd2d94e49b0/cytoolz-1.0.1-cp310-cp310-win32.whl", hash = "sha256:a9baad795d72fadc3445ccd0f122abfdbdf94269157e6d6d4835636dad318804", size = 322135, upload-time = "2024-12-13T05:44:57.695Z" }, - { url = "https://files.pythonhosted.org/packages/e8/16/7abfb1685e8b7f2838264551ee33651748994813f566ac4c3d737dfe90e5/cytoolz-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad95b386a84e18e1f6136f6d343d2509d4c3aae9f5a536f3dc96808fcc56a8cf", size = 363599, upload-time = "2024-12-13T05:44:58.875Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ea/8131ae39119820b8867cddc23716fa9f681f2b3bbce6f693e68dfb36b55b/cytoolz-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d958d4f04d9d7018e5c1850790d9d8e68b31c9a2deebca74b903706fdddd2b6", size = 406162, upload-time = "2024-12-13T05:45:01.196Z" }, - { url = "https://files.pythonhosted.org/packages/26/18/3d9bd4c146f6ea6e51300c242b20cb416966b21d481dac230e1304f1e54b/cytoolz-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0f445b8b731fc0ecb1865b8e68a070084eb95d735d04f5b6c851db2daf3048ab", size = 384961, upload-time = "2024-12-13T05:45:02.387Z" }, - { url = "https://files.pythonhosted.org/packages/e4/73/9034827907c7f85c7c484c9494e905d022fb8174526004e9ef332570349e/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f546a96460a7e28eb2ec439f4664fa646c9b3e51c6ebad9a59d3922bbe65e30", size = 2091698, upload-time = "2024-12-13T05:45:04.353Z" }, - { url = "https://files.pythonhosted.org/packages/74/af/d5c2733b0fde1a08254ff1a8a8d567874040c9eb1606363cfebc0713c73f/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0317681dd065532d21836f860b0563b199ee716f55d0c1f10de3ce7100c78a3b", size = 2188452, upload-time = "2024-12-13T05:45:05.748Z" }, - { url = "https://files.pythonhosted.org/packages/6a/bb/77c71fa9c217260b4056a732d754748903423c2cdd82a673d6064741e375/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0ef52febd5a7821a3fd8d10f21d460d1a3d2992f724ba9c91fbd7a96745d41", size = 2174203, upload-time = "2024-12-13T05:45:07.777Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a9/a5b4a3ff5d22faa1b60293bfe97362e2caf4a830c26d37ab5557f60d04b2/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebaf419acf2de73b643cf96108702b8aef8e825cf4f63209ceb078d5fbbbfd", size = 2099831, upload-time = "2024-12-13T05:45:11.477Z" }, - { url = "https://files.pythonhosted.org/packages/35/08/7f6869ea1ff31ce5289a7d58d0e7090acfe7058baa2764473048ff61ea3c/cytoolz-1.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f7f04eeb4088947585c92d6185a618b25ad4a0f8f66ea30c8db83cf94a425e3", size = 1996744, upload-time = "2024-12-13T05:45:14.172Z" }, - { url = "https://files.pythonhosted.org/packages/46/b4/9ac424c994b51763fd1bbed62d95f8fba8fa0e45c8c3c583904fdaf8f51d/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f61928803bb501c17914b82d457c6f50fe838b173fb40d39c38d5961185bd6c7", size = 2013733, upload-time = "2024-12-13T05:45:16.912Z" }, - { url = "https://files.pythonhosted.org/packages/3e/99/03009765c4b87d742d5b5a8670abb56a8c7ede033c2cdaa4be8662d3b001/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d2960cb4fa01ccb985ad1280db41f90dc97a80b397af970a15d5a5de403c8c61", size = 1994850, upload-time = "2024-12-13T05:45:18.414Z" }, - { url = "https://files.pythonhosted.org/packages/40/9a/8458af9a5557e177ea42f8cf7e477bede518b0bbef564e28c4151feaa52c/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2b407cc3e9defa8df5eb46644f6f136586f70ba49eba96f43de67b9a0984fd3", size = 2155352, upload-time = "2024-12-13T05:45:19.763Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5c/2a701423e001fcbec288b4f3fc2bf67557d114c2388237fc1ae67e1e2686/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8245f929144d4d3bd7b972c9593300195c6cea246b81b4c46053c48b3f044580", size = 2163515, upload-time = "2024-12-13T05:45:21.08Z" }, - { url = "https://files.pythonhosted.org/packages/36/16/ee2e06e65d9d533bc05cd52a0b355ba9072fc8f60d77289e529c6d2e3750/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37385db03af65763933befe89fa70faf25301effc3b0485fec1c15d4ce4f052", size = 2054431, upload-time = "2024-12-13T05:45:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d5/2fac8315f210fa1bc7106e27c19e1211580aa25bb7fa17dfd79505e5baf2/cytoolz-1.0.1-cp311-cp311-win32.whl", hash = "sha256:50f9c530f83e3e574fc95c264c3350adde8145f4f8fc8099f65f00cc595e5ead", size = 322004, upload-time = "2024-12-13T05:45:24.048Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9e/0b70b641850a95f9ff90adde9d094a4b1d81ec54dadfd97fec0a2aaf440e/cytoolz-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b7f6b617454b4326af7bd3c7c49b0fc80767f134eb9fd6449917a058d17a0e3c", size = 365358, upload-time = "2024-12-13T05:45:25.383Z" }, - { url = "https://files.pythonhosted.org/packages/d8/e8/218098344ed2cb5f8441fade9b2428e435e7073962374a9c71e59ac141a7/cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4", size = 414121, upload-time = "2024-12-13T05:45:26.588Z" }, - { url = "https://files.pythonhosted.org/packages/de/27/4d729a5653718109262b758fec1a959aa9facb74c15460d9074dc76d6635/cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662", size = 390904, upload-time = "2024-12-13T05:45:27.718Z" }, - { url = "https://files.pythonhosted.org/packages/72/c0/cbabfa788bab9c6038953bf9478adaec06e88903a726946ea7c88092f5c4/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3", size = 2090734, upload-time = "2024-12-13T05:45:30.515Z" }, - { url = "https://files.pythonhosted.org/packages/c3/66/369262c60f9423c2da82a60864a259c852f1aa122aced4acd2c679af58c0/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1", size = 2155933, upload-time = "2024-12-13T05:45:32.721Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4e/ee55186802f8d24b5fbf9a11405ccd1203b30eded07cc17750618219b94e/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8", size = 2171903, upload-time = "2024-12-13T05:45:34.205Z" }, - { url = "https://files.pythonhosted.org/packages/a1/96/bd1a9f3396e9b7f618db8cd08d15630769ce3c8b7d0534f92cd639c977ae/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d", size = 2125270, upload-time = "2024-12-13T05:45:36.982Z" }, - { url = "https://files.pythonhosted.org/packages/28/48/2a3762873091c88a69e161111cfbc6c222ff145d57ff011a642b169f04f1/cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f", size = 1973967, upload-time = "2024-12-13T05:45:39.505Z" }, - { url = "https://files.pythonhosted.org/packages/e4/50/500bd69774bdc49a4d78ec8779eb6ac7c1a9d706bfd91cf2a1dba604373a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7", size = 2021695, upload-time = "2024-12-13T05:45:40.911Z" }, - { url = "https://files.pythonhosted.org/packages/e4/4e/ba5a0ce34869495eb50653de8d676847490cf13a2cac1760fc4d313e78de/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126", size = 2010177, upload-time = "2024-12-13T05:45:42.48Z" }, - { url = "https://files.pythonhosted.org/packages/87/57/615c630b3089a13adb15351d958d227430cf624f03b1dd39eb52c34c1f59/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0", size = 2154321, upload-time = "2024-12-13T05:45:43.979Z" }, - { url = "https://files.pythonhosted.org/packages/7f/0f/fe1aa2d931e3b35ecc05215bd75da945ea7346095b3b6f6027164e602d5a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b", size = 2188374, upload-time = "2024-12-13T05:45:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/de/fa/fd363d97a641b6d0e2fd1d5c35b8fd41d9ccaeb4df56302f53bf23a58e3a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d", size = 2077911, upload-time = "2024-12-13T05:45:48.219Z" }, - { url = "https://files.pythonhosted.org/packages/d9/68/0a22946b98ae5201b54ccb4e651295285c0fb79406022b6ee8b2f791940c/cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9", size = 321903, upload-time = "2024-12-13T05:45:50.3Z" }, - { url = "https://files.pythonhosted.org/packages/62/1a/f3903197956055032f8cb297342e2dff07e50f83991aebfe5b4c4fcb55e4/cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b", size = 364490, upload-time = "2024-12-13T05:45:51.494Z" }, - { url = "https://files.pythonhosted.org/packages/aa/2e/a9f069db0107749e9e72baf6c21abe3f006841a3bcfdc9b8420e22ef31eb/cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0", size = 407365, upload-time = "2024-12-13T05:45:52.803Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9b/5e87dd0e31f54c778b4f9f34cc14c1162d3096c8d746b0f8be97d70dd73c/cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a", size = 385233, upload-time = "2024-12-13T05:45:53.994Z" }, - { url = "https://files.pythonhosted.org/packages/63/00/2fd32b16284cdb97cfe092822179bc0c3bcdd5e927dd39f986169a517642/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242", size = 2062903, upload-time = "2024-12-13T05:45:55.202Z" }, - { url = "https://files.pythonhosted.org/packages/85/39/b3cbb5a9847ba59584a263772ad4f8ca2dbfd2a0e11efd09211d1219804c/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296", size = 2139517, upload-time = "2024-12-13T05:45:56.804Z" }, - { url = "https://files.pythonhosted.org/packages/ea/39/bfcab4a46d50c467e36fe704f19d8904efead417787806ee210327f68390/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b", size = 2154849, upload-time = "2024-12-13T05:45:58.814Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/3bc6ee61b0aa47e1cb40819adc1a456d7efa809f0dea9faddacb43fdde8f/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b", size = 2102302, upload-time = "2024-12-13T05:46:00.181Z" }, - { url = "https://files.pythonhosted.org/packages/00/66/3f636c6ddea7b18026b90a8c238af472e423b86e427b11df02213689b012/cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266", size = 1960872, upload-time = "2024-12-13T05:46:01.612Z" }, - { url = "https://files.pythonhosted.org/packages/40/36/cb3b7cdd651007b69f9c48e9d104cec7cb8dc53afa1d6a720e5ad08022fa/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5", size = 2014430, upload-time = "2024-12-13T05:46:03.022Z" }, - { url = "https://files.pythonhosted.org/packages/88/3f/2e9bd2a16cfd269808922147551dcb2d8b68ba54a2c4deca2fa6a6cd0d5f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3", size = 2003127, upload-time = "2024-12-13T05:46:04.401Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7d/08604ff940aa784df8343c387fdf2489b948b714a6afb587775ae94da912/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296", size = 2142369, upload-time = "2024-12-13T05:46:06.004Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c6/39919a0645bdbdf720e97cae107f959ea9d1267fbc3b0d94fc6e1d12ac8f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140", size = 2180427, upload-time = "2024-12-13T05:46:07.526Z" }, - { url = "https://files.pythonhosted.org/packages/d8/03/dbb9d47556ee54337e7e0ac209d17ceff2d2a197c34de08005abc7a7449b/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581", size = 2069785, upload-time = "2024-12-13T05:46:10.122Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f8/11bb7b8947002231faae3ec2342df5896afbc19eb783a332cce6d219ff79/cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9", size = 320685, upload-time = "2024-12-13T05:46:11.553Z" }, - { url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297", size = 362898, upload-time = "2024-12-13T05:46:12.771Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f7/ef2a10daaec5c0f7d781d50758c6187eee484256e356ae8ef178d6c48497/cytoolz-1.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:83d19d55738ad9c60763b94f3f6d3c6e4de979aeb8d76841c1401081e0e58d96", size = 345702, upload-time = "2024-12-13T05:47:09.266Z" }, - { url = "https://files.pythonhosted.org/packages/c8/14/53c84adddedb67ff1546abb86fea04d26e24298c3ceab8436d20122ed0b9/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f112a71fad6ea824578e6393765ce5c054603afe1471a5c753ff6c67fd872d10", size = 385695, upload-time = "2024-12-13T05:47:11.011Z" }, - { url = "https://files.pythonhosted.org/packages/bd/80/3ae356c5e7b8d7dc7d1adb52f6932fee85cd748ed4e1217c269d2dfd610f/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a515df8f8aa6e1eaaf397761a6e4aff2eef73b5f920aedf271416d5471ae5ee", size = 406261, upload-time = "2024-12-13T05:47:12.24Z" }, - { url = "https://files.pythonhosted.org/packages/0c/31/8e43761ffc82d90bf9cab7e0959712eedcd1e33c211397e143dd42d7af57/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c398e7b7023460bea2edffe5fcd0a76029580f06c3f6938ac3d198b47156f3", size = 397207, upload-time = "2024-12-13T05:47:13.561Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b9/fe9da37090b6444c65f848a83e390f87d8cb43d6a4df46de1556ad7e5ceb/cytoolz-1.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3237e56211e03b13df47435b2369f5df281e02b04ad80a948ebd199b7bc10a47", size = 343358, upload-time = "2024-12-13T05:47:16.291Z" }, -] - -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - -[[package]] -name = "email-validator" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, -] - -[[package]] -name = "eth-abi" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "parsimonious" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/71/d9e1380bd77fd22f98b534699af564f189b56d539cc2b9dab908d4e4c242/eth_abi-5.2.0.tar.gz", hash = "sha256:178703fa98c07d8eecd5ae569e7e8d159e493ebb6eeb534a8fe973fbc4e40ef0", size = 49797, upload-time = "2025-01-14T16:29:34.629Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/b4/2f3982c4cbcbf5eeb6aec62df1533c0e63c653b3021ff338d44944405676/eth_abi-5.2.0-py3-none-any.whl", hash = "sha256:17abe47560ad753f18054f5b3089fcb588f3e3a092136a416b6c1502cb7e8877", size = 28511, upload-time = "2025-01-14T16:29:31.862Z" }, -] - -[[package]] -name = "eth-account" -version = "0.13.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bitarray" }, - { name = "ckzg" }, - { name = "eth-abi" }, - { name = "eth-keyfile" }, - { name = "eth-keys" }, - { name = "eth-rlp" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "rlp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/cf/20f76a29be97339c969fd765f1237154286a565a1d61be98e76bb7af946a/eth_account-0.13.7.tar.gz", hash = "sha256:5853ecbcbb22e65411176f121f5f24b8afeeaf13492359d254b16d8b18c77a46", size = 935998, upload-time = "2025-04-21T21:11:21.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/18/088fb250018cbe665bc2111974301b2d59f294a565aff7564c4df6878da2/eth_account-0.13.7-py3-none-any.whl", hash = "sha256:39727de8c94d004ff61d10da7587509c04d2dc7eac71e04830135300bdfc6d24", size = 587452, upload-time = "2025-04-21T21:11:18.346Z" }, -] - -[[package]] -name = "eth-hash" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/38/577b7bc9380ef9dff0f1dffefe0c9a1ded2385e7a06c306fd95afb6f9451/eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5", size = 12227, upload-time = "2025-01-13T21:29:21.765Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/db/f8775490669d28aca24871c67dd56b3e72105cb3bcae9a4ec65dd70859b3/eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a", size = 8028, upload-time = "2025-01-13T21:29:19.365Z" }, -] - -[package.optional-dependencies] -pycryptodome = [ - { name = "pycryptodome" }, -] - -[[package]] -name = "eth-keyfile" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-keys" }, - { name = "eth-utils" }, - { name = "pycryptodome" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/66/dd823b1537befefbbff602e2ada88f1477c5b40ec3731e3d9bc676c5f716/eth_keyfile-0.8.1.tar.gz", hash = "sha256:9708bc31f386b52cca0969238ff35b1ac72bd7a7186f2a84b86110d3c973bec1", size = 12267, upload-time = "2024-04-23T20:28:53.862Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/fc/48a586175f847dd9e05e5b8994d2fe8336098781ec2e9836a2ad94280281/eth_keyfile-0.8.1-py3-none-any.whl", hash = "sha256:65387378b82fe7e86d7cb9f8d98e6d639142661b2f6f490629da09fddbef6d64", size = 7510, upload-time = "2024-04-23T20:28:51.063Z" }, -] - -[[package]] -name = "eth-keys" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/11/1ed831c50bd74f57829aa06e58bd82a809c37e070ee501c953b9ac1f1552/eth_keys-0.7.0.tar.gz", hash = "sha256:79d24fd876201df67741de3e3fefb3f4dbcbb6ace66e47e6fe662851a4547814", size = 30166, upload-time = "2025-04-07T17:40:21.697Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/25/0ae00f2b0095e559d61ad3dc32171bd5a29dfd95ab04b4edd641f7c75f72/eth_keys-0.7.0-py3-none-any.whl", hash = "sha256:b0cdda8ffe8e5ba69c7c5ca33f153828edcace844f67aabd4542d7de38b159cf", size = 20656, upload-time = "2025-04-07T17:40:20.441Z" }, -] - -[[package]] -name = "eth-rlp" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "rlp" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7f/ea/ad39d001fa9fed07fad66edb00af701e29b48be0ed44a3bcf58cb3adf130/eth_rlp-2.2.0.tar.gz", hash = "sha256:5e4b2eb1b8213e303d6a232dfe35ab8c29e2d3051b86e8d359def80cd21db83d", size = 7720, upload-time = "2025-02-04T21:51:08.134Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/3b/57efe2bc2df0980680d57c01a36516cd3171d2319ceb30e675de19fc2cc5/eth_rlp-2.2.0-py3-none-any.whl", hash = "sha256:5692d595a741fbaef1203db6a2fedffbd2506d31455a6ad378c8449ee5985c47", size = 4446, upload-time = "2025-02-04T21:51:05.823Z" }, -] - -[[package]] -name = "eth-typing" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/54/62aa24b9cc708f06316167ee71c362779c8ed21fc8234a5cd94a8f53b623/eth_typing-5.2.1.tar.gz", hash = "sha256:7557300dbf02a93c70fa44af352b5c4a58f94e997a0fd6797fb7d1c29d9538ee", size = 21806, upload-time = "2025-04-14T20:39:28.217Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/72/c370bbe4c53da7bf998d3523f5a0f38867654923a82192df88d0705013d3/eth_typing-5.2.1-py3-none-any.whl", hash = "sha256:b0c2812ff978267563b80e9d701f487dd926f1d376d674f3b535cfe28b665d3d", size = 19163, upload-time = "2025-04-14T20:39:26.571Z" }, -] - -[[package]] -name = "eth-utils" -version = "5.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cytoolz", marker = "implementation_name == 'cpython'" }, - { name = "eth-hash" }, - { name = "eth-typing" }, - { name = "pydantic" }, - { name = "toolz", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0d/49/bee95f16d2ef068097afeeffbd6c67738107001ee57ad7bcdd4fc4d3c6a7/eth_utils-5.3.0.tar.gz", hash = "sha256:1f096867ac6be895f456fa3acb26e9573ae66e753abad9208f316d24d6178156", size = 123753, upload-time = "2025-04-14T19:35:56.431Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/c6/0417a92e6a3fc9b85f5a8380d9f9d43b69ba836a90e45f79f9ae74d41e53/eth_utils-5.3.0-py3-none-any.whl", hash = "sha256:ac184883ab299d923428bbe25dae5e356979a3993e0ef695a864db0a20bc262d", size = 102531, upload-time = "2025-04-14T19:35:55.176Z" }, -] - -[[package]] -name = "exceptiongroup" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, -] - -[[package]] -name = "fastapi" -version = "0.115.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236, upload-time = "2025-03-23T22:55:43.822Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164, upload-time = "2025-03-23T22:55:42.101Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, - { name = "httpx" }, - { name = "jinja2" }, - { name = "python-multipart" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cli" -version = "0.0.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "rich-toolkit" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/73/82a5831fbbf8ed75905bacf5b2d9d3dfd6f04d6968b29fe6f72a5ae9ceb1/fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e", size = 16753, upload-time = "2024-12-15T14:28:10.028Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705, upload-time = "2024-12-15T14:28:06.18Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "flask" -version = "3.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "blinker" }, - { name = "click" }, - { name = "itsdangerous" }, - { name = "jinja2" }, - { name = "markupsafe" }, - { name = "werkzeug" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/de/e47735752347f4128bcf354e0da07ef311a78244eba9e3dc1d4a5ab21a98/flask-3.1.1.tar.gz", hash = "sha256:284c7b8f2f58cb737f0cf1c30fd7eaf0ccfcde196099d24ecede3fc2005aa59e", size = 753440, upload-time = "2025-05-13T15:01:17.447Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl", hash = "sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c", size = 103305, upload-time = "2025-05-13T15:01:15.591Z" }, -] - -[[package]] -name = "frozenlist" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, - { url = "https://files.pythonhosted.org/packages/77/f0/77c11d13d39513b298e267b22eb6cb559c103d56f155aa9a49097221f0b6/frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61", size = 47735, upload-time = "2025-06-09T22:59:48.133Z" }, - { url = "https://files.pythonhosted.org/packages/37/12/9d07fa18971a44150593de56b2f2947c46604819976784bcf6ea0d5db43b/frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d", size = 46775, upload-time = "2025-06-09T22:59:49.564Z" }, - { url = "https://files.pythonhosted.org/packages/70/34/f73539227e06288fcd1f8a76853e755b2b48bca6747e99e283111c18bcd4/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e", size = 224644, upload-time = "2025-06-09T22:59:51.35Z" }, - { url = "https://files.pythonhosted.org/packages/fb/68/c1d9c2f4a6e438e14613bad0f2973567586610cc22dcb1e1241da71de9d3/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9", size = 222125, upload-time = "2025-06-09T22:59:52.884Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d0/98e8f9a515228d708344d7c6986752be3e3192d1795f748c24bcf154ad99/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c", size = 233455, upload-time = "2025-06-09T22:59:54.74Z" }, - { url = "https://files.pythonhosted.org/packages/79/df/8a11bcec5600557f40338407d3e5bea80376ed1c01a6c0910fcfdc4b8993/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981", size = 227339, upload-time = "2025-06-09T22:59:56.187Z" }, - { url = "https://files.pythonhosted.org/packages/50/82/41cb97d9c9a5ff94438c63cc343eb7980dac4187eb625a51bdfdb7707314/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615", size = 212969, upload-time = "2025-06-09T22:59:57.604Z" }, - { url = "https://files.pythonhosted.org/packages/13/47/f9179ee5ee4f55629e4f28c660b3fdf2775c8bfde8f9c53f2de2d93f52a9/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50", size = 222862, upload-time = "2025-06-09T22:59:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/df81e41ec6b953902c8b7e3a83bee48b195cb0e5ec2eabae5d8330c78038/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa", size = 222492, upload-time = "2025-06-09T23:00:01.026Z" }, - { url = "https://files.pythonhosted.org/packages/84/17/30d6ea87fa95a9408245a948604b82c1a4b8b3e153cea596421a2aef2754/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577", size = 238250, upload-time = "2025-06-09T23:00:03.401Z" }, - { url = "https://files.pythonhosted.org/packages/8f/00/ecbeb51669e3c3df76cf2ddd66ae3e48345ec213a55e3887d216eb4fbab3/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59", size = 218720, upload-time = "2025-06-09T23:00:05.282Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c0/c224ce0e0eb31cc57f67742071bb470ba8246623c1823a7530be0e76164c/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e", size = 232585, upload-time = "2025-06-09T23:00:07.962Z" }, - { url = "https://files.pythonhosted.org/packages/55/3c/34cb694abf532f31f365106deebdeac9e45c19304d83cf7d51ebbb4ca4d1/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd", size = 234248, upload-time = "2025-06-09T23:00:09.428Z" }, - { url = "https://files.pythonhosted.org/packages/98/c0/2052d8b6cecda2e70bd81299e3512fa332abb6dcd2969b9c80dfcdddbf75/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718", size = 221621, upload-time = "2025-06-09T23:00:11.32Z" }, - { url = "https://files.pythonhosted.org/packages/c5/bf/7dcebae315436903b1d98ffb791a09d674c88480c158aa171958a3ac07f0/frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e", size = 39578, upload-time = "2025-06-09T23:00:13.526Z" }, - { url = "https://files.pythonhosted.org/packages/8f/5f/f69818f017fa9a3d24d1ae39763e29b7f60a59e46d5f91b9c6b21622f4cd/frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464", size = 43830, upload-time = "2025-06-09T23:00:14.98Z" }, - { url = "https://files.pythonhosted.org/packages/34/7e/803dde33760128acd393a27eb002f2020ddb8d99d30a44bfbaab31c5f08a/frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a", size = 82251, upload-time = "2025-06-09T23:00:16.279Z" }, - { url = "https://files.pythonhosted.org/packages/75/a9/9c2c5760b6ba45eae11334db454c189d43d34a4c0b489feb2175e5e64277/frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750", size = 48183, upload-time = "2025-06-09T23:00:17.698Z" }, - { url = "https://files.pythonhosted.org/packages/47/be/4038e2d869f8a2da165f35a6befb9158c259819be22eeaf9c9a8f6a87771/frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd", size = 47107, upload-time = "2025-06-09T23:00:18.952Z" }, - { url = "https://files.pythonhosted.org/packages/79/26/85314b8a83187c76a37183ceed886381a5f992975786f883472fcb6dc5f2/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2", size = 237333, upload-time = "2025-06-09T23:00:20.275Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fd/e5b64f7d2c92a41639ffb2ad44a6a82f347787abc0c7df5f49057cf11770/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f", size = 231724, upload-time = "2025-06-09T23:00:21.705Z" }, - { url = "https://files.pythonhosted.org/packages/20/fb/03395c0a43a5976af4bf7534759d214405fbbb4c114683f434dfdd3128ef/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30", size = 245842, upload-time = "2025-06-09T23:00:23.148Z" }, - { url = "https://files.pythonhosted.org/packages/d0/15/c01c8e1dffdac5d9803507d824f27aed2ba76b6ed0026fab4d9866e82f1f/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98", size = 239767, upload-time = "2025-06-09T23:00:25.103Z" }, - { url = "https://files.pythonhosted.org/packages/14/99/3f4c6fe882c1f5514b6848aa0a69b20cb5e5d8e8f51a339d48c0e9305ed0/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86", size = 224130, upload-time = "2025-06-09T23:00:27.061Z" }, - { url = "https://files.pythonhosted.org/packages/4d/83/220a374bd7b2aeba9d0725130665afe11de347d95c3620b9b82cc2fcab97/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae", size = 235301, upload-time = "2025-06-09T23:00:29.02Z" }, - { url = "https://files.pythonhosted.org/packages/03/3c/3e3390d75334a063181625343e8daab61b77e1b8214802cc4e8a1bb678fc/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8", size = 234606, upload-time = "2025-06-09T23:00:30.514Z" }, - { url = "https://files.pythonhosted.org/packages/23/1e/58232c19608b7a549d72d9903005e2d82488f12554a32de2d5fb59b9b1ba/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31", size = 248372, upload-time = "2025-06-09T23:00:31.966Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a4/e4a567e01702a88a74ce8a324691e62a629bf47d4f8607f24bf1c7216e7f/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7", size = 229860, upload-time = "2025-06-09T23:00:33.375Z" }, - { url = "https://files.pythonhosted.org/packages/73/a6/63b3374f7d22268b41a9db73d68a8233afa30ed164c46107b33c4d18ecdd/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5", size = 245893, upload-time = "2025-06-09T23:00:35.002Z" }, - { url = "https://files.pythonhosted.org/packages/6d/eb/d18b3f6e64799a79673c4ba0b45e4cfbe49c240edfd03a68be20002eaeaa/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898", size = 246323, upload-time = "2025-06-09T23:00:36.468Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f5/720f3812e3d06cd89a1d5db9ff6450088b8f5c449dae8ffb2971a44da506/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56", size = 233149, upload-time = "2025-06-09T23:00:37.963Z" }, - { url = "https://files.pythonhosted.org/packages/69/68/03efbf545e217d5db8446acfd4c447c15b7c8cf4dbd4a58403111df9322d/frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7", size = 39565, upload-time = "2025-06-09T23:00:39.753Z" }, - { url = "https://files.pythonhosted.org/packages/58/17/fe61124c5c333ae87f09bb67186d65038834a47d974fc10a5fadb4cc5ae1/frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d", size = 44019, upload-time = "2025-06-09T23:00:40.988Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, - { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, - { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, - { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, - { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, - { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, - { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, - { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, - { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, - { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" }, - { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" }, - { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" }, - { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" }, - { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" }, - { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" }, - { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" }, - { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" }, - { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" }, - { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" }, - { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" }, - { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" }, - { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" }, - { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" }, - { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" }, - { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" }, - { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" }, - { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" }, - { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" }, - { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" }, - { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" }, - { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" }, - { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" }, - { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" }, - { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" }, - { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" }, - { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" }, - { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" }, - { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" }, - { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" }, - { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" }, - { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "hexbytes" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/87/adf4635b4b8c050283d74e6db9a81496063229c9263e6acc1903ab79fbec/hexbytes-1.3.1.tar.gz", hash = "sha256:a657eebebdfe27254336f98d8af6e2236f3f83aed164b87466b6cf6c5f5a4765", size = 8633, upload-time = "2025-05-14T16:45:17.5Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/e0/3b31492b1c89da3c5a846680517871455b30c54738486fc57ac79a5761bd/hexbytes-1.3.1-py3-none-any.whl", hash = "sha256:da01ff24a1a9a2b1881c4b85f0e9f9b0f51b526b379ffa23832ae7899d29c2c7", size = 5074, upload-time = "2025-05-14T16:45:16.179Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httptools" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/17c672b4bc5c7ba7f201eada4e96c71d0a59fbc185e60e42580093a86f21/httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da", size = 103297, upload-time = "2024-10-16T19:44:08.129Z" }, - { url = "https://files.pythonhosted.org/packages/92/5e/b4a826fe91971a0b68e8c2bd4e7db3e7519882f5a8ccdb1194be2b3ab98f/httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1", size = 443130, upload-time = "2024-10-16T19:44:09.45Z" }, - { url = "https://files.pythonhosted.org/packages/b0/51/ce61e531e40289a681a463e1258fa1e05e0be54540e40d91d065a264cd8f/httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50", size = 442148, upload-time = "2024-10-16T19:44:11.539Z" }, - { url = "https://files.pythonhosted.org/packages/ea/9e/270b7d767849b0c96f275c695d27ca76c30671f8eb8cc1bab6ced5c5e1d0/httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959", size = 415949, upload-time = "2024-10-16T19:44:13.388Z" }, - { url = "https://files.pythonhosted.org/packages/81/86/ced96e3179c48c6f656354e106934e65c8963d48b69be78f355797f0e1b3/httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4", size = 417591, upload-time = "2024-10-16T19:44:15.258Z" }, - { url = "https://files.pythonhosted.org/packages/75/73/187a3f620ed3175364ddb56847d7a608a6fc42d551e133197098c0143eca/httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c", size = 88344, upload-time = "2024-10-16T19:44:16.54Z" }, - { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029, upload-time = "2024-10-16T19:44:18.427Z" }, - { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492, upload-time = "2024-10-16T19:44:19.515Z" }, - { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891, upload-time = "2024-10-16T19:44:21.067Z" }, - { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788, upload-time = "2024-10-16T19:44:22.958Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214, upload-time = "2024-10-16T19:44:24.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120, upload-time = "2024-10-16T19:44:26.295Z" }, - { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565, upload-time = "2024-10-16T19:44:29.188Z" }, - { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683, upload-time = "2024-10-16T19:44:30.175Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337, upload-time = "2024-10-16T19:44:31.786Z" }, - { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796, upload-time = "2024-10-16T19:44:32.825Z" }, - { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837, upload-time = "2024-10-16T19:44:33.974Z" }, - { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289, upload-time = "2024-10-16T19:44:35.111Z" }, - { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779, upload-time = "2024-10-16T19:44:36.253Z" }, - { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634, upload-time = "2024-10-16T19:44:37.357Z" }, - { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" }, - { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" }, - { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" }, - { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" }, - { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" }, - { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "itsdangerous" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "multidict" -version = "6.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/2f/a3470242707058fe856fe59241eee5635d79087100b7042a867368863a27/multidict-6.4.4.tar.gz", hash = "sha256:69ee9e6ba214b5245031b76233dd95408a0fd57fdb019ddcc1ead4790932a8e8", size = 90183, upload-time = "2025-05-19T14:16:37.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/92/0926a5baafa164b5d0ade3cd7932be39310375d7e25c9d7ceca05cb26a45/multidict-6.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8adee3ac041145ffe4488ea73fa0a622b464cc25340d98be76924d0cda8545ff", size = 66052, upload-time = "2025-05-19T14:13:49.944Z" }, - { url = "https://files.pythonhosted.org/packages/b2/54/8a857ae4f8f643ec444d91f419fdd49cc7a90a2ca0e42d86482b604b63bd/multidict-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b61e98c3e2a861035aaccd207da585bdcacef65fe01d7a0d07478efac005e028", size = 38867, upload-time = "2025-05-19T14:13:51.92Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5f/63add9069f945c19bc8b217ea6b0f8a1ad9382eab374bb44fae4354b3baf/multidict-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75493f28dbadecdbb59130e74fe935288813301a8554dc32f0c631b6bdcdf8b0", size = 38138, upload-time = "2025-05-19T14:13:53.778Z" }, - { url = "https://files.pythonhosted.org/packages/97/8b/fbd9c0fc13966efdb4a47f5bcffff67a4f2a3189fbeead5766eaa4250b20/multidict-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc3c6a37e048b5395ee235e4a2a0d639c2349dffa32d9367a42fc20d399772", size = 220433, upload-time = "2025-05-19T14:13:55.346Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c4/5132b2d75b3ea2daedb14d10f91028f09f74f5b4d373b242c1b8eec47571/multidict-6.4.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87cb72263946b301570b0f63855569a24ee8758aaae2cd182aae7d95fbc92ca7", size = 218059, upload-time = "2025-05-19T14:13:56.993Z" }, - { url = "https://files.pythonhosted.org/packages/1a/70/f1e818c7a29b908e2d7b4fafb1d7939a41c64868e79de2982eea0a13193f/multidict-6.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bbf7bd39822fd07e3609b6b4467af4c404dd2b88ee314837ad1830a7f4a8299", size = 231120, upload-time = "2025-05-19T14:13:58.333Z" }, - { url = "https://files.pythonhosted.org/packages/b4/7e/95a194d85f27d5ef9cbe48dff9ded722fc6d12fedf641ec6e1e680890be7/multidict-6.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1f7cbd4f1f44ddf5fd86a8675b7679176eae770f2fc88115d6dddb6cefb59bc", size = 227457, upload-time = "2025-05-19T14:13:59.663Z" }, - { url = "https://files.pythonhosted.org/packages/25/2b/590ad220968d1babb42f265debe7be5c5c616df6c5688c995a06d8a9b025/multidict-6.4.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb5ac9e5bfce0e6282e7f59ff7b7b9a74aa8e5c60d38186a4637f5aa764046ad", size = 219111, upload-time = "2025-05-19T14:14:01.019Z" }, - { url = "https://files.pythonhosted.org/packages/e0/f0/b07682b995d3fb5313f339b59d7de02db19ba0c02d1f77c27bdf8212d17c/multidict-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4efc31dfef8c4eeb95b6b17d799eedad88c4902daba39ce637e23a17ea078915", size = 213012, upload-time = "2025-05-19T14:14:02.396Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/c77b5f36feef2ec92f1119756e468ac9c3eebc35aa8a4c9e51df664cbbc9/multidict-6.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9fcad2945b1b91c29ef2b4050f590bfcb68d8ac8e0995a74e659aa57e8d78e01", size = 225408, upload-time = "2025-05-19T14:14:04.826Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b3/e8189b82af9b198b47bc637766208fc917189eea91d674bad417e657bbdf/multidict-6.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d877447e7368c7320832acb7159557e49b21ea10ffeb135c1077dbbc0816b598", size = 214396, upload-time = "2025-05-19T14:14:06.187Z" }, - { url = "https://files.pythonhosted.org/packages/20/e0/200d14c84e35ae13ee99fd65dc106e1a1acb87a301f15e906fc7d5b30c17/multidict-6.4.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:33a12ebac9f380714c298cbfd3e5b9c0c4e89c75fe612ae496512ee51028915f", size = 222237, upload-time = "2025-05-19T14:14:07.778Z" }, - { url = "https://files.pythonhosted.org/packages/13/f3/bb3df40045ca8262694a3245298732ff431dc781414a89a6a364ebac6840/multidict-6.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0f14ea68d29b43a9bf37953881b1e3eb75b2739e896ba4a6aa4ad4c5b9ffa145", size = 231425, upload-time = "2025-05-19T14:14:09.516Z" }, - { url = "https://files.pythonhosted.org/packages/85/3b/538563dc18514384dac169bcba938753ad9ab4d4c8d49b55d6ae49fb2579/multidict-6.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0327ad2c747a6600e4797d115d3c38a220fdb28e54983abe8964fd17e95ae83c", size = 226251, upload-time = "2025-05-19T14:14:10.82Z" }, - { url = "https://files.pythonhosted.org/packages/56/79/77e1a65513f09142358f1beb1d4cbc06898590b34a7de2e47023e3c5a3a2/multidict-6.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d1a20707492db9719a05fc62ee215fd2c29b22b47c1b1ba347f9abc831e26683", size = 220363, upload-time = "2025-05-19T14:14:12.638Z" }, - { url = "https://files.pythonhosted.org/packages/16/57/67b0516c3e348f8daaa79c369b3de4359a19918320ab82e2e586a1c624ef/multidict-6.4.4-cp310-cp310-win32.whl", hash = "sha256:d83f18315b9fca5db2452d1881ef20f79593c4aa824095b62cb280019ef7aa3d", size = 35175, upload-time = "2025-05-19T14:14:14.805Z" }, - { url = "https://files.pythonhosted.org/packages/86/5a/4ed8fec642d113fa653777cda30ef67aa5c8a38303c091e24c521278a6c6/multidict-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:9c17341ee04545fd962ae07330cb5a39977294c883485c8d74634669b1f7fe04", size = 38678, upload-time = "2025-05-19T14:14:16.949Z" }, - { url = "https://files.pythonhosted.org/packages/19/1b/4c6e638195851524a63972c5773c7737bea7e47b1ba402186a37773acee2/multidict-6.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f5f29794ac0e73d2a06ac03fd18870adc0135a9d384f4a306a951188ed02f95", size = 65515, upload-time = "2025-05-19T14:14:19.767Z" }, - { url = "https://files.pythonhosted.org/packages/25/d5/10e6bca9a44b8af3c7f920743e5fc0c2bcf8c11bf7a295d4cfe00b08fb46/multidict-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c04157266344158ebd57b7120d9b0b35812285d26d0e78193e17ef57bfe2979a", size = 38609, upload-time = "2025-05-19T14:14:21.538Z" }, - { url = "https://files.pythonhosted.org/packages/26/b4/91fead447ccff56247edc7f0535fbf140733ae25187a33621771ee598a18/multidict-6.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb61ffd3ab8310d93427e460f565322c44ef12769f51f77277b4abad7b6f7223", size = 37871, upload-time = "2025-05-19T14:14:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/3b/37/cbc977cae59277e99d15bbda84cc53b5e0c4929ffd91d958347200a42ad0/multidict-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e0ba18a9afd495f17c351d08ebbc4284e9c9f7971d715f196b79636a4d0de44", size = 226661, upload-time = "2025-05-19T14:14:24.124Z" }, - { url = "https://files.pythonhosted.org/packages/15/cd/7e0b57fbd4dc2fc105169c4ecce5be1a63970f23bb4ec8c721b67e11953d/multidict-6.4.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9faf1b1dcaadf9f900d23a0e6d6c8eadd6a95795a0e57fcca73acce0eb912065", size = 223422, upload-time = "2025-05-19T14:14:25.437Z" }, - { url = "https://files.pythonhosted.org/packages/f1/01/1de268da121bac9f93242e30cd3286f6a819e5f0b8896511162d6ed4bf8d/multidict-6.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4d1cb1327c6082c4fce4e2a438483390964c02213bc6b8d782cf782c9b1471f", size = 235447, upload-time = "2025-05-19T14:14:26.793Z" }, - { url = "https://files.pythonhosted.org/packages/d2/8c/8b9a5e4aaaf4f2de14e86181a3a3d7b105077f668b6a06f043ec794f684c/multidict-6.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:941f1bec2f5dbd51feeb40aea654c2747f811ab01bdd3422a48a4e4576b7d76a", size = 231455, upload-time = "2025-05-19T14:14:28.149Z" }, - { url = "https://files.pythonhosted.org/packages/35/db/e1817dcbaa10b319c412769cf999b1016890849245d38905b73e9c286862/multidict-6.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5f8a146184da7ea12910a4cec51ef85e44f6268467fb489c3caf0cd512f29c2", size = 223666, upload-time = "2025-05-19T14:14:29.584Z" }, - { url = "https://files.pythonhosted.org/packages/4a/e1/66e8579290ade8a00e0126b3d9a93029033ffd84f0e697d457ed1814d0fc/multidict-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:232b7237e57ec3c09be97206bfb83a0aa1c5d7d377faa019c68a210fa35831f1", size = 217392, upload-time = "2025-05-19T14:14:30.961Z" }, - { url = "https://files.pythonhosted.org/packages/7b/6f/f8639326069c24a48c7747c2a5485d37847e142a3f741ff3340c88060a9a/multidict-6.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:55ae0721c1513e5e3210bca4fc98456b980b0c2c016679d3d723119b6b202c42", size = 228969, upload-time = "2025-05-19T14:14:32.672Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c3/3d58182f76b960eeade51c89fcdce450f93379340457a328e132e2f8f9ed/multidict-6.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d662c072579f63137919d7bb8fc250655ce79f00c82ecf11cab678f335062e", size = 217433, upload-time = "2025-05-19T14:14:34.016Z" }, - { url = "https://files.pythonhosted.org/packages/e1/4b/f31a562906f3bd375f3d0e83ce314e4a660c01b16c2923e8229b53fba5d7/multidict-6.4.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0e05c39962baa0bb19a6b210e9b1422c35c093b651d64246b6c2e1a7e242d9fd", size = 225418, upload-time = "2025-05-19T14:14:35.376Z" }, - { url = "https://files.pythonhosted.org/packages/99/89/78bb95c89c496d64b5798434a3deee21996114d4d2c28dd65850bf3a691e/multidict-6.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b1cc3ab8c31d9ebf0faa6e3540fb91257590da330ffe6d2393d4208e638925", size = 235042, upload-time = "2025-05-19T14:14:36.723Z" }, - { url = "https://files.pythonhosted.org/packages/74/91/8780a6e5885a8770442a8f80db86a0887c4becca0e5a2282ba2cae702bc4/multidict-6.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:93ec84488a384cd7b8a29c2c7f467137d8a73f6fe38bb810ecf29d1ade011a7c", size = 230280, upload-time = "2025-05-19T14:14:38.194Z" }, - { url = "https://files.pythonhosted.org/packages/68/c1/fcf69cabd542eb6f4b892469e033567ee6991d361d77abdc55e3a0f48349/multidict-6.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b308402608493638763abc95f9dc0030bbd6ac6aff784512e8ac3da73a88af08", size = 223322, upload-time = "2025-05-19T14:14:40.015Z" }, - { url = "https://files.pythonhosted.org/packages/b8/85/5b80bf4b83d8141bd763e1d99142a9cdfd0db83f0739b4797172a4508014/multidict-6.4.4-cp311-cp311-win32.whl", hash = "sha256:343892a27d1a04d6ae455ecece12904d242d299ada01633d94c4f431d68a8c49", size = 35070, upload-time = "2025-05-19T14:14:41.904Z" }, - { url = "https://files.pythonhosted.org/packages/09/66/0bed198ffd590ab86e001f7fa46b740d58cf8ff98c2f254e4a36bf8861ad/multidict-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:73484a94f55359780c0f458bbd3c39cb9cf9c182552177d2136e828269dee529", size = 38667, upload-time = "2025-05-19T14:14:43.534Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b5/5675377da23d60875fe7dae6be841787755878e315e2f517235f22f59e18/multidict-6.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc388f75a1c00000824bf28b7633e40854f4127ede80512b44c3cfeeea1839a2", size = 64293, upload-time = "2025-05-19T14:14:44.724Z" }, - { url = "https://files.pythonhosted.org/packages/34/a7/be384a482754bb8c95d2bbe91717bf7ccce6dc38c18569997a11f95aa554/multidict-6.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:98af87593a666f739d9dba5d0ae86e01b0e1a9cfcd2e30d2d361fbbbd1a9162d", size = 38096, upload-time = "2025-05-19T14:14:45.95Z" }, - { url = "https://files.pythonhosted.org/packages/66/6d/d59854bb4352306145bdfd1704d210731c1bb2c890bfee31fb7bbc1c4c7f/multidict-6.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aff4cafea2d120327d55eadd6b7f1136a8e5a0ecf6fb3b6863e8aca32cd8e50a", size = 37214, upload-time = "2025-05-19T14:14:47.158Z" }, - { url = "https://files.pythonhosted.org/packages/99/e0/c29d9d462d7cfc5fc8f9bf24f9c6843b40e953c0b55e04eba2ad2cf54fba/multidict-6.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:169c4ba7858176b797fe551d6e99040c531c775d2d57b31bcf4de6d7a669847f", size = 224686, upload-time = "2025-05-19T14:14:48.366Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4a/da99398d7fd8210d9de068f9a1b5f96dfaf67d51e3f2521f17cba4ee1012/multidict-6.4.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9eb4c59c54421a32b3273d4239865cb14ead53a606db066d7130ac80cc8ec93", size = 231061, upload-time = "2025-05-19T14:14:49.952Z" }, - { url = "https://files.pythonhosted.org/packages/21/f5/ac11add39a0f447ac89353e6ca46666847051103649831c08a2800a14455/multidict-6.4.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cf3bd54c56aa16fdb40028d545eaa8d051402b61533c21e84046e05513d5780", size = 232412, upload-time = "2025-05-19T14:14:51.812Z" }, - { url = "https://files.pythonhosted.org/packages/d9/11/4b551e2110cded705a3c13a1d4b6a11f73891eb5a1c449f1b2b6259e58a6/multidict-6.4.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f682c42003c7264134bfe886376299db4cc0c6cd06a3295b41b347044bcb5482", size = 231563, upload-time = "2025-05-19T14:14:53.262Z" }, - { url = "https://files.pythonhosted.org/packages/4c/02/751530c19e78fe73b24c3da66618eda0aa0d7f6e7aa512e46483de6be210/multidict-6.4.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920f9cf2abdf6e493c519492d892c362007f113c94da4c239ae88429835bad1", size = 223811, upload-time = "2025-05-19T14:14:55.232Z" }, - { url = "https://files.pythonhosted.org/packages/c7/cb/2be8a214643056289e51ca356026c7b2ce7225373e7a1f8c8715efee8988/multidict-6.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:530d86827a2df6504526106b4c104ba19044594f8722d3e87714e847c74a0275", size = 216524, upload-time = "2025-05-19T14:14:57.226Z" }, - { url = "https://files.pythonhosted.org/packages/19/f3/6d5011ec375c09081f5250af58de85f172bfcaafebff286d8089243c4bd4/multidict-6.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ecde56ea2439b96ed8a8d826b50c57364612ddac0438c39e473fafad7ae1c23b", size = 229012, upload-time = "2025-05-19T14:14:58.597Z" }, - { url = "https://files.pythonhosted.org/packages/67/9c/ca510785df5cf0eaf5b2a8132d7d04c1ce058dcf2c16233e596ce37a7f8e/multidict-6.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:dc8c9736d8574b560634775ac0def6bdc1661fc63fa27ffdfc7264c565bcb4f2", size = 226765, upload-time = "2025-05-19T14:15:00.048Z" }, - { url = "https://files.pythonhosted.org/packages/36/c8/ca86019994e92a0f11e642bda31265854e6ea7b235642f0477e8c2e25c1f/multidict-6.4.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7f3d3b3c34867579ea47cbd6c1f2ce23fbfd20a273b6f9e3177e256584f1eacc", size = 222888, upload-time = "2025-05-19T14:15:01.568Z" }, - { url = "https://files.pythonhosted.org/packages/c6/67/bc25a8e8bd522935379066950ec4e2277f9b236162a73548a2576d4b9587/multidict-6.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:87a728af265e08f96b6318ebe3c0f68b9335131f461efab2fc64cc84a44aa6ed", size = 234041, upload-time = "2025-05-19T14:15:03.759Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a0/70c4c2d12857fccbe607b334b7ee28b6b5326c322ca8f73ee54e70d76484/multidict-6.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9f193eeda1857f8e8d3079a4abd258f42ef4a4bc87388452ed1e1c4d2b0c8740", size = 231046, upload-time = "2025-05-19T14:15:05.698Z" }, - { url = "https://files.pythonhosted.org/packages/c1/0f/52954601d02d39742aab01d6b92f53c1dd38b2392248154c50797b4df7f1/multidict-6.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be06e73c06415199200e9a2324a11252a3d62030319919cde5e6950ffeccf72e", size = 227106, upload-time = "2025-05-19T14:15:07.124Z" }, - { url = "https://files.pythonhosted.org/packages/af/24/679d83ec4379402d28721790dce818e5d6b9f94ce1323a556fb17fa9996c/multidict-6.4.4-cp312-cp312-win32.whl", hash = "sha256:622f26ea6a7e19b7c48dd9228071f571b2fbbd57a8cd71c061e848f281550e6b", size = 35351, upload-time = "2025-05-19T14:15:08.556Z" }, - { url = "https://files.pythonhosted.org/packages/52/ef/40d98bc5f986f61565f9b345f102409534e29da86a6454eb6b7c00225a13/multidict-6.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:5e2bcda30d5009996ff439e02a9f2b5c3d64a20151d34898c000a6281faa3781", size = 38791, upload-time = "2025-05-19T14:15:09.825Z" }, - { url = "https://files.pythonhosted.org/packages/df/2a/e166d2ffbf4b10131b2d5b0e458f7cee7d986661caceae0de8753042d4b2/multidict-6.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:82ffabefc8d84c2742ad19c37f02cde5ec2a1ee172d19944d380f920a340e4b9", size = 64123, upload-time = "2025-05-19T14:15:11.044Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/e200e379ae5b6f95cbae472e0199ea98913f03d8c9a709f42612a432932c/multidict-6.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6a2f58a66fe2c22615ad26156354005391e26a2f3721c3621504cd87c1ea87bf", size = 38049, upload-time = "2025-05-19T14:15:12.902Z" }, - { url = "https://files.pythonhosted.org/packages/75/fb/47afd17b83f6a8c7fa863c6d23ac5ba6a0e6145ed8a6bcc8da20b2b2c1d2/multidict-6.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5883d6ee0fd9d8a48e9174df47540b7545909841ac82354c7ae4cbe9952603bd", size = 37078, upload-time = "2025-05-19T14:15:14.282Z" }, - { url = "https://files.pythonhosted.org/packages/fa/70/1af3143000eddfb19fd5ca5e78393985ed988ac493bb859800fe0914041f/multidict-6.4.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9abcf56a9511653fa1d052bfc55fbe53dbee8f34e68bd6a5a038731b0ca42d15", size = 224097, upload-time = "2025-05-19T14:15:15.566Z" }, - { url = "https://files.pythonhosted.org/packages/b1/39/d570c62b53d4fba844e0378ffbcd02ac25ca423d3235047013ba2f6f60f8/multidict-6.4.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6ed5ae5605d4ad5a049fad2a28bb7193400700ce2f4ae484ab702d1e3749c3f9", size = 230768, upload-time = "2025-05-19T14:15:17.308Z" }, - { url = "https://files.pythonhosted.org/packages/fd/f8/ed88f2c4d06f752b015933055eb291d9bc184936903752c66f68fb3c95a7/multidict-6.4.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbfcb60396f9bcfa63e017a180c3105b8c123a63e9d1428a36544e7d37ca9e20", size = 231331, upload-time = "2025-05-19T14:15:18.73Z" }, - { url = "https://files.pythonhosted.org/packages/9c/6f/8e07cffa32f483ab887b0d56bbd8747ac2c1acd00dc0af6fcf265f4a121e/multidict-6.4.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0f1987787f5f1e2076b59692352ab29a955b09ccc433c1f6b8e8e18666f608b", size = 230169, upload-time = "2025-05-19T14:15:20.179Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2b/5dcf173be15e42f330110875a2668ddfc208afc4229097312212dc9c1236/multidict-6.4.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0121ccce8c812047d8d43d691a1ad7641f72c4f730474878a5aeae1b8ead8c", size = 222947, upload-time = "2025-05-19T14:15:21.714Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/4ddcbcebe5ebcd6faa770b629260d15840a5fc07ce8ad295a32e14993726/multidict-6.4.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83ec4967114295b8afd120a8eec579920c882831a3e4c3331d591a8e5bfbbc0f", size = 215761, upload-time = "2025-05-19T14:15:23.242Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c9/55e998ae45ff15c5608e384206aa71a11e1b7f48b64d166db400b14a3433/multidict-6.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:995f985e2e268deaf17867801b859a282e0448633f1310e3704b30616d269d69", size = 227605, upload-time = "2025-05-19T14:15:24.763Z" }, - { url = "https://files.pythonhosted.org/packages/04/49/c2404eac74497503c77071bd2e6f88c7e94092b8a07601536b8dbe99be50/multidict-6.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d832c608f94b9f92a0ec8b7e949be7792a642b6e535fcf32f3e28fab69eeb046", size = 226144, upload-time = "2025-05-19T14:15:26.249Z" }, - { url = "https://files.pythonhosted.org/packages/62/c5/0cd0c3c6f18864c40846aa2252cd69d308699cb163e1c0d989ca301684da/multidict-6.4.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d21c1212171cf7da703c5b0b7a0e85be23b720818aef502ad187d627316d5645", size = 221100, upload-time = "2025-05-19T14:15:28.303Z" }, - { url = "https://files.pythonhosted.org/packages/71/7b/f2f3887bea71739a046d601ef10e689528d4f911d84da873b6be9194ffea/multidict-6.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:cbebaa076aaecad3d4bb4c008ecc73b09274c952cf6a1b78ccfd689e51f5a5b0", size = 232731, upload-time = "2025-05-19T14:15:30.263Z" }, - { url = "https://files.pythonhosted.org/packages/e5/b3/d9de808349df97fa75ec1372758701b5800ebad3c46ae377ad63058fbcc6/multidict-6.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c93a6fb06cc8e5d3628b2b5fda215a5db01e8f08fc15fadd65662d9b857acbe4", size = 229637, upload-time = "2025-05-19T14:15:33.337Z" }, - { url = "https://files.pythonhosted.org/packages/5e/57/13207c16b615eb4f1745b44806a96026ef8e1b694008a58226c2d8f5f0a5/multidict-6.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8cd8f81f1310182362fb0c7898145ea9c9b08a71081c5963b40ee3e3cac589b1", size = 225594, upload-time = "2025-05-19T14:15:34.832Z" }, - { url = "https://files.pythonhosted.org/packages/3a/e4/d23bec2f70221604f5565000632c305fc8f25ba953e8ce2d8a18842b9841/multidict-6.4.4-cp313-cp313-win32.whl", hash = "sha256:3e9f1cd61a0ab857154205fb0b1f3d3ace88d27ebd1409ab7af5096e409614cd", size = 35359, upload-time = "2025-05-19T14:15:36.246Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/cfe1a47632be861b627f46f642c1d031704cc1c0f5c0efbde2ad44aa34bd/multidict-6.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373", size = 38903, upload-time = "2025-05-19T14:15:37.507Z" }, - { url = "https://files.pythonhosted.org/packages/68/7b/15c259b0ab49938a0a1c8f3188572802704a779ddb294edc1b2a72252e7c/multidict-6.4.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6a602151dbf177be2450ef38966f4be3467d41a86c6a845070d12e17c858a156", size = 68895, upload-time = "2025-05-19T14:15:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/f1/7d/168b5b822bccd88142e0a3ce985858fea612404edd228698f5af691020c9/multidict-6.4.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d2b9712211b860d123815a80b859075d86a4d54787e247d7fbee9db6832cf1c", size = 40183, upload-time = "2025-05-19T14:15:40.197Z" }, - { url = "https://files.pythonhosted.org/packages/e0/b7/d4b8d98eb850ef28a4922ba508c31d90715fd9b9da3801a30cea2967130b/multidict-6.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d2fa86af59f8fc1972e121ade052145f6da22758f6996a197d69bb52f8204e7e", size = 39592, upload-time = "2025-05-19T14:15:41.508Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/a554678898a19583548e742080cf55d169733baf57efc48c2f0273a08583/multidict-6.4.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50855d03e9e4d66eab6947ba688ffb714616f985838077bc4b490e769e48da51", size = 226071, upload-time = "2025-05-19T14:15:42.877Z" }, - { url = "https://files.pythonhosted.org/packages/ee/dc/7ba6c789d05c310e294f85329efac1bf5b450338d2542498db1491a264df/multidict-6.4.4-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5bce06b83be23225be1905dcdb6b789064fae92499fbc458f59a8c0e68718601", size = 222597, upload-time = "2025-05-19T14:15:44.412Z" }, - { url = "https://files.pythonhosted.org/packages/24/4f/34eadbbf401b03768dba439be0fb94b0d187facae9142821a3d5599ccb3b/multidict-6.4.4-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66ed0731f8e5dfd8369a883b6e564aca085fb9289aacabd9decd70568b9a30de", size = 228253, upload-time = "2025-05-19T14:15:46.474Z" }, - { url = "https://files.pythonhosted.org/packages/c0/e6/493225a3cdb0d8d80d43a94503fc313536a07dae54a3f030d279e629a2bc/multidict-6.4.4-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:329ae97fc2f56f44d91bc47fe0972b1f52d21c4b7a2ac97040da02577e2daca2", size = 226146, upload-time = "2025-05-19T14:15:48.003Z" }, - { url = "https://files.pythonhosted.org/packages/2f/70/e411a7254dc3bff6f7e6e004303b1b0591358e9f0b7c08639941e0de8bd6/multidict-6.4.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c27e5dcf520923d6474d98b96749e6805f7677e93aaaf62656005b8643f907ab", size = 220585, upload-time = "2025-05-19T14:15:49.546Z" }, - { url = "https://files.pythonhosted.org/packages/08/8f/beb3ae7406a619100d2b1fb0022c3bb55a8225ab53c5663648ba50dfcd56/multidict-6.4.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:058cc59b9e9b143cc56715e59e22941a5d868c322242278d28123a5d09cdf6b0", size = 212080, upload-time = "2025-05-19T14:15:51.151Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ec/355124e9d3d01cf8edb072fd14947220f357e1c5bc79c88dff89297e9342/multidict-6.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:69133376bc9a03f8c47343d33f91f74a99c339e8b58cea90433d8e24bb298031", size = 226558, upload-time = "2025-05-19T14:15:52.665Z" }, - { url = "https://files.pythonhosted.org/packages/fd/22/d2b95cbebbc2ada3be3812ea9287dcc9712d7f1a012fad041770afddb2ad/multidict-6.4.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d6b15c55721b1b115c5ba178c77104123745b1417527ad9641a4c5e2047450f0", size = 212168, upload-time = "2025-05-19T14:15:55.279Z" }, - { url = "https://files.pythonhosted.org/packages/4d/c5/62bfc0b2f9ce88326dbe7179f9824a939c6c7775b23b95de777267b9725c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a887b77f51d3d41e6e1a63cf3bc7ddf24de5939d9ff69441387dfefa58ac2e26", size = 217970, upload-time = "2025-05-19T14:15:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/79/74/977cea1aadc43ff1c75d23bd5bc4768a8fac98c14e5878d6ee8d6bab743c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:632a3bf8f1787f7ef7d3c2f68a7bde5be2f702906f8b5842ad6da9d974d0aab3", size = 226980, upload-time = "2025-05-19T14:15:58.313Z" }, - { url = "https://files.pythonhosted.org/packages/48/fc/cc4a1a2049df2eb84006607dc428ff237af38e0fcecfdb8a29ca47b1566c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a145c550900deb7540973c5cdb183b0d24bed6b80bf7bddf33ed8f569082535e", size = 220641, upload-time = "2025-05-19T14:15:59.866Z" }, - { url = "https://files.pythonhosted.org/packages/3b/6a/a7444d113ab918701988d4abdde373dbdfd2def7bd647207e2bf645c7eac/multidict-6.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc5d83c6619ca5c9672cb78b39ed8542f1975a803dee2cda114ff73cbb076edd", size = 221728, upload-time = "2025-05-19T14:16:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b0/fdf4c73ad1c55e0f4dbbf2aa59dd37037334091f9a4961646d2b7ac91a86/multidict-6.4.4-cp313-cp313t-win32.whl", hash = "sha256:3312f63261b9df49be9d57aaa6abf53a6ad96d93b24f9cc16cf979956355ce6e", size = 41913, upload-time = "2025-05-19T14:16:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/8e/92/27989ecca97e542c0d01d05a98a5ae12198a243a9ee12563a0313291511f/multidict-6.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:ba852168d814b2c73333073e1c7116d9395bea69575a01b0b3c89d2d5a87c8fb", size = 46112, upload-time = "2025-05-19T14:16:04.909Z" }, - { url = "https://files.pythonhosted.org/packages/84/5d/e17845bb0fa76334477d5de38654d27946d5b5d3695443987a094a71b440/multidict-6.4.4-py3-none-any.whl", hash = "sha256:bd4557071b561a8b3b6075c3ce93cf9bfb6182cb241805c3d66ced3b75eff4ac", size = 10481, upload-time = "2025-05-19T14:16:36.024Z" }, -] - -[[package]] -name = "parsimonious" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7b/91/abdc50c4ef06fdf8d047f60ee777ca9b2a7885e1a9cea81343fbecda52d7/parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c", size = 52172, upload-time = "2022-09-03T17:01:17.004Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/0f/c8b64d9b54ea631fcad4e9e3c8dbe8c11bb32a623be94f22974c88e71eaf/parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f", size = 48427, upload-time = "2022-09-03T17:01:13.814Z" }, -] - -[[package]] -name = "propcache" -version = "0.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4e/ad52a7925ff01c1325653a730c7ec3175a23f948f08626a534133427dcff/propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3", size = 43133, upload-time = "2025-06-09T22:53:41.965Z" }, - { url = "https://files.pythonhosted.org/packages/63/7c/e9399ba5da7780871db4eac178e9c2e204c23dd3e7d32df202092a1ed400/propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3", size = 43039, upload-time = "2025-06-09T22:53:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/22/e1/58da211eb8fdc6fc854002387d38f415a6ca5f5c67c1315b204a5d3e9d7a/propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e", size = 201903, upload-time = "2025-06-09T22:53:44.872Z" }, - { url = "https://files.pythonhosted.org/packages/c4/0a/550ea0f52aac455cb90111c8bab995208443e46d925e51e2f6ebdf869525/propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220", size = 213362, upload-time = "2025-06-09T22:53:46.707Z" }, - { url = "https://files.pythonhosted.org/packages/5a/af/9893b7d878deda9bb69fcf54600b247fba7317761b7db11fede6e0f28bd0/propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb", size = 210525, upload-time = "2025-06-09T22:53:48.547Z" }, - { url = "https://files.pythonhosted.org/packages/7c/bb/38fd08b278ca85cde36d848091ad2b45954bc5f15cce494bb300b9285831/propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614", size = 198283, upload-time = "2025-06-09T22:53:50.067Z" }, - { url = "https://files.pythonhosted.org/packages/78/8c/9fe55bd01d362bafb413dfe508c48753111a1e269737fa143ba85693592c/propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50", size = 191872, upload-time = "2025-06-09T22:53:51.438Z" }, - { url = "https://files.pythonhosted.org/packages/54/14/4701c33852937a22584e08abb531d654c8bcf7948a8f87ad0a4822394147/propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339", size = 199452, upload-time = "2025-06-09T22:53:53.229Z" }, - { url = "https://files.pythonhosted.org/packages/16/44/447f2253d859602095356007657ee535e0093215ea0b3d1d6a41d16e5201/propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0", size = 191567, upload-time = "2025-06-09T22:53:54.541Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/e4756258749bb2d3b46defcff606a2f47410bab82be5824a67e84015b267/propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2", size = 193015, upload-time = "2025-06-09T22:53:56.44Z" }, - { url = "https://files.pythonhosted.org/packages/1e/df/e6d3c7574233164b6330b9fd697beeac402afd367280e6dc377bb99b43d9/propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7", size = 204660, upload-time = "2025-06-09T22:53:57.839Z" }, - { url = "https://files.pythonhosted.org/packages/b2/53/e4d31dd5170b4a0e2e6b730f2385a96410633b4833dc25fe5dffd1f73294/propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b", size = 206105, upload-time = "2025-06-09T22:53:59.638Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fe/74d54cf9fbe2a20ff786e5f7afcfde446588f0cf15fb2daacfbc267b866c/propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c", size = 196980, upload-time = "2025-06-09T22:54:01.071Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/c469c9d59dada8a7679625e0440b544fe72e99311a4679c279562051f6fc/propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70", size = 37679, upload-time = "2025-06-09T22:54:03.003Z" }, - { url = "https://files.pythonhosted.org/packages/38/35/07a471371ac89d418f8d0b699c75ea6dca2041fbda360823de21f6a9ce0a/propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9", size = 41459, upload-time = "2025-06-09T22:54:04.134Z" }, - { url = "https://files.pythonhosted.org/packages/80/8d/e8b436717ab9c2cfc23b116d2c297305aa4cd8339172a456d61ebf5669b8/propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be", size = 74207, upload-time = "2025-06-09T22:54:05.399Z" }, - { url = "https://files.pythonhosted.org/packages/d6/29/1e34000e9766d112171764b9fa3226fa0153ab565d0c242c70e9945318a7/propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f", size = 43648, upload-time = "2025-06-09T22:54:08.023Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/1ad5af0df781e76988897da39b5f086c2bf0f028b7f9bd1f409bb05b6874/propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9", size = 43496, upload-time = "2025-06-09T22:54:09.228Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ce/e96392460f9fb68461fabab3e095cb00c8ddf901205be4eae5ce246e5b7e/propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf", size = 217288, upload-time = "2025-06-09T22:54:10.466Z" }, - { url = "https://files.pythonhosted.org/packages/c5/2a/866726ea345299f7ceefc861a5e782b045545ae6940851930a6adaf1fca6/propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9", size = 227456, upload-time = "2025-06-09T22:54:11.828Z" }, - { url = "https://files.pythonhosted.org/packages/de/03/07d992ccb6d930398689187e1b3c718339a1c06b8b145a8d9650e4726166/propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66", size = 225429, upload-time = "2025-06-09T22:54:13.823Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/116ba39448753b1330f48ab8ba927dcd6cf0baea8a0ccbc512dfb49ba670/propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df", size = 213472, upload-time = "2025-06-09T22:54:15.232Z" }, - { url = "https://files.pythonhosted.org/packages/a6/85/f01f5d97e54e428885a5497ccf7f54404cbb4f906688a1690cd51bf597dc/propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2", size = 204480, upload-time = "2025-06-09T22:54:17.104Z" }, - { url = "https://files.pythonhosted.org/packages/e3/79/7bf5ab9033b8b8194cc3f7cf1aaa0e9c3256320726f64a3e1f113a812dce/propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7", size = 214530, upload-time = "2025-06-09T22:54:18.512Z" }, - { url = "https://files.pythonhosted.org/packages/31/0b/bd3e0c00509b609317df4a18e6b05a450ef2d9a963e1d8bc9c9415d86f30/propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95", size = 205230, upload-time = "2025-06-09T22:54:19.947Z" }, - { url = "https://files.pythonhosted.org/packages/7a/23/fae0ff9b54b0de4e819bbe559508da132d5683c32d84d0dc2ccce3563ed4/propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e", size = 206754, upload-time = "2025-06-09T22:54:21.716Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7f/ad6a3c22630aaa5f618b4dc3c3598974a72abb4c18e45a50b3cdd091eb2f/propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e", size = 218430, upload-time = "2025-06-09T22:54:23.17Z" }, - { url = "https://files.pythonhosted.org/packages/5b/2c/ba4f1c0e8a4b4c75910742f0d333759d441f65a1c7f34683b4a74c0ee015/propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf", size = 223884, upload-time = "2025-06-09T22:54:25.539Z" }, - { url = "https://files.pythonhosted.org/packages/88/e4/ebe30fc399e98572019eee82ad0caf512401661985cbd3da5e3140ffa1b0/propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e", size = 211480, upload-time = "2025-06-09T22:54:26.892Z" }, - { url = "https://files.pythonhosted.org/packages/96/0a/7d5260b914e01d1d0906f7f38af101f8d8ed0dc47426219eeaf05e8ea7c2/propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897", size = 37757, upload-time = "2025-06-09T22:54:28.241Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2d/89fe4489a884bc0da0c3278c552bd4ffe06a1ace559db5ef02ef24ab446b/propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39", size = 41500, upload-time = "2025-06-09T22:54:29.4Z" }, - { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, - { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, - { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, - { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, - { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, - { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, - { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, - { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, - { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, - { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, - { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, - { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, - { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, - { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, - { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, - { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, - { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, - { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, - { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, - { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, - { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, - { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, - { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, - { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, - { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, - { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, - { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, - { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, - { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, -] - -[[package]] -name = "pycryptodome" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" }, - { url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" }, - { url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" }, - { url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" }, - { url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" }, - { url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" }, - { url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" }, - { url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" }, - { url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" }, - { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, - { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, - { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, - { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, - { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, - { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, - { url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886, upload-time = "2025-05-17T17:21:20.614Z" }, - { url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151, upload-time = "2025-05-17T17:21:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461, upload-time = "2025-05-17T17:21:25.225Z" }, - { url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440, upload-time = "2025-05-17T17:21:27.991Z" }, - { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, -] - -[[package]] -name = "pydantic" -version = "2.10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/70/7e/fb60e6fee04d0ef8f15e4e01ff187a196fa976eb0f0ab524af4599e5754c/pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06", size = 762094, upload-time = "2024-12-18T17:09:24.84Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/26/3e1bbe954fde7ee22a6e7d31582c642aad9e84ffe4b5fb61e63b87cd326f/pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", size = 431765, upload-time = "2024-12-18T17:09:21.953Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.27.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443, upload-time = "2024-12-18T11:31:54.917Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938, upload-time = "2024-12-18T11:27:14.406Z" }, - { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684, upload-time = "2024-12-18T11:27:16.489Z" }, - { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169, upload-time = "2024-12-18T11:27:22.16Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227, upload-time = "2024-12-18T11:27:25.097Z" }, - { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695, upload-time = "2024-12-18T11:27:28.656Z" }, - { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662, upload-time = "2024-12-18T11:27:30.798Z" }, - { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370, upload-time = "2024-12-18T11:27:33.692Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813, upload-time = "2024-12-18T11:27:37.111Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287, upload-time = "2024-12-18T11:27:40.566Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414, upload-time = "2024-12-18T11:27:43.757Z" }, - { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301, upload-time = "2024-12-18T11:27:47.36Z" }, - { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685, upload-time = "2024-12-18T11:27:50.508Z" }, - { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876, upload-time = "2024-12-18T11:27:53.54Z" }, - { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421, upload-time = "2024-12-18T11:27:55.409Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998, upload-time = "2024-12-18T11:27:57.252Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167, upload-time = "2024-12-18T11:27:59.146Z" }, - { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071, upload-time = "2024-12-18T11:28:02.625Z" }, - { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244, upload-time = "2024-12-18T11:28:04.442Z" }, - { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470, upload-time = "2024-12-18T11:28:07.679Z" }, - { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291, upload-time = "2024-12-18T11:28:10.297Z" }, - { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613, upload-time = "2024-12-18T11:28:13.362Z" }, - { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355, upload-time = "2024-12-18T11:28:16.587Z" }, - { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661, upload-time = "2024-12-18T11:28:18.407Z" }, - { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261, upload-time = "2024-12-18T11:28:21.471Z" }, - { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361, upload-time = "2024-12-18T11:28:23.53Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484, upload-time = "2024-12-18T11:28:25.391Z" }, - { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102, upload-time = "2024-12-18T11:28:28.593Z" }, - { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127, upload-time = "2024-12-18T11:28:30.346Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340, upload-time = "2024-12-18T11:28:32.521Z" }, - { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900, upload-time = "2024-12-18T11:28:34.507Z" }, - { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177, upload-time = "2024-12-18T11:28:36.488Z" }, - { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046, upload-time = "2024-12-18T11:28:39.409Z" }, - { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386, upload-time = "2024-12-18T11:28:41.221Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060, upload-time = "2024-12-18T11:28:44.709Z" }, - { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870, upload-time = "2024-12-18T11:28:46.839Z" }, - { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822, upload-time = "2024-12-18T11:28:48.896Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364, upload-time = "2024-12-18T11:28:50.755Z" }, - { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303, upload-time = "2024-12-18T11:28:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064, upload-time = "2024-12-18T11:28:56.074Z" }, - { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046, upload-time = "2024-12-18T11:28:58.107Z" }, - { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092, upload-time = "2024-12-18T11:29:01.335Z" }, - { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709, upload-time = "2024-12-18T11:29:03.193Z" }, - { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273, upload-time = "2024-12-18T11:29:05.306Z" }, - { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027, upload-time = "2024-12-18T11:29:07.294Z" }, - { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888, upload-time = "2024-12-18T11:29:09.249Z" }, - { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738, upload-time = "2024-12-18T11:29:11.23Z" }, - { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138, upload-time = "2024-12-18T11:29:16.396Z" }, - { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025, upload-time = "2024-12-18T11:29:20.25Z" }, - { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633, upload-time = "2024-12-18T11:29:23.877Z" }, - { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404, upload-time = "2024-12-18T11:29:25.872Z" }, - { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130, upload-time = "2024-12-18T11:29:29.252Z" }, - { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946, upload-time = "2024-12-18T11:29:31.338Z" }, - { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387, upload-time = "2024-12-18T11:29:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453, upload-time = "2024-12-18T11:29:35.533Z" }, - { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186, upload-time = "2024-12-18T11:29:37.649Z" }, - { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159, upload-time = "2024-12-18T11:30:54.382Z" }, - { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331, upload-time = "2024-12-18T11:30:58.178Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467, upload-time = "2024-12-18T11:31:00.6Z" }, - { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797, upload-time = "2024-12-18T11:31:07.243Z" }, - { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839, upload-time = "2024-12-18T11:31:09.775Z" }, - { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861, upload-time = "2024-12-18T11:31:13.469Z" }, - { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582, upload-time = "2024-12-18T11:31:17.423Z" }, - { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985, upload-time = "2024-12-18T11:31:19.901Z" }, - { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715, upload-time = "2024-12-18T11:31:22.821Z" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234, upload-time = "2025-04-18T16:44:48.265Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356, upload-time = "2025-04-18T16:44:46.617Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920, upload-time = "2025-03-25T10:14:56.835Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256, upload-time = "2025-03-25T10:14:55.034Z" }, -] - -[[package]] -name = "python-multipart" -version = "0.0.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, -] - -[[package]] -name = "pyunormalize" -version = "16.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/08/568036c725dac746ecb267bb749ef930fb7907454fe69fce83c8557287fb/pyunormalize-16.0.0.tar.gz", hash = "sha256:2e1dfbb4a118154ae26f70710426a52a364b926c9191f764601f5a8cb12761f7", size = 49968, upload-time = "2024-09-17T17:08:18.245Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/f9/9d86e56f716e0651194a5ad58be9c146fcaf1de6901ac6f3cd3affeeb74e/pyunormalize-16.0.0-py3-none-any.whl", hash = "sha256:c647d95e5d1e2ea9a2f448d1d95d8518348df24eab5c3fd32d2b5c3300a49152", size = 49173, upload-time = "2024-09-17T17:08:17.078Z" }, -] - -[[package]] -name = "pywin32" -version = "310" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, - { url = "https://files.pythonhosted.org/packages/3c/84/1a8e3d7a15490d28a5d816efa229ecb4999cdc51a7c30dd8914f669093b8/pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213", size = 8522963, upload-time = "2025-03-17T00:55:50.969Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b1/68aa2986129fb1011dabbe95f0136f44509afaf072b12b8f815905a39f33/pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd", size = 8784284, upload-time = "2025-03-17T00:55:53.124Z" }, - { url = "https://files.pythonhosted.org/packages/b3/bd/d1592635992dd8db5bb8ace0551bc3a769de1ac8850200cfa517e72739fb/pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c", size = 9520748, upload-time = "2025-03-17T00:55:55.203Z" }, - { url = "https://files.pythonhosted.org/packages/90/b1/ac8b1ffce6603849eb45a91cf126c0fa5431f186c2e768bf56889c46f51c/pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582", size = 8455941, upload-time = "2025-03-17T00:55:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, - { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384, upload-time = "2025-03-17T00:56:04.383Z" }, - { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039, upload-time = "2025-03-17T00:56:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152, upload-time = "2025-03-17T00:56:07.819Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" }, - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, - { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669, upload-time = "2024-11-06T20:09:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684, upload-time = "2024-11-06T20:09:32.915Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589, upload-time = "2024-11-06T20:09:35.504Z" }, - { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121, upload-time = "2024-11-06T20:09:37.701Z" }, - { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275, upload-time = "2024-11-06T20:09:40.371Z" }, - { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257, upload-time = "2024-11-06T20:09:43.059Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727, upload-time = "2024-11-06T20:09:48.19Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667, upload-time = "2024-11-06T20:09:49.828Z" }, - { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963, upload-time = "2024-11-06T20:09:51.819Z" }, - { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700, upload-time = "2024-11-06T20:09:53.982Z" }, - { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592, upload-time = "2024-11-06T20:09:56.222Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929, upload-time = "2024-11-06T20:09:58.642Z" }, - { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213, upload-time = "2024-11-06T20:10:00.867Z" }, - { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734, upload-time = "2024-11-06T20:10:03.361Z" }, - { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052, upload-time = "2024-11-06T20:10:05.179Z" }, - { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, - { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, - { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, - { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, - { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, - { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, - { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, - { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, - { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, - { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, - { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, - { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, - { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, - { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, - { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, - { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, - { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, - { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, - { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, - { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, - { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, - { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, - { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, - { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, -] - -[[package]] -name = "requests" -version = "2.32.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, -] - -[[package]] -name = "rich" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, -] - -[[package]] -name = "rich-toolkit" -version = "0.14.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/7a/cb48b7024b247631ce39b1f14a0f1abedf311fb27b892b0e0387d809d4b5/rich_toolkit-0.14.7.tar.gz", hash = "sha256:6cca5a68850cc5778915f528eb785662c27ba3b4b2624612cce8340fa9701c5e", size = 104977, upload-time = "2025-05-27T15:48:09.377Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/2e/95fde5b818dac9a37683ea064096323f593442d0f6358923c5f635974393/rich_toolkit-0.14.7-py3-none-any.whl", hash = "sha256:def05cc6e0f1176d6263b6a26648f16a62c4563b277ca2f8538683acdba1e0da", size = 24870, upload-time = "2025-05-27T15:48:07.942Z" }, -] - -[[package]] -name = "rlp" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/2d/439b0728a92964a04d9c88ea1ca9ebb128893fbbd5834faa31f987f2fd4c/rlp-4.1.0.tar.gz", hash = "sha256:be07564270a96f3e225e2c107db263de96b5bc1f27722d2855bd3459a08e95a9", size = 33429, upload-time = "2025-02-04T22:05:59.089Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/fb/e4c0ced9893b84ac95b7181d69a9786ce5879aeb3bbbcbba80a164f85d6a/rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f", size = 19973, upload-time = "2025-02-04T22:05:57.05Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "starlette" -version = "0.46.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, -] - -[[package]] -name = "toolz" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790, upload-time = "2024-10-04T16:17:04.001Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383, upload-time = "2024-10-04T16:17:01.533Z" }, -] - -[[package]] -name = "typer" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, -] - -[[package]] -name = "types-requests" -version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/7f/73b3a04a53b0fd2a911d4ec517940ecd6600630b559e4505cc7b68beb5a0/types_requests-2.32.4.20250611.tar.gz", hash = "sha256:741c8777ed6425830bf51e54d6abe245f79b4dcb9019f1622b773463946bf826", size = 23118, upload-time = "2025-06-11T03:11:41.272Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/ea/0be9258c5a4fa1ba2300111aa5a0767ee6d18eb3fd20e91616c12082284d/types_requests-2.32.4.20250611-py3-none-any.whl", hash = "sha256:ad2fe5d3b0cb3c2c902c8815a70e7fb2302c4b8c1f77bdcd738192cdb3878072", size = 20643, upload-time = "2025-06-11T03:11:40.186Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, -] - -[[package]] -name = "urllib3" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, -] - -[[package]] -name = "uvicorn" -version = "0.34.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631, upload-time = "2025-06-01T07:48:17.531Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431, upload-time = "2025-06-01T07:48:15.664Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, - { url = "https://files.pythonhosted.org/packages/35/5a/62d5800358a78cc25c8a6c72ef8b10851bdb8cca22e14d9c74167b7f86da/uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d", size = 801898, upload-time = "2024-10-14T23:37:22.663Z" }, - { url = "https://files.pythonhosted.org/packages/f3/96/63695e0ebd7da6c741ccd4489b5947394435e198a1382349c17b1146bb97/uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26", size = 3827735, upload-time = "2024-10-14T23:37:25.129Z" }, - { url = "https://files.pythonhosted.org/packages/61/e0/f0f8ec84979068ffae132c58c79af1de9cceeb664076beea86d941af1a30/uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb", size = 3825126, upload-time = "2024-10-14T23:37:27.59Z" }, - { url = "https://files.pythonhosted.org/packages/bf/fe/5e94a977d058a54a19df95f12f7161ab6e323ad49f4dabc28822eb2df7ea/uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f", size = 3705789, upload-time = "2024-10-14T23:37:29.385Z" }, - { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523, upload-time = "2024-10-14T23:37:32.048Z" }, - { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410, upload-time = "2024-10-14T23:37:33.612Z" }, - { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476, upload-time = "2024-10-14T23:37:36.11Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855, upload-time = "2024-10-14T23:37:37.683Z" }, - { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185, upload-time = "2024-10-14T23:37:40.226Z" }, - { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256, upload-time = "2024-10-14T23:37:42.839Z" }, - { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323, upload-time = "2024-10-14T23:37:45.337Z" }, - { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284, upload-time = "2024-10-14T23:37:47.833Z" }, - { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349, upload-time = "2024-10-14T23:37:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089, upload-time = "2024-10-14T23:37:51.703Z" }, - { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770, upload-time = "2024-10-14T23:37:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321, upload-time = "2024-10-14T23:37:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022, upload-time = "2024-10-14T23:37:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" }, - { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" }, - { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" }, - { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" }, - { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" }, - { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" }, -] - -[[package]] -name = "watchfiles" -version = "1.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/e2/8ed598c42057de7aa5d97c472254af4906ff0a59a66699d426fc9ef795d7/watchfiles-1.0.5.tar.gz", hash = "sha256:b7529b5dcc114679d43827d8c35a07c493ad6f083633d573d81c660abc5979e9", size = 94537, upload-time = "2025-04-08T10:36:26.722Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/4d/d02e6ea147bb7fff5fd109c694a95109612f419abed46548a930e7f7afa3/watchfiles-1.0.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5c40fe7dd9e5f81e0847b1ea64e1f5dd79dd61afbedb57759df06767ac719b40", size = 405632, upload-time = "2025-04-08T10:34:41.832Z" }, - { url = "https://files.pythonhosted.org/packages/60/31/9ee50e29129d53a9a92ccf1d3992751dc56fc3c8f6ee721be1c7b9c81763/watchfiles-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c0db396e6003d99bb2d7232c957b5f0b5634bbd1b24e381a5afcc880f7373fb", size = 395734, upload-time = "2025-04-08T10:34:44.236Z" }, - { url = "https://files.pythonhosted.org/packages/ad/8c/759176c97195306f028024f878e7f1c776bda66ccc5c68fa51e699cf8f1d/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b551d4fb482fc57d852b4541f911ba28957d051c8776e79c3b4a51eb5e2a1b11", size = 455008, upload-time = "2025-04-08T10:34:45.617Z" }, - { url = "https://files.pythonhosted.org/packages/55/1a/5e977250c795ee79a0229e3b7f5e3a1b664e4e450756a22da84d2f4979fe/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:830aa432ba5c491d52a15b51526c29e4a4b92bf4f92253787f9726fe01519487", size = 459029, upload-time = "2025-04-08T10:34:46.814Z" }, - { url = "https://files.pythonhosted.org/packages/e6/17/884cf039333605c1d6e296cf5be35fad0836953c3dfd2adb71b72f9dbcd0/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a16512051a822a416b0d477d5f8c0e67b67c1a20d9acecb0aafa3aa4d6e7d256", size = 488916, upload-time = "2025-04-08T10:34:48.571Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e0/bcb6e64b45837056c0a40f3a2db3ef51c2ced19fda38484fa7508e00632c/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe0cbc787770e52a96c6fda6726ace75be7f840cb327e1b08d7d54eadc3bc85", size = 523763, upload-time = "2025-04-08T10:34:50.268Z" }, - { url = "https://files.pythonhosted.org/packages/24/e9/f67e9199f3bb35c1837447ecf07e9830ec00ff5d35a61e08c2cd67217949/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d363152c5e16b29d66cbde8fa614f9e313e6f94a8204eaab268db52231fe5358", size = 502891, upload-time = "2025-04-08T10:34:51.419Z" }, - { url = "https://files.pythonhosted.org/packages/23/ed/a6cf815f215632f5c8065e9c41fe872025ffea35aa1f80499f86eae922db/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee32c9a9bee4d0b7bd7cbeb53cb185cf0b622ac761efaa2eba84006c3b3a614", size = 454921, upload-time = "2025-04-08T10:34:52.67Z" }, - { url = "https://files.pythonhosted.org/packages/92/4c/e14978599b80cde8486ab5a77a821e8a982ae8e2fcb22af7b0886a033ec8/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29c7fd632ccaf5517c16a5188e36f6612d6472ccf55382db6c7fe3fcccb7f59f", size = 631422, upload-time = "2025-04-08T10:34:53.985Z" }, - { url = "https://files.pythonhosted.org/packages/b2/1a/9263e34c3458f7614b657f974f4ee61fd72f58adce8b436e16450e054efd/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e637810586e6fe380c8bc1b3910accd7f1d3a9a7262c8a78d4c8fb3ba6a2b3d", size = 625675, upload-time = "2025-04-08T10:34:55.173Z" }, - { url = "https://files.pythonhosted.org/packages/96/1f/1803a18bd6ab04a0766386a19bcfe64641381a04939efdaa95f0e3b0eb58/watchfiles-1.0.5-cp310-cp310-win32.whl", hash = "sha256:cd47d063fbeabd4c6cae1d4bcaa38f0902f8dc5ed168072874ea11d0c7afc1ff", size = 277921, upload-time = "2025-04-08T10:34:56.318Z" }, - { url = "https://files.pythonhosted.org/packages/c2/3b/29a89de074a7d6e8b4dc67c26e03d73313e4ecf0d6e97e942a65fa7c195e/watchfiles-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:86c0df05b47a79d80351cd179893f2f9c1b1cae49d96e8b3290c7f4bd0ca0a92", size = 291526, upload-time = "2025-04-08T10:34:57.95Z" }, - { url = "https://files.pythonhosted.org/packages/39/f4/41b591f59021786ef517e1cdc3b510383551846703e03f204827854a96f8/watchfiles-1.0.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:237f9be419e977a0f8f6b2e7b0475ababe78ff1ab06822df95d914a945eac827", size = 405336, upload-time = "2025-04-08T10:34:59.359Z" }, - { url = "https://files.pythonhosted.org/packages/ae/06/93789c135be4d6d0e4f63e96eea56dc54050b243eacc28439a26482b5235/watchfiles-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0da39ff917af8b27a4bdc5a97ac577552a38aac0d260a859c1517ea3dc1a7c4", size = 395977, upload-time = "2025-04-08T10:35:00.522Z" }, - { url = "https://files.pythonhosted.org/packages/d2/db/1cd89bd83728ca37054512d4d35ab69b5f12b8aa2ac9be3b0276b3bf06cc/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cfcb3952350e95603f232a7a15f6c5f86c5375e46f0bd4ae70d43e3e063c13d", size = 455232, upload-time = "2025-04-08T10:35:01.698Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/d8a4d44ffe960517e487c9c04f77b06b8abf05eb680bed71c82b5f2cad62/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b2dddba7a4e6151384e252a5632efcaa9bc5d1c4b567f3cb621306b2ca9f63", size = 459151, upload-time = "2025-04-08T10:35:03.358Z" }, - { url = "https://files.pythonhosted.org/packages/6c/da/267a1546f26465dead1719caaba3ce660657f83c9d9c052ba98fb8856e13/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95cf944fcfc394c5f9de794ce581914900f82ff1f855326f25ebcf24d5397418", size = 489054, upload-time = "2025-04-08T10:35:04.561Z" }, - { url = "https://files.pythonhosted.org/packages/b1/31/33850dfd5c6efb6f27d2465cc4c6b27c5a6f5ed53c6fa63b7263cf5f60f6/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecf6cd9f83d7c023b1aba15d13f705ca7b7d38675c121f3cc4a6e25bd0857ee9", size = 523955, upload-time = "2025-04-08T10:35:05.786Z" }, - { url = "https://files.pythonhosted.org/packages/09/84/b7d7b67856efb183a421f1416b44ca975cb2ea6c4544827955dfb01f7dc2/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:852de68acd6212cd6d33edf21e6f9e56e5d98c6add46f48244bd479d97c967c6", size = 502234, upload-time = "2025-04-08T10:35:07.187Z" }, - { url = "https://files.pythonhosted.org/packages/71/87/6dc5ec6882a2254cfdd8b0718b684504e737273903b65d7338efaba08b52/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5730f3aa35e646103b53389d5bc77edfbf578ab6dab2e005142b5b80a35ef25", size = 454750, upload-time = "2025-04-08T10:35:08.859Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6c/3786c50213451a0ad15170d091570d4a6554976cf0df19878002fc96075a/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:18b3bd29954bc4abeeb4e9d9cf0b30227f0f206c86657674f544cb032296acd5", size = 631591, upload-time = "2025-04-08T10:35:10.64Z" }, - { url = "https://files.pythonhosted.org/packages/1b/b3/1427425ade4e359a0deacce01a47a26024b2ccdb53098f9d64d497f6684c/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ba5552a1b07c8edbf197055bc9d518b8f0d98a1c6a73a293bc0726dce068ed01", size = 625370, upload-time = "2025-04-08T10:35:12.412Z" }, - { url = "https://files.pythonhosted.org/packages/15/ba/f60e053b0b5b8145d682672024aa91370a29c5c921a88977eb565de34086/watchfiles-1.0.5-cp311-cp311-win32.whl", hash = "sha256:2f1fefb2e90e89959447bc0420fddd1e76f625784340d64a2f7d5983ef9ad246", size = 277791, upload-time = "2025-04-08T10:35:13.719Z" }, - { url = "https://files.pythonhosted.org/packages/50/ed/7603c4e164225c12c0d4e8700b64bb00e01a6c4eeea372292a3856be33a4/watchfiles-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:b6e76ceb1dd18c8e29c73f47d41866972e891fc4cc7ba014f487def72c1cf096", size = 291622, upload-time = "2025-04-08T10:35:15.071Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c2/99bb7c96b4450e36877fde33690ded286ff555b5a5c1d925855d556968a1/watchfiles-1.0.5-cp311-cp311-win_arm64.whl", hash = "sha256:266710eb6fddc1f5e51843c70e3bebfb0f5e77cf4f27129278c70554104d19ed", size = 283699, upload-time = "2025-04-08T10:35:16.732Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8c/4f0b9bdb75a1bfbd9c78fad7d8854369283f74fe7cf03eb16be77054536d/watchfiles-1.0.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5eb568c2aa6018e26da9e6c86f3ec3fd958cee7f0311b35c2630fa4217d17f2", size = 401511, upload-time = "2025-04-08T10:35:17.956Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4e/7e15825def77f8bd359b6d3f379f0c9dac4eb09dd4ddd58fd7d14127179c/watchfiles-1.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a04059f4923ce4e856b4b4e5e783a70f49d9663d22a4c3b3298165996d1377f", size = 392715, upload-time = "2025-04-08T10:35:19.202Z" }, - { url = "https://files.pythonhosted.org/packages/58/65/b72fb817518728e08de5840d5d38571466c1b4a3f724d190cec909ee6f3f/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e380c89983ce6e6fe2dd1e1921b9952fb4e6da882931abd1824c092ed495dec", size = 454138, upload-time = "2025-04-08T10:35:20.586Z" }, - { url = "https://files.pythonhosted.org/packages/3e/a4/86833fd2ea2e50ae28989f5950b5c3f91022d67092bfec08f8300d8b347b/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe43139b2c0fdc4a14d4f8d5b5d967f7a2777fd3d38ecf5b1ec669b0d7e43c21", size = 458592, upload-time = "2025-04-08T10:35:21.87Z" }, - { url = "https://files.pythonhosted.org/packages/38/7e/42cb8df8be9a37e50dd3a818816501cf7a20d635d76d6bd65aae3dbbff68/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee0822ce1b8a14fe5a066f93edd20aada932acfe348bede8aa2149f1a4489512", size = 487532, upload-time = "2025-04-08T10:35:23.143Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/13d26721c85d7f3df6169d8b495fcac8ab0dc8f0945ebea8845de4681dab/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0dbcb1c2d8f2ab6e0a81c6699b236932bd264d4cef1ac475858d16c403de74d", size = 522865, upload-time = "2025-04-08T10:35:24.702Z" }, - { url = "https://files.pythonhosted.org/packages/a1/0d/7f9ae243c04e96c5455d111e21b09087d0eeaf9a1369e13a01c7d3d82478/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2014a2b18ad3ca53b1f6c23f8cd94a18ce930c1837bd891262c182640eb40a6", size = 499887, upload-time = "2025-04-08T10:35:25.969Z" }, - { url = "https://files.pythonhosted.org/packages/8e/0f/a257766998e26aca4b3acf2ae97dff04b57071e991a510857d3799247c67/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6ae86d5cb647bf58f9f655fcf577f713915a5d69057a0371bc257e2553234", size = 454498, upload-time = "2025-04-08T10:35:27.353Z" }, - { url = "https://files.pythonhosted.org/packages/81/79/8bf142575a03e0af9c3d5f8bcae911ee6683ae93a625d349d4ecf4c8f7df/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1a7bac2bde1d661fb31f4d4e8e539e178774b76db3c2c17c4bb3e960a5de07a2", size = 630663, upload-time = "2025-04-08T10:35:28.685Z" }, - { url = "https://files.pythonhosted.org/packages/f1/80/abe2e79f610e45c63a70d271caea90c49bbf93eb00fa947fa9b803a1d51f/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ab626da2fc1ac277bbf752446470b367f84b50295264d2d313e28dc4405d663", size = 625410, upload-time = "2025-04-08T10:35:30.42Z" }, - { url = "https://files.pythonhosted.org/packages/91/6f/bc7fbecb84a41a9069c2c6eb6319f7f7df113adf113e358c57fc1aff7ff5/watchfiles-1.0.5-cp312-cp312-win32.whl", hash = "sha256:9f4571a783914feda92018ef3901dab8caf5b029325b5fe4558c074582815249", size = 277965, upload-time = "2025-04-08T10:35:32.023Z" }, - { url = "https://files.pythonhosted.org/packages/99/a5/bf1c297ea6649ec59e935ab311f63d8af5faa8f0b86993e3282b984263e3/watchfiles-1.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:360a398c3a19672cf93527f7e8d8b60d8275119c5d900f2e184d32483117a705", size = 291693, upload-time = "2025-04-08T10:35:33.225Z" }, - { url = "https://files.pythonhosted.org/packages/7f/7b/fd01087cc21db5c47e5beae507b87965db341cce8a86f9eb12bf5219d4e0/watchfiles-1.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:1a2902ede862969077b97523987c38db28abbe09fb19866e711485d9fbf0d417", size = 283287, upload-time = "2025-04-08T10:35:34.568Z" }, - { url = "https://files.pythonhosted.org/packages/c7/62/435766874b704f39b2fecd8395a29042db2b5ec4005bd34523415e9bd2e0/watchfiles-1.0.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0b289572c33a0deae62daa57e44a25b99b783e5f7aed81b314232b3d3c81a11d", size = 401531, upload-time = "2025-04-08T10:35:35.792Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a6/e52a02c05411b9cb02823e6797ef9bbba0bfaf1bb627da1634d44d8af833/watchfiles-1.0.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a056c2f692d65bf1e99c41045e3bdcaea3cb9e6b5a53dcaf60a5f3bd95fc9763", size = 392417, upload-time = "2025-04-08T10:35:37.048Z" }, - { url = "https://files.pythonhosted.org/packages/3f/53/c4af6819770455932144e0109d4854437769672d7ad897e76e8e1673435d/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9dca99744991fc9850d18015c4f0438865414e50069670f5f7eee08340d8b40", size = 453423, upload-time = "2025-04-08T10:35:38.357Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d1/8e88df58bbbf819b8bc5cfbacd3c79e01b40261cad0fc84d1e1ebd778a07/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:894342d61d355446d02cd3988a7326af344143eb33a2fd5d38482a92072d9563", size = 458185, upload-time = "2025-04-08T10:35:39.708Z" }, - { url = "https://files.pythonhosted.org/packages/ff/70/fffaa11962dd5429e47e478a18736d4e42bec42404f5ee3b92ef1b87ad60/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab44e1580924d1ffd7b3938e02716d5ad190441965138b4aa1d1f31ea0877f04", size = 486696, upload-time = "2025-04-08T10:35:41.469Z" }, - { url = "https://files.pythonhosted.org/packages/39/db/723c0328e8b3692d53eb273797d9a08be6ffb1d16f1c0ba2bdbdc2a3852c/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6f9367b132078b2ceb8d066ff6c93a970a18c3029cea37bfd7b2d3dd2e5db8f", size = 522327, upload-time = "2025-04-08T10:35:43.289Z" }, - { url = "https://files.pythonhosted.org/packages/cd/05/9fccc43c50c39a76b68343484b9da7b12d42d0859c37c61aec018c967a32/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2e55a9b162e06e3f862fb61e399fe9f05d908d019d87bf5b496a04ef18a970a", size = 499741, upload-time = "2025-04-08T10:35:44.574Z" }, - { url = "https://files.pythonhosted.org/packages/23/14/499e90c37fa518976782b10a18b18db9f55ea73ca14641615056f8194bb3/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0125f91f70e0732a9f8ee01e49515c35d38ba48db507a50c5bdcad9503af5827", size = 453995, upload-time = "2025-04-08T10:35:46.336Z" }, - { url = "https://files.pythonhosted.org/packages/61/d9/f75d6840059320df5adecd2c687fbc18960a7f97b55c300d20f207d48aef/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:13bb21f8ba3248386337c9fa51c528868e6c34a707f729ab041c846d52a0c69a", size = 629693, upload-time = "2025-04-08T10:35:48.161Z" }, - { url = "https://files.pythonhosted.org/packages/fc/17/180ca383f5061b61406477218c55d66ec118e6c0c51f02d8142895fcf0a9/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:839ebd0df4a18c5b3c1b890145b5a3f5f64063c2a0d02b13c76d78fe5de34936", size = 624677, upload-time = "2025-04-08T10:35:49.65Z" }, - { url = "https://files.pythonhosted.org/packages/bf/15/714d6ef307f803f236d69ee9d421763707899d6298d9f3183e55e366d9af/watchfiles-1.0.5-cp313-cp313-win32.whl", hash = "sha256:4a8ec1e4e16e2d5bafc9ba82f7aaecfeec990ca7cd27e84fb6f191804ed2fcfc", size = 277804, upload-time = "2025-04-08T10:35:51.093Z" }, - { url = "https://files.pythonhosted.org/packages/a8/b4/c57b99518fadf431f3ef47a610839e46e5f8abf9814f969859d1c65c02c7/watchfiles-1.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:f436601594f15bf406518af922a89dcaab416568edb6f65c4e5bbbad1ea45c11", size = 291087, upload-time = "2025-04-08T10:35:52.458Z" }, - { url = "https://files.pythonhosted.org/packages/1a/03/81f9fcc3963b3fc415cd4b0b2b39ee8cc136c42fb10a36acf38745e9d283/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f59b870db1f1ae5a9ac28245707d955c8721dd6565e7f411024fa374b5362d1d", size = 405947, upload-time = "2025-04-08T10:36:13.721Z" }, - { url = "https://files.pythonhosted.org/packages/54/97/8c4213a852feb64807ec1d380f42d4fc8bfaef896bdbd94318f8fd7f3e4e/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9475b0093767e1475095f2aeb1d219fb9664081d403d1dff81342df8cd707034", size = 397276, upload-time = "2025-04-08T10:36:15.131Z" }, - { url = "https://files.pythonhosted.org/packages/78/12/d4464d19860cb9672efa45eec1b08f8472c478ed67dcd30647c51ada7aef/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc533aa50664ebd6c628b2f30591956519462f5d27f951ed03d6c82b2dfd9965", size = 455550, upload-time = "2025-04-08T10:36:16.635Z" }, - { url = "https://files.pythonhosted.org/packages/90/fb/b07bcdf1034d8edeaef4c22f3e9e3157d37c5071b5f9492ffdfa4ad4bed7/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed1cd825158dcaae36acce7b2db33dcbfd12b30c34317a88b8ed80f0541cc57", size = 455542, upload-time = "2025-04-08T10:36:18.655Z" }, -] - -[[package]] -name = "web3" -version = "7.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "eth-abi" }, - { name = "eth-account" }, - { name = "eth-hash", extra = ["pycryptodome"] }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "pyunormalize" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "requests" }, - { name = "types-requests" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7d/1e/fc1f5b5a12615cbdca57d35014cdb9823db7392d73b730fa0d89d6a13f6a/web3-7.12.0.tar.gz", hash = "sha256:08fbe79a2e2503c9820132ebad24ba0372831588cabac5f467999c97ace7dda3", size = 2195693, upload-time = "2025-05-22T21:06:05.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/df/0ccf18f244b96a93ba2710f7ce696da1f8dd44ef1126e3603dfb65cd68fe/web3-7.12.0-py3-none-any.whl", hash = "sha256:c7e2b9c1db5a379ef53b45fe8a19bdc2d47ad262039fbf6675794bc40f74bf06", size = 1369328, upload-time = "2025-05-22T21:06:03.124Z" }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, - { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, - { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, - { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, - { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, - { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, - { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, - { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, - { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - -[[package]] -name = "werkzeug" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, -] - -[[package]] -name = "x402" -version = "1.0.0" -source = { editable = "../../../../../python/legacy" } -dependencies = [ - { name = "eth-account" }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "fastapi", extra = ["standard"] }, - { name = "flask" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "web3" }, -] - -[package.metadata] -requires-dist = [ - { name = "eth-account", specifier = ">=0.13.7" }, - { name = "eth-typing", specifier = ">=4.0.0" }, - { name = "eth-utils", specifier = ">=3.0.0" }, - { name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" }, - { name = "flask", specifier = ">=3.0.0" }, - { name = "pydantic", specifier = ">=2.10.3" }, - { name = "pydantic-settings", specifier = ">=2.2.1" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "web3", specifier = ">=6.0.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.5" }, - { name = "pytest-asyncio", specifier = ">=1.0.0" }, - { name = "ruff", specifier = ">=0.11.9" }, -] - -[[package]] -name = "x402-fastapi-example" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "fastapi" }, - { name = "python-dotenv" }, - { name = "uvicorn" }, - { name = "x402" }, -] - -[package.metadata] -requires-dist = [ - { name = "fastapi", specifier = ">=0.109.0" }, - { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "uvicorn", specifier = ">=0.27.0" }, - { name = "x402", editable = "../../../../../python/legacy" }, -] - -[[package]] -name = "yarl" -version = "1.20.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/65/7fed0d774abf47487c64be14e9223749468922817b5e8792b8a64792a1bb/yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4", size = 132910, upload-time = "2025-06-10T00:42:31.108Z" }, - { url = "https://files.pythonhosted.org/packages/8a/7b/988f55a52da99df9e56dc733b8e4e5a6ae2090081dc2754fc8fd34e60aa0/yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a", size = 90644, upload-time = "2025-06-10T00:42:33.851Z" }, - { url = "https://files.pythonhosted.org/packages/f7/de/30d98f03e95d30c7e3cc093759982d038c8833ec2451001d45ef4854edc1/yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed", size = 89322, upload-time = "2025-06-10T00:42:35.688Z" }, - { url = "https://files.pythonhosted.org/packages/e0/7a/f2f314f5ebfe9200724b0b748de2186b927acb334cf964fd312eb86fc286/yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e", size = 323786, upload-time = "2025-06-10T00:42:37.817Z" }, - { url = "https://files.pythonhosted.org/packages/15/3f/718d26f189db96d993d14b984ce91de52e76309d0fd1d4296f34039856aa/yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73", size = 319627, upload-time = "2025-06-10T00:42:39.937Z" }, - { url = "https://files.pythonhosted.org/packages/a5/76/8fcfbf5fa2369157b9898962a4a7d96764b287b085b5b3d9ffae69cdefd1/yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e", size = 339149, upload-time = "2025-06-10T00:42:42.627Z" }, - { url = "https://files.pythonhosted.org/packages/3c/95/d7fc301cc4661785967acc04f54a4a42d5124905e27db27bb578aac49b5c/yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8", size = 333327, upload-time = "2025-06-10T00:42:44.842Z" }, - { url = "https://files.pythonhosted.org/packages/65/94/e21269718349582eee81efc5c1c08ee71c816bfc1585b77d0ec3f58089eb/yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23", size = 326054, upload-time = "2025-06-10T00:42:47.149Z" }, - { url = "https://files.pythonhosted.org/packages/32/ae/8616d1f07853704523519f6131d21f092e567c5af93de7e3e94b38d7f065/yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70", size = 315035, upload-time = "2025-06-10T00:42:48.852Z" }, - { url = "https://files.pythonhosted.org/packages/48/aa/0ace06280861ef055855333707db5e49c6e3a08840a7ce62682259d0a6c0/yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb", size = 338962, upload-time = "2025-06-10T00:42:51.024Z" }, - { url = "https://files.pythonhosted.org/packages/20/52/1e9d0e6916f45a8fb50e6844f01cb34692455f1acd548606cbda8134cd1e/yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2", size = 335399, upload-time = "2025-06-10T00:42:53.007Z" }, - { url = "https://files.pythonhosted.org/packages/f2/65/60452df742952c630e82f394cd409de10610481d9043aa14c61bf846b7b1/yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30", size = 338649, upload-time = "2025-06-10T00:42:54.964Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f5/6cd4ff38dcde57a70f23719a838665ee17079640c77087404c3d34da6727/yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309", size = 358563, upload-time = "2025-06-10T00:42:57.28Z" }, - { url = "https://files.pythonhosted.org/packages/d1/90/c42eefd79d0d8222cb3227bdd51b640c0c1d0aa33fe4cc86c36eccba77d3/yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24", size = 357609, upload-time = "2025-06-10T00:42:59.055Z" }, - { url = "https://files.pythonhosted.org/packages/03/c8/cea6b232cb4617514232e0f8a718153a95b5d82b5290711b201545825532/yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13", size = 350224, upload-time = "2025-06-10T00:43:01.248Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a3/eaa0ab9712f1f3d01faf43cf6f1f7210ce4ea4a7e9b28b489a2261ca8db9/yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8", size = 81753, upload-time = "2025-06-10T00:43:03.486Z" }, - { url = "https://files.pythonhosted.org/packages/8f/34/e4abde70a9256465fe31c88ed02c3f8502b7b5dead693a4f350a06413f28/yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16", size = 86817, upload-time = "2025-06-10T00:43:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b1/18/893b50efc2350e47a874c5c2d67e55a0ea5df91186b2a6f5ac52eff887cd/yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e", size = 133833, upload-time = "2025-06-10T00:43:07.393Z" }, - { url = "https://files.pythonhosted.org/packages/89/ed/b8773448030e6fc47fa797f099ab9eab151a43a25717f9ac043844ad5ea3/yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b", size = 91070, upload-time = "2025-06-10T00:43:09.538Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e3/409bd17b1e42619bf69f60e4f031ce1ccb29bd7380117a55529e76933464/yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b", size = 89818, upload-time = "2025-06-10T00:43:11.575Z" }, - { url = "https://files.pythonhosted.org/packages/f8/77/64d8431a4d77c856eb2d82aa3de2ad6741365245a29b3a9543cd598ed8c5/yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4", size = 347003, upload-time = "2025-06-10T00:43:14.088Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d2/0c7e4def093dcef0bd9fa22d4d24b023788b0a33b8d0088b51aa51e21e99/yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1", size = 336537, upload-time = "2025-06-10T00:43:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f3/fc514f4b2cf02cb59d10cbfe228691d25929ce8f72a38db07d3febc3f706/yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833", size = 362358, upload-time = "2025-06-10T00:43:18.704Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6d/a313ac8d8391381ff9006ac05f1d4331cee3b1efaa833a53d12253733255/yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d", size = 357362, upload-time = "2025-06-10T00:43:20.888Z" }, - { url = "https://files.pythonhosted.org/packages/00/70/8f78a95d6935a70263d46caa3dd18e1f223cf2f2ff2037baa01a22bc5b22/yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8", size = 348979, upload-time = "2025-06-10T00:43:23.169Z" }, - { url = "https://files.pythonhosted.org/packages/cb/05/42773027968968f4f15143553970ee36ead27038d627f457cc44bbbeecf3/yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf", size = 337274, upload-time = "2025-06-10T00:43:27.111Z" }, - { url = "https://files.pythonhosted.org/packages/05/be/665634aa196954156741ea591d2f946f1b78ceee8bb8f28488bf28c0dd62/yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e", size = 363294, upload-time = "2025-06-10T00:43:28.96Z" }, - { url = "https://files.pythonhosted.org/packages/eb/90/73448401d36fa4e210ece5579895731f190d5119c4b66b43b52182e88cd5/yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389", size = 358169, upload-time = "2025-06-10T00:43:30.701Z" }, - { url = "https://files.pythonhosted.org/packages/c3/b0/fce922d46dc1eb43c811f1889f7daa6001b27a4005587e94878570300881/yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f", size = 362776, upload-time = "2025-06-10T00:43:32.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/0d/b172628fce039dae8977fd22caeff3eeebffd52e86060413f5673767c427/yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845", size = 381341, upload-time = "2025-06-10T00:43:34.543Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9b/5b886d7671f4580209e855974fe1cecec409aa4a89ea58b8f0560dc529b1/yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1", size = 379988, upload-time = "2025-06-10T00:43:36.489Z" }, - { url = "https://files.pythonhosted.org/packages/73/be/75ef5fd0fcd8f083a5d13f78fd3f009528132a1f2a1d7c925c39fa20aa79/yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e", size = 371113, upload-time = "2025-06-10T00:43:38.592Z" }, - { url = "https://files.pythonhosted.org/packages/50/4f/62faab3b479dfdcb741fe9e3f0323e2a7d5cd1ab2edc73221d57ad4834b2/yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773", size = 81485, upload-time = "2025-06-10T00:43:41.038Z" }, - { url = "https://files.pythonhosted.org/packages/f0/09/d9c7942f8f05c32ec72cd5c8e041c8b29b5807328b68b4801ff2511d4d5e/yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e", size = 86686, upload-time = "2025-06-10T00:43:42.692Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, - { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, - { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, - { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, - { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, - { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, - { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, - { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, - { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, - { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, - { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, - { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, - { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, - { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, - { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, - { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, - { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, - { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, - { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, - { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, - { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, - { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, - { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, - { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, - { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, - { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, - { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, - { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, - { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, - { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, - { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, - { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, - { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, - { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, - { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, - { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, - { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, -] diff --git a/examples/python/legacy/servers/flask/.env-local b/examples/python/legacy/servers/flask/.env-local deleted file mode 100644 index 459e595ede..0000000000 --- a/examples/python/legacy/servers/flask/.env-local +++ /dev/null @@ -1 +0,0 @@ -ADDRESS= diff --git a/examples/python/legacy/servers/flask/README.md b/examples/python/legacy/servers/flask/README.md deleted file mode 100644 index 380b150e3e..0000000000 --- a/examples/python/legacy/servers/flask/README.md +++ /dev/null @@ -1,52 +0,0 @@ -# x402 Flask Example Server - -This is an example Flask server that demonstrates how to use the x402 `flask` middleware to implement paywall functionality in your API endpoints. - -## Prerequisites - -- Python 3.10+ -- A valid Ethereum address for receiving payments - -## Setup - -1. Copy `.env-local` to `.env` and add your Ethereum address to receive payments: - -```bash -cp .env-local .env -``` - -2. Install dependencies: -```bash -uv sync -``` - -3. Run the server: -```bash -uv run python main.py -``` - -The server will start on http://localhost:4021 - -## Extending the Example - -To add more paid endpoints, follow this pattern: - -```python -# First, initialize the payment middleware -payment_middleware = PaymentMiddleware(app) - -# Then add payment configurations for your routes -payment_middleware.add( - path="/your-endpoint", - price="$0.10", - pay_to_address=ADDRESS, - network=NETWORK, -) - -# Then define your routes as normal -@app.route("/your-endpoint") -def your_endpoint(): - return jsonify({ - # Your response data - }) -``` diff --git a/examples/python/legacy/servers/flask/main.py b/examples/python/legacy/servers/flask/main.py deleted file mode 100644 index 7837542356..0000000000 --- a/examples/python/legacy/servers/flask/main.py +++ /dev/null @@ -1,72 +0,0 @@ -import os -from flask import Flask, jsonify -from dotenv import load_dotenv -from x402.flask.middleware import PaymentMiddleware -from x402.types import EIP712Domain, TokenAmount, TokenAsset - -# Load environment variables -load_dotenv() - -# Get configuration from environment -ADDRESS = os.getenv("ADDRESS") - -if not ADDRESS: - raise ValueError("Missing required environment variables") - -app = Flask(__name__) - -# Initialize payment middleware -payment_middleware = PaymentMiddleware(app) - -# Apply payment middleware to specific routes -payment_middleware.add( - path="/weather", - price="$0.001", - pay_to_address=ADDRESS, - network="base-sepolia", -) - -# Apply payment middleware to premium routes -payment_middleware.add( - path="/premium/*", - price=TokenAmount( - amount="10000", - asset=TokenAsset( - address="0x036CbD53842c5426634e7929541eC2318f3dCF7e", - decimals=6, - eip712=EIP712Domain(name="USDC", version="2"), - ), - ), - pay_to_address=ADDRESS, - network="base-sepolia", -) - - -@app.route("/weather") -def get_weather(): - return jsonify( - { - "report": { - "weather": "sunny", - "temperature": 70, - } - } - ) - - -@app.route("/premium/content") -def get_premium_content(): - return jsonify( - { - "content": "This is premium content", - } - ) - - -@app.route("/public") -def public(): - return jsonify({"message": "This is a public endpoint."}) - - -if __name__ == "__main__": - app.run(host="0.0.0.0", port=4021, debug=True) diff --git a/examples/python/legacy/servers/flask/pyproject.toml b/examples/python/legacy/servers/flask/pyproject.toml deleted file mode 100644 index 7d1555af19..0000000000 --- a/examples/python/legacy/servers/flask/pyproject.toml +++ /dev/null @@ -1,27 +0,0 @@ -[project] -name = "x402-flask-example" -version = "0.1.0" -description = "Example of using a fastapi server with x402 middleware" -requires-python = ">=3.10" -dependencies = [ - "x402", - "Flask>=3.1.1", - "uvicorn>=0.27.0", - "python-dotenv>=1.0.0" -] - -[build-system] -requires = ["hatchling"] -build-backend = "hatchling.build" - -[tool.hatch.build.targets.wheel] -packages = ["."] - -[tool.hatch.metadata] -allow-direct-references = true - -[tool.uv] -package = false - -[tool.uv.sources] -x402 = { path = "../../../../../python/legacy", editable = true } diff --git a/examples/python/legacy/servers/flask/uv.lock b/examples/python/legacy/servers/flask/uv.lock deleted file mode 100644 index af615f565a..0000000000 --- a/examples/python/legacy/servers/flask/uv.lock +++ /dev/null @@ -1,1975 +0,0 @@ -version = 1 -revision = 2 -requires-python = ">=3.10" - -[[package]] -name = "aiohappyeyeballs" -version = "2.6.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/26/30/f84a107a9c4331c14b2b586036f40965c128aa4fee4dda5d3d51cb14ad54/aiohappyeyeballs-2.6.1.tar.gz", hash = "sha256:c3f9d0113123803ccadfdf3f0faa505bc78e6a72d1cc4806cbd719826e943558", size = 22760, upload-time = "2025-03-12T01:42:48.764Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/15/5bf3b99495fb160b63f95972b81750f18f7f4e02ad051373b669d17d44f2/aiohappyeyeballs-2.6.1-py3-none-any.whl", hash = "sha256:f349ba8f4b75cb25c99c5c2d84e997e485204d2902a9597802b0371f09331fb8", size = 15265, upload-time = "2025-03-12T01:42:47.083Z" }, -] - -[[package]] -name = "aiohttp" -version = "3.12.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohappyeyeballs" }, - { name = "aiosignal" }, - { name = "async-timeout", marker = "python_full_version < '3.11'" }, - { name = "attrs" }, - { name = "frozenlist" }, - { name = "multidict" }, - { name = "propcache" }, - { name = "yarl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f2/84/ea27e6ad14747d8c51afe201fb88a5c8282b6278256d30a6f71f730add88/aiohttp-3.12.12.tar.gz", hash = "sha256:05875595d2483d96cb61fa9f64e75262d7ac6251a7e3c811d8e26f7d721760bd", size = 7818643, upload-time = "2025-06-10T05:22:00.247Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b4/d9/cfde93b9cb75253c716b8b1c773565209e3d4dd0772dd3ce3a2adcaa4639/aiohttp-3.12.12-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6f25e9d274d6abbb15254f76f100c3984d6b9ad6e66263cc60a465dd5c7e48f5", size = 702071, upload-time = "2025-06-10T05:18:23.986Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/46e38b8bc0bc645317deec32612af922ad9bafd85a1df255a67c2f2305f6/aiohttp-3.12.12-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b8ec3c1a1c13d24941b5b913607e57b9364e4c0ea69d5363181467492c4b2ba6", size = 478436, upload-time = "2025-06-10T05:18:28.411Z" }, - { url = "https://files.pythonhosted.org/packages/8f/47/9c83db7f02ca71eb99a707ee13657fc24ba703b9babc59000c1f58ac1198/aiohttp-3.12.12-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:81ef2f9253c327c211cb7b06ea2edd90e637cf21c347b894d540466b8d304e08", size = 466213, upload-time = "2025-06-10T05:18:30.706Z" }, - { url = "https://files.pythonhosted.org/packages/31/fe/4690c112e269e06c9182c32eeb43f3a95c4f203fdb095502717327993b80/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:28ded835c3663fd41c9ad44685811b11e34e6ac9a7516a30bfce13f6abba4496", size = 1648258, upload-time = "2025-06-10T05:18:32.498Z" }, - { url = "https://files.pythonhosted.org/packages/c8/1f/dacca6c7bbe69c77d8535d7a672478803e7078cc20fd9993fe09aa5be880/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a4b78ccf254fc10605b263996949a94ca3f50e4f9100e05137d6583e266b711e", size = 1622316, upload-time = "2025-06-10T05:18:34.357Z" }, - { url = "https://files.pythonhosted.org/packages/ff/65/5ef47708f70524fcdecda735e0aea06e0feb7b8679e976e9bd1e7900f4c0/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4f4a5af90d5232c41bb857568fe7d11ed84408653ec9da1ff999cc30258b9bd1", size = 1694723, upload-time = "2025-06-10T05:18:36.858Z" }, - { url = "https://files.pythonhosted.org/packages/18/62/ab32bfa59f61292e4096c383316863e10001eec30e5b4b314856ed7156e2/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ffa5205c2f53f1120e93fdf2eca41b0f6344db131bc421246ee82c1e1038a14a", size = 1737037, upload-time = "2025-06-10T05:18:39.663Z" }, - { url = "https://files.pythonhosted.org/packages/c1/b9/8b8f793081311e4f63aea63003a519064048e406c627c0454d6ed09dbc99/aiohttp-3.12.12-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f68301660f0d7a3eddfb84f959f78a8f9db98c76a49b5235508fa16edaad0f7c", size = 1641701, upload-time = "2025-06-10T05:18:41.666Z" }, - { url = "https://files.pythonhosted.org/packages/1a/5c/72f510d42d626463b526345dcb8d14b390de89a9ba27a4717b518460bcd4/aiohttp-3.12.12-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:db874d3b0c92fdbb553751af9d2733b378c25cc83cd9dfba87f12fafd2dc9cd5", size = 1581824, upload-time = "2025-06-10T05:18:44.136Z" }, - { url = "https://files.pythonhosted.org/packages/61/6f/9378c9e1543d1c800ca040e21cd333b8f923ed051ae82b5a49ad96a6ac71/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5e53cf9c201b45838a2d07b1f2d5f7fec9666db7979240002ce64f9b8a1e0cf2", size = 1625674, upload-time = "2025-06-10T05:18:46.716Z" }, - { url = "https://files.pythonhosted.org/packages/bb/85/4eef9bd52b497a405c88469cc099f4d15d33b149b5746ca4ef8ec6ab6388/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:8687cc5f32b4e328c233acd387d09a1b477007896b2f03c1c823a0fd05f63883", size = 1636460, upload-time = "2025-06-10T05:18:49.305Z" }, - { url = "https://files.pythonhosted.org/packages/56/59/d8e954830b375fd658843cf7d88d27ca5e38dd5fcbfe62db3d1ba415d0fe/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:5ee537ad29de716a3d8dc46c609908de0c25ffeebf93cd94a03d64cdc07d66d0", size = 1611912, upload-time = "2025-06-10T05:18:51.694Z" }, - { url = "https://files.pythonhosted.org/packages/c3/5d/d0096a02f0515a38dff67db42d966273a12d17fc895e91466bfb4ab3875e/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:411f821be5af6af11dc5bed6c6c1dc6b6b25b91737d968ec2756f9baa75e5f9b", size = 1691498, upload-time = "2025-06-10T05:18:54.36Z" }, - { url = "https://files.pythonhosted.org/packages/87/8d/d3a02397a6345c06623ae4648e2aef18fced858510b4a89d7262cfa4c683/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:f90319d94cf5f9786773237f24bd235a7b5959089f1af8ec1154580a3434b503", size = 1714737, upload-time = "2025-06-10T05:18:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/a9/40/b81000bf07c96db878703ea3dc561393d82441597729910459a8e06acc9a/aiohttp-3.12.12-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:73b148e606f34e9d513c451fd65efe1091772659ca5703338a396a99f60108ff", size = 1643078, upload-time = "2025-06-10T05:18:59.33Z" }, - { url = "https://files.pythonhosted.org/packages/41/e5/31830642ce2c6d3dba74ed8a94933213df5e1651c1e8b4efc81cc88105ab/aiohttp-3.12.12-cp310-cp310-win32.whl", hash = "sha256:d40e7bfd577fdc8a92b72f35dfbdd3ec90f1bc8a72a42037fefe34d4eca2d4a1", size = 427517, upload-time = "2025-06-10T05:19:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/55/9d/a4e5379d44679e5f8d7d7ebecb0dae8cafab95176c4e753da6bc4b4aebb5/aiohttp-3.12.12-cp310-cp310-win_amd64.whl", hash = "sha256:65c7804a2343893d6dea9fce69811aea0a9ac47f68312cf2e3ee1668cd9a387f", size = 450725, upload-time = "2025-06-10T05:19:03.874Z" }, - { url = "https://files.pythonhosted.org/packages/47/1f/b1b66e05dc3066a9ba7862d50e2e95b3871db82ccf9652568845f353eeba/aiohttp-3.12.12-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:38823fe0d8bc059b3eaedb263fe427d887c7032e72b4ef92c472953285f0e658", size = 709385, upload-time = "2025-06-10T05:19:05.763Z" }, - { url = "https://files.pythonhosted.org/packages/43/e6/3230e42af16438b450b1e193c537fd3d2d31771dafda3c2105a8d11af707/aiohttp-3.12.12-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:10237f2c34711215d04ed21da63852ce023608299554080a45c576215d9df81c", size = 481660, upload-time = "2025-06-10T05:19:08.332Z" }, - { url = "https://files.pythonhosted.org/packages/06/ba/cfa91fe5cc262535e1175b1522d8fcc09f9d6ad18b85241f4ee3be1d780f/aiohttp-3.12.12-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:563ec477c0dc6d56fc7f943a3475b5acdb399c7686c30f5a98ada24bb7562c7a", size = 469924, upload-time = "2025-06-10T05:19:10.342Z" }, - { url = "https://files.pythonhosted.org/packages/9a/f0/5c706cfddd4769b55c0cda466aa6034412d39e416f0b30dda81c4a24616f/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f3d05c46a61aca7c47df74afff818bc06a251ab95d95ff80b53665edfe1e0bdf", size = 1740116, upload-time = "2025-06-10T05:19:12.783Z" }, - { url = "https://files.pythonhosted.org/packages/4d/9f/04dba2e1c8bee53c3c623d11a1f947c9e2712500f734dc0dfd06daad32ec/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:277c882916759b4a6b6dc7e2ceb124aad071b3c6456487808d9ab13e1b448d57", size = 1688784, upload-time = "2025-06-10T05:19:15.36Z" }, - { url = "https://files.pythonhosted.org/packages/df/24/19d6d4c41fbf8304fe7c111fcc701e0aa5a2232ee3ac16272677a11f9cfe/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:216abf74b324b0f4e67041dd4fb2819613909a825904f8a51701fbcd40c09cd7", size = 1787575, upload-time = "2025-06-10T05:19:18.586Z" }, - { url = "https://files.pythonhosted.org/packages/0c/59/01f4c55a1f91ad3b5255b2498b3a22362a3fe6ee9bc9ba1af3cc668244da/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:65d6cefad286459b68e7f867b9586a821fb7f121057b88f02f536ef570992329", size = 1826621, upload-time = "2025-06-10T05:19:21.284Z" }, - { url = "https://files.pythonhosted.org/packages/55/85/6357166918ff5025602a7cc41332c1ae7a5b57f2fe3da4d755ae30f24bd0/aiohttp-3.12.12-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:feaaaff61966b5f4b4eae0b79fc79427f49484e4cfa5ab7d138ecd933ab540a8", size = 1729082, upload-time = "2025-06-10T05:19:23.307Z" }, - { url = "https://files.pythonhosted.org/packages/e3/ca/de3b5ccd5a2aa9352f6ec6f446565f6e1601ebb54860c94c686a9ff76660/aiohttp-3.12.12-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a05917780b7cad1755784b16cfaad806bc16029a93d15f063ca60185b7d9ba05", size = 1666159, upload-time = "2025-06-10T05:19:25.929Z" }, - { url = "https://files.pythonhosted.org/packages/d1/69/a1006021a1d3244c0872ee75cd8da150e0098b3b2ec6945c225754d11a60/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:082c5ec6d262c1b2ee01c63f4fb9152c17f11692bf16f0f100ad94a7a287d456", size = 1714433, upload-time = "2025-06-10T05:19:28.044Z" }, - { url = "https://files.pythonhosted.org/packages/d2/2a/15aa1179e9fbdd0d17cdf117b4296dedad098abb5a93f8e9c8ab4626f6ea/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:b265a3a8b379b38696ac78bdef943bdc4f4a5d6bed1a3fb5c75c6bab1ecea422", size = 1709590, upload-time = "2025-06-10T05:19:30.165Z" }, - { url = "https://files.pythonhosted.org/packages/a2/f0/95ed9e21250815f1d1a0cd3e868a3f39400a16010ae59f19ddd4ccc4e787/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:2e0f2e208914ecbc4b2a3b7b4daa759d0c587d9a0b451bb0835ac47fae7fa735", size = 1689776, upload-time = "2025-06-10T05:19:32.965Z" }, - { url = "https://files.pythonhosted.org/packages/81/4d/370ecc133c648c98a85445f2d331c1272859c89cd52c29a293015bc352c7/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:9923b025845b72f64d167bca221113377c8ffabd0a351dc18fb839d401ee8e22", size = 1783378, upload-time = "2025-06-10T05:19:35.14Z" }, - { url = "https://files.pythonhosted.org/packages/a8/86/414e3dae7e07caf6b02cd75d7148d0d8673d4c5077f407be3627d6e33fac/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:1ebb213445900527831fecc70e185bf142fdfe5f2a691075f22d63c65ee3c35a", size = 1803841, upload-time = "2025-06-10T05:19:37.41Z" }, - { url = "https://files.pythonhosted.org/packages/88/df/486f10df681cd1a8c898acc8dc2edbd46ffb088b886757b71ae362bf44d3/aiohttp-3.12.12-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6fc369fb273a8328077d37798b77c1e65676709af5c182cb74bd169ca9defe81", size = 1716896, upload-time = "2025-06-10T05:19:40.172Z" }, - { url = "https://files.pythonhosted.org/packages/07/1e/1cacaf5d838869432e96ece1580d0b51494ebb66351f0e8118b74b38d2f0/aiohttp-3.12.12-cp311-cp311-win32.whl", hash = "sha256:58ecd10fda6a44c311cd3742cfd2aea8c4c600338e9f27cb37434d9f5ca9ddaa", size = 427030, upload-time = "2025-06-10T05:19:42.152Z" }, - { url = "https://files.pythonhosted.org/packages/30/dd/e89c1d190da2c84e0ca03c2970b9988a9c56005d18db7f447cf62b3ae6d0/aiohttp-3.12.12-cp311-cp311-win_amd64.whl", hash = "sha256:b0066e88f30be00badffb5ef8f2281532b9a9020863d873ae15f7c147770b6ec", size = 451419, upload-time = "2025-06-10T05:19:44.176Z" }, - { url = "https://files.pythonhosted.org/packages/df/e6/df14ec151942818ecc5e685fa8a4b07d3d3d8a9e4a7d2701047c89290551/aiohttp-3.12.12-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:98451ce9ce229d092f278a74a7c2a06b3aa72984673c87796126d7ccade893e9", size = 700494, upload-time = "2025-06-10T05:19:46.18Z" }, - { url = "https://files.pythonhosted.org/packages/4f/dc/7bc6e17adcd7a82b0d0317ad3e792ac22c93fb672077f0eade93e8d70182/aiohttp-3.12.12-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:adbac7286d89245e1aff42e948503fdc6edf6d5d65c8e305a67c40f6a8fb95f4", size = 475095, upload-time = "2025-06-10T05:19:48.246Z" }, - { url = "https://files.pythonhosted.org/packages/80/fd/c4e8846ad9d9ecdb7d5ba96de65b7bf2c1582f0b2732f2023080c1c05255/aiohttp-3.12.12-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0728882115bfa85cbd8d0f664c8ccc0cfd5bd3789dd837596785450ae52fac31", size = 467929, upload-time = "2025-06-10T05:19:50.79Z" }, - { url = "https://files.pythonhosted.org/packages/70/40/abebcf5c81f5e65b4379c05929773be2731ce12414264d3e0fe09ee241eb/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6bf3b9d9e767f9d0e09fb1a31516410fc741a62cc08754578c40abc497d09540", size = 1714729, upload-time = "2025-06-10T05:19:52.989Z" }, - { url = "https://files.pythonhosted.org/packages/8e/67/4c4f96ef6f16405e7c5205ab3c28852c7e904493b6ddc1c744dda1c97a81/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c944860e86b9f77a462321a440ccf6fa10f5719bb9d026f6b0b11307b1c96c7b", size = 1697380, upload-time = "2025-06-10T05:19:55.832Z" }, - { url = "https://files.pythonhosted.org/packages/e9/a2/dae9ebea4caa8030170c0237e55fa0960df44b3596a849ab9ea621964054/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b1979e1f0c98c06fd0cd940988833b102fa3aa56751f6c40ffe85cabc51f6fd", size = 1752474, upload-time = "2025-06-10T05:19:58.007Z" }, - { url = "https://files.pythonhosted.org/packages/31/ef/f3d9073565ac7ad5257aaa1490ebfc2f182dfc817d3ccfd38c8ab35b2247/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:120b7dd084e96cfdad85acea2ce1e7708c70a26db913eabb8d7b417c728f5d84", size = 1798631, upload-time = "2025-06-10T05:20:00.393Z" }, - { url = "https://files.pythonhosted.org/packages/8b/0b/8b1978662274c80c8e4a739d9be1ae9ef25e5ce42b55838d6a9d1a4e3497/aiohttp-3.12.12-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e58f5ae79649ffa247081c2e8c85e31d29623cf2a3137dda985ae05c9478aae", size = 1718071, upload-time = "2025-06-10T05:20:02.812Z" }, - { url = "https://files.pythonhosted.org/packages/56/aa/35786137db867901b41cb3d2c19c0f4c56dfe581694dba99dec2683d8f8d/aiohttp-3.12.12-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9aa5f049e3e2745b0141f13e5a64e7c48b1a1427ed18bbb7957b348f282fee56", size = 1633871, upload-time = "2025-06-10T05:20:05.127Z" }, - { url = "https://files.pythonhosted.org/packages/63/1d/34d45497dd04d08d662ecda875c44e91d271bbc5d21f4c9e4cbd3ddf7ae2/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7163cc9cf3722d90f1822f8a38b211e3ae2fc651c63bb55449f03dc1b3ff1d44", size = 1694933, upload-time = "2025-06-10T05:20:07.431Z" }, - { url = "https://files.pythonhosted.org/packages/29/c7/41e09a4517449eabbb0a7fe6d60f584fe5b21d4bff761197eb0b81e70034/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:ef97c4d035b721de6607f3980fa3e4ef0ec3aca76474b5789b7fac286a8c4e23", size = 1716386, upload-time = "2025-06-10T05:20:09.787Z" }, - { url = "https://files.pythonhosted.org/packages/3a/32/907bd2010b51b70de5314ad707dfc4e898ea0011ff3d678cdf43d6f8980a/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:1c14448d6a86acadc3f7b2f4cc385d1fb390acb6f37dce27f86fe629410d92e3", size = 1657039, upload-time = "2025-06-10T05:20:12.198Z" }, - { url = "https://files.pythonhosted.org/packages/60/27/8d87344a33346dcd39273adc33060aeb135e0ef70d1d6e71a3b03894a8e9/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:a1b6df6255cfc493454c79221183d64007dd5080bcda100db29b7ff181b8832c", size = 1736599, upload-time = "2025-06-10T05:20:14.519Z" }, - { url = "https://files.pythonhosted.org/packages/ca/45/57c7ef1af694a6d0906abab6edde03787c8c6b0cf5d8359b69d1eb0679df/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:60fc7338dfb0626c2927bfbac4785de3ea2e2bbe3d328ba5f3ece123edda4977", size = 1764575, upload-time = "2025-06-10T05:20:16.993Z" }, - { url = "https://files.pythonhosted.org/packages/2a/cc/b1f918cd702efa9ead9d41f89214e9225cda4e5d013d6eed7f1915c17d0a/aiohttp-3.12.12-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:d2afc72207ef4c9d4ca9fcd00689a6a37ef2d625600c3d757b5c2b80c9d0cf9a", size = 1724184, upload-time = "2025-06-10T05:20:19.296Z" }, - { url = "https://files.pythonhosted.org/packages/47/55/089762ee32c2a2e0f523d9ab38c9da2a344cac0e0cc8d16ecf206517ef7e/aiohttp-3.12.12-cp312-cp312-win32.whl", hash = "sha256:8098a48f93b2cbcdb5778e7c9a0e0375363e40ad692348e6e65c3b70d593b27c", size = 421762, upload-time = "2025-06-10T05:20:22.063Z" }, - { url = "https://files.pythonhosted.org/packages/ab/47/151f657e429972916f61399bd52b410e9072d5a2cae1b794f890930e5797/aiohttp-3.12.12-cp312-cp312-win_amd64.whl", hash = "sha256:d1c1879b2e0fc337d7a1b63fe950553c2b9e93c071cf95928aeea1902d441403", size = 447863, upload-time = "2025-06-10T05:20:24.326Z" }, - { url = "https://files.pythonhosted.org/packages/ee/3e/396a7d1c47aa7a74612b186dc716857506c61afac72337a7a96215c2a124/aiohttp-3.12.12-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ea5d604318234427929d486954e3199aded65f41593ac57aa0241ab93dda3d15", size = 694901, upload-time = "2025-06-10T05:20:26.58Z" }, - { url = "https://files.pythonhosted.org/packages/cc/97/235e48eadf73a1854b4d4da29b88d00049309d897d55a511e1cbe4412603/aiohttp-3.12.12-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e03ff38250b8b572dce6fcd7b6fb6ee398bb8a59e6aa199009c5322d721df4fc", size = 472552, upload-time = "2025-06-10T05:20:28.957Z" }, - { url = "https://files.pythonhosted.org/packages/6b/73/cd7c9439e8cab4113650541017c6524bd0e675b219dfdbbf945a78305e3f/aiohttp-3.12.12-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:71125b1fc2b6a94bccc63bbece620906a4dead336d2051f8af9cbf04480bc5af", size = 464853, upload-time = "2025-06-10T05:20:31.652Z" }, - { url = "https://files.pythonhosted.org/packages/d1/33/eea88ee55ed4b3f74732d9fc773e6fcf134a2971a19c7ecc49a291e7e57f/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:784a66f9f853a22c6b8c2bd0ff157f9b879700f468d6d72cfa99167df08c5c9c", size = 1703671, upload-time = "2025-06-10T05:20:33.969Z" }, - { url = "https://files.pythonhosted.org/packages/2a/e3/a67ecf9c154b13bad9e2a86ea3782a4b73e889343ffde8c1aadcf9099c09/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:a5be0b58670b54301404bd1840e4902570a1c3be00358e2700919cb1ea73c438", size = 1684934, upload-time = "2025-06-10T05:20:36.721Z" }, - { url = "https://files.pythonhosted.org/packages/89/f0/3aaea866531be2f2fcf3a87607e1f55fa72e6ce5acd6b058941a4fc35e15/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8f13566fc7bf5a728275b434bc3bdea87a7ed3ad5f734102b02ca59d9b510f", size = 1737004, upload-time = "2025-06-10T05:20:39.533Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/15867a4c7d39d8fd9bd02191cf60b1d06415fc407bbd4ff2f9660845f1cb/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d736e57d1901683bc9be648aa308cb73e646252c74b4c639c35dcd401ed385ea", size = 1786378, upload-time = "2025-06-10T05:20:42.03Z" }, - { url = "https://files.pythonhosted.org/packages/bd/61/82b15f87088b35705e01fce55806241b45a1099b3470bbca0bed8ee98662/aiohttp-3.12.12-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e2007eaa7aae9102f211c519d1ec196bd3cecb1944a095db19eeaf132b798738", size = 1708707, upload-time = "2025-06-10T05:20:44.474Z" }, - { url = "https://files.pythonhosted.org/packages/28/f2/aed0786d5a1c2ed1f5a13ff2a98baacc27206b81d93812da28fc49d8a5d0/aiohttp-3.12.12-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2a813e61583cab6d5cdbaa34bc28863acdb92f9f46e11de1b3b9251a1e8238f6", size = 1622410, upload-time = "2025-06-10T05:20:46.957Z" }, - { url = "https://files.pythonhosted.org/packages/17/54/8305f49a960376136ada977be1370fddb584c63d40bd1b9bef59469f28c7/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:e408293aa910b0aea48b86a28eace41d497a85ba16c20f619f0c604597ef996c", size = 1675435, upload-time = "2025-06-10T05:20:49.379Z" }, - { url = "https://files.pythonhosted.org/packages/bb/dc/0a55350025bc297265cfa6c6b1b1f7508f4226ca3238697cbe5e772a7d76/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:f3d31faf290f5a30acba46b388465b67c6dbe8655d183e9efe2f6a1d594e6d9d", size = 1707099, upload-time = "2025-06-10T05:20:51.974Z" }, - { url = "https://files.pythonhosted.org/packages/d8/70/d949a1612b996e49d540c10ed77a0a1465c482a590e9a59c1c7897746119/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0b84731697325b023902aa643bd1726d999f5bc7854bc28b17ff410a81151d4b", size = 1649693, upload-time = "2025-06-10T05:20:54.973Z" }, - { url = "https://files.pythonhosted.org/packages/c1/ea/fb87beb7135e25576a1e6fbe98106c037d9fcf1543f19108f9ceb73c192c/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:a324c6852b6e327811748446e56cc9bb6eaa58710557922183175816e82a4234", size = 1725825, upload-time = "2025-06-10T05:20:57.433Z" }, - { url = "https://files.pythonhosted.org/packages/f1/1f/adbeb3e440d49b733cef499ace94723ab1fe9fb516425e219379e03b7c9a/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:22fd867fbd72612dcf670c90486dbcbaf702cb807fb0b42bc0b7a142a573574a", size = 1759300, upload-time = "2025-06-10T05:21:00.444Z" }, - { url = "https://files.pythonhosted.org/packages/f2/c1/2fe007ad930f409d0d7fd9916cd55ec9b78b6a611a237424266ed71da48b/aiohttp-3.12.12-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:3e092f1a970223794a4bf620a26c0e4e4e8e36bccae9b0b5da35e6d8ee598a03", size = 1708189, upload-time = "2025-06-10T05:21:02.969Z" }, - { url = "https://files.pythonhosted.org/packages/85/5e/ed3ed640fafae3972eae6cd26f66240108cf62452ac8128d59970d538cb1/aiohttp-3.12.12-cp313-cp313-win32.whl", hash = "sha256:7f5f5eb8717ef8ba15ab35fcde5a70ad28bbdc34157595d1cddd888a985f5aae", size = 420783, upload-time = "2025-06-10T05:21:06.287Z" }, - { url = "https://files.pythonhosted.org/packages/a6/db/57d2bb4af52dd0c6f62c42c7d34b82495b2902e50440134f70bfb7ee0fdd/aiohttp-3.12.12-cp313-cp313-win_amd64.whl", hash = "sha256:ace2499bdd03c329c054dc4b47361f2b19d5aa470f7db5c7e0e989336761b33c", size = 446721, upload-time = "2025-06-10T05:21:08.738Z" }, -] - -[[package]] -name = "aiosignal" -version = "1.3.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "frozenlist" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ba/b5/6d55e80f6d8a08ce22b982eafa278d823b541c925f11ee774b0b9c43473d/aiosignal-1.3.2.tar.gz", hash = "sha256:a8c255c66fafb1e499c9351d0bf32ff2d8a0321595ebac3b93713656d2436f54", size = 19424, upload-time = "2024-12-13T17:10:40.86Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ec/6a/bc7e17a3e87a2985d3e8f4da4cd0f481060eb78fb08596c42be62c90a4d9/aiosignal-1.3.2-py2.py3-none-any.whl", hash = "sha256:45cde58e409a301715980c2b01d0c28bdde3770d8290b5eb2173759d9acb31a5", size = 7597, upload-time = "2024-12-13T17:10:38.469Z" }, -] - -[[package]] -name = "annotated-types" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/67/531ea369ba64dcff5ec9c3402f9f51bf748cec26dde048a2f973a4eea7f5/annotated_types-0.7.0.tar.gz", hash = "sha256:aff07c09a53a08bc8cfccb9c85b05f1aa9a2a6f23728d790723543408344ce89", size = 16081, upload-time = "2024-05-20T21:33:25.928Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/b6/6307fbef88d9b5ee7421e68d78a9f162e0da4900bc5f5793f6d3d0e34fb8/annotated_types-0.7.0-py3-none-any.whl", hash = "sha256:1f02e8b43a8fbbc3f3e0d4f0f4bfc8131bcb4eebe8849b8e5c773f3a1c582a53", size = 13643, upload-time = "2024-05-20T21:33:24.1Z" }, -] - -[[package]] -name = "anyio" -version = "4.9.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "exceptiongroup", marker = "python_full_version < '3.11'" }, - { name = "idna" }, - { name = "sniffio" }, - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/95/7d/4c1bd541d4dffa1b52bd83fb8527089e097a106fc90b467a7313b105f840/anyio-4.9.0.tar.gz", hash = "sha256:673c0c244e15788651a4ff38710fea9675823028a6f08a5eda409e0c9840a028", size = 190949, upload-time = "2025-03-17T00:02:54.77Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/ee/48ca1a7c89ffec8b6a0c5d02b89c305671d5ffd8d3c94acf8b8c408575bb/anyio-4.9.0-py3-none-any.whl", hash = "sha256:9f76d541cad6e36af7beb62e978876f3b41e3e04f2c1fbf0884604c0a9c4d93c", size = 100916, upload-time = "2025-03-17T00:02:52.713Z" }, -] - -[[package]] -name = "async-timeout" -version = "5.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a5/ae/136395dfbfe00dfc94da3f3e136d0b13f394cba8f4841120e34226265780/async_timeout-5.0.1.tar.gz", hash = "sha256:d9321a7a3d5a6a5e187e824d2fa0793ce379a202935782d555d6e9d2735677d3", size = 9274, upload-time = "2024-11-06T16:41:39.6Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/fe/ba/e2081de779ca30d473f21f5b30e0e737c438205440784c7dfc81efc2b029/async_timeout-5.0.1-py3-none-any.whl", hash = "sha256:39e3809566ff85354557ec2398b55e096c8364bacac9405a7a1fa429e77fe76c", size = 6233, upload-time = "2024-11-06T16:41:37.9Z" }, -] - -[[package]] -name = "attrs" -version = "25.3.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/5a/b0/1367933a8532ee6ff8d63537de4f1177af4bff9f3e829baf7331f595bb24/attrs-25.3.0.tar.gz", hash = "sha256:75d7cefc7fb576747b2c81b4442d4d4a1ce0900973527c011d1030fd3bf4af1b", size = 812032, upload-time = "2025-03-13T11:10:22.779Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/77/06/bb80f5f86020c4551da315d78b3ab75e8228f89f0162f2c3a819e407941a/attrs-25.3.0-py3-none-any.whl", hash = "sha256:427318ce031701fea540783410126f03899a97ffc6f61596ad581ac2e40e3bc3", size = 63815, upload-time = "2025-03-13T11:10:21.14Z" }, -] - -[[package]] -name = "bitarray" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b8/0d/15826c7c2d49a4518a1b24b0d432f1ecad2e0b68168f942058b5de498498/bitarray-3.4.2.tar.gz", hash = "sha256:78ed2b911aabede3a31e3329b1de8abdc8104bd5e0545184ddbd9c7f668f4059", size = 143756, upload-time = "2025-05-21T16:21:44.056Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f1/61/fa3a06d74bfba1dc591efa9f4f5ad2e5645f06a8c4d113cf12d18b5ac25b/bitarray-3.4.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:42b552f885c5629182928c79237b375a92bcf1bc1e725b1c8a5e8eab28ea300d", size = 141280, upload-time = "2025-05-21T16:18:02.593Z" }, - { url = "https://files.pythonhosted.org/packages/17/ba/7eb30374c0e4c4b732a3ca3457d9fb0e44165ae4c5af9758597b03211a28/bitarray-3.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3e16d6184f349587b6a5045bcf073baf763a86273aab454485ba437d0bca82e8", size = 138031, upload-time = "2025-05-21T16:18:05.616Z" }, - { url = "https://files.pythonhosted.org/packages/6e/6d/91582b0a232b54e910add5d0db34a926d0bdfdd1447685b8750349c71958/bitarray-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2ecf456f0dee61bd818011e290d922e3e3b1aeb0544f6f19c4da9c5fc2e52818", size = 306437, upload-time = "2025-05-21T16:18:06.793Z" }, - { url = "https://files.pythonhosted.org/packages/b8/23/113ccc20f6324d517ef6210c8fc6ae300346eb481c5a0483735e19b4deea/bitarray-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e8bbe8249ae90dc0cd78b21d5d5d27a614e15bf30737ae6e8a0e2e60cc492acc", size = 322335, upload-time = "2025-05-21T16:18:07.925Z" }, - { url = "https://files.pythonhosted.org/packages/6d/89/bf5a36e05ac3d77bdccbe9ba0eea4c47253411c2616379de0f181c27ecee/bitarray-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe7706f75f3b86e7afa516452bed9757ee301b59aea580c551c32a5e1cef082c", size = 314137, upload-time = "2025-05-21T16:18:09.333Z" }, - { url = "https://files.pythonhosted.org/packages/66/a6/bed287f9095a2a266fc68ee42d6ee2815ff500783f973876d86a6d37a434/bitarray-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9c60c8d30bb6efd2c04cf82d077df6449964234aeca996f6f1df317a08feffc0", size = 307963, upload-time = "2025-05-21T16:18:10.618Z" }, - { url = "https://files.pythonhosted.org/packages/2f/50/3ca2adaf0da034e6c1a2ed60a3781b065672dd282e67f88593290c3990a7/bitarray-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6b4cb5c22706d411010c7ce5efc0a4cc99f755a30fc7f6770eb1b1a0c0962bbb", size = 295182, upload-time = "2025-05-21T16:18:11.932Z" }, - { url = "https://files.pythonhosted.org/packages/90/de/8c3d96e273bc51e4912185bd809fc6a9ec14a09e607336892c149e0c57c5/bitarray-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:0fd60137a9474ce53bdace68c718a7c538f9df01d390452cc984f1ee78d7bcdb", size = 300063, upload-time = "2025-05-21T16:18:13.221Z" }, - { url = "https://files.pythonhosted.org/packages/9d/71/34f0ea6ac5b2cbdd84f3e6283b5b796628cef616e786cb442cefce0fe224/bitarray-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:cd514a8e27d0751f0254861df60335edabacccfcb2457793ff30c8b2ed8f799d", size = 292053, upload-time = "2025-05-21T16:18:14.802Z" }, - { url = "https://files.pythonhosted.org/packages/77/99/6ef41312536d2c37f14f0f7173aa1a012e9675d62900c10afa7641b47f75/bitarray-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:6c8f7447cdf2faff1d176c5dd207f0134f05cfa2a238d3d3944dc5019dc41593", size = 317007, upload-time = "2025-05-21T16:18:16.117Z" }, - { url = "https://files.pythonhosted.org/packages/22/f9/cc4e73f54698bcdd1e0f1ea582da7e005464651e8116291a226deab95e1b/bitarray-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:75040a2a1abe4ccd40236f4ba0d39abde981d23f3ce7691b3b3f2137f134b99b", size = 319402, upload-time = "2025-05-21T16:18:18.097Z" }, - { url = "https://files.pythonhosted.org/packages/55/40/c23dd5726107cbbc5e698b3fcca5ffac83d29146ef469f27f5277d18c2d7/bitarray-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:ba15725cd9040b9b1b2650edb33253cb2ba7b68d087974e296e5ff082198952f", size = 299456, upload-time = "2025-05-21T16:18:20.029Z" }, - { url = "https://files.pythonhosted.org/packages/21/31/6bfd9fda776f8d98512d5484fcb55fbb25e60796e7b5d3b9a3a300e8bc1c/bitarray-3.4.2-cp310-cp310-win32.whl", hash = "sha256:2959dfc61d963546e97220cfcaab7dfc489276c6e00092b57710522e68712b28", size = 134279, upload-time = "2025-05-21T16:18:21.609Z" }, - { url = "https://files.pythonhosted.org/packages/82/9d/7067f6548b470beb86d83f7ac6c45cac3b9c28cf77fa0f9f3e67353d69d3/bitarray-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:97077fa0ec3b7eed57cd8d1cb0eb75d670423d20b7e4901482347a81efe2f6fd", size = 141360, upload-time = "2025-05-21T16:18:23.197Z" }, - { url = "https://files.pythonhosted.org/packages/94/ba/508ba6a3ea16eb6c21baae33cd1b7bf6e299d21a496a1f90b8203a22d6d0/bitarray-3.4.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:90ca8e260b75a7ac0c542093e5f29154e51fd0d2d0fa5041c038cb2b58415eeb", size = 141425, upload-time = "2025-05-21T16:18:24.452Z" }, - { url = "https://files.pythonhosted.org/packages/eb/a1/44d9b88cd3daee3734ea98dac691acc2c935a3bfbd5bfc38267a59bd986d/bitarray-3.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:549dabcae78fb8f9133e3138b9473c7648d6054bb6fec84d28d3861aaec5ddd1", size = 138172, upload-time = "2025-05-21T16:18:25.601Z" }, - { url = "https://files.pythonhosted.org/packages/5f/aa/5a8c33ab39e8a894978d42427ad0a1ba2d5c9cb61c8480101be555c0e3a7/bitarray-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5a3da536ac84e6911cbc8e86be0baf1cab0d4f4ccb80c0f39b4fa28509f2db1a", size = 313373, upload-time = "2025-05-21T16:18:26.796Z" }, - { url = "https://files.pythonhosted.org/packages/89/48/b0d28e21d91ec5c0477a320b9443096ddc816fbc59778b367f9e49094532/bitarray-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7a5e84d6b737de2d773ab1bd538e6f37fa7f667ea734f00a48d9a973b181c751", size = 329657, upload-time = "2025-05-21T16:18:28.097Z" }, - { url = "https://files.pythonhosted.org/packages/bd/d5/1f858bd559568286435a460e7a169a5185b2b29184684e6c6fa303af3ca9/bitarray-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e265c5eede8316ba64bb6029832f282f6284a557b625bb3207a7680fd5da7925", size = 321873, upload-time = "2025-05-21T16:18:29.511Z" }, - { url = "https://files.pythonhosted.org/packages/e8/c8/23df4174142cccf6a8bd114651b8e9bf965005ab1ef741d37c9f72e8d2eb/bitarray-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:63fb45c60c7ab7a724aa64203305e56f344489e12d41619bdc9d7887d6562e01", size = 314796, upload-time = "2025-05-21T16:18:31.2Z" }, - { url = "https://files.pythonhosted.org/packages/8f/21/329178b165f1aaf3f2ace3eb24aca5ad197febae908d7b41e552a69043e9/bitarray-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:083c2a9234dacf3e4e166a5844256da2a397941d3f6397e5b919bffca638f6ef", size = 302724, upload-time = "2025-05-21T16:18:32.729Z" }, - { url = "https://files.pythonhosted.org/packages/26/a8/a66d3c0d3410d01f51824f8476b060f96b3353db7d6b45c87dba6d1aa0e0/bitarray-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:e72606adb2438002873cb0e8e81c3fce926386a59bbafa82fea07cdb2a6d8a05", size = 307434, upload-time = "2025-05-21T16:18:34.394Z" }, - { url = "https://files.pythonhosted.org/packages/ed/ac/3052386e7ff80c80eb2549a22c890f511e9f9f7fbbe6244b04255adae031/bitarray-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:dc994d22a3a563e1d402dc2f64c61e60605a1a3e66dd8aea7636f607b99f03cb", size = 299232, upload-time = "2025-05-21T16:18:35.708Z" }, - { url = "https://files.pythonhosted.org/packages/9d/46/91a32ccd39d40371ed7404d96a6f3cf1e381eaf36be5390c6bff5034f344/bitarray-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:214468391680ba1c831872a7949f1b563ab3cd832d10adc52df4f36e0af24446", size = 324056, upload-time = "2025-05-21T16:18:37.536Z" }, - { url = "https://files.pythonhosted.org/packages/39/0e/cb824f0e0302cd08809f67b35b3ae21b47af5dd122e99740bfe6bde1c824/bitarray-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:c7483b97807bb018a7cd7f9741800c714c9c56ba4e5a7e962c5f956c4b858f3c", size = 327058, upload-time = "2025-05-21T16:18:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/09/01/845e977d490e4e261179785540d1fdeff966c99296f503adc0e5407fc257/bitarray-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5774bf14ec451d5ac311cfcfe0b0cf2a1a9fa74b6ca81dfbc4f56a98872a5541", size = 306629, upload-time = "2025-05-21T16:18:40.211Z" }, - { url = "https://files.pythonhosted.org/packages/29/ef/33ee8533ff1b2a8cd0b9e84fd81b2a90d66c2774544c861e281c5361eaa2/bitarray-3.4.2-cp311-cp311-win32.whl", hash = "sha256:e6f35567347ddb8b9e8b6bf6ab7d64be88bdb6b6c107b8edbb2c3d426c1590a0", size = 134450, upload-time = "2025-05-21T16:18:42.435Z" }, - { url = "https://files.pythonhosted.org/packages/09/52/069c255d067319a9695c93369641d7f5539625069c1cf3ded2becff1bfbc/bitarray-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:ae5b0a8d3caf6284220232738dc7c05af81ec3a9f93d4a462295462dd0a492b2", size = 141596, upload-time = "2025-05-21T16:18:43.743Z" }, - { url = "https://files.pythonhosted.org/packages/05/57/0b2b50eb3f50c3144f705d0994171f17fda00ee3a72d563ba764ea235f66/bitarray-3.4.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:a0e498563e0eefa96a1b92461d083de11256f6510b7706d5f2e6473cd9b7137a", size = 141191, upload-time = "2025-05-21T16:18:45.436Z" }, - { url = "https://files.pythonhosted.org/packages/81/c3/1d9ce4d0041c10ce90d924b8cea63afdda84a64623179045c0c67998922c/bitarray-3.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:114870ab71a0ebdac211aa0a120a54206c333b74b99fdf4b58fbe904979e1fef", size = 138158, upload-time = "2025-05-21T16:18:46.685Z" }, - { url = "https://files.pythonhosted.org/packages/5d/dd/a8653dac671ba97b1c68ee73b08a0eb2042f24e5e31f51b86afc09588c06/bitarray-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fbf6121978cba4313c31f7cc5961e481242def2b8ddfea34ca27ba9da52c9c1", size = 315834, upload-time = "2025-05-21T16:18:47.926Z" }, - { url = "https://files.pythonhosted.org/packages/3d/a2/30547bea0a35f9f953e99f5157749d56304d3f3a96b01a982dd604a9dc48/bitarray-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:423bb4e1bec0bc5d63969e12bcc5cc0081cc5aec4d7b62a6cd8240342aa36107", size = 331317, upload-time = "2025-05-21T16:18:49.169Z" }, - { url = "https://files.pythonhosted.org/packages/2d/b9/1789476280f46455a9a30bcd252fda6fd995583d97d1b919ec0296393e2a/bitarray-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2ef80a96487c82477e8def69a58a218491794f7989b3e191cbaaa7b450315a5c", size = 324416, upload-time = "2025-05-21T16:18:50.917Z" }, - { url = "https://files.pythonhosted.org/packages/84/89/519c829ca641a3e7b8c9be56d177aaa05572b7e15e4298df4a77959b6a1e/bitarray-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:35f5c69a79047e50bc1d54a777541b0a86b213e23559b1ac3d76fa9a42cc5522", size = 317634, upload-time = "2025-05-21T16:18:52.718Z" }, - { url = "https://files.pythonhosted.org/packages/0d/39/ebb6a6539261279c0994836b40b99384fa5e27ec239e70b203e310343f80/bitarray-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:002f7b128ed9d18d3ecb51ca78aeea5afffbe8e80d6be4ff2984d045b1c4b937", size = 305392, upload-time = "2025-05-21T16:18:54.888Z" }, - { url = "https://files.pythonhosted.org/packages/83/04/0ee0d57b2a60fdf881346f196fd92b824f44f4736026da1d8c7970745266/bitarray-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:999bccc72704afcf4a3d9868db4d149c032cdf910f9f7d91e30166978530af7f", size = 309740, upload-time = "2025-05-21T16:18:56.76Z" }, - { url = "https://files.pythonhosted.org/packages/f6/39/5ab0339e93097f2a2631ea281a6386c31707011499d5cf68b4e0e37ba124/bitarray-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:2e44cfe2bc161cde3b11604f279e3048ef7bd3413837aadbd2ca30b5233c82cb", size = 301607, upload-time = "2025-05-21T16:18:58.144Z" }, - { url = "https://files.pythonhosted.org/packages/e8/bb/b8f697ba6a16c1e393afe75029d069e2dd457e62b112c3cb26768d2e65eb/bitarray-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:f408ba3e6f706a0eabae405d1906ceb539f34a318562a91ab9799c5e1712e18c", size = 325942, upload-time = "2025-05-21T16:18:59.471Z" }, - { url = "https://files.pythonhosted.org/packages/64/ec/77d866a96909c09c5a34f1716f015386f9d9bbbf4b5dc7219f642b8043e2/bitarray-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bf94513ae559b2525e6218e41b03790f866d75df5404490420f2c25e42cf55e7", size = 329491, upload-time = "2025-05-21T16:19:01.205Z" }, - { url = "https://files.pythonhosted.org/packages/37/6e/633b7d392a39df655c92035da9ee52f7332bb165ae72038692a33a6def6c/bitarray-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:6f2c88c792815d2755c49a3a1fca256e142c4adfadf1a2142b5a3a37e4d4b871", size = 309566, upload-time = "2025-05-21T16:19:02.762Z" }, - { url = "https://files.pythonhosted.org/packages/ab/38/9d7ad6eca72e09b81097176dd66eed3aeaabdea4c24cf6ce25609599ce7b/bitarray-3.4.2-cp312-cp312-win32.whl", hash = "sha256:f4dac6b942c4d7ae5f6eb555ee3993de1432bf9c8f46e3caf74b6671ac5571a3", size = 134600, upload-time = "2025-05-21T16:19:04.057Z" }, - { url = "https://files.pythonhosted.org/packages/d4/d3/c83ec3d912be73861a064f1a705436f270b8c5b5926350a875bd6c06b6df/bitarray-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:6c37e6814633041307f0df281651a86372b0ccdb1e4768247a87e83e2b68f9b9", size = 141844, upload-time = "2025-05-21T16:19:05.254Z" }, - { url = "https://files.pythonhosted.org/packages/f2/22/973d377477e1f27cf64f9e3292343219577136e32665a52667589380100d/bitarray-3.4.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:16263bdbb05ce379e7b8e9a9f3e0a61a9204a06a037bbc91322d2939b3079fd5", size = 141162, upload-time = "2025-05-21T16:19:06.488Z" }, - { url = "https://files.pythonhosted.org/packages/eb/53/65541b94fb6df1e8aa9a7359ac68f469c3243d8bc7302c5fb8ff8936dab2/bitarray-3.4.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:41fdc6fb8c3aabfcfe0073302c69fef0c74d6499491f133ba58755c3f2afb3d0", size = 138162, upload-time = "2025-05-21T16:19:07.688Z" }, - { url = "https://files.pythonhosted.org/packages/a4/b2/83d587965f7969a5016a5bf5c9295a0651a34b668df41fa089d7c924ac08/bitarray-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:02c2571337b11c69206e339170516f3e72b4ec16250876c4f2bbb6e82b9caa15", size = 315760, upload-time = "2025-05-21T16:19:09.834Z" }, - { url = "https://files.pythonhosted.org/packages/4f/f5/2b2924181809debdb644143aa33d16facdce5763d5ff17e5301ecdaf89dc/bitarray-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c0e3d5f37217dde9b206418c37c4d86e173f072a892670e9714e6bb20b228e95", size = 331250, upload-time = "2025-05-21T16:19:11.449Z" }, - { url = "https://files.pythonhosted.org/packages/00/2b/8ed4eeb947e05ef54614feff4cc4badd03e29ec35d46aa0218513cc9f8ac/bitarray-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:83202735f21fc781f27228daeae94b6c7df1a9f673b9dd6a1c0b3764d92b8e50", size = 324299, upload-time = "2025-05-21T16:19:13.236Z" }, - { url = "https://files.pythonhosted.org/packages/05/27/d7f1b15c079cbeffad76f97c41c27635873be4d5600f6896b2bbc4f5caff/bitarray-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:53b3f8c35812d85a299d6c0ff097f93e18dfb7a324c129e20a4ec0ecfc4ba995", size = 317522, upload-time = "2025-05-21T16:19:14.832Z" }, - { url = "https://files.pythonhosted.org/packages/a5/db/e6a857a23222360dbc0b0d177e6060ecd88d63a1d6a3c2b52333c21a9683/bitarray-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ef3f2e8ba5d6e0f38b57960d1bfb72aa9e2115f7cdca48561fadced652798d49", size = 305290, upload-time = "2025-05-21T16:19:16.57Z" }, - { url = "https://files.pythonhosted.org/packages/16/12/3b945e415233889c57c26f95a9a6a245da546e2c8d1de09991332cb796ff/bitarray-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:508ec6547bdd9f0c435c322fbb127a3dfd74c943a6c7f77fa5dfcb3e9ce1de66", size = 309764, upload-time = "2025-05-21T16:19:18.34Z" }, - { url = "https://files.pythonhosted.org/packages/6c/0e/9effb83e23ef5495c9078bdbac948df4fe2b202fb0ac5b33412848ab4b1e/bitarray-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1a3a08cc920f601258ea33d97b4454cd7cb04d17930e0a3bc7328ba3d732f8b0", size = 301690, upload-time = "2025-05-21T16:19:19.694Z" }, - { url = "https://files.pythonhosted.org/packages/cb/67/9a73476c8cd6a67ff5ab9c5c1d916307e4fb9178d76ee2781552451c995c/bitarray-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:60189130ae1ebaadbab27e3ad0a7d7ed44f5d9456bbfae07c72138501ce59053", size = 326049, upload-time = "2025-05-21T16:19:21.371Z" }, - { url = "https://files.pythonhosted.org/packages/bf/b1/2a81f5f96c1ccc033d8c63b4584aedbd9e27499cf2276fc70d4f87ad673b/bitarray-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:9e425eaf21a8d7b76531630029441c6d61f6064cbf4dd592af1607c79eb2e4d0", size = 329565, upload-time = "2025-05-21T16:19:22.88Z" }, - { url = "https://files.pythonhosted.org/packages/2e/30/670efe7771944b4b7d0aacdc076969adc9428c9d0939ee70230bdf4c8aed/bitarray-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:952cc40c593f663ba083be76d1ccdb6dc9dafab8fb6d949056405636b2e720f3", size = 309661, upload-time = "2025-05-21T16:19:24.574Z" }, - { url = "https://files.pythonhosted.org/packages/ee/2e/b2d8e842fe484d7d18fcd137289e396c7784b8484e0ec7e94ffe4bb7e8f9/bitarray-3.4.2-cp313-cp313-win32.whl", hash = "sha256:158f6b1a315eaf971f88e66f9b93431c3b580b46d2121c6a1166e7b761408fdf", size = 134614, upload-time = "2025-05-21T16:19:25.914Z" }, - { url = "https://files.pythonhosted.org/packages/0c/50/0ec25a51197410a66146eea7950e3597baedb000f2f2e2458bb6d5306b0a/bitarray-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:2d24658ac96a82beb4da2f5c71bef9790f3dcabadbe8ead8dda742ab207fe2f9", size = 141851, upload-time = "2025-05-21T16:19:27.388Z" }, - { url = "https://files.pythonhosted.org/packages/e7/03/77eca3d93f162c0982f370e6459d1fcb6ff51e84f80adb34c43256653bda/bitarray-3.4.2-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:9c02f3234b1ec391aa235b265a3649e8078d814cdd6b42bc5aee267cc370b0c8", size = 135778, upload-time = "2025-05-21T16:20:58.492Z" }, - { url = "https://files.pythonhosted.org/packages/68/fd/5b148fb07e2b74e1cd17db7b940abdb1c7af6ac3a024810a5931db6e436b/bitarray-3.4.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:e19e5a35f53c0eaf4516cfa3f80de110eb831fd3d9785aa8b8f4a8a8c0d99523", size = 132826, upload-time = "2025-05-21T16:21:00.901Z" }, - { url = "https://files.pythonhosted.org/packages/e5/50/8cfb459218cd074a3af7121f6509ac55be2d6ac5a0a048b188934976f589/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f633d1e92fdc6a039b118d67f23d17b9ac4046a629bde04e178b770fe83a618f", size = 141592, upload-time = "2025-05-21T16:21:02.4Z" }, - { url = "https://files.pythonhosted.org/packages/43/c0/a70a212ecfd4256e7281456beee5330945ea09cec8fb0be3f99ed6828a08/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c08bc2ec3f15fbb3a99923ef1b16b621af45ab9d5146a06f970c0f0d7cab22ba", size = 142502, upload-time = "2025-05-21T16:21:08.366Z" }, - { url = "https://files.pythonhosted.org/packages/1e/8e/9fc84001701ef1fd7f18b0254bf08d594adaed34fe0b5770d8c032b4d53a/bitarray-3.4.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eed46fa39af8440b1cff09a9805d65449583d524006efa29e5262bea9e08787e", size = 143930, upload-time = "2025-05-21T16:21:09.819Z" }, - { url = "https://files.pythonhosted.org/packages/f7/05/2f6753d75282033e66e0a9626ef4209500cd7a08aa8f92cc70fa49681cf3/bitarray-3.4.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:9cf23c13c84c1559ed28bd211a6290b7326c2011f6c30c82cee052b254ac09f0", size = 140275, upload-time = "2025-05-21T16:21:11.481Z" }, -] - -[[package]] -name = "blinker" -version = "1.9.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/28/9b3f50ce0e048515135495f198351908d99540d69bfdc8c1d15b73dc55ce/blinker-1.9.0.tar.gz", hash = "sha256:b4ce2265a7abece45e7cc896e98dbebe6cead56bcf805a3d23136d145f5445bf", size = 22460, upload-time = "2024-11-08T17:25:47.436Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/10/cb/f2ad4230dc2eb1a74edf38f1a38b9b52277f75bef262d8908e60d957e13c/blinker-1.9.0-py3-none-any.whl", hash = "sha256:ba0efaa9080b619ff2f3459d1d500c57bddea4a6b424b60a91141db6fd2f08bc", size = 8458, upload-time = "2024-11-08T17:25:46.184Z" }, -] - -[[package]] -name = "certifi" -version = "2025.4.26" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e8/9e/c05b3920a3b7d20d3d3310465f50348e5b3694f4f88c6daf736eef3024c4/certifi-2025.4.26.tar.gz", hash = "sha256:0a816057ea3cdefcef70270d2c515e4506bbc954f417fa5ade2021213bb8f0c6", size = 160705, upload-time = "2025-04-26T02:12:29.51Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4a/7e/3db2bd1b1f9e95f7cddca6d6e75e2f2bd9f51b1246e546d88addca0106bd/certifi-2025.4.26-py3-none-any.whl", hash = "sha256:30350364dfe371162649852c63336a15c70c6510c2ad5015b21c2345311805f3", size = 159618, upload-time = "2025-04-26T02:12:27.662Z" }, -] - -[[package]] -name = "charset-normalizer" -version = "3.4.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/e4/33/89c2ced2b67d1c2a61c19c6751aa8902d46ce3dacb23600a283619f5a12d/charset_normalizer-3.4.2.tar.gz", hash = "sha256:5baececa9ecba31eff645232d59845c07aa030f0c81ee70184a90d35099a0e63", size = 126367, upload-time = "2025-05-02T08:34:42.01Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/28/9901804da60055b406e1a1c5ba7aac1276fb77f1dde635aabfc7fd84b8ab/charset_normalizer-3.4.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7c48ed483eb946e6c04ccbe02c6b4d1d48e51944b6db70f697e089c193404941", size = 201818, upload-time = "2025-05-02T08:31:46.725Z" }, - { url = "https://files.pythonhosted.org/packages/d9/9b/892a8c8af9110935e5adcbb06d9c6fe741b6bb02608c6513983048ba1a18/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b2d318c11350e10662026ad0eb71bb51c7812fc8590825304ae0bdd4ac283acd", size = 144649, upload-time = "2025-05-02T08:31:48.889Z" }, - { url = "https://files.pythonhosted.org/packages/7b/a5/4179abd063ff6414223575e008593861d62abfc22455b5d1a44995b7c101/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9cbfacf36cb0ec2897ce0ebc5d08ca44213af24265bd56eca54bee7923c48fd6", size = 155045, upload-time = "2025-05-02T08:31:50.757Z" }, - { url = "https://files.pythonhosted.org/packages/3b/95/bc08c7dfeddd26b4be8c8287b9bb055716f31077c8b0ea1cd09553794665/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:18dd2e350387c87dabe711b86f83c9c78af772c748904d372ade190b5c7c9d4d", size = 147356, upload-time = "2025-05-02T08:31:52.634Z" }, - { url = "https://files.pythonhosted.org/packages/a8/2d/7a5b635aa65284bf3eab7653e8b4151ab420ecbae918d3e359d1947b4d61/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8075c35cd58273fee266c58c0c9b670947c19df5fb98e7b66710e04ad4e9ff86", size = 149471, upload-time = "2025-05-02T08:31:56.207Z" }, - { url = "https://files.pythonhosted.org/packages/ae/38/51fc6ac74251fd331a8cfdb7ec57beba8c23fd5493f1050f71c87ef77ed0/charset_normalizer-3.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5bf4545e3b962767e5c06fe1738f951f77d27967cb2caa64c28be7c4563e162c", size = 151317, upload-time = "2025-05-02T08:31:57.613Z" }, - { url = "https://files.pythonhosted.org/packages/b7/17/edee1e32215ee6e9e46c3e482645b46575a44a2d72c7dfd49e49f60ce6bf/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:7a6ab32f7210554a96cd9e33abe3ddd86732beeafc7a28e9955cdf22ffadbab0", size = 146368, upload-time = "2025-05-02T08:31:59.468Z" }, - { url = "https://files.pythonhosted.org/packages/26/2c/ea3e66f2b5f21fd00b2825c94cafb8c326ea6240cd80a91eb09e4a285830/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:b33de11b92e9f75a2b545d6e9b6f37e398d86c3e9e9653c4864eb7e89c5773ef", size = 154491, upload-time = "2025-05-02T08:32:01.219Z" }, - { url = "https://files.pythonhosted.org/packages/52/47/7be7fa972422ad062e909fd62460d45c3ef4c141805b7078dbab15904ff7/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:8755483f3c00d6c9a77f490c17e6ab0c8729e39e6390328e42521ef175380ae6", size = 157695, upload-time = "2025-05-02T08:32:03.045Z" }, - { url = "https://files.pythonhosted.org/packages/2f/42/9f02c194da282b2b340f28e5fb60762de1151387a36842a92b533685c61e/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:68a328e5f55ec37c57f19ebb1fdc56a248db2e3e9ad769919a58672958e8f366", size = 154849, upload-time = "2025-05-02T08:32:04.651Z" }, - { url = "https://files.pythonhosted.org/packages/67/44/89cacd6628f31fb0b63201a618049be4be2a7435a31b55b5eb1c3674547a/charset_normalizer-3.4.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:21b2899062867b0e1fde9b724f8aecb1af14f2778d69aacd1a5a1853a597a5db", size = 150091, upload-time = "2025-05-02T08:32:06.719Z" }, - { url = "https://files.pythonhosted.org/packages/1f/79/4b8da9f712bc079c0f16b6d67b099b0b8d808c2292c937f267d816ec5ecc/charset_normalizer-3.4.2-cp310-cp310-win32.whl", hash = "sha256:e8082b26888e2f8b36a042a58307d5b917ef2b1cacab921ad3323ef91901c71a", size = 98445, upload-time = "2025-05-02T08:32:08.66Z" }, - { url = "https://files.pythonhosted.org/packages/7d/d7/96970afb4fb66497a40761cdf7bd4f6fca0fc7bafde3a84f836c1f57a926/charset_normalizer-3.4.2-cp310-cp310-win_amd64.whl", hash = "sha256:f69a27e45c43520f5487f27627059b64aaf160415589230992cec34c5e18a509", size = 105782, upload-time = "2025-05-02T08:32:10.46Z" }, - { url = "https://files.pythonhosted.org/packages/05/85/4c40d00dcc6284a1c1ad5de5e0996b06f39d8232f1031cd23c2f5c07ee86/charset_normalizer-3.4.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:be1e352acbe3c78727a16a455126d9ff83ea2dfdcbc83148d2982305a04714c2", size = 198794, upload-time = "2025-05-02T08:32:11.945Z" }, - { url = "https://files.pythonhosted.org/packages/41/d9/7a6c0b9db952598e97e93cbdfcb91bacd89b9b88c7c983250a77c008703c/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa88ca0b1932e93f2d961bf3addbb2db902198dca337d88c89e1559e066e7645", size = 142846, upload-time = "2025-05-02T08:32:13.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/82/a37989cda2ace7e37f36c1a8ed16c58cf48965a79c2142713244bf945c89/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d524ba3f1581b35c03cb42beebab4a13e6cdad7b36246bd22541fa585a56cccd", size = 153350, upload-time = "2025-05-02T08:32:15.873Z" }, - { url = "https://files.pythonhosted.org/packages/df/68/a576b31b694d07b53807269d05ec3f6f1093e9545e8607121995ba7a8313/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28a1005facc94196e1fb3e82a3d442a9d9110b8434fc1ded7a24a2983c9888d8", size = 145657, upload-time = "2025-05-02T08:32:17.283Z" }, - { url = "https://files.pythonhosted.org/packages/92/9b/ad67f03d74554bed3aefd56fe836e1623a50780f7c998d00ca128924a499/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fdb20a30fe1175ecabed17cbf7812f7b804b8a315a25f24678bcdf120a90077f", size = 147260, upload-time = "2025-05-02T08:32:18.807Z" }, - { url = "https://files.pythonhosted.org/packages/a6/e6/8aebae25e328160b20e31a7e9929b1578bbdc7f42e66f46595a432f8539e/charset_normalizer-3.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0f5d9ed7f254402c9e7d35d2f5972c9bbea9040e99cd2861bd77dc68263277c7", size = 149164, upload-time = "2025-05-02T08:32:20.333Z" }, - { url = "https://files.pythonhosted.org/packages/8b/f2/b3c2f07dbcc248805f10e67a0262c93308cfa149a4cd3d1fe01f593e5fd2/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:efd387a49825780ff861998cd959767800d54f8308936b21025326de4b5a42b9", size = 144571, upload-time = "2025-05-02T08:32:21.86Z" }, - { url = "https://files.pythonhosted.org/packages/60/5b/c3f3a94bc345bc211622ea59b4bed9ae63c00920e2e8f11824aa5708e8b7/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:f0aa37f3c979cf2546b73e8222bbfa3dc07a641585340179d768068e3455e544", size = 151952, upload-time = "2025-05-02T08:32:23.434Z" }, - { url = "https://files.pythonhosted.org/packages/e2/4d/ff460c8b474122334c2fa394a3f99a04cf11c646da895f81402ae54f5c42/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:e70e990b2137b29dc5564715de1e12701815dacc1d056308e2b17e9095372a82", size = 155959, upload-time = "2025-05-02T08:32:24.993Z" }, - { url = "https://files.pythonhosted.org/packages/a2/2b/b964c6a2fda88611a1fe3d4c400d39c66a42d6c169c924818c848f922415/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:0c8c57f84ccfc871a48a47321cfa49ae1df56cd1d965a09abe84066f6853b9c0", size = 153030, upload-time = "2025-05-02T08:32:26.435Z" }, - { url = "https://files.pythonhosted.org/packages/59/2e/d3b9811db26a5ebf444bc0fa4f4be5aa6d76fc6e1c0fd537b16c14e849b6/charset_normalizer-3.4.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:6b66f92b17849b85cad91259efc341dce9c1af48e2173bf38a85c6329f1033e5", size = 148015, upload-time = "2025-05-02T08:32:28.376Z" }, - { url = "https://files.pythonhosted.org/packages/90/07/c5fd7c11eafd561bb51220d600a788f1c8d77c5eef37ee49454cc5c35575/charset_normalizer-3.4.2-cp311-cp311-win32.whl", hash = "sha256:daac4765328a919a805fa5e2720f3e94767abd632ae410a9062dff5412bae65a", size = 98106, upload-time = "2025-05-02T08:32:30.281Z" }, - { url = "https://files.pythonhosted.org/packages/a8/05/5e33dbef7e2f773d672b6d79f10ec633d4a71cd96db6673625838a4fd532/charset_normalizer-3.4.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53efc7c7cee4c1e70661e2e112ca46a575f90ed9ae3fef200f2a25e954f4b28", size = 105402, upload-time = "2025-05-02T08:32:32.191Z" }, - { url = "https://files.pythonhosted.org/packages/d7/a4/37f4d6035c89cac7930395a35cc0f1b872e652eaafb76a6075943754f095/charset_normalizer-3.4.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:0c29de6a1a95f24b9a1aa7aefd27d2487263f00dfd55a77719b530788f75cff7", size = 199936, upload-time = "2025-05-02T08:32:33.712Z" }, - { url = "https://files.pythonhosted.org/packages/ee/8a/1a5e33b73e0d9287274f899d967907cd0bf9c343e651755d9307e0dbf2b3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cddf7bd982eaa998934a91f69d182aec997c6c468898efe6679af88283b498d3", size = 143790, upload-time = "2025-05-02T08:32:35.768Z" }, - { url = "https://files.pythonhosted.org/packages/66/52/59521f1d8e6ab1482164fa21409c5ef44da3e9f653c13ba71becdd98dec3/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fcbe676a55d7445b22c10967bceaaf0ee69407fbe0ece4d032b6eb8d4565982a", size = 153924, upload-time = "2025-05-02T08:32:37.284Z" }, - { url = "https://files.pythonhosted.org/packages/86/2d/fb55fdf41964ec782febbf33cb64be480a6b8f16ded2dbe8db27a405c09f/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d41c4d287cfc69060fa91cae9683eacffad989f1a10811995fa309df656ec214", size = 146626, upload-time = "2025-05-02T08:32:38.803Z" }, - { url = "https://files.pythonhosted.org/packages/8c/73/6ede2ec59bce19b3edf4209d70004253ec5f4e319f9a2e3f2f15601ed5f7/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e594135de17ab3866138f496755f302b72157d115086d100c3f19370839dd3a", size = 148567, upload-time = "2025-05-02T08:32:40.251Z" }, - { url = "https://files.pythonhosted.org/packages/09/14/957d03c6dc343c04904530b6bef4e5efae5ec7d7990a7cbb868e4595ee30/charset_normalizer-3.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:cf713fe9a71ef6fd5adf7a79670135081cd4431c2943864757f0fa3a65b1fafd", size = 150957, upload-time = "2025-05-02T08:32:41.705Z" }, - { url = "https://files.pythonhosted.org/packages/0d/c8/8174d0e5c10ccebdcb1b53cc959591c4c722a3ad92461a273e86b9f5a302/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:a370b3e078e418187da8c3674eddb9d983ec09445c99a3a263c2011993522981", size = 145408, upload-time = "2025-05-02T08:32:43.709Z" }, - { url = "https://files.pythonhosted.org/packages/58/aa/8904b84bc8084ac19dc52feb4f5952c6df03ffb460a887b42615ee1382e8/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a955b438e62efdf7e0b7b52a64dc5c3396e2634baa62471768a64bc2adb73d5c", size = 153399, upload-time = "2025-05-02T08:32:46.197Z" }, - { url = "https://files.pythonhosted.org/packages/c2/26/89ee1f0e264d201cb65cf054aca6038c03b1a0c6b4ae998070392a3ce605/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7222ffd5e4de8e57e03ce2cef95a4c43c98fcb72ad86909abdfc2c17d227fc1b", size = 156815, upload-time = "2025-05-02T08:32:48.105Z" }, - { url = "https://files.pythonhosted.org/packages/fd/07/68e95b4b345bad3dbbd3a8681737b4338ff2c9df29856a6d6d23ac4c73cb/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:bee093bf902e1d8fc0ac143c88902c3dfc8941f7ea1d6a8dd2bcb786d33db03d", size = 154537, upload-time = "2025-05-02T08:32:49.719Z" }, - { url = "https://files.pythonhosted.org/packages/77/1a/5eefc0ce04affb98af07bc05f3bac9094513c0e23b0562d64af46a06aae4/charset_normalizer-3.4.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:dedb8adb91d11846ee08bec4c8236c8549ac721c245678282dcb06b221aab59f", size = 149565, upload-time = "2025-05-02T08:32:51.404Z" }, - { url = "https://files.pythonhosted.org/packages/37/a0/2410e5e6032a174c95e0806b1a6585eb21e12f445ebe239fac441995226a/charset_normalizer-3.4.2-cp312-cp312-win32.whl", hash = "sha256:db4c7bf0e07fc3b7d89ac2a5880a6a8062056801b83ff56d8464b70f65482b6c", size = 98357, upload-time = "2025-05-02T08:32:53.079Z" }, - { url = "https://files.pythonhosted.org/packages/6c/4f/c02d5c493967af3eda9c771ad4d2bbc8df6f99ddbeb37ceea6e8716a32bc/charset_normalizer-3.4.2-cp312-cp312-win_amd64.whl", hash = "sha256:5a9979887252a82fefd3d3ed2a8e3b937a7a809f65dcb1e068b090e165bbe99e", size = 105776, upload-time = "2025-05-02T08:32:54.573Z" }, - { url = "https://files.pythonhosted.org/packages/ea/12/a93df3366ed32db1d907d7593a94f1fe6293903e3e92967bebd6950ed12c/charset_normalizer-3.4.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:926ca93accd5d36ccdabd803392ddc3e03e6d4cd1cf17deff3b989ab8e9dbcf0", size = 199622, upload-time = "2025-05-02T08:32:56.363Z" }, - { url = "https://files.pythonhosted.org/packages/04/93/bf204e6f344c39d9937d3c13c8cd5bbfc266472e51fc8c07cb7f64fcd2de/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eba9904b0f38a143592d9fc0e19e2df0fa2e41c3c3745554761c5f6447eedabf", size = 143435, upload-time = "2025-05-02T08:32:58.551Z" }, - { url = "https://files.pythonhosted.org/packages/22/2a/ea8a2095b0bafa6c5b5a55ffdc2f924455233ee7b91c69b7edfcc9e02284/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3fddb7e2c84ac87ac3a947cb4e66d143ca5863ef48e4a5ecb83bd48619e4634e", size = 153653, upload-time = "2025-05-02T08:33:00.342Z" }, - { url = "https://files.pythonhosted.org/packages/b6/57/1b090ff183d13cef485dfbe272e2fe57622a76694061353c59da52c9a659/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:98f862da73774290f251b9df8d11161b6cf25b599a66baf087c1ffe340e9bfd1", size = 146231, upload-time = "2025-05-02T08:33:02.081Z" }, - { url = "https://files.pythonhosted.org/packages/e2/28/ffc026b26f441fc67bd21ab7f03b313ab3fe46714a14b516f931abe1a2d8/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c9379d65defcab82d07b2a9dfbfc2e95bc8fe0ebb1b176a3190230a3ef0e07c", size = 148243, upload-time = "2025-05-02T08:33:04.063Z" }, - { url = "https://files.pythonhosted.org/packages/c0/0f/9abe9bd191629c33e69e47c6ef45ef99773320e9ad8e9cb08b8ab4a8d4cb/charset_normalizer-3.4.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e635b87f01ebc977342e2697d05b56632f5f879a4f15955dfe8cef2448b51691", size = 150442, upload-time = "2025-05-02T08:33:06.418Z" }, - { url = "https://files.pythonhosted.org/packages/67/7c/a123bbcedca91d5916c056407f89a7f5e8fdfce12ba825d7d6b9954a1a3c/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:1c95a1e2902a8b722868587c0e1184ad5c55631de5afc0eb96bc4b0d738092c0", size = 145147, upload-time = "2025-05-02T08:33:08.183Z" }, - { url = "https://files.pythonhosted.org/packages/ec/fe/1ac556fa4899d967b83e9893788e86b6af4d83e4726511eaaad035e36595/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:ef8de666d6179b009dce7bcb2ad4c4a779f113f12caf8dc77f0162c29d20490b", size = 153057, upload-time = "2025-05-02T08:33:09.986Z" }, - { url = "https://files.pythonhosted.org/packages/2b/ff/acfc0b0a70b19e3e54febdd5301a98b72fa07635e56f24f60502e954c461/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:32fc0341d72e0f73f80acb0a2c94216bd704f4f0bce10aedea38f30502b271ff", size = 156454, upload-time = "2025-05-02T08:33:11.814Z" }, - { url = "https://files.pythonhosted.org/packages/92/08/95b458ce9c740d0645feb0e96cea1f5ec946ea9c580a94adfe0b617f3573/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:289200a18fa698949d2b39c671c2cc7a24d44096784e76614899a7ccf2574b7b", size = 154174, upload-time = "2025-05-02T08:33:13.707Z" }, - { url = "https://files.pythonhosted.org/packages/78/be/8392efc43487ac051eee6c36d5fbd63032d78f7728cb37aebcc98191f1ff/charset_normalizer-3.4.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4a476b06fbcf359ad25d34a057b7219281286ae2477cc5ff5e3f70a246971148", size = 149166, upload-time = "2025-05-02T08:33:15.458Z" }, - { url = "https://files.pythonhosted.org/packages/44/96/392abd49b094d30b91d9fbda6a69519e95802250b777841cf3bda8fe136c/charset_normalizer-3.4.2-cp313-cp313-win32.whl", hash = "sha256:aaeeb6a479c7667fbe1099af9617c83aaca22182d6cf8c53966491a0f1b7ffb7", size = 98064, upload-time = "2025-05-02T08:33:17.06Z" }, - { url = "https://files.pythonhosted.org/packages/e9/b0/0200da600134e001d91851ddc797809e2fe0ea72de90e09bec5a2fbdaccb/charset_normalizer-3.4.2-cp313-cp313-win_amd64.whl", hash = "sha256:aa6af9e7d59f9c12b33ae4e9450619cf2488e2bbe9b44030905877f0b2324980", size = 105641, upload-time = "2025-05-02T08:33:18.753Z" }, - { url = "https://files.pythonhosted.org/packages/20/94/c5790835a017658cbfabd07f3bfb549140c3ac458cfc196323996b10095a/charset_normalizer-3.4.2-py3-none-any.whl", hash = "sha256:7f56930ab0abd1c45cd15be65cc741c28b1c9a34876ce8c17a2fa107810c0af0", size = 52626, upload-time = "2025-05-02T08:34:40.053Z" }, -] - -[[package]] -name = "ckzg" -version = "2.1.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/55/df/f6db8e83bd4594c1ea685cd37fb81d5399e55765aae16d1a8a9502598f4e/ckzg-2.1.1.tar.gz", hash = "sha256:d6b306b7ec93a24e4346aa53d07f7f75053bc0afc7398e35fa649e5f9d48fcc4", size = 1120500, upload-time = "2025-03-31T21:24:12.324Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/33/4b/cd25e857cdf46a752e97c530fe2582fae77c4d16c29fff5a15b7a998e2fd/ckzg-2.1.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:4b9825a1458219e8b4b023012b8ef027ef1f47e903f9541cbca4615f80132730", size = 116377, upload-time = "2025-03-31T21:22:26.952Z" }, - { url = "https://files.pythonhosted.org/packages/7e/bc/5dfef36589545f797245ecacb54ed2acfa75507f63cfe12182d1277a88f1/ckzg-2.1.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:e2a40a3ba65cca4b52825d26829e6f7eb464aa27a9e9efb6b8b2ce183442c741", size = 100208, upload-time = "2025-03-31T21:22:28.04Z" }, - { url = "https://files.pythonhosted.org/packages/b7/52/96f0e3affbed321dc52b9b4ca13e0fb594da572d1f8edc47378fe48d8e9a/ckzg-2.1.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a1d753fbe85be7c21602eddc2d40e0915e25fce10329f4f801a0002a4f886cc7", size = 174800, upload-time = "2025-03-31T21:22:29.719Z" }, - { url = "https://files.pythonhosted.org/packages/dc/21/b1bc07cc8e5ed32817e89b054e2399d38775d92ff2d55e24bf233f537c02/ckzg-2.1.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9d76b50527f1d12430bf118aff6fa4051e9860eada43f29177258b8d399448ea", size = 160847, upload-time = "2025-03-31T21:22:30.973Z" }, - { url = "https://files.pythonhosted.org/packages/c9/5a/97b173d4ff9bce798031beb12b340c4f1729eaaddd07f69f368f843db28e/ckzg-2.1.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:44c8603e43c021d100f355f50189183135d1df3cbbddb8881552d57fbf421dde", size = 169712, upload-time = "2025-03-31T21:22:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/7b/52/48be78c07f362438e189e2fbea7df8543290c3ee99845442549c8dc5405b/ckzg-2.1.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:38707a638c9d715b3c30b29352b969f78d8fc10faed7db5faf517f04359895c0", size = 172942, upload-time = "2025-03-31T21:22:32.8Z" }, - { url = "https://files.pythonhosted.org/packages/13/42/3cfcd6cbdfb9030b9071d5e413a458f93883e47ad4a7d8d4c1d57608e57d/ckzg-2.1.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:52c4d257bdcbe822d20c5cd24c8154ec5aac33c49a8f5a19e716d9107a1c8785", size = 187707, upload-time = "2025-03-31T21:22:33.673Z" }, - { url = "https://files.pythonhosted.org/packages/eb/54/d43bc3a2de486fb8be29ffedc3ec80f5726765ee4fa78beabe2ab2440f93/ckzg-2.1.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:1507f7bfb9bcf51d816db5d8d0f0ed53c8289605137820d437b69daea8333e16", size = 182505, upload-time = "2025-03-31T21:22:34.563Z" }, - { url = "https://files.pythonhosted.org/packages/21/43/5bcd2b7630732b532006572fbb8d64a29f69530c630ae4811167a2a0dc3b/ckzg-2.1.1-cp310-cp310-win_amd64.whl", hash = "sha256:d02eaaf4f841910133552b3a051dea53bcfe60cd98199fc4cf80b27609d8baa2", size = 98822, upload-time = "2025-03-31T21:22:35.786Z" }, - { url = "https://files.pythonhosted.org/packages/95/2c/44120b2d9dcb0246d67a1f28b9eaa625c499014d4d42561467e28eedd285/ckzg-2.1.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:465e2b71cf9dc383f66f1979269420a0da9274a3a9e98b1a4455e84927dfe491", size = 116378, upload-time = "2025-03-31T21:22:36.96Z" }, - { url = "https://files.pythonhosted.org/packages/23/88/c5b89ba9a730fee5e089be9e0c7048fb6707c1a0e4b6c30fcf725c3eef44/ckzg-2.1.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ee2f26f17a64ad0aab833d637b276f28486b82a29e34f32cf54b237b8f8ab72d", size = 100202, upload-time = "2025-03-31T21:22:37.799Z" }, - { url = "https://files.pythonhosted.org/packages/ee/11/b0a473e80346db52ad9a629bc9fd8f773c718ed78932ea3a70392306ffc3/ckzg-2.1.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:99cc2c4e9fb8c62e3e0862c7f4df9142f07ba640da17fded5f6e0fd09f75909f", size = 175595, upload-time = "2025-03-31T21:22:39.013Z" }, - { url = "https://files.pythonhosted.org/packages/52/fa/17a7e125d07a96dd6dce4db7262231f7583856b2be5d5b7df59e04bfa188/ckzg-2.1.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:773dd016693d74aca1f5d7982db2bad7dde2e147563aeb16a783f7e5f69c01fe", size = 161681, upload-time = "2025-03-31T21:22:40.257Z" }, - { url = "https://files.pythonhosted.org/packages/57/bd/46d6b90bf53da732f9adab7593d132a0834ed4f2f7659b4c7414d8f78d39/ckzg-2.1.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0af2b2144f87ba218d8db01382a961b3ecbdde5ede4fa0d9428d35f8c8a595ba", size = 170471, upload-time = "2025-03-31T21:22:41.513Z" }, - { url = "https://files.pythonhosted.org/packages/9d/98/113c7704749d037d75f23240ffc5c46dfe8416de574b946438587835715f/ckzg-2.1.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8f55e63d3f7c934a2cb53728ed1d815479e177aca8c84efe991c2920977cff6", size = 173595, upload-time = "2025-03-31T21:22:42.534Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d5/05fca6dcb5a19327be491157794eafc3d7498daf615c2ff5a5b745852945/ckzg-2.1.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ecb42aaa0ffa427ff14a9dde9356ba69e5ae6014650b397af55b31bdae7a9b6e", size = 188417, upload-time = "2025-03-31T21:22:43.466Z" }, - { url = "https://files.pythonhosted.org/packages/72/36/131ae2dfc82d0fdc98fae8e3bbfe71ff14265bb434b23bd07b585afc6d61/ckzg-2.1.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5a01514239f12fb1a7ad9009c20062a4496e13b09541c1a65f97e295da648c70", size = 183286, upload-time = "2025-03-31T21:22:44.732Z" }, - { url = "https://files.pythonhosted.org/packages/c5/6a/d371b27024422b25228fc11fa57b1ba7756a94cc9fb0c75da292c235fdaa/ckzg-2.1.1-cp311-cp311-win_amd64.whl", hash = "sha256:6516b9684aae262c85cf7fddd8b585b8139ad20e08ec03994e219663abbb0916", size = 98819, upload-time = "2025-03-31T21:22:45.57Z" }, - { url = "https://files.pythonhosted.org/packages/93/a1/9c07513dd0ea01e5db727e67bd2660f3b300a4511281cdb8d5e04afa1cfd/ckzg-2.1.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:c60e8903344ce98ce036f0fabacce952abb714cad4607198b2f0961c28b8aa72", size = 116421, upload-time = "2025-03-31T21:22:46.434Z" }, - { url = "https://files.pythonhosted.org/packages/27/04/b69a0dfbb2722a14c98a52973f276679151ec56a14178cb48e6f2e1697bc/ckzg-2.1.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:a4299149dd72448e5a8d2d1cc6cc7472c92fc9d9f00b1377f5b017c089d9cd92", size = 100216, upload-time = "2025-03-31T21:22:47.633Z" }, - { url = "https://files.pythonhosted.org/packages/2e/24/9cc850d0b8ead395ad5064de67c7c91adacaf31b6b35292ab53fbd93270b/ckzg-2.1.1-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:025dd31ffdcc799f3ff842570a2a6683b6c5b01567da0109c0c05d11768729c4", size = 175764, upload-time = "2025-03-31T21:22:48.768Z" }, - { url = "https://files.pythonhosted.org/packages/c0/c1/eb13ba399082a98b932f10b230ec08e6456051c0ce3886b3f6d8548d11ab/ckzg-2.1.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9b42ab8385c273f40a693657c09d2bba40cb4f4666141e263906ba2e519e80bd", size = 161885, upload-time = "2025-03-31T21:22:50.05Z" }, - { url = "https://files.pythonhosted.org/packages/57/c7/58baa64199781950c5a8c6139a46e1acff0f057a36e56769817400eb87fb/ckzg-2.1.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1be3890fc1543f4fcfc0063e4baf5c036eb14bcf736dabdc6171ab017e0f1671", size = 170757, upload-time = "2025-03-31T21:22:51.282Z" }, - { url = "https://files.pythonhosted.org/packages/65/bd/4b8e1c70972c98829371b7004dc750a45268c5d3442d602e1b62f13ca867/ckzg-2.1.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:b754210ded172968b201e2d7252573af6bf52d6ad127ddd13d0b9a45a51dae7b", size = 173761, upload-time = "2025-03-31T21:22:52.6Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/c3fd1002f97ba3e0c5b1d9ab2c8fb7a6f475fa9b80ed9c4fa55975501a54/ckzg-2.1.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:b2f8fda87865897a269c4e951e3826c2e814427a6cdfed6731cccfe548f12b36", size = 188666, upload-time = "2025-03-31T21:22:53.47Z" }, - { url = "https://files.pythonhosted.org/packages/e2/d9/91cf5a8169ee60c9397c975163cbca34432571f94facec5f8c0086bb47d8/ckzg-2.1.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:98e70b5923d77c7359432490145e9d1ab0bf873eb5de56ec53f4a551d7eaec79", size = 183652, upload-time = "2025-03-31T21:22:54.351Z" }, - { url = "https://files.pythonhosted.org/packages/25/d4/8c9f6b852f99926862344b29f0c59681916ccfec2ac60a85952a369e0bca/ckzg-2.1.1-cp312-cp312-win_amd64.whl", hash = "sha256:42af7bde4ca45469cd93a96c3d15d69d51d40e7f0d30e3a20711ebd639465fcb", size = 98816, upload-time = "2025-03-31T21:22:55.23Z" }, - { url = "https://files.pythonhosted.org/packages/b7/9a/fa698b12e97452d11dd314e0335aae759725284ef6e1c1665aed56b1cd3e/ckzg-2.1.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:7e4edfdaf87825ff43b9885fabfdea408737a714f4ce5467100d9d1d0a03b673", size = 116426, upload-time = "2025-03-31T21:22:56.108Z" }, - { url = "https://files.pythonhosted.org/packages/a1/a6/8cccd308bd11b49b40eecad6900b5769da117951cac33e880dd25e851ef7/ckzg-2.1.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:815fd2a87d6d6c57d669fda30c150bc9bf387d47e67d84535aa42b909fdc28ea", size = 100219, upload-time = "2025-03-31T21:22:56.982Z" }, - { url = "https://files.pythonhosted.org/packages/30/0e/63573d816c1292b9a4d70eb6a7366b3593d29a977794039e926805a76ca0/ckzg-2.1.1-cp313-cp313-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c32466e809b1ab3ff01d3b0bb0b9912f61dcf72957885615595f75e3f7cc10e5", size = 175725, upload-time = "2025-03-31T21:22:58.213Z" }, - { url = "https://files.pythonhosted.org/packages/86/f6/a279609516695ad3fb8b201098c669ba3b2844cbf4fa0d83a0f02b9bb29b/ckzg-2.1.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f11b73ccf37b12993f39a7dbace159c6d580aacacde6ee17282848476550ddbc", size = 161835, upload-time = "2025-03-31T21:22:59.448Z" }, - { url = "https://files.pythonhosted.org/packages/39/e4/8cf7aef7dc05a777cb221e94046f947c6fe5317159a8dae2cd7090d52ef2/ckzg-2.1.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3b9433a1f2604bd9ac1646d3c83ad84a850d454d3ac589fe8e70c94b38a6b0", size = 170759, upload-time = "2025-03-31T21:23:01.022Z" }, - { url = "https://files.pythonhosted.org/packages/0b/17/b34e3c08eb36bc67e338b114f289b2595e581b8bdc09a8f12299a1db5d2f/ckzg-2.1.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:b7d7e1b5ea06234558cd95c483666fd785a629b720a7f1622b3cbffebdc62033", size = 173787, upload-time = "2025-03-31T21:23:01.974Z" }, - { url = "https://files.pythonhosted.org/packages/2e/f0/aff87c3ed80713453cb6c84fe6fbb7582d86a7a5e4460fda2a497d47f489/ckzg-2.1.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:9f5556e6675866040cc4335907be6c537051e7f668da289fa660fdd8a30c9ddb", size = 188722, upload-time = "2025-03-31T21:23:02.966Z" }, - { url = "https://files.pythonhosted.org/packages/44/d9/1f08bfb8fd1cbb8c7513e7ad3fb76bbb5c3fb446238c1eba582276e4d905/ckzg-2.1.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:55b2ba30c5c9daac0c55f1aac851f1b7bf1f7aa0028c2db4440e963dd5b866d6", size = 183686, upload-time = "2025-03-31T21:23:03.905Z" }, - { url = "https://files.pythonhosted.org/packages/a3/ff/434f6d2893cbdfad00c20d17e9a52d426ca042f5e980d5c3db96bc6b6e15/ckzg-2.1.1-cp313-cp313-win_amd64.whl", hash = "sha256:10d201601fc8f28c0e8cec3406676797024dd374c367bbeec5a7a9eac9147237", size = 98817, upload-time = "2025-03-31T21:23:05.2Z" }, - { url = "https://files.pythonhosted.org/packages/30/b3/a0c7d7ba6e669cf04605dc0329173db62fc1fe3c488761755cc01e5e1b4d/ckzg-2.1.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:375918e25eafb9bafe5215ab91698504cba3fe51b4fe92f5896af6c5663f50c6", size = 113191, upload-time = "2025-03-31T21:23:40.646Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b9/a6cf403b8528d18d7d9154e28381a397bf466c86aa8e0b3327cffdde5749/ckzg-2.1.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:38b3b7802c76d4ad015db2b7a79a49c193babae50ee5f77e9ac2865c9e9ddb09", size = 96207, upload-time = "2025-03-31T21:23:41.596Z" }, - { url = "https://files.pythonhosted.org/packages/63/6b/5ddd713d97886becb8450e3e13db891199125f722366d30d087ad5438390/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:438a5009fd254ace0bc1ad974d524547f1a41e6aa5e778c5cd41f4ee3106bcd6", size = 126160, upload-time = "2025-03-31T21:23:42.553Z" }, - { url = "https://files.pythonhosted.org/packages/c7/dd/e05aecc01e62108a7579f8df5e5d38536841f50e12172f8a84677edac0fa/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ce11cc163a2e0dab3af7455aca7053f9d5bb8d157f231acc7665fd230565d48", size = 102811, upload-time = "2025-03-31T21:23:43.494Z" }, - { url = "https://files.pythonhosted.org/packages/c6/81/6cdadd8626ac11290af3f58ae5dcffe38bd2c8f8c798dacee7475e244aac/ckzg-2.1.1-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b53964c07f6a076e97eaa1ef35045e935d7040aff14f80bae7e9105717702d05", size = 111328, upload-time = "2025-03-31T21:23:44.449Z" }, - { url = "https://files.pythonhosted.org/packages/36/b7/b129ff6955cd264c6ab3dbd52dd1b2759d1b121c09c03f9991e4c722c72f/ckzg-2.1.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cf085f15ae52ab2599c9b5a3d5842794bcf5613b7f58661fbfb0c5d9eac988b9", size = 98846, upload-time = "2025-03-31T21:23:45.407Z" }, - { url = "https://files.pythonhosted.org/packages/7f/ba/7d9c1f9cec7e0e382653c72165896194a05743e589b1dae2aa80236aa87f/ckzg-2.1.1-pp311-pypy311_pp73-macosx_10_15_x86_64.whl", hash = "sha256:4b0c850bd6cad22ac79b2a2ab884e0e7cd2b54a67d643cd616c145ebdb535a11", size = 113188, upload-time = "2025-03-31T21:23:46.337Z" }, - { url = "https://files.pythonhosted.org/packages/2f/92/9728f5ccc1c5e87c6c5ae7941250a447b61fd5a63aadbc15249e29c21bcf/ckzg-2.1.1-pp311-pypy311_pp73-macosx_11_0_arm64.whl", hash = "sha256:26951f36bb60c9150bbd38110f5e1625596f9779dad54d1d492d8ec38bc84e3a", size = 96208, upload-time = "2025-03-31T21:23:47.255Z" }, - { url = "https://files.pythonhosted.org/packages/39/63/5e27d587bd224fee70cb66b022e7c4ef95d0e091e08ee76c25ec12094b0d/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bbe12445e49c4bee67746b7b958e90a973b0de116d0390749b0df351d94e9a8c", size = 126158, upload-time = "2025-03-31T21:23:48.195Z" }, - { url = "https://files.pythonhosted.org/packages/43/98/e0a45946575a7b823d8ee0b47afb104b6017e54e1208f07da2529bc01900/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71c5d4f66f09de4a99271acac74d2acb3559a77de77a366b34a91e99e8822667", size = 102812, upload-time = "2025-03-31T21:23:49.16Z" }, - { url = "https://files.pythonhosted.org/packages/cb/50/718ca7b03e4b89b18cdf99cc3038050105b0acbf9b612c23cd513093c6de/ckzg-2.1.1-pp311-pypy311_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42673c1d007372a4e8b48f6ef8f0ce31a9688a463317a98539757d1e2fb1ecc7", size = 111327, upload-time = "2025-03-31T21:23:50.126Z" }, - { url = "https://files.pythonhosted.org/packages/29/c5/80e5a0c6967d02d801150104320484a258e5a49bd191e198643e74039320/ckzg-2.1.1-pp311-pypy311_pp73-win_amd64.whl", hash = "sha256:57a7dc41ec6b69c1d9117eb61cf001295e6b4f67a736020442e71fb4367fb1a5", size = 98847, upload-time = "2025-03-31T21:23:51.084Z" }, -] - -[[package]] -name = "click" -version = "8.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/6c/8ca2efa64cf75a977a0d7fac081354553ebe483345c734fb6b6515d96bbc/click-8.2.1.tar.gz", hash = "sha256:27c491cc05d968d271d5a1db13e3b5a184636d9d930f148c50b038f0d0646202", size = 286342, upload-time = "2025-05-20T23:19:49.832Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/85/32/10bb5764d90a8eee674e9dc6f4db6a0ab47c8c4d0d83c27f7c39ac415a4d/click-8.2.1-py3-none-any.whl", hash = "sha256:61a3265b914e850b85317d0b3109c7f8cd35a670f963866005d6ef1d5175a12b", size = 102215, upload-time = "2025-05-20T23:19:47.796Z" }, -] - -[[package]] -name = "colorama" -version = "0.4.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d8/53/6f443c9a4a8358a93a6792e2acffb9d9d5cb0a5cfd8802644b7b1c9a02e4/colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44", size = 27697, upload-time = "2022-10-25T02:36:22.414Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d1/d6/3965ed04c63042e047cb6a3e6ed1a63a35087b6a609aa3a15ed8ac56c221/colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6", size = 25335, upload-time = "2022-10-25T02:36:20.889Z" }, -] - -[[package]] -name = "cytoolz" -version = "1.0.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "toolz" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a7/f9/3243eed3a6545c2a33a21f74f655e3fcb5d2192613cd3db81a93369eb339/cytoolz-1.0.1.tar.gz", hash = "sha256:89cc3161b89e1bb3ed7636f74ed2e55984fd35516904fc878cae216e42b2c7d6", size = 626652, upload-time = "2024-12-13T05:47:36.672Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/d9/f13d66c16cff1fa1cb6c234698029877c456f35f577ef274aba3b86e7c51/cytoolz-1.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:cec9af61f71fc3853eb5dca3d42eb07d1f48a4599fa502cbe92adde85f74b042", size = 403515, upload-time = "2024-12-13T05:44:27.845Z" }, - { url = "https://files.pythonhosted.org/packages/4b/2d/4cdf848a69300c7d44984f2ebbebb3b8576e5449c8dea157298f3bdc4da3/cytoolz-1.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:140bbd649dbda01e91add7642149a5987a7c3ccc251f2263de894b89f50b6608", size = 383936, upload-time = "2024-12-13T05:44:29.5Z" }, - { url = "https://files.pythonhosted.org/packages/72/a4/ccfdd3f0ed9cc818f734b424261f6018fc61e3ec833bf85225a9aca0d994/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e90124bdc42ff58b88cdea1d24a6bc5f776414a314cc4d94f25c88badb3a16d1", size = 1934569, upload-time = "2024-12-13T05:44:30.799Z" }, - { url = "https://files.pythonhosted.org/packages/50/fc/38d5344fa595683ad10dc819cfc1d8b9d2b3391ccf3e8cb7bab4899a01f5/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e74801b751e28f7c5cc3ad264c123954a051f546f2fdfe089f5aa7a12ccfa6da", size = 2015129, upload-time = "2024-12-13T05:44:32.297Z" }, - { url = "https://files.pythonhosted.org/packages/28/29/75261748dc54a20a927f33641f4e9aac674cfc6d3fbd4f332e10d0b37639/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:582dad4545ddfb5127494ef23f3fa4855f1673a35d50c66f7638e9fb49805089", size = 2000506, upload-time = "2024-12-13T05:44:34.403Z" }, - { url = "https://files.pythonhosted.org/packages/00/ae/e4ead004cc2698281d153c4a5388638d67cdb5544d6d6cc1e5b3db2bd2a3/cytoolz-1.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd7bd0618e16efe03bd12f19c2a26a27e6e6b75d7105adb7be1cd2a53fa755d8", size = 1957537, upload-time = "2024-12-13T05:44:39.499Z" }, - { url = "https://files.pythonhosted.org/packages/4a/ff/4f3aa07f4f47701f7f63df60ce0a5669fa09c256c3d4a33503a9414ea5cc/cytoolz-1.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d74cca6acf1c4af58b2e4a89cc565ed61c5e201de2e434748c93e5a0f5c541a5", size = 1863331, upload-time = "2024-12-13T05:44:42.61Z" }, - { url = "https://files.pythonhosted.org/packages/a2/29/654f57f2a9b8e9765a4ab876765f64f94530b61fc6471a07feea42ece6d4/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:823a3763828d8d457f542b2a45d75d6b4ced5e470b5c7cf2ed66a02f508ed442", size = 1849938, upload-time = "2024-12-13T05:44:45.324Z" }, - { url = "https://files.pythonhosted.org/packages/bc/7b/11f457db6b291060a98315ab2c7198077d8bddeeebe5f7126d9dad98cc54/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:51633a14e6844c61db1d68c1ffd077cf949f5c99c60ed5f1e265b9e2966f1b52", size = 1852345, upload-time = "2024-12-13T05:44:47.994Z" }, - { url = "https://files.pythonhosted.org/packages/6b/92/0dccc96ce0323be236d404f5084479b79b747fa0e74e43a270e95868b5f9/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:f3ec9b01c45348f1d0d712507d54c2bfd69c62fbd7c9ef555c9d8298693c2432", size = 1989877, upload-time = "2024-12-13T05:44:51.514Z" }, - { url = "https://files.pythonhosted.org/packages/a3/c8/1c5203a81200bae51aa8f7b5fad613f695bf1afa03f16251ca23ecb2ef9f/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:1855022b712a9c7a5bce354517ab4727a38095f81e2d23d3eabaf1daeb6a3b3c", size = 1994492, upload-time = "2024-12-13T05:44:52.922Z" }, - { url = "https://files.pythonhosted.org/packages/e2/8a/04bc193c4d7ced8ef6bb62cdcd0bf40b5e5eb26586ed2cfb4433ec7dfd0a/cytoolz-1.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:9930f7288c4866a1dc1cc87174f0c6ff4cad1671eb1f6306808aa6c445857d78", size = 1896077, upload-time = "2024-12-13T05:44:56.118Z" }, - { url = "https://files.pythonhosted.org/packages/21/a5/bee63a58f51d2c74856db66e6119a014464ff8cb1c9387fa4bd2d94e49b0/cytoolz-1.0.1-cp310-cp310-win32.whl", hash = "sha256:a9baad795d72fadc3445ccd0f122abfdbdf94269157e6d6d4835636dad318804", size = 322135, upload-time = "2024-12-13T05:44:57.695Z" }, - { url = "https://files.pythonhosted.org/packages/e8/16/7abfb1685e8b7f2838264551ee33651748994813f566ac4c3d737dfe90e5/cytoolz-1.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:ad95b386a84e18e1f6136f6d343d2509d4c3aae9f5a536f3dc96808fcc56a8cf", size = 363599, upload-time = "2024-12-13T05:44:58.875Z" }, - { url = "https://files.pythonhosted.org/packages/dc/ea/8131ae39119820b8867cddc23716fa9f681f2b3bbce6f693e68dfb36b55b/cytoolz-1.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2d958d4f04d9d7018e5c1850790d9d8e68b31c9a2deebca74b903706fdddd2b6", size = 406162, upload-time = "2024-12-13T05:45:01.196Z" }, - { url = "https://files.pythonhosted.org/packages/26/18/3d9bd4c146f6ea6e51300c242b20cb416966b21d481dac230e1304f1e54b/cytoolz-1.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0f445b8b731fc0ecb1865b8e68a070084eb95d735d04f5b6c851db2daf3048ab", size = 384961, upload-time = "2024-12-13T05:45:02.387Z" }, - { url = "https://files.pythonhosted.org/packages/e4/73/9034827907c7f85c7c484c9494e905d022fb8174526004e9ef332570349e/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f546a96460a7e28eb2ec439f4664fa646c9b3e51c6ebad9a59d3922bbe65e30", size = 2091698, upload-time = "2024-12-13T05:45:04.353Z" }, - { url = "https://files.pythonhosted.org/packages/74/af/d5c2733b0fde1a08254ff1a8a8d567874040c9eb1606363cfebc0713c73f/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0317681dd065532d21836f860b0563b199ee716f55d0c1f10de3ce7100c78a3b", size = 2188452, upload-time = "2024-12-13T05:45:05.748Z" }, - { url = "https://files.pythonhosted.org/packages/6a/bb/77c71fa9c217260b4056a732d754748903423c2cdd82a673d6064741e375/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:0c0ef52febd5a7821a3fd8d10f21d460d1a3d2992f724ba9c91fbd7a96745d41", size = 2174203, upload-time = "2024-12-13T05:45:07.777Z" }, - { url = "https://files.pythonhosted.org/packages/fc/a9/a5b4a3ff5d22faa1b60293bfe97362e2caf4a830c26d37ab5557f60d04b2/cytoolz-1.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f5ebaf419acf2de73b643cf96108702b8aef8e825cf4f63209ceb078d5fbbbfd", size = 2099831, upload-time = "2024-12-13T05:45:11.477Z" }, - { url = "https://files.pythonhosted.org/packages/35/08/7f6869ea1ff31ce5289a7d58d0e7090acfe7058baa2764473048ff61ea3c/cytoolz-1.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f7f04eeb4088947585c92d6185a618b25ad4a0f8f66ea30c8db83cf94a425e3", size = 1996744, upload-time = "2024-12-13T05:45:14.172Z" }, - { url = "https://files.pythonhosted.org/packages/46/b4/9ac424c994b51763fd1bbed62d95f8fba8fa0e45c8c3c583904fdaf8f51d/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:f61928803bb501c17914b82d457c6f50fe838b173fb40d39c38d5961185bd6c7", size = 2013733, upload-time = "2024-12-13T05:45:16.912Z" }, - { url = "https://files.pythonhosted.org/packages/3e/99/03009765c4b87d742d5b5a8670abb56a8c7ede033c2cdaa4be8662d3b001/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:d2960cb4fa01ccb985ad1280db41f90dc97a80b397af970a15d5a5de403c8c61", size = 1994850, upload-time = "2024-12-13T05:45:18.414Z" }, - { url = "https://files.pythonhosted.org/packages/40/9a/8458af9a5557e177ea42f8cf7e477bede518b0bbef564e28c4151feaa52c/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:b2b407cc3e9defa8df5eb46644f6f136586f70ba49eba96f43de67b9a0984fd3", size = 2155352, upload-time = "2024-12-13T05:45:19.763Z" }, - { url = "https://files.pythonhosted.org/packages/5e/5c/2a701423e001fcbec288b4f3fc2bf67557d114c2388237fc1ae67e1e2686/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:8245f929144d4d3bd7b972c9593300195c6cea246b81b4c46053c48b3f044580", size = 2163515, upload-time = "2024-12-13T05:45:21.08Z" }, - { url = "https://files.pythonhosted.org/packages/36/16/ee2e06e65d9d533bc05cd52a0b355ba9072fc8f60d77289e529c6d2e3750/cytoolz-1.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:e37385db03af65763933befe89fa70faf25301effc3b0485fec1c15d4ce4f052", size = 2054431, upload-time = "2024-12-13T05:45:22.521Z" }, - { url = "https://files.pythonhosted.org/packages/d8/d5/2fac8315f210fa1bc7106e27c19e1211580aa25bb7fa17dfd79505e5baf2/cytoolz-1.0.1-cp311-cp311-win32.whl", hash = "sha256:50f9c530f83e3e574fc95c264c3350adde8145f4f8fc8099f65f00cc595e5ead", size = 322004, upload-time = "2024-12-13T05:45:24.048Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9e/0b70b641850a95f9ff90adde9d094a4b1d81ec54dadfd97fec0a2aaf440e/cytoolz-1.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:b7f6b617454b4326af7bd3c7c49b0fc80767f134eb9fd6449917a058d17a0e3c", size = 365358, upload-time = "2024-12-13T05:45:25.383Z" }, - { url = "https://files.pythonhosted.org/packages/d8/e8/218098344ed2cb5f8441fade9b2428e435e7073962374a9c71e59ac141a7/cytoolz-1.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fcb8f7d0d65db1269022e7e0428471edee8c937bc288ebdcb72f13eaa67c2fe4", size = 414121, upload-time = "2024-12-13T05:45:26.588Z" }, - { url = "https://files.pythonhosted.org/packages/de/27/4d729a5653718109262b758fec1a959aa9facb74c15460d9074dc76d6635/cytoolz-1.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:207d4e4b445e087e65556196ff472ff134370d9a275d591724142e255f384662", size = 390904, upload-time = "2024-12-13T05:45:27.718Z" }, - { url = "https://files.pythonhosted.org/packages/72/c0/cbabfa788bab9c6038953bf9478adaec06e88903a726946ea7c88092f5c4/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21cdf6bac6fd843f3b20280a66fd8df20dea4c58eb7214a2cd8957ec176f0bb3", size = 2090734, upload-time = "2024-12-13T05:45:30.515Z" }, - { url = "https://files.pythonhosted.org/packages/c3/66/369262c60f9423c2da82a60864a259c852f1aa122aced4acd2c679af58c0/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a55ec098036c0dea9f3bdc021f8acd9d105a945227d0811589f0573f21c9ce1", size = 2155933, upload-time = "2024-12-13T05:45:32.721Z" }, - { url = "https://files.pythonhosted.org/packages/aa/4e/ee55186802f8d24b5fbf9a11405ccd1203b30eded07cc17750618219b94e/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a13ab79ff4ce202e03ab646a2134696988b554b6dc4b71451e948403db1331d8", size = 2171903, upload-time = "2024-12-13T05:45:34.205Z" }, - { url = "https://files.pythonhosted.org/packages/a1/96/bd1a9f3396e9b7f618db8cd08d15630769ce3c8b7d0534f92cd639c977ae/cytoolz-1.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4e2d944799026e1ff08a83241f1027a2d9276c41f7a74224cd98b7df6e03957d", size = 2125270, upload-time = "2024-12-13T05:45:36.982Z" }, - { url = "https://files.pythonhosted.org/packages/28/48/2a3762873091c88a69e161111cfbc6c222ff145d57ff011a642b169f04f1/cytoolz-1.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88ba85834cd523b91fdf10325e1e6d71c798de36ea9bdc187ca7bd146420de6f", size = 1973967, upload-time = "2024-12-13T05:45:39.505Z" }, - { url = "https://files.pythonhosted.org/packages/e4/50/500bd69774bdc49a4d78ec8779eb6ac7c1a9d706bfd91cf2a1dba604373a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5a750b1af7e8bf6727f588940b690d69e25dc47cce5ce467925a76561317eaf7", size = 2021695, upload-time = "2024-12-13T05:45:40.911Z" }, - { url = "https://files.pythonhosted.org/packages/e4/4e/ba5a0ce34869495eb50653de8d676847490cf13a2cac1760fc4d313e78de/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:44a71870f7eae31d263d08b87da7c2bf1176f78892ed8bdade2c2850478cb126", size = 2010177, upload-time = "2024-12-13T05:45:42.48Z" }, - { url = "https://files.pythonhosted.org/packages/87/57/615c630b3089a13adb15351d958d227430cf624f03b1dd39eb52c34c1f59/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c8231b9abbd8e368e036f4cc2e16902c9482d4cf9e02a6147ed0e9a3cd4a9ab0", size = 2154321, upload-time = "2024-12-13T05:45:43.979Z" }, - { url = "https://files.pythonhosted.org/packages/7f/0f/fe1aa2d931e3b35ecc05215bd75da945ea7346095b3b6f6027164e602d5a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:aa87599ccc755de5a096a4d6c34984de6cd9dc928a0c5eaa7607457317aeaf9b", size = 2188374, upload-time = "2024-12-13T05:45:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/de/fa/fd363d97a641b6d0e2fd1d5c35b8fd41d9ccaeb4df56302f53bf23a58e3a/cytoolz-1.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:67cd16537df51baabde3baa770ab7b8d16839c4d21219d5b96ac59fb012ebd2d", size = 2077911, upload-time = "2024-12-13T05:45:48.219Z" }, - { url = "https://files.pythonhosted.org/packages/d9/68/0a22946b98ae5201b54ccb4e651295285c0fb79406022b6ee8b2f791940c/cytoolz-1.0.1-cp312-cp312-win32.whl", hash = "sha256:fb988c333f05ee30ad4693fe4da55d95ec0bb05775d2b60191236493ea2e01f9", size = 321903, upload-time = "2024-12-13T05:45:50.3Z" }, - { url = "https://files.pythonhosted.org/packages/62/1a/f3903197956055032f8cb297342e2dff07e50f83991aebfe5b4c4fcb55e4/cytoolz-1.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:8f89c48d8e5aec55ffd566a8ec858706d70ed0c6a50228eca30986bfa5b4da8b", size = 364490, upload-time = "2024-12-13T05:45:51.494Z" }, - { url = "https://files.pythonhosted.org/packages/aa/2e/a9f069db0107749e9e72baf6c21abe3f006841a3bcfdc9b8420e22ef31eb/cytoolz-1.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6944bb93b287032a4c5ca6879b69bcd07df46f3079cf8393958cf0b0454f50c0", size = 407365, upload-time = "2024-12-13T05:45:52.803Z" }, - { url = "https://files.pythonhosted.org/packages/a9/9b/5e87dd0e31f54c778b4f9f34cc14c1162d3096c8d746b0f8be97d70dd73c/cytoolz-1.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:e027260fd2fc5cb041277158ac294fc13dca640714527219f702fb459a59823a", size = 385233, upload-time = "2024-12-13T05:45:53.994Z" }, - { url = "https://files.pythonhosted.org/packages/63/00/2fd32b16284cdb97cfe092822179bc0c3bcdd5e927dd39f986169a517642/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:88662c0e07250d26f5af9bc95911e6137e124a5c1ec2ce4a5d74de96718ab242", size = 2062903, upload-time = "2024-12-13T05:45:55.202Z" }, - { url = "https://files.pythonhosted.org/packages/85/39/b3cbb5a9847ba59584a263772ad4f8ca2dbfd2a0e11efd09211d1219804c/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:309dffa78b0961b4c0cf55674b828fbbc793cf2d816277a5c8293c0c16155296", size = 2139517, upload-time = "2024-12-13T05:45:56.804Z" }, - { url = "https://files.pythonhosted.org/packages/ea/39/bfcab4a46d50c467e36fe704f19d8904efead417787806ee210327f68390/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:edb34246e6eb40343c5860fc51b24937698e4fa1ee415917a73ad772a9a1746b", size = 2154849, upload-time = "2024-12-13T05:45:58.814Z" }, - { url = "https://files.pythonhosted.org/packages/fd/42/3bc6ee61b0aa47e1cb40819adc1a456d7efa809f0dea9faddacb43fdde8f/cytoolz-1.0.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a54da7a8e4348a18d45d4d5bc84af6c716d7f131113a4f1cc45569d37edff1b", size = 2102302, upload-time = "2024-12-13T05:46:00.181Z" }, - { url = "https://files.pythonhosted.org/packages/00/66/3f636c6ddea7b18026b90a8c238af472e423b86e427b11df02213689b012/cytoolz-1.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:241c679c3b1913c0f7259cf1d9639bed5084c86d0051641d537a0980548aa266", size = 1960872, upload-time = "2024-12-13T05:46:01.612Z" }, - { url = "https://files.pythonhosted.org/packages/40/36/cb3b7cdd651007b69f9c48e9d104cec7cb8dc53afa1d6a720e5ad08022fa/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:5bfc860251a8f280ac79696fc3343cfc3a7c30b94199e0240b6c9e5b6b01a2a5", size = 2014430, upload-time = "2024-12-13T05:46:03.022Z" }, - { url = "https://files.pythonhosted.org/packages/88/3f/2e9bd2a16cfd269808922147551dcb2d8b68ba54a2c4deca2fa6a6cd0d5f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:c8edd1547014050c1bdad3ff85d25c82bd1c2a3c96830c6181521eb78b9a42b3", size = 2003127, upload-time = "2024-12-13T05:46:04.401Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7d/08604ff940aa784df8343c387fdf2489b948b714a6afb587775ae94da912/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:b349bf6162e8de215403d7f35f8a9b4b1853dc2a48e6e1a609a5b1a16868b296", size = 2142369, upload-time = "2024-12-13T05:46:06.004Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c6/39919a0645bdbdf720e97cae107f959ea9d1267fbc3b0d94fc6e1d12ac8f/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:1b18b35256219b6c3dd0fa037741b85d0bea39c552eab0775816e85a52834140", size = 2180427, upload-time = "2024-12-13T05:46:07.526Z" }, - { url = "https://files.pythonhosted.org/packages/d8/03/dbb9d47556ee54337e7e0ac209d17ceff2d2a197c34de08005abc7a7449b/cytoolz-1.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:738b2350f340ff8af883eb301054eb724997f795d20d90daec7911c389d61581", size = 2069785, upload-time = "2024-12-13T05:46:10.122Z" }, - { url = "https://files.pythonhosted.org/packages/ea/f8/11bb7b8947002231faae3ec2342df5896afbc19eb783a332cce6d219ff79/cytoolz-1.0.1-cp313-cp313-win32.whl", hash = "sha256:9cbd9c103df54fcca42be55ef40e7baea624ac30ee0b8bf1149f21146d1078d9", size = 320685, upload-time = "2024-12-13T05:46:11.553Z" }, - { url = "https://files.pythonhosted.org/packages/40/eb/dde173cf2357084ca9423950be1f2f11ab11d65d8bd30165bfb8fd4213e9/cytoolz-1.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:90e577e08d3a4308186d9e1ec06876d4756b1e8164b92971c69739ea17e15297", size = 362898, upload-time = "2024-12-13T05:46:12.771Z" }, - { url = "https://files.pythonhosted.org/packages/d9/f7/ef2a10daaec5c0f7d781d50758c6187eee484256e356ae8ef178d6c48497/cytoolz-1.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:83d19d55738ad9c60763b94f3f6d3c6e4de979aeb8d76841c1401081e0e58d96", size = 345702, upload-time = "2024-12-13T05:47:09.266Z" }, - { url = "https://files.pythonhosted.org/packages/c8/14/53c84adddedb67ff1546abb86fea04d26e24298c3ceab8436d20122ed0b9/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f112a71fad6ea824578e6393765ce5c054603afe1471a5c753ff6c67fd872d10", size = 385695, upload-time = "2024-12-13T05:47:11.011Z" }, - { url = "https://files.pythonhosted.org/packages/bd/80/3ae356c5e7b8d7dc7d1adb52f6932fee85cd748ed4e1217c269d2dfd610f/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5a515df8f8aa6e1eaaf397761a6e4aff2eef73b5f920aedf271416d5471ae5ee", size = 406261, upload-time = "2024-12-13T05:47:12.24Z" }, - { url = "https://files.pythonhosted.org/packages/0c/31/8e43761ffc82d90bf9cab7e0959712eedcd1e33c211397e143dd42d7af57/cytoolz-1.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92c398e7b7023460bea2edffe5fcd0a76029580f06c3f6938ac3d198b47156f3", size = 397207, upload-time = "2024-12-13T05:47:13.561Z" }, - { url = "https://files.pythonhosted.org/packages/d1/b9/fe9da37090b6444c65f848a83e390f87d8cb43d6a4df46de1556ad7e5ceb/cytoolz-1.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:3237e56211e03b13df47435b2369f5df281e02b04ad80a948ebd199b7bc10a47", size = 343358, upload-time = "2024-12-13T05:47:16.291Z" }, -] - -[[package]] -name = "dnspython" -version = "2.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b5/4a/263763cb2ba3816dd94b08ad3a33d5fdae34ecb856678773cc40a3605829/dnspython-2.7.0.tar.gz", hash = "sha256:ce9c432eda0dc91cf618a5cedf1a4e142651196bbcd2c80e89ed5a907e5cfaf1", size = 345197, upload-time = "2024-10-05T20:14:59.362Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/68/1b/e0a87d256e40e8c888847551b20a017a6b98139178505dc7ffb96f04e954/dnspython-2.7.0-py3-none-any.whl", hash = "sha256:b4c34b7d10b51bcc3a5071e7b8dee77939f1e878477eeecc965e9835f63c6c86", size = 313632, upload-time = "2024-10-05T20:14:57.687Z" }, -] - -[[package]] -name = "email-validator" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "dnspython" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/48/ce/13508a1ec3f8bb981ae4ca79ea40384becc868bfae97fd1c942bb3a001b1/email_validator-2.2.0.tar.gz", hash = "sha256:cb690f344c617a714f22e66ae771445a1ceb46821152df8e165c5f9a364582b7", size = 48967, upload-time = "2024-06-20T11:30:30.034Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/d7/ee/bf0adb559ad3c786f12bcbc9296b3f5675f529199bef03e2df281fa1fadb/email_validator-2.2.0-py3-none-any.whl", hash = "sha256:561977c2d73ce3611850a06fa56b414621e0c8faa9d66f2611407d87465da631", size = 33521, upload-time = "2024-06-20T11:30:28.248Z" }, -] - -[[package]] -name = "eth-abi" -version = "5.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "parsimonious" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/00/71/d9e1380bd77fd22f98b534699af564f189b56d539cc2b9dab908d4e4c242/eth_abi-5.2.0.tar.gz", hash = "sha256:178703fa98c07d8eecd5ae569e7e8d159e493ebb6eeb534a8fe973fbc4e40ef0", size = 49797, upload-time = "2025-01-14T16:29:34.629Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7a/b4/2f3982c4cbcbf5eeb6aec62df1533c0e63c653b3021ff338d44944405676/eth_abi-5.2.0-py3-none-any.whl", hash = "sha256:17abe47560ad753f18054f5b3089fcb588f3e3a092136a416b6c1502cb7e8877", size = 28511, upload-time = "2025-01-14T16:29:31.862Z" }, -] - -[[package]] -name = "eth-account" -version = "0.13.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "bitarray" }, - { name = "ckzg" }, - { name = "eth-abi" }, - { name = "eth-keyfile" }, - { name = "eth-keys" }, - { name = "eth-rlp" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "rlp" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/74/cf/20f76a29be97339c969fd765f1237154286a565a1d61be98e76bb7af946a/eth_account-0.13.7.tar.gz", hash = "sha256:5853ecbcbb22e65411176f121f5f24b8afeeaf13492359d254b16d8b18c77a46", size = 935998, upload-time = "2025-04-21T21:11:21.204Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/46/18/088fb250018cbe665bc2111974301b2d59f294a565aff7564c4df6878da2/eth_account-0.13.7-py3-none-any.whl", hash = "sha256:39727de8c94d004ff61d10da7587509c04d2dc7eac71e04830135300bdfc6d24", size = 587452, upload-time = "2025-04-21T21:11:18.346Z" }, -] - -[[package]] -name = "eth-hash" -version = "0.7.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ee/38/577b7bc9380ef9dff0f1dffefe0c9a1ded2385e7a06c306fd95afb6f9451/eth_hash-0.7.1.tar.gz", hash = "sha256:d2411a403a0b0a62e8247b4117932d900ffb4c8c64b15f92620547ca5ce46be5", size = 12227, upload-time = "2025-01-13T21:29:21.765Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/eb/db/f8775490669d28aca24871c67dd56b3e72105cb3bcae9a4ec65dd70859b3/eth_hash-0.7.1-py3-none-any.whl", hash = "sha256:0fb1add2adf99ef28883fd6228eb447ef519ea72933535ad1a0b28c6f65f868a", size = 8028, upload-time = "2025-01-13T21:29:19.365Z" }, -] - -[package.optional-dependencies] -pycryptodome = [ - { name = "pycryptodome" }, -] - -[[package]] -name = "eth-keyfile" -version = "0.8.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-keys" }, - { name = "eth-utils" }, - { name = "pycryptodome" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/35/66/dd823b1537befefbbff602e2ada88f1477c5b40ec3731e3d9bc676c5f716/eth_keyfile-0.8.1.tar.gz", hash = "sha256:9708bc31f386b52cca0969238ff35b1ac72bd7a7186f2a84b86110d3c973bec1", size = 12267, upload-time = "2024-04-23T20:28:53.862Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/88/fc/48a586175f847dd9e05e5b8994d2fe8336098781ec2e9836a2ad94280281/eth_keyfile-0.8.1-py3-none-any.whl", hash = "sha256:65387378b82fe7e86d7cb9f8d98e6d639142661b2f6f490629da09fddbef6d64", size = 7510, upload-time = "2024-04-23T20:28:51.063Z" }, -] - -[[package]] -name = "eth-keys" -version = "0.7.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-typing" }, - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/58/11/1ed831c50bd74f57829aa06e58bd82a809c37e070ee501c953b9ac1f1552/eth_keys-0.7.0.tar.gz", hash = "sha256:79d24fd876201df67741de3e3fefb3f4dbcbb6ace66e47e6fe662851a4547814", size = 30166, upload-time = "2025-04-07T17:40:21.697Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/4d/25/0ae00f2b0095e559d61ad3dc32171bd5a29dfd95ab04b4edd641f7c75f72/eth_keys-0.7.0-py3-none-any.whl", hash = "sha256:b0cdda8ffe8e5ba69c7c5ca33f153828edcace844f67aabd4542d7de38b159cf", size = 20656, upload-time = "2025-04-07T17:40:20.441Z" }, -] - -[[package]] -name = "eth-rlp" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "rlp" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7f/ea/ad39d001fa9fed07fad66edb00af701e29b48be0ed44a3bcf58cb3adf130/eth_rlp-2.2.0.tar.gz", hash = "sha256:5e4b2eb1b8213e303d6a232dfe35ab8c29e2d3051b86e8d359def80cd21db83d", size = 7720, upload-time = "2025-02-04T21:51:08.134Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/3b/57efe2bc2df0980680d57c01a36516cd3171d2319ceb30e675de19fc2cc5/eth_rlp-2.2.0-py3-none-any.whl", hash = "sha256:5692d595a741fbaef1203db6a2fedffbd2506d31455a6ad378c8449ee5985c47", size = 4446, upload-time = "2025-02-04T21:51:05.823Z" }, -] - -[[package]] -name = "eth-typing" -version = "5.2.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/60/54/62aa24b9cc708f06316167ee71c362779c8ed21fc8234a5cd94a8f53b623/eth_typing-5.2.1.tar.gz", hash = "sha256:7557300dbf02a93c70fa44af352b5c4a58f94e997a0fd6797fb7d1c29d9538ee", size = 21806, upload-time = "2025-04-14T20:39:28.217Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/30/72/c370bbe4c53da7bf998d3523f5a0f38867654923a82192df88d0705013d3/eth_typing-5.2.1-py3-none-any.whl", hash = "sha256:b0c2812ff978267563b80e9d701f487dd926f1d376d674f3b535cfe28b665d3d", size = 19163, upload-time = "2025-04-14T20:39:26.571Z" }, -] - -[[package]] -name = "eth-utils" -version = "5.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "cytoolz", marker = "implementation_name == 'cpython'" }, - { name = "eth-hash" }, - { name = "eth-typing" }, - { name = "pydantic" }, - { name = "toolz", marker = "implementation_name == 'pypy'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0d/49/bee95f16d2ef068097afeeffbd6c67738107001ee57ad7bcdd4fc4d3c6a7/eth_utils-5.3.0.tar.gz", hash = "sha256:1f096867ac6be895f456fa3acb26e9573ae66e753abad9208f316d24d6178156", size = 123753, upload-time = "2025-04-14T19:35:56.431Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/c4/c6/0417a92e6a3fc9b85f5a8380d9f9d43b69ba836a90e45f79f9ae74d41e53/eth_utils-5.3.0-py3-none-any.whl", hash = "sha256:ac184883ab299d923428bbe25dae5e356979a3993e0ef695a864db0a20bc262d", size = 102531, upload-time = "2025-04-14T19:35:55.176Z" }, -] - -[[package]] -name = "exceptiongroup" -version = "1.3.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.13'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0b/9f/a65090624ecf468cdca03533906e7c69ed7588582240cfe7cc9e770b50eb/exceptiongroup-1.3.0.tar.gz", hash = "sha256:b241f5885f560bc56a59ee63ca4c6a8bfa46ae4ad651af316d4e81817bb9fd88", size = 29749, upload-time = "2025-05-10T17:42:51.123Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/36/f4/c6e662dade71f56cd2f3735141b265c3c79293c109549c1e6933b0651ffc/exceptiongroup-1.3.0-py3-none-any.whl", hash = "sha256:4d111e6e0c13d0644cad6ddaa7ed0261a0b36971f6d23e7ec9b4b9097da78a10", size = 16674, upload-time = "2025-05-10T17:42:49.33Z" }, -] - -[[package]] -name = "fastapi" -version = "0.115.12" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "starlette" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f4/55/ae499352d82338331ca1e28c7f4a63bfd09479b16395dce38cf50a39e2c2/fastapi-0.115.12.tar.gz", hash = "sha256:1e2c2a2646905f9e83d32f04a3f86aff4a286669c6c950ca95b5fd68c2602681", size = 295236, upload-time = "2025-03-23T22:55:43.822Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/50/b3/b51f09c2ba432a576fe63758bddc81f78f0c6309d9e5c10d194313bf021e/fastapi-0.115.12-py3-none-any.whl", hash = "sha256:e94613d6c05e27be7ffebdd6ea5f388112e5e430c8f7d6494a9d1d88d43e814d", size = 95164, upload-time = "2025-03-23T22:55:42.101Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "email-validator" }, - { name = "fastapi-cli", extra = ["standard"] }, - { name = "httpx" }, - { name = "jinja2" }, - { name = "python-multipart" }, - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "fastapi-cli" -version = "0.0.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "rich-toolkit" }, - { name = "typer" }, - { name = "uvicorn", extra = ["standard"] }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fe/73/82a5831fbbf8ed75905bacf5b2d9d3dfd6f04d6968b29fe6f72a5ae9ceb1/fastapi_cli-0.0.7.tar.gz", hash = "sha256:02b3b65956f526412515907a0793c9094abd4bfb5457b389f645b0ea6ba3605e", size = 16753, upload-time = "2024-12-15T14:28:10.028Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/a1/e6/5daefc851b514ce2287d8f5d358ae4341089185f78f3217a69d0ce3a390c/fastapi_cli-0.0.7-py3-none-any.whl", hash = "sha256:d549368ff584b2804336c61f192d86ddea080c11255f375959627911944804f4", size = 10705, upload-time = "2024-12-15T14:28:06.18Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "uvicorn", extra = ["standard"] }, -] - -[[package]] -name = "flask" -version = "3.1.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "blinker" }, - { name = "click" }, - { name = "itsdangerous" }, - { name = "jinja2" }, - { name = "markupsafe" }, - { name = "werkzeug" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c0/de/e47735752347f4128bcf354e0da07ef311a78244eba9e3dc1d4a5ab21a98/flask-3.1.1.tar.gz", hash = "sha256:284c7b8f2f58cb737f0cf1c30fd7eaf0ccfcde196099d24ecede3fc2005aa59e", size = 753440, upload-time = "2025-05-13T15:01:17.447Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/68/9d4508e893976286d2ead7f8f571314af6c2037af34853a30fd769c02e9d/flask-3.1.1-py3-none-any.whl", hash = "sha256:07aae2bb5eaf77993ef57e357491839f5fd9f4dc281593a81a9e4d79a24f295c", size = 103305, upload-time = "2025-05-13T15:01:15.591Z" }, -] - -[[package]] -name = "frozenlist" -version = "1.7.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/79/b1/b64018016eeb087db503b038296fd782586432b9c077fc5c7839e9cb6ef6/frozenlist-1.7.0.tar.gz", hash = "sha256:2e310d81923c2437ea8670467121cc3e9b0f76d3043cc1d2331d56c7fb7a3a8f", size = 45078, upload-time = "2025-06-09T23:02:35.538Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/36/0da0a49409f6b47cc2d060dc8c9040b897b5902a8a4e37d9bc1deb11f680/frozenlist-1.7.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:cc4df77d638aa2ed703b878dd093725b72a824c3c546c076e8fdf276f78ee84a", size = 81304, upload-time = "2025-06-09T22:59:46.226Z" }, - { url = "https://files.pythonhosted.org/packages/77/f0/77c11d13d39513b298e267b22eb6cb559c103d56f155aa9a49097221f0b6/frozenlist-1.7.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:716a9973a2cc963160394f701964fe25012600f3d311f60c790400b00e568b61", size = 47735, upload-time = "2025-06-09T22:59:48.133Z" }, - { url = "https://files.pythonhosted.org/packages/37/12/9d07fa18971a44150593de56b2f2947c46604819976784bcf6ea0d5db43b/frozenlist-1.7.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:a0fd1bad056a3600047fb9462cff4c5322cebc59ebf5d0a3725e0ee78955001d", size = 46775, upload-time = "2025-06-09T22:59:49.564Z" }, - { url = "https://files.pythonhosted.org/packages/70/34/f73539227e06288fcd1f8a76853e755b2b48bca6747e99e283111c18bcd4/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3789ebc19cb811163e70fe2bd354cea097254ce6e707ae42e56f45e31e96cb8e", size = 224644, upload-time = "2025-06-09T22:59:51.35Z" }, - { url = "https://files.pythonhosted.org/packages/fb/68/c1d9c2f4a6e438e14613bad0f2973567586610cc22dcb1e1241da71de9d3/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:af369aa35ee34f132fcfad5be45fbfcde0e3a5f6a1ec0712857f286b7d20cca9", size = 222125, upload-time = "2025-06-09T22:59:52.884Z" }, - { url = "https://files.pythonhosted.org/packages/b9/d0/98e8f9a515228d708344d7c6986752be3e3192d1795f748c24bcf154ad99/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ac64b6478722eeb7a3313d494f8342ef3478dff539d17002f849101b212ef97c", size = 233455, upload-time = "2025-06-09T22:59:54.74Z" }, - { url = "https://files.pythonhosted.org/packages/79/df/8a11bcec5600557f40338407d3e5bea80376ed1c01a6c0910fcfdc4b8993/frozenlist-1.7.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f89f65d85774f1797239693cef07ad4c97fdd0639544bad9ac4b869782eb1981", size = 227339, upload-time = "2025-06-09T22:59:56.187Z" }, - { url = "https://files.pythonhosted.org/packages/50/82/41cb97d9c9a5ff94438c63cc343eb7980dac4187eb625a51bdfdb7707314/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1073557c941395fdfcfac13eb2456cb8aad89f9de27bae29fabca8e563b12615", size = 212969, upload-time = "2025-06-09T22:59:57.604Z" }, - { url = "https://files.pythonhosted.org/packages/13/47/f9179ee5ee4f55629e4f28c660b3fdf2775c8bfde8f9c53f2de2d93f52a9/frozenlist-1.7.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1ed8d2fa095aae4bdc7fdd80351009a48d286635edffee66bf865e37a9125c50", size = 222862, upload-time = "2025-06-09T22:59:59.498Z" }, - { url = "https://files.pythonhosted.org/packages/1a/52/df81e41ec6b953902c8b7e3a83bee48b195cb0e5ec2eabae5d8330c78038/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:24c34bea555fe42d9f928ba0a740c553088500377448febecaa82cc3e88aa1fa", size = 222492, upload-time = "2025-06-09T23:00:01.026Z" }, - { url = "https://files.pythonhosted.org/packages/84/17/30d6ea87fa95a9408245a948604b82c1a4b8b3e153cea596421a2aef2754/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:69cac419ac6a6baad202c85aaf467b65ac860ac2e7f2ac1686dc40dbb52f6577", size = 238250, upload-time = "2025-06-09T23:00:03.401Z" }, - { url = "https://files.pythonhosted.org/packages/8f/00/ecbeb51669e3c3df76cf2ddd66ae3e48345ec213a55e3887d216eb4fbab3/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:960d67d0611f4c87da7e2ae2eacf7ea81a5be967861e0c63cf205215afbfac59", size = 218720, upload-time = "2025-06-09T23:00:05.282Z" }, - { url = "https://files.pythonhosted.org/packages/1a/c0/c224ce0e0eb31cc57f67742071bb470ba8246623c1823a7530be0e76164c/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:41be2964bd4b15bf575e5daee5a5ce7ed3115320fb3c2b71fca05582ffa4dc9e", size = 232585, upload-time = "2025-06-09T23:00:07.962Z" }, - { url = "https://files.pythonhosted.org/packages/55/3c/34cb694abf532f31f365106deebdeac9e45c19304d83cf7d51ebbb4ca4d1/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:46d84d49e00c9429238a7ce02dc0be8f6d7cd0cd405abd1bebdc991bf27c15bd", size = 234248, upload-time = "2025-06-09T23:00:09.428Z" }, - { url = "https://files.pythonhosted.org/packages/98/c0/2052d8b6cecda2e70bd81299e3512fa332abb6dcd2969b9c80dfcdddbf75/frozenlist-1.7.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:15900082e886edb37480335d9d518cec978afc69ccbc30bd18610b7c1b22a718", size = 221621, upload-time = "2025-06-09T23:00:11.32Z" }, - { url = "https://files.pythonhosted.org/packages/c5/bf/7dcebae315436903b1d98ffb791a09d674c88480c158aa171958a3ac07f0/frozenlist-1.7.0-cp310-cp310-win32.whl", hash = "sha256:400ddd24ab4e55014bba442d917203c73b2846391dd42ca5e38ff52bb18c3c5e", size = 39578, upload-time = "2025-06-09T23:00:13.526Z" }, - { url = "https://files.pythonhosted.org/packages/8f/5f/f69818f017fa9a3d24d1ae39763e29b7f60a59e46d5f91b9c6b21622f4cd/frozenlist-1.7.0-cp310-cp310-win_amd64.whl", hash = "sha256:6eb93efb8101ef39d32d50bce242c84bcbddb4f7e9febfa7b524532a239b4464", size = 43830, upload-time = "2025-06-09T23:00:14.98Z" }, - { url = "https://files.pythonhosted.org/packages/34/7e/803dde33760128acd393a27eb002f2020ddb8d99d30a44bfbaab31c5f08a/frozenlist-1.7.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:aa51e147a66b2d74de1e6e2cf5921890de6b0f4820b257465101d7f37b49fb5a", size = 82251, upload-time = "2025-06-09T23:00:16.279Z" }, - { url = "https://files.pythonhosted.org/packages/75/a9/9c2c5760b6ba45eae11334db454c189d43d34a4c0b489feb2175e5e64277/frozenlist-1.7.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:9b35db7ce1cd71d36ba24f80f0c9e7cff73a28d7a74e91fe83e23d27c7828750", size = 48183, upload-time = "2025-06-09T23:00:17.698Z" }, - { url = "https://files.pythonhosted.org/packages/47/be/4038e2d869f8a2da165f35a6befb9158c259819be22eeaf9c9a8f6a87771/frozenlist-1.7.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:34a69a85e34ff37791e94542065c8416c1afbf820b68f720452f636d5fb990cd", size = 47107, upload-time = "2025-06-09T23:00:18.952Z" }, - { url = "https://files.pythonhosted.org/packages/79/26/85314b8a83187c76a37183ceed886381a5f992975786f883472fcb6dc5f2/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4a646531fa8d82c87fe4bb2e596f23173caec9185bfbca5d583b4ccfb95183e2", size = 237333, upload-time = "2025-06-09T23:00:20.275Z" }, - { url = "https://files.pythonhosted.org/packages/1f/fd/e5b64f7d2c92a41639ffb2ad44a6a82f347787abc0c7df5f49057cf11770/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:79b2ffbba483f4ed36a0f236ccb85fbb16e670c9238313709638167670ba235f", size = 231724, upload-time = "2025-06-09T23:00:21.705Z" }, - { url = "https://files.pythonhosted.org/packages/20/fb/03395c0a43a5976af4bf7534759d214405fbbb4c114683f434dfdd3128ef/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a26f205c9ca5829cbf82bb2a84b5c36f7184c4316617d7ef1b271a56720d6b30", size = 245842, upload-time = "2025-06-09T23:00:23.148Z" }, - { url = "https://files.pythonhosted.org/packages/d0/15/c01c8e1dffdac5d9803507d824f27aed2ba76b6ed0026fab4d9866e82f1f/frozenlist-1.7.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bcacfad3185a623fa11ea0e0634aac7b691aa925d50a440f39b458e41c561d98", size = 239767, upload-time = "2025-06-09T23:00:25.103Z" }, - { url = "https://files.pythonhosted.org/packages/14/99/3f4c6fe882c1f5514b6848aa0a69b20cb5e5d8e8f51a339d48c0e9305ed0/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:72c1b0fe8fe451b34f12dce46445ddf14bd2a5bcad7e324987194dc8e3a74c86", size = 224130, upload-time = "2025-06-09T23:00:27.061Z" }, - { url = "https://files.pythonhosted.org/packages/4d/83/220a374bd7b2aeba9d0725130665afe11de347d95c3620b9b82cc2fcab97/frozenlist-1.7.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:61d1a5baeaac6c0798ff6edfaeaa00e0e412d49946c53fae8d4b8e8b3566c4ae", size = 235301, upload-time = "2025-06-09T23:00:29.02Z" }, - { url = "https://files.pythonhosted.org/packages/03/3c/3e3390d75334a063181625343e8daab61b77e1b8214802cc4e8a1bb678fc/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:7edf5c043c062462f09b6820de9854bf28cc6cc5b6714b383149745e287181a8", size = 234606, upload-time = "2025-06-09T23:00:30.514Z" }, - { url = "https://files.pythonhosted.org/packages/23/1e/58232c19608b7a549d72d9903005e2d82488f12554a32de2d5fb59b9b1ba/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:d50ac7627b3a1bd2dcef6f9da89a772694ec04d9a61b66cf87f7d9446b4a0c31", size = 248372, upload-time = "2025-06-09T23:00:31.966Z" }, - { url = "https://files.pythonhosted.org/packages/c0/a4/e4a567e01702a88a74ce8a324691e62a629bf47d4f8607f24bf1c7216e7f/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:ce48b2fece5aeb45265bb7a58259f45027db0abff478e3077e12b05b17fb9da7", size = 229860, upload-time = "2025-06-09T23:00:33.375Z" }, - { url = "https://files.pythonhosted.org/packages/73/a6/63b3374f7d22268b41a9db73d68a8233afa30ed164c46107b33c4d18ecdd/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:fe2365ae915a1fafd982c146754e1de6ab3478def8a59c86e1f7242d794f97d5", size = 245893, upload-time = "2025-06-09T23:00:35.002Z" }, - { url = "https://files.pythonhosted.org/packages/6d/eb/d18b3f6e64799a79673c4ba0b45e4cfbe49c240edfd03a68be20002eaeaa/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:45a6f2fdbd10e074e8814eb98b05292f27bad7d1883afbe009d96abdcf3bc898", size = 246323, upload-time = "2025-06-09T23:00:36.468Z" }, - { url = "https://files.pythonhosted.org/packages/5a/f5/720f3812e3d06cd89a1d5db9ff6450088b8f5c449dae8ffb2971a44da506/frozenlist-1.7.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:21884e23cffabb157a9dd7e353779077bf5b8f9a58e9b262c6caad2ef5f80a56", size = 233149, upload-time = "2025-06-09T23:00:37.963Z" }, - { url = "https://files.pythonhosted.org/packages/69/68/03efbf545e217d5db8446acfd4c447c15b7c8cf4dbd4a58403111df9322d/frozenlist-1.7.0-cp311-cp311-win32.whl", hash = "sha256:284d233a8953d7b24f9159b8a3496fc1ddc00f4db99c324bd5fb5f22d8698ea7", size = 39565, upload-time = "2025-06-09T23:00:39.753Z" }, - { url = "https://files.pythonhosted.org/packages/58/17/fe61124c5c333ae87f09bb67186d65038834a47d974fc10a5fadb4cc5ae1/frozenlist-1.7.0-cp311-cp311-win_amd64.whl", hash = "sha256:387cbfdcde2f2353f19c2f66bbb52406d06ed77519ac7ee21be0232147c2592d", size = 44019, upload-time = "2025-06-09T23:00:40.988Z" }, - { url = "https://files.pythonhosted.org/packages/ef/a2/c8131383f1e66adad5f6ecfcce383d584ca94055a34d683bbb24ac5f2f1c/frozenlist-1.7.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3dbf9952c4bb0e90e98aec1bd992b3318685005702656bc6f67c1a32b76787f2", size = 81424, upload-time = "2025-06-09T23:00:42.24Z" }, - { url = "https://files.pythonhosted.org/packages/4c/9d/02754159955088cb52567337d1113f945b9e444c4960771ea90eb73de8db/frozenlist-1.7.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:1f5906d3359300b8a9bb194239491122e6cf1444c2efb88865426f170c262cdb", size = 47952, upload-time = "2025-06-09T23:00:43.481Z" }, - { url = "https://files.pythonhosted.org/packages/01/7a/0046ef1bd6699b40acd2067ed6d6670b4db2f425c56980fa21c982c2a9db/frozenlist-1.7.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:3dabd5a8f84573c8d10d8859a50ea2dec01eea372031929871368c09fa103478", size = 46688, upload-time = "2025-06-09T23:00:44.793Z" }, - { url = "https://files.pythonhosted.org/packages/d6/a2/a910bafe29c86997363fb4c02069df4ff0b5bc39d33c5198b4e9dd42d8f8/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aa57daa5917f1738064f302bf2626281a1cb01920c32f711fbc7bc36111058a8", size = 243084, upload-time = "2025-06-09T23:00:46.125Z" }, - { url = "https://files.pythonhosted.org/packages/64/3e/5036af9d5031374c64c387469bfcc3af537fc0f5b1187d83a1cf6fab1639/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:c193dda2b6d49f4c4398962810fa7d7c78f032bf45572b3e04dd5249dff27e08", size = 233524, upload-time = "2025-06-09T23:00:47.73Z" }, - { url = "https://files.pythonhosted.org/packages/06/39/6a17b7c107a2887e781a48ecf20ad20f1c39d94b2a548c83615b5b879f28/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe2b675cf0aaa6d61bf8fbffd3c274b3c9b7b1623beb3809df8a81399a4a9c4", size = 248493, upload-time = "2025-06-09T23:00:49.742Z" }, - { url = "https://files.pythonhosted.org/packages/be/00/711d1337c7327d88c44d91dd0f556a1c47fb99afc060ae0ef66b4d24793d/frozenlist-1.7.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8fc5d5cda37f62b262405cf9652cf0856839c4be8ee41be0afe8858f17f4c94b", size = 244116, upload-time = "2025-06-09T23:00:51.352Z" }, - { url = "https://files.pythonhosted.org/packages/24/fe/74e6ec0639c115df13d5850e75722750adabdc7de24e37e05a40527ca539/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b0d5ce521d1dd7d620198829b87ea002956e4319002ef0bc8d3e6d045cb4646e", size = 224557, upload-time = "2025-06-09T23:00:52.855Z" }, - { url = "https://files.pythonhosted.org/packages/8d/db/48421f62a6f77c553575201e89048e97198046b793f4a089c79a6e3268bd/frozenlist-1.7.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:488d0a7d6a0008ca0db273c542098a0fa9e7dfaa7e57f70acef43f32b3f69dca", size = 241820, upload-time = "2025-06-09T23:00:54.43Z" }, - { url = "https://files.pythonhosted.org/packages/1d/fa/cb4a76bea23047c8462976ea7b7a2bf53997a0ca171302deae9d6dd12096/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:15a7eaba63983d22c54d255b854e8108e7e5f3e89f647fc854bd77a237e767df", size = 236542, upload-time = "2025-06-09T23:00:56.409Z" }, - { url = "https://files.pythonhosted.org/packages/5d/32/476a4b5cfaa0ec94d3f808f193301debff2ea42288a099afe60757ef6282/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1eaa7e9c6d15df825bf255649e05bd8a74b04a4d2baa1ae46d9c2d00b2ca2cb5", size = 249350, upload-time = "2025-06-09T23:00:58.468Z" }, - { url = "https://files.pythonhosted.org/packages/8d/ba/9a28042f84a6bf8ea5dbc81cfff8eaef18d78b2a1ad9d51c7bc5b029ad16/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:e4389e06714cfa9d47ab87f784a7c5be91d3934cd6e9a7b85beef808297cc025", size = 225093, upload-time = "2025-06-09T23:01:00.015Z" }, - { url = "https://files.pythonhosted.org/packages/bc/29/3a32959e68f9cf000b04e79ba574527c17e8842e38c91d68214a37455786/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:73bd45e1488c40b63fe5a7df892baf9e2a4d4bb6409a2b3b78ac1c6236178e01", size = 245482, upload-time = "2025-06-09T23:01:01.474Z" }, - { url = "https://files.pythonhosted.org/packages/80/e8/edf2f9e00da553f07f5fa165325cfc302dead715cab6ac8336a5f3d0adc2/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:99886d98e1643269760e5fe0df31e5ae7050788dd288947f7f007209b8c33f08", size = 249590, upload-time = "2025-06-09T23:01:02.961Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/9a0eb48b944050f94cc51ee1c413eb14a39543cc4f760ed12657a5a3c45a/frozenlist-1.7.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:290a172aae5a4c278c6da8a96222e6337744cd9c77313efe33d5670b9f65fc43", size = 237785, upload-time = "2025-06-09T23:01:05.095Z" }, - { url = "https://files.pythonhosted.org/packages/f3/74/87601e0fb0369b7a2baf404ea921769c53b7ae00dee7dcfe5162c8c6dbf0/frozenlist-1.7.0-cp312-cp312-win32.whl", hash = "sha256:426c7bc70e07cfebc178bc4c2bf2d861d720c4fff172181eeb4a4c41d4ca2ad3", size = 39487, upload-time = "2025-06-09T23:01:06.54Z" }, - { url = "https://files.pythonhosted.org/packages/0b/15/c026e9a9fc17585a9d461f65d8593d281fedf55fbf7eb53f16c6df2392f9/frozenlist-1.7.0-cp312-cp312-win_amd64.whl", hash = "sha256:563b72efe5da92e02eb68c59cb37205457c977aa7a449ed1b37e6939e5c47c6a", size = 43874, upload-time = "2025-06-09T23:01:07.752Z" }, - { url = "https://files.pythonhosted.org/packages/24/90/6b2cebdabdbd50367273c20ff6b57a3dfa89bd0762de02c3a1eb42cb6462/frozenlist-1.7.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee80eeda5e2a4e660651370ebffd1286542b67e268aa1ac8d6dbe973120ef7ee", size = 79791, upload-time = "2025-06-09T23:01:09.368Z" }, - { url = "https://files.pythonhosted.org/packages/83/2e/5b70b6a3325363293fe5fc3ae74cdcbc3e996c2a11dde2fd9f1fb0776d19/frozenlist-1.7.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:d1a81c85417b914139e3a9b995d4a1c84559afc839a93cf2cb7f15e6e5f6ed2d", size = 47165, upload-time = "2025-06-09T23:01:10.653Z" }, - { url = "https://files.pythonhosted.org/packages/f4/25/a0895c99270ca6966110f4ad98e87e5662eab416a17e7fd53c364bf8b954/frozenlist-1.7.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:cbb65198a9132ebc334f237d7b0df163e4de83fb4f2bdfe46c1e654bdb0c5d43", size = 45881, upload-time = "2025-06-09T23:01:12.296Z" }, - { url = "https://files.pythonhosted.org/packages/19/7c/71bb0bbe0832793c601fff68cd0cf6143753d0c667f9aec93d3c323f4b55/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:dab46c723eeb2c255a64f9dc05b8dd601fde66d6b19cdb82b2e09cc6ff8d8b5d", size = 232409, upload-time = "2025-06-09T23:01:13.641Z" }, - { url = "https://files.pythonhosted.org/packages/c0/45/ed2798718910fe6eb3ba574082aaceff4528e6323f9a8570be0f7028d8e9/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6aeac207a759d0dedd2e40745575ae32ab30926ff4fa49b1635def65806fddee", size = 225132, upload-time = "2025-06-09T23:01:15.264Z" }, - { url = "https://files.pythonhosted.org/packages/ba/e2/8417ae0f8eacb1d071d4950f32f229aa6bf68ab69aab797b72a07ea68d4f/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bd8c4e58ad14b4fa7802b8be49d47993182fdd4023393899632c88fd8cd994eb", size = 237638, upload-time = "2025-06-09T23:01:16.752Z" }, - { url = "https://files.pythonhosted.org/packages/f8/b7/2ace5450ce85f2af05a871b8c8719b341294775a0a6c5585d5e6170f2ce7/frozenlist-1.7.0-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:04fb24d104f425da3540ed83cbfc31388a586a7696142004c577fa61c6298c3f", size = 233539, upload-time = "2025-06-09T23:01:18.202Z" }, - { url = "https://files.pythonhosted.org/packages/46/b9/6989292c5539553dba63f3c83dc4598186ab2888f67c0dc1d917e6887db6/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a5c505156368e4ea6b53b5ac23c92d7edc864537ff911d2fb24c140bb175e60", size = 215646, upload-time = "2025-06-09T23:01:19.649Z" }, - { url = "https://files.pythonhosted.org/packages/72/31/bc8c5c99c7818293458fe745dab4fd5730ff49697ccc82b554eb69f16a24/frozenlist-1.7.0-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8bd7eb96a675f18aa5c553eb7ddc24a43c8c18f22e1f9925528128c052cdbe00", size = 232233, upload-time = "2025-06-09T23:01:21.175Z" }, - { url = "https://files.pythonhosted.org/packages/59/52/460db4d7ba0811b9ccb85af996019f5d70831f2f5f255f7cc61f86199795/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:05579bf020096fe05a764f1f84cd104a12f78eaab68842d036772dc6d4870b4b", size = 227996, upload-time = "2025-06-09T23:01:23.098Z" }, - { url = "https://files.pythonhosted.org/packages/ba/c9/f4b39e904c03927b7ecf891804fd3b4df3db29b9e487c6418e37988d6e9d/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:376b6222d114e97eeec13d46c486facd41d4f43bab626b7c3f6a8b4e81a5192c", size = 242280, upload-time = "2025-06-09T23:01:24.808Z" }, - { url = "https://files.pythonhosted.org/packages/b8/33/3f8d6ced42f162d743e3517781566b8481322be321b486d9d262adf70bfb/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:0aa7e176ebe115379b5b1c95b4096fb1c17cce0847402e227e712c27bdb5a949", size = 217717, upload-time = "2025-06-09T23:01:26.28Z" }, - { url = "https://files.pythonhosted.org/packages/3e/e8/ad683e75da6ccef50d0ab0c2b2324b32f84fc88ceee778ed79b8e2d2fe2e/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3fbba20e662b9c2130dc771e332a99eff5da078b2b2648153a40669a6d0e36ca", size = 236644, upload-time = "2025-06-09T23:01:27.887Z" }, - { url = "https://files.pythonhosted.org/packages/b2/14/8d19ccdd3799310722195a72ac94ddc677541fb4bef4091d8e7775752360/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:f3f4410a0a601d349dd406b5713fec59b4cee7e71678d5b17edda7f4655a940b", size = 238879, upload-time = "2025-06-09T23:01:29.524Z" }, - { url = "https://files.pythonhosted.org/packages/ce/13/c12bf657494c2fd1079a48b2db49fa4196325909249a52d8f09bc9123fd7/frozenlist-1.7.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:e2cdfaaec6a2f9327bf43c933c0319a7c429058e8537c508964a133dffee412e", size = 232502, upload-time = "2025-06-09T23:01:31.287Z" }, - { url = "https://files.pythonhosted.org/packages/d7/8b/e7f9dfde869825489382bc0d512c15e96d3964180c9499efcec72e85db7e/frozenlist-1.7.0-cp313-cp313-win32.whl", hash = "sha256:5fc4df05a6591c7768459caba1b342d9ec23fa16195e744939ba5914596ae3e1", size = 39169, upload-time = "2025-06-09T23:01:35.503Z" }, - { url = "https://files.pythonhosted.org/packages/35/89/a487a98d94205d85745080a37860ff5744b9820a2c9acbcdd9440bfddf98/frozenlist-1.7.0-cp313-cp313-win_amd64.whl", hash = "sha256:52109052b9791a3e6b5d1b65f4b909703984b770694d3eb64fad124c835d7cba", size = 43219, upload-time = "2025-06-09T23:01:36.784Z" }, - { url = "https://files.pythonhosted.org/packages/56/d5/5c4cf2319a49eddd9dd7145e66c4866bdc6f3dbc67ca3d59685149c11e0d/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:a6f86e4193bb0e235ef6ce3dde5cbabed887e0b11f516ce8a0f4d3b33078ec2d", size = 84345, upload-time = "2025-06-09T23:01:38.295Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7d/ec2c1e1dc16b85bc9d526009961953df9cec8481b6886debb36ec9107799/frozenlist-1.7.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:82d664628865abeb32d90ae497fb93df398a69bb3434463d172b80fc25b0dd7d", size = 48880, upload-time = "2025-06-09T23:01:39.887Z" }, - { url = "https://files.pythonhosted.org/packages/69/86/f9596807b03de126e11e7d42ac91e3d0b19a6599c714a1989a4e85eeefc4/frozenlist-1.7.0-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:912a7e8375a1c9a68325a902f3953191b7b292aa3c3fb0d71a216221deca460b", size = 48498, upload-time = "2025-06-09T23:01:41.318Z" }, - { url = "https://files.pythonhosted.org/packages/5e/cb/df6de220f5036001005f2d726b789b2c0b65f2363b104bbc16f5be8084f8/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9537c2777167488d539bc5de2ad262efc44388230e5118868e172dd4a552b146", size = 292296, upload-time = "2025-06-09T23:01:42.685Z" }, - { url = "https://files.pythonhosted.org/packages/83/1f/de84c642f17c8f851a2905cee2dae401e5e0daca9b5ef121e120e19aa825/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:f34560fb1b4c3e30ba35fa9a13894ba39e5acfc5f60f57d8accde65f46cc5e74", size = 273103, upload-time = "2025-06-09T23:01:44.166Z" }, - { url = "https://files.pythonhosted.org/packages/88/3c/c840bfa474ba3fa13c772b93070893c6e9d5c0350885760376cbe3b6c1b3/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:acd03d224b0175f5a850edc104ac19040d35419eddad04e7cf2d5986d98427f1", size = 292869, upload-time = "2025-06-09T23:01:45.681Z" }, - { url = "https://files.pythonhosted.org/packages/a6/1c/3efa6e7d5a39a1d5ef0abeb51c48fb657765794a46cf124e5aca2c7a592c/frozenlist-1.7.0-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2038310bc582f3d6a09b3816ab01737d60bf7b1ec70f5356b09e84fb7408ab1", size = 291467, upload-time = "2025-06-09T23:01:47.234Z" }, - { url = "https://files.pythonhosted.org/packages/4f/00/d5c5e09d4922c395e2f2f6b79b9a20dab4b67daaf78ab92e7729341f61f6/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b8c05e4c8e5f36e5e088caa1bf78a687528f83c043706640a92cb76cd6999384", size = 266028, upload-time = "2025-06-09T23:01:48.819Z" }, - { url = "https://files.pythonhosted.org/packages/4e/27/72765be905619dfde25a7f33813ac0341eb6b076abede17a2e3fbfade0cb/frozenlist-1.7.0-cp313-cp313t-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:765bb588c86e47d0b68f23c1bee323d4b703218037765dcf3f25c838c6fecceb", size = 284294, upload-time = "2025-06-09T23:01:50.394Z" }, - { url = "https://files.pythonhosted.org/packages/88/67/c94103a23001b17808eb7dd1200c156bb69fb68e63fcf0693dde4cd6228c/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:32dc2e08c67d86d0969714dd484fd60ff08ff81d1a1e40a77dd34a387e6ebc0c", size = 281898, upload-time = "2025-06-09T23:01:52.234Z" }, - { url = "https://files.pythonhosted.org/packages/42/34/a3e2c00c00f9e2a9db5653bca3fec306349e71aff14ae45ecc6d0951dd24/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:c0303e597eb5a5321b4de9c68e9845ac8f290d2ab3f3e2c864437d3c5a30cd65", size = 290465, upload-time = "2025-06-09T23:01:53.788Z" }, - { url = "https://files.pythonhosted.org/packages/bb/73/f89b7fbce8b0b0c095d82b008afd0590f71ccb3dee6eee41791cf8cd25fd/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a47f2abb4e29b3a8d0b530f7c3598badc6b134562b1a5caee867f7c62fee51e3", size = 266385, upload-time = "2025-06-09T23:01:55.769Z" }, - { url = "https://files.pythonhosted.org/packages/cd/45/e365fdb554159462ca12df54bc59bfa7a9a273ecc21e99e72e597564d1ae/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:3d688126c242a6fabbd92e02633414d40f50bb6002fa4cf995a1d18051525657", size = 288771, upload-time = "2025-06-09T23:01:57.4Z" }, - { url = "https://files.pythonhosted.org/packages/00/11/47b6117002a0e904f004d70ec5194fe9144f117c33c851e3d51c765962d0/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:4e7e9652b3d367c7bd449a727dc79d5043f48b88d0cbfd4f9f1060cf2b414104", size = 288206, upload-time = "2025-06-09T23:01:58.936Z" }, - { url = "https://files.pythonhosted.org/packages/40/37/5f9f3c3fd7f7746082ec67bcdc204db72dad081f4f83a503d33220a92973/frozenlist-1.7.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:1a85e345b4c43db8b842cab1feb41be5cc0b10a1830e6295b69d7310f99becaf", size = 282620, upload-time = "2025-06-09T23:02:00.493Z" }, - { url = "https://files.pythonhosted.org/packages/0b/31/8fbc5af2d183bff20f21aa743b4088eac4445d2bb1cdece449ae80e4e2d1/frozenlist-1.7.0-cp313-cp313t-win32.whl", hash = "sha256:3a14027124ddb70dfcee5148979998066897e79f89f64b13328595c4bdf77c81", size = 43059, upload-time = "2025-06-09T23:02:02.072Z" }, - { url = "https://files.pythonhosted.org/packages/bb/ed/41956f52105b8dbc26e457c5705340c67c8cc2b79f394b79bffc09d0e938/frozenlist-1.7.0-cp313-cp313t-win_amd64.whl", hash = "sha256:3bf8010d71d4507775f658e9823210b7427be36625b387221642725b515dcf3e", size = 47516, upload-time = "2025-06-09T23:02:03.779Z" }, - { url = "https://files.pythonhosted.org/packages/ee/45/b82e3c16be2182bff01179db177fe144d58b5dc787a7d4492c6ed8b9317f/frozenlist-1.7.0-py3-none-any.whl", hash = "sha256:9a5af342e34f7e97caf8c995864c7a396418ae2859cc6fdf1b1073020d516a7e", size = 13106, upload-time = "2025-06-09T23:02:34.204Z" }, -] - -[[package]] -name = "h11" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/01/ee/02a2c011bdab74c6fb3c75474d40b3052059d95df7e73351460c8588d963/h11-0.16.0.tar.gz", hash = "sha256:4e35b956cf45792e4caa5885e69fba00bdbc6ffafbfa020300e549b208ee5ff1", size = 101250, upload-time = "2025-04-24T03:35:25.427Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, -] - -[[package]] -name = "hexbytes" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7f/87/adf4635b4b8c050283d74e6db9a81496063229c9263e6acc1903ab79fbec/hexbytes-1.3.1.tar.gz", hash = "sha256:a657eebebdfe27254336f98d8af6e2236f3f83aed164b87466b6cf6c5f5a4765", size = 8633, upload-time = "2025-05-14T16:45:17.5Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8d/e0/3b31492b1c89da3c5a846680517871455b30c54738486fc57ac79a5761bd/hexbytes-1.3.1-py3-none-any.whl", hash = "sha256:da01ff24a1a9a2b1881c4b85f0e9f9b0f51b526b379ffa23832ae7899d29c2c7", size = 5074, upload-time = "2025-05-14T16:45:16.179Z" }, -] - -[[package]] -name = "httpcore" -version = "1.0.9" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "h11" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/06/94/82699a10bca87a5556c9c59b5963f2d039dbd239f25bc2a63907a05a14cb/httpcore-1.0.9.tar.gz", hash = "sha256:6e34463af53fd2ab5d807f399a9b45ea31c3dfa2276f15a2c3f00afff6e176e8", size = 85484, upload-time = "2025-04-24T22:06:22.219Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7e/f5/f66802a942d491edb555dd61e3a9961140fd64c90bce1eafd741609d334d/httpcore-1.0.9-py3-none-any.whl", hash = "sha256:2d400746a40668fc9dec9810239072b40b4484b640a8c38fd654a024c7a1bf55", size = 78784, upload-time = "2025-04-24T22:06:20.566Z" }, -] - -[[package]] -name = "httptools" -version = "0.6.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a7/9a/ce5e1f7e131522e6d3426e8e7a490b3a01f39a6696602e1c4f33f9e94277/httptools-0.6.4.tar.gz", hash = "sha256:4e93eee4add6493b59a5c514da98c939b244fce4a0d8879cd3f466562f4b7d5c", size = 240639, upload-time = "2024-10-16T19:45:08.902Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3b/6f/972f8eb0ea7d98a1c6be436e2142d51ad2a64ee18e02b0e7ff1f62171ab1/httptools-0.6.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:3c73ce323711a6ffb0d247dcd5a550b8babf0f757e86a52558fe5b86d6fefcc0", size = 198780, upload-time = "2024-10-16T19:44:06.882Z" }, - { url = "https://files.pythonhosted.org/packages/6a/b0/17c672b4bc5c7ba7f201eada4e96c71d0a59fbc185e60e42580093a86f21/httptools-0.6.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:345c288418f0944a6fe67be8e6afa9262b18c7626c3ef3c28adc5eabc06a68da", size = 103297, upload-time = "2024-10-16T19:44:08.129Z" }, - { url = "https://files.pythonhosted.org/packages/92/5e/b4a826fe91971a0b68e8c2bd4e7db3e7519882f5a8ccdb1194be2b3ab98f/httptools-0.6.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:deee0e3343f98ee8047e9f4c5bc7cedbf69f5734454a94c38ee829fb2d5fa3c1", size = 443130, upload-time = "2024-10-16T19:44:09.45Z" }, - { url = "https://files.pythonhosted.org/packages/b0/51/ce61e531e40289a681a463e1258fa1e05e0be54540e40d91d065a264cd8f/httptools-0.6.4-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ca80b7485c76f768a3bc83ea58373f8db7b015551117375e4918e2aa77ea9b50", size = 442148, upload-time = "2024-10-16T19:44:11.539Z" }, - { url = "https://files.pythonhosted.org/packages/ea/9e/270b7d767849b0c96f275c695d27ca76c30671f8eb8cc1bab6ced5c5e1d0/httptools-0.6.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:90d96a385fa941283ebd231464045187a31ad932ebfa541be8edf5b3c2328959", size = 415949, upload-time = "2024-10-16T19:44:13.388Z" }, - { url = "https://files.pythonhosted.org/packages/81/86/ced96e3179c48c6f656354e106934e65c8963d48b69be78f355797f0e1b3/httptools-0.6.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:59e724f8b332319e2875efd360e61ac07f33b492889284a3e05e6d13746876f4", size = 417591, upload-time = "2024-10-16T19:44:15.258Z" }, - { url = "https://files.pythonhosted.org/packages/75/73/187a3f620ed3175364ddb56847d7a608a6fc42d551e133197098c0143eca/httptools-0.6.4-cp310-cp310-win_amd64.whl", hash = "sha256:c26f313951f6e26147833fc923f78f95604bbec812a43e5ee37f26dc9e5a686c", size = 88344, upload-time = "2024-10-16T19:44:16.54Z" }, - { url = "https://files.pythonhosted.org/packages/7b/26/bb526d4d14c2774fe07113ca1db7255737ffbb119315839af2065abfdac3/httptools-0.6.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:f47f8ed67cc0ff862b84a1189831d1d33c963fb3ce1ee0c65d3b0cbe7b711069", size = 199029, upload-time = "2024-10-16T19:44:18.427Z" }, - { url = "https://files.pythonhosted.org/packages/a6/17/3e0d3e9b901c732987a45f4f94d4e2c62b89a041d93db89eafb262afd8d5/httptools-0.6.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:0614154d5454c21b6410fdf5262b4a3ddb0f53f1e1721cfd59d55f32138c578a", size = 103492, upload-time = "2024-10-16T19:44:19.515Z" }, - { url = "https://files.pythonhosted.org/packages/b7/24/0fe235d7b69c42423c7698d086d4db96475f9b50b6ad26a718ef27a0bce6/httptools-0.6.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f8787367fbdfccae38e35abf7641dafc5310310a5987b689f4c32cc8cc3ee975", size = 462891, upload-time = "2024-10-16T19:44:21.067Z" }, - { url = "https://files.pythonhosted.org/packages/b1/2f/205d1f2a190b72da6ffb5f41a3736c26d6fa7871101212b15e9b5cd8f61d/httptools-0.6.4-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40b0f7fe4fd38e6a507bdb751db0379df1e99120c65fbdc8ee6c1d044897a636", size = 459788, upload-time = "2024-10-16T19:44:22.958Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4c/d09ce0eff09057a206a74575ae8f1e1e2f0364d20e2442224f9e6612c8b9/httptools-0.6.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:40a5ec98d3f49904b9fe36827dcf1aadfef3b89e2bd05b0e35e94f97c2b14721", size = 433214, upload-time = "2024-10-16T19:44:24.513Z" }, - { url = "https://files.pythonhosted.org/packages/3e/d2/84c9e23edbccc4a4c6f96a1b8d99dfd2350289e94f00e9ccc7aadde26fb5/httptools-0.6.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:dacdd3d10ea1b4ca9df97a0a303cbacafc04b5cd375fa98732678151643d4988", size = 434120, upload-time = "2024-10-16T19:44:26.295Z" }, - { url = "https://files.pythonhosted.org/packages/d0/46/4d8e7ba9581416de1c425b8264e2cadd201eb709ec1584c381f3e98f51c1/httptools-0.6.4-cp311-cp311-win_amd64.whl", hash = "sha256:288cd628406cc53f9a541cfaf06041b4c71d751856bab45e3702191f931ccd17", size = 88565, upload-time = "2024-10-16T19:44:29.188Z" }, - { url = "https://files.pythonhosted.org/packages/bb/0e/d0b71465c66b9185f90a091ab36389a7352985fe857e352801c39d6127c8/httptools-0.6.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:df017d6c780287d5c80601dafa31f17bddb170232d85c066604d8558683711a2", size = 200683, upload-time = "2024-10-16T19:44:30.175Z" }, - { url = "https://files.pythonhosted.org/packages/e2/b8/412a9bb28d0a8988de3296e01efa0bd62068b33856cdda47fe1b5e890954/httptools-0.6.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:85071a1e8c2d051b507161f6c3e26155b5c790e4e28d7f236422dbacc2a9cc44", size = 104337, upload-time = "2024-10-16T19:44:31.786Z" }, - { url = "https://files.pythonhosted.org/packages/9b/01/6fb20be3196ffdc8eeec4e653bc2a275eca7f36634c86302242c4fbb2760/httptools-0.6.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69422b7f458c5af875922cdb5bd586cc1f1033295aa9ff63ee196a87519ac8e1", size = 508796, upload-time = "2024-10-16T19:44:32.825Z" }, - { url = "https://files.pythonhosted.org/packages/f7/d8/b644c44acc1368938317d76ac991c9bba1166311880bcc0ac297cb9d6bd7/httptools-0.6.4-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:16e603a3bff50db08cd578d54f07032ca1631450ceb972c2f834c2b860c28ea2", size = 510837, upload-time = "2024-10-16T19:44:33.974Z" }, - { url = "https://files.pythonhosted.org/packages/52/d8/254d16a31d543073a0e57f1c329ca7378d8924e7e292eda72d0064987486/httptools-0.6.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ec4f178901fa1834d4a060320d2f3abc5c9e39766953d038f1458cb885f47e81", size = 485289, upload-time = "2024-10-16T19:44:35.111Z" }, - { url = "https://files.pythonhosted.org/packages/5f/3c/4aee161b4b7a971660b8be71a92c24d6c64372c1ab3ae7f366b3680df20f/httptools-0.6.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:f9eb89ecf8b290f2e293325c646a211ff1c2493222798bb80a530c5e7502494f", size = 489779, upload-time = "2024-10-16T19:44:36.253Z" }, - { url = "https://files.pythonhosted.org/packages/12/b7/5cae71a8868e555f3f67a50ee7f673ce36eac970f029c0c5e9d584352961/httptools-0.6.4-cp312-cp312-win_amd64.whl", hash = "sha256:db78cb9ca56b59b016e64b6031eda5653be0589dba2b1b43453f6e8b405a0970", size = 88634, upload-time = "2024-10-16T19:44:37.357Z" }, - { url = "https://files.pythonhosted.org/packages/94/a3/9fe9ad23fd35f7de6b91eeb60848986058bd8b5a5c1e256f5860a160cc3e/httptools-0.6.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ade273d7e767d5fae13fa637f4d53b6e961fb7fd93c7797562663f0171c26660", size = 197214, upload-time = "2024-10-16T19:44:38.738Z" }, - { url = "https://files.pythonhosted.org/packages/ea/d9/82d5e68bab783b632023f2fa31db20bebb4e89dfc4d2293945fd68484ee4/httptools-0.6.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:856f4bc0478ae143bad54a4242fccb1f3f86a6e1be5548fecfd4102061b3a083", size = 102431, upload-time = "2024-10-16T19:44:39.818Z" }, - { url = "https://files.pythonhosted.org/packages/96/c1/cb499655cbdbfb57b577734fde02f6fa0bbc3fe9fb4d87b742b512908dff/httptools-0.6.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:322d20ea9cdd1fa98bd6a74b77e2ec5b818abdc3d36695ab402a0de8ef2865a3", size = 473121, upload-time = "2024-10-16T19:44:41.189Z" }, - { url = "https://files.pythonhosted.org/packages/af/71/ee32fd358f8a3bb199b03261f10921716990808a675d8160b5383487a317/httptools-0.6.4-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4d87b29bd4486c0093fc64dea80231f7c7f7eb4dc70ae394d70a495ab8436071", size = 473805, upload-time = "2024-10-16T19:44:42.384Z" }, - { url = "https://files.pythonhosted.org/packages/8a/0a/0d4df132bfca1507114198b766f1737d57580c9ad1cf93c1ff673e3387be/httptools-0.6.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:342dd6946aa6bda4b8f18c734576106b8a31f2fe31492881a9a160ec84ff4bd5", size = 448858, upload-time = "2024-10-16T19:44:43.959Z" }, - { url = "https://files.pythonhosted.org/packages/1e/6a/787004fdef2cabea27bad1073bf6a33f2437b4dbd3b6fb4a9d71172b1c7c/httptools-0.6.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4b36913ba52008249223042dca46e69967985fb4051951f94357ea681e1f5dc0", size = 452042, upload-time = "2024-10-16T19:44:45.071Z" }, - { url = "https://files.pythonhosted.org/packages/4d/dc/7decab5c404d1d2cdc1bb330b1bf70e83d6af0396fd4fc76fc60c0d522bf/httptools-0.6.4-cp313-cp313-win_amd64.whl", hash = "sha256:28908df1b9bb8187393d5b5db91435ccc9c8e891657f9cbb42a2541b44c82fc8", size = 87682, upload-time = "2024-10-16T19:44:46.46Z" }, -] - -[[package]] -name = "httpx" -version = "0.28.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, - { name = "certifi" }, - { name = "httpcore" }, - { name = "idna" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/b1/df/48c586a5fe32a0f01324ee087459e112ebb7224f646c0b5023f5e79e9956/httpx-0.28.1.tar.gz", hash = "sha256:75e98c5f16b0f35b567856f597f06ff2270a374470a5c2392242528e3e3e42fc", size = 141406, upload-time = "2024-12-06T15:37:23.222Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, -] - -[[package]] -name = "idna" -version = "3.10" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f1/70/7703c29685631f5a7590aa73f1f1d3fa9a380e654b86af429e0934a32f7d/idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9", size = 190490, upload-time = "2024-09-15T18:07:39.745Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/c6/c88e154df9c4e1a2a66ccf0005a88dfb2650c1dffb6f5ce603dfbd452ce3/idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3", size = 70442, upload-time = "2024-09-15T18:07:37.964Z" }, -] - -[[package]] -name = "itsdangerous" -version = "2.2.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/9c/cb/8ac0172223afbccb63986cc25049b154ecfb5e85932587206f42317be31d/itsdangerous-2.2.0.tar.gz", hash = "sha256:e0050c0b7da1eea53ffaf149c0cfbb5c6e2e2b69c4bef22c81fa6eb73e5f6173", size = 54410, upload-time = "2024-04-16T21:28:15.614Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/96/92447566d16df59b2a776c0fb82dbc4d9e07cd95062562af01e408583fc4/itsdangerous-2.2.0-py3-none-any.whl", hash = "sha256:c6242fc49e35958c8b15141343aa660db5fc54d4f13a1db01a3f5891b98700ef", size = 16234, upload-time = "2024-04-16T21:28:14.499Z" }, -] - -[[package]] -name = "jinja2" -version = "3.1.6" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/df/bf/f7da0350254c0ed7c72f3e33cef02e048281fec7ecec5f032d4aac52226b/jinja2-3.1.6.tar.gz", hash = "sha256:0137fb05990d35f1275a587e9aee6d56da821fc83491a0fb838183be43f66d6d", size = 245115, upload-time = "2025-03-05T20:05:02.478Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/62/a1/3d680cbfd5f4b8f15abc1d571870c5fc3e594bb582bc3b64ea099db13e56/jinja2-3.1.6-py3-none-any.whl", hash = "sha256:85ece4451f492d0c13c5dd7c13a64681a86afae63a5f347908daf103ce6d2f67", size = 134899, upload-time = "2025-03-05T20:05:00.369Z" }, -] - -[[package]] -name = "markdown-it-py" -version = "3.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "mdurl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/38/71/3b932df36c1a044d397a1f92d1cf91ee0a503d91e470cbd670aa66b07ed0/markdown-it-py-3.0.0.tar.gz", hash = "sha256:e3f60a94fa066dc52ec76661e37c851cb232d92f9886b15cb560aaada2df8feb", size = 74596, upload-time = "2023-06-03T06:41:14.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/42/d7/1ec15b46af6af88f19b8e5ffea08fa375d433c998b8a7639e76935c14f1f/markdown_it_py-3.0.0-py3-none-any.whl", hash = "sha256:355216845c60bd96232cd8d8c40e8f9765cc86f46880e43a8fd22dc1a1a8cab1", size = 87528, upload-time = "2023-06-03T06:41:11.019Z" }, -] - -[[package]] -name = "markupsafe" -version = "3.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b2/97/5d42485e71dfc078108a86d6de8fa46db44a1a9295e89c5d6d4a06e23a62/markupsafe-3.0.2.tar.gz", hash = "sha256:ee55d3edf80167e48ea11a923c7386f4669df67d7994554387f84e7d8b0a2bf0", size = 20537, upload-time = "2024-10-18T15:21:54.129Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/90/d08277ce111dd22f77149fd1a5d4653eeb3b3eaacbdfcbae5afb2600eebd/MarkupSafe-3.0.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:7e94c425039cde14257288fd61dcfb01963e658efbc0ff54f5306b06054700f8", size = 14357, upload-time = "2024-10-18T15:20:51.44Z" }, - { url = "https://files.pythonhosted.org/packages/04/e1/6e2194baeae0bca1fae6629dc0cbbb968d4d941469cbab11a3872edff374/MarkupSafe-3.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:9e2d922824181480953426608b81967de705c3cef4d1af983af849d7bd619158", size = 12393, upload-time = "2024-10-18T15:20:52.426Z" }, - { url = "https://files.pythonhosted.org/packages/1d/69/35fa85a8ece0a437493dc61ce0bb6d459dcba482c34197e3efc829aa357f/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:38a9ef736c01fccdd6600705b09dc574584b89bea478200c5fbf112a6b0d5579", size = 21732, upload-time = "2024-10-18T15:20:53.578Z" }, - { url = "https://files.pythonhosted.org/packages/22/35/137da042dfb4720b638d2937c38a9c2df83fe32d20e8c8f3185dbfef05f7/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bbcb445fa71794da8f178f0f6d66789a28d7319071af7a496d4d507ed566270d", size = 20866, upload-time = "2024-10-18T15:20:55.06Z" }, - { url = "https://files.pythonhosted.org/packages/29/28/6d029a903727a1b62edb51863232152fd335d602def598dade38996887f0/MarkupSafe-3.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:57cb5a3cf367aeb1d316576250f65edec5bb3be939e9247ae594b4bcbc317dfb", size = 20964, upload-time = "2024-10-18T15:20:55.906Z" }, - { url = "https://files.pythonhosted.org/packages/cc/cd/07438f95f83e8bc028279909d9c9bd39e24149b0d60053a97b2bc4f8aa51/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:3809ede931876f5b2ec92eef964286840ed3540dadf803dd570c3b7e13141a3b", size = 21977, upload-time = "2024-10-18T15:20:57.189Z" }, - { url = "https://files.pythonhosted.org/packages/29/01/84b57395b4cc062f9c4c55ce0df7d3108ca32397299d9df00fedd9117d3d/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e07c3764494e3776c602c1e78e298937c3315ccc9043ead7e685b7f2b8d47b3c", size = 21366, upload-time = "2024-10-18T15:20:58.235Z" }, - { url = "https://files.pythonhosted.org/packages/bd/6e/61ebf08d8940553afff20d1fb1ba7294b6f8d279df9fd0c0db911b4bbcfd/MarkupSafe-3.0.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:b424c77b206d63d500bcb69fa55ed8d0e6a3774056bdc4839fc9298a7edca171", size = 21091, upload-time = "2024-10-18T15:20:59.235Z" }, - { url = "https://files.pythonhosted.org/packages/11/23/ffbf53694e8c94ebd1e7e491de185124277964344733c45481f32ede2499/MarkupSafe-3.0.2-cp310-cp310-win32.whl", hash = "sha256:fcabf5ff6eea076f859677f5f0b6b5c1a51e70a376b0579e0eadef8db48c6b50", size = 15065, upload-time = "2024-10-18T15:21:00.307Z" }, - { url = "https://files.pythonhosted.org/packages/44/06/e7175d06dd6e9172d4a69a72592cb3f7a996a9c396eee29082826449bbc3/MarkupSafe-3.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:6af100e168aa82a50e186c82875a5893c5597a0c1ccdb0d8b40240b1f28b969a", size = 15514, upload-time = "2024-10-18T15:21:01.122Z" }, - { url = "https://files.pythonhosted.org/packages/6b/28/bbf83e3f76936960b850435576dd5e67034e200469571be53f69174a2dfd/MarkupSafe-3.0.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:9025b4018f3a1314059769c7bf15441064b2207cb3f065e6ea1e7359cb46db9d", size = 14353, upload-time = "2024-10-18T15:21:02.187Z" }, - { url = "https://files.pythonhosted.org/packages/6c/30/316d194b093cde57d448a4c3209f22e3046c5bb2fb0820b118292b334be7/MarkupSafe-3.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:93335ca3812df2f366e80509ae119189886b0f3c2b81325d39efdb84a1e2ae93", size = 12392, upload-time = "2024-10-18T15:21:02.941Z" }, - { url = "https://files.pythonhosted.org/packages/f2/96/9cdafba8445d3a53cae530aaf83c38ec64c4d5427d975c974084af5bc5d2/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cb8438c3cbb25e220c2ab33bb226559e7afb3baec11c4f218ffa7308603c832", size = 23984, upload-time = "2024-10-18T15:21:03.953Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a4/aefb044a2cd8d7334c8a47d3fb2c9f328ac48cb349468cc31c20b539305f/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a123e330ef0853c6e822384873bef7507557d8e4a082961e1defa947aa59ba84", size = 23120, upload-time = "2024-10-18T15:21:06.495Z" }, - { url = "https://files.pythonhosted.org/packages/8d/21/5e4851379f88f3fad1de30361db501300d4f07bcad047d3cb0449fc51f8c/MarkupSafe-3.0.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e084f686b92e5b83186b07e8a17fc09e38fff551f3602b249881fec658d3eca", size = 23032, upload-time = "2024-10-18T15:21:07.295Z" }, - { url = "https://files.pythonhosted.org/packages/00/7b/e92c64e079b2d0d7ddf69899c98842f3f9a60a1ae72657c89ce2655c999d/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:d8213e09c917a951de9d09ecee036d5c7d36cb6cb7dbaece4c71a60d79fb9798", size = 24057, upload-time = "2024-10-18T15:21:08.073Z" }, - { url = "https://files.pythonhosted.org/packages/f9/ac/46f960ca323037caa0a10662ef97d0a4728e890334fc156b9f9e52bcc4ca/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5b02fb34468b6aaa40dfc198d813a641e3a63b98c2b05a16b9f80b7ec314185e", size = 23359, upload-time = "2024-10-18T15:21:09.318Z" }, - { url = "https://files.pythonhosted.org/packages/69/84/83439e16197337b8b14b6a5b9c2105fff81d42c2a7c5b58ac7b62ee2c3b1/MarkupSafe-3.0.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:0bff5e0ae4ef2e1ae4fdf2dfd5b76c75e5c2fa4132d05fc1b0dabcd20c7e28c4", size = 23306, upload-time = "2024-10-18T15:21:10.185Z" }, - { url = "https://files.pythonhosted.org/packages/9a/34/a15aa69f01e2181ed8d2b685c0d2f6655d5cca2c4db0ddea775e631918cd/MarkupSafe-3.0.2-cp311-cp311-win32.whl", hash = "sha256:6c89876f41da747c8d3677a2b540fb32ef5715f97b66eeb0c6b66f5e3ef6f59d", size = 15094, upload-time = "2024-10-18T15:21:11.005Z" }, - { url = "https://files.pythonhosted.org/packages/da/b8/3a3bd761922d416f3dc5d00bfbed11f66b1ab89a0c2b6e887240a30b0f6b/MarkupSafe-3.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:70a87b411535ccad5ef2f1df5136506a10775d267e197e4cf531ced10537bd6b", size = 15521, upload-time = "2024-10-18T15:21:12.911Z" }, - { url = "https://files.pythonhosted.org/packages/22/09/d1f21434c97fc42f09d290cbb6350d44eb12f09cc62c9476effdb33a18aa/MarkupSafe-3.0.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:9778bd8ab0a994ebf6f84c2b949e65736d5575320a17ae8984a77fab08db94cf", size = 14274, upload-time = "2024-10-18T15:21:13.777Z" }, - { url = "https://files.pythonhosted.org/packages/6b/b0/18f76bba336fa5aecf79d45dcd6c806c280ec44538b3c13671d49099fdd0/MarkupSafe-3.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:846ade7b71e3536c4e56b386c2a47adf5741d2d8b94ec9dc3e92e5e1ee1e2225", size = 12348, upload-time = "2024-10-18T15:21:14.822Z" }, - { url = "https://files.pythonhosted.org/packages/e0/25/dd5c0f6ac1311e9b40f4af06c78efde0f3b5cbf02502f8ef9501294c425b/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1c99d261bd2d5f6b59325c92c73df481e05e57f19837bdca8413b9eac4bd8028", size = 24149, upload-time = "2024-10-18T15:21:15.642Z" }, - { url = "https://files.pythonhosted.org/packages/f3/f0/89e7aadfb3749d0f52234a0c8c7867877876e0a20b60e2188e9850794c17/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e17c96c14e19278594aa4841ec148115f9c7615a47382ecb6b82bd8fea3ab0c8", size = 23118, upload-time = "2024-10-18T15:21:17.133Z" }, - { url = "https://files.pythonhosted.org/packages/d5/da/f2eeb64c723f5e3777bc081da884b414671982008c47dcc1873d81f625b6/MarkupSafe-3.0.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:88416bd1e65dcea10bc7569faacb2c20ce071dd1f87539ca2ab364bf6231393c", size = 22993, upload-time = "2024-10-18T15:21:18.064Z" }, - { url = "https://files.pythonhosted.org/packages/da/0e/1f32af846df486dce7c227fe0f2398dc7e2e51d4a370508281f3c1c5cddc/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:2181e67807fc2fa785d0592dc2d6206c019b9502410671cc905d132a92866557", size = 24178, upload-time = "2024-10-18T15:21:18.859Z" }, - { url = "https://files.pythonhosted.org/packages/c4/f6/bb3ca0532de8086cbff5f06d137064c8410d10779c4c127e0e47d17c0b71/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:52305740fe773d09cffb16f8ed0427942901f00adedac82ec8b67752f58a1b22", size = 23319, upload-time = "2024-10-18T15:21:19.671Z" }, - { url = "https://files.pythonhosted.org/packages/a2/82/8be4c96ffee03c5b4a034e60a31294daf481e12c7c43ab8e34a1453ee48b/MarkupSafe-3.0.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:ad10d3ded218f1039f11a75f8091880239651b52e9bb592ca27de44eed242a48", size = 23352, upload-time = "2024-10-18T15:21:20.971Z" }, - { url = "https://files.pythonhosted.org/packages/51/ae/97827349d3fcffee7e184bdf7f41cd6b88d9919c80f0263ba7acd1bbcb18/MarkupSafe-3.0.2-cp312-cp312-win32.whl", hash = "sha256:0f4ca02bea9a23221c0182836703cbf8930c5e9454bacce27e767509fa286a30", size = 15097, upload-time = "2024-10-18T15:21:22.646Z" }, - { url = "https://files.pythonhosted.org/packages/c1/80/a61f99dc3a936413c3ee4e1eecac96c0da5ed07ad56fd975f1a9da5bc630/MarkupSafe-3.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:8e06879fc22a25ca47312fbe7c8264eb0b662f6db27cb2d3bbbc74b1df4b9b87", size = 15601, upload-time = "2024-10-18T15:21:23.499Z" }, - { url = "https://files.pythonhosted.org/packages/83/0e/67eb10a7ecc77a0c2bbe2b0235765b98d164d81600746914bebada795e97/MarkupSafe-3.0.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ba9527cdd4c926ed0760bc301f6728ef34d841f405abf9d4f959c478421e4efd", size = 14274, upload-time = "2024-10-18T15:21:24.577Z" }, - { url = "https://files.pythonhosted.org/packages/2b/6d/9409f3684d3335375d04e5f05744dfe7e9f120062c9857df4ab490a1031a/MarkupSafe-3.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f8b3d067f2e40fe93e1ccdd6b2e1d16c43140e76f02fb1319a05cf2b79d99430", size = 12352, upload-time = "2024-10-18T15:21:25.382Z" }, - { url = "https://files.pythonhosted.org/packages/d2/f5/6eadfcd3885ea85fe2a7c128315cc1bb7241e1987443d78c8fe712d03091/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:569511d3b58c8791ab4c2e1285575265991e6d8f8700c7be0e88f86cb0672094", size = 24122, upload-time = "2024-10-18T15:21:26.199Z" }, - { url = "https://files.pythonhosted.org/packages/0c/91/96cf928db8236f1bfab6ce15ad070dfdd02ed88261c2afafd4b43575e9e9/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:15ab75ef81add55874e7ab7055e9c397312385bd9ced94920f2802310c930396", size = 23085, upload-time = "2024-10-18T15:21:27.029Z" }, - { url = "https://files.pythonhosted.org/packages/c2/cf/c9d56af24d56ea04daae7ac0940232d31d5a8354f2b457c6d856b2057d69/MarkupSafe-3.0.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f3818cb119498c0678015754eba762e0d61e5b52d34c8b13d770f0719f7b1d79", size = 22978, upload-time = "2024-10-18T15:21:27.846Z" }, - { url = "https://files.pythonhosted.org/packages/2a/9f/8619835cd6a711d6272d62abb78c033bda638fdc54c4e7f4272cf1c0962b/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:cdb82a876c47801bb54a690c5ae105a46b392ac6099881cdfb9f6e95e4014c6a", size = 24208, upload-time = "2024-10-18T15:21:28.744Z" }, - { url = "https://files.pythonhosted.org/packages/f9/bf/176950a1792b2cd2102b8ffeb5133e1ed984547b75db47c25a67d3359f77/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:cabc348d87e913db6ab4aa100f01b08f481097838bdddf7c7a84b7575b7309ca", size = 23357, upload-time = "2024-10-18T15:21:29.545Z" }, - { url = "https://files.pythonhosted.org/packages/ce/4f/9a02c1d335caabe5c4efb90e1b6e8ee944aa245c1aaaab8e8a618987d816/MarkupSafe-3.0.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:444dcda765c8a838eaae23112db52f1efaf750daddb2d9ca300bcae1039adc5c", size = 23344, upload-time = "2024-10-18T15:21:30.366Z" }, - { url = "https://files.pythonhosted.org/packages/ee/55/c271b57db36f748f0e04a759ace9f8f759ccf22b4960c270c78a394f58be/MarkupSafe-3.0.2-cp313-cp313-win32.whl", hash = "sha256:bcf3e58998965654fdaff38e58584d8937aa3096ab5354d493c77d1fdd66d7a1", size = 15101, upload-time = "2024-10-18T15:21:31.207Z" }, - { url = "https://files.pythonhosted.org/packages/29/88/07df22d2dd4df40aba9f3e402e6dc1b8ee86297dddbad4872bd5e7b0094f/MarkupSafe-3.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:e6a2a455bd412959b57a172ce6328d2dd1f01cb2135efda2e4576e8a23fa3b0f", size = 15603, upload-time = "2024-10-18T15:21:32.032Z" }, - { url = "https://files.pythonhosted.org/packages/62/6a/8b89d24db2d32d433dffcd6a8779159da109842434f1dd2f6e71f32f738c/MarkupSafe-3.0.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:b5a6b3ada725cea8a5e634536b1b01c30bcdcd7f9c6fff4151548d5bf6b3a36c", size = 14510, upload-time = "2024-10-18T15:21:33.625Z" }, - { url = "https://files.pythonhosted.org/packages/7a/06/a10f955f70a2e5a9bf78d11a161029d278eeacbd35ef806c3fd17b13060d/MarkupSafe-3.0.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:a904af0a6162c73e3edcb969eeeb53a63ceeb5d8cf642fade7d39e7963a22ddb", size = 12486, upload-time = "2024-10-18T15:21:34.611Z" }, - { url = "https://files.pythonhosted.org/packages/34/cf/65d4a571869a1a9078198ca28f39fba5fbb910f952f9dbc5220afff9f5e6/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4aa4e5faecf353ed117801a068ebab7b7e09ffb6e1d5e412dc852e0da018126c", size = 25480, upload-time = "2024-10-18T15:21:35.398Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e3/90e9651924c430b885468b56b3d597cabf6d72be4b24a0acd1fa0e12af67/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c0ef13eaeee5b615fb07c9a7dadb38eac06a0608b41570d8ade51c56539e509d", size = 23914, upload-time = "2024-10-18T15:21:36.231Z" }, - { url = "https://files.pythonhosted.org/packages/66/8c/6c7cf61f95d63bb866db39085150df1f2a5bd3335298f14a66b48e92659c/MarkupSafe-3.0.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d16a81a06776313e817c951135cf7340a3e91e8c1ff2fac444cfd75fffa04afe", size = 23796, upload-time = "2024-10-18T15:21:37.073Z" }, - { url = "https://files.pythonhosted.org/packages/bb/35/cbe9238ec3f47ac9a7c8b3df7a808e7cb50fe149dc7039f5f454b3fba218/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:6381026f158fdb7c72a168278597a5e3a5222e83ea18f543112b2662a9b699c5", size = 25473, upload-time = "2024-10-18T15:21:37.932Z" }, - { url = "https://files.pythonhosted.org/packages/e6/32/7621a4382488aa283cc05e8984a9c219abad3bca087be9ec77e89939ded9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:3d79d162e7be8f996986c064d1c7c817f6df3a77fe3d6859f6f9e7be4b8c213a", size = 24114, upload-time = "2024-10-18T15:21:39.799Z" }, - { url = "https://files.pythonhosted.org/packages/0d/80/0985960e4b89922cb5a0bac0ed39c5b96cbc1a536a99f30e8c220a996ed9/MarkupSafe-3.0.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:131a3c7689c85f5ad20f9f6fb1b866f402c445b220c19fe4308c0b147ccd2ad9", size = 24098, upload-time = "2024-10-18T15:21:40.813Z" }, - { url = "https://files.pythonhosted.org/packages/82/78/fedb03c7d5380df2427038ec8d973587e90561b2d90cd472ce9254cf348b/MarkupSafe-3.0.2-cp313-cp313t-win32.whl", hash = "sha256:ba8062ed2cf21c07a9e295d5b8a2a5ce678b913b45fdf68c32d95d6c1291e0b6", size = 15208, upload-time = "2024-10-18T15:21:41.814Z" }, - { url = "https://files.pythonhosted.org/packages/4f/65/6079a46068dfceaeabb5dcad6d674f5f5c61a6fa5673746f42a9f4c233b3/MarkupSafe-3.0.2-cp313-cp313t-win_amd64.whl", hash = "sha256:e444a31f8db13eb18ada366ab3cf45fd4b31e4db1236a4448f68778c1d1a5a2f", size = 15739, upload-time = "2024-10-18T15:21:42.784Z" }, -] - -[[package]] -name = "mdurl" -version = "0.1.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d6/54/cfe61301667036ec958cb99bd3efefba235e65cdeb9c84d24a8293ba1d90/mdurl-0.1.2.tar.gz", hash = "sha256:bb413d29f5eea38f31dd4754dd7377d4465116fb207585f97bf925588687c1ba", size = 8729, upload-time = "2022-08-14T12:40:10.846Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b3/38/89ba8ad64ae25be8de66a6d463314cf1eb366222074cfda9ee839c56a4b4/mdurl-0.1.2-py3-none-any.whl", hash = "sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8", size = 9979, upload-time = "2022-08-14T12:40:09.779Z" }, -] - -[[package]] -name = "multidict" -version = "6.4.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/91/2f/a3470242707058fe856fe59241eee5635d79087100b7042a867368863a27/multidict-6.4.4.tar.gz", hash = "sha256:69ee9e6ba214b5245031b76233dd95408a0fd57fdb019ddcc1ead4790932a8e8", size = 90183, upload-time = "2025-05-19T14:16:37.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1f/92/0926a5baafa164b5d0ade3cd7932be39310375d7e25c9d7ceca05cb26a45/multidict-6.4.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:8adee3ac041145ffe4488ea73fa0a622b464cc25340d98be76924d0cda8545ff", size = 66052, upload-time = "2025-05-19T14:13:49.944Z" }, - { url = "https://files.pythonhosted.org/packages/b2/54/8a857ae4f8f643ec444d91f419fdd49cc7a90a2ca0e42d86482b604b63bd/multidict-6.4.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:b61e98c3e2a861035aaccd207da585bdcacef65fe01d7a0d07478efac005e028", size = 38867, upload-time = "2025-05-19T14:13:51.92Z" }, - { url = "https://files.pythonhosted.org/packages/9e/5f/63add9069f945c19bc8b217ea6b0f8a1ad9382eab374bb44fae4354b3baf/multidict-6.4.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:75493f28dbadecdbb59130e74fe935288813301a8554dc32f0c631b6bdcdf8b0", size = 38138, upload-time = "2025-05-19T14:13:53.778Z" }, - { url = "https://files.pythonhosted.org/packages/97/8b/fbd9c0fc13966efdb4a47f5bcffff67a4f2a3189fbeead5766eaa4250b20/multidict-6.4.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4ffc3c6a37e048b5395ee235e4a2a0d639c2349dffa32d9367a42fc20d399772", size = 220433, upload-time = "2025-05-19T14:13:55.346Z" }, - { url = "https://files.pythonhosted.org/packages/a9/c4/5132b2d75b3ea2daedb14d10f91028f09f74f5b4d373b242c1b8eec47571/multidict-6.4.4-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:87cb72263946b301570b0f63855569a24ee8758aaae2cd182aae7d95fbc92ca7", size = 218059, upload-time = "2025-05-19T14:13:56.993Z" }, - { url = "https://files.pythonhosted.org/packages/1a/70/f1e818c7a29b908e2d7b4fafb1d7939a41c64868e79de2982eea0a13193f/multidict-6.4.4-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:9bbf7bd39822fd07e3609b6b4467af4c404dd2b88ee314837ad1830a7f4a8299", size = 231120, upload-time = "2025-05-19T14:13:58.333Z" }, - { url = "https://files.pythonhosted.org/packages/b4/7e/95a194d85f27d5ef9cbe48dff9ded722fc6d12fedf641ec6e1e680890be7/multidict-6.4.4-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d1f7cbd4f1f44ddf5fd86a8675b7679176eae770f2fc88115d6dddb6cefb59bc", size = 227457, upload-time = "2025-05-19T14:13:59.663Z" }, - { url = "https://files.pythonhosted.org/packages/25/2b/590ad220968d1babb42f265debe7be5c5c616df6c5688c995a06d8a9b025/multidict-6.4.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bb5ac9e5bfce0e6282e7f59ff7b7b9a74aa8e5c60d38186a4637f5aa764046ad", size = 219111, upload-time = "2025-05-19T14:14:01.019Z" }, - { url = "https://files.pythonhosted.org/packages/e0/f0/b07682b995d3fb5313f339b59d7de02db19ba0c02d1f77c27bdf8212d17c/multidict-6.4.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4efc31dfef8c4eeb95b6b17d799eedad88c4902daba39ce637e23a17ea078915", size = 213012, upload-time = "2025-05-19T14:14:02.396Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/c77b5f36feef2ec92f1119756e468ac9c3eebc35aa8a4c9e51df664cbbc9/multidict-6.4.4-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:9fcad2945b1b91c29ef2b4050f590bfcb68d8ac8e0995a74e659aa57e8d78e01", size = 225408, upload-time = "2025-05-19T14:14:04.826Z" }, - { url = "https://files.pythonhosted.org/packages/cc/b3/e8189b82af9b198b47bc637766208fc917189eea91d674bad417e657bbdf/multidict-6.4.4-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:d877447e7368c7320832acb7159557e49b21ea10ffeb135c1077dbbc0816b598", size = 214396, upload-time = "2025-05-19T14:14:06.187Z" }, - { url = "https://files.pythonhosted.org/packages/20/e0/200d14c84e35ae13ee99fd65dc106e1a1acb87a301f15e906fc7d5b30c17/multidict-6.4.4-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:33a12ebac9f380714c298cbfd3e5b9c0c4e89c75fe612ae496512ee51028915f", size = 222237, upload-time = "2025-05-19T14:14:07.778Z" }, - { url = "https://files.pythonhosted.org/packages/13/f3/bb3df40045ca8262694a3245298732ff431dc781414a89a6a364ebac6840/multidict-6.4.4-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:0f14ea68d29b43a9bf37953881b1e3eb75b2739e896ba4a6aa4ad4c5b9ffa145", size = 231425, upload-time = "2025-05-19T14:14:09.516Z" }, - { url = "https://files.pythonhosted.org/packages/85/3b/538563dc18514384dac169bcba938753ad9ab4d4c8d49b55d6ae49fb2579/multidict-6.4.4-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:0327ad2c747a6600e4797d115d3c38a220fdb28e54983abe8964fd17e95ae83c", size = 226251, upload-time = "2025-05-19T14:14:10.82Z" }, - { url = "https://files.pythonhosted.org/packages/56/79/77e1a65513f09142358f1beb1d4cbc06898590b34a7de2e47023e3c5a3a2/multidict-6.4.4-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:d1a20707492db9719a05fc62ee215fd2c29b22b47c1b1ba347f9abc831e26683", size = 220363, upload-time = "2025-05-19T14:14:12.638Z" }, - { url = "https://files.pythonhosted.org/packages/16/57/67b0516c3e348f8daaa79c369b3de4359a19918320ab82e2e586a1c624ef/multidict-6.4.4-cp310-cp310-win32.whl", hash = "sha256:d83f18315b9fca5db2452d1881ef20f79593c4aa824095b62cb280019ef7aa3d", size = 35175, upload-time = "2025-05-19T14:14:14.805Z" }, - { url = "https://files.pythonhosted.org/packages/86/5a/4ed8fec642d113fa653777cda30ef67aa5c8a38303c091e24c521278a6c6/multidict-6.4.4-cp310-cp310-win_amd64.whl", hash = "sha256:9c17341ee04545fd962ae07330cb5a39977294c883485c8d74634669b1f7fe04", size = 38678, upload-time = "2025-05-19T14:14:16.949Z" }, - { url = "https://files.pythonhosted.org/packages/19/1b/4c6e638195851524a63972c5773c7737bea7e47b1ba402186a37773acee2/multidict-6.4.4-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:4f5f29794ac0e73d2a06ac03fd18870adc0135a9d384f4a306a951188ed02f95", size = 65515, upload-time = "2025-05-19T14:14:19.767Z" }, - { url = "https://files.pythonhosted.org/packages/25/d5/10e6bca9a44b8af3c7f920743e5fc0c2bcf8c11bf7a295d4cfe00b08fb46/multidict-6.4.4-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c04157266344158ebd57b7120d9b0b35812285d26d0e78193e17ef57bfe2979a", size = 38609, upload-time = "2025-05-19T14:14:21.538Z" }, - { url = "https://files.pythonhosted.org/packages/26/b4/91fead447ccff56247edc7f0535fbf140733ae25187a33621771ee598a18/multidict-6.4.4-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:bb61ffd3ab8310d93427e460f565322c44ef12769f51f77277b4abad7b6f7223", size = 37871, upload-time = "2025-05-19T14:14:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/3b/37/cbc977cae59277e99d15bbda84cc53b5e0c4929ffd91d958347200a42ad0/multidict-6.4.4-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5e0ba18a9afd495f17c351d08ebbc4284e9c9f7971d715f196b79636a4d0de44", size = 226661, upload-time = "2025-05-19T14:14:24.124Z" }, - { url = "https://files.pythonhosted.org/packages/15/cd/7e0b57fbd4dc2fc105169c4ecce5be1a63970f23bb4ec8c721b67e11953d/multidict-6.4.4-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:9faf1b1dcaadf9f900d23a0e6d6c8eadd6a95795a0e57fcca73acce0eb912065", size = 223422, upload-time = "2025-05-19T14:14:25.437Z" }, - { url = "https://files.pythonhosted.org/packages/f1/01/1de268da121bac9f93242e30cd3286f6a819e5f0b8896511162d6ed4bf8d/multidict-6.4.4-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a4d1cb1327c6082c4fce4e2a438483390964c02213bc6b8d782cf782c9b1471f", size = 235447, upload-time = "2025-05-19T14:14:26.793Z" }, - { url = "https://files.pythonhosted.org/packages/d2/8c/8b9a5e4aaaf4f2de14e86181a3a3d7b105077f668b6a06f043ec794f684c/multidict-6.4.4-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:941f1bec2f5dbd51feeb40aea654c2747f811ab01bdd3422a48a4e4576b7d76a", size = 231455, upload-time = "2025-05-19T14:14:28.149Z" }, - { url = "https://files.pythonhosted.org/packages/35/db/e1817dcbaa10b319c412769cf999b1016890849245d38905b73e9c286862/multidict-6.4.4-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e5f8a146184da7ea12910a4cec51ef85e44f6268467fb489c3caf0cd512f29c2", size = 223666, upload-time = "2025-05-19T14:14:29.584Z" }, - { url = "https://files.pythonhosted.org/packages/4a/e1/66e8579290ade8a00e0126b3d9a93029033ffd84f0e697d457ed1814d0fc/multidict-6.4.4-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:232b7237e57ec3c09be97206bfb83a0aa1c5d7d377faa019c68a210fa35831f1", size = 217392, upload-time = "2025-05-19T14:14:30.961Z" }, - { url = "https://files.pythonhosted.org/packages/7b/6f/f8639326069c24a48c7747c2a5485d37847e142a3f741ff3340c88060a9a/multidict-6.4.4-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:55ae0721c1513e5e3210bca4fc98456b980b0c2c016679d3d723119b6b202c42", size = 228969, upload-time = "2025-05-19T14:14:32.672Z" }, - { url = "https://files.pythonhosted.org/packages/d2/c3/3d58182f76b960eeade51c89fcdce450f93379340457a328e132e2f8f9ed/multidict-6.4.4-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:51d662c072579f63137919d7bb8fc250655ce79f00c82ecf11cab678f335062e", size = 217433, upload-time = "2025-05-19T14:14:34.016Z" }, - { url = "https://files.pythonhosted.org/packages/e1/4b/f31a562906f3bd375f3d0e83ce314e4a660c01b16c2923e8229b53fba5d7/multidict-6.4.4-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:0e05c39962baa0bb19a6b210e9b1422c35c093b651d64246b6c2e1a7e242d9fd", size = 225418, upload-time = "2025-05-19T14:14:35.376Z" }, - { url = "https://files.pythonhosted.org/packages/99/89/78bb95c89c496d64b5798434a3deee21996114d4d2c28dd65850bf3a691e/multidict-6.4.4-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:d5b1cc3ab8c31d9ebf0faa6e3540fb91257590da330ffe6d2393d4208e638925", size = 235042, upload-time = "2025-05-19T14:14:36.723Z" }, - { url = "https://files.pythonhosted.org/packages/74/91/8780a6e5885a8770442a8f80db86a0887c4becca0e5a2282ba2cae702bc4/multidict-6.4.4-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:93ec84488a384cd7b8a29c2c7f467137d8a73f6fe38bb810ecf29d1ade011a7c", size = 230280, upload-time = "2025-05-19T14:14:38.194Z" }, - { url = "https://files.pythonhosted.org/packages/68/c1/fcf69cabd542eb6f4b892469e033567ee6991d361d77abdc55e3a0f48349/multidict-6.4.4-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:b308402608493638763abc95f9dc0030bbd6ac6aff784512e8ac3da73a88af08", size = 223322, upload-time = "2025-05-19T14:14:40.015Z" }, - { url = "https://files.pythonhosted.org/packages/b8/85/5b80bf4b83d8141bd763e1d99142a9cdfd0db83f0739b4797172a4508014/multidict-6.4.4-cp311-cp311-win32.whl", hash = "sha256:343892a27d1a04d6ae455ecece12904d242d299ada01633d94c4f431d68a8c49", size = 35070, upload-time = "2025-05-19T14:14:41.904Z" }, - { url = "https://files.pythonhosted.org/packages/09/66/0bed198ffd590ab86e001f7fa46b740d58cf8ff98c2f254e4a36bf8861ad/multidict-6.4.4-cp311-cp311-win_amd64.whl", hash = "sha256:73484a94f55359780c0f458bbd3c39cb9cf9c182552177d2136e828269dee529", size = 38667, upload-time = "2025-05-19T14:14:43.534Z" }, - { url = "https://files.pythonhosted.org/packages/d2/b5/5675377da23d60875fe7dae6be841787755878e315e2f517235f22f59e18/multidict-6.4.4-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:dc388f75a1c00000824bf28b7633e40854f4127ede80512b44c3cfeeea1839a2", size = 64293, upload-time = "2025-05-19T14:14:44.724Z" }, - { url = "https://files.pythonhosted.org/packages/34/a7/be384a482754bb8c95d2bbe91717bf7ccce6dc38c18569997a11f95aa554/multidict-6.4.4-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:98af87593a666f739d9dba5d0ae86e01b0e1a9cfcd2e30d2d361fbbbd1a9162d", size = 38096, upload-time = "2025-05-19T14:14:45.95Z" }, - { url = "https://files.pythonhosted.org/packages/66/6d/d59854bb4352306145bdfd1704d210731c1bb2c890bfee31fb7bbc1c4c7f/multidict-6.4.4-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:aff4cafea2d120327d55eadd6b7f1136a8e5a0ecf6fb3b6863e8aca32cd8e50a", size = 37214, upload-time = "2025-05-19T14:14:47.158Z" }, - { url = "https://files.pythonhosted.org/packages/99/e0/c29d9d462d7cfc5fc8f9bf24f9c6843b40e953c0b55e04eba2ad2cf54fba/multidict-6.4.4-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:169c4ba7858176b797fe551d6e99040c531c775d2d57b31bcf4de6d7a669847f", size = 224686, upload-time = "2025-05-19T14:14:48.366Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4a/da99398d7fd8210d9de068f9a1b5f96dfaf67d51e3f2521f17cba4ee1012/multidict-6.4.4-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:b9eb4c59c54421a32b3273d4239865cb14ead53a606db066d7130ac80cc8ec93", size = 231061, upload-time = "2025-05-19T14:14:49.952Z" }, - { url = "https://files.pythonhosted.org/packages/21/f5/ac11add39a0f447ac89353e6ca46666847051103649831c08a2800a14455/multidict-6.4.4-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:7cf3bd54c56aa16fdb40028d545eaa8d051402b61533c21e84046e05513d5780", size = 232412, upload-time = "2025-05-19T14:14:51.812Z" }, - { url = "https://files.pythonhosted.org/packages/d9/11/4b551e2110cded705a3c13a1d4b6a11f73891eb5a1c449f1b2b6259e58a6/multidict-6.4.4-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f682c42003c7264134bfe886376299db4cc0c6cd06a3295b41b347044bcb5482", size = 231563, upload-time = "2025-05-19T14:14:53.262Z" }, - { url = "https://files.pythonhosted.org/packages/4c/02/751530c19e78fe73b24c3da66618eda0aa0d7f6e7aa512e46483de6be210/multidict-6.4.4-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a920f9cf2abdf6e493c519492d892c362007f113c94da4c239ae88429835bad1", size = 223811, upload-time = "2025-05-19T14:14:55.232Z" }, - { url = "https://files.pythonhosted.org/packages/c7/cb/2be8a214643056289e51ca356026c7b2ce7225373e7a1f8c8715efee8988/multidict-6.4.4-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:530d86827a2df6504526106b4c104ba19044594f8722d3e87714e847c74a0275", size = 216524, upload-time = "2025-05-19T14:14:57.226Z" }, - { url = "https://files.pythonhosted.org/packages/19/f3/6d5011ec375c09081f5250af58de85f172bfcaafebff286d8089243c4bd4/multidict-6.4.4-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:ecde56ea2439b96ed8a8d826b50c57364612ddac0438c39e473fafad7ae1c23b", size = 229012, upload-time = "2025-05-19T14:14:58.597Z" }, - { url = "https://files.pythonhosted.org/packages/67/9c/ca510785df5cf0eaf5b2a8132d7d04c1ce058dcf2c16233e596ce37a7f8e/multidict-6.4.4-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:dc8c9736d8574b560634775ac0def6bdc1661fc63fa27ffdfc7264c565bcb4f2", size = 226765, upload-time = "2025-05-19T14:15:00.048Z" }, - { url = "https://files.pythonhosted.org/packages/36/c8/ca86019994e92a0f11e642bda31265854e6ea7b235642f0477e8c2e25c1f/multidict-6.4.4-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:7f3d3b3c34867579ea47cbd6c1f2ce23fbfd20a273b6f9e3177e256584f1eacc", size = 222888, upload-time = "2025-05-19T14:15:01.568Z" }, - { url = "https://files.pythonhosted.org/packages/c6/67/bc25a8e8bd522935379066950ec4e2277f9b236162a73548a2576d4b9587/multidict-6.4.4-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:87a728af265e08f96b6318ebe3c0f68b9335131f461efab2fc64cc84a44aa6ed", size = 234041, upload-time = "2025-05-19T14:15:03.759Z" }, - { url = "https://files.pythonhosted.org/packages/f1/a0/70c4c2d12857fccbe607b334b7ee28b6b5326c322ca8f73ee54e70d76484/multidict-6.4.4-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:9f193eeda1857f8e8d3079a4abd258f42ef4a4bc87388452ed1e1c4d2b0c8740", size = 231046, upload-time = "2025-05-19T14:15:05.698Z" }, - { url = "https://files.pythonhosted.org/packages/c1/0f/52954601d02d39742aab01d6b92f53c1dd38b2392248154c50797b4df7f1/multidict-6.4.4-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:be06e73c06415199200e9a2324a11252a3d62030319919cde5e6950ffeccf72e", size = 227106, upload-time = "2025-05-19T14:15:07.124Z" }, - { url = "https://files.pythonhosted.org/packages/af/24/679d83ec4379402d28721790dce818e5d6b9f94ce1323a556fb17fa9996c/multidict-6.4.4-cp312-cp312-win32.whl", hash = "sha256:622f26ea6a7e19b7c48dd9228071f571b2fbbd57a8cd71c061e848f281550e6b", size = 35351, upload-time = "2025-05-19T14:15:08.556Z" }, - { url = "https://files.pythonhosted.org/packages/52/ef/40d98bc5f986f61565f9b345f102409534e29da86a6454eb6b7c00225a13/multidict-6.4.4-cp312-cp312-win_amd64.whl", hash = "sha256:5e2bcda30d5009996ff439e02a9f2b5c3d64a20151d34898c000a6281faa3781", size = 38791, upload-time = "2025-05-19T14:15:09.825Z" }, - { url = "https://files.pythonhosted.org/packages/df/2a/e166d2ffbf4b10131b2d5b0e458f7cee7d986661caceae0de8753042d4b2/multidict-6.4.4-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:82ffabefc8d84c2742ad19c37f02cde5ec2a1ee172d19944d380f920a340e4b9", size = 64123, upload-time = "2025-05-19T14:15:11.044Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/e200e379ae5b6f95cbae472e0199ea98913f03d8c9a709f42612a432932c/multidict-6.4.4-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:6a2f58a66fe2c22615ad26156354005391e26a2f3721c3621504cd87c1ea87bf", size = 38049, upload-time = "2025-05-19T14:15:12.902Z" }, - { url = "https://files.pythonhosted.org/packages/75/fb/47afd17b83f6a8c7fa863c6d23ac5ba6a0e6145ed8a6bcc8da20b2b2c1d2/multidict-6.4.4-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:5883d6ee0fd9d8a48e9174df47540b7545909841ac82354c7ae4cbe9952603bd", size = 37078, upload-time = "2025-05-19T14:15:14.282Z" }, - { url = "https://files.pythonhosted.org/packages/fa/70/1af3143000eddfb19fd5ca5e78393985ed988ac493bb859800fe0914041f/multidict-6.4.4-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9abcf56a9511653fa1d052bfc55fbe53dbee8f34e68bd6a5a038731b0ca42d15", size = 224097, upload-time = "2025-05-19T14:15:15.566Z" }, - { url = "https://files.pythonhosted.org/packages/b1/39/d570c62b53d4fba844e0378ffbcd02ac25ca423d3235047013ba2f6f60f8/multidict-6.4.4-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:6ed5ae5605d4ad5a049fad2a28bb7193400700ce2f4ae484ab702d1e3749c3f9", size = 230768, upload-time = "2025-05-19T14:15:17.308Z" }, - { url = "https://files.pythonhosted.org/packages/fd/f8/ed88f2c4d06f752b015933055eb291d9bc184936903752c66f68fb3c95a7/multidict-6.4.4-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbfcb60396f9bcfa63e017a180c3105b8c123a63e9d1428a36544e7d37ca9e20", size = 231331, upload-time = "2025-05-19T14:15:18.73Z" }, - { url = "https://files.pythonhosted.org/packages/9c/6f/8e07cffa32f483ab887b0d56bbd8747ac2c1acd00dc0af6fcf265f4a121e/multidict-6.4.4-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b0f1987787f5f1e2076b59692352ab29a955b09ccc433c1f6b8e8e18666f608b", size = 230169, upload-time = "2025-05-19T14:15:20.179Z" }, - { url = "https://files.pythonhosted.org/packages/e6/2b/5dcf173be15e42f330110875a2668ddfc208afc4229097312212dc9c1236/multidict-6.4.4-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1d0121ccce8c812047d8d43d691a1ad7641f72c4f730474878a5aeae1b8ead8c", size = 222947, upload-time = "2025-05-19T14:15:21.714Z" }, - { url = "https://files.pythonhosted.org/packages/39/75/4ddcbcebe5ebcd6faa770b629260d15840a5fc07ce8ad295a32e14993726/multidict-6.4.4-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83ec4967114295b8afd120a8eec579920c882831a3e4c3331d591a8e5bfbbc0f", size = 215761, upload-time = "2025-05-19T14:15:23.242Z" }, - { url = "https://files.pythonhosted.org/packages/6a/c9/55e998ae45ff15c5608e384206aa71a11e1b7f48b64d166db400b14a3433/multidict-6.4.4-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:995f985e2e268deaf17867801b859a282e0448633f1310e3704b30616d269d69", size = 227605, upload-time = "2025-05-19T14:15:24.763Z" }, - { url = "https://files.pythonhosted.org/packages/04/49/c2404eac74497503c77071bd2e6f88c7e94092b8a07601536b8dbe99be50/multidict-6.4.4-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:d832c608f94b9f92a0ec8b7e949be7792a642b6e535fcf32f3e28fab69eeb046", size = 226144, upload-time = "2025-05-19T14:15:26.249Z" }, - { url = "https://files.pythonhosted.org/packages/62/c5/0cd0c3c6f18864c40846aa2252cd69d308699cb163e1c0d989ca301684da/multidict-6.4.4-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:d21c1212171cf7da703c5b0b7a0e85be23b720818aef502ad187d627316d5645", size = 221100, upload-time = "2025-05-19T14:15:28.303Z" }, - { url = "https://files.pythonhosted.org/packages/71/7b/f2f3887bea71739a046d601ef10e689528d4f911d84da873b6be9194ffea/multidict-6.4.4-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:cbebaa076aaecad3d4bb4c008ecc73b09274c952cf6a1b78ccfd689e51f5a5b0", size = 232731, upload-time = "2025-05-19T14:15:30.263Z" }, - { url = "https://files.pythonhosted.org/packages/e5/b3/d9de808349df97fa75ec1372758701b5800ebad3c46ae377ad63058fbcc6/multidict-6.4.4-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:c93a6fb06cc8e5d3628b2b5fda215a5db01e8f08fc15fadd65662d9b857acbe4", size = 229637, upload-time = "2025-05-19T14:15:33.337Z" }, - { url = "https://files.pythonhosted.org/packages/5e/57/13207c16b615eb4f1745b44806a96026ef8e1b694008a58226c2d8f5f0a5/multidict-6.4.4-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:8cd8f81f1310182362fb0c7898145ea9c9b08a71081c5963b40ee3e3cac589b1", size = 225594, upload-time = "2025-05-19T14:15:34.832Z" }, - { url = "https://files.pythonhosted.org/packages/3a/e4/d23bec2f70221604f5565000632c305fc8f25ba953e8ce2d8a18842b9841/multidict-6.4.4-cp313-cp313-win32.whl", hash = "sha256:3e9f1cd61a0ab857154205fb0b1f3d3ace88d27ebd1409ab7af5096e409614cd", size = 35359, upload-time = "2025-05-19T14:15:36.246Z" }, - { url = "https://files.pythonhosted.org/packages/a7/7a/cfe1a47632be861b627f46f642c1d031704cc1c0f5c0efbde2ad44aa34bd/multidict-6.4.4-cp313-cp313-win_amd64.whl", hash = "sha256:8ffb40b74400e4455785c2fa37eba434269149ec525fc8329858c862e4b35373", size = 38903, upload-time = "2025-05-19T14:15:37.507Z" }, - { url = "https://files.pythonhosted.org/packages/68/7b/15c259b0ab49938a0a1c8f3188572802704a779ddb294edc1b2a72252e7c/multidict-6.4.4-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:6a602151dbf177be2450ef38966f4be3467d41a86c6a845070d12e17c858a156", size = 68895, upload-time = "2025-05-19T14:15:38.856Z" }, - { url = "https://files.pythonhosted.org/packages/f1/7d/168b5b822bccd88142e0a3ce985858fea612404edd228698f5af691020c9/multidict-6.4.4-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:0d2b9712211b860d123815a80b859075d86a4d54787e247d7fbee9db6832cf1c", size = 40183, upload-time = "2025-05-19T14:15:40.197Z" }, - { url = "https://files.pythonhosted.org/packages/e0/b7/d4b8d98eb850ef28a4922ba508c31d90715fd9b9da3801a30cea2967130b/multidict-6.4.4-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:d2fa86af59f8fc1972e121ade052145f6da22758f6996a197d69bb52f8204e7e", size = 39592, upload-time = "2025-05-19T14:15:41.508Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/a554678898a19583548e742080cf55d169733baf57efc48c2f0273a08583/multidict-6.4.4-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:50855d03e9e4d66eab6947ba688ffb714616f985838077bc4b490e769e48da51", size = 226071, upload-time = "2025-05-19T14:15:42.877Z" }, - { url = "https://files.pythonhosted.org/packages/ee/dc/7ba6c789d05c310e294f85329efac1bf5b450338d2542498db1491a264df/multidict-6.4.4-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:5bce06b83be23225be1905dcdb6b789064fae92499fbc458f59a8c0e68718601", size = 222597, upload-time = "2025-05-19T14:15:44.412Z" }, - { url = "https://files.pythonhosted.org/packages/24/4f/34eadbbf401b03768dba439be0fb94b0d187facae9142821a3d5599ccb3b/multidict-6.4.4-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:66ed0731f8e5dfd8369a883b6e564aca085fb9289aacabd9decd70568b9a30de", size = 228253, upload-time = "2025-05-19T14:15:46.474Z" }, - { url = "https://files.pythonhosted.org/packages/c0/e6/493225a3cdb0d8d80d43a94503fc313536a07dae54a3f030d279e629a2bc/multidict-6.4.4-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:329ae97fc2f56f44d91bc47fe0972b1f52d21c4b7a2ac97040da02577e2daca2", size = 226146, upload-time = "2025-05-19T14:15:48.003Z" }, - { url = "https://files.pythonhosted.org/packages/2f/70/e411a7254dc3bff6f7e6e004303b1b0591358e9f0b7c08639941e0de8bd6/multidict-6.4.4-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c27e5dcf520923d6474d98b96749e6805f7677e93aaaf62656005b8643f907ab", size = 220585, upload-time = "2025-05-19T14:15:49.546Z" }, - { url = "https://files.pythonhosted.org/packages/08/8f/beb3ae7406a619100d2b1fb0022c3bb55a8225ab53c5663648ba50dfcd56/multidict-6.4.4-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:058cc59b9e9b143cc56715e59e22941a5d868c322242278d28123a5d09cdf6b0", size = 212080, upload-time = "2025-05-19T14:15:51.151Z" }, - { url = "https://files.pythonhosted.org/packages/9c/ec/355124e9d3d01cf8edb072fd14947220f357e1c5bc79c88dff89297e9342/multidict-6.4.4-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:69133376bc9a03f8c47343d33f91f74a99c339e8b58cea90433d8e24bb298031", size = 226558, upload-time = "2025-05-19T14:15:52.665Z" }, - { url = "https://files.pythonhosted.org/packages/fd/22/d2b95cbebbc2ada3be3812ea9287dcc9712d7f1a012fad041770afddb2ad/multidict-6.4.4-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:d6b15c55721b1b115c5ba178c77104123745b1417527ad9641a4c5e2047450f0", size = 212168, upload-time = "2025-05-19T14:15:55.279Z" }, - { url = "https://files.pythonhosted.org/packages/4d/c5/62bfc0b2f9ce88326dbe7179f9824a939c6c7775b23b95de777267b9725c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:a887b77f51d3d41e6e1a63cf3bc7ddf24de5939d9ff69441387dfefa58ac2e26", size = 217970, upload-time = "2025-05-19T14:15:56.806Z" }, - { url = "https://files.pythonhosted.org/packages/79/74/977cea1aadc43ff1c75d23bd5bc4768a8fac98c14e5878d6ee8d6bab743c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:632a3bf8f1787f7ef7d3c2f68a7bde5be2f702906f8b5842ad6da9d974d0aab3", size = 226980, upload-time = "2025-05-19T14:15:58.313Z" }, - { url = "https://files.pythonhosted.org/packages/48/fc/cc4a1a2049df2eb84006607dc428ff237af38e0fcecfdb8a29ca47b1566c/multidict-6.4.4-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:a145c550900deb7540973c5cdb183b0d24bed6b80bf7bddf33ed8f569082535e", size = 220641, upload-time = "2025-05-19T14:15:59.866Z" }, - { url = "https://files.pythonhosted.org/packages/3b/6a/a7444d113ab918701988d4abdde373dbdfd2def7bd647207e2bf645c7eac/multidict-6.4.4-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:cc5d83c6619ca5c9672cb78b39ed8542f1975a803dee2cda114ff73cbb076edd", size = 221728, upload-time = "2025-05-19T14:16:01.535Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b0/fdf4c73ad1c55e0f4dbbf2aa59dd37037334091f9a4961646d2b7ac91a86/multidict-6.4.4-cp313-cp313t-win32.whl", hash = "sha256:3312f63261b9df49be9d57aaa6abf53a6ad96d93b24f9cc16cf979956355ce6e", size = 41913, upload-time = "2025-05-19T14:16:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/8e/92/27989ecca97e542c0d01d05a98a5ae12198a243a9ee12563a0313291511f/multidict-6.4.4-cp313-cp313t-win_amd64.whl", hash = "sha256:ba852168d814b2c73333073e1c7116d9395bea69575a01b0b3c89d2d5a87c8fb", size = 46112, upload-time = "2025-05-19T14:16:04.909Z" }, - { url = "https://files.pythonhosted.org/packages/84/5d/e17845bb0fa76334477d5de38654d27946d5b5d3695443987a094a71b440/multidict-6.4.4-py3-none-any.whl", hash = "sha256:bd4557071b561a8b3b6075c3ce93cf9bfb6182cb241805c3d66ced3b75eff4ac", size = 10481, upload-time = "2025-05-19T14:16:36.024Z" }, -] - -[[package]] -name = "parsimonious" -version = "0.10.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "regex" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7b/91/abdc50c4ef06fdf8d047f60ee777ca9b2a7885e1a9cea81343fbecda52d7/parsimonious-0.10.0.tar.gz", hash = "sha256:8281600da180ec8ae35427a4ab4f7b82bfec1e3d1e52f80cb60ea82b9512501c", size = 52172, upload-time = "2022-09-03T17:01:17.004Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/aa/0f/c8b64d9b54ea631fcad4e9e3c8dbe8c11bb32a623be94f22974c88e71eaf/parsimonious-0.10.0-py3-none-any.whl", hash = "sha256:982ab435fabe86519b57f6b35610aa4e4e977e9f02a14353edf4bbc75369fc0f", size = 48427, upload-time = "2022-09-03T17:01:13.814Z" }, -] - -[[package]] -name = "propcache" -version = "0.3.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a6/16/43264e4a779dd8588c21a70f0709665ee8f611211bdd2c87d952cfa7c776/propcache-0.3.2.tar.gz", hash = "sha256:20d7d62e4e7ef05f221e0db2856b979540686342e7dd9973b815599c7057e168", size = 44139, upload-time = "2025-06-09T22:56:06.081Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ab/14/510deed325e262afeb8b360043c5d7c960da7d3ecd6d6f9496c9c56dc7f4/propcache-0.3.2-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:22d9962a358aedbb7a2e36187ff273adeaab9743373a272976d2e348d08c7770", size = 73178, upload-time = "2025-06-09T22:53:40.126Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4e/ad52a7925ff01c1325653a730c7ec3175a23f948f08626a534133427dcff/propcache-0.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0d0fda578d1dc3f77b6b5a5dce3b9ad69a8250a891760a548df850a5e8da87f3", size = 43133, upload-time = "2025-06-09T22:53:41.965Z" }, - { url = "https://files.pythonhosted.org/packages/63/7c/e9399ba5da7780871db4eac178e9c2e204c23dd3e7d32df202092a1ed400/propcache-0.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3def3da3ac3ce41562d85db655d18ebac740cb3fa4367f11a52b3da9d03a5cc3", size = 43039, upload-time = "2025-06-09T22:53:43.268Z" }, - { url = "https://files.pythonhosted.org/packages/22/e1/58da211eb8fdc6fc854002387d38f415a6ca5f5c67c1315b204a5d3e9d7a/propcache-0.3.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9bec58347a5a6cebf239daba9bda37dffec5b8d2ce004d9fe4edef3d2815137e", size = 201903, upload-time = "2025-06-09T22:53:44.872Z" }, - { url = "https://files.pythonhosted.org/packages/c4/0a/550ea0f52aac455cb90111c8bab995208443e46d925e51e2f6ebdf869525/propcache-0.3.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55ffda449a507e9fbd4aca1a7d9aa6753b07d6166140e5a18d2ac9bc49eac220", size = 213362, upload-time = "2025-06-09T22:53:46.707Z" }, - { url = "https://files.pythonhosted.org/packages/5a/af/9893b7d878deda9bb69fcf54600b247fba7317761b7db11fede6e0f28bd0/propcache-0.3.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:64a67fb39229a8a8491dd42f864e5e263155e729c2e7ff723d6e25f596b1e8cb", size = 210525, upload-time = "2025-06-09T22:53:48.547Z" }, - { url = "https://files.pythonhosted.org/packages/7c/bb/38fd08b278ca85cde36d848091ad2b45954bc5f15cce494bb300b9285831/propcache-0.3.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9da1cf97b92b51253d5b68cf5a2b9e0dafca095e36b7f2da335e27dc6172a614", size = 198283, upload-time = "2025-06-09T22:53:50.067Z" }, - { url = "https://files.pythonhosted.org/packages/78/8c/9fe55bd01d362bafb413dfe508c48753111a1e269737fa143ba85693592c/propcache-0.3.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5f559e127134b07425134b4065be45b166183fdcb433cb6c24c8e4149056ad50", size = 191872, upload-time = "2025-06-09T22:53:51.438Z" }, - { url = "https://files.pythonhosted.org/packages/54/14/4701c33852937a22584e08abb531d654c8bcf7948a8f87ad0a4822394147/propcache-0.3.2-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:aff2e4e06435d61f11a428360a932138d0ec288b0a31dd9bd78d200bd4a2b339", size = 199452, upload-time = "2025-06-09T22:53:53.229Z" }, - { url = "https://files.pythonhosted.org/packages/16/44/447f2253d859602095356007657ee535e0093215ea0b3d1d6a41d16e5201/propcache-0.3.2-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:4927842833830942a5d0a56e6f4839bc484785b8e1ce8d287359794818633ba0", size = 191567, upload-time = "2025-06-09T22:53:54.541Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/e4756258749bb2d3b46defcff606a2f47410bab82be5824a67e84015b267/propcache-0.3.2-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:6107ddd08b02654a30fb8ad7a132021759d750a82578b94cd55ee2772b6ebea2", size = 193015, upload-time = "2025-06-09T22:53:56.44Z" }, - { url = "https://files.pythonhosted.org/packages/1e/df/e6d3c7574233164b6330b9fd697beeac402afd367280e6dc377bb99b43d9/propcache-0.3.2-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:70bd8b9cd6b519e12859c99f3fc9a93f375ebd22a50296c3a295028bea73b9e7", size = 204660, upload-time = "2025-06-09T22:53:57.839Z" }, - { url = "https://files.pythonhosted.org/packages/b2/53/e4d31dd5170b4a0e2e6b730f2385a96410633b4833dc25fe5dffd1f73294/propcache-0.3.2-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:2183111651d710d3097338dd1893fcf09c9f54e27ff1a8795495a16a469cc90b", size = 206105, upload-time = "2025-06-09T22:53:59.638Z" }, - { url = "https://files.pythonhosted.org/packages/7f/fe/74d54cf9fbe2a20ff786e5f7afcfde446588f0cf15fb2daacfbc267b866c/propcache-0.3.2-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:fb075ad271405dcad8e2a7ffc9a750a3bf70e533bd86e89f0603e607b93aa64c", size = 196980, upload-time = "2025-06-09T22:54:01.071Z" }, - { url = "https://files.pythonhosted.org/packages/22/ec/c469c9d59dada8a7679625e0440b544fe72e99311a4679c279562051f6fc/propcache-0.3.2-cp310-cp310-win32.whl", hash = "sha256:404d70768080d3d3bdb41d0771037da19d8340d50b08e104ca0e7f9ce55fce70", size = 37679, upload-time = "2025-06-09T22:54:03.003Z" }, - { url = "https://files.pythonhosted.org/packages/38/35/07a471371ac89d418f8d0b699c75ea6dca2041fbda360823de21f6a9ce0a/propcache-0.3.2-cp310-cp310-win_amd64.whl", hash = "sha256:7435d766f978b4ede777002e6b3b6641dd229cd1da8d3d3106a45770365f9ad9", size = 41459, upload-time = "2025-06-09T22:54:04.134Z" }, - { url = "https://files.pythonhosted.org/packages/80/8d/e8b436717ab9c2cfc23b116d2c297305aa4cd8339172a456d61ebf5669b8/propcache-0.3.2-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:0b8d2f607bd8f80ddc04088bc2a037fdd17884a6fcadc47a96e334d72f3717be", size = 74207, upload-time = "2025-06-09T22:54:05.399Z" }, - { url = "https://files.pythonhosted.org/packages/d6/29/1e34000e9766d112171764b9fa3226fa0153ab565d0c242c70e9945318a7/propcache-0.3.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:06766d8f34733416e2e34f46fea488ad5d60726bb9481d3cddf89a6fa2d9603f", size = 43648, upload-time = "2025-06-09T22:54:08.023Z" }, - { url = "https://files.pythonhosted.org/packages/46/92/1ad5af0df781e76988897da39b5f086c2bf0f028b7f9bd1f409bb05b6874/propcache-0.3.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:a2dc1f4a1df4fecf4e6f68013575ff4af84ef6f478fe5344317a65d38a8e6dc9", size = 43496, upload-time = "2025-06-09T22:54:09.228Z" }, - { url = "https://files.pythonhosted.org/packages/b3/ce/e96392460f9fb68461fabab3e095cb00c8ddf901205be4eae5ce246e5b7e/propcache-0.3.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:be29c4f4810c5789cf10ddf6af80b041c724e629fa51e308a7a0fb19ed1ef7bf", size = 217288, upload-time = "2025-06-09T22:54:10.466Z" }, - { url = "https://files.pythonhosted.org/packages/c5/2a/866726ea345299f7ceefc861a5e782b045545ae6940851930a6adaf1fca6/propcache-0.3.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59d61f6970ecbd8ff2e9360304d5c8876a6abd4530cb752c06586849ac8a9dc9", size = 227456, upload-time = "2025-06-09T22:54:11.828Z" }, - { url = "https://files.pythonhosted.org/packages/de/03/07d992ccb6d930398689187e1b3c718339a1c06b8b145a8d9650e4726166/propcache-0.3.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:62180e0b8dbb6b004baec00a7983e4cc52f5ada9cd11f48c3528d8cfa7b96a66", size = 225429, upload-time = "2025-06-09T22:54:13.823Z" }, - { url = "https://files.pythonhosted.org/packages/5d/e6/116ba39448753b1330f48ab8ba927dcd6cf0baea8a0ccbc512dfb49ba670/propcache-0.3.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c144ca294a204c470f18cf4c9d78887810d04a3e2fbb30eea903575a779159df", size = 213472, upload-time = "2025-06-09T22:54:15.232Z" }, - { url = "https://files.pythonhosted.org/packages/a6/85/f01f5d97e54e428885a5497ccf7f54404cbb4f906688a1690cd51bf597dc/propcache-0.3.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5c2a784234c28854878d68978265617aa6dc0780e53d44b4d67f3651a17a9a2", size = 204480, upload-time = "2025-06-09T22:54:17.104Z" }, - { url = "https://files.pythonhosted.org/packages/e3/79/7bf5ab9033b8b8194cc3f7cf1aaa0e9c3256320726f64a3e1f113a812dce/propcache-0.3.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:5745bc7acdafa978ca1642891b82c19238eadc78ba2aaa293c6863b304e552d7", size = 214530, upload-time = "2025-06-09T22:54:18.512Z" }, - { url = "https://files.pythonhosted.org/packages/31/0b/bd3e0c00509b609317df4a18e6b05a450ef2d9a963e1d8bc9c9415d86f30/propcache-0.3.2-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:c0075bf773d66fa8c9d41f66cc132ecc75e5bb9dd7cce3cfd14adc5ca184cb95", size = 205230, upload-time = "2025-06-09T22:54:19.947Z" }, - { url = "https://files.pythonhosted.org/packages/7a/23/fae0ff9b54b0de4e819bbe559508da132d5683c32d84d0dc2ccce3563ed4/propcache-0.3.2-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:5f57aa0847730daceff0497f417c9de353c575d8da3579162cc74ac294c5369e", size = 206754, upload-time = "2025-06-09T22:54:21.716Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7f/ad6a3c22630aaa5f618b4dc3c3598974a72abb4c18e45a50b3cdd091eb2f/propcache-0.3.2-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:eef914c014bf72d18efb55619447e0aecd5fb7c2e3fa7441e2e5d6099bddff7e", size = 218430, upload-time = "2025-06-09T22:54:23.17Z" }, - { url = "https://files.pythonhosted.org/packages/5b/2c/ba4f1c0e8a4b4c75910742f0d333759d441f65a1c7f34683b4a74c0ee015/propcache-0.3.2-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:2a4092e8549031e82facf3decdbc0883755d5bbcc62d3aea9d9e185549936dcf", size = 223884, upload-time = "2025-06-09T22:54:25.539Z" }, - { url = "https://files.pythonhosted.org/packages/88/e4/ebe30fc399e98572019eee82ad0caf512401661985cbd3da5e3140ffa1b0/propcache-0.3.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:85871b050f174bc0bfb437efbdb68aaf860611953ed12418e4361bc9c392749e", size = 211480, upload-time = "2025-06-09T22:54:26.892Z" }, - { url = "https://files.pythonhosted.org/packages/96/0a/7d5260b914e01d1d0906f7f38af101f8d8ed0dc47426219eeaf05e8ea7c2/propcache-0.3.2-cp311-cp311-win32.whl", hash = "sha256:36c8d9b673ec57900c3554264e630d45980fd302458e4ac801802a7fd2ef7897", size = 37757, upload-time = "2025-06-09T22:54:28.241Z" }, - { url = "https://files.pythonhosted.org/packages/e1/2d/89fe4489a884bc0da0c3278c552bd4ffe06a1ace559db5ef02ef24ab446b/propcache-0.3.2-cp311-cp311-win_amd64.whl", hash = "sha256:e53af8cb6a781b02d2ea079b5b853ba9430fcbe18a8e3ce647d5982a3ff69f39", size = 41500, upload-time = "2025-06-09T22:54:29.4Z" }, - { url = "https://files.pythonhosted.org/packages/a8/42/9ca01b0a6f48e81615dca4765a8f1dd2c057e0540f6116a27dc5ee01dfb6/propcache-0.3.2-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:8de106b6c84506b31c27168582cd3cb3000a6412c16df14a8628e5871ff83c10", size = 73674, upload-time = "2025-06-09T22:54:30.551Z" }, - { url = "https://files.pythonhosted.org/packages/af/6e/21293133beb550f9c901bbece755d582bfaf2176bee4774000bd4dd41884/propcache-0.3.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:28710b0d3975117239c76600ea351934ac7b5ff56e60953474342608dbbb6154", size = 43570, upload-time = "2025-06-09T22:54:32.296Z" }, - { url = "https://files.pythonhosted.org/packages/0c/c8/0393a0a3a2b8760eb3bde3c147f62b20044f0ddac81e9d6ed7318ec0d852/propcache-0.3.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce26862344bdf836650ed2487c3d724b00fbfec4233a1013f597b78c1cb73615", size = 43094, upload-time = "2025-06-09T22:54:33.929Z" }, - { url = "https://files.pythonhosted.org/packages/37/2c/489afe311a690399d04a3e03b069225670c1d489eb7b044a566511c1c498/propcache-0.3.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bca54bd347a253af2cf4544bbec232ab982f4868de0dd684246b67a51bc6b1db", size = 226958, upload-time = "2025-06-09T22:54:35.186Z" }, - { url = "https://files.pythonhosted.org/packages/9d/ca/63b520d2f3d418c968bf596839ae26cf7f87bead026b6192d4da6a08c467/propcache-0.3.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:55780d5e9a2ddc59711d727226bb1ba83a22dd32f64ee15594b9392b1f544eb1", size = 234894, upload-time = "2025-06-09T22:54:36.708Z" }, - { url = "https://files.pythonhosted.org/packages/11/60/1d0ed6fff455a028d678df30cc28dcee7af77fa2b0e6962ce1df95c9a2a9/propcache-0.3.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:035e631be25d6975ed87ab23153db6a73426a48db688070d925aa27e996fe93c", size = 233672, upload-time = "2025-06-09T22:54:38.062Z" }, - { url = "https://files.pythonhosted.org/packages/37/7c/54fd5301ef38505ab235d98827207176a5c9b2aa61939b10a460ca53e123/propcache-0.3.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ee6f22b6eaa39297c751d0e80c0d3a454f112f5c6481214fcf4c092074cecd67", size = 224395, upload-time = "2025-06-09T22:54:39.634Z" }, - { url = "https://files.pythonhosted.org/packages/ee/1a/89a40e0846f5de05fdc6779883bf46ba980e6df4d2ff8fb02643de126592/propcache-0.3.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7ca3aee1aa955438c4dba34fc20a9f390e4c79967257d830f137bd5a8a32ed3b", size = 212510, upload-time = "2025-06-09T22:54:41.565Z" }, - { url = "https://files.pythonhosted.org/packages/5e/33/ca98368586c9566a6b8d5ef66e30484f8da84c0aac3f2d9aec6d31a11bd5/propcache-0.3.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:7a4f30862869fa2b68380d677cc1c5fcf1e0f2b9ea0cf665812895c75d0ca3b8", size = 222949, upload-time = "2025-06-09T22:54:43.038Z" }, - { url = "https://files.pythonhosted.org/packages/ba/11/ace870d0aafe443b33b2f0b7efdb872b7c3abd505bfb4890716ad7865e9d/propcache-0.3.2-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:b77ec3c257d7816d9f3700013639db7491a434644c906a2578a11daf13176251", size = 217258, upload-time = "2025-06-09T22:54:44.376Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d2/86fd6f7adffcfc74b42c10a6b7db721d1d9ca1055c45d39a1a8f2a740a21/propcache-0.3.2-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:cab90ac9d3f14b2d5050928483d3d3b8fb6b4018893fc75710e6aa361ecb2474", size = 213036, upload-time = "2025-06-09T22:54:46.243Z" }, - { url = "https://files.pythonhosted.org/packages/07/94/2d7d1e328f45ff34a0a284cf5a2847013701e24c2a53117e7c280a4316b3/propcache-0.3.2-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:0b504d29f3c47cf6b9e936c1852246c83d450e8e063d50562115a6be6d3a2535", size = 227684, upload-time = "2025-06-09T22:54:47.63Z" }, - { url = "https://files.pythonhosted.org/packages/b7/05/37ae63a0087677e90b1d14710e532ff104d44bc1efa3b3970fff99b891dc/propcache-0.3.2-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:ce2ac2675a6aa41ddb2a0c9cbff53780a617ac3d43e620f8fd77ba1c84dcfc06", size = 234562, upload-time = "2025-06-09T22:54:48.982Z" }, - { url = "https://files.pythonhosted.org/packages/a4/7c/3f539fcae630408d0bd8bf3208b9a647ccad10976eda62402a80adf8fc34/propcache-0.3.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:62b4239611205294cc433845b914131b2a1f03500ff3c1ed093ed216b82621e1", size = 222142, upload-time = "2025-06-09T22:54:50.424Z" }, - { url = "https://files.pythonhosted.org/packages/7c/d2/34b9eac8c35f79f8a962546b3e97e9d4b990c420ee66ac8255d5d9611648/propcache-0.3.2-cp312-cp312-win32.whl", hash = "sha256:df4a81b9b53449ebc90cc4deefb052c1dd934ba85012aa912c7ea7b7e38b60c1", size = 37711, upload-time = "2025-06-09T22:54:52.072Z" }, - { url = "https://files.pythonhosted.org/packages/19/61/d582be5d226cf79071681d1b46b848d6cb03d7b70af7063e33a2787eaa03/propcache-0.3.2-cp312-cp312-win_amd64.whl", hash = "sha256:7046e79b989d7fe457bb755844019e10f693752d169076138abf17f31380800c", size = 41479, upload-time = "2025-06-09T22:54:53.234Z" }, - { url = "https://files.pythonhosted.org/packages/dc/d1/8c747fafa558c603c4ca19d8e20b288aa0c7cda74e9402f50f31eb65267e/propcache-0.3.2-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ca592ed634a73ca002967458187109265e980422116c0a107cf93d81f95af945", size = 71286, upload-time = "2025-06-09T22:54:54.369Z" }, - { url = "https://files.pythonhosted.org/packages/61/99/d606cb7986b60d89c36de8a85d58764323b3a5ff07770a99d8e993b3fa73/propcache-0.3.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:9ecb0aad4020e275652ba3975740f241bd12a61f1a784df044cf7477a02bc252", size = 42425, upload-time = "2025-06-09T22:54:55.642Z" }, - { url = "https://files.pythonhosted.org/packages/8c/96/ef98f91bbb42b79e9bb82bdd348b255eb9d65f14dbbe3b1594644c4073f7/propcache-0.3.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:7f08f1cc28bd2eade7a8a3d2954ccc673bb02062e3e7da09bc75d843386b342f", size = 41846, upload-time = "2025-06-09T22:54:57.246Z" }, - { url = "https://files.pythonhosted.org/packages/5b/ad/3f0f9a705fb630d175146cd7b1d2bf5555c9beaed54e94132b21aac098a6/propcache-0.3.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d1a342c834734edb4be5ecb1e9fb48cb64b1e2320fccbd8c54bf8da8f2a84c33", size = 208871, upload-time = "2025-06-09T22:54:58.975Z" }, - { url = "https://files.pythonhosted.org/packages/3a/38/2085cda93d2c8b6ec3e92af2c89489a36a5886b712a34ab25de9fbca7992/propcache-0.3.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8a544caaae1ac73f1fecfae70ded3e93728831affebd017d53449e3ac052ac1e", size = 215720, upload-time = "2025-06-09T22:55:00.471Z" }, - { url = "https://files.pythonhosted.org/packages/61/c1/d72ea2dc83ac7f2c8e182786ab0fc2c7bd123a1ff9b7975bee671866fe5f/propcache-0.3.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:310d11aa44635298397db47a3ebce7db99a4cc4b9bbdfcf6c98a60c8d5261cf1", size = 215203, upload-time = "2025-06-09T22:55:01.834Z" }, - { url = "https://files.pythonhosted.org/packages/af/81/b324c44ae60c56ef12007105f1460d5c304b0626ab0cc6b07c8f2a9aa0b8/propcache-0.3.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4c1396592321ac83157ac03a2023aa6cc4a3cc3cfdecb71090054c09e5a7cce3", size = 206365, upload-time = "2025-06-09T22:55:03.199Z" }, - { url = "https://files.pythonhosted.org/packages/09/73/88549128bb89e66d2aff242488f62869014ae092db63ccea53c1cc75a81d/propcache-0.3.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8cabf5b5902272565e78197edb682017d21cf3b550ba0460ee473753f28d23c1", size = 196016, upload-time = "2025-06-09T22:55:04.518Z" }, - { url = "https://files.pythonhosted.org/packages/b9/3f/3bdd14e737d145114a5eb83cb172903afba7242f67c5877f9909a20d948d/propcache-0.3.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:0a2f2235ac46a7aa25bdeb03a9e7060f6ecbd213b1f9101c43b3090ffb971ef6", size = 205596, upload-time = "2025-06-09T22:55:05.942Z" }, - { url = "https://files.pythonhosted.org/packages/0f/ca/2f4aa819c357d3107c3763d7ef42c03980f9ed5c48c82e01e25945d437c1/propcache-0.3.2-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:92b69e12e34869a6970fd2f3da91669899994b47c98f5d430b781c26f1d9f387", size = 200977, upload-time = "2025-06-09T22:55:07.792Z" }, - { url = "https://files.pythonhosted.org/packages/cd/4a/e65276c7477533c59085251ae88505caf6831c0e85ff8b2e31ebcbb949b1/propcache-0.3.2-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:54e02207c79968ebbdffc169591009f4474dde3b4679e16634d34c9363ff56b4", size = 197220, upload-time = "2025-06-09T22:55:09.173Z" }, - { url = "https://files.pythonhosted.org/packages/7c/54/fc7152e517cf5578278b242396ce4d4b36795423988ef39bb8cd5bf274c8/propcache-0.3.2-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:4adfb44cb588001f68c5466579d3f1157ca07f7504fc91ec87862e2b8e556b88", size = 210642, upload-time = "2025-06-09T22:55:10.62Z" }, - { url = "https://files.pythonhosted.org/packages/b9/80/abeb4a896d2767bf5f1ea7b92eb7be6a5330645bd7fb844049c0e4045d9d/propcache-0.3.2-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:fd3e6019dc1261cd0291ee8919dd91fbab7b169bb76aeef6c716833a3f65d206", size = 212789, upload-time = "2025-06-09T22:55:12.029Z" }, - { url = "https://files.pythonhosted.org/packages/b3/db/ea12a49aa7b2b6d68a5da8293dcf50068d48d088100ac016ad92a6a780e6/propcache-0.3.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4c181cad81158d71c41a2bce88edce078458e2dd5ffee7eddd6b05da85079f43", size = 205880, upload-time = "2025-06-09T22:55:13.45Z" }, - { url = "https://files.pythonhosted.org/packages/d1/e5/9076a0bbbfb65d1198007059c65639dfd56266cf8e477a9707e4b1999ff4/propcache-0.3.2-cp313-cp313-win32.whl", hash = "sha256:8a08154613f2249519e549de2330cf8e2071c2887309a7b07fb56098f5170a02", size = 37220, upload-time = "2025-06-09T22:55:15.284Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f5/b369e026b09a26cd77aa88d8fffd69141d2ae00a2abaaf5380d2603f4b7f/propcache-0.3.2-cp313-cp313-win_amd64.whl", hash = "sha256:e41671f1594fc4ab0a6dec1351864713cb3a279910ae8b58f884a88a0a632c05", size = 40678, upload-time = "2025-06-09T22:55:16.445Z" }, - { url = "https://files.pythonhosted.org/packages/a4/3a/6ece377b55544941a08d03581c7bc400a3c8cd3c2865900a68d5de79e21f/propcache-0.3.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:9a3cf035bbaf035f109987d9d55dc90e4b0e36e04bbbb95af3055ef17194057b", size = 76560, upload-time = "2025-06-09T22:55:17.598Z" }, - { url = "https://files.pythonhosted.org/packages/0c/da/64a2bb16418740fa634b0e9c3d29edff1db07f56d3546ca2d86ddf0305e1/propcache-0.3.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:156c03d07dc1323d8dacaa221fbe028c5c70d16709cdd63502778e6c3ccca1b0", size = 44676, upload-time = "2025-06-09T22:55:18.922Z" }, - { url = "https://files.pythonhosted.org/packages/36/7b/f025e06ea51cb72c52fb87e9b395cced02786610b60a3ed51da8af017170/propcache-0.3.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:74413c0ba02ba86f55cf60d18daab219f7e531620c15f1e23d95563f505efe7e", size = 44701, upload-time = "2025-06-09T22:55:20.106Z" }, - { url = "https://files.pythonhosted.org/packages/a4/00/faa1b1b7c3b74fc277f8642f32a4c72ba1d7b2de36d7cdfb676db7f4303e/propcache-0.3.2-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f066b437bb3fa39c58ff97ab2ca351db465157d68ed0440abecb21715eb24b28", size = 276934, upload-time = "2025-06-09T22:55:21.5Z" }, - { url = "https://files.pythonhosted.org/packages/74/ab/935beb6f1756e0476a4d5938ff44bf0d13a055fed880caf93859b4f1baf4/propcache-0.3.2-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f1304b085c83067914721e7e9d9917d41ad87696bf70f0bc7dee450e9c71ad0a", size = 278316, upload-time = "2025-06-09T22:55:22.918Z" }, - { url = "https://files.pythonhosted.org/packages/f8/9d/994a5c1ce4389610838d1caec74bdf0e98b306c70314d46dbe4fcf21a3e2/propcache-0.3.2-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ab50cef01b372763a13333b4e54021bdcb291fc9a8e2ccb9c2df98be51bcde6c", size = 282619, upload-time = "2025-06-09T22:55:24.651Z" }, - { url = "https://files.pythonhosted.org/packages/2b/00/a10afce3d1ed0287cef2e09506d3be9822513f2c1e96457ee369adb9a6cd/propcache-0.3.2-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fad3b2a085ec259ad2c2842666b2a0a49dea8463579c606426128925af1ed725", size = 265896, upload-time = "2025-06-09T22:55:26.049Z" }, - { url = "https://files.pythonhosted.org/packages/2e/a8/2aa6716ffa566ca57c749edb909ad27884680887d68517e4be41b02299f3/propcache-0.3.2-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:261fa020c1c14deafd54c76b014956e2f86991af198c51139faf41c4d5e83892", size = 252111, upload-time = "2025-06-09T22:55:27.381Z" }, - { url = "https://files.pythonhosted.org/packages/36/4f/345ca9183b85ac29c8694b0941f7484bf419c7f0fea2d1e386b4f7893eed/propcache-0.3.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:46d7f8aa79c927e5f987ee3a80205c987717d3659f035c85cf0c3680526bdb44", size = 268334, upload-time = "2025-06-09T22:55:28.747Z" }, - { url = "https://files.pythonhosted.org/packages/3e/ca/fcd54f78b59e3f97b3b9715501e3147f5340167733d27db423aa321e7148/propcache-0.3.2-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:6d8f3f0eebf73e3c0ff0e7853f68be638b4043c65a70517bb575eff54edd8dbe", size = 255026, upload-time = "2025-06-09T22:55:30.184Z" }, - { url = "https://files.pythonhosted.org/packages/8b/95/8e6a6bbbd78ac89c30c225210a5c687790e532ba4088afb8c0445b77ef37/propcache-0.3.2-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:03c89c1b14a5452cf15403e291c0ccd7751d5b9736ecb2c5bab977ad6c5bcd81", size = 250724, upload-time = "2025-06-09T22:55:31.646Z" }, - { url = "https://files.pythonhosted.org/packages/ee/b0/0dd03616142baba28e8b2d14ce5df6631b4673850a3d4f9c0f9dd714a404/propcache-0.3.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:0cc17efde71e12bbaad086d679ce575268d70bc123a5a71ea7ad76f70ba30bba", size = 268868, upload-time = "2025-06-09T22:55:33.209Z" }, - { url = "https://files.pythonhosted.org/packages/c5/98/2c12407a7e4fbacd94ddd32f3b1e3d5231e77c30ef7162b12a60e2dd5ce3/propcache-0.3.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:acdf05d00696bc0447e278bb53cb04ca72354e562cf88ea6f9107df8e7fd9770", size = 271322, upload-time = "2025-06-09T22:55:35.065Z" }, - { url = "https://files.pythonhosted.org/packages/35/91/9cb56efbb428b006bb85db28591e40b7736847b8331d43fe335acf95f6c8/propcache-0.3.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:4445542398bd0b5d32df908031cb1b30d43ac848e20470a878b770ec2dcc6330", size = 265778, upload-time = "2025-06-09T22:55:36.45Z" }, - { url = "https://files.pythonhosted.org/packages/9a/4c/b0fe775a2bdd01e176b14b574be679d84fc83958335790f7c9a686c1f468/propcache-0.3.2-cp313-cp313t-win32.whl", hash = "sha256:f86e5d7cd03afb3a1db8e9f9f6eff15794e79e791350ac48a8c924e6f439f394", size = 41175, upload-time = "2025-06-09T22:55:38.436Z" }, - { url = "https://files.pythonhosted.org/packages/a4/ff/47f08595e3d9b5e149c150f88d9714574f1a7cbd89fe2817158a952674bf/propcache-0.3.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9704bedf6e7cbe3c65eca4379a9b53ee6a83749f047808cbb5044d40d7d72198", size = 44857, upload-time = "2025-06-09T22:55:39.687Z" }, - { url = "https://files.pythonhosted.org/packages/cc/35/cc0aaecf278bb4575b8555f2b137de5ab821595ddae9da9d3cd1da4072c7/propcache-0.3.2-py3-none-any.whl", hash = "sha256:98f1ec44fb675f5052cccc8e609c46ed23a35a1cfd18545ad4e29002d858a43f", size = 12663, upload-time = "2025-06-09T22:56:04.484Z" }, -] - -[[package]] -name = "pycryptodome" -version = "3.23.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/a6/8452177684d5e906854776276ddd34eca30d1b1e15aa1ee9cefc289a33f5/pycryptodome-3.23.0.tar.gz", hash = "sha256:447700a657182d60338bab09fdb27518f8856aecd80ae4c6bdddb67ff5da44ef", size = 4921276, upload-time = "2025-05-17T17:21:45.242Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/04/5d/bdb09489b63cd34a976cc9e2a8d938114f7a53a74d3dd4f125ffa49dce82/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:0011f7f00cdb74879142011f95133274741778abba114ceca229adbf8e62c3e4", size = 2495152, upload-time = "2025-05-17T17:20:20.833Z" }, - { url = "https://files.pythonhosted.org/packages/a7/ce/7840250ed4cc0039c433cd41715536f926d6e86ce84e904068eb3244b6a6/pycryptodome-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:90460fc9e088ce095f9ee8356722d4f10f86e5be06e2354230a9880b9c549aae", size = 1639348, upload-time = "2025-05-17T17:20:23.171Z" }, - { url = "https://files.pythonhosted.org/packages/ee/f0/991da24c55c1f688d6a3b5a11940567353f74590734ee4a64294834ae472/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4764e64b269fc83b00f682c47443c2e6e85b18273712b98aa43bcb77f8570477", size = 2184033, upload-time = "2025-05-17T17:20:25.424Z" }, - { url = "https://files.pythonhosted.org/packages/54/16/0e11882deddf00f68b68dd4e8e442ddc30641f31afeb2bc25588124ac8de/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eb8f24adb74984aa0e5d07a2368ad95276cf38051fe2dc6605cbcf482e04f2a7", size = 2270142, upload-time = "2025-05-17T17:20:27.808Z" }, - { url = "https://files.pythonhosted.org/packages/d5/fc/4347fea23a3f95ffb931f383ff28b3f7b1fe868739182cb76718c0da86a1/pycryptodome-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:d97618c9c6684a97ef7637ba43bdf6663a2e2e77efe0f863cce97a76af396446", size = 2309384, upload-time = "2025-05-17T17:20:30.765Z" }, - { url = "https://files.pythonhosted.org/packages/6e/d9/c5261780b69ce66d8cfab25d2797bd6e82ba0241804694cd48be41add5eb/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:9a53a4fe5cb075075d515797d6ce2f56772ea7e6a1e5e4b96cf78a14bac3d265", size = 2183237, upload-time = "2025-05-17T17:20:33.736Z" }, - { url = "https://files.pythonhosted.org/packages/5a/6f/3af2ffedd5cfa08c631f89452c6648c4d779e7772dfc388c77c920ca6bbf/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:763d1d74f56f031788e5d307029caef067febf890cd1f8bf61183ae142f1a77b", size = 2343898, upload-time = "2025-05-17T17:20:36.086Z" }, - { url = "https://files.pythonhosted.org/packages/9a/dc/9060d807039ee5de6e2f260f72f3d70ac213993a804f5e67e0a73a56dd2f/pycryptodome-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:954af0e2bd7cea83ce72243b14e4fb518b18f0c1649b576d114973e2073b273d", size = 2269197, upload-time = "2025-05-17T17:20:38.414Z" }, - { url = "https://files.pythonhosted.org/packages/f9/34/e6c8ca177cb29dcc4967fef73f5de445912f93bd0343c9c33c8e5bf8cde8/pycryptodome-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:257bb3572c63ad8ba40b89f6fc9d63a2a628e9f9708d31ee26560925ebe0210a", size = 1768600, upload-time = "2025-05-17T17:20:40.688Z" }, - { url = "https://files.pythonhosted.org/packages/e4/1d/89756b8d7ff623ad0160f4539da571d1f594d21ee6d68be130a6eccb39a4/pycryptodome-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:6501790c5b62a29fcb227bd6b62012181d886a767ce9ed03b303d1f22eb5c625", size = 1799740, upload-time = "2025-05-17T17:20:42.413Z" }, - { url = "https://files.pythonhosted.org/packages/5d/61/35a64f0feaea9fd07f0d91209e7be91726eb48c0f1bfc6720647194071e4/pycryptodome-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:9a77627a330ab23ca43b48b130e202582e91cc69619947840ea4d2d1be21eb39", size = 1703685, upload-time = "2025-05-17T17:20:44.388Z" }, - { url = "https://files.pythonhosted.org/packages/db/6c/a1f71542c969912bb0e106f64f60a56cc1f0fabecf9396f45accbe63fa68/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:187058ab80b3281b1de11c2e6842a357a1f71b42cb1e15bce373f3d238135c27", size = 2495627, upload-time = "2025-05-17T17:20:47.139Z" }, - { url = "https://files.pythonhosted.org/packages/6e/4e/a066527e079fc5002390c8acdd3aca431e6ea0a50ffd7201551175b47323/pycryptodome-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:cfb5cd445280c5b0a4e6187a7ce8de5a07b5f3f897f235caa11f1f435f182843", size = 1640362, upload-time = "2025-05-17T17:20:50.392Z" }, - { url = "https://files.pythonhosted.org/packages/50/52/adaf4c8c100a8c49d2bd058e5b551f73dfd8cb89eb4911e25a0c469b6b4e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:67bd81fcbe34f43ad9422ee8fd4843c8e7198dd88dd3d40e6de42ee65fbe1490", size = 2182625, upload-time = "2025-05-17T17:20:52.866Z" }, - { url = "https://files.pythonhosted.org/packages/5f/e9/a09476d436d0ff1402ac3867d933c61805ec2326c6ea557aeeac3825604e/pycryptodome-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c8987bd3307a39bc03df5c8e0e3d8be0c4c3518b7f044b0f4c15d1aa78f52575", size = 2268954, upload-time = "2025-05-17T17:20:55.027Z" }, - { url = "https://files.pythonhosted.org/packages/f9/c5/ffe6474e0c551d54cab931918127c46d70cab8f114e0c2b5a3c071c2f484/pycryptodome-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0698f65e5b570426fc31b8162ed4603b0c2841cbb9088e2b01641e3065915b", size = 2308534, upload-time = "2025-05-17T17:20:57.279Z" }, - { url = "https://files.pythonhosted.org/packages/18/28/e199677fc15ecf43010f2463fde4c1a53015d1fe95fb03bca2890836603a/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:53ecbafc2b55353edcebd64bf5da94a2a2cdf5090a6915bcca6eca6cc452585a", size = 2181853, upload-time = "2025-05-17T17:20:59.322Z" }, - { url = "https://files.pythonhosted.org/packages/ce/ea/4fdb09f2165ce1365c9eaefef36625583371ee514db58dc9b65d3a255c4c/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:156df9667ad9f2ad26255926524e1c136d6664b741547deb0a86a9acf5ea631f", size = 2342465, upload-time = "2025-05-17T17:21:03.83Z" }, - { url = "https://files.pythonhosted.org/packages/22/82/6edc3fc42fe9284aead511394bac167693fb2b0e0395b28b8bedaa07ef04/pycryptodome-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:dea827b4d55ee390dc89b2afe5927d4308a8b538ae91d9c6f7a5090f397af1aa", size = 2267414, upload-time = "2025-05-17T17:21:06.72Z" }, - { url = "https://files.pythonhosted.org/packages/59/fe/aae679b64363eb78326c7fdc9d06ec3de18bac68be4b612fc1fe8902693c/pycryptodome-3.23.0-cp37-abi3-win32.whl", hash = "sha256:507dbead45474b62b2bbe318eb1c4c8ee641077532067fec9c1aa82c31f84886", size = 1768484, upload-time = "2025-05-17T17:21:08.535Z" }, - { url = "https://files.pythonhosted.org/packages/54/2f/e97a1b8294db0daaa87012c24a7bb714147c7ade7656973fd6c736b484ff/pycryptodome-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:c75b52aacc6c0c260f204cbdd834f76edc9fb0d8e0da9fbf8352ef58202564e2", size = 1799636, upload-time = "2025-05-17T17:21:10.393Z" }, - { url = "https://files.pythonhosted.org/packages/18/3d/f9441a0d798bf2b1e645adc3265e55706aead1255ccdad3856dbdcffec14/pycryptodome-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:11eeeb6917903876f134b56ba11abe95c0b0fd5e3330def218083c7d98bbcb3c", size = 1703675, upload-time = "2025-05-17T17:21:13.146Z" }, - { url = "https://files.pythonhosted.org/packages/d9/12/e33935a0709c07de084d7d58d330ec3f4daf7910a18e77937affdb728452/pycryptodome-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ddb95b49df036ddd264a0ad246d1be5b672000f12d6961ea2c267083a5e19379", size = 1623886, upload-time = "2025-05-17T17:21:20.614Z" }, - { url = "https://files.pythonhosted.org/packages/22/0b/aa8f9419f25870889bebf0b26b223c6986652bdf071f000623df11212c90/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e95564beb8782abfd9e431c974e14563a794a4944c29d6d3b7b5ea042110b4", size = 1672151, upload-time = "2025-05-17T17:21:22.666Z" }, - { url = "https://files.pythonhosted.org/packages/d4/5e/63f5cbde2342b7f70a39e591dbe75d9809d6338ce0b07c10406f1a140cdc/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:14e15c081e912c4b0d75632acd8382dfce45b258667aa3c67caf7a4d4c13f630", size = 1664461, upload-time = "2025-05-17T17:21:25.225Z" }, - { url = "https://files.pythonhosted.org/packages/d6/92/608fbdad566ebe499297a86aae5f2a5263818ceeecd16733006f1600403c/pycryptodome-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a7fc76bf273353dc7e5207d172b83f569540fc9a28d63171061c42e361d22353", size = 1702440, upload-time = "2025-05-17T17:21:27.991Z" }, - { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, -] - -[[package]] -name = "pydantic" -version = "2.10.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "annotated-types" }, - { name = "pydantic-core" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/70/7e/fb60e6fee04d0ef8f15e4e01ff187a196fa976eb0f0ab524af4599e5754c/pydantic-2.10.4.tar.gz", hash = "sha256:82f12e9723da6de4fe2ba888b5971157b3be7ad914267dea8f05f82b28254f06", size = 762094, upload-time = "2024-12-18T17:09:24.84Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/26/3e1bbe954fde7ee22a6e7d31582c642aad9e84ffe4b5fb61e63b87cd326f/pydantic-2.10.4-py3-none-any.whl", hash = "sha256:597e135ea68be3a37552fb524bc7d0d66dcf93d395acd93a00682f1efcb8ee3d", size = 431765, upload-time = "2024-12-18T17:09:21.953Z" }, -] - -[[package]] -name = "pydantic-core" -version = "2.27.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/fc/01/f3e5ac5e7c25833db5eb555f7b7ab24cd6f8c322d3a3ad2d67a952dc0abc/pydantic_core-2.27.2.tar.gz", hash = "sha256:eb026e5a4c1fee05726072337ff51d1efb6f59090b7da90d30ea58625b1ffb39", size = 413443, upload-time = "2024-12-18T11:31:54.917Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3a/bc/fed5f74b5d802cf9a03e83f60f18864e90e3aed7223adaca5ffb7a8d8d64/pydantic_core-2.27.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2d367ca20b2f14095a8f4fa1210f5a7b78b8a20009ecced6b12818f455b1e9fa", size = 1895938, upload-time = "2024-12-18T11:27:14.406Z" }, - { url = "https://files.pythonhosted.org/packages/71/2a/185aff24ce844e39abb8dd680f4e959f0006944f4a8a0ea372d9f9ae2e53/pydantic_core-2.27.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:491a2b73db93fab69731eaee494f320faa4e093dbed776be1a829c2eb222c34c", size = 1815684, upload-time = "2024-12-18T11:27:16.489Z" }, - { url = "https://files.pythonhosted.org/packages/c3/43/fafabd3d94d159d4f1ed62e383e264f146a17dd4d48453319fd782e7979e/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7969e133a6f183be60e9f6f56bfae753585680f3b7307a8e555a948d443cc05a", size = 1829169, upload-time = "2024-12-18T11:27:22.16Z" }, - { url = "https://files.pythonhosted.org/packages/a2/d1/f2dfe1a2a637ce6800b799aa086d079998959f6f1215eb4497966efd2274/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:3de9961f2a346257caf0aa508a4da705467f53778e9ef6fe744c038119737ef5", size = 1867227, upload-time = "2024-12-18T11:27:25.097Z" }, - { url = "https://files.pythonhosted.org/packages/7d/39/e06fcbcc1c785daa3160ccf6c1c38fea31f5754b756e34b65f74e99780b5/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:e2bb4d3e5873c37bb3dd58714d4cd0b0e6238cebc4177ac8fe878f8b3aa8e74c", size = 2037695, upload-time = "2024-12-18T11:27:28.656Z" }, - { url = "https://files.pythonhosted.org/packages/7a/67/61291ee98e07f0650eb756d44998214231f50751ba7e13f4f325d95249ab/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:280d219beebb0752699480fe8f1dc61ab6615c2046d76b7ab7ee38858de0a4e7", size = 2741662, upload-time = "2024-12-18T11:27:30.798Z" }, - { url = "https://files.pythonhosted.org/packages/32/90/3b15e31b88ca39e9e626630b4c4a1f5a0dfd09076366f4219429e6786076/pydantic_core-2.27.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:47956ae78b6422cbd46f772f1746799cbb862de838fd8d1fbd34a82e05b0983a", size = 1993370, upload-time = "2024-12-18T11:27:33.692Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/c06d333ee3a67e2e13e07794995c1535565132940715931c1c43bfc85b11/pydantic_core-2.27.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:14d4a5c49d2f009d62a2a7140d3064f686d17a5d1a268bc641954ba181880236", size = 1996813, upload-time = "2024-12-18T11:27:37.111Z" }, - { url = "https://files.pythonhosted.org/packages/7c/f7/89be1c8deb6e22618a74f0ca0d933fdcb8baa254753b26b25ad3acff8f74/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:337b443af21d488716f8d0b6164de833e788aa6bd7e3a39c005febc1284f4962", size = 2005287, upload-time = "2024-12-18T11:27:40.566Z" }, - { url = "https://files.pythonhosted.org/packages/b7/7d/8eb3e23206c00ef7feee17b83a4ffa0a623eb1a9d382e56e4aa46fd15ff2/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_armv7l.whl", hash = "sha256:03d0f86ea3184a12f41a2d23f7ccb79cdb5a18e06993f8a45baa8dfec746f0e9", size = 2128414, upload-time = "2024-12-18T11:27:43.757Z" }, - { url = "https://files.pythonhosted.org/packages/4e/99/fe80f3ff8dd71a3ea15763878d464476e6cb0a2db95ff1c5c554133b6b83/pydantic_core-2.27.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:7041c36f5680c6e0f08d922aed302e98b3745d97fe1589db0a3eebf6624523af", size = 2155301, upload-time = "2024-12-18T11:27:47.36Z" }, - { url = "https://files.pythonhosted.org/packages/2b/a3/e50460b9a5789ca1451b70d4f52546fa9e2b420ba3bfa6100105c0559238/pydantic_core-2.27.2-cp310-cp310-win32.whl", hash = "sha256:50a68f3e3819077be2c98110c1f9dcb3817e93f267ba80a2c05bb4f8799e2ff4", size = 1816685, upload-time = "2024-12-18T11:27:50.508Z" }, - { url = "https://files.pythonhosted.org/packages/57/4c/a8838731cb0f2c2a39d3535376466de6049034d7b239c0202a64aaa05533/pydantic_core-2.27.2-cp310-cp310-win_amd64.whl", hash = "sha256:e0fd26b16394ead34a424eecf8a31a1f5137094cabe84a1bcb10fa6ba39d3d31", size = 1982876, upload-time = "2024-12-18T11:27:53.54Z" }, - { url = "https://files.pythonhosted.org/packages/c2/89/f3450af9d09d44eea1f2c369f49e8f181d742f28220f88cc4dfaae91ea6e/pydantic_core-2.27.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:8e10c99ef58cfdf2a66fc15d66b16c4a04f62bca39db589ae8cba08bc55331bc", size = 1893421, upload-time = "2024-12-18T11:27:55.409Z" }, - { url = "https://files.pythonhosted.org/packages/9e/e3/71fe85af2021f3f386da42d291412e5baf6ce7716bd7101ea49c810eda90/pydantic_core-2.27.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:26f32e0adf166a84d0cb63be85c562ca8a6fa8de28e5f0d92250c6b7e9e2aff7", size = 1814998, upload-time = "2024-12-18T11:27:57.252Z" }, - { url = "https://files.pythonhosted.org/packages/a6/3c/724039e0d848fd69dbf5806894e26479577316c6f0f112bacaf67aa889ac/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8c19d1ea0673cd13cc2f872f6c9ab42acc4e4f492a7ca9d3795ce2b112dd7e15", size = 1826167, upload-time = "2024-12-18T11:27:59.146Z" }, - { url = "https://files.pythonhosted.org/packages/2b/5b/1b29e8c1fb5f3199a9a57c1452004ff39f494bbe9bdbe9a81e18172e40d3/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:5e68c4446fe0810e959cdff46ab0a41ce2f2c86d227d96dc3847af0ba7def306", size = 1865071, upload-time = "2024-12-18T11:28:02.625Z" }, - { url = "https://files.pythonhosted.org/packages/89/6c/3985203863d76bb7d7266e36970d7e3b6385148c18a68cc8915fd8c84d57/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d9640b0059ff4f14d1f37321b94061c6db164fbe49b334b31643e0528d100d99", size = 2036244, upload-time = "2024-12-18T11:28:04.442Z" }, - { url = "https://files.pythonhosted.org/packages/0e/41/f15316858a246b5d723f7d7f599f79e37493b2e84bfc789e58d88c209f8a/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:40d02e7d45c9f8af700f3452f329ead92da4c5f4317ca9b896de7ce7199ea459", size = 2737470, upload-time = "2024-12-18T11:28:07.679Z" }, - { url = "https://files.pythonhosted.org/packages/a8/7c/b860618c25678bbd6d1d99dbdfdf0510ccb50790099b963ff78a124b754f/pydantic_core-2.27.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1c1fd185014191700554795c99b347d64f2bb637966c4cfc16998a0ca700d048", size = 1992291, upload-time = "2024-12-18T11:28:10.297Z" }, - { url = "https://files.pythonhosted.org/packages/bf/73/42c3742a391eccbeab39f15213ecda3104ae8682ba3c0c28069fbcb8c10d/pydantic_core-2.27.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d81d2068e1c1228a565af076598f9e7451712700b673de8f502f0334f281387d", size = 1994613, upload-time = "2024-12-18T11:28:13.362Z" }, - { url = "https://files.pythonhosted.org/packages/94/7a/941e89096d1175d56f59340f3a8ebaf20762fef222c298ea96d36a6328c5/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:1a4207639fb02ec2dbb76227d7c751a20b1a6b4bc52850568e52260cae64ca3b", size = 2002355, upload-time = "2024-12-18T11:28:16.587Z" }, - { url = "https://files.pythonhosted.org/packages/6e/95/2359937a73d49e336a5a19848713555605d4d8d6940c3ec6c6c0ca4dcf25/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_armv7l.whl", hash = "sha256:3de3ce3c9ddc8bbd88f6e0e304dea0e66d843ec9de1b0042b0911c1663ffd474", size = 2126661, upload-time = "2024-12-18T11:28:18.407Z" }, - { url = "https://files.pythonhosted.org/packages/2b/4c/ca02b7bdb6012a1adef21a50625b14f43ed4d11f1fc237f9d7490aa5078c/pydantic_core-2.27.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:30c5f68ded0c36466acede341551106821043e9afaad516adfb6e8fa80a4e6a6", size = 2153261, upload-time = "2024-12-18T11:28:21.471Z" }, - { url = "https://files.pythonhosted.org/packages/72/9d/a241db83f973049a1092a079272ffe2e3e82e98561ef6214ab53fe53b1c7/pydantic_core-2.27.2-cp311-cp311-win32.whl", hash = "sha256:c70c26d2c99f78b125a3459f8afe1aed4d9687c24fd677c6a4436bc042e50d6c", size = 1812361, upload-time = "2024-12-18T11:28:23.53Z" }, - { url = "https://files.pythonhosted.org/packages/e8/ef/013f07248041b74abd48a385e2110aa3a9bbfef0fbd97d4e6d07d2f5b89a/pydantic_core-2.27.2-cp311-cp311-win_amd64.whl", hash = "sha256:08e125dbdc505fa69ca7d9c499639ab6407cfa909214d500897d02afb816e7cc", size = 1982484, upload-time = "2024-12-18T11:28:25.391Z" }, - { url = "https://files.pythonhosted.org/packages/10/1c/16b3a3e3398fd29dca77cea0a1d998d6bde3902fa2706985191e2313cc76/pydantic_core-2.27.2-cp311-cp311-win_arm64.whl", hash = "sha256:26f0d68d4b235a2bae0c3fc585c585b4ecc51382db0e3ba402a22cbc440915e4", size = 1867102, upload-time = "2024-12-18T11:28:28.593Z" }, - { url = "https://files.pythonhosted.org/packages/d6/74/51c8a5482ca447871c93e142d9d4a92ead74de6c8dc5e66733e22c9bba89/pydantic_core-2.27.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9e0c8cfefa0ef83b4da9588448b6d8d2a2bf1a53c3f1ae5fca39eb3061e2f0b0", size = 1893127, upload-time = "2024-12-18T11:28:30.346Z" }, - { url = "https://files.pythonhosted.org/packages/d3/f3/c97e80721735868313c58b89d2de85fa80fe8dfeeed84dc51598b92a135e/pydantic_core-2.27.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:83097677b8e3bd7eaa6775720ec8e0405f1575015a463285a92bfdfe254529ef", size = 1811340, upload-time = "2024-12-18T11:28:32.521Z" }, - { url = "https://files.pythonhosted.org/packages/9e/91/840ec1375e686dbae1bd80a9e46c26a1e0083e1186abc610efa3d9a36180/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:172fce187655fece0c90d90a678424b013f8fbb0ca8b036ac266749c09438cb7", size = 1822900, upload-time = "2024-12-18T11:28:34.507Z" }, - { url = "https://files.pythonhosted.org/packages/f6/31/4240bc96025035500c18adc149aa6ffdf1a0062a4b525c932065ceb4d868/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:519f29f5213271eeeeb3093f662ba2fd512b91c5f188f3bb7b27bc5973816934", size = 1869177, upload-time = "2024-12-18T11:28:36.488Z" }, - { url = "https://files.pythonhosted.org/packages/fa/20/02fbaadb7808be578317015c462655c317a77a7c8f0ef274bc016a784c54/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:05e3a55d124407fffba0dd6b0c0cd056d10e983ceb4e5dbd10dda135c31071d6", size = 2038046, upload-time = "2024-12-18T11:28:39.409Z" }, - { url = "https://files.pythonhosted.org/packages/06/86/7f306b904e6c9eccf0668248b3f272090e49c275bc488a7b88b0823444a4/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9c3ed807c7b91de05e63930188f19e921d1fe90de6b4f5cd43ee7fcc3525cb8c", size = 2685386, upload-time = "2024-12-18T11:28:41.221Z" }, - { url = "https://files.pythonhosted.org/packages/8d/f0/49129b27c43396581a635d8710dae54a791b17dfc50c70164866bbf865e3/pydantic_core-2.27.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6fb4aadc0b9a0c063206846d603b92030eb6f03069151a625667f982887153e2", size = 1997060, upload-time = "2024-12-18T11:28:44.709Z" }, - { url = "https://files.pythonhosted.org/packages/0d/0f/943b4af7cd416c477fd40b187036c4f89b416a33d3cc0ab7b82708a667aa/pydantic_core-2.27.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:28ccb213807e037460326424ceb8b5245acb88f32f3d2777427476e1b32c48c4", size = 2004870, upload-time = "2024-12-18T11:28:46.839Z" }, - { url = "https://files.pythonhosted.org/packages/35/40/aea70b5b1a63911c53a4c8117c0a828d6790483f858041f47bab0b779f44/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:de3cd1899e2c279b140adde9357c4495ed9d47131b4a4eaff9052f23398076b3", size = 1999822, upload-time = "2024-12-18T11:28:48.896Z" }, - { url = "https://files.pythonhosted.org/packages/f2/b3/807b94fd337d58effc5498fd1a7a4d9d59af4133e83e32ae39a96fddec9d/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_armv7l.whl", hash = "sha256:220f892729375e2d736b97d0e51466252ad84c51857d4d15f5e9692f9ef12be4", size = 2130364, upload-time = "2024-12-18T11:28:50.755Z" }, - { url = "https://files.pythonhosted.org/packages/fc/df/791c827cd4ee6efd59248dca9369fb35e80a9484462c33c6649a8d02b565/pydantic_core-2.27.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:a0fcd29cd6b4e74fe8ddd2c90330fd8edf2e30cb52acda47f06dd615ae72da57", size = 2158303, upload-time = "2024-12-18T11:28:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/9b/67/4e197c300976af185b7cef4c02203e175fb127e414125916bf1128b639a9/pydantic_core-2.27.2-cp312-cp312-win32.whl", hash = "sha256:1e2cb691ed9834cd6a8be61228471d0a503731abfb42f82458ff27be7b2186fc", size = 1834064, upload-time = "2024-12-18T11:28:56.074Z" }, - { url = "https://files.pythonhosted.org/packages/1f/ea/cd7209a889163b8dcca139fe32b9687dd05249161a3edda62860430457a5/pydantic_core-2.27.2-cp312-cp312-win_amd64.whl", hash = "sha256:cc3f1a99a4f4f9dd1de4fe0312c114e740b5ddead65bb4102884b384c15d8bc9", size = 1989046, upload-time = "2024-12-18T11:28:58.107Z" }, - { url = "https://files.pythonhosted.org/packages/bc/49/c54baab2f4658c26ac633d798dab66b4c3a9bbf47cff5284e9c182f4137a/pydantic_core-2.27.2-cp312-cp312-win_arm64.whl", hash = "sha256:3911ac9284cd8a1792d3cb26a2da18f3ca26c6908cc434a18f730dc0db7bfa3b", size = 1885092, upload-time = "2024-12-18T11:29:01.335Z" }, - { url = "https://files.pythonhosted.org/packages/41/b1/9bc383f48f8002f99104e3acff6cba1231b29ef76cfa45d1506a5cad1f84/pydantic_core-2.27.2-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:7d14bd329640e63852364c306f4d23eb744e0f8193148d4044dd3dacdaacbd8b", size = 1892709, upload-time = "2024-12-18T11:29:03.193Z" }, - { url = "https://files.pythonhosted.org/packages/10/6c/e62b8657b834f3eb2961b49ec8e301eb99946245e70bf42c8817350cbefc/pydantic_core-2.27.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:82f91663004eb8ed30ff478d77c4d1179b3563df6cdb15c0817cd1cdaf34d154", size = 1811273, upload-time = "2024-12-18T11:29:05.306Z" }, - { url = "https://files.pythonhosted.org/packages/ba/15/52cfe49c8c986e081b863b102d6b859d9defc63446b642ccbbb3742bf371/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:71b24c7d61131bb83df10cc7e687433609963a944ccf45190cfc21e0887b08c9", size = 1823027, upload-time = "2024-12-18T11:29:07.294Z" }, - { url = "https://files.pythonhosted.org/packages/b1/1c/b6f402cfc18ec0024120602bdbcebc7bdd5b856528c013bd4d13865ca473/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fa8e459d4954f608fa26116118bb67f56b93b209c39b008277ace29937453dc9", size = 1868888, upload-time = "2024-12-18T11:29:09.249Z" }, - { url = "https://files.pythonhosted.org/packages/bd/7b/8cb75b66ac37bc2975a3b7de99f3c6f355fcc4d89820b61dffa8f1e81677/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce8918cbebc8da707ba805b7fd0b382816858728ae7fe19a942080c24e5b7cd1", size = 2037738, upload-time = "2024-12-18T11:29:11.23Z" }, - { url = "https://files.pythonhosted.org/packages/c8/f1/786d8fe78970a06f61df22cba58e365ce304bf9b9f46cc71c8c424e0c334/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eda3f5c2a021bbc5d976107bb302e0131351c2ba54343f8a496dc8783d3d3a6a", size = 2685138, upload-time = "2024-12-18T11:29:16.396Z" }, - { url = "https://files.pythonhosted.org/packages/a6/74/d12b2cd841d8724dc8ffb13fc5cef86566a53ed358103150209ecd5d1999/pydantic_core-2.27.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bd8086fa684c4775c27f03f062cbb9eaa6e17f064307e86b21b9e0abc9c0f02e", size = 1997025, upload-time = "2024-12-18T11:29:20.25Z" }, - { url = "https://files.pythonhosted.org/packages/a0/6e/940bcd631bc4d9a06c9539b51f070b66e8f370ed0933f392db6ff350d873/pydantic_core-2.27.2-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:8d9b3388db186ba0c099a6d20f0604a44eabdeef1777ddd94786cdae158729e4", size = 2004633, upload-time = "2024-12-18T11:29:23.877Z" }, - { url = "https://files.pythonhosted.org/packages/50/cc/a46b34f1708d82498c227d5d80ce615b2dd502ddcfd8376fc14a36655af1/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:7a66efda2387de898c8f38c0cf7f14fca0b51a8ef0b24bfea5849f1b3c95af27", size = 1999404, upload-time = "2024-12-18T11:29:25.872Z" }, - { url = "https://files.pythonhosted.org/packages/ca/2d/c365cfa930ed23bc58c41463bae347d1005537dc8db79e998af8ba28d35e/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_armv7l.whl", hash = "sha256:18a101c168e4e092ab40dbc2503bdc0f62010e95d292b27827871dc85450d7ee", size = 2130130, upload-time = "2024-12-18T11:29:29.252Z" }, - { url = "https://files.pythonhosted.org/packages/f4/d7/eb64d015c350b7cdb371145b54d96c919d4db516817f31cd1c650cae3b21/pydantic_core-2.27.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:ba5dd002f88b78a4215ed2f8ddbdf85e8513382820ba15ad5ad8955ce0ca19a1", size = 2157946, upload-time = "2024-12-18T11:29:31.338Z" }, - { url = "https://files.pythonhosted.org/packages/a4/99/bddde3ddde76c03b65dfd5a66ab436c4e58ffc42927d4ff1198ffbf96f5f/pydantic_core-2.27.2-cp313-cp313-win32.whl", hash = "sha256:1ebaf1d0481914d004a573394f4be3a7616334be70261007e47c2a6fe7e50130", size = 1834387, upload-time = "2024-12-18T11:29:33.481Z" }, - { url = "https://files.pythonhosted.org/packages/71/47/82b5e846e01b26ac6f1893d3c5f9f3a2eb6ba79be26eef0b759b4fe72946/pydantic_core-2.27.2-cp313-cp313-win_amd64.whl", hash = "sha256:953101387ecf2f5652883208769a79e48db18c6df442568a0b5ccd8c2723abee", size = 1990453, upload-time = "2024-12-18T11:29:35.533Z" }, - { url = "https://files.pythonhosted.org/packages/51/b2/b2b50d5ecf21acf870190ae5d093602d95f66c9c31f9d5de6062eb329ad1/pydantic_core-2.27.2-cp313-cp313-win_arm64.whl", hash = "sha256:ac4dbfd1691affb8f48c2c13241a2e3b60ff23247cbcf981759c768b6633cf8b", size = 1885186, upload-time = "2024-12-18T11:29:37.649Z" }, - { url = "https://files.pythonhosted.org/packages/46/72/af70981a341500419e67d5cb45abe552a7c74b66326ac8877588488da1ac/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:2bf14caea37e91198329b828eae1618c068dfb8ef17bb33287a7ad4b61ac314e", size = 1891159, upload-time = "2024-12-18T11:30:54.382Z" }, - { url = "https://files.pythonhosted.org/packages/ad/3d/c5913cccdef93e0a6a95c2d057d2c2cba347815c845cda79ddd3c0f5e17d/pydantic_core-2.27.2-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:b0cb791f5b45307caae8810c2023a184c74605ec3bcbb67d13846c28ff731ff8", size = 1768331, upload-time = "2024-12-18T11:30:58.178Z" }, - { url = "https://files.pythonhosted.org/packages/f6/f0/a3ae8fbee269e4934f14e2e0e00928f9346c5943174f2811193113e58252/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:688d3fd9fcb71f41c4c015c023d12a79d1c4c0732ec9eb35d96e3388a120dcf3", size = 1822467, upload-time = "2024-12-18T11:31:00.6Z" }, - { url = "https://files.pythonhosted.org/packages/d7/7a/7bbf241a04e9f9ea24cd5874354a83526d639b02674648af3f350554276c/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d591580c34f4d731592f0e9fe40f9cc1b430d297eecc70b962e93c5c668f15f", size = 1979797, upload-time = "2024-12-18T11:31:07.243Z" }, - { url = "https://files.pythonhosted.org/packages/4f/5f/4784c6107731f89e0005a92ecb8a2efeafdb55eb992b8e9d0a2be5199335/pydantic_core-2.27.2-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:82f986faf4e644ffc189a7f1aafc86e46ef70372bb153e7001e8afccc6e54133", size = 1987839, upload-time = "2024-12-18T11:31:09.775Z" }, - { url = "https://files.pythonhosted.org/packages/6d/a7/61246562b651dff00de86a5f01b6e4befb518df314c54dec187a78d81c84/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_aarch64.whl", hash = "sha256:bec317a27290e2537f922639cafd54990551725fc844249e64c523301d0822fc", size = 1998861, upload-time = "2024-12-18T11:31:13.469Z" }, - { url = "https://files.pythonhosted.org/packages/86/aa/837821ecf0c022bbb74ca132e117c358321e72e7f9702d1b6a03758545e2/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_armv7l.whl", hash = "sha256:0296abcb83a797db256b773f45773da397da75a08f5fcaef41f2044adec05f50", size = 2116582, upload-time = "2024-12-18T11:31:17.423Z" }, - { url = "https://files.pythonhosted.org/packages/81/b0/5e74656e95623cbaa0a6278d16cf15e10a51f6002e3ec126541e95c29ea3/pydantic_core-2.27.2-pp310-pypy310_pp73-musllinux_1_1_x86_64.whl", hash = "sha256:0d75070718e369e452075a6017fbf187f788e17ed67a3abd47fa934d001863d9", size = 2151985, upload-time = "2024-12-18T11:31:19.901Z" }, - { url = "https://files.pythonhosted.org/packages/63/37/3e32eeb2a451fddaa3898e2163746b0cffbbdbb4740d38372db0490d67f3/pydantic_core-2.27.2-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:7e17b560be3c98a8e3aa66ce828bdebb9e9ac6ad5466fba92eb74c4c95cb1151", size = 2004715, upload-time = "2024-12-18T11:31:22.821Z" }, -] - -[[package]] -name = "pydantic-settings" -version = "2.9.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "pydantic" }, - { name = "python-dotenv" }, - { name = "typing-inspection" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/67/1d/42628a2c33e93f8e9acbde0d5d735fa0850f3e6a2f8cb1eb6c40b9a732ac/pydantic_settings-2.9.1.tar.gz", hash = "sha256:c509bf79d27563add44e8446233359004ed85066cd096d8b510f715e6ef5d268", size = 163234, upload-time = "2025-04-18T16:44:48.265Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b6/5f/d6d641b490fd3ec2c4c13b4244d68deea3a1b970a97be64f34fb5504ff72/pydantic_settings-2.9.1-py3-none-any.whl", hash = "sha256:59b4f431b1defb26fe620c71a7d3968a710d719f5f4cdbbdb7926edeb770f6ef", size = 44356, upload-time = "2025-04-18T16:44:46.617Z" }, -] - -[[package]] -name = "pygments" -version = "2.19.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/7c/2d/c3338d48ea6cc0feb8446d8e6937e1408088a72a39937982cc6111d17f84/pygments-2.19.1.tar.gz", hash = "sha256:61c16d2a8576dc0649d9f39e089b5f02bcd27fba10d8fb4dcc28173f7a45151f", size = 4968581, upload-time = "2025-01-06T17:26:30.443Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8a/0b/9fcc47d19c48b59121088dd6da2488a49d5f72dacf8262e2790a1d2c7d15/pygments-2.19.1-py3-none-any.whl", hash = "sha256:9ea1544ad55cecf4b8242fab6dd35a93bbce657034b0611ee383099054ab6d8c", size = 1225293, upload-time = "2025-01-06T17:26:25.553Z" }, -] - -[[package]] -name = "python-dotenv" -version = "1.1.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/88/2c/7bb1416c5620485aa793f2de31d3df393d3686aa8a8506d11e10e13c5baf/python_dotenv-1.1.0.tar.gz", hash = "sha256:41f90bc6f5f177fb41f53e87666db362025010eb28f60a01c9143bfa33a2b2d5", size = 39920, upload-time = "2025-03-25T10:14:56.835Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/18/98a99ad95133c6a6e2005fe89faedf294a748bd5dc803008059409ac9b1e/python_dotenv-1.1.0-py3-none-any.whl", hash = "sha256:d7c01d9e2293916c18baf562d95698754b0dbbb5e74d457c45d4f6561fb9d55d", size = 20256, upload-time = "2025-03-25T10:14:55.034Z" }, -] - -[[package]] -name = "python-multipart" -version = "0.0.20" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/f3/87/f44d7c9f274c7ee665a29b885ec97089ec5dc034c7f3fafa03da9e39a09e/python_multipart-0.0.20.tar.gz", hash = "sha256:8dd0cab45b8e23064ae09147625994d090fa46f5b0d1e13af944c331a7fa9d13", size = 37158, upload-time = "2024-12-16T19:45:46.972Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/45/58/38b5afbc1a800eeea951b9285d3912613f2603bdf897a4ab0f4bd7f405fc/python_multipart-0.0.20-py3-none-any.whl", hash = "sha256:8a62d3a8335e06589fe01f2a3e178cdcc632f3fbe0d492ad9ee0ec35aab1f104", size = 24546, upload-time = "2024-12-16T19:45:44.423Z" }, -] - -[[package]] -name = "pyunormalize" -version = "16.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b3/08/568036c725dac746ecb267bb749ef930fb7907454fe69fce83c8557287fb/pyunormalize-16.0.0.tar.gz", hash = "sha256:2e1dfbb4a118154ae26f70710426a52a364b926c9191f764601f5a8cb12761f7", size = 49968, upload-time = "2024-09-17T17:08:18.245Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/39/f9/9d86e56f716e0651194a5ad58be9c146fcaf1de6901ac6f3cd3affeeb74e/pyunormalize-16.0.0-py3-none-any.whl", hash = "sha256:c647d95e5d1e2ea9a2f448d1d95d8518348df24eab5c3fd32d2b5c3300a49152", size = 49173, upload-time = "2024-09-17T17:08:17.078Z" }, -] - -[[package]] -name = "pywin32" -version = "310" -source = { registry = "https://pypi.org/simple" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/da/a5f38fffbba2fb99aa4aa905480ac4b8e83ca486659ac8c95bce47fb5276/pywin32-310-cp310-cp310-win32.whl", hash = "sha256:6dd97011efc8bf51d6793a82292419eba2c71cf8e7250cfac03bba284454abc1", size = 8848240, upload-time = "2025-03-17T00:55:46.783Z" }, - { url = "https://files.pythonhosted.org/packages/aa/fe/d873a773324fa565619ba555a82c9dabd677301720f3660a731a5d07e49a/pywin32-310-cp310-cp310-win_amd64.whl", hash = "sha256:c3e78706e4229b915a0821941a84e7ef420bf2b77e08c9dae3c76fd03fd2ae3d", size = 9601854, upload-time = "2025-03-17T00:55:48.783Z" }, - { url = "https://files.pythonhosted.org/packages/3c/84/1a8e3d7a15490d28a5d816efa229ecb4999cdc51a7c30dd8914f669093b8/pywin32-310-cp310-cp310-win_arm64.whl", hash = "sha256:33babed0cf0c92a6f94cc6cc13546ab24ee13e3e800e61ed87609ab91e4c8213", size = 8522963, upload-time = "2025-03-17T00:55:50.969Z" }, - { url = "https://files.pythonhosted.org/packages/f7/b1/68aa2986129fb1011dabbe95f0136f44509afaf072b12b8f815905a39f33/pywin32-310-cp311-cp311-win32.whl", hash = "sha256:1e765f9564e83011a63321bb9d27ec456a0ed90d3732c4b2e312b855365ed8bd", size = 8784284, upload-time = "2025-03-17T00:55:53.124Z" }, - { url = "https://files.pythonhosted.org/packages/b3/bd/d1592635992dd8db5bb8ace0551bc3a769de1ac8850200cfa517e72739fb/pywin32-310-cp311-cp311-win_amd64.whl", hash = "sha256:126298077a9d7c95c53823934f000599f66ec9296b09167810eb24875f32689c", size = 9520748, upload-time = "2025-03-17T00:55:55.203Z" }, - { url = "https://files.pythonhosted.org/packages/90/b1/ac8b1ffce6603849eb45a91cf126c0fa5431f186c2e768bf56889c46f51c/pywin32-310-cp311-cp311-win_arm64.whl", hash = "sha256:19ec5fc9b1d51c4350be7bb00760ffce46e6c95eaf2f0b2f1150657b1a43c582", size = 8455941, upload-time = "2025-03-17T00:55:57.048Z" }, - { url = "https://files.pythonhosted.org/packages/6b/ec/4fdbe47932f671d6e348474ea35ed94227fb5df56a7c30cbbb42cd396ed0/pywin32-310-cp312-cp312-win32.whl", hash = "sha256:8a75a5cc3893e83a108c05d82198880704c44bbaee4d06e442e471d3c9ea4f3d", size = 8796239, upload-time = "2025-03-17T00:55:58.807Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e5/b0627f8bb84e06991bea89ad8153a9e50ace40b2e1195d68e9dff6b03d0f/pywin32-310-cp312-cp312-win_amd64.whl", hash = "sha256:bf5c397c9a9a19a6f62f3fb821fbf36cac08f03770056711f765ec1503972060", size = 9503839, upload-time = "2025-03-17T00:56:00.8Z" }, - { url = "https://files.pythonhosted.org/packages/1f/32/9ccf53748df72301a89713936645a664ec001abd35ecc8578beda593d37d/pywin32-310-cp312-cp312-win_arm64.whl", hash = "sha256:2349cc906eae872d0663d4d6290d13b90621eaf78964bb1578632ff20e152966", size = 8459470, upload-time = "2025-03-17T00:56:02.601Z" }, - { url = "https://files.pythonhosted.org/packages/1c/09/9c1b978ffc4ae53999e89c19c77ba882d9fce476729f23ef55211ea1c034/pywin32-310-cp313-cp313-win32.whl", hash = "sha256:5d241a659c496ada3253cd01cfaa779b048e90ce4b2b38cd44168ad555ce74ab", size = 8794384, upload-time = "2025-03-17T00:56:04.383Z" }, - { url = "https://files.pythonhosted.org/packages/45/3c/b4640f740ffebadd5d34df35fecba0e1cfef8fde9f3e594df91c28ad9b50/pywin32-310-cp313-cp313-win_amd64.whl", hash = "sha256:667827eb3a90208ddbdcc9e860c81bde63a135710e21e4cb3348968e4bd5249e", size = 9503039, upload-time = "2025-03-17T00:56:06.207Z" }, - { url = "https://files.pythonhosted.org/packages/b4/f4/f785020090fb050e7fb6d34b780f2231f302609dc964672f72bfaeb59a28/pywin32-310-cp313-cp313-win_arm64.whl", hash = "sha256:e308f831de771482b7cf692a1f308f8fca701b2d8f9dde6cc440c7da17e47b33", size = 8458152, upload-time = "2025-03-17T00:56:07.819Z" }, -] - -[[package]] -name = "pyyaml" -version = "6.0.2" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/54/ed/79a089b6be93607fa5cdaedf301d7dfb23af5f25c398d5ead2525b063e17/pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e", size = 130631, upload-time = "2024-08-06T20:33:50.674Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/9b/95/a3fac87cb7158e231b5a6012e438c647e1a87f09f8e0d123acec8ab8bf71/PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086", size = 184199, upload-time = "2024-08-06T20:31:40.178Z" }, - { url = "https://files.pythonhosted.org/packages/c7/7a/68bd47624dab8fd4afbfd3c48e3b79efe09098ae941de5b58abcbadff5cb/PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf", size = 171758, upload-time = "2024-08-06T20:31:42.173Z" }, - { url = "https://files.pythonhosted.org/packages/49/ee/14c54df452143b9ee9f0f29074d7ca5516a36edb0b4cc40c3f280131656f/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237", size = 718463, upload-time = "2024-08-06T20:31:44.263Z" }, - { url = "https://files.pythonhosted.org/packages/4d/61/de363a97476e766574650d742205be468921a7b532aa2499fcd886b62530/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b", size = 719280, upload-time = "2024-08-06T20:31:50.199Z" }, - { url = "https://files.pythonhosted.org/packages/6b/4e/1523cb902fd98355e2e9ea5e5eb237cbc5f3ad5f3075fa65087aa0ecb669/PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed", size = 751239, upload-time = "2024-08-06T20:31:52.292Z" }, - { url = "https://files.pythonhosted.org/packages/b7/33/5504b3a9a4464893c32f118a9cc045190a91637b119a9c881da1cf6b7a72/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180", size = 695802, upload-time = "2024-08-06T20:31:53.836Z" }, - { url = "https://files.pythonhosted.org/packages/5c/20/8347dcabd41ef3a3cdc4f7b7a2aff3d06598c8779faa189cdbf878b626a4/PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68", size = 720527, upload-time = "2024-08-06T20:31:55.565Z" }, - { url = "https://files.pythonhosted.org/packages/be/aa/5afe99233fb360d0ff37377145a949ae258aaab831bde4792b32650a4378/PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99", size = 144052, upload-time = "2024-08-06T20:31:56.914Z" }, - { url = "https://files.pythonhosted.org/packages/b5/84/0fa4b06f6d6c958d207620fc60005e241ecedceee58931bb20138e1e5776/PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e", size = 161774, upload-time = "2024-08-06T20:31:58.304Z" }, - { url = "https://files.pythonhosted.org/packages/f8/aa/7af4e81f7acba21a4c6be026da38fd2b872ca46226673c89a758ebdc4fd2/PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774", size = 184612, upload-time = "2024-08-06T20:32:03.408Z" }, - { url = "https://files.pythonhosted.org/packages/8b/62/b9faa998fd185f65c1371643678e4d58254add437edb764a08c5a98fb986/PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee", size = 172040, upload-time = "2024-08-06T20:32:04.926Z" }, - { url = "https://files.pythonhosted.org/packages/ad/0c/c804f5f922a9a6563bab712d8dcc70251e8af811fce4524d57c2c0fd49a4/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c", size = 736829, upload-time = "2024-08-06T20:32:06.459Z" }, - { url = "https://files.pythonhosted.org/packages/51/16/6af8d6a6b210c8e54f1406a6b9481febf9c64a3109c541567e35a49aa2e7/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317", size = 764167, upload-time = "2024-08-06T20:32:08.338Z" }, - { url = "https://files.pythonhosted.org/packages/75/e4/2c27590dfc9992f73aabbeb9241ae20220bd9452df27483b6e56d3975cc5/PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85", size = 762952, upload-time = "2024-08-06T20:32:14.124Z" }, - { url = "https://files.pythonhosted.org/packages/9b/97/ecc1abf4a823f5ac61941a9c00fe501b02ac3ab0e373c3857f7d4b83e2b6/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4", size = 735301, upload-time = "2024-08-06T20:32:16.17Z" }, - { url = "https://files.pythonhosted.org/packages/45/73/0f49dacd6e82c9430e46f4a027baa4ca205e8b0a9dce1397f44edc23559d/PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e", size = 756638, upload-time = "2024-08-06T20:32:18.555Z" }, - { url = "https://files.pythonhosted.org/packages/22/5f/956f0f9fc65223a58fbc14459bf34b4cc48dec52e00535c79b8db361aabd/PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5", size = 143850, upload-time = "2024-08-06T20:32:19.889Z" }, - { url = "https://files.pythonhosted.org/packages/ed/23/8da0bbe2ab9dcdd11f4f4557ccaf95c10b9811b13ecced089d43ce59c3c8/PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44", size = 161980, upload-time = "2024-08-06T20:32:21.273Z" }, - { url = "https://files.pythonhosted.org/packages/86/0c/c581167fc46d6d6d7ddcfb8c843a4de25bdd27e4466938109ca68492292c/PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab", size = 183873, upload-time = "2024-08-06T20:32:25.131Z" }, - { url = "https://files.pythonhosted.org/packages/a8/0c/38374f5bb272c051e2a69281d71cba6fdb983413e6758b84482905e29a5d/PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725", size = 173302, upload-time = "2024-08-06T20:32:26.511Z" }, - { url = "https://files.pythonhosted.org/packages/c3/93/9916574aa8c00aa06bbac729972eb1071d002b8e158bd0e83a3b9a20a1f7/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5", size = 739154, upload-time = "2024-08-06T20:32:28.363Z" }, - { url = "https://files.pythonhosted.org/packages/95/0f/b8938f1cbd09739c6da569d172531567dbcc9789e0029aa070856f123984/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425", size = 766223, upload-time = "2024-08-06T20:32:30.058Z" }, - { url = "https://files.pythonhosted.org/packages/b9/2b/614b4752f2e127db5cc206abc23a8c19678e92b23c3db30fc86ab731d3bd/PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476", size = 767542, upload-time = "2024-08-06T20:32:31.881Z" }, - { url = "https://files.pythonhosted.org/packages/d4/00/dd137d5bcc7efea1836d6264f049359861cf548469d18da90cd8216cf05f/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48", size = 731164, upload-time = "2024-08-06T20:32:37.083Z" }, - { url = "https://files.pythonhosted.org/packages/c9/1f/4f998c900485e5c0ef43838363ba4a9723ac0ad73a9dc42068b12aaba4e4/PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b", size = 756611, upload-time = "2024-08-06T20:32:38.898Z" }, - { url = "https://files.pythonhosted.org/packages/df/d1/f5a275fdb252768b7a11ec63585bc38d0e87c9e05668a139fea92b80634c/PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4", size = 140591, upload-time = "2024-08-06T20:32:40.241Z" }, - { url = "https://files.pythonhosted.org/packages/0c/e8/4f648c598b17c3d06e8753d7d13d57542b30d56e6c2dedf9c331ae56312e/PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8", size = 156338, upload-time = "2024-08-06T20:32:41.93Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e3/3af305b830494fa85d95f6d95ef7fa73f2ee1cc8ef5b495c7c3269fb835f/PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba", size = 181309, upload-time = "2024-08-06T20:32:43.4Z" }, - { url = "https://files.pythonhosted.org/packages/45/9f/3b1c20a0b7a3200524eb0076cc027a970d320bd3a6592873c85c92a08731/PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1", size = 171679, upload-time = "2024-08-06T20:32:44.801Z" }, - { url = "https://files.pythonhosted.org/packages/7c/9a/337322f27005c33bcb656c655fa78325b730324c78620e8328ae28b64d0c/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133", size = 733428, upload-time = "2024-08-06T20:32:46.432Z" }, - { url = "https://files.pythonhosted.org/packages/a3/69/864fbe19e6c18ea3cc196cbe5d392175b4cf3d5d0ac1403ec3f2d237ebb5/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484", size = 763361, upload-time = "2024-08-06T20:32:51.188Z" }, - { url = "https://files.pythonhosted.org/packages/04/24/b7721e4845c2f162d26f50521b825fb061bc0a5afcf9a386840f23ea19fa/PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5", size = 759523, upload-time = "2024-08-06T20:32:53.019Z" }, - { url = "https://files.pythonhosted.org/packages/2b/b2/e3234f59ba06559c6ff63c4e10baea10e5e7df868092bf9ab40e5b9c56b6/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc", size = 726660, upload-time = "2024-08-06T20:32:54.708Z" }, - { url = "https://files.pythonhosted.org/packages/fe/0f/25911a9f080464c59fab9027482f822b86bf0608957a5fcc6eaac85aa515/PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652", size = 751597, upload-time = "2024-08-06T20:32:56.985Z" }, - { url = "https://files.pythonhosted.org/packages/14/0d/e2c3b43bbce3cf6bd97c840b46088a3031085179e596d4929729d8d68270/PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183", size = 140527, upload-time = "2024-08-06T20:33:03.001Z" }, - { url = "https://files.pythonhosted.org/packages/fa/de/02b54f42487e3d3c6efb3f89428677074ca7bf43aae402517bc7cca949f3/PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563", size = 156446, upload-time = "2024-08-06T20:33:04.33Z" }, -] - -[[package]] -name = "regex" -version = "2024.11.6" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8e/5f/bd69653fbfb76cf8604468d3b4ec4c403197144c7bfe0e6a5fc9e02a07cb/regex-2024.11.6.tar.gz", hash = "sha256:7ab159b063c52a0333c884e4679f8d7a85112ee3078fe3d9004b2dd875585519", size = 399494, upload-time = "2024-11-06T20:12:31.635Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/95/3c/4651f6b130c6842a8f3df82461a8950f923925db8b6961063e82744bddcc/regex-2024.11.6-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ff590880083d60acc0433f9c3f713c51f7ac6ebb9adf889c79a261ecf541aa91", size = 482674, upload-time = "2024-11-06T20:08:57.575Z" }, - { url = "https://files.pythonhosted.org/packages/15/51/9f35d12da8434b489c7b7bffc205c474a0a9432a889457026e9bc06a297a/regex-2024.11.6-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:658f90550f38270639e83ce492f27d2c8d2cd63805c65a13a14d36ca126753f0", size = 287684, upload-time = "2024-11-06T20:08:59.787Z" }, - { url = "https://files.pythonhosted.org/packages/bd/18/b731f5510d1b8fb63c6b6d3484bfa9a59b84cc578ac8b5172970e05ae07c/regex-2024.11.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:164d8b7b3b4bcb2068b97428060b2a53be050085ef94eca7f240e7947f1b080e", size = 284589, upload-time = "2024-11-06T20:09:01.896Z" }, - { url = "https://files.pythonhosted.org/packages/78/a2/6dd36e16341ab95e4c6073426561b9bfdeb1a9c9b63ab1b579c2e96cb105/regex-2024.11.6-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d3660c82f209655a06b587d55e723f0b813d3a7db2e32e5e7dc64ac2a9e86fde", size = 782511, upload-time = "2024-11-06T20:09:04.062Z" }, - { url = "https://files.pythonhosted.org/packages/1b/2b/323e72d5d2fd8de0d9baa443e1ed70363ed7e7b2fb526f5950c5cb99c364/regex-2024.11.6-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d22326fcdef5e08c154280b71163ced384b428343ae16a5ab2b3354aed12436e", size = 821149, upload-time = "2024-11-06T20:09:06.237Z" }, - { url = "https://files.pythonhosted.org/packages/90/30/63373b9ea468fbef8a907fd273e5c329b8c9535fee36fc8dba5fecac475d/regex-2024.11.6-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f1ac758ef6aebfc8943560194e9fd0fa18bcb34d89fd8bd2af18183afd8da3a2", size = 809707, upload-time = "2024-11-06T20:09:07.715Z" }, - { url = "https://files.pythonhosted.org/packages/f2/98/26d3830875b53071f1f0ae6d547f1d98e964dd29ad35cbf94439120bb67a/regex-2024.11.6-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:997d6a487ff00807ba810e0f8332c18b4eb8d29463cfb7c820dc4b6e7562d0cf", size = 781702, upload-time = "2024-11-06T20:09:10.101Z" }, - { url = "https://files.pythonhosted.org/packages/87/55/eb2a068334274db86208ab9d5599ffa63631b9f0f67ed70ea7c82a69bbc8/regex-2024.11.6-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:02a02d2bb04fec86ad61f3ea7f49c015a0681bf76abb9857f945d26159d2968c", size = 771976, upload-time = "2024-11-06T20:09:11.566Z" }, - { url = "https://files.pythonhosted.org/packages/74/c0/be707bcfe98254d8f9d2cff55d216e946f4ea48ad2fd8cf1428f8c5332ba/regex-2024.11.6-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f02f93b92358ee3f78660e43b4b0091229260c5d5c408d17d60bf26b6c900e86", size = 697397, upload-time = "2024-11-06T20:09:13.119Z" }, - { url = "https://files.pythonhosted.org/packages/49/dc/bb45572ceb49e0f6509f7596e4ba7031f6819ecb26bc7610979af5a77f45/regex-2024.11.6-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:06eb1be98df10e81ebaded73fcd51989dcf534e3c753466e4b60c4697a003b67", size = 768726, upload-time = "2024-11-06T20:09:14.85Z" }, - { url = "https://files.pythonhosted.org/packages/5a/db/f43fd75dc4c0c2d96d0881967897926942e935d700863666f3c844a72ce6/regex-2024.11.6-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:040df6fe1a5504eb0f04f048e6d09cd7c7110fef851d7c567a6b6e09942feb7d", size = 775098, upload-time = "2024-11-06T20:09:16.504Z" }, - { url = "https://files.pythonhosted.org/packages/99/d7/f94154db29ab5a89d69ff893159b19ada89e76b915c1293e98603d39838c/regex-2024.11.6-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:fdabbfc59f2c6edba2a6622c647b716e34e8e3867e0ab975412c5c2f79b82da2", size = 839325, upload-time = "2024-11-06T20:09:18.698Z" }, - { url = "https://files.pythonhosted.org/packages/f7/17/3cbfab1f23356fbbf07708220ab438a7efa1e0f34195bf857433f79f1788/regex-2024.11.6-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:8447d2d39b5abe381419319f942de20b7ecd60ce86f16a23b0698f22e1b70008", size = 843277, upload-time = "2024-11-06T20:09:21.725Z" }, - { url = "https://files.pythonhosted.org/packages/7e/f2/48b393b51900456155de3ad001900f94298965e1cad1c772b87f9cfea011/regex-2024.11.6-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:da8f5fc57d1933de22a9e23eec290a0d8a5927a5370d24bda9a6abe50683fe62", size = 773197, upload-time = "2024-11-06T20:09:24.092Z" }, - { url = "https://files.pythonhosted.org/packages/45/3f/ef9589aba93e084cd3f8471fded352826dcae8489b650d0b9b27bc5bba8a/regex-2024.11.6-cp310-cp310-win32.whl", hash = "sha256:b489578720afb782f6ccf2840920f3a32e31ba28a4b162e13900c3e6bd3f930e", size = 261714, upload-time = "2024-11-06T20:09:26.36Z" }, - { url = "https://files.pythonhosted.org/packages/42/7e/5f1b92c8468290c465fd50c5318da64319133231415a8aa6ea5ab995a815/regex-2024.11.6-cp310-cp310-win_amd64.whl", hash = "sha256:5071b2093e793357c9d8b2929dfc13ac5f0a6c650559503bb81189d0a3814519", size = 274042, upload-time = "2024-11-06T20:09:28.762Z" }, - { url = "https://files.pythonhosted.org/packages/58/58/7e4d9493a66c88a7da6d205768119f51af0f684fe7be7bac8328e217a52c/regex-2024.11.6-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:5478c6962ad548b54a591778e93cd7c456a7a29f8eca9c49e4f9a806dcc5d638", size = 482669, upload-time = "2024-11-06T20:09:31.064Z" }, - { url = "https://files.pythonhosted.org/packages/34/4c/8f8e631fcdc2ff978609eaeef1d6994bf2f028b59d9ac67640ed051f1218/regex-2024.11.6-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:2c89a8cc122b25ce6945f0423dc1352cb9593c68abd19223eebbd4e56612c5b7", size = 287684, upload-time = "2024-11-06T20:09:32.915Z" }, - { url = "https://files.pythonhosted.org/packages/c5/1b/f0e4d13e6adf866ce9b069e191f303a30ab1277e037037a365c3aad5cc9c/regex-2024.11.6-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:94d87b689cdd831934fa3ce16cc15cd65748e6d689f5d2b8f4f4df2065c9fa20", size = 284589, upload-time = "2024-11-06T20:09:35.504Z" }, - { url = "https://files.pythonhosted.org/packages/25/4d/ab21047f446693887f25510887e6820b93f791992994f6498b0318904d4a/regex-2024.11.6-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1062b39a0a2b75a9c694f7a08e7183a80c63c0d62b301418ffd9c35f55aaa114", size = 792121, upload-time = "2024-11-06T20:09:37.701Z" }, - { url = "https://files.pythonhosted.org/packages/45/ee/c867e15cd894985cb32b731d89576c41a4642a57850c162490ea34b78c3b/regex-2024.11.6-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:167ed4852351d8a750da48712c3930b031f6efdaa0f22fa1933716bfcd6bf4a3", size = 831275, upload-time = "2024-11-06T20:09:40.371Z" }, - { url = "https://files.pythonhosted.org/packages/b3/12/b0f480726cf1c60f6536fa5e1c95275a77624f3ac8fdccf79e6727499e28/regex-2024.11.6-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2d548dafee61f06ebdb584080621f3e0c23fff312f0de1afc776e2a2ba99a74f", size = 818257, upload-time = "2024-11-06T20:09:43.059Z" }, - { url = "https://files.pythonhosted.org/packages/bf/ce/0d0e61429f603bac433910d99ef1a02ce45a8967ffbe3cbee48599e62d88/regex-2024.11.6-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f2a19f302cd1ce5dd01a9099aaa19cae6173306d1302a43b627f62e21cf18ac0", size = 792727, upload-time = "2024-11-06T20:09:48.19Z" }, - { url = "https://files.pythonhosted.org/packages/e4/c1/243c83c53d4a419c1556f43777ccb552bccdf79d08fda3980e4e77dd9137/regex-2024.11.6-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bec9931dfb61ddd8ef2ebc05646293812cb6b16b60cf7c9511a832b6f1854b55", size = 780667, upload-time = "2024-11-06T20:09:49.828Z" }, - { url = "https://files.pythonhosted.org/packages/c5/f4/75eb0dd4ce4b37f04928987f1d22547ddaf6c4bae697623c1b05da67a8aa/regex-2024.11.6-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:9714398225f299aa85267fd222f7142fcb5c769e73d7733344efc46f2ef5cf89", size = 776963, upload-time = "2024-11-06T20:09:51.819Z" }, - { url = "https://files.pythonhosted.org/packages/16/5d/95c568574e630e141a69ff8a254c2f188b4398e813c40d49228c9bbd9875/regex-2024.11.6-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:202eb32e89f60fc147a41e55cb086db2a3f8cb82f9a9a88440dcfc5d37faae8d", size = 784700, upload-time = "2024-11-06T20:09:53.982Z" }, - { url = "https://files.pythonhosted.org/packages/8e/b5/f8495c7917f15cc6fee1e7f395e324ec3e00ab3c665a7dc9d27562fd5290/regex-2024.11.6-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:4181b814e56078e9b00427ca358ec44333765f5ca1b45597ec7446d3a1ef6e34", size = 848592, upload-time = "2024-11-06T20:09:56.222Z" }, - { url = "https://files.pythonhosted.org/packages/1c/80/6dd7118e8cb212c3c60b191b932dc57db93fb2e36fb9e0e92f72a5909af9/regex-2024.11.6-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:068376da5a7e4da51968ce4c122a7cd31afaaec4fccc7856c92f63876e57b51d", size = 852929, upload-time = "2024-11-06T20:09:58.642Z" }, - { url = "https://files.pythonhosted.org/packages/11/9b/5a05d2040297d2d254baf95eeeb6df83554e5e1df03bc1a6687fc4ba1f66/regex-2024.11.6-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:ac10f2c4184420d881a3475fb2c6f4d95d53a8d50209a2500723d831036f7c45", size = 781213, upload-time = "2024-11-06T20:10:00.867Z" }, - { url = "https://files.pythonhosted.org/packages/26/b7/b14e2440156ab39e0177506c08c18accaf2b8932e39fb092074de733d868/regex-2024.11.6-cp311-cp311-win32.whl", hash = "sha256:c36f9b6f5f8649bb251a5f3f66564438977b7ef8386a52460ae77e6070d309d9", size = 261734, upload-time = "2024-11-06T20:10:03.361Z" }, - { url = "https://files.pythonhosted.org/packages/80/32/763a6cc01d21fb3819227a1cc3f60fd251c13c37c27a73b8ff4315433a8e/regex-2024.11.6-cp311-cp311-win_amd64.whl", hash = "sha256:02e28184be537f0e75c1f9b2f8847dc51e08e6e171c6bde130b2687e0c33cf60", size = 274052, upload-time = "2024-11-06T20:10:05.179Z" }, - { url = "https://files.pythonhosted.org/packages/ba/30/9a87ce8336b172cc232a0db89a3af97929d06c11ceaa19d97d84fa90a8f8/regex-2024.11.6-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:52fb28f528778f184f870b7cf8f225f5eef0a8f6e3778529bdd40c7b3920796a", size = 483781, upload-time = "2024-11-06T20:10:07.07Z" }, - { url = "https://files.pythonhosted.org/packages/01/e8/00008ad4ff4be8b1844786ba6636035f7ef926db5686e4c0f98093612add/regex-2024.11.6-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:fdd6028445d2460f33136c55eeb1f601ab06d74cb3347132e1c24250187500d9", size = 288455, upload-time = "2024-11-06T20:10:09.117Z" }, - { url = "https://files.pythonhosted.org/packages/60/85/cebcc0aff603ea0a201667b203f13ba75d9fc8668fab917ac5b2de3967bc/regex-2024.11.6-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:805e6b60c54bf766b251e94526ebad60b7de0c70f70a4e6210ee2891acb70bf2", size = 284759, upload-time = "2024-11-06T20:10:11.155Z" }, - { url = "https://files.pythonhosted.org/packages/94/2b/701a4b0585cb05472a4da28ee28fdfe155f3638f5e1ec92306d924e5faf0/regex-2024.11.6-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b85c2530be953a890eaffde05485238f07029600e8f098cdf1848d414a8b45e4", size = 794976, upload-time = "2024-11-06T20:10:13.24Z" }, - { url = "https://files.pythonhosted.org/packages/4b/bf/fa87e563bf5fee75db8915f7352e1887b1249126a1be4813837f5dbec965/regex-2024.11.6-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bb26437975da7dc36b7efad18aa9dd4ea569d2357ae6b783bf1118dabd9ea577", size = 833077, upload-time = "2024-11-06T20:10:15.37Z" }, - { url = "https://files.pythonhosted.org/packages/a1/56/7295e6bad94b047f4d0834e4779491b81216583c00c288252ef625c01d23/regex-2024.11.6-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:abfa5080c374a76a251ba60683242bc17eeb2c9818d0d30117b4486be10c59d3", size = 823160, upload-time = "2024-11-06T20:10:19.027Z" }, - { url = "https://files.pythonhosted.org/packages/fb/13/e3b075031a738c9598c51cfbc4c7879e26729c53aa9cca59211c44235314/regex-2024.11.6-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b7fa6606c2881c1db9479b0eaa11ed5dfa11c8d60a474ff0e095099f39d98e", size = 796896, upload-time = "2024-11-06T20:10:21.85Z" }, - { url = "https://files.pythonhosted.org/packages/24/56/0b3f1b66d592be6efec23a795b37732682520b47c53da5a32c33ed7d84e3/regex-2024.11.6-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0c32f75920cf99fe6b6c539c399a4a128452eaf1af27f39bce8909c9a3fd8cbe", size = 783997, upload-time = "2024-11-06T20:10:24.329Z" }, - { url = "https://files.pythonhosted.org/packages/f9/a1/eb378dada8b91c0e4c5f08ffb56f25fcae47bf52ad18f9b2f33b83e6d498/regex-2024.11.6-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:982e6d21414e78e1f51cf595d7f321dcd14de1f2881c5dc6a6e23bbbbd68435e", size = 781725, upload-time = "2024-11-06T20:10:28.067Z" }, - { url = "https://files.pythonhosted.org/packages/83/f2/033e7dec0cfd6dda93390089864732a3409246ffe8b042e9554afa9bff4e/regex-2024.11.6-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:a7c2155f790e2fb448faed6dd241386719802296ec588a8b9051c1f5c481bc29", size = 789481, upload-time = "2024-11-06T20:10:31.612Z" }, - { url = "https://files.pythonhosted.org/packages/83/23/15d4552ea28990a74e7696780c438aadd73a20318c47e527b47a4a5a596d/regex-2024.11.6-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:149f5008d286636e48cd0b1dd65018548944e495b0265b45e1bffecce1ef7f39", size = 852896, upload-time = "2024-11-06T20:10:34.054Z" }, - { url = "https://files.pythonhosted.org/packages/e3/39/ed4416bc90deedbfdada2568b2cb0bc1fdb98efe11f5378d9892b2a88f8f/regex-2024.11.6-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:e5364a4502efca094731680e80009632ad6624084aff9a23ce8c8c6820de3e51", size = 860138, upload-time = "2024-11-06T20:10:36.142Z" }, - { url = "https://files.pythonhosted.org/packages/93/2d/dd56bb76bd8e95bbce684326302f287455b56242a4f9c61f1bc76e28360e/regex-2024.11.6-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0a86e7eeca091c09e021db8eb72d54751e527fa47b8d5787caf96d9831bd02ad", size = 787692, upload-time = "2024-11-06T20:10:38.394Z" }, - { url = "https://files.pythonhosted.org/packages/0b/55/31877a249ab7a5156758246b9c59539abbeba22461b7d8adc9e8475ff73e/regex-2024.11.6-cp312-cp312-win32.whl", hash = "sha256:32f9a4c643baad4efa81d549c2aadefaeba12249b2adc5af541759237eee1c54", size = 262135, upload-time = "2024-11-06T20:10:40.367Z" }, - { url = "https://files.pythonhosted.org/packages/38/ec/ad2d7de49a600cdb8dd78434a1aeffe28b9d6fc42eb36afab4a27ad23384/regex-2024.11.6-cp312-cp312-win_amd64.whl", hash = "sha256:a93c194e2df18f7d264092dc8539b8ffb86b45b899ab976aa15d48214138e81b", size = 273567, upload-time = "2024-11-06T20:10:43.467Z" }, - { url = "https://files.pythonhosted.org/packages/90/73/bcb0e36614601016552fa9344544a3a2ae1809dc1401b100eab02e772e1f/regex-2024.11.6-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:a6ba92c0bcdf96cbf43a12c717eae4bc98325ca3730f6b130ffa2e3c3c723d84", size = 483525, upload-time = "2024-11-06T20:10:45.19Z" }, - { url = "https://files.pythonhosted.org/packages/0f/3f/f1a082a46b31e25291d830b369b6b0c5576a6f7fb89d3053a354c24b8a83/regex-2024.11.6-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:525eab0b789891ac3be914d36893bdf972d483fe66551f79d3e27146191a37d4", size = 288324, upload-time = "2024-11-06T20:10:47.177Z" }, - { url = "https://files.pythonhosted.org/packages/09/c9/4e68181a4a652fb3ef5099e077faf4fd2a694ea6e0f806a7737aff9e758a/regex-2024.11.6-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:086a27a0b4ca227941700e0b31425e7a28ef1ae8e5e05a33826e17e47fbfdba0", size = 284617, upload-time = "2024-11-06T20:10:49.312Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/37868b75eaf63843165f1d2122ca6cb94bfc0271e4428cf58c0616786dce/regex-2024.11.6-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bde01f35767c4a7899b7eb6e823b125a64de314a8ee9791367c9a34d56af18d0", size = 795023, upload-time = "2024-11-06T20:10:51.102Z" }, - { url = "https://files.pythonhosted.org/packages/c4/7c/d4cd9c528502a3dedb5c13c146e7a7a539a3853dc20209c8e75d9ba9d1b2/regex-2024.11.6-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:b583904576650166b3d920d2bcce13971f6f9e9a396c673187f49811b2769dc7", size = 833072, upload-time = "2024-11-06T20:10:52.926Z" }, - { url = "https://files.pythonhosted.org/packages/4f/db/46f563a08f969159c5a0f0e722260568425363bea43bb7ae370becb66a67/regex-2024.11.6-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:1c4de13f06a0d54fa0d5ab1b7138bfa0d883220965a29616e3ea61b35d5f5fc7", size = 823130, upload-time = "2024-11-06T20:10:54.828Z" }, - { url = "https://files.pythonhosted.org/packages/db/60/1eeca2074f5b87df394fccaa432ae3fc06c9c9bfa97c5051aed70e6e00c2/regex-2024.11.6-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3cde6e9f2580eb1665965ce9bf17ff4952f34f5b126beb509fee8f4e994f143c", size = 796857, upload-time = "2024-11-06T20:10:56.634Z" }, - { url = "https://files.pythonhosted.org/packages/10/db/ac718a08fcee981554d2f7bb8402f1faa7e868c1345c16ab1ebec54b0d7b/regex-2024.11.6-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0d7f453dca13f40a02b79636a339c5b62b670141e63efd511d3f8f73fba162b3", size = 784006, upload-time = "2024-11-06T20:10:59.369Z" }, - { url = "https://files.pythonhosted.org/packages/c2/41/7da3fe70216cea93144bf12da2b87367590bcf07db97604edeea55dac9ad/regex-2024.11.6-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:59dfe1ed21aea057a65c6b586afd2a945de04fc7db3de0a6e3ed5397ad491b07", size = 781650, upload-time = "2024-11-06T20:11:02.042Z" }, - { url = "https://files.pythonhosted.org/packages/a7/d5/880921ee4eec393a4752e6ab9f0fe28009435417c3102fc413f3fe81c4e5/regex-2024.11.6-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:b97c1e0bd37c5cd7902e65f410779d39eeda155800b65fc4d04cc432efa9bc6e", size = 789545, upload-time = "2024-11-06T20:11:03.933Z" }, - { url = "https://files.pythonhosted.org/packages/dc/96/53770115e507081122beca8899ab7f5ae28ae790bfcc82b5e38976df6a77/regex-2024.11.6-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f9d1e379028e0fc2ae3654bac3cbbef81bf3fd571272a42d56c24007979bafb6", size = 853045, upload-time = "2024-11-06T20:11:06.497Z" }, - { url = "https://files.pythonhosted.org/packages/31/d3/1372add5251cc2d44b451bd94f43b2ec78e15a6e82bff6a290ef9fd8f00a/regex-2024.11.6-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:13291b39131e2d002a7940fb176e120bec5145f3aeb7621be6534e46251912c4", size = 860182, upload-time = "2024-11-06T20:11:09.06Z" }, - { url = "https://files.pythonhosted.org/packages/ed/e3/c446a64984ea9f69982ba1a69d4658d5014bc7a0ea468a07e1a1265db6e2/regex-2024.11.6-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:4f51f88c126370dcec4908576c5a627220da6c09d0bff31cfa89f2523843316d", size = 787733, upload-time = "2024-11-06T20:11:11.256Z" }, - { url = "https://files.pythonhosted.org/packages/2b/f1/e40c8373e3480e4f29f2692bd21b3e05f296d3afebc7e5dcf21b9756ca1c/regex-2024.11.6-cp313-cp313-win32.whl", hash = "sha256:63b13cfd72e9601125027202cad74995ab26921d8cd935c25f09c630436348ff", size = 262122, upload-time = "2024-11-06T20:11:13.161Z" }, - { url = "https://files.pythonhosted.org/packages/45/94/bc295babb3062a731f52621cdc992d123111282e291abaf23faa413443ea/regex-2024.11.6-cp313-cp313-win_amd64.whl", hash = "sha256:2b3361af3198667e99927da8b84c1b010752fa4b1115ee30beaa332cabc3ef1a", size = 273545, upload-time = "2024-11-06T20:11:15Z" }, -] - -[[package]] -name = "requests" -version = "2.32.4" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "certifi" }, - { name = "charset-normalizer" }, - { name = "idna" }, - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/e1/0a/929373653770d8a0d7ea76c37de6e41f11eb07559b103b1c02cafb3f7cf8/requests-2.32.4.tar.gz", hash = "sha256:27d0316682c8a29834d3264820024b62a36942083d52caf2f14c0591336d3422", size = 135258, upload-time = "2025-06-09T16:43:07.34Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/7c/e4/56027c4a6b4ae70ca9de302488c5ca95ad4a39e190093d6c1a8ace08341b/requests-2.32.4-py3-none-any.whl", hash = "sha256:27babd3cda2a6d50b30443204ee89830707d396671944c998b5975b031ac2b2c", size = 64847, upload-time = "2025-06-09T16:43:05.728Z" }, -] - -[[package]] -name = "rich" -version = "14.0.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markdown-it-py" }, - { name = "pygments" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/a1/53/830aa4c3066a8ab0ae9a9955976fb770fe9c6102117c8ec4ab3ea62d89e8/rich-14.0.0.tar.gz", hash = "sha256:82f1bc23a6a21ebca4ae0c45af9bdbc492ed20231dcb63f297d6d1021a9d5725", size = 224078, upload-time = "2025-03-30T14:15:14.23Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0d/9b/63f4c7ebc259242c89b3acafdb37b41d1185c07ff0011164674e9076b491/rich-14.0.0-py3-none-any.whl", hash = "sha256:1c9491e1951aac09caffd42f448ee3d04e58923ffe14993f6e83068dc395d7e0", size = 243229, upload-time = "2025-03-30T14:15:12.283Z" }, -] - -[[package]] -name = "rich-toolkit" -version = "0.14.7" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/5b/7a/cb48b7024b247631ce39b1f14a0f1abedf311fb27b892b0e0387d809d4b5/rich_toolkit-0.14.7.tar.gz", hash = "sha256:6cca5a68850cc5778915f528eb785662c27ba3b4b2624612cce8340fa9701c5e", size = 104977, upload-time = "2025-05-27T15:48:09.377Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0f/2e/95fde5b818dac9a37683ea064096323f593442d0f6358923c5f635974393/rich_toolkit-0.14.7-py3-none-any.whl", hash = "sha256:def05cc6e0f1176d6263b6a26648f16a62c4563b277ca2f8538683acdba1e0da", size = 24870, upload-time = "2025-05-27T15:48:07.942Z" }, -] - -[[package]] -name = "rlp" -version = "4.1.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "eth-utils" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/1b/2d/439b0728a92964a04d9c88ea1ca9ebb128893fbbd5834faa31f987f2fd4c/rlp-4.1.0.tar.gz", hash = "sha256:be07564270a96f3e225e2c107db263de96b5bc1f27722d2855bd3459a08e95a9", size = 33429, upload-time = "2025-02-04T22:05:59.089Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/99/fb/e4c0ced9893b84ac95b7181d69a9786ce5879aeb3bbbcbba80a164f85d6a/rlp-4.1.0-py3-none-any.whl", hash = "sha256:8eca394c579bad34ee0b937aecb96a57052ff3716e19c7a578883e767bc5da6f", size = 19973, upload-time = "2025-02-04T22:05:57.05Z" }, -] - -[[package]] -name = "shellingham" -version = "1.5.4" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/58/15/8b3609fd3830ef7b27b655beb4b4e9c62313a4e8da8c676e142cc210d58e/shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de", size = 10310, upload-time = "2023-10-24T04:13:40.426Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e0/f9/0595336914c5619e5f28a1fb793285925a8cd4b432c9da0a987836c7f822/shellingham-1.5.4-py2.py3-none-any.whl", hash = "sha256:7ecfff8f2fd72616f7481040475a65b2bf8af90a56c89140852d1120324e8686", size = 9755, upload-time = "2023-10-24T04:13:38.866Z" }, -] - -[[package]] -name = "sniffio" -version = "1.3.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/a2/87/a6771e1546d97e7e041b6ae58d80074f81b7d5121207425c964ddf5cfdbd/sniffio-1.3.1.tar.gz", hash = "sha256:f4324edc670a0f49750a81b895f35c3adb843cca46f0530f79fc1babb23789dc", size = 20372, upload-time = "2024-02-25T23:20:04.057Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/e9/44/75a9c9421471a6c4805dbf2356f7c181a29c1879239abab1ea2cc8f38b40/sniffio-1.3.1-py3-none-any.whl", hash = "sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2", size = 10235, upload-time = "2024-02-25T23:20:01.196Z" }, -] - -[[package]] -name = "starlette" -version = "0.46.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/ce/20/08dfcd9c983f6a6f4a1000d934b9e6d626cff8d2eeb77a89a68eef20a2b7/starlette-0.46.2.tar.gz", hash = "sha256:7f7361f34eed179294600af672f565727419830b54b7b084efe44bb82d2fccd5", size = 2580846, upload-time = "2025-04-13T13:56:17.942Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/8b/0c/9d30a4ebeb6db2b25a841afbb80f6ef9a854fc3b41be131d249a977b4959/starlette-0.46.2-py3-none-any.whl", hash = "sha256:595633ce89f8ffa71a015caed34a5b2dc1c0cdb3f0f1fbd1e69339cf2abeec35", size = 72037, upload-time = "2025-04-13T13:56:16.21Z" }, -] - -[[package]] -name = "toolz" -version = "1.0.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/0b/d80dfa675bf592f636d1ea0b835eab4ec8df6e9415d8cfd766df54456123/toolz-1.0.0.tar.gz", hash = "sha256:2c86e3d9a04798ac556793bced838816296a2f085017664e4995cb40a1047a02", size = 66790, upload-time = "2024-10-04T16:17:04.001Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/03/98/eb27cc78ad3af8e302c9d8ff4977f5026676e130d28dd7578132a457170c/toolz-1.0.0-py3-none-any.whl", hash = "sha256:292c8f1c4e7516bf9086f8850935c799a874039c8bcf959d47b600e4c44a6236", size = 56383, upload-time = "2024-10-04T16:17:01.533Z" }, -] - -[[package]] -name = "typer" -version = "0.16.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "rich" }, - { name = "shellingham" }, - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/c5/8c/7d682431efca5fd290017663ea4588bf6f2c6aad085c7f108c5dbc316e70/typer-0.16.0.tar.gz", hash = "sha256:af377ffaee1dbe37ae9440cb4e8f11686ea5ce4e9bae01b84ae7c63b87f1dd3b", size = 102625, upload-time = "2025-05-26T14:30:31.824Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/76/42/3efaf858001d2c2913de7f354563e3a3a2f0decae3efe98427125a8f441e/typer-0.16.0-py3-none-any.whl", hash = "sha256:1f79bed11d4d02d4310e3c1b7ba594183bcedb0ac73b27a9e5f28f6fb5b98855", size = 46317, upload-time = "2025-05-26T14:30:30.523Z" }, -] - -[[package]] -name = "types-requests" -version = "2.32.4.20250611" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "urllib3" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/6d/7f/73b3a04a53b0fd2a911d4ec517940ecd6600630b559e4505cc7b68beb5a0/types_requests-2.32.4.20250611.tar.gz", hash = "sha256:741c8777ed6425830bf51e54d6abe245f79b4dcb9019f1622b773463946bf826", size = 23118, upload-time = "2025-06-11T03:11:41.272Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/ea/0be9258c5a4fa1ba2300111aa5a0767ee6d18eb3fd20e91616c12082284d/types_requests-2.32.4.20250611-py3-none-any.whl", hash = "sha256:ad2fe5d3b0cb3c2c902c8815a70e7fb2302c4b8c1f77bdcd738192cdb3878072", size = 20643, upload-time = "2025-06-11T03:11:40.186Z" }, -] - -[[package]] -name = "typing-extensions" -version = "4.14.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/d1/bc/51647cd02527e87d05cb083ccc402f93e441606ff1f01739a62c8ad09ba5/typing_extensions-4.14.0.tar.gz", hash = "sha256:8676b788e32f02ab42d9e7c61324048ae4c6d844a399eebace3d4979d75ceef4", size = 107423, upload-time = "2025-06-02T14:52:11.399Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/69/e0/552843e0d356fbb5256d21449fa957fa4eff3bbc135a74a691ee70c7c5da/typing_extensions-4.14.0-py3-none-any.whl", hash = "sha256:a1514509136dd0b477638fc68d6a91497af5076466ad0fa6c338e44e359944af", size = 43839, upload-time = "2025-06-02T14:52:10.026Z" }, -] - -[[package]] -name = "typing-inspection" -version = "0.4.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "typing-extensions" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/f8/b1/0c11f5058406b3af7609f121aaa6b609744687f1d158b3c3a5bf4cc94238/typing_inspection-0.4.1.tar.gz", hash = "sha256:6ae134cc0203c33377d43188d4064e9b357dba58cff3185f22924610e70a9d28", size = 75726, upload-time = "2025-05-21T18:55:23.885Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/17/69/cd203477f944c353c31bade965f880aa1061fd6bf05ded0726ca845b6ff7/typing_inspection-0.4.1-py3-none-any.whl", hash = "sha256:389055682238f53b04f7badcb49b989835495a96700ced5dab2d8feae4b26f51", size = 14552, upload-time = "2025-05-21T18:55:22.152Z" }, -] - -[[package]] -name = "urllib3" -version = "2.4.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/8a/78/16493d9c386d8e60e442a35feac5e00f0913c0f4b7c217c11e8ec2ff53e0/urllib3-2.4.0.tar.gz", hash = "sha256:414bc6535b787febd7567804cc015fee39daab8ad86268f1310a9250697de466", size = 390672, upload-time = "2025-04-10T15:23:39.232Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6b/11/cc635220681e93a0183390e26485430ca2c7b5f9d33b15c74c2861cb8091/urllib3-2.4.0-py3-none-any.whl", hash = "sha256:4e16665048960a0900c702d4a66415956a584919c03361cac9f1df5c5dd7e813", size = 128680, upload-time = "2025-04-10T15:23:37.377Z" }, -] - -[[package]] -name = "uvicorn" -version = "0.34.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "click" }, - { name = "h11" }, - { name = "typing-extensions", marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/de/ad/713be230bcda622eaa35c28f0d328c3675c371238470abdea52417f17a8e/uvicorn-0.34.3.tar.gz", hash = "sha256:35919a9a979d7a59334b6b10e05d77c1d0d574c50e0fc98b8b1a0f165708b55a", size = 76631, upload-time = "2025-06-01T07:48:17.531Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/6d/0d/8adfeaa62945f90d19ddc461c55f4a50c258af7662d34b6a3d5d1f8646f6/uvicorn-0.34.3-py3-none-any.whl", hash = "sha256:16246631db62bdfbf069b0645177d6e8a77ba950cfedbfd093acef9444e4d885", size = 62431, upload-time = "2025-06-01T07:48:15.664Z" }, -] - -[package.optional-dependencies] -standard = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "httptools" }, - { name = "python-dotenv" }, - { name = "pyyaml" }, - { name = "uvloop", marker = "platform_python_implementation != 'PyPy' and sys_platform != 'cygwin' and sys_platform != 'win32'" }, - { name = "watchfiles" }, - { name = "websockets" }, -] - -[[package]] -name = "uvloop" -version = "0.21.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/af/c0/854216d09d33c543f12a44b393c402e89a920b1a0a7dc634c42de91b9cf6/uvloop-0.21.0.tar.gz", hash = "sha256:3bf12b0fda68447806a7ad847bfa591613177275d35b6724b1ee573faa3704e3", size = 2492741, upload-time = "2024-10-14T23:38:35.489Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/3d/76/44a55515e8c9505aa1420aebacf4dd82552e5e15691654894e90d0bd051a/uvloop-0.21.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:ec7e6b09a6fdded42403182ab6b832b71f4edaf7f37a9a0e371a01db5f0cb45f", size = 1442019, upload-time = "2024-10-14T23:37:20.068Z" }, - { url = "https://files.pythonhosted.org/packages/35/5a/62d5800358a78cc25c8a6c72ef8b10851bdb8cca22e14d9c74167b7f86da/uvloop-0.21.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:196274f2adb9689a289ad7d65700d37df0c0930fd8e4e743fa4834e850d7719d", size = 801898, upload-time = "2024-10-14T23:37:22.663Z" }, - { url = "https://files.pythonhosted.org/packages/f3/96/63695e0ebd7da6c741ccd4489b5947394435e198a1382349c17b1146bb97/uvloop-0.21.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f38b2e090258d051d68a5b14d1da7203a3c3677321cf32a95a6f4db4dd8b6f26", size = 3827735, upload-time = "2024-10-14T23:37:25.129Z" }, - { url = "https://files.pythonhosted.org/packages/61/e0/f0f8ec84979068ffae132c58c79af1de9cceeb664076beea86d941af1a30/uvloop-0.21.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:87c43e0f13022b998eb9b973b5e97200c8b90823454d4bc06ab33829e09fb9bb", size = 3825126, upload-time = "2024-10-14T23:37:27.59Z" }, - { url = "https://files.pythonhosted.org/packages/bf/fe/5e94a977d058a54a19df95f12f7161ab6e323ad49f4dabc28822eb2df7ea/uvloop-0.21.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:10d66943def5fcb6e7b37310eb6b5639fd2ccbc38df1177262b0640c3ca68c1f", size = 3705789, upload-time = "2024-10-14T23:37:29.385Z" }, - { url = "https://files.pythonhosted.org/packages/26/dd/c7179618e46092a77e036650c1f056041a028a35c4d76945089fcfc38af8/uvloop-0.21.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:67dd654b8ca23aed0a8e99010b4c34aca62f4b7fce88f39d452ed7622c94845c", size = 3800523, upload-time = "2024-10-14T23:37:32.048Z" }, - { url = "https://files.pythonhosted.org/packages/57/a7/4cf0334105c1160dd6819f3297f8700fda7fc30ab4f61fbf3e725acbc7cc/uvloop-0.21.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:c0f3fa6200b3108919f8bdabb9a7f87f20e7097ea3c543754cabc7d717d95cf8", size = 1447410, upload-time = "2024-10-14T23:37:33.612Z" }, - { url = "https://files.pythonhosted.org/packages/8c/7c/1517b0bbc2dbe784b563d6ab54f2ef88c890fdad77232c98ed490aa07132/uvloop-0.21.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:0878c2640cf341b269b7e128b1a5fed890adc4455513ca710d77d5e93aa6d6a0", size = 805476, upload-time = "2024-10-14T23:37:36.11Z" }, - { url = "https://files.pythonhosted.org/packages/ee/ea/0bfae1aceb82a503f358d8d2fa126ca9dbdb2ba9c7866974faec1cb5875c/uvloop-0.21.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9fb766bb57b7388745d8bcc53a359b116b8a04c83a2288069809d2b3466c37e", size = 3960855, upload-time = "2024-10-14T23:37:37.683Z" }, - { url = "https://files.pythonhosted.org/packages/8a/ca/0864176a649838b838f36d44bf31c451597ab363b60dc9e09c9630619d41/uvloop-0.21.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8a375441696e2eda1c43c44ccb66e04d61ceeffcd76e4929e527b7fa401b90fb", size = 3973185, upload-time = "2024-10-14T23:37:40.226Z" }, - { url = "https://files.pythonhosted.org/packages/30/bf/08ad29979a936d63787ba47a540de2132169f140d54aa25bc8c3df3e67f4/uvloop-0.21.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:baa0e6291d91649c6ba4ed4b2f982f9fa165b5bbd50a9e203c416a2797bab3c6", size = 3820256, upload-time = "2024-10-14T23:37:42.839Z" }, - { url = "https://files.pythonhosted.org/packages/da/e2/5cf6ef37e3daf2f06e651aae5ea108ad30df3cb269102678b61ebf1fdf42/uvloop-0.21.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4509360fcc4c3bd2c70d87573ad472de40c13387f5fda8cb58350a1d7475e58d", size = 3937323, upload-time = "2024-10-14T23:37:45.337Z" }, - { url = "https://files.pythonhosted.org/packages/8c/4c/03f93178830dc7ce8b4cdee1d36770d2f5ebb6f3d37d354e061eefc73545/uvloop-0.21.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:359ec2c888397b9e592a889c4d72ba3d6befba8b2bb01743f72fffbde663b59c", size = 1471284, upload-time = "2024-10-14T23:37:47.833Z" }, - { url = "https://files.pythonhosted.org/packages/43/3e/92c03f4d05e50f09251bd8b2b2b584a2a7f8fe600008bcc4523337abe676/uvloop-0.21.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:f7089d2dc73179ce5ac255bdf37c236a9f914b264825fdaacaded6990a7fb4c2", size = 821349, upload-time = "2024-10-14T23:37:50.149Z" }, - { url = "https://files.pythonhosted.org/packages/a6/ef/a02ec5da49909dbbfb1fd205a9a1ac4e88ea92dcae885e7c961847cd51e2/uvloop-0.21.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:baa4dcdbd9ae0a372f2167a207cd98c9f9a1ea1188a8a526431eef2f8116cc8d", size = 4580089, upload-time = "2024-10-14T23:37:51.703Z" }, - { url = "https://files.pythonhosted.org/packages/06/a7/b4e6a19925c900be9f98bec0a75e6e8f79bb53bdeb891916609ab3958967/uvloop-0.21.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:86975dca1c773a2c9864f4c52c5a55631038e387b47eaf56210f873887b6c8dc", size = 4693770, upload-time = "2024-10-14T23:37:54.122Z" }, - { url = "https://files.pythonhosted.org/packages/ce/0c/f07435a18a4b94ce6bd0677d8319cd3de61f3a9eeb1e5f8ab4e8b5edfcb3/uvloop-0.21.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:461d9ae6660fbbafedd07559c6a2e57cd553b34b0065b6550685f6653a98c1cb", size = 4451321, upload-time = "2024-10-14T23:37:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/8f/eb/f7032be105877bcf924709c97b1bf3b90255b4ec251f9340cef912559f28/uvloop-0.21.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:183aef7c8730e54c9a3ee3227464daed66e37ba13040bb3f350bc2ddc040f22f", size = 4659022, upload-time = "2024-10-14T23:37:58.195Z" }, - { url = "https://files.pythonhosted.org/packages/3f/8d/2cbef610ca21539f0f36e2b34da49302029e7c9f09acef0b1c3b5839412b/uvloop-0.21.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:bfd55dfcc2a512316e65f16e503e9e450cab148ef11df4e4e679b5e8253a5281", size = 1468123, upload-time = "2024-10-14T23:38:00.688Z" }, - { url = "https://files.pythonhosted.org/packages/93/0d/b0038d5a469f94ed8f2b2fce2434a18396d8fbfb5da85a0a9781ebbdec14/uvloop-0.21.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:787ae31ad8a2856fc4e7c095341cccc7209bd657d0e71ad0dc2ea83c4a6fa8af", size = 819325, upload-time = "2024-10-14T23:38:02.309Z" }, - { url = "https://files.pythonhosted.org/packages/50/94/0a687f39e78c4c1e02e3272c6b2ccdb4e0085fda3b8352fecd0410ccf915/uvloop-0.21.0-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5ee4d4ef48036ff6e5cfffb09dd192c7a5027153948d85b8da7ff705065bacc6", size = 4582806, upload-time = "2024-10-14T23:38:04.711Z" }, - { url = "https://files.pythonhosted.org/packages/d2/19/f5b78616566ea68edd42aacaf645adbf71fbd83fc52281fba555dc27e3f1/uvloop-0.21.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3df876acd7ec037a3d005b3ab85a7e4110422e4d9c1571d4fc89b0fc41b6816", size = 4701068, upload-time = "2024-10-14T23:38:06.385Z" }, - { url = "https://files.pythonhosted.org/packages/47/57/66f061ee118f413cd22a656de622925097170b9380b30091b78ea0c6ea75/uvloop-0.21.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:bd53ecc9a0f3d87ab847503c2e1552b690362e005ab54e8a48ba97da3924c0dc", size = 4454428, upload-time = "2024-10-14T23:38:08.416Z" }, - { url = "https://files.pythonhosted.org/packages/63/9a/0962b05b308494e3202d3f794a6e85abe471fe3cafdbcf95c2e8c713aabd/uvloop-0.21.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:a5c39f217ab3c663dc699c04cbd50c13813e31d917642d459fdcec07555cc553", size = 4660018, upload-time = "2024-10-14T23:38:10.888Z" }, -] - -[[package]] -name = "watchfiles" -version = "1.0.5" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "anyio" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/03/e2/8ed598c42057de7aa5d97c472254af4906ff0a59a66699d426fc9ef795d7/watchfiles-1.0.5.tar.gz", hash = "sha256:b7529b5dcc114679d43827d8c35a07c493ad6f083633d573d81c660abc5979e9", size = 94537, upload-time = "2025-04-08T10:36:26.722Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/af/4d/d02e6ea147bb7fff5fd109c694a95109612f419abed46548a930e7f7afa3/watchfiles-1.0.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5c40fe7dd9e5f81e0847b1ea64e1f5dd79dd61afbedb57759df06767ac719b40", size = 405632, upload-time = "2025-04-08T10:34:41.832Z" }, - { url = "https://files.pythonhosted.org/packages/60/31/9ee50e29129d53a9a92ccf1d3992751dc56fc3c8f6ee721be1c7b9c81763/watchfiles-1.0.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:8c0db396e6003d99bb2d7232c957b5f0b5634bbd1b24e381a5afcc880f7373fb", size = 395734, upload-time = "2025-04-08T10:34:44.236Z" }, - { url = "https://files.pythonhosted.org/packages/ad/8c/759176c97195306f028024f878e7f1c776bda66ccc5c68fa51e699cf8f1d/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b551d4fb482fc57d852b4541f911ba28957d051c8776e79c3b4a51eb5e2a1b11", size = 455008, upload-time = "2025-04-08T10:34:45.617Z" }, - { url = "https://files.pythonhosted.org/packages/55/1a/5e977250c795ee79a0229e3b7f5e3a1b664e4e450756a22da84d2f4979fe/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:830aa432ba5c491d52a15b51526c29e4a4b92bf4f92253787f9726fe01519487", size = 459029, upload-time = "2025-04-08T10:34:46.814Z" }, - { url = "https://files.pythonhosted.org/packages/e6/17/884cf039333605c1d6e296cf5be35fad0836953c3dfd2adb71b72f9dbcd0/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a16512051a822a416b0d477d5f8c0e67b67c1a20d9acecb0aafa3aa4d6e7d256", size = 488916, upload-time = "2025-04-08T10:34:48.571Z" }, - { url = "https://files.pythonhosted.org/packages/ef/e0/bcb6e64b45837056c0a40f3a2db3ef51c2ced19fda38484fa7508e00632c/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bfe0cbc787770e52a96c6fda6726ace75be7f840cb327e1b08d7d54eadc3bc85", size = 523763, upload-time = "2025-04-08T10:34:50.268Z" }, - { url = "https://files.pythonhosted.org/packages/24/e9/f67e9199f3bb35c1837447ecf07e9830ec00ff5d35a61e08c2cd67217949/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d363152c5e16b29d66cbde8fa614f9e313e6f94a8204eaab268db52231fe5358", size = 502891, upload-time = "2025-04-08T10:34:51.419Z" }, - { url = "https://files.pythonhosted.org/packages/23/ed/a6cf815f215632f5c8065e9c41fe872025ffea35aa1f80499f86eae922db/watchfiles-1.0.5-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ee32c9a9bee4d0b7bd7cbeb53cb185cf0b622ac761efaa2eba84006c3b3a614", size = 454921, upload-time = "2025-04-08T10:34:52.67Z" }, - { url = "https://files.pythonhosted.org/packages/92/4c/e14978599b80cde8486ab5a77a821e8a982ae8e2fcb22af7b0886a033ec8/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:29c7fd632ccaf5517c16a5188e36f6612d6472ccf55382db6c7fe3fcccb7f59f", size = 631422, upload-time = "2025-04-08T10:34:53.985Z" }, - { url = "https://files.pythonhosted.org/packages/b2/1a/9263e34c3458f7614b657f974f4ee61fd72f58adce8b436e16450e054efd/watchfiles-1.0.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8e637810586e6fe380c8bc1b3910accd7f1d3a9a7262c8a78d4c8fb3ba6a2b3d", size = 625675, upload-time = "2025-04-08T10:34:55.173Z" }, - { url = "https://files.pythonhosted.org/packages/96/1f/1803a18bd6ab04a0766386a19bcfe64641381a04939efdaa95f0e3b0eb58/watchfiles-1.0.5-cp310-cp310-win32.whl", hash = "sha256:cd47d063fbeabd4c6cae1d4bcaa38f0902f8dc5ed168072874ea11d0c7afc1ff", size = 277921, upload-time = "2025-04-08T10:34:56.318Z" }, - { url = "https://files.pythonhosted.org/packages/c2/3b/29a89de074a7d6e8b4dc67c26e03d73313e4ecf0d6e97e942a65fa7c195e/watchfiles-1.0.5-cp310-cp310-win_amd64.whl", hash = "sha256:86c0df05b47a79d80351cd179893f2f9c1b1cae49d96e8b3290c7f4bd0ca0a92", size = 291526, upload-time = "2025-04-08T10:34:57.95Z" }, - { url = "https://files.pythonhosted.org/packages/39/f4/41b591f59021786ef517e1cdc3b510383551846703e03f204827854a96f8/watchfiles-1.0.5-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:237f9be419e977a0f8f6b2e7b0475ababe78ff1ab06822df95d914a945eac827", size = 405336, upload-time = "2025-04-08T10:34:59.359Z" }, - { url = "https://files.pythonhosted.org/packages/ae/06/93789c135be4d6d0e4f63e96eea56dc54050b243eacc28439a26482b5235/watchfiles-1.0.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:e0da39ff917af8b27a4bdc5a97ac577552a38aac0d260a859c1517ea3dc1a7c4", size = 395977, upload-time = "2025-04-08T10:35:00.522Z" }, - { url = "https://files.pythonhosted.org/packages/d2/db/1cd89bd83728ca37054512d4d35ab69b5f12b8aa2ac9be3b0276b3bf06cc/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2cfcb3952350e95603f232a7a15f6c5f86c5375e46f0bd4ae70d43e3e063c13d", size = 455232, upload-time = "2025-04-08T10:35:01.698Z" }, - { url = "https://files.pythonhosted.org/packages/40/90/d8a4d44ffe960517e487c9c04f77b06b8abf05eb680bed71c82b5f2cad62/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:68b2dddba7a4e6151384e252a5632efcaa9bc5d1c4b567f3cb621306b2ca9f63", size = 459151, upload-time = "2025-04-08T10:35:03.358Z" }, - { url = "https://files.pythonhosted.org/packages/6c/da/267a1546f26465dead1719caaba3ce660657f83c9d9c052ba98fb8856e13/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:95cf944fcfc394c5f9de794ce581914900f82ff1f855326f25ebcf24d5397418", size = 489054, upload-time = "2025-04-08T10:35:04.561Z" }, - { url = "https://files.pythonhosted.org/packages/b1/31/33850dfd5c6efb6f27d2465cc4c6b27c5a6f5ed53c6fa63b7263cf5f60f6/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ecf6cd9f83d7c023b1aba15d13f705ca7b7d38675c121f3cc4a6e25bd0857ee9", size = 523955, upload-time = "2025-04-08T10:35:05.786Z" }, - { url = "https://files.pythonhosted.org/packages/09/84/b7d7b67856efb183a421f1416b44ca975cb2ea6c4544827955dfb01f7dc2/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:852de68acd6212cd6d33edf21e6f9e56e5d98c6add46f48244bd479d97c967c6", size = 502234, upload-time = "2025-04-08T10:35:07.187Z" }, - { url = "https://files.pythonhosted.org/packages/71/87/6dc5ec6882a2254cfdd8b0718b684504e737273903b65d7338efaba08b52/watchfiles-1.0.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d5730f3aa35e646103b53389d5bc77edfbf578ab6dab2e005142b5b80a35ef25", size = 454750, upload-time = "2025-04-08T10:35:08.859Z" }, - { url = "https://files.pythonhosted.org/packages/3d/6c/3786c50213451a0ad15170d091570d4a6554976cf0df19878002fc96075a/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:18b3bd29954bc4abeeb4e9d9cf0b30227f0f206c86657674f544cb032296acd5", size = 631591, upload-time = "2025-04-08T10:35:10.64Z" }, - { url = "https://files.pythonhosted.org/packages/1b/b3/1427425ade4e359a0deacce01a47a26024b2ccdb53098f9d64d497f6684c/watchfiles-1.0.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:ba5552a1b07c8edbf197055bc9d518b8f0d98a1c6a73a293bc0726dce068ed01", size = 625370, upload-time = "2025-04-08T10:35:12.412Z" }, - { url = "https://files.pythonhosted.org/packages/15/ba/f60e053b0b5b8145d682672024aa91370a29c5c921a88977eb565de34086/watchfiles-1.0.5-cp311-cp311-win32.whl", hash = "sha256:2f1fefb2e90e89959447bc0420fddd1e76f625784340d64a2f7d5983ef9ad246", size = 277791, upload-time = "2025-04-08T10:35:13.719Z" }, - { url = "https://files.pythonhosted.org/packages/50/ed/7603c4e164225c12c0d4e8700b64bb00e01a6c4eeea372292a3856be33a4/watchfiles-1.0.5-cp311-cp311-win_amd64.whl", hash = "sha256:b6e76ceb1dd18c8e29c73f47d41866972e891fc4cc7ba014f487def72c1cf096", size = 291622, upload-time = "2025-04-08T10:35:15.071Z" }, - { url = "https://files.pythonhosted.org/packages/a2/c2/99bb7c96b4450e36877fde33690ded286ff555b5a5c1d925855d556968a1/watchfiles-1.0.5-cp311-cp311-win_arm64.whl", hash = "sha256:266710eb6fddc1f5e51843c70e3bebfb0f5e77cf4f27129278c70554104d19ed", size = 283699, upload-time = "2025-04-08T10:35:16.732Z" }, - { url = "https://files.pythonhosted.org/packages/2a/8c/4f0b9bdb75a1bfbd9c78fad7d8854369283f74fe7cf03eb16be77054536d/watchfiles-1.0.5-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:b5eb568c2aa6018e26da9e6c86f3ec3fd958cee7f0311b35c2630fa4217d17f2", size = 401511, upload-time = "2025-04-08T10:35:17.956Z" }, - { url = "https://files.pythonhosted.org/packages/dc/4e/7e15825def77f8bd359b6d3f379f0c9dac4eb09dd4ddd58fd7d14127179c/watchfiles-1.0.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0a04059f4923ce4e856b4b4e5e783a70f49d9663d22a4c3b3298165996d1377f", size = 392715, upload-time = "2025-04-08T10:35:19.202Z" }, - { url = "https://files.pythonhosted.org/packages/58/65/b72fb817518728e08de5840d5d38571466c1b4a3f724d190cec909ee6f3f/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3e380c89983ce6e6fe2dd1e1921b9952fb4e6da882931abd1824c092ed495dec", size = 454138, upload-time = "2025-04-08T10:35:20.586Z" }, - { url = "https://files.pythonhosted.org/packages/3e/a4/86833fd2ea2e50ae28989f5950b5c3f91022d67092bfec08f8300d8b347b/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:fe43139b2c0fdc4a14d4f8d5b5d967f7a2777fd3d38ecf5b1ec669b0d7e43c21", size = 458592, upload-time = "2025-04-08T10:35:21.87Z" }, - { url = "https://files.pythonhosted.org/packages/38/7e/42cb8df8be9a37e50dd3a818816501cf7a20d635d76d6bd65aae3dbbff68/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ee0822ce1b8a14fe5a066f93edd20aada932acfe348bede8aa2149f1a4489512", size = 487532, upload-time = "2025-04-08T10:35:23.143Z" }, - { url = "https://files.pythonhosted.org/packages/fc/fd/13d26721c85d7f3df6169d8b495fcac8ab0dc8f0945ebea8845de4681dab/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a0dbcb1c2d8f2ab6e0a81c6699b236932bd264d4cef1ac475858d16c403de74d", size = 522865, upload-time = "2025-04-08T10:35:24.702Z" }, - { url = "https://files.pythonhosted.org/packages/a1/0d/7f9ae243c04e96c5455d111e21b09087d0eeaf9a1369e13a01c7d3d82478/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a2014a2b18ad3ca53b1f6c23f8cd94a18ce930c1837bd891262c182640eb40a6", size = 499887, upload-time = "2025-04-08T10:35:25.969Z" }, - { url = "https://files.pythonhosted.org/packages/8e/0f/a257766998e26aca4b3acf2ae97dff04b57071e991a510857d3799247c67/watchfiles-1.0.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10f6ae86d5cb647bf58f9f655fcf577f713915a5d69057a0371bc257e2553234", size = 454498, upload-time = "2025-04-08T10:35:27.353Z" }, - { url = "https://files.pythonhosted.org/packages/81/79/8bf142575a03e0af9c3d5f8bcae911ee6683ae93a625d349d4ecf4c8f7df/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:1a7bac2bde1d661fb31f4d4e8e539e178774b76db3c2c17c4bb3e960a5de07a2", size = 630663, upload-time = "2025-04-08T10:35:28.685Z" }, - { url = "https://files.pythonhosted.org/packages/f1/80/abe2e79f610e45c63a70d271caea90c49bbf93eb00fa947fa9b803a1d51f/watchfiles-1.0.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:4ab626da2fc1ac277bbf752446470b367f84b50295264d2d313e28dc4405d663", size = 625410, upload-time = "2025-04-08T10:35:30.42Z" }, - { url = "https://files.pythonhosted.org/packages/91/6f/bc7fbecb84a41a9069c2c6eb6319f7f7df113adf113e358c57fc1aff7ff5/watchfiles-1.0.5-cp312-cp312-win32.whl", hash = "sha256:9f4571a783914feda92018ef3901dab8caf5b029325b5fe4558c074582815249", size = 277965, upload-time = "2025-04-08T10:35:32.023Z" }, - { url = "https://files.pythonhosted.org/packages/99/a5/bf1c297ea6649ec59e935ab311f63d8af5faa8f0b86993e3282b984263e3/watchfiles-1.0.5-cp312-cp312-win_amd64.whl", hash = "sha256:360a398c3a19672cf93527f7e8d8b60d8275119c5d900f2e184d32483117a705", size = 291693, upload-time = "2025-04-08T10:35:33.225Z" }, - { url = "https://files.pythonhosted.org/packages/7f/7b/fd01087cc21db5c47e5beae507b87965db341cce8a86f9eb12bf5219d4e0/watchfiles-1.0.5-cp312-cp312-win_arm64.whl", hash = "sha256:1a2902ede862969077b97523987c38db28abbe09fb19866e711485d9fbf0d417", size = 283287, upload-time = "2025-04-08T10:35:34.568Z" }, - { url = "https://files.pythonhosted.org/packages/c7/62/435766874b704f39b2fecd8395a29042db2b5ec4005bd34523415e9bd2e0/watchfiles-1.0.5-cp313-cp313-macosx_10_12_x86_64.whl", hash = "sha256:0b289572c33a0deae62daa57e44a25b99b783e5f7aed81b314232b3d3c81a11d", size = 401531, upload-time = "2025-04-08T10:35:35.792Z" }, - { url = "https://files.pythonhosted.org/packages/6e/a6/e52a02c05411b9cb02823e6797ef9bbba0bfaf1bb627da1634d44d8af833/watchfiles-1.0.5-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:a056c2f692d65bf1e99c41045e3bdcaea3cb9e6b5a53dcaf60a5f3bd95fc9763", size = 392417, upload-time = "2025-04-08T10:35:37.048Z" }, - { url = "https://files.pythonhosted.org/packages/3f/53/c4af6819770455932144e0109d4854437769672d7ad897e76e8e1673435d/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9dca99744991fc9850d18015c4f0438865414e50069670f5f7eee08340d8b40", size = 453423, upload-time = "2025-04-08T10:35:38.357Z" }, - { url = "https://files.pythonhosted.org/packages/cb/d1/8e88df58bbbf819b8bc5cfbacd3c79e01b40261cad0fc84d1e1ebd778a07/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:894342d61d355446d02cd3988a7326af344143eb33a2fd5d38482a92072d9563", size = 458185, upload-time = "2025-04-08T10:35:39.708Z" }, - { url = "https://files.pythonhosted.org/packages/ff/70/fffaa11962dd5429e47e478a18736d4e42bec42404f5ee3b92ef1b87ad60/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ab44e1580924d1ffd7b3938e02716d5ad190441965138b4aa1d1f31ea0877f04", size = 486696, upload-time = "2025-04-08T10:35:41.469Z" }, - { url = "https://files.pythonhosted.org/packages/39/db/723c0328e8b3692d53eb273797d9a08be6ffb1d16f1c0ba2bdbdc2a3852c/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d6f9367b132078b2ceb8d066ff6c93a970a18c3029cea37bfd7b2d3dd2e5db8f", size = 522327, upload-time = "2025-04-08T10:35:43.289Z" }, - { url = "https://files.pythonhosted.org/packages/cd/05/9fccc43c50c39a76b68343484b9da7b12d42d0859c37c61aec018c967a32/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f2e55a9b162e06e3f862fb61e399fe9f05d908d019d87bf5b496a04ef18a970a", size = 499741, upload-time = "2025-04-08T10:35:44.574Z" }, - { url = "https://files.pythonhosted.org/packages/23/14/499e90c37fa518976782b10a18b18db9f55ea73ca14641615056f8194bb3/watchfiles-1.0.5-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0125f91f70e0732a9f8ee01e49515c35d38ba48db507a50c5bdcad9503af5827", size = 453995, upload-time = "2025-04-08T10:35:46.336Z" }, - { url = "https://files.pythonhosted.org/packages/61/d9/f75d6840059320df5adecd2c687fbc18960a7f97b55c300d20f207d48aef/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:13bb21f8ba3248386337c9fa51c528868e6c34a707f729ab041c846d52a0c69a", size = 629693, upload-time = "2025-04-08T10:35:48.161Z" }, - { url = "https://files.pythonhosted.org/packages/fc/17/180ca383f5061b61406477218c55d66ec118e6c0c51f02d8142895fcf0a9/watchfiles-1.0.5-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:839ebd0df4a18c5b3c1b890145b5a3f5f64063c2a0d02b13c76d78fe5de34936", size = 624677, upload-time = "2025-04-08T10:35:49.65Z" }, - { url = "https://files.pythonhosted.org/packages/bf/15/714d6ef307f803f236d69ee9d421763707899d6298d9f3183e55e366d9af/watchfiles-1.0.5-cp313-cp313-win32.whl", hash = "sha256:4a8ec1e4e16e2d5bafc9ba82f7aaecfeec990ca7cd27e84fb6f191804ed2fcfc", size = 277804, upload-time = "2025-04-08T10:35:51.093Z" }, - { url = "https://files.pythonhosted.org/packages/a8/b4/c57b99518fadf431f3ef47a610839e46e5f8abf9814f969859d1c65c02c7/watchfiles-1.0.5-cp313-cp313-win_amd64.whl", hash = "sha256:f436601594f15bf406518af922a89dcaab416568edb6f65c4e5bbbad1ea45c11", size = 291087, upload-time = "2025-04-08T10:35:52.458Z" }, - { url = "https://files.pythonhosted.org/packages/1a/03/81f9fcc3963b3fc415cd4b0b2b39ee8cc136c42fb10a36acf38745e9d283/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_10_12_x86_64.whl", hash = "sha256:f59b870db1f1ae5a9ac28245707d955c8721dd6565e7f411024fa374b5362d1d", size = 405947, upload-time = "2025-04-08T10:36:13.721Z" }, - { url = "https://files.pythonhosted.org/packages/54/97/8c4213a852feb64807ec1d380f42d4fc8bfaef896bdbd94318f8fd7f3e4e/watchfiles-1.0.5-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:9475b0093767e1475095f2aeb1d219fb9664081d403d1dff81342df8cd707034", size = 397276, upload-time = "2025-04-08T10:36:15.131Z" }, - { url = "https://files.pythonhosted.org/packages/78/12/d4464d19860cb9672efa45eec1b08f8472c478ed67dcd30647c51ada7aef/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fc533aa50664ebd6c628b2f30591956519462f5d27f951ed03d6c82b2dfd9965", size = 455550, upload-time = "2025-04-08T10:36:16.635Z" }, - { url = "https://files.pythonhosted.org/packages/90/fb/b07bcdf1034d8edeaef4c22f3e9e3157d37c5071b5f9492ffdfa4ad4bed7/watchfiles-1.0.5-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fed1cd825158dcaae36acce7b2db33dcbfd12b30c34317a88b8ed80f0541cc57", size = 455542, upload-time = "2025-04-08T10:36:18.655Z" }, -] - -[[package]] -name = "web3" -version = "7.12.0" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "aiohttp" }, - { name = "eth-abi" }, - { name = "eth-account" }, - { name = "eth-hash", extra = ["pycryptodome"] }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "hexbytes" }, - { name = "pydantic" }, - { name = "pyunormalize" }, - { name = "pywin32", marker = "sys_platform == 'win32'" }, - { name = "requests" }, - { name = "types-requests" }, - { name = "typing-extensions" }, - { name = "websockets" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/7d/1e/fc1f5b5a12615cbdca57d35014cdb9823db7392d73b730fa0d89d6a13f6a/web3-7.12.0.tar.gz", hash = "sha256:08fbe79a2e2503c9820132ebad24ba0372831588cabac5f467999c97ace7dda3", size = 2195693, upload-time = "2025-05-22T21:06:05.381Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/b8/df/0ccf18f244b96a93ba2710f7ce696da1f8dd44ef1126e3603dfb65cd68fe/web3-7.12.0-py3-none-any.whl", hash = "sha256:c7e2b9c1db5a379ef53b45fe8a19bdc2d47ad262039fbf6675794bc40f74bf06", size = 1369328, upload-time = "2025-05-22T21:06:03.124Z" }, -] - -[[package]] -name = "websockets" -version = "15.0.1" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/21/e6/26d09fab466b7ca9c7737474c52be4f76a40301b08362eb2dbc19dcc16c1/websockets-15.0.1.tar.gz", hash = "sha256:82544de02076bafba038ce055ee6412d68da13ab47f0c60cab827346de828dee", size = 177016, upload-time = "2025-03-05T20:03:41.606Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/1e/da/6462a9f510c0c49837bbc9345aca92d767a56c1fb2939e1579df1e1cdcf7/websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b", size = 175423, upload-time = "2025-03-05T20:01:35.363Z" }, - { url = "https://files.pythonhosted.org/packages/1c/9f/9d11c1a4eb046a9e106483b9ff69bce7ac880443f00e5ce64261b47b07e7/websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205", size = 173080, upload-time = "2025-03-05T20:01:37.304Z" }, - { url = "https://files.pythonhosted.org/packages/d5/4f/b462242432d93ea45f297b6179c7333dd0402b855a912a04e7fc61c0d71f/websockets-15.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5756779642579d902eed757b21b0164cd6fe338506a8083eb58af5c372e39d9a", size = 173329, upload-time = "2025-03-05T20:01:39.668Z" }, - { url = "https://files.pythonhosted.org/packages/6e/0c/6afa1f4644d7ed50284ac59cc70ef8abd44ccf7d45850d989ea7310538d0/websockets-15.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0fdfe3e2a29e4db3659dbd5bbf04560cea53dd9610273917799f1cde46aa725e", size = 182312, upload-time = "2025-03-05T20:01:41.815Z" }, - { url = "https://files.pythonhosted.org/packages/dd/d4/ffc8bd1350b229ca7a4db2a3e1c482cf87cea1baccd0ef3e72bc720caeec/websockets-15.0.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:4c2529b320eb9e35af0fa3016c187dffb84a3ecc572bcee7c3ce302bfeba52bf", size = 181319, upload-time = "2025-03-05T20:01:43.967Z" }, - { url = "https://files.pythonhosted.org/packages/97/3a/5323a6bb94917af13bbb34009fac01e55c51dfde354f63692bf2533ffbc2/websockets-15.0.1-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ac1e5c9054fe23226fb11e05a6e630837f074174c4c2f0fe442996112a6de4fb", size = 181631, upload-time = "2025-03-05T20:01:46.104Z" }, - { url = "https://files.pythonhosted.org/packages/a6/cc/1aeb0f7cee59ef065724041bb7ed667b6ab1eeffe5141696cccec2687b66/websockets-15.0.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:5df592cd503496351d6dc14f7cdad49f268d8e618f80dce0cd5a36b93c3fc08d", size = 182016, upload-time = "2025-03-05T20:01:47.603Z" }, - { url = "https://files.pythonhosted.org/packages/79/f9/c86f8f7af208e4161a7f7e02774e9d0a81c632ae76db2ff22549e1718a51/websockets-15.0.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:0a34631031a8f05657e8e90903e656959234f3a04552259458aac0b0f9ae6fd9", size = 181426, upload-time = "2025-03-05T20:01:48.949Z" }, - { url = "https://files.pythonhosted.org/packages/c7/b9/828b0bc6753db905b91df6ae477c0b14a141090df64fb17f8a9d7e3516cf/websockets-15.0.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:3d00075aa65772e7ce9e990cab3ff1de702aa09be3940d1dc88d5abf1ab8a09c", size = 181360, upload-time = "2025-03-05T20:01:50.938Z" }, - { url = "https://files.pythonhosted.org/packages/89/fb/250f5533ec468ba6327055b7d98b9df056fb1ce623b8b6aaafb30b55d02e/websockets-15.0.1-cp310-cp310-win32.whl", hash = "sha256:1234d4ef35db82f5446dca8e35a7da7964d02c127b095e172e54397fb6a6c256", size = 176388, upload-time = "2025-03-05T20:01:52.213Z" }, - { url = "https://files.pythonhosted.org/packages/1c/46/aca7082012768bb98e5608f01658ff3ac8437e563eca41cf068bd5849a5e/websockets-15.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:39c1fec2c11dc8d89bba6b2bf1556af381611a173ac2b511cf7231622058af41", size = 176830, upload-time = "2025-03-05T20:01:53.922Z" }, - { url = "https://files.pythonhosted.org/packages/9f/32/18fcd5919c293a398db67443acd33fde142f283853076049824fc58e6f75/websockets-15.0.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:823c248b690b2fd9303ba00c4f66cd5e2d8c3ba4aa968b2779be9532a4dad431", size = 175423, upload-time = "2025-03-05T20:01:56.276Z" }, - { url = "https://files.pythonhosted.org/packages/76/70/ba1ad96b07869275ef42e2ce21f07a5b0148936688c2baf7e4a1f60d5058/websockets-15.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:678999709e68425ae2593acf2e3ebcbcf2e69885a5ee78f9eb80e6e371f1bf57", size = 173082, upload-time = "2025-03-05T20:01:57.563Z" }, - { url = "https://files.pythonhosted.org/packages/86/f2/10b55821dd40eb696ce4704a87d57774696f9451108cff0d2824c97e0f97/websockets-15.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:d50fd1ee42388dcfb2b3676132c78116490976f1300da28eb629272d5d93e905", size = 173330, upload-time = "2025-03-05T20:01:59.063Z" }, - { url = "https://files.pythonhosted.org/packages/a5/90/1c37ae8b8a113d3daf1065222b6af61cc44102da95388ac0018fcb7d93d9/websockets-15.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d99e5546bf73dbad5bf3547174cd6cb8ba7273062a23808ffea025ecb1cf8562", size = 182878, upload-time = "2025-03-05T20:02:00.305Z" }, - { url = "https://files.pythonhosted.org/packages/8e/8d/96e8e288b2a41dffafb78e8904ea7367ee4f891dafc2ab8d87e2124cb3d3/websockets-15.0.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:66dd88c918e3287efc22409d426c8f729688d89a0c587c88971a0faa2c2f3792", size = 181883, upload-time = "2025-03-05T20:02:03.148Z" }, - { url = "https://files.pythonhosted.org/packages/93/1f/5d6dbf551766308f6f50f8baf8e9860be6182911e8106da7a7f73785f4c4/websockets-15.0.1-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8dd8327c795b3e3f219760fa603dcae1dcc148172290a8ab15158cf85a953413", size = 182252, upload-time = "2025-03-05T20:02:05.29Z" }, - { url = "https://files.pythonhosted.org/packages/d4/78/2d4fed9123e6620cbf1706c0de8a1632e1a28e7774d94346d7de1bba2ca3/websockets-15.0.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:8fdc51055e6ff4adeb88d58a11042ec9a5eae317a0a53d12c062c8a8865909e8", size = 182521, upload-time = "2025-03-05T20:02:07.458Z" }, - { url = "https://files.pythonhosted.org/packages/e7/3b/66d4c1b444dd1a9823c4a81f50231b921bab54eee2f69e70319b4e21f1ca/websockets-15.0.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:693f0192126df6c2327cce3baa7c06f2a117575e32ab2308f7f8216c29d9e2e3", size = 181958, upload-time = "2025-03-05T20:02:09.842Z" }, - { url = "https://files.pythonhosted.org/packages/08/ff/e9eed2ee5fed6f76fdd6032ca5cd38c57ca9661430bb3d5fb2872dc8703c/websockets-15.0.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:54479983bd5fb469c38f2f5c7e3a24f9a4e70594cd68cd1fa6b9340dadaff7cf", size = 181918, upload-time = "2025-03-05T20:02:11.968Z" }, - { url = "https://files.pythonhosted.org/packages/d8/75/994634a49b7e12532be6a42103597b71098fd25900f7437d6055ed39930a/websockets-15.0.1-cp311-cp311-win32.whl", hash = "sha256:16b6c1b3e57799b9d38427dda63edcbe4926352c47cf88588c0be4ace18dac85", size = 176388, upload-time = "2025-03-05T20:02:13.32Z" }, - { url = "https://files.pythonhosted.org/packages/98/93/e36c73f78400a65f5e236cd376713c34182e6663f6889cd45a4a04d8f203/websockets-15.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:27ccee0071a0e75d22cb35849b1db43f2ecd3e161041ac1ee9d2352ddf72f065", size = 176828, upload-time = "2025-03-05T20:02:14.585Z" }, - { url = "https://files.pythonhosted.org/packages/51/6b/4545a0d843594f5d0771e86463606a3988b5a09ca5123136f8a76580dd63/websockets-15.0.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:3e90baa811a5d73f3ca0bcbf32064d663ed81318ab225ee4f427ad4e26e5aff3", size = 175437, upload-time = "2025-03-05T20:02:16.706Z" }, - { url = "https://files.pythonhosted.org/packages/f4/71/809a0f5f6a06522af902e0f2ea2757f71ead94610010cf570ab5c98e99ed/websockets-15.0.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:592f1a9fe869c778694f0aa806ba0374e97648ab57936f092fd9d87f8bc03665", size = 173096, upload-time = "2025-03-05T20:02:18.832Z" }, - { url = "https://files.pythonhosted.org/packages/3d/69/1a681dd6f02180916f116894181eab8b2e25b31e484c5d0eae637ec01f7c/websockets-15.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:0701bc3cfcb9164d04a14b149fd74be7347a530ad3bbf15ab2c678a2cd3dd9a2", size = 173332, upload-time = "2025-03-05T20:02:20.187Z" }, - { url = "https://files.pythonhosted.org/packages/a6/02/0073b3952f5bce97eafbb35757f8d0d54812b6174ed8dd952aa08429bcc3/websockets-15.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e8b56bdcdb4505c8078cb6c7157d9811a85790f2f2b3632c7d1462ab5783d215", size = 183152, upload-time = "2025-03-05T20:02:22.286Z" }, - { url = "https://files.pythonhosted.org/packages/74/45/c205c8480eafd114b428284840da0b1be9ffd0e4f87338dc95dc6ff961a1/websockets-15.0.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0af68c55afbd5f07986df82831c7bff04846928ea8d1fd7f30052638788bc9b5", size = 182096, upload-time = "2025-03-05T20:02:24.368Z" }, - { url = "https://files.pythonhosted.org/packages/14/8f/aa61f528fba38578ec553c145857a181384c72b98156f858ca5c8e82d9d3/websockets-15.0.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:64dee438fed052b52e4f98f76c5790513235efaa1ef7f3f2192c392cd7c91b65", size = 182523, upload-time = "2025-03-05T20:02:25.669Z" }, - { url = "https://files.pythonhosted.org/packages/ec/6d/0267396610add5bc0d0d3e77f546d4cd287200804fe02323797de77dbce9/websockets-15.0.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:d5f6b181bb38171a8ad1d6aa58a67a6aa9d4b38d0f8c5f496b9e42561dfc62fe", size = 182790, upload-time = "2025-03-05T20:02:26.99Z" }, - { url = "https://files.pythonhosted.org/packages/02/05/c68c5adbf679cf610ae2f74a9b871ae84564462955d991178f95a1ddb7dd/websockets-15.0.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:5d54b09eba2bada6011aea5375542a157637b91029687eb4fdb2dab11059c1b4", size = 182165, upload-time = "2025-03-05T20:02:30.291Z" }, - { url = "https://files.pythonhosted.org/packages/29/93/bb672df7b2f5faac89761cb5fa34f5cec45a4026c383a4b5761c6cea5c16/websockets-15.0.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:3be571a8b5afed347da347bfcf27ba12b069d9d7f42cb8c7028b5e98bbb12597", size = 182160, upload-time = "2025-03-05T20:02:31.634Z" }, - { url = "https://files.pythonhosted.org/packages/ff/83/de1f7709376dc3ca9b7eeb4b9a07b4526b14876b6d372a4dc62312bebee0/websockets-15.0.1-cp312-cp312-win32.whl", hash = "sha256:c338ffa0520bdb12fbc527265235639fb76e7bc7faafbb93f6ba80d9c06578a9", size = 176395, upload-time = "2025-03-05T20:02:33.017Z" }, - { url = "https://files.pythonhosted.org/packages/7d/71/abf2ebc3bbfa40f391ce1428c7168fb20582d0ff57019b69ea20fa698043/websockets-15.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:fcd5cf9e305d7b8338754470cf69cf81f420459dbae8a3b40cee57417f4614a7", size = 176841, upload-time = "2025-03-05T20:02:34.498Z" }, - { url = "https://files.pythonhosted.org/packages/cb/9f/51f0cf64471a9d2b4d0fc6c534f323b664e7095640c34562f5182e5a7195/websockets-15.0.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:ee443ef070bb3b6ed74514f5efaa37a252af57c90eb33b956d35c8e9c10a1931", size = 175440, upload-time = "2025-03-05T20:02:36.695Z" }, - { url = "https://files.pythonhosted.org/packages/8a/05/aa116ec9943c718905997412c5989f7ed671bc0188ee2ba89520e8765d7b/websockets-15.0.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:5a939de6b7b4e18ca683218320fc67ea886038265fd1ed30173f5ce3f8e85675", size = 173098, upload-time = "2025-03-05T20:02:37.985Z" }, - { url = "https://files.pythonhosted.org/packages/ff/0b/33cef55ff24f2d92924923c99926dcce78e7bd922d649467f0eda8368923/websockets-15.0.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:746ee8dba912cd6fc889a8147168991d50ed70447bf18bcda7039f7d2e3d9151", size = 173329, upload-time = "2025-03-05T20:02:39.298Z" }, - { url = "https://files.pythonhosted.org/packages/31/1d/063b25dcc01faa8fada1469bdf769de3768b7044eac9d41f734fd7b6ad6d/websockets-15.0.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:595b6c3969023ecf9041b2936ac3827e4623bfa3ccf007575f04c5a6aa318c22", size = 183111, upload-time = "2025-03-05T20:02:40.595Z" }, - { url = "https://files.pythonhosted.org/packages/93/53/9a87ee494a51bf63e4ec9241c1ccc4f7c2f45fff85d5bde2ff74fcb68b9e/websockets-15.0.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3c714d2fc58b5ca3e285461a4cc0c9a66bd0e24c5da9911e30158286c9b5be7f", size = 182054, upload-time = "2025-03-05T20:02:41.926Z" }, - { url = "https://files.pythonhosted.org/packages/ff/b2/83a6ddf56cdcbad4e3d841fcc55d6ba7d19aeb89c50f24dd7e859ec0805f/websockets-15.0.1-cp313-cp313-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0f3c1e2ab208db911594ae5b4f79addeb3501604a165019dd221c0bdcabe4db8", size = 182496, upload-time = "2025-03-05T20:02:43.304Z" }, - { url = "https://files.pythonhosted.org/packages/98/41/e7038944ed0abf34c45aa4635ba28136f06052e08fc2168520bb8b25149f/websockets-15.0.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:229cf1d3ca6c1804400b0a9790dc66528e08a6a1feec0d5040e8b9eb14422375", size = 182829, upload-time = "2025-03-05T20:02:48.812Z" }, - { url = "https://files.pythonhosted.org/packages/e0/17/de15b6158680c7623c6ef0db361da965ab25d813ae54fcfeae2e5b9ef910/websockets-15.0.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:756c56e867a90fb00177d530dca4b097dd753cde348448a1012ed6c5131f8b7d", size = 182217, upload-time = "2025-03-05T20:02:50.14Z" }, - { url = "https://files.pythonhosted.org/packages/33/2b/1f168cb6041853eef0362fb9554c3824367c5560cbdaad89ac40f8c2edfc/websockets-15.0.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:558d023b3df0bffe50a04e710bc87742de35060580a293c2a984299ed83bc4e4", size = 182195, upload-time = "2025-03-05T20:02:51.561Z" }, - { url = "https://files.pythonhosted.org/packages/86/eb/20b6cdf273913d0ad05a6a14aed4b9a85591c18a987a3d47f20fa13dcc47/websockets-15.0.1-cp313-cp313-win32.whl", hash = "sha256:ba9e56e8ceeeedb2e080147ba85ffcd5cd0711b89576b83784d8605a7df455fa", size = 176393, upload-time = "2025-03-05T20:02:53.814Z" }, - { url = "https://files.pythonhosted.org/packages/1b/6c/c65773d6cab416a64d191d6ee8a8b1c68a09970ea6909d16965d26bfed1e/websockets-15.0.1-cp313-cp313-win_amd64.whl", hash = "sha256:e09473f095a819042ecb2ab9465aee615bd9c2028e4ef7d933600a8401c79561", size = 176837, upload-time = "2025-03-05T20:02:55.237Z" }, - { url = "https://files.pythonhosted.org/packages/02/9e/d40f779fa16f74d3468357197af8d6ad07e7c5a27ea1ca74ceb38986f77a/websockets-15.0.1-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:0c9e74d766f2818bb95f84c25be4dea09841ac0f734d1966f415e4edfc4ef1c3", size = 173109, upload-time = "2025-03-05T20:03:17.769Z" }, - { url = "https://files.pythonhosted.org/packages/bc/cd/5b887b8585a593073fd92f7c23ecd3985cd2c3175025a91b0d69b0551372/websockets-15.0.1-pp310-pypy310_pp73-macosx_11_0_arm64.whl", hash = "sha256:1009ee0c7739c08a0cd59de430d6de452a55e42d6b522de7aa15e6f67db0b8e1", size = 173343, upload-time = "2025-03-05T20:03:19.094Z" }, - { url = "https://files.pythonhosted.org/packages/fe/ae/d34f7556890341e900a95acf4886833646306269f899d58ad62f588bf410/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76d1f20b1c7a2fa82367e04982e708723ba0e7b8d43aa643d3dcd404d74f1475", size = 174599, upload-time = "2025-03-05T20:03:21.1Z" }, - { url = "https://files.pythonhosted.org/packages/71/e6/5fd43993a87db364ec60fc1d608273a1a465c0caba69176dd160e197ce42/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f29d80eb9a9263b8d109135351caf568cc3f80b9928bccde535c235de55c22d9", size = 174207, upload-time = "2025-03-05T20:03:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/2b/fb/c492d6daa5ec067c2988ac80c61359ace5c4c674c532985ac5a123436cec/websockets-15.0.1-pp310-pypy310_pp73-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b359ed09954d7c18bbc1680f380c7301f92c60bf924171629c5db97febb12f04", size = 174155, upload-time = "2025-03-05T20:03:25.321Z" }, - { url = "https://files.pythonhosted.org/packages/68/a1/dcb68430b1d00b698ae7a7e0194433bce4f07ded185f0ee5fb21e2a2e91e/websockets-15.0.1-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:cad21560da69f4ce7658ca2cb83138fb4cf695a2ba3e475e0559e05991aa8122", size = 176884, upload-time = "2025-03-05T20:03:27.934Z" }, - { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, -] - -[[package]] -name = "werkzeug" -version = "3.1.3" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "markupsafe" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/9f/69/83029f1f6300c5fb2471d621ab06f6ec6b3324685a2ce0f9777fd4a8b71e/werkzeug-3.1.3.tar.gz", hash = "sha256:60723ce945c19328679790e3282cc758aa4a6040e4bb330f53d30fa546d44746", size = 806925, upload-time = "2024-11-08T15:52:18.093Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/52/24/ab44c871b0f07f491e5d2ad12c9bd7358e527510618cb1b803a88e986db1/werkzeug-3.1.3-py3-none-any.whl", hash = "sha256:54b78bf3716d19a65be4fceccc0d1d7b89e608834989dfae50ea87564639213e", size = 224498, upload-time = "2024-11-08T15:52:16.132Z" }, -] - -[[package]] -name = "x402" -version = "1.0.0" -source = { editable = "../../../../../python/legacy" } -dependencies = [ - { name = "eth-account" }, - { name = "eth-typing" }, - { name = "eth-utils" }, - { name = "fastapi", extra = ["standard"] }, - { name = "flask" }, - { name = "pydantic" }, - { name = "pydantic-settings" }, - { name = "python-dotenv" }, - { name = "web3" }, -] - -[package.metadata] -requires-dist = [ - { name = "eth-account", specifier = ">=0.13.7" }, - { name = "eth-typing", specifier = ">=4.0.0" }, - { name = "eth-utils", specifier = ">=3.0.0" }, - { name = "fastapi", extras = ["standard"], specifier = ">=0.115.12" }, - { name = "flask", specifier = ">=3.0.0" }, - { name = "pydantic", specifier = ">=2.10.3" }, - { name = "pydantic-settings", specifier = ">=2.2.1" }, - { name = "python-dotenv", specifier = ">=1.0.1" }, - { name = "web3", specifier = ">=6.0.0" }, -] - -[package.metadata.requires-dev] -dev = [ - { name = "pytest", specifier = ">=8.3.5" }, - { name = "pytest-asyncio", specifier = ">=1.0.0" }, - { name = "ruff", specifier = ">=0.11.9" }, -] - -[[package]] -name = "x402-flask-example" -version = "0.1.0" -source = { virtual = "." } -dependencies = [ - { name = "flask" }, - { name = "python-dotenv" }, - { name = "uvicorn" }, - { name = "x402" }, -] - -[package.metadata] -requires-dist = [ - { name = "flask", specifier = ">=3.1.1" }, - { name = "python-dotenv", specifier = ">=1.0.0" }, - { name = "uvicorn", specifier = ">=0.27.0" }, - { name = "x402", editable = "../../../../../python/legacy" }, -] - -[[package]] -name = "yarl" -version = "1.20.1" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "idna" }, - { name = "multidict" }, - { name = "propcache" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/3c/fb/efaa23fa4e45537b827620f04cf8f3cd658b76642205162e072703a5b963/yarl-1.20.1.tar.gz", hash = "sha256:d017a4997ee50c91fd5466cef416231bb82177b93b029906cefc542ce14c35ac", size = 186428, upload-time = "2025-06-10T00:46:09.923Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/cb/65/7fed0d774abf47487c64be14e9223749468922817b5e8792b8a64792a1bb/yarl-1.20.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:6032e6da6abd41e4acda34d75a816012717000fa6839f37124a47fcefc49bec4", size = 132910, upload-time = "2025-06-10T00:42:31.108Z" }, - { url = "https://files.pythonhosted.org/packages/8a/7b/988f55a52da99df9e56dc733b8e4e5a6ae2090081dc2754fc8fd34e60aa0/yarl-1.20.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:2c7b34d804b8cf9b214f05015c4fee2ebe7ed05cf581e7192c06555c71f4446a", size = 90644, upload-time = "2025-06-10T00:42:33.851Z" }, - { url = "https://files.pythonhosted.org/packages/f7/de/30d98f03e95d30c7e3cc093759982d038c8833ec2451001d45ef4854edc1/yarl-1.20.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:0c869f2651cc77465f6cd01d938d91a11d9ea5d798738c1dc077f3de0b5e5fed", size = 89322, upload-time = "2025-06-10T00:42:35.688Z" }, - { url = "https://files.pythonhosted.org/packages/e0/7a/f2f314f5ebfe9200724b0b748de2186b927acb334cf964fd312eb86fc286/yarl-1.20.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:62915e6688eb4d180d93840cda4110995ad50c459bf931b8b3775b37c264af1e", size = 323786, upload-time = "2025-06-10T00:42:37.817Z" }, - { url = "https://files.pythonhosted.org/packages/15/3f/718d26f189db96d993d14b984ce91de52e76309d0fd1d4296f34039856aa/yarl-1.20.1-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:41ebd28167bc6af8abb97fec1a399f412eec5fd61a3ccbe2305a18b84fb4ca73", size = 319627, upload-time = "2025-06-10T00:42:39.937Z" }, - { url = "https://files.pythonhosted.org/packages/a5/76/8fcfbf5fa2369157b9898962a4a7d96764b287b085b5b3d9ffae69cdefd1/yarl-1.20.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:21242b4288a6d56f04ea193adde174b7e347ac46ce6bc84989ff7c1b1ecea84e", size = 339149, upload-time = "2025-06-10T00:42:42.627Z" }, - { url = "https://files.pythonhosted.org/packages/3c/95/d7fc301cc4661785967acc04f54a4a42d5124905e27db27bb578aac49b5c/yarl-1.20.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:bea21cdae6c7eb02ba02a475f37463abfe0a01f5d7200121b03e605d6a0439f8", size = 333327, upload-time = "2025-06-10T00:42:44.842Z" }, - { url = "https://files.pythonhosted.org/packages/65/94/e21269718349582eee81efc5c1c08ee71c816bfc1585b77d0ec3f58089eb/yarl-1.20.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f8a891e4a22a89f5dde7862994485e19db246b70bb288d3ce73a34422e55b23", size = 326054, upload-time = "2025-06-10T00:42:47.149Z" }, - { url = "https://files.pythonhosted.org/packages/32/ae/8616d1f07853704523519f6131d21f092e567c5af93de7e3e94b38d7f065/yarl-1.20.1-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dd803820d44c8853a109a34e3660e5a61beae12970da479cf44aa2954019bf70", size = 315035, upload-time = "2025-06-10T00:42:48.852Z" }, - { url = "https://files.pythonhosted.org/packages/48/aa/0ace06280861ef055855333707db5e49c6e3a08840a7ce62682259d0a6c0/yarl-1.20.1-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:b982fa7f74c80d5c0c7b5b38f908971e513380a10fecea528091405f519b9ebb", size = 338962, upload-time = "2025-06-10T00:42:51.024Z" }, - { url = "https://files.pythonhosted.org/packages/20/52/1e9d0e6916f45a8fb50e6844f01cb34692455f1acd548606cbda8134cd1e/yarl-1.20.1-cp310-cp310-musllinux_1_2_armv7l.whl", hash = "sha256:33f29ecfe0330c570d997bcf1afd304377f2e48f61447f37e846a6058a4d33b2", size = 335399, upload-time = "2025-06-10T00:42:53.007Z" }, - { url = "https://files.pythonhosted.org/packages/f2/65/60452df742952c630e82f394cd409de10610481d9043aa14c61bf846b7b1/yarl-1.20.1-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:835ab2cfc74d5eb4a6a528c57f05688099da41cf4957cf08cad38647e4a83b30", size = 338649, upload-time = "2025-06-10T00:42:54.964Z" }, - { url = "https://files.pythonhosted.org/packages/7b/f5/6cd4ff38dcde57a70f23719a838665ee17079640c77087404c3d34da6727/yarl-1.20.1-cp310-cp310-musllinux_1_2_ppc64le.whl", hash = "sha256:46b5e0ccf1943a9a6e766b2c2b8c732c55b34e28be57d8daa2b3c1d1d4009309", size = 358563, upload-time = "2025-06-10T00:42:57.28Z" }, - { url = "https://files.pythonhosted.org/packages/d1/90/c42eefd79d0d8222cb3227bdd51b640c0c1d0aa33fe4cc86c36eccba77d3/yarl-1.20.1-cp310-cp310-musllinux_1_2_s390x.whl", hash = "sha256:df47c55f7d74127d1b11251fe6397d84afdde0d53b90bedb46a23c0e534f9d24", size = 357609, upload-time = "2025-06-10T00:42:59.055Z" }, - { url = "https://files.pythonhosted.org/packages/03/c8/cea6b232cb4617514232e0f8a718153a95b5d82b5290711b201545825532/yarl-1.20.1-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:76d12524d05841276b0e22573f28d5fbcb67589836772ae9244d90dd7d66aa13", size = 350224, upload-time = "2025-06-10T00:43:01.248Z" }, - { url = "https://files.pythonhosted.org/packages/ce/a3/eaa0ab9712f1f3d01faf43cf6f1f7210ce4ea4a7e9b28b489a2261ca8db9/yarl-1.20.1-cp310-cp310-win32.whl", hash = "sha256:6c4fbf6b02d70e512d7ade4b1f998f237137f1417ab07ec06358ea04f69134f8", size = 81753, upload-time = "2025-06-10T00:43:03.486Z" }, - { url = "https://files.pythonhosted.org/packages/8f/34/e4abde70a9256465fe31c88ed02c3f8502b7b5dead693a4f350a06413f28/yarl-1.20.1-cp310-cp310-win_amd64.whl", hash = "sha256:aef6c4d69554d44b7f9d923245f8ad9a707d971e6209d51279196d8e8fe1ae16", size = 86817, upload-time = "2025-06-10T00:43:05.231Z" }, - { url = "https://files.pythonhosted.org/packages/b1/18/893b50efc2350e47a874c5c2d67e55a0ea5df91186b2a6f5ac52eff887cd/yarl-1.20.1-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:47ee6188fea634bdfaeb2cc420f5b3b17332e6225ce88149a17c413c77ff269e", size = 133833, upload-time = "2025-06-10T00:43:07.393Z" }, - { url = "https://files.pythonhosted.org/packages/89/ed/b8773448030e6fc47fa797f099ab9eab151a43a25717f9ac043844ad5ea3/yarl-1.20.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:d0f6500f69e8402d513e5eedb77a4e1818691e8f45e6b687147963514d84b44b", size = 91070, upload-time = "2025-06-10T00:43:09.538Z" }, - { url = "https://files.pythonhosted.org/packages/e3/e3/409bd17b1e42619bf69f60e4f031ce1ccb29bd7380117a55529e76933464/yarl-1.20.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:7a8900a42fcdaad568de58887c7b2f602962356908eedb7628eaf6021a6e435b", size = 89818, upload-time = "2025-06-10T00:43:11.575Z" }, - { url = "https://files.pythonhosted.org/packages/f8/77/64d8431a4d77c856eb2d82aa3de2ad6741365245a29b3a9543cd598ed8c5/yarl-1.20.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bad6d131fda8ef508b36be3ece16d0902e80b88ea7200f030a0f6c11d9e508d4", size = 347003, upload-time = "2025-06-10T00:43:14.088Z" }, - { url = "https://files.pythonhosted.org/packages/8d/d2/0c7e4def093dcef0bd9fa22d4d24b023788b0a33b8d0088b51aa51e21e99/yarl-1.20.1-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:df018d92fe22aaebb679a7f89fe0c0f368ec497e3dda6cb81a567610f04501f1", size = 336537, upload-time = "2025-06-10T00:43:16.431Z" }, - { url = "https://files.pythonhosted.org/packages/f0/f3/fc514f4b2cf02cb59d10cbfe228691d25929ce8f72a38db07d3febc3f706/yarl-1.20.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f969afbb0a9b63c18d0feecf0db09d164b7a44a053e78a7d05f5df163e43833", size = 362358, upload-time = "2025-06-10T00:43:18.704Z" }, - { url = "https://files.pythonhosted.org/packages/ea/6d/a313ac8d8391381ff9006ac05f1d4331cee3b1efaa833a53d12253733255/yarl-1.20.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:812303eb4aa98e302886ccda58d6b099e3576b1b9276161469c25803a8db277d", size = 357362, upload-time = "2025-06-10T00:43:20.888Z" }, - { url = "https://files.pythonhosted.org/packages/00/70/8f78a95d6935a70263d46caa3dd18e1f223cf2f2ff2037baa01a22bc5b22/yarl-1.20.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98c4a7d166635147924aa0bf9bfe8d8abad6fffa6102de9c99ea04a1376f91e8", size = 348979, upload-time = "2025-06-10T00:43:23.169Z" }, - { url = "https://files.pythonhosted.org/packages/cb/05/42773027968968f4f15143553970ee36ead27038d627f457cc44bbbeecf3/yarl-1.20.1-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:12e768f966538e81e6e7550f9086a6236b16e26cd964cf4df35349970f3551cf", size = 337274, upload-time = "2025-06-10T00:43:27.111Z" }, - { url = "https://files.pythonhosted.org/packages/05/be/665634aa196954156741ea591d2f946f1b78ceee8bb8f28488bf28c0dd62/yarl-1.20.1-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:fe41919b9d899661c5c28a8b4b0acf704510b88f27f0934ac7a7bebdd8938d5e", size = 363294, upload-time = "2025-06-10T00:43:28.96Z" }, - { url = "https://files.pythonhosted.org/packages/eb/90/73448401d36fa4e210ece5579895731f190d5119c4b66b43b52182e88cd5/yarl-1.20.1-cp311-cp311-musllinux_1_2_armv7l.whl", hash = "sha256:8601bc010d1d7780592f3fc1bdc6c72e2b6466ea34569778422943e1a1f3c389", size = 358169, upload-time = "2025-06-10T00:43:30.701Z" }, - { url = "https://files.pythonhosted.org/packages/c3/b0/fce922d46dc1eb43c811f1889f7daa6001b27a4005587e94878570300881/yarl-1.20.1-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:daadbdc1f2a9033a2399c42646fbd46da7992e868a5fe9513860122d7fe7a73f", size = 362776, upload-time = "2025-06-10T00:43:32.51Z" }, - { url = "https://files.pythonhosted.org/packages/f1/0d/b172628fce039dae8977fd22caeff3eeebffd52e86060413f5673767c427/yarl-1.20.1-cp311-cp311-musllinux_1_2_ppc64le.whl", hash = "sha256:03aa1e041727cb438ca762628109ef1333498b122e4c76dd858d186a37cec845", size = 381341, upload-time = "2025-06-10T00:43:34.543Z" }, - { url = "https://files.pythonhosted.org/packages/6b/9b/5b886d7671f4580209e855974fe1cecec409aa4a89ea58b8f0560dc529b1/yarl-1.20.1-cp311-cp311-musllinux_1_2_s390x.whl", hash = "sha256:642980ef5e0fa1de5fa96d905c7e00cb2c47cb468bfcac5a18c58e27dbf8d8d1", size = 379988, upload-time = "2025-06-10T00:43:36.489Z" }, - { url = "https://files.pythonhosted.org/packages/73/be/75ef5fd0fcd8f083a5d13f78fd3f009528132a1f2a1d7c925c39fa20aa79/yarl-1.20.1-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:86971e2795584fe8c002356d3b97ef6c61862720eeff03db2a7c86b678d85b3e", size = 371113, upload-time = "2025-06-10T00:43:38.592Z" }, - { url = "https://files.pythonhosted.org/packages/50/4f/62faab3b479dfdcb741fe9e3f0323e2a7d5cd1ab2edc73221d57ad4834b2/yarl-1.20.1-cp311-cp311-win32.whl", hash = "sha256:597f40615b8d25812f14562699e287f0dcc035d25eb74da72cae043bb884d773", size = 81485, upload-time = "2025-06-10T00:43:41.038Z" }, - { url = "https://files.pythonhosted.org/packages/f0/09/d9c7942f8f05c32ec72cd5c8e041c8b29b5807328b68b4801ff2511d4d5e/yarl-1.20.1-cp311-cp311-win_amd64.whl", hash = "sha256:26ef53a9e726e61e9cd1cda6b478f17e350fb5800b4bd1cd9fe81c4d91cfeb2e", size = 86686, upload-time = "2025-06-10T00:43:42.692Z" }, - { url = "https://files.pythonhosted.org/packages/5f/9a/cb7fad7d73c69f296eda6815e4a2c7ed53fc70c2f136479a91c8e5fbdb6d/yarl-1.20.1-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:bdcc4cd244e58593a4379fe60fdee5ac0331f8eb70320a24d591a3be197b94a9", size = 133667, upload-time = "2025-06-10T00:43:44.369Z" }, - { url = "https://files.pythonhosted.org/packages/67/38/688577a1cb1e656e3971fb66a3492501c5a5df56d99722e57c98249e5b8a/yarl-1.20.1-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:b29a2c385a5f5b9c7d9347e5812b6f7ab267193c62d282a540b4fc528c8a9d2a", size = 91025, upload-time = "2025-06-10T00:43:46.295Z" }, - { url = "https://files.pythonhosted.org/packages/50/ec/72991ae51febeb11a42813fc259f0d4c8e0507f2b74b5514618d8b640365/yarl-1.20.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:1112ae8154186dfe2de4732197f59c05a83dc814849a5ced892b708033f40dc2", size = 89709, upload-time = "2025-06-10T00:43:48.22Z" }, - { url = "https://files.pythonhosted.org/packages/99/da/4d798025490e89426e9f976702e5f9482005c548c579bdae792a4c37769e/yarl-1.20.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:90bbd29c4fe234233f7fa2b9b121fb63c321830e5d05b45153a2ca68f7d310ee", size = 352287, upload-time = "2025-06-10T00:43:49.924Z" }, - { url = "https://files.pythonhosted.org/packages/1a/26/54a15c6a567aac1c61b18aa0f4b8aa2e285a52d547d1be8bf48abe2b3991/yarl-1.20.1-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:680e19c7ce3710ac4cd964e90dad99bf9b5029372ba0c7cbfcd55e54d90ea819", size = 345429, upload-time = "2025-06-10T00:43:51.7Z" }, - { url = "https://files.pythonhosted.org/packages/d6/95/9dcf2386cb875b234353b93ec43e40219e14900e046bf6ac118f94b1e353/yarl-1.20.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4a979218c1fdb4246a05efc2cc23859d47c89af463a90b99b7c56094daf25a16", size = 365429, upload-time = "2025-06-10T00:43:53.494Z" }, - { url = "https://files.pythonhosted.org/packages/91/b2/33a8750f6a4bc224242a635f5f2cff6d6ad5ba651f6edcccf721992c21a0/yarl-1.20.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:255b468adf57b4a7b65d8aad5b5138dce6a0752c139965711bdcb81bc370e1b6", size = 363862, upload-time = "2025-06-10T00:43:55.766Z" }, - { url = "https://files.pythonhosted.org/packages/98/28/3ab7acc5b51f4434b181b0cee8f1f4b77a65919700a355fb3617f9488874/yarl-1.20.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a97d67108e79cfe22e2b430d80d7571ae57d19f17cda8bb967057ca8a7bf5bfd", size = 355616, upload-time = "2025-06-10T00:43:58.056Z" }, - { url = "https://files.pythonhosted.org/packages/36/a3/f666894aa947a371724ec7cd2e5daa78ee8a777b21509b4252dd7bd15e29/yarl-1.20.1-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:8570d998db4ddbfb9a590b185a0a33dbf8aafb831d07a5257b4ec9948df9cb0a", size = 339954, upload-time = "2025-06-10T00:43:59.773Z" }, - { url = "https://files.pythonhosted.org/packages/f1/81/5f466427e09773c04219d3450d7a1256138a010b6c9f0af2d48565e9ad13/yarl-1.20.1-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:97c75596019baae7c71ccf1d8cc4738bc08134060d0adfcbe5642f778d1dca38", size = 365575, upload-time = "2025-06-10T00:44:02.051Z" }, - { url = "https://files.pythonhosted.org/packages/2e/e3/e4b0ad8403e97e6c9972dd587388940a032f030ebec196ab81a3b8e94d31/yarl-1.20.1-cp312-cp312-musllinux_1_2_armv7l.whl", hash = "sha256:1c48912653e63aef91ff988c5432832692ac5a1d8f0fb8a33091520b5bbe19ef", size = 365061, upload-time = "2025-06-10T00:44:04.196Z" }, - { url = "https://files.pythonhosted.org/packages/ac/99/b8a142e79eb86c926f9f06452eb13ecb1bb5713bd01dc0038faf5452e544/yarl-1.20.1-cp312-cp312-musllinux_1_2_i686.whl", hash = "sha256:4c3ae28f3ae1563c50f3d37f064ddb1511ecc1d5584e88c6b7c63cf7702a6d5f", size = 364142, upload-time = "2025-06-10T00:44:06.527Z" }, - { url = "https://files.pythonhosted.org/packages/34/f2/08ed34a4a506d82a1a3e5bab99ccd930a040f9b6449e9fd050320e45845c/yarl-1.20.1-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:c5e9642f27036283550f5f57dc6156c51084b458570b9d0d96100c8bebb186a8", size = 381894, upload-time = "2025-06-10T00:44:08.379Z" }, - { url = "https://files.pythonhosted.org/packages/92/f8/9a3fbf0968eac704f681726eff595dce9b49c8a25cd92bf83df209668285/yarl-1.20.1-cp312-cp312-musllinux_1_2_s390x.whl", hash = "sha256:2c26b0c49220d5799f7b22c6838409ee9bc58ee5c95361a4d7831f03cc225b5a", size = 383378, upload-time = "2025-06-10T00:44:10.51Z" }, - { url = "https://files.pythonhosted.org/packages/af/85/9363f77bdfa1e4d690957cd39d192c4cacd1c58965df0470a4905253b54f/yarl-1.20.1-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:564ab3d517e3d01c408c67f2e5247aad4019dcf1969982aba3974b4093279004", size = 374069, upload-time = "2025-06-10T00:44:12.834Z" }, - { url = "https://files.pythonhosted.org/packages/35/99/9918c8739ba271dcd935400cff8b32e3cd319eaf02fcd023d5dcd487a7c8/yarl-1.20.1-cp312-cp312-win32.whl", hash = "sha256:daea0d313868da1cf2fac6b2d3a25c6e3a9e879483244be38c8e6a41f1d876a5", size = 81249, upload-time = "2025-06-10T00:44:14.731Z" }, - { url = "https://files.pythonhosted.org/packages/eb/83/5d9092950565481b413b31a23e75dd3418ff0a277d6e0abf3729d4d1ce25/yarl-1.20.1-cp312-cp312-win_amd64.whl", hash = "sha256:48ea7d7f9be0487339828a4de0360d7ce0efc06524a48e1810f945c45b813698", size = 86710, upload-time = "2025-06-10T00:44:16.716Z" }, - { url = "https://files.pythonhosted.org/packages/8a/e1/2411b6d7f769a07687acee88a062af5833cf1966b7266f3d8dfb3d3dc7d3/yarl-1.20.1-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:0b5ff0fbb7c9f1b1b5ab53330acbfc5247893069e7716840c8e7d5bb7355038a", size = 131811, upload-time = "2025-06-10T00:44:18.933Z" }, - { url = "https://files.pythonhosted.org/packages/b2/27/584394e1cb76fb771371770eccad35de400e7b434ce3142c2dd27392c968/yarl-1.20.1-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:14f326acd845c2b2e2eb38fb1346c94f7f3b01a4f5c788f8144f9b630bfff9a3", size = 90078, upload-time = "2025-06-10T00:44:20.635Z" }, - { url = "https://files.pythonhosted.org/packages/bf/9a/3246ae92d4049099f52d9b0fe3486e3b500e29b7ea872d0f152966fc209d/yarl-1.20.1-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:f60e4ad5db23f0b96e49c018596707c3ae89f5d0bd97f0ad3684bcbad899f1e7", size = 88748, upload-time = "2025-06-10T00:44:22.34Z" }, - { url = "https://files.pythonhosted.org/packages/a3/25/35afe384e31115a1a801fbcf84012d7a066d89035befae7c5d4284df1e03/yarl-1.20.1-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:49bdd1b8e00ce57e68ba51916e4bb04461746e794e7c4d4bbc42ba2f18297691", size = 349595, upload-time = "2025-06-10T00:44:24.314Z" }, - { url = "https://files.pythonhosted.org/packages/28/2d/8aca6cb2cabc8f12efcb82749b9cefecbccfc7b0384e56cd71058ccee433/yarl-1.20.1-cp313-cp313-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:66252d780b45189975abfed839616e8fd2dbacbdc262105ad7742c6ae58f3e31", size = 342616, upload-time = "2025-06-10T00:44:26.167Z" }, - { url = "https://files.pythonhosted.org/packages/0b/e9/1312633d16b31acf0098d30440ca855e3492d66623dafb8e25b03d00c3da/yarl-1.20.1-cp313-cp313-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59174e7332f5d153d8f7452a102b103e2e74035ad085f404df2e40e663a22b28", size = 361324, upload-time = "2025-06-10T00:44:27.915Z" }, - { url = "https://files.pythonhosted.org/packages/bc/a0/688cc99463f12f7669eec7c8acc71ef56a1521b99eab7cd3abb75af887b0/yarl-1.20.1-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:e3968ec7d92a0c0f9ac34d5ecfd03869ec0cab0697c91a45db3fbbd95fe1b653", size = 359676, upload-time = "2025-06-10T00:44:30.041Z" }, - { url = "https://files.pythonhosted.org/packages/af/44/46407d7f7a56e9a85a4c207724c9f2c545c060380718eea9088f222ba697/yarl-1.20.1-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d1a4fbb50e14396ba3d375f68bfe02215d8e7bc3ec49da8341fe3157f59d2ff5", size = 352614, upload-time = "2025-06-10T00:44:32.171Z" }, - { url = "https://files.pythonhosted.org/packages/b1/91/31163295e82b8d5485d31d9cf7754d973d41915cadce070491778d9c9825/yarl-1.20.1-cp313-cp313-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:11a62c839c3a8eac2410e951301309426f368388ff2f33799052787035793b02", size = 336766, upload-time = "2025-06-10T00:44:34.494Z" }, - { url = "https://files.pythonhosted.org/packages/b4/8e/c41a5bc482121f51c083c4c2bcd16b9e01e1cf8729e380273a952513a21f/yarl-1.20.1-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:041eaa14f73ff5a8986b4388ac6bb43a77f2ea09bf1913df7a35d4646db69e53", size = 364615, upload-time = "2025-06-10T00:44:36.856Z" }, - { url = "https://files.pythonhosted.org/packages/e3/5b/61a3b054238d33d70ea06ebba7e58597891b71c699e247df35cc984ab393/yarl-1.20.1-cp313-cp313-musllinux_1_2_armv7l.whl", hash = "sha256:377fae2fef158e8fd9d60b4c8751387b8d1fb121d3d0b8e9b0be07d1b41e83dc", size = 360982, upload-time = "2025-06-10T00:44:39.141Z" }, - { url = "https://files.pythonhosted.org/packages/df/a3/6a72fb83f8d478cb201d14927bc8040af901811a88e0ff2da7842dd0ed19/yarl-1.20.1-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:1c92f4390e407513f619d49319023664643d3339bd5e5a56a3bebe01bc67ec04", size = 369792, upload-time = "2025-06-10T00:44:40.934Z" }, - { url = "https://files.pythonhosted.org/packages/7c/af/4cc3c36dfc7c077f8dedb561eb21f69e1e9f2456b91b593882b0b18c19dc/yarl-1.20.1-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:d25ddcf954df1754ab0f86bb696af765c5bfaba39b74095f27eececa049ef9a4", size = 382049, upload-time = "2025-06-10T00:44:42.854Z" }, - { url = "https://files.pythonhosted.org/packages/19/3a/e54e2c4752160115183a66dc9ee75a153f81f3ab2ba4bf79c3c53b33de34/yarl-1.20.1-cp313-cp313-musllinux_1_2_s390x.whl", hash = "sha256:909313577e9619dcff8c31a0ea2aa0a2a828341d92673015456b3ae492e7317b", size = 384774, upload-time = "2025-06-10T00:44:45.275Z" }, - { url = "https://files.pythonhosted.org/packages/9c/20/200ae86dabfca89060ec6447649f219b4cbd94531e425e50d57e5f5ac330/yarl-1.20.1-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:793fd0580cb9664548c6b83c63b43c477212c0260891ddf86809e1c06c8b08f1", size = 374252, upload-time = "2025-06-10T00:44:47.31Z" }, - { url = "https://files.pythonhosted.org/packages/83/75/11ee332f2f516b3d094e89448da73d557687f7d137d5a0f48c40ff211487/yarl-1.20.1-cp313-cp313-win32.whl", hash = "sha256:468f6e40285de5a5b3c44981ca3a319a4b208ccc07d526b20b12aeedcfa654b7", size = 81198, upload-time = "2025-06-10T00:44:49.164Z" }, - { url = "https://files.pythonhosted.org/packages/ba/ba/39b1ecbf51620b40ab402b0fc817f0ff750f6d92712b44689c2c215be89d/yarl-1.20.1-cp313-cp313-win_amd64.whl", hash = "sha256:495b4ef2fea40596bfc0affe3837411d6aa3371abcf31aac0ccc4bdd64d4ef5c", size = 86346, upload-time = "2025-06-10T00:44:51.182Z" }, - { url = "https://files.pythonhosted.org/packages/43/c7/669c52519dca4c95153c8ad96dd123c79f354a376346b198f438e56ffeb4/yarl-1.20.1-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:f60233b98423aab21d249a30eb27c389c14929f47be8430efa7dbd91493a729d", size = 138826, upload-time = "2025-06-10T00:44:52.883Z" }, - { url = "https://files.pythonhosted.org/packages/6a/42/fc0053719b44f6ad04a75d7f05e0e9674d45ef62f2d9ad2c1163e5c05827/yarl-1.20.1-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:6f3eff4cc3f03d650d8755c6eefc844edde99d641d0dcf4da3ab27141a5f8ddf", size = 93217, upload-time = "2025-06-10T00:44:54.658Z" }, - { url = "https://files.pythonhosted.org/packages/4f/7f/fa59c4c27e2a076bba0d959386e26eba77eb52ea4a0aac48e3515c186b4c/yarl-1.20.1-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:69ff8439d8ba832d6bed88af2c2b3445977eba9a4588b787b32945871c2444e3", size = 92700, upload-time = "2025-06-10T00:44:56.784Z" }, - { url = "https://files.pythonhosted.org/packages/2f/d4/062b2f48e7c93481e88eff97a6312dca15ea200e959f23e96d8ab898c5b8/yarl-1.20.1-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cf34efa60eb81dd2645a2e13e00bb98b76c35ab5061a3989c7a70f78c85006d", size = 347644, upload-time = "2025-06-10T00:44:59.071Z" }, - { url = "https://files.pythonhosted.org/packages/89/47/78b7f40d13c8f62b499cc702fdf69e090455518ae544c00a3bf4afc9fc77/yarl-1.20.1-cp313-cp313t-manylinux_2_17_armv7l.manylinux2014_armv7l.manylinux_2_31_armv7l.whl", hash = "sha256:8e0fe9364ad0fddab2688ce72cb7a8e61ea42eff3c7caeeb83874a5d479c896c", size = 323452, upload-time = "2025-06-10T00:45:01.605Z" }, - { url = "https://files.pythonhosted.org/packages/eb/2b/490d3b2dc66f52987d4ee0d3090a147ea67732ce6b4d61e362c1846d0d32/yarl-1.20.1-cp313-cp313t-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8f64fbf81878ba914562c672024089e3401974a39767747691c65080a67b18c1", size = 346378, upload-time = "2025-06-10T00:45:03.946Z" }, - { url = "https://files.pythonhosted.org/packages/66/ad/775da9c8a94ce925d1537f939a4f17d782efef1f973039d821cbe4bcc211/yarl-1.20.1-cp313-cp313t-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f6342d643bf9a1de97e512e45e4b9560a043347e779a173250824f8b254bd5ce", size = 353261, upload-time = "2025-06-10T00:45:05.992Z" }, - { url = "https://files.pythonhosted.org/packages/4b/23/0ed0922b47a4f5c6eb9065d5ff1e459747226ddce5c6a4c111e728c9f701/yarl-1.20.1-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:56dac5f452ed25eef0f6e3c6a066c6ab68971d96a9fb441791cad0efba6140d3", size = 335987, upload-time = "2025-06-10T00:45:08.227Z" }, - { url = "https://files.pythonhosted.org/packages/3e/49/bc728a7fe7d0e9336e2b78f0958a2d6b288ba89f25a1762407a222bf53c3/yarl-1.20.1-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7d7f497126d65e2cad8dc5f97d34c27b19199b6414a40cb36b52f41b79014be", size = 329361, upload-time = "2025-06-10T00:45:10.11Z" }, - { url = "https://files.pythonhosted.org/packages/93/8f/b811b9d1f617c83c907e7082a76e2b92b655400e61730cd61a1f67178393/yarl-1.20.1-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:67e708dfb8e78d8a19169818eeb5c7a80717562de9051bf2413aca8e3696bf16", size = 346460, upload-time = "2025-06-10T00:45:12.055Z" }, - { url = "https://files.pythonhosted.org/packages/70/fd/af94f04f275f95da2c3b8b5e1d49e3e79f1ed8b6ceb0f1664cbd902773ff/yarl-1.20.1-cp313-cp313t-musllinux_1_2_armv7l.whl", hash = "sha256:595c07bc79af2494365cc96ddeb772f76272364ef7c80fb892ef9d0649586513", size = 334486, upload-time = "2025-06-10T00:45:13.995Z" }, - { url = "https://files.pythonhosted.org/packages/84/65/04c62e82704e7dd0a9b3f61dbaa8447f8507655fd16c51da0637b39b2910/yarl-1.20.1-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:7bdd2f80f4a7df852ab9ab49484a4dee8030023aa536df41f2d922fd57bf023f", size = 342219, upload-time = "2025-06-10T00:45:16.479Z" }, - { url = "https://files.pythonhosted.org/packages/91/95/459ca62eb958381b342d94ab9a4b6aec1ddec1f7057c487e926f03c06d30/yarl-1.20.1-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:c03bfebc4ae8d862f853a9757199677ab74ec25424d0ebd68a0027e9c639a390", size = 350693, upload-time = "2025-06-10T00:45:18.399Z" }, - { url = "https://files.pythonhosted.org/packages/a6/00/d393e82dd955ad20617abc546a8f1aee40534d599ff555ea053d0ec9bf03/yarl-1.20.1-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:344d1103e9c1523f32a5ed704d576172d2cabed3122ea90b1d4e11fe17c66458", size = 355803, upload-time = "2025-06-10T00:45:20.677Z" }, - { url = "https://files.pythonhosted.org/packages/9e/ed/c5fb04869b99b717985e244fd93029c7a8e8febdfcffa06093e32d7d44e7/yarl-1.20.1-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:88cab98aa4e13e1ade8c141daeedd300a4603b7132819c484841bb7af3edce9e", size = 341709, upload-time = "2025-06-10T00:45:23.221Z" }, - { url = "https://files.pythonhosted.org/packages/24/fd/725b8e73ac2a50e78a4534ac43c6addf5c1c2d65380dd48a9169cc6739a9/yarl-1.20.1-cp313-cp313t-win32.whl", hash = "sha256:b121ff6a7cbd4abc28985b6028235491941b9fe8fe226e6fdc539c977ea1739d", size = 86591, upload-time = "2025-06-10T00:45:25.793Z" }, - { url = "https://files.pythonhosted.org/packages/94/c3/b2e9f38bc3e11191981d57ea08cab2166e74ea770024a646617c9cddd9f6/yarl-1.20.1-cp313-cp313t-win_amd64.whl", hash = "sha256:541d050a355bbbc27e55d906bc91cb6fe42f96c01413dd0f4ed5a5240513874f", size = 93003, upload-time = "2025-06-10T00:45:27.752Z" }, - { url = "https://files.pythonhosted.org/packages/b4/2d/2345fce04cfd4bee161bf1e7d9cdc702e3e16109021035dbb24db654a622/yarl-1.20.1-py3-none-any.whl", hash = "sha256:83b8eb083fe4683c6115795d9fc1cfaf2cbbefb19b3a1cb68f6527460f483a77", size = 46542, upload-time = "2025-06-10T00:46:07.521Z" }, -] diff --git a/examples/python/legacy/sync.py b/examples/python/legacy/sync.py deleted file mode 100755 index 48a5c412cf..0000000000 --- a/examples/python/legacy/sync.py +++ /dev/null @@ -1,38 +0,0 @@ -#!/usr/bin/env python3 - -import subprocess -from pathlib import Path - - -def run_uv_sync(project_dir: Path): - """Run uv sync in the given directory if it contains a pyproject.toml file.""" - if (project_dir / "pyproject.toml").exists(): - print(f"Running uv sync in {project_dir}") - subprocess.run(["uv", "sync"], cwd=project_dir, check=True) - - -def main(): - # Get the examples/python directory - examples_dir = Path(__file__).parent.absolute() - - # Process servers directory - servers_dir = examples_dir / "servers" - for server_dir in servers_dir.iterdir(): - if server_dir.is_dir(): - run_uv_sync(server_dir) - - # Process clients directory - clients_dir = examples_dir / "clients" - for client_dir in clients_dir.iterdir(): - if client_dir.is_dir(): - run_uv_sync(client_dir) - - # Process fullstack directory - fullstack_dir = examples_dir / "fullstack" - for fullstack_dir in fullstack_dir.iterdir(): - if fullstack_dir.is_dir(): - run_uv_sync(fullstack_dir) - - -if __name__ == "__main__": - main() diff --git a/examples/python/servers/advanced/.env-local b/examples/python/servers/advanced/.env-local new file mode 100644 index 0000000000..c9c0c0fbe8 --- /dev/null +++ b/examples/python/servers/advanced/.env-local @@ -0,0 +1,6 @@ +PORT=4021 +EVM_ADDRESS= +SVM_ADDRESS= +TVM_ADDRESS= +TVM_NETWORK=tvm:-3 +FACILITATOR_URL=http://localhost:4022 diff --git a/examples/python/servers/advanced/README.md b/examples/python/servers/advanced/README.md index 497694b743..2a0f4afe2f 100644 --- a/examples/python/servers/advanced/README.md +++ b/examples/python/servers/advanced/README.md @@ -1,6 +1,6 @@ # x402 FastAPI Advanced Example -FastAPI server demonstrating advanced x402 patterns including dynamic pricing, payment routing, lifecycle hooks and API discoverability. +FastAPI server demonstrating advanced x402 patterns including dynamic pricing, payment routing, lifecycle hooks and API discoverability across EVM, SVM, and TVM. ```python from fastapi import FastAPI @@ -10,18 +10,21 @@ from x402.http.types import RouteConfig from x402.server import x402ResourceServer from x402.mechanisms.evm.exact import ExactEvmServerScheme from x402.mechanisms.svm.exact import ExactSvmServerScheme +from x402.mechanisms.tvm.exact import ExactTvmServerScheme app = FastAPI() server = x402ResourceServer(HTTPFacilitatorClient(FacilitatorConfig(url=facilitator_url))) server.register("eip155:84532", ExactEvmServerScheme()) server.register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", ExactSvmServerScheme()) +server.register("tvm:-3", ExactTvmServerScheme()) routes = { "GET /weather": RouteConfig( accepts=[ PaymentOption(scheme="exact", price="$0.01", network="eip155:84532", pay_to=evm_address), PaymentOption(scheme="exact", price="$0.01", network="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", pay_to=svm_address), + PaymentOption(scheme="exact", price="$0.001", network="tvm:-3", pay_to=tvm_address), ] ), } @@ -36,8 +39,10 @@ async def get_weather(): - Python 3.10+ - uv (install via [docs.astral.sh/uv](https://docs.astral.sh/uv/getting-started/installation/)) -- Valid EVM address for receiving payments (Base Sepolia) -- Valid SVM address for receiving payments (Solana Devnet) +- Optional payment addresses for one or more networks: + - EVM address for Base Sepolia + - SVM address for Solana Devnet + - TVM address for TON testnet/mainnet - URL of a facilitator supporting the desired payment network, see [facilitator list](https://www.x402.org/ecosystem?category=facilitators) ## Setup @@ -52,6 +57,8 @@ cp .env-local .env - `EVM_ADDRESS` - Ethereum address to receive payments (Base Sepolia) - `SVM_ADDRESS` - Solana address to receive payments (Solana Devnet) +- `TVM_ADDRESS` - TON wallet address to receive TVM payments +- `TVM_NETWORK` - TVM CAIP-2 network (optional, defaults to `tvm:-3`) - `FACILITATOR_URL` - Facilitator endpoint URL (optional, defaults to production) 3. Install dependencies: @@ -156,6 +163,13 @@ routes = { network="solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", pay_to=SVM_ADDRESS, ), + # TVM payment option + PaymentOption( + scheme="exact", + price="$0.10", + network="tvm:-3", + pay_to=TVM_ADDRESS, + ), ] ), } @@ -193,6 +207,10 @@ Network identifiers use [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/mai - `solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1` — Solana Devnet - `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` — Solana Mainnet +**TVM Networks:** +- `tvm:-3` — TON Testnet +- `tvm:-239` — TON Mainnet + ## Advanced Features ### Paywall (Browser Payment UI) diff --git a/examples/python/servers/advanced/all_networks.py b/examples/python/servers/advanced/all_networks.py index a5f21c4c10..ab56bf6bc4 100644 --- a/examples/python/servers/advanced/all_networks.py +++ b/examples/python/servers/advanced/all_networks.py @@ -4,7 +4,7 @@ optional chain configuration via environment variables. New chain support should be added here in alphabetic order by network prefix -(e.g., "eip155" before "solana"). +(e.g., "eip155" before "solana" before "tvm"). """ import os @@ -19,6 +19,8 @@ from x402.http.types import RouteConfig from x402.mechanisms.evm.exact import ExactEvmServerScheme from x402.mechanisms.svm.exact import ExactSvmServerScheme +from x402.mechanisms.tvm import TVM_TESTNET +from x402.mechanisms.tvm.exact import ExactTvmServerScheme from x402.schemas import Network from x402.server import x402ResourceServer @@ -27,15 +29,17 @@ # Configuration - optional per network EVM_ADDRESS = os.getenv("EVM_ADDRESS") SVM_ADDRESS = os.getenv("SVM_ADDRESS") +TVM_ADDRESS = os.getenv("TVM_ADDRESS") # Validate at least one address is provided -if not EVM_ADDRESS and not SVM_ADDRESS: - print("❌ At least one of EVM_ADDRESS or SVM_ADDRESS is required") +if not EVM_ADDRESS and not SVM_ADDRESS and not TVM_ADDRESS: + print("❌ At least one of EVM_ADDRESS, SVM_ADDRESS, or TVM_ADDRESS is required") sys.exit(1) # Network configuration EVM_NETWORK: Network = "eip155:84532" # Base Sepolia SVM_NETWORK: Network = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" # Solana Devnet +TVM_NETWORK: Network = os.getenv("TVM_NETWORK", TVM_TESTNET) # TON testnet by default FACILITATOR_URL = os.getenv("FACILITATOR_URL", "https://x402.org/facilitator") @@ -52,7 +56,7 @@ class WeatherResponse(BaseModel): # App app = FastAPI( title="All Networks Server", - description="x402 server supporting both EVM and SVM networks", + description="x402 server supporting EVM, SVM, and TVM networks", version="2.0.0", ) @@ -77,6 +81,15 @@ class WeatherResponse(BaseModel): network=SVM_NETWORK, ) ) +if TVM_ADDRESS: + accepts.append( + PaymentOption( + scheme="exact", + pay_to=TVM_ADDRESS, + price="$0.001", + network=TVM_NETWORK, + ) + ) # x402 Middleware facilitator = HTTPFacilitatorClient(FacilitatorConfig(url=FACILITATOR_URL)) @@ -87,6 +100,8 @@ class WeatherResponse(BaseModel): server.register(EVM_NETWORK, ExactEvmServerScheme()) if SVM_ADDRESS: server.register(SVM_NETWORK, ExactSvmServerScheme()) +if TVM_ADDRESS: + server.register(TVM_NETWORK, ExactTvmServerScheme()) routes = { "GET /weather": RouteConfig( @@ -118,6 +133,8 @@ async def get_weather() -> WeatherResponse: print(f" EVM: {EVM_ADDRESS} on {EVM_NETWORK}") if SVM_ADDRESS: print(f" SVM: {SVM_ADDRESS} on {SVM_NETWORK}") + if TVM_ADDRESS: + print(f" TVM: {TVM_ADDRESS} on {TVM_NETWORK}") print(f" Facilitator: {FACILITATOR_URL}") print() uvicorn.run(app, host="0.0.0.0", port=port) diff --git a/examples/python/servers/advanced/pyproject.toml b/examples/python/servers/advanced/pyproject.toml index f42260e728..0e158c6cb4 100644 --- a/examples/python/servers/advanced/pyproject.toml +++ b/examples/python/servers/advanced/pyproject.toml @@ -9,7 +9,7 @@ authors = [ requires-python = ">=3.10" keywords = ["x402", "payment", "protocol", "http", "402"] dependencies = [ - "x402[fastapi,evm,svm,extensions]", + "x402[fastapi,evm,svm,tvm,extensions]", "python-dotenv>=1.2.1", "uvicorn[standard]>=0.40.0", ] @@ -24,6 +24,7 @@ dev = [ ] [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/servers/advanced/uv.lock b/examples/python/servers/advanced/uv.lock index 69ec02187d..b829668a35 100644 --- a/examples/python/servers/advanced/uv.lock +++ b/examples/python/servers/advanced/uv.lock @@ -342,6 +342,88 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/e6/ad/3cc14f097111b4de0040c83a525973216457bbeeb63739ef1ed275c1c021/certifi-2026.1.4-py3-none-any.whl", hash = "sha256:9943707519e4add1115f44c2bc244f782c0249876bf51b6599fee1ffbedd685c", size = 152900, upload-time = "2026-01-04T02:42:40.15Z" }, ] +[[package]] +name = "cffi" +version = "2.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pycparser", marker = "implementation_name != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/eb/56/b1ba7935a17738ae8453301356628e8147c79dbb825bcbc73dc7401f9846/cffi-2.0.0.tar.gz", hash = "sha256:44d1b5909021139fe36001ae048dbdde8214afa20200eda0f64c068cac5d5529", size = 523588, upload-time = "2025-09-08T23:24:04.541Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/93/d7/516d984057745a6cd96575eea814fe1edd6646ee6efd552fb7b0921dec83/cffi-2.0.0-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:0cf2d91ecc3fcc0625c2c530fe004f82c110405f101548512cce44322fa8ac44", size = 184283, upload-time = "2025-09-08T23:22:08.01Z" }, + { url = "https://files.pythonhosted.org/packages/9e/84/ad6a0b408daa859246f57c03efd28e5dd1b33c21737c2db84cae8c237aa5/cffi-2.0.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:f73b96c41e3b2adedc34a7356e64c8eb96e03a3782b535e043a986276ce12a49", size = 180504, upload-time = "2025-09-08T23:22:10.637Z" }, + { url = "https://files.pythonhosted.org/packages/50/bd/b1a6362b80628111e6653c961f987faa55262b4002fcec42308cad1db680/cffi-2.0.0-cp310-cp310-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:53f77cbe57044e88bbd5ed26ac1d0514d2acf0591dd6bb02a3ae37f76811b80c", size = 208811, upload-time = "2025-09-08T23:22:12.267Z" }, + { url = "https://files.pythonhosted.org/packages/4f/27/6933a8b2562d7bd1fb595074cf99cc81fc3789f6a6c05cdabb46284a3188/cffi-2.0.0-cp310-cp310-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:3e837e369566884707ddaf85fc1744b47575005c0a229de3327f8f9a20f4efeb", size = 216402, upload-time = "2025-09-08T23:22:13.455Z" }, + { url = "https://files.pythonhosted.org/packages/05/eb/b86f2a2645b62adcfff53b0dd97e8dfafb5c8aa864bd0d9a2c2049a0d551/cffi-2.0.0-cp310-cp310-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:5eda85d6d1879e692d546a078b44251cdd08dd1cfb98dfb77b670c97cee49ea0", size = 203217, upload-time = "2025-09-08T23:22:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/9f/e0/6cbe77a53acf5acc7c08cc186c9928864bd7c005f9efd0d126884858a5fe/cffi-2.0.0-cp310-cp310-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9332088d75dc3241c702d852d4671613136d90fa6881da7d770a483fd05248b4", size = 203079, upload-time = "2025-09-08T23:22:15.769Z" }, + { url = "https://files.pythonhosted.org/packages/98/29/9b366e70e243eb3d14a5cb488dfd3a0b6b2f1fb001a203f653b93ccfac88/cffi-2.0.0-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fc7de24befaeae77ba923797c7c87834c73648a05a4bde34b3b7e5588973a453", size = 216475, upload-time = "2025-09-08T23:22:17.427Z" }, + { url = "https://files.pythonhosted.org/packages/21/7a/13b24e70d2f90a322f2900c5d8e1f14fa7e2a6b3332b7309ba7b2ba51a5a/cffi-2.0.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:cf364028c016c03078a23b503f02058f1814320a56ad535686f90565636a9495", size = 218829, upload-time = "2025-09-08T23:22:19.069Z" }, + { url = "https://files.pythonhosted.org/packages/60/99/c9dc110974c59cc981b1f5b66e1d8af8af764e00f0293266824d9c4254bc/cffi-2.0.0-cp310-cp310-musllinux_1_2_i686.whl", hash = "sha256:e11e82b744887154b182fd3e7e8512418446501191994dbf9c9fc1f32cc8efd5", size = 211211, upload-time = "2025-09-08T23:22:20.588Z" }, + { url = "https://files.pythonhosted.org/packages/49/72/ff2d12dbf21aca1b32a40ed792ee6b40f6dc3a9cf1644bd7ef6e95e0ac5e/cffi-2.0.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:8ea985900c5c95ce9db1745f7933eeef5d314f0565b27625d9a10ec9881e1bfb", size = 218036, upload-time = "2025-09-08T23:22:22.143Z" }, + { url = "https://files.pythonhosted.org/packages/e2/cc/027d7fb82e58c48ea717149b03bcadcbdc293553edb283af792bd4bcbb3f/cffi-2.0.0-cp310-cp310-win32.whl", hash = "sha256:1f72fb8906754ac8a2cc3f9f5aaa298070652a0ffae577e0ea9bd480dc3c931a", size = 172184, upload-time = "2025-09-08T23:22:23.328Z" }, + { url = "https://files.pythonhosted.org/packages/33/fa/072dd15ae27fbb4e06b437eb6e944e75b068deb09e2a2826039e49ee2045/cffi-2.0.0-cp310-cp310-win_amd64.whl", hash = "sha256:b18a3ed7d5b3bd8d9ef7a8cb226502c6bf8308df1525e1cc676c3680e7176739", size = 182790, upload-time = "2025-09-08T23:22:24.752Z" }, + { url = "https://files.pythonhosted.org/packages/12/4a/3dfd5f7850cbf0d06dc84ba9aa00db766b52ca38d8b86e3a38314d52498c/cffi-2.0.0-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:b4c854ef3adc177950a8dfc81a86f5115d2abd545751a304c5bcf2c2c7283cfe", size = 184344, upload-time = "2025-09-08T23:22:26.456Z" }, + { url = "https://files.pythonhosted.org/packages/4f/8b/f0e4c441227ba756aafbe78f117485b25bb26b1c059d01f137fa6d14896b/cffi-2.0.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:2de9a304e27f7596cd03d16f1b7c72219bd944e99cc52b84d0145aefb07cbd3c", size = 180560, upload-time = "2025-09-08T23:22:28.197Z" }, + { url = "https://files.pythonhosted.org/packages/b1/b7/1200d354378ef52ec227395d95c2576330fd22a869f7a70e88e1447eb234/cffi-2.0.0-cp311-cp311-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:baf5215e0ab74c16e2dd324e8ec067ef59e41125d3eade2b863d294fd5035c92", size = 209613, upload-time = "2025-09-08T23:22:29.475Z" }, + { url = "https://files.pythonhosted.org/packages/b8/56/6033f5e86e8cc9bb629f0077ba71679508bdf54a9a5e112a3c0b91870332/cffi-2.0.0-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:730cacb21e1bdff3ce90babf007d0a0917cc3e6492f336c2f0134101e0944f93", size = 216476, upload-time = "2025-09-08T23:22:31.063Z" }, + { url = "https://files.pythonhosted.org/packages/dc/7f/55fecd70f7ece178db2f26128ec41430d8720f2d12ca97bf8f0a628207d5/cffi-2.0.0-cp311-cp311-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:6824f87845e3396029f3820c206e459ccc91760e8fa24422f8b0c3d1731cbec5", size = 203374, upload-time = "2025-09-08T23:22:32.507Z" }, + { url = "https://files.pythonhosted.org/packages/84/ef/a7b77c8bdc0f77adc3b46888f1ad54be8f3b7821697a7b89126e829e676a/cffi-2.0.0-cp311-cp311-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:9de40a7b0323d889cf8d23d1ef214f565ab154443c42737dfe52ff82cf857664", size = 202597, upload-time = "2025-09-08T23:22:34.132Z" }, + { url = "https://files.pythonhosted.org/packages/d7/91/500d892b2bf36529a75b77958edfcd5ad8e2ce4064ce2ecfeab2125d72d1/cffi-2.0.0-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:8941aaadaf67246224cee8c3803777eed332a19d909b47e29c9842ef1e79ac26", size = 215574, upload-time = "2025-09-08T23:22:35.443Z" }, + { url = "https://files.pythonhosted.org/packages/44/64/58f6255b62b101093d5df22dcb752596066c7e89dd725e0afaed242a61be/cffi-2.0.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:a05d0c237b3349096d3981b727493e22147f934b20f6f125a3eba8f994bec4a9", size = 218971, upload-time = "2025-09-08T23:22:36.805Z" }, + { url = "https://files.pythonhosted.org/packages/ab/49/fa72cebe2fd8a55fbe14956f9970fe8eb1ac59e5df042f603ef7c8ba0adc/cffi-2.0.0-cp311-cp311-musllinux_1_2_i686.whl", hash = "sha256:94698a9c5f91f9d138526b48fe26a199609544591f859c870d477351dc7b2414", size = 211972, upload-time = "2025-09-08T23:22:38.436Z" }, + { url = "https://files.pythonhosted.org/packages/0b/28/dd0967a76aab36731b6ebfe64dec4e981aff7e0608f60c2d46b46982607d/cffi-2.0.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:5fed36fccc0612a53f1d4d9a816b50a36702c28a2aa880cb8a122b3466638743", size = 217078, upload-time = "2025-09-08T23:22:39.776Z" }, + { url = "https://files.pythonhosted.org/packages/2b/c0/015b25184413d7ab0a410775fdb4a50fca20f5589b5dab1dbbfa3baad8ce/cffi-2.0.0-cp311-cp311-win32.whl", hash = "sha256:c649e3a33450ec82378822b3dad03cc228b8f5963c0c12fc3b1e0ab940f768a5", size = 172076, upload-time = "2025-09-08T23:22:40.95Z" }, + { url = "https://files.pythonhosted.org/packages/ae/8f/dc5531155e7070361eb1b7e4c1a9d896d0cb21c49f807a6c03fd63fc877e/cffi-2.0.0-cp311-cp311-win_amd64.whl", hash = "sha256:66f011380d0e49ed280c789fbd08ff0d40968ee7b665575489afa95c98196ab5", size = 182820, upload-time = "2025-09-08T23:22:42.463Z" }, + { url = "https://files.pythonhosted.org/packages/95/5c/1b493356429f9aecfd56bc171285a4c4ac8697f76e9bbbbb105e537853a1/cffi-2.0.0-cp311-cp311-win_arm64.whl", hash = "sha256:c6638687455baf640e37344fe26d37c404db8b80d037c3d29f58fe8d1c3b194d", size = 177635, upload-time = "2025-09-08T23:22:43.623Z" }, + { url = "https://files.pythonhosted.org/packages/ea/47/4f61023ea636104d4f16ab488e268b93008c3d0bb76893b1b31db1f96802/cffi-2.0.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6d02d6655b0e54f54c4ef0b94eb6be0607b70853c45ce98bd278dc7de718be5d", size = 185271, upload-time = "2025-09-08T23:22:44.795Z" }, + { url = "https://files.pythonhosted.org/packages/df/a2/781b623f57358e360d62cdd7a8c681f074a71d445418a776eef0aadb4ab4/cffi-2.0.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eca2a813c1cb7ad4fb74d368c2ffbbb4789d377ee5bb8df98373c2cc0dee76c", size = 181048, upload-time = "2025-09-08T23:22:45.938Z" }, + { url = "https://files.pythonhosted.org/packages/ff/df/a4f0fbd47331ceeba3d37c2e51e9dfc9722498becbeec2bd8bc856c9538a/cffi-2.0.0-cp312-cp312-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:21d1152871b019407d8ac3985f6775c079416c282e431a4da6afe7aefd2bccbe", size = 212529, upload-time = "2025-09-08T23:22:47.349Z" }, + { url = "https://files.pythonhosted.org/packages/d5/72/12b5f8d3865bf0f87cf1404d8c374e7487dcf097a1c91c436e72e6badd83/cffi-2.0.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:b21e08af67b8a103c71a250401c78d5e0893beff75e28c53c98f4de42f774062", size = 220097, upload-time = "2025-09-08T23:22:48.677Z" }, + { url = "https://files.pythonhosted.org/packages/c2/95/7a135d52a50dfa7c882ab0ac17e8dc11cec9d55d2c18dda414c051c5e69e/cffi-2.0.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:1e3a615586f05fc4065a8b22b8152f0c1b00cdbc60596d187c2a74f9e3036e4e", size = 207983, upload-time = "2025-09-08T23:22:50.06Z" }, + { url = "https://files.pythonhosted.org/packages/3a/c8/15cb9ada8895957ea171c62dc78ff3e99159ee7adb13c0123c001a2546c1/cffi-2.0.0-cp312-cp312-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:81afed14892743bbe14dacb9e36d9e0e504cd204e0b165062c488942b9718037", size = 206519, upload-time = "2025-09-08T23:22:51.364Z" }, + { url = "https://files.pythonhosted.org/packages/78/2d/7fa73dfa841b5ac06c7b8855cfc18622132e365f5b81d02230333ff26e9e/cffi-2.0.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:3e17ed538242334bf70832644a32a7aae3d83b57567f9fd60a26257e992b79ba", size = 219572, upload-time = "2025-09-08T23:22:52.902Z" }, + { url = "https://files.pythonhosted.org/packages/07/e0/267e57e387b4ca276b90f0434ff88b2c2241ad72b16d31836adddfd6031b/cffi-2.0.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:3925dd22fa2b7699ed2617149842d2e6adde22b262fcbfada50e3d195e4b3a94", size = 222963, upload-time = "2025-09-08T23:22:54.518Z" }, + { url = "https://files.pythonhosted.org/packages/b6/75/1f2747525e06f53efbd878f4d03bac5b859cbc11c633d0fb81432d98a795/cffi-2.0.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:2c8f814d84194c9ea681642fd164267891702542f028a15fc97d4674b6206187", size = 221361, upload-time = "2025-09-08T23:22:55.867Z" }, + { url = "https://files.pythonhosted.org/packages/7b/2b/2b6435f76bfeb6bbf055596976da087377ede68df465419d192acf00c437/cffi-2.0.0-cp312-cp312-win32.whl", hash = "sha256:da902562c3e9c550df360bfa53c035b2f241fed6d9aef119048073680ace4a18", size = 172932, upload-time = "2025-09-08T23:22:57.188Z" }, + { url = "https://files.pythonhosted.org/packages/f8/ed/13bd4418627013bec4ed6e54283b1959cf6db888048c7cf4b4c3b5b36002/cffi-2.0.0-cp312-cp312-win_amd64.whl", hash = "sha256:da68248800ad6320861f129cd9c1bf96ca849a2771a59e0344e88681905916f5", size = 183557, upload-time = "2025-09-08T23:22:58.351Z" }, + { url = "https://files.pythonhosted.org/packages/95/31/9f7f93ad2f8eff1dbc1c3656d7ca5bfd8fb52c9d786b4dcf19b2d02217fa/cffi-2.0.0-cp312-cp312-win_arm64.whl", hash = "sha256:4671d9dd5ec934cb9a73e7ee9676f9362aba54f7f34910956b84d727b0d73fb6", size = 177762, upload-time = "2025-09-08T23:22:59.668Z" }, + { url = "https://files.pythonhosted.org/packages/4b/8d/a0a47a0c9e413a658623d014e91e74a50cdd2c423f7ccfd44086ef767f90/cffi-2.0.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:00bdf7acc5f795150faa6957054fbbca2439db2f775ce831222b66f192f03beb", size = 185230, upload-time = "2025-09-08T23:23:00.879Z" }, + { url = "https://files.pythonhosted.org/packages/4a/d2/a6c0296814556c68ee32009d9c2ad4f85f2707cdecfd7727951ec228005d/cffi-2.0.0-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:45d5e886156860dc35862657e1494b9bae8dfa63bf56796f2fb56e1679fc0bca", size = 181043, upload-time = "2025-09-08T23:23:02.231Z" }, + { url = "https://files.pythonhosted.org/packages/b0/1e/d22cc63332bd59b06481ceaac49d6c507598642e2230f201649058a7e704/cffi-2.0.0-cp313-cp313-manylinux1_i686.manylinux2014_i686.manylinux_2_17_i686.manylinux_2_5_i686.whl", hash = "sha256:07b271772c100085dd28b74fa0cd81c8fb1a3ba18b21e03d7c27f3436a10606b", size = 212446, upload-time = "2025-09-08T23:23:03.472Z" }, + { url = "https://files.pythonhosted.org/packages/a9/f5/a2c23eb03b61a0b8747f211eb716446c826ad66818ddc7810cc2cc19b3f2/cffi-2.0.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d48a880098c96020b02d5a1f7d9251308510ce8858940e6fa99ece33f610838b", size = 220101, upload-time = "2025-09-08T23:23:04.792Z" }, + { url = "https://files.pythonhosted.org/packages/f2/7f/e6647792fc5850d634695bc0e6ab4111ae88e89981d35ac269956605feba/cffi-2.0.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:f93fd8e5c8c0a4aa1f424d6173f14a892044054871c771f8566e4008eaa359d2", size = 207948, upload-time = "2025-09-08T23:23:06.127Z" }, + { url = "https://files.pythonhosted.org/packages/cb/1e/a5a1bd6f1fb30f22573f76533de12a00bf274abcdc55c8edab639078abb6/cffi-2.0.0-cp313-cp313-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:dd4f05f54a52fb558f1ba9f528228066954fee3ebe629fc1660d874d040ae5a3", size = 206422, upload-time = "2025-09-08T23:23:07.753Z" }, + { url = "https://files.pythonhosted.org/packages/98/df/0a1755e750013a2081e863e7cd37e0cdd02664372c754e5560099eb7aa44/cffi-2.0.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c8d3b5532fc71b7a77c09192b4a5a200ea992702734a2e9279a37f2478236f26", size = 219499, upload-time = "2025-09-08T23:23:09.648Z" }, + { url = "https://files.pythonhosted.org/packages/50/e1/a969e687fcf9ea58e6e2a928ad5e2dd88cc12f6f0ab477e9971f2309b57c/cffi-2.0.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:d9b29c1f0ae438d5ee9acb31cadee00a58c46cc9c0b2f9038c6b0b3470877a8c", size = 222928, upload-time = "2025-09-08T23:23:10.928Z" }, + { url = "https://files.pythonhosted.org/packages/36/54/0362578dd2c9e557a28ac77698ed67323ed5b9775ca9d3fe73fe191bb5d8/cffi-2.0.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:6d50360be4546678fc1b79ffe7a66265e28667840010348dd69a314145807a1b", size = 221302, upload-time = "2025-09-08T23:23:12.42Z" }, + { url = "https://files.pythonhosted.org/packages/eb/6d/bf9bda840d5f1dfdbf0feca87fbdb64a918a69bca42cfa0ba7b137c48cb8/cffi-2.0.0-cp313-cp313-win32.whl", hash = "sha256:74a03b9698e198d47562765773b4a8309919089150a0bb17d829ad7b44b60d27", size = 172909, upload-time = "2025-09-08T23:23:14.32Z" }, + { url = "https://files.pythonhosted.org/packages/37/18/6519e1ee6f5a1e579e04b9ddb6f1676c17368a7aba48299c3759bbc3c8b3/cffi-2.0.0-cp313-cp313-win_amd64.whl", hash = "sha256:19f705ada2530c1167abacb171925dd886168931e0a7b78f5bffcae5c6b5be75", size = 183402, upload-time = "2025-09-08T23:23:15.535Z" }, + { url = "https://files.pythonhosted.org/packages/cb/0e/02ceeec9a7d6ee63bb596121c2c8e9b3a9e150936f4fbef6ca1943e6137c/cffi-2.0.0-cp313-cp313-win_arm64.whl", hash = "sha256:256f80b80ca3853f90c21b23ee78cd008713787b1b1e93eae9f3d6a7134abd91", size = 177780, upload-time = "2025-09-08T23:23:16.761Z" }, + { url = "https://files.pythonhosted.org/packages/92/c4/3ce07396253a83250ee98564f8d7e9789fab8e58858f35d07a9a2c78de9f/cffi-2.0.0-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fc33c5141b55ed366cfaad382df24fe7dcbc686de5be719b207bb248e3053dc5", size = 185320, upload-time = "2025-09-08T23:23:18.087Z" }, + { url = "https://files.pythonhosted.org/packages/59/dd/27e9fa567a23931c838c6b02d0764611c62290062a6d4e8ff7863daf9730/cffi-2.0.0-cp314-cp314-macosx_11_0_arm64.whl", hash = "sha256:c654de545946e0db659b3400168c9ad31b5d29593291482c43e3564effbcee13", size = 181487, upload-time = "2025-09-08T23:23:19.622Z" }, + { url = "https://files.pythonhosted.org/packages/d6/43/0e822876f87ea8a4ef95442c3d766a06a51fc5298823f884ef87aaad168c/cffi-2.0.0-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:24b6f81f1983e6df8db3adc38562c83f7d4a0c36162885ec7f7b77c7dcbec97b", size = 220049, upload-time = "2025-09-08T23:23:20.853Z" }, + { url = "https://files.pythonhosted.org/packages/b4/89/76799151d9c2d2d1ead63c2429da9ea9d7aac304603de0c6e8764e6e8e70/cffi-2.0.0-cp314-cp314-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:12873ca6cb9b0f0d3a0da705d6086fe911591737a59f28b7936bdfed27c0d47c", size = 207793, upload-time = "2025-09-08T23:23:22.08Z" }, + { url = "https://files.pythonhosted.org/packages/bb/dd/3465b14bb9e24ee24cb88c9e3730f6de63111fffe513492bf8c808a3547e/cffi-2.0.0-cp314-cp314-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:d9b97165e8aed9272a6bb17c01e3cc5871a594a446ebedc996e2397a1c1ea8ef", size = 206300, upload-time = "2025-09-08T23:23:23.314Z" }, + { url = "https://files.pythonhosted.org/packages/47/d9/d83e293854571c877a92da46fdec39158f8d7e68da75bf73581225d28e90/cffi-2.0.0-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:afb8db5439b81cf9c9d0c80404b60c3cc9c3add93e114dcae767f1477cb53775", size = 219244, upload-time = "2025-09-08T23:23:24.541Z" }, + { url = "https://files.pythonhosted.org/packages/2b/0f/1f177e3683aead2bb00f7679a16451d302c436b5cbf2505f0ea8146ef59e/cffi-2.0.0-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:737fe7d37e1a1bffe70bd5754ea763a62a066dc5913ca57e957824b72a85e205", size = 222828, upload-time = "2025-09-08T23:23:26.143Z" }, + { url = "https://files.pythonhosted.org/packages/c6/0f/cafacebd4b040e3119dcb32fed8bdef8dfe94da653155f9d0b9dc660166e/cffi-2.0.0-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:38100abb9d1b1435bc4cc340bb4489635dc2f0da7456590877030c9b3d40b0c1", size = 220926, upload-time = "2025-09-08T23:23:27.873Z" }, + { url = "https://files.pythonhosted.org/packages/3e/aa/df335faa45b395396fcbc03de2dfcab242cd61a9900e914fe682a59170b1/cffi-2.0.0-cp314-cp314-win32.whl", hash = "sha256:087067fa8953339c723661eda6b54bc98c5625757ea62e95eb4898ad5e776e9f", size = 175328, upload-time = "2025-09-08T23:23:44.61Z" }, + { url = "https://files.pythonhosted.org/packages/bb/92/882c2d30831744296ce713f0feb4c1cd30f346ef747b530b5318715cc367/cffi-2.0.0-cp314-cp314-win_amd64.whl", hash = "sha256:203a48d1fb583fc7d78a4c6655692963b860a417c0528492a6bc21f1aaefab25", size = 185650, upload-time = "2025-09-08T23:23:45.848Z" }, + { url = "https://files.pythonhosted.org/packages/9f/2c/98ece204b9d35a7366b5b2c6539c350313ca13932143e79dc133ba757104/cffi-2.0.0-cp314-cp314-win_arm64.whl", hash = "sha256:dbd5c7a25a7cb98f5ca55d258b103a2054f859a46ae11aaf23134f9cc0d356ad", size = 180687, upload-time = "2025-09-08T23:23:47.105Z" }, + { url = "https://files.pythonhosted.org/packages/3e/61/c768e4d548bfa607abcda77423448df8c471f25dbe64fb2ef6d555eae006/cffi-2.0.0-cp314-cp314t-macosx_10_13_x86_64.whl", hash = "sha256:9a67fc9e8eb39039280526379fb3a70023d77caec1852002b4da7e8b270c4dd9", size = 188773, upload-time = "2025-09-08T23:23:29.347Z" }, + { url = "https://files.pythonhosted.org/packages/2c/ea/5f76bce7cf6fcd0ab1a1058b5af899bfbef198bea4d5686da88471ea0336/cffi-2.0.0-cp314-cp314t-macosx_11_0_arm64.whl", hash = "sha256:7a66c7204d8869299919db4d5069a82f1561581af12b11b3c9f48c584eb8743d", size = 185013, upload-time = "2025-09-08T23:23:30.63Z" }, + { url = "https://files.pythonhosted.org/packages/be/b4/c56878d0d1755cf9caa54ba71e5d049479c52f9e4afc230f06822162ab2f/cffi-2.0.0-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7cc09976e8b56f8cebd752f7113ad07752461f48a58cbba644139015ac24954c", size = 221593, upload-time = "2025-09-08T23:23:31.91Z" }, + { url = "https://files.pythonhosted.org/packages/e0/0d/eb704606dfe8033e7128df5e90fee946bbcb64a04fcdaa97321309004000/cffi-2.0.0-cp314-cp314t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.whl", hash = "sha256:92b68146a71df78564e4ef48af17551a5ddd142e5190cdf2c5624d0c3ff5b2e8", size = 209354, upload-time = "2025-09-08T23:23:33.214Z" }, + { url = "https://files.pythonhosted.org/packages/d8/19/3c435d727b368ca475fb8742ab97c9cb13a0de600ce86f62eab7fa3eea60/cffi-2.0.0-cp314-cp314t-manylinux2014_s390x.manylinux_2_17_s390x.whl", hash = "sha256:b1e74d11748e7e98e2f426ab176d4ed720a64412b6a15054378afdb71e0f37dc", size = 208480, upload-time = "2025-09-08T23:23:34.495Z" }, + { url = "https://files.pythonhosted.org/packages/d0/44/681604464ed9541673e486521497406fadcc15b5217c3e326b061696899a/cffi-2.0.0-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:28a3a209b96630bca57cce802da70c266eb08c6e97e5afd61a75611ee6c64592", size = 221584, upload-time = "2025-09-08T23:23:36.096Z" }, + { url = "https://files.pythonhosted.org/packages/25/8e/342a504ff018a2825d395d44d63a767dd8ebc927ebda557fecdaca3ac33a/cffi-2.0.0-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:7553fb2090d71822f02c629afe6042c299edf91ba1bf94951165613553984512", size = 224443, upload-time = "2025-09-08T23:23:37.328Z" }, + { url = "https://files.pythonhosted.org/packages/e1/5e/b666bacbbc60fbf415ba9988324a132c9a7a0448a9a8f125074671c0f2c3/cffi-2.0.0-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:6c6c373cfc5c83a975506110d17457138c8c63016b563cc9ed6e056a82f13ce4", size = 223437, upload-time = "2025-09-08T23:23:38.945Z" }, + { url = "https://files.pythonhosted.org/packages/a0/1d/ec1a60bd1a10daa292d3cd6bb0b359a81607154fb8165f3ec95fe003b85c/cffi-2.0.0-cp314-cp314t-win32.whl", hash = "sha256:1fc9ea04857caf665289b7a75923f2c6ed559b8298a1b8c49e59f7dd95c8481e", size = 180487, upload-time = "2025-09-08T23:23:40.423Z" }, + { url = "https://files.pythonhosted.org/packages/bf/41/4c1168c74fac325c0c8156f04b6749c8b6a8f405bbf91413ba088359f60d/cffi-2.0.0-cp314-cp314t-win_amd64.whl", hash = "sha256:d68b6cef7827e8641e8ef16f4494edda8b36104d79773a334beaa1e3521430f6", size = 191726, upload-time = "2025-09-08T23:23:41.742Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3a/dbeec9d1ee0844c679f6bb5d6ad4e9f198b1224f4e7a32825f47f6192b0c/cffi-2.0.0-cp314-cp314t-win_arm64.whl", hash = "sha256:0a1527a803f0a659de1af2e1fd700213caba79377e27e4693648c2923da066f9", size = 184195, upload-time = "2025-09-08T23:23:43.004Z" }, +] + [[package]] name = "charset-normalizer" version = "3.4.4" @@ -1883,6 +1965,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5b/5a/bc7b4a4ef808fa59a816c17b20c4bef6884daebbdf627ff2a161da67da19/propcache-0.4.1-py3-none-any.whl", hash = "sha256:af2a6052aeb6cf17d3e46ee169099044fd8224cbaf75c76a2ef596e8163e2237", size = 13305, upload-time = "2025-10-08T19:49:00.792Z" }, ] +[[package]] +name = "pycparser" +version = "3.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/1b/7d/92392ff7815c21062bea51aa7b87d45576f649f16458d78b7cf94b9ab2e6/pycparser-3.0.tar.gz", hash = "sha256:600f49d217304a5902ac3c37e1281c9fe94e4d0489de643a9504c5cdfdfc6b29", size = 103492, upload-time = "2026-01-21T14:26:51.89Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0c/c3/44f3fbbfa403ea2a7c779186dc20772604442dde72947e7d01069cbe98e3/pycparser-3.0-py3-none-any.whl", hash = "sha256:b727414169a36b7d524c1c3e31839a521725078d7b2ff038656844266160a992", size = 48172, upload-time = "2026-01-21T14:26:50.693Z" }, +] + [[package]] name = "pycryptodome" version = "3.23.0" @@ -1918,6 +2009,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, ] +[[package]] +name = "pycryptodomex" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -2092,6 +2218,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c7/21/705964c7812476f378728bdf590ca4b771ec72385c533964653c68e86bdc/pygments-2.19.2-py3-none-any.whl", hash = "sha256:86540386c03d588bb81d44bc3928634ff26449851e99741617ecb9037ee5ec0b", size = 1225217, upload-time = "2025-06-21T13:39:07.939Z" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "pytest" version = "9.0.2" @@ -2151,6 +2312,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" }, ] +[[package]] +name = "pytoniq" +version = "0.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytoniq-core" }, + { name = "requests" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/b2/9991a953e4b766918a142fe111f71f12803c6acf65eb30f36eb85ed08f31/pytoniq-0.1.43.tar.gz", hash = "sha256:b4b1c8fed2f9d2f1b6f0ab4b3f1fc5503a0088630d8081f817807ff31e608606", size = 50463, upload-time = "2025-11-30T12:30:41.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/c1/b6e5c739839e0e12bde4563438acd55d39552ea63f6de123724b4b91ac64/pytoniq-0.1.43-py3-none-any.whl", hash = "sha256:922c1721124bf7214e0b7044fba2a439e006367778611c0ce813cbe5b00079d3", size = 56118, upload-time = "2025-11-30T12:30:39.65Z" }, +] + +[[package]] +name = "pytoniq-core" +version = "0.1.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "x25519" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/2c/7afbb9003a3aa72ccfe69711433fe36d2493db2c4acf66dde32f7b55799b/pytoniq_core-0.1.46.tar.gz", hash = "sha256:c8e3cf9ccb1852780a725cd51ba7a66a28122eb39c8b9bb97dcdc5bd02c24734", size = 101236, upload-time = "2025-11-28T10:23:21.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/0e/e27cf7ce1bebb47fb95e1d6deae5c91c6ffcb7851f156990e57079cbe8db/pytoniq_core-0.1.46-py3-none-any.whl", hash = "sha256:0a284c8b68f9fed9d54e4dad871238d844339183bf985a614796360e36e1b95e", size = 91400, upload-time = "2025-11-28T10:23:20.95Z" }, +] + [[package]] name = "pyunormalize" version = "17.0.0" @@ -2703,6 +2895,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/88/43/1c586f9f413765201234541857cb82fda076f4b0f7bad4a0ec248da39cf3/sentry_sdk-2.49.0-py2.py3-none-any.whl", hash = "sha256:6ea78499133874445a20fe9c826c9e960070abeb7ae0cdf930314ab16bb97aa0", size = 415693, upload-time = "2026-01-08T09:56:21.872Z" }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + [[package]] name = "shellingham" version = "1.5.4" @@ -3137,9 +3338,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/fa/a8/5b41e0da817d64113292ab1f8247140aac61cbf6cfd085d6a0fa77f4984f/websockets-15.0.1-py3-none-any.whl", hash = "sha256:f7a866fbc1e97b5c617ee4116daaa09b722101d4a3c170c787450ba409f9736f", size = 169743, upload-time = "2025-03-05T20:03:39.41Z" }, ] +[[package]] +name = "x25519" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/b6/fca895aff0800cdf941f856df0685a5513094163664b904576e3e3ef1460/x25519-0.0.2.tar.gz", hash = "sha256:ed91d0aba7f4f4959ed8b37118c11d94f56d36c38bb6f2e6c20d0438d75b1556", size = 4833, upload-time = "2021-10-24T15:18:38.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d1/66c637eb8e7a9601675bf7f04bb9a3015358a0f49e4c31d29a2b9a9d72d9/x25519-0.0.2-py3-none-any.whl", hash = "sha256:5c0833260a548bea9137a5a1b5c30334b751a59d148a62832df0c9e7b919ce99", size = 4907, upload-time = "2021-10-24T15:18:36.727Z" }, +] + [[package]] name = "x402" -version = "2.1.0" +version = "2.5.0" source = { editable = "../../../../python/x402" } dependencies = [ { name = "nest-asyncio" }, @@ -3166,38 +3376,48 @@ svm = [ { name = "solana" }, { name = "solders" }, ] +tvm = [ + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, +] [package.metadata] requires-dist = [ { name = "eth-abi", marker = "extra == 'evm'", specifier = ">=5.0.0" }, - { name = "eth-account", marker = "extra == 'evm'", specifier = ">=0.12.0" }, + { name = "eth-account", marker = "extra == 'evm'", specifier = ">=0.13.0" }, { name = "eth-keys", marker = "extra == 'evm'", specifier = ">=0.5.0" }, { name = "eth-utils", marker = "extra == 'evm'", specifier = ">=4.0.0" }, { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.115.0" }, { name = "flask", marker = "extra == 'flask'", specifier = ">=3.0.0" }, { name = "httpx", marker = "extra == 'httpx'", specifier = ">=0.28.1" }, + { name = "httpx", marker = "extra == 'tvm'", specifier = ">=0.28.1" }, { name = "jsonschema", marker = "extra == 'extensions'", specifier = ">=4.0.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pynacl", marker = "extra == 'tvm'", specifier = ">=1.5.0" }, + { name = "pytoniq", marker = "extra == 'tvm'", specifier = ">=0.1.39" }, + { name = "pytoniq-core", marker = "extra == 'tvm'", specifier = ">=0.1.36" }, { name = "requests", marker = "extra == 'requests'", specifier = ">=2.31.0" }, { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0" }, { name = "solders", marker = "extra == 'svm'", specifier = ">=0.27.0" }, { name = "starlette", marker = "extra == 'fastapi'", specifier = ">=0.27.0" }, { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "web3", marker = "extra == 'evm'", specifier = ">=7.0.0" }, - { name = "x402", extras = ["evm", "svm"], marker = "extra == 'mechanisms'" }, + { name = "x402", extras = ["evm", "svm", "tvm"], marker = "extra == 'mechanisms'" }, { name = "x402", extras = ["flask", "fastapi"], marker = "extra == 'servers'" }, { name = "x402", extras = ["httpx", "requests"], marker = "extra == 'clients'" }, - { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions"], marker = "extra == 'all'" }, + { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions"], marker = "extra == 'all'" }, ] -provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] +provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] [package.metadata.requires-dev] dev = [ { name = "black", specifier = ">=23.0.0" }, { name = "eth-abi", specifier = ">=5.0.0" }, - { name = "eth-account", specifier = ">=0.12.0" }, + { name = "eth-account", specifier = ">=0.13.0" }, { name = "eth-keys", specifier = ">=0.5.0" }, { name = "eth-utils", specifier = ">=4.0.0" }, { name = "fastapi", extras = ["standard"], specifier = ">=0.115.0" }, @@ -3207,8 +3427,11 @@ dev = [ { name = "mcp", specifier = ">=1.26.0" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, + { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytest", specifier = ">=7.0.0" }, { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytoniq", specifier = ">=0.1.39" }, + { name = "pytoniq-core", specifier = ">=0.1.36" }, { name = "requests", specifier = ">=2.31.0" }, { name = "ruff", specifier = ">=0.1.0" }, { name = "solana", specifier = ">=0.36.0" }, @@ -3225,7 +3448,7 @@ source = { virtual = "." } dependencies = [ { name = "python-dotenv" }, { name = "uvicorn", extra = ["standard"] }, - { name = "x402", extra = ["evm", "extensions", "fastapi", "svm"] }, + { name = "x402", extra = ["evm", "extensions", "fastapi", "svm", "tvm"] }, ] [package.dev-dependencies] @@ -3241,7 +3464,7 @@ dev = [ requires-dist = [ { name = "python-dotenv", specifier = ">=1.2.1" }, { name = "uvicorn", extras = ["standard"], specifier = ">=0.40.0" }, - { name = "x402", extras = ["fastapi", "evm", "svm", "extensions"], editable = "../../../../python/x402" }, + { name = "x402", extras = ["fastapi", "evm", "svm", "tvm", "extensions"], editable = "../../../../python/x402" }, ] [package.metadata.requires-dev] diff --git a/examples/python/servers/bazaar/pyproject.toml b/examples/python/servers/bazaar/pyproject.toml index b76ba97a62..dd91690d96 100644 --- a/examples/python/servers/bazaar/pyproject.toml +++ b/examples/python/servers/bazaar/pyproject.toml @@ -24,6 +24,7 @@ dev = [ ] [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/servers/custom/pyproject.toml b/examples/python/servers/custom/pyproject.toml index 52f2207518..08ada79c93 100644 --- a/examples/python/servers/custom/pyproject.toml +++ b/examples/python/servers/custom/pyproject.toml @@ -24,6 +24,7 @@ dev = [ ] [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/servers/fastapi/pyproject.toml b/examples/python/servers/fastapi/pyproject.toml index 1aff97238c..ca5c0cef9a 100644 --- a/examples/python/servers/fastapi/pyproject.toml +++ b/examples/python/servers/fastapi/pyproject.toml @@ -24,6 +24,7 @@ dev = [ ] [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/servers/flask/pyproject.toml b/examples/python/servers/flask/pyproject.toml index c2e9ab9c68..8920006e85 100644 --- a/examples/python/servers/flask/pyproject.toml +++ b/examples/python/servers/flask/pyproject.toml @@ -22,6 +22,7 @@ dev = [ ] [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/servers/mcp/pyproject.toml b/examples/python/servers/mcp/pyproject.toml index c99fd64f2b..15c842bd1e 100644 --- a/examples/python/servers/mcp/pyproject.toml +++ b/examples/python/servers/mcp/pyproject.toml @@ -11,6 +11,7 @@ dependencies = [ ] [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/python/servers/payment-identifier/pyproject.toml b/examples/python/servers/payment-identifier/pyproject.toml index 96f6f400ec..05035eb789 100644 --- a/examples/python/servers/payment-identifier/pyproject.toml +++ b/examples/python/servers/payment-identifier/pyproject.toml @@ -20,6 +20,7 @@ packages = ["."] allow-direct-references = true [tool.uv] +exclude-newer = "3 days" package = false [tool.uv.sources] diff --git a/examples/typescript/clients/advanced/.env-local b/examples/typescript/clients/advanced/.env-local index 57f92e9636..4b94e61469 100644 --- a/examples/typescript/clients/advanced/.env-local +++ b/examples/typescript/clients/advanced/.env-local @@ -1,5 +1,8 @@ EVM_PRIVATE_KEY= SVM_PRIVATE_KEY= STELLAR_PRIVATE_KEY= +HEDERA_ACCOUNT_ID= +HEDERA_PRIVATE_KEY= +HEDERA_NETWORK= RESOURCE_SERVER_URL=http://localhost:4021 ENDPOINT_PATH=/weather \ No newline at end of file diff --git a/examples/typescript/clients/advanced/README.md b/examples/typescript/clients/advanced/README.md index 4c3470db26..b85ec48aef 100644 --- a/examples/typescript/clients/advanced/README.md +++ b/examples/typescript/clients/advanced/README.md @@ -41,6 +41,9 @@ and fill required environment variables: - `EVM_PRIVATE_KEY` - Ethereum private key for EVM payments - `SVM_PRIVATE_KEY` - Solana private key for SVM payments - `STELLAR_PRIVATE_KEY` - Stellar secret key (starts with `S`) for signing Stellar payments +- `HEDERA_ACCOUNT_ID` - Hedera account id for Hedera payments (optional) +- `HEDERA_PRIVATE_KEY` - Hedera **ECDSA** private key (0x-prefixed or DER-encoded) for Hedera payments (optional) +- `HEDERA_NETWORK` - Hedera network (optional, defaults to `hedera:testnet`) 2. Install and build all packages from the typescript examples root: diff --git a/examples/typescript/clients/advanced/all_networks.ts b/examples/typescript/clients/advanced/all_networks.ts index 01c8b78fad..8eb56da883 100644 --- a/examples/typescript/clients/advanced/all_networks.ts +++ b/examples/typescript/clients/advanced/all_networks.ts @@ -5,25 +5,35 @@ * optional chain configuration via environment variables. * * New chain support should be added here in alphabetic order by network prefix - * (e.g., "eip155" before "solana" before "stellar"). + * (e.g., "algorand" before "eip155" before "solana"). */ import { config } from "dotenv"; import { x402Client, wrapFetchWithPayment, x402HTTPClient } from "@x402/fetch"; +import { toClientAvmSigner } from "@x402/avm"; +import { ExactAvmScheme } from "@x402/avm/exact/client"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { ExactSvmScheme } from "@x402/svm/exact/client"; import { ExactStellarScheme } from "@x402/stellar/exact/client"; import { createEd25519Signer } from "@x402/stellar"; -import { privateKeyToAccount } from "viem/accounts"; -import { createKeyPairSignerFromBytes } from "@solana/kit"; +import { ExactHederaScheme } from "@x402/hedera/exact/client"; +import { createClientHederaSigner, PrivateKey } from "@x402/hedera"; import { base58 } from "@scure/base"; +import { createKeyPairSignerFromBytes } from "@solana/kit"; +import { privateKeyToAccount } from "viem/accounts"; config(); // Configuration - optional per network +const avmPrivateKey = process.env.AVM_PRIVATE_KEY as string | undefined; const evmPrivateKey = process.env.EVM_PRIVATE_KEY as `0x${string}` | undefined; const svmPrivateKey = process.env.SVM_PRIVATE_KEY as string | undefined; const stellarPrivateKey = process.env.STELLAR_PRIVATE_KEY as string | undefined; +const hederaAccountId = process.env.HEDERA_ACCOUNT_ID; +// Hedera private key should be an ECDSA key string (0x-prefixed or DER-encoded). +const hederaPrivateKey = process.env.HEDERA_PRIVATE_KEY; +const hederaNetwork = process.env.HEDERA_NETWORK || "hedera:testnet"; const baseURL = process.env.RESOURCE_SERVER_URL || "http://localhost:4021"; const endpointPath = process.env.ENDPOINT_PATH || "/weather"; const url = `${baseURL}${endpointPath}`; @@ -34,9 +44,15 @@ const url = `${baseURL}${endpointPath}`; */ async function main(): Promise { // Validate at least one private key is provided - if (!evmPrivateKey && !svmPrivateKey && !stellarPrivateKey) { + if ( + !avmPrivateKey && + !evmPrivateKey && + !svmPrivateKey && + !stellarPrivateKey && + !(hederaAccountId && hederaPrivateKey) + ) { console.error( - "❌ At least one of EVM_PRIVATE_KEY, SVM_PRIVATE_KEY, or STELLAR_PRIVATE_KEY is required", + "❌ At least one of AVM_PRIVATE_KEY, EVM_PRIVATE_KEY, SVM_PRIVATE_KEY, STELLAR_PRIVATE_KEY, or HEDERA_ACCOUNT_ID + HEDERA_PRIVATE_KEY is required", ); process.exit(1); } @@ -44,10 +60,18 @@ async function main(): Promise { // Create x402 client const client = new x402Client(); + // Register AVM scheme if private key is provided + if (avmPrivateKey) { + const avmSigner = toClientAvmSigner(avmPrivateKey); + client.register("algorand:*", new ExactAvmScheme(avmSigner)); + console.log(`Initialized AVM account: ${avmSigner.address}`); + } + // Register EVM scheme if private key is provided if (evmPrivateKey) { const evmSigner = privateKeyToAccount(evmPrivateKey); client.register("eip155:*", new ExactEvmScheme(evmSigner)); + client.register("eip155:*", new UptoEvmScheme(evmSigner)); console.log(`Initialized EVM account: ${evmSigner.address}`); } @@ -57,6 +81,15 @@ async function main(): Promise { client.register("solana:*", new ExactSvmScheme(svmSigner)); console.log(`Initialized SVM account: ${svmSigner.address}`); } + if (hederaAccountId && hederaPrivateKey) { + const hederaSigner = createClientHederaSigner( + hederaAccountId, + PrivateKey.fromStringECDSA(hederaPrivateKey), + { network: hederaNetwork }, + ); + client.register("hedera:*", new ExactHederaScheme(hederaSigner)); + console.log(`Initialized Hedera account: ${hederaAccountId} on ${hederaNetwork}`); + } // Register Stellar scheme if private key is provided if (stellarPrivateKey) { diff --git a/examples/typescript/clients/advanced/builder-pattern.ts b/examples/typescript/clients/advanced/builder-pattern.ts index 0a91bd122e..6552b2de97 100644 --- a/examples/typescript/clients/advanced/builder-pattern.ts +++ b/examples/typescript/clients/advanced/builder-pattern.ts @@ -1,6 +1,7 @@ import { privateKeyToAccount } from "viem/accounts"; import { x402Client, wrapFetchWithPayment, x402HTTPClient } from "@x402/fetch"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { ExactSvmScheme } from "@x402/svm/exact/client"; import { createKeyPairSignerFromBytes } from "@solana/kit"; import { base58 } from "@scure/base"; @@ -35,7 +36,8 @@ export async function runBuilderPatternExample( // Builder pattern allows fine-grained control over network registration // More specific patterns (e.g., "eip155:1") take precedence over wildcards (e.g., "eip155:*") const client = new x402Client() - .register("eip155:*", new ExactEvmScheme(evmSigner)) // All EVM networks + .register("eip155:*", new ExactEvmScheme(evmSigner)) // All EVM networks (exact) + .register("eip155:*", new UptoEvmScheme(evmSigner)) // All EVM networks (upto) .register("eip155:1", new ExactEvmScheme(ethereumMainnetSigner)) // Ethereum mainnet override .register("solana:*", new ExactSvmScheme(svmSigner)) // All Solana networks .register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme(solanaDevnetSigner)); // Devnet override diff --git a/examples/typescript/clients/advanced/hooks.ts b/examples/typescript/clients/advanced/hooks.ts index 79e419f8b0..eaa3fea398 100644 --- a/examples/typescript/clients/advanced/hooks.ts +++ b/examples/typescript/clients/advanced/hooks.ts @@ -1,6 +1,7 @@ import { privateKeyToAccount } from "viem/accounts"; import { x402Client } from "@x402/fetch"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; /** * Hooks Example @@ -27,6 +28,7 @@ export async function runHooksExample(evmPrivateKey: `0x${string}`, url: string) const client = new x402Client() .register("eip155:*", new ExactEvmScheme(evmSigner)) + .register("eip155:*", new UptoEvmScheme(evmSigner)) .onBeforePaymentCreation(async context => { console.log("🔍 [BeforePaymentCreation] Creating payment for:"); console.log(` Network: ${context.selectedRequirements.network}`); diff --git a/examples/typescript/clients/advanced/package.json b/examples/typescript/clients/advanced/package.json index 66b2fc1a26..abc3a31efc 100644 --- a/examples/typescript/clients/advanced/package.json +++ b/examples/typescript/clients/advanced/package.json @@ -16,16 +16,19 @@ }, "dependencies": { "@scure/base": "^1.2.6", + "@x402/avm": "workspace:*", "@x402/evm": "workspace:*", "@x402/svm": "workspace:*", "@x402/stellar": "workspace:*", + "@x402/hedera": "workspace:*", "@x402/fetch": "workspace:*", "dotenv": "^16.4.7", - "viem": "^2.39.0", + "viem": "^2.48.11", "@solana/kit": "^6.1.0" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -33,7 +36,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/clients/advanced/preferred-network.ts b/examples/typescript/clients/advanced/preferred-network.ts index b22ae4eadc..721b399e38 100644 --- a/examples/typescript/clients/advanced/preferred-network.ts +++ b/examples/typescript/clients/advanced/preferred-network.ts @@ -1,6 +1,7 @@ import { privateKeyToAccount } from "viem/accounts"; import { x402Client, type PaymentRequirements } from "@x402/fetch"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { ExactSvmScheme } from "@x402/svm/exact/client"; import { createKeyPairSignerFromBytes } from "@solana/kit"; import { base58 } from "@scure/base"; @@ -72,6 +73,7 @@ export async function runPreferredNetworkExample( const client = new x402Client(preferredNetworkSelector) .register("eip155:*", new ExactEvmScheme(evmSigner)) + .register("eip155:*", new UptoEvmScheme(evmSigner)) .register("solana:*", new ExactSvmScheme(svmSigner)); const fetchWithPayment = wrapFetchWithPayment(fetch, client); diff --git a/examples/typescript/clients/axios/README.md b/examples/typescript/clients/axios/README.md index 7495313b39..3817313830 100644 --- a/examples/typescript/clients/axios/README.md +++ b/examples/typescript/clients/axios/README.md @@ -45,6 +45,10 @@ Required environment variables: - `EVM_PRIVATE_KEY` - Ethereum private key for EVM payments - `SVM_PRIVATE_KEY` - Solana private key for SVM payments +Optional environment variables: + +- `EVM_RPC_URL` - JSON-RPC endpoint for on-chain reads. Enables gas sponsoring extensions (EIP-2612 and ERC-20 approval). Example: `https://sepolia.base.org` + 3. Run the client: ```bash diff --git a/examples/typescript/clients/axios/index.ts b/examples/typescript/clients/axios/index.ts index b0d96c249d..60ec1659b1 100644 --- a/examples/typescript/clients/axios/index.ts +++ b/examples/typescript/clients/axios/index.ts @@ -1,6 +1,7 @@ import { config } from "dotenv"; import { x402Client, wrapAxiosWithPayment, x402HTTPClient } from "@x402/axios"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { ExactSvmScheme } from "@x402/svm/exact/client"; import { privateKeyToAccount } from "viem/accounts"; import { createKeyPairSignerFromBytes } from "@solana/kit"; @@ -11,6 +12,7 @@ config(); const evmPrivateKey = process.env.EVM_PRIVATE_KEY as `0x${string}`; const svmPrivateKey = process.env.SVM_PRIVATE_KEY as string; +const evmRpcUrl = process.env.EVM_RPC_URL; const baseURL = process.env.RESOURCE_SERVER_URL || "http://localhost:4021"; const endpointPath = process.env.ENDPOINT_PATH || "/weather"; const url = `${baseURL}${endpointPath}`; @@ -23,13 +25,18 @@ const url = `${baseURL}${endpointPath}`; * Required environment variables: * - EVM_PRIVATE_KEY: The private key of the EVM signer * - SVM_PRIVATE_KEY: The private key of the SVM signer + * + * Optional environment variables: + * - EVM_RPC_URL: JSON-RPC endpoint for on-chain reads (enables gas sponsoring extensions) */ async function main(): Promise { const evmSigner = privateKeyToAccount(evmPrivateKey); const svmSigner = await createKeyPairSignerFromBytes(base58.decode(svmPrivateKey)); + const rpcOptions = evmRpcUrl ? { rpcUrl: evmRpcUrl } : undefined; const client = new x402Client(); - client.register("eip155:*", new ExactEvmScheme(evmSigner)); + client.register("eip155:*", new ExactEvmScheme(evmSigner, rpcOptions)); + client.register("eip155:*", new UptoEvmScheme(evmSigner, rpcOptions)); client.register("solana:*", new ExactSvmScheme(svmSigner)); const api = wrapAxiosWithPayment(axios.create(), client); diff --git a/examples/typescript/clients/axios/package.json b/examples/typescript/clients/axios/package.json index 0a5130a51b..66599c9431 100644 --- a/examples/typescript/clients/axios/package.json +++ b/examples/typescript/clients/axios/package.json @@ -20,10 +20,11 @@ "@x402/svm": "workspace:*", "axios": "^1.13.2", "dotenv": "^16.4.7", - "viem": "^2.39.0" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -31,7 +32,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/clients/batch-settlement/.env-local b/examples/typescript/clients/batch-settlement/.env-local new file mode 100644 index 0000000000..2681759326 --- /dev/null +++ b/examples/typescript/clients/batch-settlement/.env-local @@ -0,0 +1,20 @@ +EVM_PRIVATE_KEY=0x... + +# Optional: dedicated voucher-signing EOA (faster verification, recommended for smart wallets) +EVM_VOUCHER_SIGNER_PRIVATE_KEY= + +RESOURCE_SERVER_URL=http://localhost:4021 +ENDPOINT_PATH=/weather + +# 32-byte hex; differentiates channels with the same payer/payee/token tuple +CHANNEL_SALT=0x0000000000000000000000000000000000000000000000000000000000000000 + +# Optional: persist session state across runs +STORAGE_DIR= + +NUMBER_OF_REQUESTS=3 + +# After the request loop completes, request a cooperative refund. +REFUND_AFTER_REQUESTS=false +# Optional partial refund amount (base units). Empty drains the remaining channel balance. +REFUND_AMOUNT= diff --git a/examples/typescript/legacy/agent/.prettierignore b/examples/typescript/clients/batch-settlement/.prettierignore similarity index 100% rename from examples/typescript/legacy/agent/.prettierignore rename to examples/typescript/clients/batch-settlement/.prettierignore diff --git a/examples/typescript/legacy/agent/.prettierrc b/examples/typescript/clients/batch-settlement/.prettierrc similarity index 100% rename from examples/typescript/legacy/agent/.prettierrc rename to examples/typescript/clients/batch-settlement/.prettierrc diff --git a/examples/typescript/clients/batch-settlement/README.md b/examples/typescript/clients/batch-settlement/README.md new file mode 100644 index 0000000000..f5508eb833 --- /dev/null +++ b/examples/typescript/clients/batch-settlement/README.md @@ -0,0 +1,84 @@ +# Batch-Settlement Client Example + +Fetch-based client that pays for a sequence of requests over a single payment channel using the **batch-settlement** EVM scheme. The first request opens the channel with a deposit; subsequent requests pay with a fresh cumulative voucher. + + +See the [scheme specification](../../../../specs/schemes/batch-settlement/scheme_batch_settlement_evm.md) and the [scheme README](../../../../typescript/packages/mechanisms/evm/src/batch-settlement/README.md) for protocol details. + +## Voucher Signer Delegation + +By default, vouchers are signed by the same key as the payer (`EVM_PRIVATE_KEY`). Set `EVM_VOUCHER_SIGNER_PRIVATE_KEY` to delegate voucher signing to a dedicated EOA — its address is committed into the channel as the `payerAuthorizer`. + +```typescript +const voucherSigner = toClientEvmSigner(privateKeyToAccount(VOUCHER_KEY)); +const scheme = new BatchSettlementEvmScheme(signer, { voucherSigner }); +``` + +Use this when: + +- The payer key should only sign deposit authorizations. +- The payer is a smart wallet (EIP-1271). Delegating to an EOA voucher signer lets the facilitator verify vouchers with ECDSA recovery instead of an onchain `isValidSignature` call. + +## Deposit policy + +Use `depositStrategy` for app-specific deposit decisions. The strategy can: + +- **`undefined`** — use the SDK default (`depositAmount` in context). +- **`false`** — skip this deposit attempt. +- **Base-unit string or `bigint`** — custom amount; must be **≥ `minimumDepositAmount`** or the scheme throws. + +```typescript +const maxDeposit = 1_000_000n; + +const scheme = new BatchSettlementEvmScheme(signer, { + depositPolicy: { depositMultiplier }, + depositStrategy: ({ depositAmount }) => { + const amount = BigInt(depositAmount); + return amount > maxDeposit ? maxDeposit : undefined; + }, +}); +``` + +## Prerequisites + +- Node.js v20+, pnpm v10 +- A running [batch-settlement server](../../servers/batch-settlement) +- A funded EVM `EVM_PRIVATE_KEY` holding the deposit token (USDC on Base Sepolia by default) + +## Setup + +```bash +cp .env-local .env +# fill EVM_PRIVATE_KEY (and optionally EVM_VOUCHER_SIGNER_PRIVATE_KEY) + +cd ../../ +pnpm install && pnpm build +cd clients/batch-settlement + +pnpm start +``` + +## Concurrent requests + +Use the concurrent example to send requests over multiple channels in parallel. Each slot uses a unique salt derived from `CHANNEL_SALT`, so the server can serialize work per channel while still processing channels concurrently. + +```bash +CONCURRENCY=3 NUMBER_OF_ROUNDS=3 pnpm dev:concurrent +``` + +## Environment + +| Variable | Required | Description | +|----------|----------|-------------| +| `EVM_PRIVATE_KEY` | yes | Payer key (funds the deposit) | +| `EVM_VOUCHER_SIGNER_PRIVATE_KEY` | no | Dedicated voucher-signing EOA (committed as `payerAuthorizer`) | +| `RESOURCE_SERVER_URL` | no | Server base URL (default `http://localhost:4021`) | +| `ENDPOINT_PATH` | no | Path on the server (default `/weather`) | +| `CHANNEL_SALT` | no | `bytes32` salt for channel id; change to open a fresh channel | +| `DEPOSIT_MULTIPLIER` | no | Per-request deposit is payment amount × this multiplier (must be integer **≥ 3**; default `5`) | +| `STORAGE_DIR` | no | Persist client session state (defaults to in-memory) | +| `NUMBER_OF_REQUESTS` | no | How many paid requests to issue (default 3) | +| `CONCURRENCY` | no | How many channels to run in parallel in `pnpm dev:concurrent` (default 3) | +| `NUMBER_OF_ROUNDS` | no | How many concurrent rounds to run in `pnpm dev:concurrent` (default 3) | +| `REFUND_AFTER_REQUESTS` | no | If `true`, issue a self-contained refund via `scheme.refund(url)` after the request loop | +| `REFUND_AMOUNT` | no | Partial refund amount in base units; omit for a full refund | diff --git a/examples/typescript/legacy/agent/eslint.config.js b/examples/typescript/clients/batch-settlement/eslint.config.js similarity index 100% rename from examples/typescript/legacy/agent/eslint.config.js rename to examples/typescript/clients/batch-settlement/eslint.config.js diff --git a/examples/typescript/clients/batch-settlement/index.ts b/examples/typescript/clients/batch-settlement/index.ts new file mode 100644 index 0000000000..dc535ef2ab --- /dev/null +++ b/examples/typescript/clients/batch-settlement/index.ts @@ -0,0 +1,106 @@ +import { toClientEvmSigner } from "@x402/evm"; +import { + BatchSettlementEvmScheme, + FileClientChannelStorage, +} from "@x402/evm/batch-settlement/client"; +import { x402Client, wrapFetchWithPayment, x402HTTPClient } from "@x402/fetch"; +import { config } from "dotenv"; +import { createPublicClient, http } from "viem"; +import { baseSepolia } from "viem/chains"; +import { privateKeyToAccount } from "viem/accounts"; + +config(); + +const evmPrivateKeyRaw = process.env.EVM_PRIVATE_KEY?.trim(); +if (!evmPrivateKeyRaw) { + console.error("EVM_PRIVATE_KEY environment variable is required"); + process.exit(1); +} +const evmPrivateKey = evmPrivateKeyRaw as `0x${string}`; +// Blank `KEY=` in .env is "" not undefined — treat as unset (same as optional Go env). +const evmVoucherSignerPrivateKey = process.env.EVM_VOUCHER_SIGNER_PRIVATE_KEY?.trim() || undefined; +const baseURL = process.env.RESOURCE_SERVER_URL || "http://localhost:4021"; +const endpointPath = process.env.ENDPOINT_PATH || "/weather"; +const url = `${baseURL}${endpointPath}`; +const storageDir = process.env.STORAGE_DIR; +const channelSalt = (process.env.CHANNEL_SALT ?? + "0x0000000000000000000000000000000000000000000000000000000000000000") as `0x${string}`; +const numberOfRequests = Number(process.env.NUMBER_OF_REQUESTS ?? "3"); +const refundAfterRequests = process.env.REFUND_AFTER_REQUESTS === "true"; +const refundAmount = process.env.REFUND_AMOUNT; +const depositMultiplier = Number(process.env.DEPOSIT_MULTIPLIER ?? "5"); + +/** + * Runs sequential paid requests against the configured resource server endpoint. + * + * @returns Resolves after all configured requests complete. + */ +async function main(): Promise { + const account = privateKeyToAccount(evmPrivateKey); + const publicClient = createPublicClient({ + chain: baseSepolia, + transport: http(), + }); + const signer = toClientEvmSigner(account, publicClient); + + const voucherSigner = evmVoucherSignerPrivateKey + ? toClientEvmSigner(privateKeyToAccount(evmVoucherSignerPrivateKey as `0x${string}`)) + : undefined; + + const batchedScheme = new BatchSettlementEvmScheme(signer, { + depositPolicy: { + depositMultiplier, + }, + salt: channelSalt, + ...(voucherSigner ? { voucherSigner } : {}), + ...(storageDir ? { storage: new FileClientChannelStorage({ directory: storageDir }) } : {}), + }); + + const client = new x402Client(); + client.register("eip155:*", batchedScheme); + + const fetchWithPayment = wrapFetchWithPayment(fetch, client); + const httpClient = new x402HTTPClient(client); + + console.log(`Base URL: ${baseURL}, endpoint: ${endpointPath}`); + console.log("payer:", signer.address); + console.log("payerAuthorizer:", voucherSigner?.address ?? signer.address, "\n"); + + for (let i = 0; i < numberOfRequests; i++) { + const requestT0 = performance.now(); + + const response = await fetchWithPayment(url, { method: "GET" }); + const result = await httpClient.processResponse(response); + + if (result.kind === "success") { + console.log(`Request ${i + 1} — RESPONSE`); + console.log(result.body); + console.log(JSON.stringify(result.settleResponse, null, 2)); + } else { + console.log(`Request ${i + 1} — ${result.kind}`); + console.log(JSON.stringify(result, null, 2)); + } + console.log( + `Request ${i + 1} — completed in ${((performance.now() - requestT0) / 1000).toFixed(3)}s\n`, + ); + } + + if (refundAfterRequests) { + console.log( + refundAmount + ? `REQUESTING PARTIAL REFUND of ${refundAmount} base units` + : "REQUESTING FULL REFUND of remaining channel balance", + ); + const refundT0 = performance.now(); + const settle = await batchedScheme.refund(url, { + ...(refundAmount ? { amount: refundAmount } : {}), + }); + console.log(JSON.stringify(settle, null, 2)); + console.log(`Refund completed in ${((performance.now() - refundT0) / 1000).toFixed(3)}s`); + } +} + +main().catch(error => { + console.error(error?.response?.data?.error ?? error); + process.exit(1); +}); diff --git a/examples/typescript/legacy/servers/advanced/package.json b/examples/typescript/clients/batch-settlement/package.json similarity index 70% rename from examples/typescript/legacy/servers/advanced/package.json rename to examples/typescript/clients/batch-settlement/package.json index 215eb6c196..cc90ef7b77 100644 --- a/examples/typescript/legacy/servers/advanced/package.json +++ b/examples/typescript/clients/batch-settlement/package.json @@ -1,31 +1,33 @@ { - "name": "advanced-server-example", + "name": "@x402/batch-settlement-client-example", "private": true, "type": "module", "scripts": { + "start": "tsx index.ts", "dev": "tsx index.ts", + "dev:concurrent": "tsx concurrent.ts", "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", "lint": "eslint . --ext .ts --fix", "lint:check": "eslint . --ext .ts" }, "dependencies": { + "@x402/evm": "workspace:*", + "@x402/fetch": "workspace:*", "dotenv": "^16.4.7", - "express": "^4.18.2", - "x402": "workspace:*" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", - "eslint": "^9.24.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", + "eslint": "^9.24.0", "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsdoc": "^50.6.9", + "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0", - "@types/express": "^5.0.1" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/legacy/clients/axios/tsconfig.json b/examples/typescript/clients/batch-settlement/tsconfig.json similarity index 100% rename from examples/typescript/legacy/clients/axios/tsconfig.json rename to examples/typescript/clients/batch-settlement/tsconfig.json diff --git a/examples/typescript/clients/custom/index.ts b/examples/typescript/clients/custom/index.ts index 16ab384035..852cdb2606 100644 --- a/examples/typescript/clients/custom/index.ts +++ b/examples/typescript/clients/custom/index.ts @@ -9,6 +9,7 @@ import { encodePaymentSignatureHeader, } from "@x402/core/http"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { ExactSvmScheme } from "@x402/svm/exact/client"; import type { PaymentRequirements } from "@x402/core/types"; @@ -121,6 +122,7 @@ async function main(): Promise { const client = new x402Client(selectPayment) .register("eip155:*", new ExactEvmScheme(evmSigner)) + .register("eip155:*", new UptoEvmScheme(evmSigner)) .register("solana:*", new ExactSvmScheme(solanaSigner)); console.log("✅ Client ready\n"); diff --git a/examples/typescript/clients/custom/package.json b/examples/typescript/clients/custom/package.json index fa3f580b76..525a589fc5 100644 --- a/examples/typescript/clients/custom/package.json +++ b/examples/typescript/clients/custom/package.json @@ -17,10 +17,11 @@ "@x402/evm": "workspace:*", "@x402/svm": "workspace:*", "dotenv": "^16.4.7", - "viem": "^2.39.0" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -28,7 +29,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/clients/fetch/README.md b/examples/typescript/clients/fetch/README.md index ee64e966ad..5158790afb 100644 --- a/examples/typescript/clients/fetch/README.md +++ b/examples/typescript/clients/fetch/README.md @@ -48,6 +48,10 @@ Required environment variables: - `EVM_PRIVATE_KEY` - Ethereum private key for EVM payments - `SVM_PRIVATE_KEY` - Solana private key for SVM payments +Optional environment variables: + +- `EVM_RPC_URL` - JSON-RPC endpoint for on-chain reads. Enables gas sponsoring extensions (EIP-2612 and ERC-20 approval). Example: `https://sepolia.base.org` + 3. Run the client: ```bash diff --git a/examples/typescript/clients/fetch/index.ts b/examples/typescript/clients/fetch/index.ts index d51b341025..95ef29edac 100644 --- a/examples/typescript/clients/fetch/index.ts +++ b/examples/typescript/clients/fetch/index.ts @@ -1,6 +1,7 @@ import { config } from "dotenv"; import { x402Client, wrapFetchWithPayment, x402HTTPClient } from "@x402/fetch"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { ExactSvmScheme } from "@x402/svm/exact/client"; import { privateKeyToAccount } from "viem/accounts"; import { createKeyPairSignerFromBytes } from "@solana/kit"; @@ -10,6 +11,7 @@ config(); const evmPrivateKey = process.env.EVM_PRIVATE_KEY as `0x${string}`; const svmPrivateKey = process.env.SVM_PRIVATE_KEY as string; +const evmRpcUrl = process.env.EVM_RPC_URL; const baseURL = process.env.RESOURCE_SERVER_URL || "http://localhost:4021"; const endpointPath = process.env.ENDPOINT_PATH || "/weather"; const url = `${baseURL}${endpointPath}`; @@ -22,13 +24,18 @@ const url = `${baseURL}${endpointPath}`; * Required environment variables: * - EVM_PRIVATE_KEY: The private key of the EVM signer * - SVM_PRIVATE_KEY: The private key of the SVM signer + * + * Optional environment variables: + * - EVM_RPC_URL: JSON-RPC endpoint for onchain reads (enables gas sponsoring extensions) */ async function main(): Promise { const evmSigner = privateKeyToAccount(evmPrivateKey); const svmSigner = await createKeyPairSignerFromBytes(base58.decode(svmPrivateKey)); + const rpcOptions = evmRpcUrl ? { rpcUrl: evmRpcUrl } : undefined; const client = new x402Client(); - client.register("eip155:*", new ExactEvmScheme(evmSigner)); + client.register("eip155:*", new ExactEvmScheme(evmSigner, rpcOptions)); + client.register("eip155:*", new UptoEvmScheme(evmSigner, rpcOptions)); client.register("solana:*", new ExactSvmScheme(svmSigner)); const fetchWithPayment = wrapFetchWithPayment(fetch, client); diff --git a/examples/typescript/clients/fetch/package.json b/examples/typescript/clients/fetch/package.json index b7dc80299d..e957e2597a 100644 --- a/examples/typescript/clients/fetch/package.json +++ b/examples/typescript/clients/fetch/package.json @@ -19,11 +19,11 @@ "@x402/fetch": "workspace:*", "@x402/svm": "workspace:*", "dotenv": "^16.4.7", - "viem": "^2.39.0" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", - "@types/node": "^20.0.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -31,7 +31,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/clients/mcp-chatbot/index.ts b/examples/typescript/clients/mcp-chatbot/index.ts index 194be92843..7e7df6fbc5 100644 --- a/examples/typescript/clients/mcp-chatbot/index.ts +++ b/examples/typescript/clients/mcp-chatbot/index.ts @@ -12,6 +12,7 @@ import { config } from "dotenv"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { createx402MCPClient } from "@x402/mcp"; import { privateKeyToAccount } from "viem/accounts"; import OpenAI from "openai"; @@ -69,7 +70,10 @@ export async function main(): Promise { const mcpClient = createx402MCPClient({ name: "openai-mcp-chatbot", version: "1.0.0", - schemes: [{ network: "eip155:84532", client: new ExactEvmScheme(evmSigner) }], + schemes: [ + { network: "eip155:84532", client: new ExactEvmScheme(evmSigner) }, + { network: "eip155:84532", client: new UptoEvmScheme(evmSigner) }, + ], autoPayment: true, onPaymentRequested: async context => { const price = context.paymentRequired.accepts[0]; diff --git a/examples/typescript/clients/mcp-chatbot/package.json b/examples/typescript/clients/mcp-chatbot/package.json index 05ac5f9791..4ddc869fff 100644 --- a/examples/typescript/clients/mcp-chatbot/package.json +++ b/examples/typescript/clients/mcp-chatbot/package.json @@ -11,15 +11,15 @@ }, "dependencies": { "@modelcontextprotocol/sdk": "^1.12.1", - "@x402/core": "workspace:*", "@x402/evm": "workspace:*", "@x402/mcp": "workspace:*", "dotenv": "^16.5.0", "openai": "^4.77.3", - "viem": "^2.39.0" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -27,7 +27,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.20.4", - "typescript": "^5.9.2" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/clients/mcp/advanced.ts b/examples/typescript/clients/mcp/advanced.ts index 0b996b1fcf..462e4f5964 100644 --- a/examples/typescript/clients/mcp/advanced.ts +++ b/examples/typescript/clients/mcp/advanced.ts @@ -15,6 +15,7 @@ import { config } from "dotenv"; import { Client } from "@modelcontextprotocol/sdk/client/index.js"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { x402MCPClient } from "@x402/mcp"; import { x402Client } from "@x402/core/client"; import { privateKeyToAccount } from "viem/accounts"; @@ -61,6 +62,7 @@ export async function main(): Promise { // Step 2: Create x402 payment client manually const paymentClient = new x402Client(); paymentClient.register("eip155:84532", new ExactEvmScheme(evmSigner)); + paymentClient.register("eip155:84532", new UptoEvmScheme(evmSigner)); // Step 3: Compose into x402MCPClient const x402Mcp = new x402MCPClient(mcpClient, paymentClient, { diff --git a/examples/typescript/clients/mcp/chatbot.ts b/examples/typescript/clients/mcp/chatbot.ts index 71bc11d725..aec8e9c466 100644 --- a/examples/typescript/clients/mcp/chatbot.ts +++ b/examples/typescript/clients/mcp/chatbot.ts @@ -16,6 +16,7 @@ import { config } from "dotenv"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { createx402MCPClient } from "@x402/mcp"; import { privateKeyToAccount } from "viem/accounts"; import * as readline from "readline"; @@ -44,7 +45,10 @@ export async function main(): Promise { const client = createx402MCPClient({ name: "x402-chatbot", version: "1.0.0", - schemes: [{ network: "eip155:84532", client: new ExactEvmScheme(evmSigner) }], + schemes: [ + { network: "eip155:84532", client: new ExactEvmScheme(evmSigner) }, + { network: "eip155:84532", client: new UptoEvmScheme(evmSigner) }, + ], autoPayment: true, onPaymentRequested: async context => { const price = context.paymentRequired.accepts[0]; diff --git a/examples/typescript/clients/mcp/openai-chatbot.ts b/examples/typescript/clients/mcp/openai-chatbot.ts index b90613b9fd..71b493fdbe 100644 --- a/examples/typescript/clients/mcp/openai-chatbot.ts +++ b/examples/typescript/clients/mcp/openai-chatbot.ts @@ -18,6 +18,7 @@ import { config } from "dotenv"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { createx402MCPClient } from "@x402/mcp"; import { privateKeyToAccount } from "viem/accounts"; import OpenAI from "openai"; @@ -61,7 +62,10 @@ export async function main(): Promise { const mcpClient = createx402MCPClient({ name: "openai-chatbot", version: "1.0.0", - schemes: [{ network: "eip155:84532", client: new ExactEvmScheme(evmSigner) }], + schemes: [ + { network: "eip155:84532", client: new ExactEvmScheme(evmSigner) }, + { network: "eip155:84532", client: new UptoEvmScheme(evmSigner) }, + ], autoPayment: true, onPaymentRequested: async context => { const price = context.paymentRequired.accepts[0]; diff --git a/examples/typescript/clients/mcp/package.json b/examples/typescript/clients/mcp/package.json index 681c6c797a..6e62ecea40 100644 --- a/examples/typescript/clients/mcp/package.json +++ b/examples/typescript/clients/mcp/package.json @@ -19,10 +19,11 @@ "@x402/mcp": "workspace:*", "dotenv": "^16.5.0", "openai": "^4.77.3", - "viem": "^2.39.0" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -30,7 +31,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/clients/mcp/simple.ts b/examples/typescript/clients/mcp/simple.ts index dc9bbf2490..cdc2c8022f 100644 --- a/examples/typescript/clients/mcp/simple.ts +++ b/examples/typescript/clients/mcp/simple.ts @@ -10,6 +10,7 @@ import { config } from "dotenv"; import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { createx402MCPClient } from "@x402/mcp"; import { privateKeyToAccount } from "viem/accounts"; @@ -41,7 +42,10 @@ export async function main(): Promise { const x402Mcp = createx402MCPClient({ name: "x402-mcp-client-demo", version: "1.0.0", - schemes: [{ network: "eip155:84532", client: new ExactEvmScheme(evmSigner) }], + schemes: [ + { network: "eip155:84532", client: new ExactEvmScheme(evmSigner) }, + { network: "eip155:84532", client: new UptoEvmScheme(evmSigner) }, + ], autoPayment: true, onPaymentRequested: async context => { const price = context.paymentRequired.accepts[0]; diff --git a/examples/typescript/clients/offer-receipt/package.json b/examples/typescript/clients/offer-receipt/package.json index f523c4e2b5..bddcc9e17f 100644 --- a/examples/typescript/clients/offer-receipt/package.json +++ b/examples/typescript/clients/offer-receipt/package.json @@ -17,11 +17,11 @@ "@x402/fetch": "workspace:*", "@x402/svm": "workspace:*", "dotenv": "^16.4.7", - "viem": "^2.39.0" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", - "@types/node": "^20.0.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -29,7 +29,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/clients/payment-identifier/index.ts b/examples/typescript/clients/payment-identifier/index.ts index 51196ffbaf..fec6c512a5 100644 --- a/examples/typescript/clients/payment-identifier/index.ts +++ b/examples/typescript/clients/payment-identifier/index.ts @@ -1,6 +1,7 @@ import { config } from "dotenv"; import { x402Client, wrapFetchWithPayment, x402HTTPClient } from "@x402/fetch"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { privateKeyToAccount } from "viem/accounts"; import { appendPaymentIdentifierToExtensions, @@ -35,6 +36,7 @@ async function main(): Promise { const client = new x402Client(); client.register("eip155:*", new ExactEvmScheme(signer)); + client.register("eip155:*", new UptoEvmScheme(signer)); // Generate a unique payment ID for this request const paymentId = generatePaymentId(); diff --git a/examples/typescript/clients/payment-identifier/package.json b/examples/typescript/clients/payment-identifier/package.json index 9970be98de..9d78644fdc 100644 --- a/examples/typescript/clients/payment-identifier/package.json +++ b/examples/typescript/clients/payment-identifier/package.json @@ -15,10 +15,11 @@ "@x402/fetch": "workspace:*", "@x402/extensions": "workspace:*", "dotenv": "^16.4.7", - "viem": "^2.39.0" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -26,7 +27,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/clients/sign-in-with-x/index.ts b/examples/typescript/clients/sign-in-with-x/index.ts index a8b1b31cfe..c9cdd6a833 100644 --- a/examples/typescript/clients/sign-in-with-x/index.ts +++ b/examples/typescript/clients/sign-in-with-x/index.ts @@ -1,6 +1,7 @@ import { config } from "dotenv"; import { x402Client, x402HTTPClient, wrapFetchWithPayment } from "@x402/fetch"; import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; import { ExactSvmScheme } from "@x402/svm/exact/client"; import { privateKeyToAccount } from "viem/accounts"; import { createKeyPairSignerFromBytes } from "@solana/kit"; @@ -27,6 +28,7 @@ const svmSigner = svmPrivateKey const client = new x402Client(); if (evmSigner) { client.register("eip155:*", new ExactEvmScheme(evmSigner)); + client.register("eip155:*", new UptoEvmScheme(evmSigner)); } if (svmSigner) { client.register("solana:*", new ExactSvmScheme(svmSigner)); diff --git a/examples/typescript/clients/sign-in-with-x/package.json b/examples/typescript/clients/sign-in-with-x/package.json index 5c91986e11..fd1cedd485 100644 --- a/examples/typescript/clients/sign-in-with-x/package.json +++ b/examples/typescript/clients/sign-in-with-x/package.json @@ -12,17 +12,18 @@ }, "dependencies": { "@solana/kit": "^5.1.0", + "@scure/base": "^1.2.6", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", "@x402/extensions": "workspace:*", "@x402/fetch": "workspace:*", "@x402/svm": "workspace:*", "dotenv": "^16.4.7", - "viem": "^2.39.0" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", - "@types/node": "^22.10.5", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -30,8 +31,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0", - "@scure/base": "^1.2.6" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/facilitator/.env-local b/examples/typescript/facilitator/.env-local index b9b7a2492b..d3d28c3afa 100644 --- a/examples/typescript/facilitator/.env-local +++ b/examples/typescript/facilitator/.env-local @@ -1,4 +1,6 @@ PORT= EVM_PRIVATE_KEY= STELLAR_PRIVATE_KEY= -SVM_PRIVATE_KEY= \ No newline at end of file +SVM_PRIVATE_KEY= +HEDERA_ACCOUNT_ID= +HEDERA_PRIVATE_KEY= \ No newline at end of file diff --git a/examples/typescript/facilitator/advanced/.env-local b/examples/typescript/facilitator/advanced/.env-local new file mode 100644 index 0000000000..a25f6d3e29 --- /dev/null +++ b/examples/typescript/facilitator/advanced/.env-local @@ -0,0 +1,5 @@ +PORT= +EVM_PRIVATE_KEY= +SVM_PRIVATE_KEY= +HEDERA_ACCOUNT_ID= +HEDERA_PRIVATE_KEY= \ No newline at end of file diff --git a/examples/typescript/facilitator/advanced/README.md b/examples/typescript/facilitator/advanced/README.md index a0ab84758e..17cefc2b85 100644 --- a/examples/typescript/facilitator/advanced/README.md +++ b/examples/typescript/facilitator/advanced/README.md @@ -1,6 +1,6 @@ # x402 Advanced Facilitator Examples -Express.js facilitator service demonstrating advanced x402 patterns including all-networks support, bazaar discovery, and lifecycle hooks. +Express.js facilitator service demonstrating advanced x402 patterns including all-networks support, bazaar discovery, Permit2 gas-sponsoring extensions (`gas_extensions`), and lifecycle hooks. ## Prerequisites @@ -9,6 +9,7 @@ Express.js facilitator service demonstrating advanced x402 patterns including al - EVM private key with Base Sepolia ETH for transaction fees - SVM private key with Solana Devnet SOL for transaction fees - Stellar private key with testnet XLM for transaction fees (fund via [Stellar Laboratory](https://lab.stellar.org/account/create) ➡️ Generate keypair ➡️ Fund account with Friendbot) +- Hedera account id + private key for Hedera testnet fees (optional) ## Setup @@ -23,6 +24,8 @@ and fill required environment variables: - `EVM_PRIVATE_KEY` - Ethereum private key - `SVM_PRIVATE_KEY` - Solana private key - `STELLAR_PRIVATE_KEY` - Stellar secret key (starts with `S`) +- `HEDERA_ACCOUNT_ID` - Hedera account id for fee payer (optional) +- `HEDERA_PRIVATE_KEY` - Hedera **ECDSA** private key (0x-prefixed or DER-encoded) for fee payer (optional) - `PORT` - Server port (optional, defaults to 4022) 2. Install and build all packages from the typescript examples root: @@ -38,16 +41,18 @@ cd facilitator/advanced ```bash pnpm dev:all-networks # All supported networks pnpm dev:bazaar # Bazaar discovery extension +pnpm dev:gas-extensions # exact + upto with EIP-2612 and ERC-20 approval gas sponsoring ``` ## Available Examples Each example demonstrates a specific advanced pattern: -| Example | Command | Description | -| -------------- | ----------------------- | -------------------------------------------------------- | -| `all-networks` | `pnpm dev:all-networks` | All supported networks with optional chain configuration | -| `bazaar` | `pnpm dev:bazaar` | Bazaar discovery extension for cataloging x402 resources | +| Example | Command | Description | +| ---------------- | ------------------------- | ------------------------------------------------------------------------- | +| `all-networks` | `pnpm dev:all-networks` | All supported networks with optional chain configuration | +| `bazaar` | `pnpm dev:bazaar` | Bazaar discovery extension for cataloging x402 resources | +| `gas_extensions` | `pnpm dev:gas-extensions` | Base Sepolia `exact` + `upto` with both Permit2 gas-sponsoring extensions | ## API Endpoints @@ -242,3 +247,5 @@ Networks use [CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/cai - `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` — Solana Mainnet - `stellar:testnet` — Stellar Testnet - `stellar:pubnet` — Stellar Mainnet +- `hedera:testnet` — Hedera Testnet +- `hedera:mainnet` — Hedera Mainnet diff --git a/examples/typescript/facilitator/advanced/all_networks.ts b/examples/typescript/facilitator/advanced/all_networks.ts index 1513417b41..ecce239c76 100644 --- a/examples/typescript/facilitator/advanced/all_networks.ts +++ b/examples/typescript/facilitator/advanced/all_networks.ts @@ -8,8 +8,8 @@ * (e.g., "eip155" before "solana" before "stellar"). */ -import { base58 } from "@scure/base"; -import { createKeyPairSignerFromBytes } from "@solana/kit"; +import { toFacilitatorAvmSigner } from "@x402/avm"; +import { ExactAvmScheme } from "@x402/avm/exact/facilitator"; import { x402Facilitator } from "@x402/core/facilitator"; import { PaymentPayload, @@ -19,8 +19,21 @@ import { } from "@x402/core/types"; import { toFacilitatorEvmSigner } from "@x402/evm"; import { ExactEvmScheme } from "@x402/evm/exact/facilitator"; +import { UptoEvmScheme } from "@x402/evm/upto/facilitator"; +import { + AccountId, + Client, + PrivateKey, + createHederaClient, + createHederaPreflightTransfer, + createHederaSignAndSubmitTransaction, + toFacilitatorHederaSigner, +} from "@x402/hedera"; +import { ExactHederaScheme } from "@x402/hedera/exact/facilitator"; import { toFacilitatorSvmSigner } from "@x402/svm"; import { ExactSvmScheme } from "@x402/svm/exact/facilitator"; +import { base58 } from "@scure/base"; +import { createKeyPairSignerFromBytes } from "@solana/kit"; import { createEd25519Signer } from "@x402/stellar"; import { ExactStellarScheme } from "@x402/stellar/exact/facilitator"; import dotenv from "dotenv"; @@ -34,21 +47,33 @@ dotenv.config(); // Configuration const PORT = process.env.PORT || "4022"; -// Configuration - optional per network +// Configuration - optional per network (alphabetic order) +const avmPrivateKey = process.env.AVM_PRIVATE_KEY as string | undefined; const evmPrivateKey = process.env.EVM_PRIVATE_KEY as `0x${string}` | undefined; const svmPrivateKey = process.env.SVM_PRIVATE_KEY as string | undefined; const stellarPrivateKey = process.env.STELLAR_PRIVATE_KEY as string | undefined; +const hederaAccountId = process.env.HEDERA_ACCOUNT_ID; +// Hedera private key should be an ECDSA key string (0x-prefixed or DER-encoded). +const hederaPrivateKey = process.env.HEDERA_PRIVATE_KEY; // Validate at least one private key is provided -if (!evmPrivateKey && !svmPrivateKey && !stellarPrivateKey) { +if ( + !avmPrivateKey && + !evmPrivateKey && + !svmPrivateKey && + !stellarPrivateKey && + !(hederaAccountId && hederaPrivateKey) +) { console.error( - "❌ At least one of EVM_PRIVATE_KEY, SVM_PRIVATE_KEY, or STELLAR_PRIVATE_KEY is required", + "❌ At least one of AVM_PRIVATE_KEY, EVM_PRIVATE_KEY, SVM_PRIVATE_KEY, STELLAR_PRIVATE_KEY, or HEDERA_ACCOUNT_ID + HEDERA_PRIVATE_KEY is required", ); process.exit(1); } -// Network configuration +// Network configuration (alphabetic order) +const AVM_NETWORK = "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="; // Algorand Testnet const EVM_NETWORK = "eip155:84532"; // Base Sepolia +const HEDERA_NETWORK = "hedera:testnet"; // Hedera Testnet const SVM_NETWORK = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1"; // Solana Devnet const STELLAR_NETWORK = "stellar:testnet"; // Stellar Testnet @@ -73,6 +98,13 @@ const facilitator = new x402Facilitator() console.log("Settle failure", context); }); +// Register AVM scheme if private key is provided +if (avmPrivateKey) { + const avmSigner = toFacilitatorAvmSigner(avmPrivateKey); + console.info(`AVM Facilitator account: ${avmSigner.getAddresses()[0]}`); + facilitator.register(AVM_NETWORK, new ExactAvmScheme(avmSigner)); +} + // Register EVM scheme if private key is provided if (evmPrivateKey) { const evmAccount = privateKeyToAccount(evmPrivateKey); @@ -127,6 +159,7 @@ if (evmPrivateKey) { EVM_NETWORK, new ExactEvmScheme(evmSigner, { deployERC4337WithEIP6492: true }), ); + facilitator.register(EVM_NETWORK, new UptoEvmScheme(evmSigner)); } // Register SVM scheme if private key is provided @@ -152,6 +185,27 @@ if (stellarPrivateKey) { ); } +// Register Hedera scheme if account and private key are provided +if (hederaAccountId && hederaPrivateKey) { + const hederaKey = PrivateKey.fromStringECDSA(hederaPrivateKey); + const buildHederaClient = (network: string): Client => { + const client = createHederaClient(network); + client.setOperator(AccountId.fromString(hederaAccountId), hederaKey); + return client; + }; + + const hederaSigner = toFacilitatorHederaSigner({ + getAddresses: () => [hederaAccountId], + signAndSubmitTransaction: createHederaSignAndSubmitTransaction( + buildHederaClient, + hederaKey, + ), + preflightTransfer: createHederaPreflightTransfer(buildHederaClient), + }); + facilitator.register(HEDERA_NETWORK, new ExactHederaScheme(hederaSigner)); + console.info(`Hedera Facilitator account: ${hederaAccountId}`); +} + // Initialize Express app const app = express(); app.use(express.json()); diff --git a/examples/typescript/facilitator/advanced/bazaar.ts b/examples/typescript/facilitator/advanced/bazaar.ts index d1a701b560..beee3f1513 100644 --- a/examples/typescript/facilitator/advanced/bazaar.ts +++ b/examples/typescript/facilitator/advanced/bazaar.ts @@ -16,6 +16,7 @@ import { } from "@x402/core/types"; import { toFacilitatorEvmSigner } from "@x402/evm"; import { ExactEvmScheme } from "@x402/evm/exact/facilitator"; +import { UptoEvmScheme } from "@x402/evm/upto/facilitator"; import { toFacilitatorSvmSigner } from "@x402/svm"; import { ExactSvmScheme } from "@x402/svm/exact/facilitator"; import { extractDiscoveryInfo, DiscoveryInfo } from "@x402/extensions/bazaar"; @@ -56,6 +57,7 @@ interface DiscoveredResource { accepts: PaymentRequirements[]; discoveryInfo?: DiscoveryInfo; lastUpdated: string; + extensions?: Record; } // BazaarCatalog stores discovered resources @@ -82,10 +84,59 @@ class BazaarCatalog { getAll(): DiscoveredResource[] { return Array.from(this.resources.values()); } + + /** + * Search resources using case-insensitive keyword matching. + * Matches against resource URL, type, and extension values. + * + * @param query - Search query string + * @param type - Optional filter by resource type + * @param limit - Optional advisory maximum results + * @returns Matching resources with optional pagination hints + */ + search(query: string, type?: string, limit?: number): DiscoveredResource[] { + const needle = query.toLowerCase(); + let results = Array.from(this.resources.values()).filter((r) => { + const haystack = [ + r.resource, + r.type, + r.description ?? "", + ...Object.values(r.extensions ?? {}), + ] + .join(" ") + .toLowerCase(); + return haystack.includes(needle); + }); + + if (type) { + results = results.filter((r) => r.type === type); + } + + return limit !== undefined ? results.slice(0, limit) : results; + } } const bazaarCatalog = new BazaarCatalog(); +const EXTENSION_RESPONSES_HEADER = "EXTENSION-RESPONSES"; + +/** + * Attach an example bazaar extension response header for clients to read back. + * + * @param res - Express response + */ +function setExtensionResponsesHeader(res: express.Response): void { + const extensionResponses = { + bazaar: { + status: "success", + }, + }; + res.setHeader( + EXTENSION_RESPONSES_HEADER, + Buffer.from(JSON.stringify(extensionResponses), "utf8").toString("base64"), + ); +} + // Initialize the x402 Facilitator with discovery hooks const facilitator = new x402Facilitator() .onBeforeVerify(async (context) => { @@ -117,11 +168,12 @@ const facilitator = new x402Facilitator() resource: discovered.resourceUrl, description: discovered.description, mimeType: discovered.mimeType, - type: "http", + type: discovered.discoveryInfo.input.type, x402Version: discovered.x402Version, accepts: [context.requirements], discoveryInfo: discovered.discoveryInfo, lastUpdated: new Date().toISOString(), + extensions: {}, }); console.log(" ✅ Added to bazaar catalog"); } @@ -196,6 +248,7 @@ if (evmPrivateKey) { EVM_NETWORK, new ExactEvmScheme(evmSigner, { deployERC4337WithEIP6492: true }), ); + facilitator.register(EVM_NETWORK, new UptoEvmScheme(evmSigner)); } // Register SVM scheme if private key is provided @@ -241,6 +294,7 @@ app.post("/verify", async (req, res) => { paymentRequirements, ); + setExtensionResponsesHeader(res); res.json(response); } catch (error) { console.error("Verify error:", error); @@ -269,6 +323,7 @@ app.post("/settle", async (req, res) => { paymentRequirements as PaymentRequirements, ); + setExtensionResponsesHeader(res); res.json(response); } catch (error) { console.error("Settle error:", error); @@ -331,6 +386,37 @@ app.get("/discovery/resources", async (req, res) => { } }); +/** + * GET /discovery/search + * Search discovered resources using keyword matching + */ +app.get("/discovery/search", async (req, res) => { + try { + const query = req.query.query as string; + if (!query) { + return res.status(400).json({ error: "query parameter is required" }); + } + const type = req.query.type as string | undefined; + const limit = req.query.limit + ? parseInt(req.query.limit as string) + : undefined; + + const items = bazaarCatalog.search(query, type, limit); + + res.json({ + x402Version: 2, + resources: items, + partialResults: false, + pagination: null, + }); + } catch (error) { + console.error("Discovery search error:", error); + res.status(500).json({ + error: error instanceof Error ? error.message : "Unknown error", + }); + } +}); + /** * GET /health * Health check endpoint diff --git a/examples/typescript/facilitator/advanced/gas_extensions.ts b/examples/typescript/facilitator/advanced/gas_extensions.ts new file mode 100644 index 0000000000..207740ca0c --- /dev/null +++ b/examples/typescript/facilitator/advanced/gas_extensions.ts @@ -0,0 +1,242 @@ +/** + * Permit2 gas sponsorship facilitator example (`exact` + `upto`) + * + * Registers both `exact` and `upto` EVM schemes on Base Sepolia and advertises the two + * gas-sponsoring extensions: EIP-2612 permits and ERC-20 `approve` transactions (tokens + * without EIP-2612). Both schemes use Permit2 paths that can pair with these extensions. + * + * Requires `EVM_PRIVATE_KEY` with Base Sepolia ETH for settlement and for broadcasting + * client-supplied approval transactions when those extensions are used. + */ + +import { x402Facilitator } from "@x402/core/facilitator"; +import { + PaymentPayload, + PaymentRequirements, + SettleResponse, + VerifyResponse, +} from "@x402/core/types"; +import { toFacilitatorEvmSigner } from "@x402/evm"; +import { ExactEvmScheme } from "@x402/evm/exact/facilitator"; +import { UptoEvmScheme } from "@x402/evm/upto/facilitator"; +import { + EIP2612_GAS_SPONSORING, + createErc20ApprovalGasSponsoringExtension, +} from "@x402/extensions"; +import dotenv from "dotenv"; +import express from "express"; +import { createWalletClient, http, publicActions } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { baseSepolia } from "viem/chains"; + +dotenv.config(); + +const PORT = process.env.PORT || "4022"; +const EVM_NETWORK = "eip155:84532"; + +if (!process.env.EVM_PRIVATE_KEY) { + console.error("❌ EVM_PRIVATE_KEY environment variable is required"); + process.exit(1); +} + +const evmAccount = privateKeyToAccount( + process.env.EVM_PRIVATE_KEY as `0x${string}`, +); +console.info(`EVM Facilitator account: ${evmAccount.address}`); + +const viemClient = createWalletClient({ + account: evmAccount, + chain: baseSepolia, + transport: http(), +}).extend(publicActions); + +const evmSigner = toFacilitatorEvmSigner({ + getCode: (args: { address: `0x${string}` }) => viemClient.getCode(args), + address: evmAccount.address, + readContract: (args: { + address: `0x${string}`; + abi: readonly unknown[]; + functionName: string; + args?: readonly unknown[]; + }) => + viemClient.readContract({ + ...args, + args: args.args || [], + }), + verifyTypedData: (args: { + address: `0x${string}`; + domain: Record; + types: Record; + primaryType: string; + message: Record; + signature: `0x${string}`; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + }) => viemClient.verifyTypedData(args as any), + writeContract: (args: { + address: `0x${string}`; + abi: readonly unknown[]; + functionName: string; + args: readonly unknown[]; + }) => + viemClient.writeContract({ + ...args, + args: args.args || [], + }), + sendTransaction: (args: { to: `0x${string}`; data: `0x${string}` }) => + viemClient.sendTransaction(args), + waitForTransactionReceipt: (args: { hash: `0x${string}` }) => + viemClient.waitForTransactionReceipt(args), +}); + +const facilitator = new x402Facilitator() + .onBeforeVerify(async (context) => { + console.log("Before verify", context); + }) + .onAfterVerify(async (context) => { + console.log("After verify", context); + }) + .onVerifyFailure(async (context) => { + console.log("Verify failure", context); + }) + .onBeforeSettle(async (context) => { + console.log("Before settle", context); + }) + .onAfterSettle(async (context) => { + console.log("After settle", context); + }) + .onSettleFailure(async (context) => { + console.log("Settle failure", context); + }); + +facilitator.register( + EVM_NETWORK, + new ExactEvmScheme(evmSigner, { deployERC4337WithEIP6492: true }), +); +facilitator.register(EVM_NETWORK, new UptoEvmScheme(evmSigner)); + +const erc20ApprovalSigner = { + ...evmSigner, + sendTransactions: async ( + transactions: ( + | `0x${string}` + | { to: `0x${string}`; data: `0x${string}`; gas?: bigint } + )[], + ): Promise<`0x${string}`[]> => { + const hashes: `0x${string}`[] = []; + for (const tx of transactions) { + let hash: `0x${string}`; + if (typeof tx === "string") { + hash = await viemClient.sendRawTransaction({ + serializedTransaction: tx, + }); + } else { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + hash = await viemClient.sendTransaction(tx as any); + } + const receipt = await viemClient.waitForTransactionReceipt({ hash }); + if (receipt.status !== "success") { + throw new Error(`transaction_failed: ${hash}`); + } + hashes.push(hash); + } + return hashes; + }, +}; + +facilitator + .registerExtension(EIP2612_GAS_SPONSORING) + .registerExtension( + createErc20ApprovalGasSponsoringExtension(erc20ApprovalSigner), + ); + +const app = express(); +app.use(express.json()); + +app.post("/verify", async (req, res) => { + try { + const { paymentPayload, paymentRequirements } = req.body as { + paymentPayload: PaymentPayload; + paymentRequirements: PaymentRequirements; + }; + + if (!paymentPayload || !paymentRequirements) { + return res.status(400).json({ + error: "Missing paymentPayload or paymentRequirements", + }); + } + + const response: VerifyResponse = await facilitator.verify( + paymentPayload, + paymentRequirements, + ); + + res.json(response); + } catch (error) { + console.error("Verify error:", error); + res.status(500).json({ + error: error instanceof Error ? error.message : "Unknown error", + }); + } +}); + +app.post("/settle", async (req, res) => { + try { + const { paymentPayload, paymentRequirements } = req.body; + + if (!paymentPayload || !paymentRequirements) { + return res.status(400).json({ + error: "Missing paymentPayload or paymentRequirements", + }); + } + + const response: SettleResponse = await facilitator.settle( + paymentPayload as PaymentPayload, + paymentRequirements as PaymentRequirements, + ); + + res.json(response); + } catch (error) { + console.error("Settle error:", error); + + if ( + error instanceof Error && + error.message.includes("Settlement aborted:") + ) { + return res.json({ + success: false, + errorReason: error.message.replace("Settlement aborted: ", ""), + network: req.body?.paymentPayload?.network || "unknown", + } as SettleResponse); + } + + res.status(500).json({ + error: error instanceof Error ? error.message : "Unknown error", + }); + } +}); + +app.get("/supported", async (req, res) => { + try { + const response = facilitator.getSupported(); + res.json(response); + } catch (error) { + console.error("Supported error:", error); + res.status(500).json({ + error: error instanceof Error ? error.message : "Unknown error", + }); + } +}); + +app.get("/health", (req, res) => { + res.json({ status: "ok" }); +}); + +app.listen(parseInt(PORT), () => { + console.log( + `🚀 Gas extensions facilitator (exact + upto) listening on http://localhost:${PORT}`, + ); + console.log( + ` Extensions: eip2612GasSponsoring, erc20ApprovalGasSponsoring`, + ); + console.log(); +}); diff --git a/examples/typescript/facilitator/advanced/package.json b/examples/typescript/facilitator/advanced/package.json index 34253157d8..339e68a4ed 100644 --- a/examples/typescript/facilitator/advanced/package.json +++ b/examples/typescript/facilitator/advanced/package.json @@ -8,6 +8,7 @@ "dev": "tsx all_networks.ts", "dev:all-networks": "tsx all_networks.ts", "dev:bazaar": "tsx bazaar.ts", + "dev:gas-extensions": "tsx gas_extensions.ts", "build": "tsc", "lint": "eslint .", "format": "prettier --write .", @@ -16,27 +17,29 @@ "dependencies": { "@scure/base": "^1.2.6", "@solana/kit": "^6.1.0", + "@x402/avm": "workspace:*", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", "@x402/extensions": "workspace:*", + "@x402/hedera": "workspace:*", "@x402/svm": "workspace:*", "@x402/stellar": "workspace:*", "dotenv": "^16.4.5", "express": "^4.19.2", - "viem": "^2.21.54" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "^4.17.21", - "@types/node": "^22.10.1", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", - "eslint": "^9.15.0", + "eslint": "^9.24.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", - "prettier": "^3.3.3", - "tsx": "^4.19.2", - "typescript": "^5.7.2" + "prettier": "3.5.2", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/facilitator/basic/README.md b/examples/typescript/facilitator/basic/README.md index 6baf4845f5..952ca4b2d7 100644 --- a/examples/typescript/facilitator/basic/README.md +++ b/examples/typescript/facilitator/basic/README.md @@ -6,8 +6,8 @@ Express.js facilitator service that verifies and settles payments on-chain for t - Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) - pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- EVM private key with Base Sepolia ETH for transaction fees -- SVM private key with Solana Devnet SOL for transaction fees +- Dedicated EVM facilitator private key with Base Sepolia ETH for transaction fees +- Dedicated SVM facilitator private key with Solana Devnet SOL for transaction fees ## Setup @@ -19,10 +19,12 @@ cp .env-local .env and fill required environment variables: -- `EVM_PRIVATE_KEY` - Ethereum private key -- `SVM_PRIVATE_KEY` - Solana private key +- `EVM_PRIVATE_KEY` - Ethereum facilitator private key +- `SVM_PRIVATE_KEY` - Solana facilitator private key - `PORT` - Server port (optional, defaults to 4022) +**⚠️ Security Note:** The facilitator key is the signer used to settle payments on-chain. Keep it separate from your seller `payTo` wallet and buyer test wallets, and make sure it is funded only for facilitator gas/fees. + 2. Install and build all packages from the typescript examples root: ```bash diff --git a/examples/typescript/facilitator/basic/index.ts b/examples/typescript/facilitator/basic/index.ts index baf957bea8..2a90c30b27 100644 --- a/examples/typescript/facilitator/basic/index.ts +++ b/examples/typescript/facilitator/basic/index.ts @@ -9,6 +9,7 @@ import { } from "@x402/core/types"; import { toFacilitatorEvmSigner } from "@x402/evm"; import { ExactEvmScheme } from "@x402/evm/exact/facilitator"; +import { UptoEvmScheme } from "@x402/evm/upto/facilitator"; import { toFacilitatorSvmSigner } from "@x402/svm"; import { ExactSvmScheme } from "@x402/svm/exact/facilitator"; import dotenv from "dotenv"; @@ -120,6 +121,7 @@ facilitator.register( "eip155:84532", new ExactEvmScheme(evmSigner, { deployERC4337WithEIP6492: true }), ); // Base Sepolia +facilitator.register("eip155:84532", new UptoEvmScheme(evmSigner)); facilitator.register( "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme(svmSigner), diff --git a/examples/typescript/facilitator/basic/package.json b/examples/typescript/facilitator/basic/package.json index 8e8b0185f6..bcd6d183a3 100644 --- a/examples/typescript/facilitator/basic/package.json +++ b/examples/typescript/facilitator/basic/package.json @@ -16,24 +16,23 @@ "@solana/kit": "^6.1.0", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", - "@x402/extensions": "workspace:*", "@x402/svm": "workspace:*", "dotenv": "^16.4.5", "express": "^4.19.2", - "viem": "^2.21.54" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "^4.17.21", - "@types/node": "^22.10.1", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", - "eslint": "^9.15.0", + "eslint": "^9.24.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", - "prettier": "^3.3.3", - "tsx": "^4.19.2", - "typescript": "^5.7.2" + "prettier": "3.5.2", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/facilitator/batch-settlement/.env-local b/examples/typescript/facilitator/batch-settlement/.env-local new file mode 100644 index 0000000000..bf689dec72 --- /dev/null +++ b/examples/typescript/facilitator/batch-settlement/.env-local @@ -0,0 +1,8 @@ +EVM_PRIVATE_KEY=0x... +EVM_RPC_URL=https://sepolia.base.org + +# Optional dedicated authorizer key (defaults to EVM_PRIVATE_KEY) +EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY= + +# Optional (default 4022). Same as examples/go/facilitator/batch-settlement. +PORT= diff --git a/examples/typescript/facilitator/batch-settlement/README.md b/examples/typescript/facilitator/batch-settlement/README.md new file mode 100644 index 0000000000..716aeffd51 --- /dev/null +++ b/examples/typescript/facilitator/batch-settlement/README.md @@ -0,0 +1,68 @@ +# Batch-Settlement Facilitator Example + +Express.js facilitator for the **batch-settlement** EVM scheme on Base Sepolia. It exposes standard x402 facilitator endpoints and submits the batch-settlement contract calls. + +See the [scheme specification](../../../../specs/schemes/batch-settlement/scheme_batch_settlement_evm.md) and the [scheme README](../../../../typescript/packages/mechanisms/evm/src/batch-settlement/README.md) for protocol details. + +## Two Signer Roles + +This example can use separate keys for relaying transactions and authorizing receiver actions: + +| Env var | Role | Onchain effect | +| ------------------------------------- | -------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------ | +| `EVM_PRIVATE_KEY` | **Relayer** — submits transactions | Pays gas for `deposit` / `claimWithSignature` / `settle` / `refundWithSignature` | +| `EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY` | **Receiver authorizer** — signs `ClaimBatch` and `Refund` EIP-712 messages | Address is committed into the channel identity for any server that delegates to this facilitator | + +If `EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY` is omitted, the relayer key is reused for both roles. In production, keep them separate so the receiver-authorizer key (which controls how much gets claimed) can be rotated independently of the gas-paying hot wallet. + +> The receiver-authorizer address is advertised under `kinds[].extra.receiverAuthorizer` in `GET /supported`. **Servers that delegate authorization to this facilitator bind that address into their channel config** — rotating the authorizer key requires opening new channels, so treat this address as long-lived. + +## Prerequisites + +- Node.js v20+, pnpm v10 +- Base Sepolia ETH on the **relayer** address (gas) +- Optional: a separate funded address for the **authorizer** (no gas required if relayer is separate) + +## Setup + +```bash +cp .env-local .env +# fill EVM_PRIVATE_KEY (and optionally EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY, EVM_RPC_URL, PORT) + +cd ../../ +pnpm install && pnpm build +cd facilitator/batch-settlement + +pnpm dev +``` + +The facilitator listens on `http://localhost:4022` by default (`PORT` env var to override). Env keys match `examples/go/facilitator/batch-settlement/.env-example` (TS uses `.env-local`; Go uses `.env-example`, per each ecosystem's convention). + +## API Surface + +Standard x402 facilitator endpoints: `POST /verify`, `POST /settle`, `GET /supported`. The `/settle` endpoint dispatches on `payload.type`: + +| Payload type | Triggered by | Contract call / effect | +| ------------ | ----------------------------- | ----------------------------------------------- | +| `deposit` | First request or top-up | Funds the channel via EIP-3009 or Permit2 | +| `claim` | Server batches voucher claims | Calls `claimWithSignature` (no transfer) | +| `settle` | Server sweeps unsettled funds | Calls `settle` to transfer claimed funds | +| `refund` | Cooperative refund | Calls `refundWithSignature` for unclaimed funds | + +`/verify` and `/settle` always return the onchain channel snapshot (`balance`, `totalClaimed`, `withdrawRequestedAt`, `refundNonce`) in the `extra` field — the resource server mirrors these into its session state. + +`GET /supported` advertises the receiver authorizer address: + +```json +{ + "kinds": [ + { + "x402Version": 2, + "scheme": "batch-settlement", + "network": "eip155:84532", + "extra": { "receiverAuthorizer": "0x..." } + } + ], + "signers": { "eip155:*": ["0x..."] } +} +``` diff --git a/examples/typescript/legacy/clients/fetch/eslint.config.js b/examples/typescript/facilitator/batch-settlement/eslint.config.js similarity index 95% rename from examples/typescript/legacy/clients/fetch/eslint.config.js rename to examples/typescript/facilitator/batch-settlement/eslint.config.js index ca28b5c47f..784ecd5435 100644 --- a/examples/typescript/legacy/clients/fetch/eslint.config.js +++ b/examples/typescript/facilitator/batch-settlement/eslint.config.js @@ -39,7 +39,10 @@ export default [ "import/first": "error", "prettier/prettier": "error", "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_$" }], + "@typescript-eslint/no-unused-vars": [ + "error", + { argsIgnorePattern: "^_$" }, + ], "jsdoc/tag-lines": ["error", "any", { startLines: 1 }], "jsdoc/check-alignment": "error", "jsdoc/no-undefined-types": "off", diff --git a/examples/typescript/facilitator/batch-settlement/index.ts b/examples/typescript/facilitator/batch-settlement/index.ts new file mode 100644 index 0000000000..0d31eadcf9 --- /dev/null +++ b/examples/typescript/facilitator/batch-settlement/index.ts @@ -0,0 +1,220 @@ +import { x402Facilitator } from "@x402/core/facilitator"; +import { + PaymentPayload, + PaymentRequirements, + SettleResponse, + VerifyResponse, +} from "@x402/core/types"; +import { type AuthorizerSigner, toFacilitatorEvmSigner } from "@x402/evm"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/facilitator"; +import dotenv from "dotenv"; +import express from "express"; +import { createWalletClient, http, nonceManager, publicActions } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { baseSepolia } from "viem/chains"; + +dotenv.config(); + +// Configuration +const PORT = process.env.PORT || "4022"; + +// Validate required environment variables +if (!process.env.EVM_PRIVATE_KEY) { + console.error("❌ EVM_PRIVATE_KEY environment variable is required"); + process.exit(1); +} + +const evmRpcUrl = process.env.EVM_RPC_URL ?? "https://sepolia.base.org"; + +// Treat unset or blank like Go's envOr: `.env` often has `KEY=` which is "" not undefined. +const receiverAuthorizerPrivateKey = + process.env.EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY?.trim() || + process.env.EVM_PRIVATE_KEY; + +// Initialize the EVM account from private key (submits transactions) +const evmAccount = privateKeyToAccount( + process.env.EVM_PRIVATE_KEY as `0x${string}`, + { nonceManager }, +); + +// Dedicated receiverAuthorizer (signs ClaimBatch / Refund EIP-712 messages) +const authorizerAccount = privateKeyToAccount( + receiverAuthorizerPrivateKey as `0x${string}`, +); +const authorizerSigner: AuthorizerSigner = { + address: authorizerAccount.address, + signTypedData: (params) => + authorizerAccount.signTypedData( + params as Parameters[0], + ), +}; + +console.info(`EVM Facilitator account: ${evmAccount.address}`); +console.info(`EVM Receiver Authorizer: ${authorizerSigner.address}`); + +// Create a Viem client with both wallet and public capabilities +const viemClient = createWalletClient({ + account: evmAccount, + chain: baseSepolia, + transport: http(evmRpcUrl), +}).extend(publicActions); + +// Initialize the x402 Facilitator with EVM support +const evmSigner = toFacilitatorEvmSigner({ + address: evmAccount.address, + getCode: (args) => viemClient.getCode(args), + readContract: (args) => + viemClient.readContract({ ...args, args: args.args ?? [] } as Parameters< + typeof viemClient.readContract + >[0]), + verifyTypedData: (args) => + viemClient.verifyTypedData( + args as Parameters[0], + ), + writeContract: (args) => + viemClient.writeContract( + args as Parameters[0], + ), + sendTransaction: (args) => + viemClient.sendTransaction( + args as Parameters[0], + ), + waitForTransactionReceipt: (args) => + viemClient.waitForTransactionReceipt(args), +}); + +const facilitator = new x402Facilitator() + .onBeforeVerify(async (context) => { + console.log("Before verify", context); + }) + .onAfterVerify(async (context) => { + console.log("After verify", context); + }) + .onVerifyFailure(async (context) => { + console.log("Verify failure", context); + }) + .onBeforeSettle(async (context) => { + console.log("Before settle", context); + }) + .onAfterSettle(async (context) => { + console.log("After settle", context); + }) + .onSettleFailure(async (context) => { + console.log("Settle failure", context); + }); + +// Register EVM schemes (batched: deposit / voucher / claim / settle) +facilitator.register( + "eip155:84532", + new BatchSettlementEvmScheme(evmSigner, authorizerSigner), +); // Base Sepolia + +// Initialize Express app +const app = express(); +app.use(express.json()); + +/** + * POST /verify + * Verify a payment against requirements + * + * Note: Payment tracking and bazaar discovery are handled by lifecycle hooks + */ +app.post("/verify", async (req, res) => { + try { + const { paymentPayload, paymentRequirements } = req.body as { + paymentPayload: PaymentPayload; + paymentRequirements: PaymentRequirements; + }; + + if (!paymentPayload || !paymentRequirements) { + return res.status(400).json({ + error: "Missing paymentPayload or paymentRequirements", + }); + } + + // Hooks will automatically: + // - Track verified payment (onAfterVerify) + // - Extract and catalog discovery info (onAfterVerify) + const response: VerifyResponse = await facilitator.verify( + paymentPayload, + paymentRequirements, + ); + + res.json(response); + } catch (error) { + console.error("Verify error:", error); + res.status(500).json({ + error: error instanceof Error ? error.message : "Unknown error", + }); + } +}); + +/** + * POST /settle + * Settle a payment onchain + * + * Note: Verification validation and cleanup are handled by lifecycle hooks + */ +app.post("/settle", async (req, res) => { + try { + const { paymentPayload, paymentRequirements } = req.body; + + if (!paymentPayload || !paymentRequirements) { + return res.status(400).json({ + error: "Missing paymentPayload or paymentRequirements", + }); + } + + // Hooks will automatically: + // - Validate payment was verified (onBeforeSettle - will abort if not) + // - Check verification timeout (onBeforeSettle) + // - Clean up tracking (onAfterSettle / onSettleFailure) + const response: SettleResponse = await facilitator.settle( + paymentPayload as PaymentPayload, + paymentRequirements as PaymentRequirements, + ); + + res.json(response); + } catch (error) { + console.error("Settle error:", error); + + // Check if this was an abort from hook + if ( + error instanceof Error && + error.message.includes("Settlement aborted:") + ) { + // Return a proper SettleResponse instead of 500 error + return res.json({ + success: false, + errorReason: error.message.replace("Settlement aborted: ", ""), + network: req.body?.paymentPayload?.network || "unknown", + } as SettleResponse); + } + + res.status(500).json({ + error: error instanceof Error ? error.message : "Unknown error", + }); + } +}); + +/** + * GET /supported + * Get supported payment kinds and extensions + */ +app.get("/supported", async (req, res) => { + try { + const response = facilitator.getSupported(); + res.json(response); + } catch (error) { + console.error("Supported error:", error); + res.status(500).json({ + error: error instanceof Error ? error.message : "Unknown error", + }); + } +}); + +// Start the server +app.listen(parseInt(PORT), () => { + console.log(`🚀 Facilitator listening on http://localhost:${PORT}`); + console.log(); +}); diff --git a/examples/typescript/facilitator/batch-settlement/package.json b/examples/typescript/facilitator/batch-settlement/package.json new file mode 100644 index 0000000000..ee95f7a17b --- /dev/null +++ b/examples/typescript/facilitator/batch-settlement/package.json @@ -0,0 +1,35 @@ +{ + "name": "@x402/batch-settlement-facilitator-typescript", + "version": "2.0.0", + "type": "module", + "private": true, + "scripts": { + "start": "tsx index.ts", + "dev": "tsx watch index.ts", + "build": "tsc", + "lint": "eslint .", + "format": "prettier --write .", + "typecheck": "tsc --noEmit" + }, + "dependencies": { + "@x402/core": "workspace:*", + "@x402/evm": "workspace:*", + "dotenv": "^16.4.5", + "express": "^4.19.2", + "viem": "^2.48.11" + }, + "devDependencies": { + "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", + "@types/express": "^4.17.21", + "@typescript-eslint/eslint-plugin": "^8.29.1", + "@typescript-eslint/parser": "^8.29.1", + "eslint": "^9.24.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsdoc": "^50.6.9", + "eslint-plugin-prettier": "^5.2.6", + "prettier": "3.5.2", + "tsx": "^4.21.0", + "typescript": "^5.7.3" + } +} diff --git a/examples/typescript/legacy/fullstack/auth_based_pricing/tsconfig.json b/examples/typescript/facilitator/batch-settlement/tsconfig.json similarity index 63% rename from examples/typescript/legacy/fullstack/auth_based_pricing/tsconfig.json rename to examples/typescript/facilitator/batch-settlement/tsconfig.json index 20dae19206..fc0e5250ed 100644 --- a/examples/typescript/legacy/fullstack/auth_based_pricing/tsconfig.json +++ b/examples/typescript/facilitator/batch-settlement/tsconfig.json @@ -3,17 +3,17 @@ "target": "ES2022", "module": "NodeNext", "moduleResolution": "NodeNext", - "outDir": "./dist", - "rootDir": ".", + "lib": ["ES2022"], "strict": true, "esModuleInterop": true, "skipLibCheck": true, "forceConsistentCasingInFileNames": true, "resolveJsonModule": true, - "experimentalDecorators": true, - "emitDecoratorMetadata": true, - "types": ["node"] + "declaration": true, + "declarationMap": true, + "sourceMap": true, + "outDir": "./dist" }, - "include": ["*.ts", "src/**/*"], + "include": ["*.ts"], "exclude": ["node_modules", "dist"] -} \ No newline at end of file +} diff --git a/examples/typescript/fullstack/miniapp/package.json b/examples/typescript/fullstack/miniapp/package.json index a2f9dc070d..58a7f90166 100644 --- a/examples/typescript/fullstack/miniapp/package.json +++ b/examples/typescript/fullstack/miniapp/package.json @@ -15,7 +15,6 @@ "dependencies": { "@coinbase/onchainkit": "1.1.2", "@farcaster/miniapp-sdk": "0.2.1", - "@tanstack/react-query": "^5", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", "@x402/fetch": "workspace:*", @@ -23,13 +22,13 @@ "next": "^16.0.10", "react": "^19.2.3", "react-dom": "^19.2.3", - "viem": "^2.27.2", + "viem": "^2.48.11", "wagmi": "^2.14.11" }, "devDependencies": { "@eslint/js": "^9.24.0", - "@tailwindcss/postcss": "^4.0.0", "@types/node": "^22.13.4", + "@tailwindcss/postcss": "^4.0.0", "@types/react": "^19", "@types/react-dom": "^19", "@typescript-eslint/eslint-plugin": "^8.29.1", @@ -41,6 +40,6 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tailwindcss": "^4.0.0", - "typescript": "^5" + "typescript": "^5.7.3" } } diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/.env-local b/examples/typescript/fullstack/next-batch-settlement-redis/.env-local new file mode 100644 index 0000000000..a2afa8e790 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/.env-local @@ -0,0 +1,4 @@ +EVM_ADDRESS= +EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY= +FACILITATOR_URL=https://x402.org/facilitator +REDIS_URL= \ No newline at end of file diff --git a/examples/typescript/legacy/clients/chainlink-vrf-nft/.prettierignore b/examples/typescript/fullstack/next-batch-settlement-redis/.prettierignore similarity index 91% rename from examples/typescript/legacy/clients/chainlink-vrf-nft/.prettierignore rename to examples/typescript/fullstack/next-batch-settlement-redis/.prettierignore index 5bd240ba90..406cfdb763 100644 --- a/examples/typescript/legacy/clients/chainlink-vrf-nft/.prettierignore +++ b/examples/typescript/fullstack/next-batch-settlement-redis/.prettierignore @@ -3,6 +3,7 @@ dist/ node_modules/ coverage/ .github/ +.next/ src/client **/**/*.json *.md \ No newline at end of file diff --git a/examples/typescript/legacy/clients/axios/.prettierrc b/examples/typescript/fullstack/next-batch-settlement-redis/.prettierrc similarity index 100% rename from examples/typescript/legacy/clients/axios/.prettierrc rename to examples/typescript/fullstack/next-batch-settlement-redis/.prettierrc diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/README.md b/examples/typescript/fullstack/next-batch-settlement-redis/README.md new file mode 100644 index 0000000000..32ca906ba4 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/README.md @@ -0,0 +1,77 @@ +# Next.js batch-settlement (Redis storage) + +Next.js demo that exposes **`GET /api/weather`** behind `withX402` with the **batch-settlement** scheme. Channel state uses **`RedisChannelStorage`** (`@x402/evm/batch-settlement/server`), backed by the **`redis`** npm client via `lib/redisChannelClient.ts`. + +Parallels: + +- Response shape / `withX402` usage: `examples/typescript/fullstack/next/app/api/weather/route.ts` +- Batch-settlement Express example wiring: `examples/typescript/servers/batch-settlement/index.ts` +- Batch-settlement client: `examples/typescript/clients/batch-settlement` + +## Prerequisites + +- Node.js 20+, pnpm 10 +- Redis reachable from the app (`REDIS_URL`) +- A facilitator URL and receiver address (same variables as other examples) + +## Setup + +From `examples/typescript`: + +```bash +pnpm install && pnpm build +cd fullstack/next-batch-settlement-redis +``` + +Copy `.env-local` to `.env` (or create `.env`) and set: + +| Variable | Required | Description | +|----------|----------|-------------| +| `FACILITATOR_URL` | yes | Facilitator HTTP endpoint | +| `EVM_ADDRESS` | yes | Receiver `0x…` address | +| `REDIS_URL` | yes | e.g. `redis://127.0.0.1:6379` | +| `EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY` | no | Local receiver-authorizer signer (omit to use facilitator) | +| `DEFERRED_WITHDRAW_DELAY_SECONDS` | no | Defaults to `108000` (30 hours) | +| `CRON_SECRET` | no | Bearer token required by cron routes when set | + +```bash +pnpm dev +``` + +Paid endpoint: **`GET /api/weather`**. + +## Cron Jobs + +Run cron jobs locally before deploying: + +```bash +pnpm cron:claim +pnpm cron:settle +pnpm cron:claim-and-settle +``` + +`cron:claim` claims up to 100 vouchers per facilitator transaction. `cron:settle` settles already-claimed funds. `cron:claim-and-settle` does both in one operation and skips settlement when there are no claim transactions. + +The shared cron helpers accept the same `selectClaimChannels` option as the background `ChannelManager` runner, so custom jobs can claim a subset without duplicating claim batching or signing logic: + +```typescript +await runClaimAndSettleCron({ + maxClaimsPerBatch: 100, + selectClaimChannels: channels => + channels.filter(channel => channel.withdrawRequestedAt > 0), +}); +``` + +Vercel deployment uses `vercel.json` to call **`GET /api/cron/claim-and-settle`** once per day at `02:00 UTC`, which is compatible with Vercel Hobby cron limits. Set `CRON_SECRET` in Vercel to require `Authorization: Bearer ` for manual calls. + +With a daily cron, `DEFERRED_WITHDRAW_DELAY_SECONDS` must exceed the daily cadence plus Vercel's hourly scheduling precision and operational safety margin. The default 30-hour delay is intended for this deployment shape. More frequent claim, settle, or refund policies require Vercel Pro cron frequency or an external scheduler. + +## Files + +- `lib/server.ts` — facilitator client, `BatchSettlementEvmScheme` + `RedisChannelStorage` +- `lib/cron.ts` — shared claim, settle, and claim-and-settle cron implementations +- `lib/cronAuth.ts` — optional bearer-token check for cron routes +- `lib/redisChannelClient.ts` — lazy `redis` adapter implementing `RedisChannelStorageClient` +- `app/api/weather/route.ts` — `withX402` + batch-settlement (weather JSON, discovery extension) +- `app/api/cron/*/route.ts` — claim, settle, and claim-and-settle cron routes +- `scripts/cron.ts` — local cron runner diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/app/api/cron/claim-and-settle/route.ts b/examples/typescript/fullstack/next-batch-settlement-redis/app/api/cron/claim-and-settle/route.ts new file mode 100644 index 0000000000..592dcb1d44 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/app/api/cron/claim-and-settle/route.ts @@ -0,0 +1,20 @@ +import { NextRequest, NextResponse } from "next/server"; + +import { authorizeCronRequest } from "../../../../lib/cronAuth"; +import { runClaimAndSettleCron } from "../../../../lib/cron"; + +/** + * Runs the scheduled batch-settlement claim-and-settle job. + * + * @param request - Incoming cron request. + * @returns JSON claim-and-settle summary. + */ +export async function GET(request: NextRequest) { + const unauthorized = authorizeCronRequest(request); + if (unauthorized) { + return unauthorized; + } + + const summary = await runClaimAndSettleCron({ maxClaimsPerBatch: 100 }); + return NextResponse.json(summary); +} diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/app/api/cron/claim/route.ts b/examples/typescript/fullstack/next-batch-settlement-redis/app/api/cron/claim/route.ts new file mode 100644 index 0000000000..c6cb6ccc19 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/app/api/cron/claim/route.ts @@ -0,0 +1,20 @@ +import { NextRequest, NextResponse } from "next/server"; + +import { authorizeCronRequest } from "../../../../lib/cronAuth"; +import { runClaimCron } from "../../../../lib/cron"; + +/** + * Runs the scheduled batch-settlement claim job. + * + * @param request - Incoming cron request. + * @returns JSON claim summary. + */ +export async function GET(request: NextRequest) { + const unauthorized = authorizeCronRequest(request); + if (unauthorized) { + return unauthorized; + } + + const summary = await runClaimCron({ maxClaimsPerBatch: 100 }); + return NextResponse.json(summary); +} diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/app/api/cron/settle/route.ts b/examples/typescript/fullstack/next-batch-settlement-redis/app/api/cron/settle/route.ts new file mode 100644 index 0000000000..f6ac12f4b6 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/app/api/cron/settle/route.ts @@ -0,0 +1,20 @@ +import { NextRequest, NextResponse } from "next/server"; + +import { authorizeCronRequest } from "../../../../lib/cronAuth"; +import { runSettleCron } from "../../../../lib/cron"; + +/** + * Runs the scheduled batch-settlement settle job. + * + * @param request - Incoming cron request. + * @returns JSON settle summary. + */ +export async function GET(request: NextRequest) { + const unauthorized = authorizeCronRequest(request); + if (unauthorized) { + return unauthorized; + } + + const summary = await runSettleCron(); + return NextResponse.json(summary); +} diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/app/api/weather/route.ts b/examples/typescript/fullstack/next-batch-settlement-redis/app/api/weather/route.ts new file mode 100644 index 0000000000..1824ef7255 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/app/api/weather/route.ts @@ -0,0 +1,57 @@ +import { NextRequest, NextResponse } from "next/server"; +import { withX402 } from "@x402/next"; +import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; + +import { evmAddress, NETWORK, server } from "../../../lib/server"; + +const price = "$0.001"; + +/** + * Weather API handler for the batch-settlement Next example (API-only; no paywall HTML). + * + * @param _ - Incoming Next.js request + * @returns JSON response with weather data + */ +const handler = async (_: NextRequest) => { + return NextResponse.json( + { + report: { + weather: "sunny", + temperature: 72, + }, + }, + { status: 200 }, + ); +}; + +/** + * Protected weather API using `withX402` and batch-settlement (mirrors `fullstack/next` weather shape). + */ +export const GET = withX402( + handler, + { + accepts: [ + { + scheme: "batch-settlement", + price, + network: NETWORK, + payTo: evmAddress, + }, + ], + description: "Access to weather API", + mimeType: "application/json", + extensions: { + ...declareDiscoveryExtension({ + output: { + example: { + report: { + weather: "sunny", + temperature: 72, + }, + }, + }, + }), + }, + }, + server, +); diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/app/layout.tsx b/examples/typescript/fullstack/next-batch-settlement-redis/app/layout.tsx new file mode 100644 index 0000000000..297cd55346 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/app/layout.tsx @@ -0,0 +1,20 @@ +import type { Metadata } from "next"; + +export const metadata: Metadata = { + title: "x402 batch-settlement (Next.js API)", +}; + +/** + * Minimal root layout — this example is intended for `GET /api/weather` only. + */ +export default function RootLayout({ + children, +}: Readonly<{ + children: React.ReactNode; +}>) { + return ( + + {children} + + ); +} diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/app/page.tsx b/examples/typescript/fullstack/next-batch-settlement-redis/app/page.tsx new file mode 100644 index 0000000000..ce39c96c06 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/app/page.tsx @@ -0,0 +1,6 @@ +/** + * Placeholder root page. Use `GET /api/weather` with the batch-settlement client example. + */ +export default function Home() { + return null; +} diff --git a/examples/typescript/legacy/fullstack/next/eslint.config.js b/examples/typescript/fullstack/next-batch-settlement-redis/eslint.config.js similarity index 100% rename from examples/typescript/legacy/fullstack/next/eslint.config.js rename to examples/typescript/fullstack/next-batch-settlement-redis/eslint.config.js diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/lib/cron.ts b/examples/typescript/fullstack/next-batch-settlement-redis/lib/cron.ts new file mode 100644 index 0000000000..98ab163535 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/lib/cron.ts @@ -0,0 +1,87 @@ +import type { AutoSettlementContext, Channel } from "@x402/evm/batch-settlement/server"; + +import { channelManager } from "./server"; + +export interface ClaimCronOptions { + maxClaimsPerBatch?: number; + idleSecs?: number; + selectClaimChannels?: ( + channels: Channel[], + context: AutoSettlementContext, + ) => Channel[] | Promise; +} + +export type ClaimAndSettleCronOptions = ClaimCronOptions; + +export interface ClaimCronSummary { + claimBatches: number; + vouchers: number; + claimTransactions: string[]; +} + +export interface SettleCronSummary { + settleTransaction: string; +} + +export interface ClaimAndSettleCronSummary { + claimBatches: number; + vouchers: number; + claimTransactions: string[]; + settleTransaction?: string; +} + +/** + * Claims pending vouchers in cron-friendly batches. + * + * @param opts - Optional cron execution settings. + * @param opts.maxClaimsPerBatch - Max vouchers per facilitator claim transaction. + * @returns Compact claim summary. + */ +export async function runClaimCron(opts?: ClaimCronOptions): Promise { + const claims = await channelManager.claim({ + ...opts, + maxClaimsPerBatch: opts?.maxClaimsPerBatch ?? 100, + }); + + return { + claimBatches: claims.length, + vouchers: claims.reduce((total, claim) => total + claim.vouchers, 0), + claimTransactions: claims.map(claim => claim.transaction), + }; +} + +/** + * Settles already-claimed funds to the receiver. + * + * @returns Compact settle summary. + */ +export async function runSettleCron(): Promise { + const settle = await channelManager.settle(); + + return { + settleTransaction: settle.transaction, + }; +} + +/** + * Claims pending vouchers and settles them in one cron-friendly operation. + * + * @param opts - Optional cron execution settings. + * @param opts.maxClaimsPerBatch - Max vouchers per facilitator claim transaction. + * @returns Compact claim-and-settle summary. + */ +export async function runClaimAndSettleCron( + opts?: ClaimAndSettleCronOptions, +): Promise { + const { claims, settle } = await channelManager.claimAndSettle({ + ...opts, + maxClaimsPerBatch: opts?.maxClaimsPerBatch ?? 100, + }); + + return { + claimBatches: claims.length, + vouchers: claims.reduce((total, claim) => total + claim.vouchers, 0), + claimTransactions: claims.map(claim => claim.transaction), + ...(settle ? { settleTransaction: settle.transaction } : {}), + }; +} diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/lib/cronAuth.ts b/examples/typescript/fullstack/next-batch-settlement-redis/lib/cronAuth.ts new file mode 100644 index 0000000000..e5f452044e --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/lib/cronAuth.ts @@ -0,0 +1,22 @@ +import { NextRequest, NextResponse } from "next/server"; + +/** + * Checks the optional bearer secret used by cron endpoints. + * + * @param request - Incoming cron request. + * @returns Unauthorized response when the configured secret is missing or invalid. + */ +export function authorizeCronRequest(request: NextRequest): NextResponse | undefined { + const cronSecret = process.env.CRON_SECRET; + + if (!cronSecret) { + return undefined; + } + + const authorization = request.headers.get("authorization"); + if (authorization !== `Bearer ${cronSecret}`) { + return NextResponse.json({ error: "Unauthorized" }, { status: 401 }); + } + + return undefined; +} diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/lib/redisChannelClient.ts b/examples/typescript/fullstack/next-batch-settlement-redis/lib/redisChannelClient.ts new file mode 100644 index 0000000000..fc5047be46 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/lib/redisChannelClient.ts @@ -0,0 +1,96 @@ +import type { + RedisChannelStorageClient, + RedisEvalOptions, + RedisScanOptions, + RedisSetOptions, +} from "@x402/evm/batch-settlement/server"; +import { createClient } from "redis"; + +export type LazyRedisChannelStorageClient = RedisChannelStorageClient & { + /** Close the TCP connection */ + disconnect: () => Promise; +}; + +/** + * Wraps a lazily connected node-redis client as {@link RedisChannelStorageClient}. + * + * @param url - Redis connection URL (same shape as `REDIS_URL` / `redis://…`). + * @returns An adapter compatible with Redis-backed batch-settlement channel storage. + */ +export function createLazyRedisChannelStorageClient(url: string): LazyRedisChannelStorageClient { + const connect = async () => { + const client = createClient({ url }); + client.on("error", err => { + console.error("Redis client error:", err); + }); + await client.connect(); + return client; + }; + + let connecting: Promise>> | undefined; + + const ensureClient = () => { + if (!connecting) connecting = connect(); + return connecting; + }; + + const normalizeRedisString = (value: string | Buffer | null): string | null => { + if (value == null) return null; + return typeof value === "string" ? value : value.toString("utf8"); + }; + + const normalizeScanKey = (key: string | Buffer): string => + typeof key === "string" ? key : key.toString("utf8"); + + return { + disconnect: async () => { + if (!connecting) return; + try { + const c = await connecting; + if (c.isOpen) await c.quit(); + } catch { + // connect or quit failed — still drop the handle so the process can exit + } finally { + connecting = undefined; + } + }, + get: key => + ensureClient() + .then(c => c.get(key)) + .then(normalizeRedisString), + set: (key, value, opts?: RedisSetOptions) => + ensureClient() + .then(c => { + if (opts?.NX) { + return c.set(key, value, { + NX: true, + ...(opts.PX !== undefined ? { PX: opts.PX } : {}), + }); + } + if (opts?.PX !== undefined) { + return c.set(key, value, { PX: opts.PX }); + } + return c.set(key, value); + }) + .then(normalizeRedisString), + del: key => + ensureClient() + .then(c => c.del(key)) + .then(n => Number(n)), + eval: (script, options: RedisEvalOptions) => ensureClient().then(c => c.eval(script, options)), + scanIterator(options: RedisScanOptions): AsyncIterable { + return { + async *[Symbol.asyncIterator]() { + const c = await ensureClient(); + for await (const chunk of c.scanIterator(options)) { + if (Array.isArray(chunk)) { + yield chunk.map(normalizeScanKey); + continue; + } + yield normalizeScanKey(chunk); + } + }, + }; + }, + }; +} diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/lib/server.ts b/examples/typescript/fullstack/next-batch-settlement-redis/lib/server.ts new file mode 100644 index 0000000000..2e8ce234cc --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/lib/server.ts @@ -0,0 +1,56 @@ +import { HTTPFacilitatorClient, x402ResourceServer } from "@x402/core/server"; +import { BatchSettlementEvmScheme, RedisChannelStorage } from "@x402/evm/batch-settlement/server"; +import { privateKeyToAccount } from "viem/accounts"; + +import { createLazyRedisChannelStorageClient } from "./redisChannelClient"; + +export const NETWORK = "eip155:84532" as const; + +const facilitatorUrl = process.env.FACILITATOR_URL; +const evmAddress = process.env.EVM_ADDRESS as `0x${string}`; +const redisUrl = process.env.REDIS_URL; + +const receiverAuthorizerPrivateKey = process.env.EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY as + | `0x${string}` + | undefined; + +const withdrawDelay = Number(process.env.DEFERRED_WITHDRAW_DELAY_SECONDS ?? "108000"); + +if (!facilitatorUrl) { + console.error("Missing required FACILITATOR_URL environment variable"); + process.exit(1); +} + +if (!evmAddress || !/^0x[0-9a-fA-F]{40}$/.test(evmAddress)) { + console.error("Missing or invalid EVM_ADDRESS (checksummed 20-byte hex, 0x-prefixed)"); + process.exit(1); +} + +if (!redisUrl) { + console.error("Missing required REDIS_URL environment variable"); + process.exit(1); +} + +const receiverAuthorizerSigner = receiverAuthorizerPrivateKey + ? privateKeyToAccount(receiverAuthorizerPrivateKey) + : undefined; + +export const facilitatorClient = new HTTPFacilitatorClient({ url: facilitatorUrl }); + +const redisAdapter = createLazyRedisChannelStorageClient(redisUrl); + +export const batchedScheme = new BatchSettlementEvmScheme(evmAddress, { + ...(receiverAuthorizerSigner ? { receiverAuthorizerSigner } : {}), + withdrawDelay, + storage: new RedisChannelStorage({ client: redisAdapter }), +}); + +export const server = new x402ResourceServer(facilitatorClient).register(NETWORK, batchedScheme); +export const channelManager = batchedScheme.createChannelManager(facilitatorClient, NETWORK); + +/** Release the Redis connection (required for CLI cron scripts to exit). */ +export async function disconnectRedisChannelStorage(): Promise { + await redisAdapter.disconnect(); +} + +export { evmAddress }; diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/next-env.d.ts b/examples/typescript/fullstack/next-batch-settlement-redis/next-env.d.ts new file mode 100644 index 0000000000..9edff1c7ca --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/next-env.d.ts @@ -0,0 +1,6 @@ +/// +/// +import "./.next/types/routes.d.ts"; + +// NOTE: This file should not be edited +// see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/next.config.ts b/examples/typescript/fullstack/next-batch-settlement-redis/next.config.ts new file mode 100644 index 0000000000..cb651cdc00 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/next.config.ts @@ -0,0 +1,5 @@ +import type { NextConfig } from "next"; + +const nextConfig: NextConfig = {}; + +export default nextConfig; diff --git a/examples/typescript/legacy/fullstack/next/package.json b/examples/typescript/fullstack/next-batch-settlement-redis/package.json similarity index 57% rename from examples/typescript/legacy/fullstack/next/package.json rename to examples/typescript/fullstack/next-batch-settlement-redis/package.json index 1f3b8f74c1..316818bbc4 100644 --- a/examples/typescript/legacy/fullstack/next/package.json +++ b/examples/typescript/fullstack/next-batch-settlement-redis/package.json @@ -1,5 +1,5 @@ { - "name": "next-example", + "name": "@x402/next-batch-settlement-redis-example", "version": "0.1.0", "private": true, "type": "module", @@ -7,35 +7,39 @@ "dev": "next dev", "build": "next build", "start": "next start", + "cron:claim": "tsx scripts/cron.ts claim", + "cron:settle": "tsx scripts/cron.ts settle", + "cron:claim-and-settle": "tsx scripts/cron.ts claim-and-settle", "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", "lint": "eslint . --ext .ts --fix", "lint:check": "eslint . --ext .ts" }, "dependencies": { - "@heroicons/react": "^2.2.0", - "next": "16.0.10", - "react": "19.2.3", - "react-dom": "19.2.3", - "viem": "^2.21.26", - "x402-next": "workspace:*" + "@x402/core": "workspace:*", + "@x402/evm": "workspace:*", + "@x402/extensions": "workspace:*", + "@x402/next": "workspace:*", + "next": "^16.0.10", + "react": "^19.2.3", + "react-dom": "^19.2.3", + "redis": "^5.12.1", + "viem": "^2.48.11" }, "devDependencies": { - "@svgr/webpack": "^8.1.0", - "@types/node": "^20", + "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/react": "^19", "@types/react-dom": "^19", - "@eslint/js": "^9.24.0", - "eslint": "^9.24.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", + "eslint": "^9.24.0", + "eslint-config-next": "16.0.6", "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsdoc": "^50.6.9", + "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "eslint-config-next": "16.0.7", - "postcss": "^8", - "tailwindcss": "^3.4.1", - "typescript": "^5" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/public/favicon.ico b/examples/typescript/fullstack/next-batch-settlement-redis/public/favicon.ico new file mode 100644 index 0000000000..ce91c36638 Binary files /dev/null and b/examples/typescript/fullstack/next-batch-settlement-redis/public/favicon.ico differ diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/public/site.webmanifest b/examples/typescript/fullstack/next-batch-settlement-redis/public/site.webmanifest new file mode 100644 index 0000000000..ee6a32d92d --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/public/site.webmanifest @@ -0,0 +1,19 @@ +{ + "name": "x402 Next.js Demo", + "short_name": "x402 Demo", + "icons": [ + { + "src": "/x402-icon-black.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/x402-icon-black.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#000000", + "background_color": "#ffffff", + "display": "standalone" +} \ No newline at end of file diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/public/x402-icon-black.png b/examples/typescript/fullstack/next-batch-settlement-redis/public/x402-icon-black.png new file mode 100644 index 0000000000..ce91c36638 Binary files /dev/null and b/examples/typescript/fullstack/next-batch-settlement-redis/public/x402-icon-black.png differ diff --git a/examples/typescript/legacy/fullstack/next/public/x402-icon-blue.png b/examples/typescript/fullstack/next-batch-settlement-redis/public/x402-icon-blue.png similarity index 100% rename from examples/typescript/legacy/fullstack/next/public/x402-icon-blue.png rename to examples/typescript/fullstack/next-batch-settlement-redis/public/x402-icon-blue.png diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/public/x402-logo-dark.png b/examples/typescript/fullstack/next-batch-settlement-redis/public/x402-logo-dark.png new file mode 100644 index 0000000000..f45c3c9522 Binary files /dev/null and b/examples/typescript/fullstack/next-batch-settlement-redis/public/x402-logo-dark.png differ diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/scripts/cron.ts b/examples/typescript/fullstack/next-batch-settlement-redis/scripts/cron.ts new file mode 100644 index 0000000000..63db3dbf12 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/scripts/cron.ts @@ -0,0 +1,42 @@ +import { existsSync, readFileSync } from "node:fs"; +import { dirname, resolve } from "node:path"; +import { fileURLToPath } from "node:url"; + +const packageDir = resolve(dirname(fileURLToPath(import.meta.url)), ".."); +for (const file of [".env.local", ".env"]) { + const path = resolve(packageDir, file); + if (!existsSync(path)) continue; + + for (const line of readFileSync(path, "utf8").split("\n")) { + const match = line.match(/^\s*([\w.-]+)\s*=\s*(.*)?\s*$/); + if (!match || match[1].startsWith("#")) continue; + + const value = (match[2] ?? "").replace(/^['"]|['"]$/g, ""); + process.env[match[1]] ??= value; + } +} + +const command = process.argv[2]; +const [{ runClaimAndSettleCron, runClaimCron, runSettleCron }, { disconnectRedisChannelStorage }] = + await Promise.all([import("../lib/cron"), import("../lib/server")]); + +let summary; +switch (command) { + case "claim": + summary = await runClaimCron({ maxClaimsPerBatch: 100 }); + break; + case "settle": + summary = await runSettleCron(); + break; + case "claim-and-settle": + summary = await runClaimAndSettleCron({ maxClaimsPerBatch: 100 }); + break; +} + +if (!summary) { + console.error("Usage: tsx scripts/cron.ts "); + process.exit(1); +} + +console.log(JSON.stringify(summary, null, 2)); +await disconnectRedisChannelStorage(); diff --git a/examples/typescript/legacy/fullstack/next/tsconfig.json b/examples/typescript/fullstack/next-batch-settlement-redis/tsconfig.json similarity index 96% rename from examples/typescript/legacy/fullstack/next/tsconfig.json rename to examples/typescript/fullstack/next-batch-settlement-redis/tsconfig.json index 6a3c51ac3f..2ee3a66608 100644 --- a/examples/typescript/legacy/fullstack/next/tsconfig.json +++ b/examples/typescript/fullstack/next-batch-settlement-redis/tsconfig.json @@ -23,7 +23,7 @@ } }, "include": [ - "types/video.d.ts", + "types/**/*.ts", "next-env.d.ts", "**/*.ts", "**/*.tsx", diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/turbo.json b/examples/typescript/fullstack/next-batch-settlement-redis/turbo.json new file mode 100644 index 0000000000..572dd61f42 --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/turbo.json @@ -0,0 +1,9 @@ +{ + "$schema": "https://turborepo.org/schema.json", + "extends": ["//"], + "tasks": { + "build": { + "outputs": [".next/**", "!.next/cache/**"] + } + } +} diff --git a/examples/typescript/fullstack/next-batch-settlement-redis/vercel.json b/examples/typescript/fullstack/next-batch-settlement-redis/vercel.json new file mode 100644 index 0000000000..dbbd41c10b --- /dev/null +++ b/examples/typescript/fullstack/next-batch-settlement-redis/vercel.json @@ -0,0 +1,8 @@ +{ + "crons": [ + { + "path": "/api/cron/claim-and-settle", + "schedule": "0 2 * * *" + } + ] +} diff --git a/examples/typescript/fullstack/next/package.json b/examples/typescript/fullstack/next/package.json index d05454f0b4..19c691c316 100644 --- a/examples/typescript/fullstack/next/package.json +++ b/examples/typescript/fullstack/next/package.json @@ -13,7 +13,6 @@ "lint:check": "eslint . --ext .ts" }, "dependencies": { - "@heroicons/react": "^2.2.0", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", "@x402/svm": "workspace:*", @@ -26,8 +25,8 @@ }, "devDependencies": { "@eslint/js": "^9.24.0", - "@tailwindcss/postcss": "^4.0.0", "@types/node": "^22.13.4", + "@tailwindcss/postcss": "^4.0.0", "@types/react": "^19", "@types/react-dom": "^19", "@typescript-eslint/eslint-plugin": "^8.29.1", @@ -39,6 +38,6 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tailwindcss": "^4.0.0", - "typescript": "^5" + "typescript": "^5.7.3" } } diff --git a/examples/typescript/legacy/agent/.env-local b/examples/typescript/legacy/agent/.env-local deleted file mode 100644 index ca6bdcdd40..0000000000 --- a/examples/typescript/legacy/agent/.env-local +++ /dev/null @@ -1,2 +0,0 @@ -PRIVATE_KEY= -RESOURCE_SERVER_URL= \ No newline at end of file diff --git a/examples/typescript/legacy/agent/README.md b/examples/typescript/legacy/agent/README.md deleted file mode 100644 index afa3b90f48..0000000000 --- a/examples/typescript/legacy/agent/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# Demo of paying for Anthropic tokens via a proxy - -This example demonstrates how to use x402 to pay for Anthropic API calls using a proxy server. The setup involves configuring both a Go proxy server and a TypeScript agent. - -## Prerequisites - -- Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) -- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- Go (install via `brew install go` on macOS or [golang.org/dl](https://golang.org/dl) for other platforms) -- A valid Ethereum private key for making payments (must have Base Sepolia USDC) -- An Anthropic API key - -## Setup - -1. Install and build all packages from the typescript examples root: -```bash -cd ../../ -pnpm install -pnpm build -cd clients/agent -``` - -2. Configure your environment: - - Create a `.env` file in the agent directory - - Add your private key (must be prefixed with `0x`): - ``` - PRIVATE_KEY=0x - ``` - - Add your resource server URL (default: http://localhost:4021): - ``` - RESOURCE_SERVER_URL=http://localhost:4021 - ``` - -### 1. Configure and Start the Proxy Server - -1. Navigate to the proxy directory: - ```bash - cd go/bin - ``` - -2. Create an `anthropic_config.json` file with the following configuration: - ```json - { - "targetURL": "https://api.anthropic.com", - "amount": 0.01, - "payTo": "address to pay to", - "headers": { - "x-api-key": "", - "anthropic-version": "2023-06-01", - "content-type": "application/json" - } - } - ``` - -3. Start the proxy server: - ```bash - go run proxy_demo.go anthropic_config.json - ``` - -### 2. Run the Agent - -1. Navigate back to the agent directory: - ```bash - cd ../../examples/typescript/clients/agent - ``` - -2. Run the agent: - ```bash - pnpm agent - ``` - -## Troubleshooting - -### Common Issues - -1. **Go Command Not Found** - - Ensure Go is properly installed and in your PATH - - Verify installation with `go version` - -2. **Module Not Found** - - Make sure you've built the x402 package before running the agent - - Run `pnpm install` and `pnpm build` in the x402 package directory - -3. **Invalid Private Key** - - Ensure your private key is prefixed with `0x` - - Verify the key has the correct format and length - -4. **Proxy Connection Issues** - - Verify the proxy server is running - - Check that the `anthropic_config.json` has the correct configuration - - Ensure your Anthropic API key is valid - -## Security Notes - -- Never commit your private keys or API keys to version control -- Always use testnet funds (Base Sepolia) for development -- Keep your `.env` file secure and never share it \ No newline at end of file diff --git a/examples/typescript/legacy/agent/index.ts b/examples/typescript/legacy/agent/index.ts deleted file mode 100644 index 66edf99d4a..0000000000 --- a/examples/typescript/legacy/agent/index.ts +++ /dev/null @@ -1,30 +0,0 @@ -import Anthropic from "@anthropic-ai/sdk"; -import { config } from "dotenv"; -import { Hex } from "viem"; -import { privateKeyToAccount } from "viem/accounts"; -import { wrapFetchWithPayment } from "x402-fetch"; - -config(); - -const privateKey = process.env.PRIVATE_KEY as Hex; -const baseURL = process.env.RESOURCE_SERVER_URL as string; - -if (!baseURL || !privateKey) { - console.error("Missing required environment variables"); - process.exit(1); -} - -const account = privateKeyToAccount(privateKey); - -const anthropic = new Anthropic({ - baseURL, - apiKey: "not needed", - fetch: wrapFetchWithPayment(fetch, account), -}); - -const msg = await anthropic.messages.create({ - model: "claude-3-7-sonnet-20250219", - max_tokens: 1024, - messages: [{ role: "user", content: "Hello, Claude do you know what x402 is?" }], -}); -console.log(msg); diff --git a/examples/typescript/legacy/agent/package.json b/examples/typescript/legacy/agent/package.json deleted file mode 100644 index b029f380cd..0000000000 --- a/examples/typescript/legacy/agent/package.json +++ /dev/null @@ -1,45 +0,0 @@ -{ - "name": "agent-client-example", - "version": "0.1.0", - "scripts": { - "dev": "tsx index.ts", - "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", - "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", - "lint": "eslint . --ext .ts --fix", - "lint:check": "eslint . --ext .ts" - }, - "keywords": [], - "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", - "description": "x402 Payment Protocol", - "devDependencies": { - "@eslint/js": "^9.24.0", - "@types/node": "^22.13.4", - "@typescript-eslint/eslint-plugin": "^8.29.1", - "@typescript-eslint/parser": "^8.29.1", - "eslint": "^9.24.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", - "prettier": "3.5.2", - "tsx": "^4.19.2", - "typescript": "^5.7.3" - }, - "dependencies": { - "@anthropic-ai/sdk": "^0.39.0", - "@coinbase/agentkit": "^0.5.0", - "@coinbase/agentkit-langchain": "^0.3.0", - "@langchain/core": "^0.3.43", - "@langchain/langgraph": "^0.2.62", - "@langchain/openai": "^0.5.2", - "dotenv": "^16.4.7", - "viem": "^2.26.2", - "x402-fetch": "workspace:*", - "zod": "^3.24.2" - }, - "type": "module", - "files": [ - "dist" - ] -} diff --git a/examples/typescript/legacy/agent/tsconfig.json b/examples/typescript/legacy/agent/tsconfig.json deleted file mode 100644 index 1bdf94ca8d..0000000000 --- a/examples/typescript/legacy/agent/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ES2022", - "moduleResolution": "bundler", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true, - "strict": true, - "resolveJsonModule": true, - "baseUrl": ".", - "types": ["node"] - }, - "include": ["index.ts"] -} diff --git a/examples/typescript/legacy/clients/axios/.env-local b/examples/typescript/legacy/clients/axios/.env-local deleted file mode 100644 index 3d2e1855d1..0000000000 --- a/examples/typescript/legacy/clients/axios/.env-local +++ /dev/null @@ -1,3 +0,0 @@ -RESOURCE_SERVER_URL=http://localhost:4021 -ENDPOINT_PATH=/weather -PRIVATE_KEY= diff --git a/examples/typescript/legacy/clients/axios/README.md b/examples/typescript/legacy/clients/axios/README.md deleted file mode 100644 index 4bb308ba95..0000000000 --- a/examples/typescript/legacy/clients/axios/README.md +++ /dev/null @@ -1,80 +0,0 @@ -# x402-axios Example Client - -This is an example client that demonstrates how to use the `x402-axios` package to make HTTP requests to endpoints protected by the x402 payment protocol. - -## Prerequisites - -- Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) -- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- A running x402 server (you can use the example express server at `examples/typescript/servers/express`) -- A valid Ethereum private key for making payments - -## Setup - -1. Install and build all packages from the typescript examples root: -```bash -cd ../../ -pnpm install -pnpm build -cd clients/axios -``` - -2. Copy `.env-local` to `.env` and add your Ethereum private key (remember it should have USDC on Base Sepolia, which you can provision using the [CDP Faucet](https://portal.cdp.coinbase.com/products/faucet)): -```bash -cp .env-local .env -``` - -3. Start the example client (remember you need to be running a server locally or point at an endpoint): -```bash -pnpm dev -``` - -## How It Works - -The example demonstrates how to: -1. Create a wallet client using viem -2. Create an Axios instance with x402 payment handling -3. Make a request to a paid endpoint -4. Handle the response or any errors - -## Example Code - -```typescript -import { config } from "dotenv"; -import { createWalletClient, http, publicActions } from "viem"; -import { privateKeyToAccount } from "viem/accounts"; -import { withPaymentInterceptor } from "x402-axios"; -import axios from "axios"; -import { baseSepolia } from "viem/chains"; - -config(); - -const { RESOURCE_SERVER_URL, PRIVATE_KEY, ENDPOINT_PATH } = process.env; - -// Create wallet client -const account = privateKeyToAccount(PRIVATE_KEY as "0x${string}"); -const client = createWalletClient({ - account, - transport: http(), - chain: baseSepolia, -}).extend(publicActions); - -// Create Axios instance with payment handling -const api = withPaymentInterceptor( - axios.create({ - baseURL: RESOURCE_SERVER_URL, - }), - client -); - -// Make request to paid endpoint -api - .get(ENDPOINT_PATH) - .then(response => { - console.log(response.headers); - console.log(response.data); - }) - .catch(error => { - console.error(error.response?.data?.error); - }); -``` diff --git a/examples/typescript/legacy/clients/axios/eslint.config.js b/examples/typescript/legacy/clients/axios/eslint.config.js deleted file mode 100644 index ca28b5c47f..0000000000 --- a/examples/typescript/legacy/clients/axios/eslint.config.js +++ /dev/null @@ -1,72 +0,0 @@ -import js from "@eslint/js"; -import ts from "@typescript-eslint/eslint-plugin"; -import tsParser from "@typescript-eslint/parser"; -import prettier from "eslint-plugin-prettier"; -import jsdoc from "eslint-plugin-jsdoc"; -import importPlugin from "eslint-plugin-import"; - -export default [ - { - ignores: ["dist/**", "node_modules/**"], - }, - { - files: ["**/*.ts"], - languageOptions: { - parser: tsParser, - sourceType: "module", - ecmaVersion: 2020, - globals: { - process: "readonly", - __dirname: "readonly", - module: "readonly", - require: "readonly", - Buffer: "readonly", - exports: "readonly", - setTimeout: "readonly", - clearTimeout: "readonly", - setInterval: "readonly", - clearInterval: "readonly", - }, - }, - plugins: { - "@typescript-eslint": ts, - prettier: prettier, - jsdoc: jsdoc, - import: importPlugin, - }, - rules: { - ...ts.configs.recommended.rules, - "import/first": "error", - "prettier/prettier": "error", - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_$" }], - "jsdoc/tag-lines": ["error", "any", { startLines: 1 }], - "jsdoc/check-alignment": "error", - "jsdoc/no-undefined-types": "off", - "jsdoc/check-param-names": "error", - "jsdoc/check-tag-names": "error", - "jsdoc/check-types": "error", - "jsdoc/implements-on-classes": "error", - "jsdoc/require-description": "error", - "jsdoc/require-jsdoc": [ - "error", - { - require: { - FunctionDeclaration: true, - MethodDefinition: true, - ClassDeclaration: true, - ArrowFunctionExpression: false, - FunctionExpression: false, - }, - }, - ], - "jsdoc/require-param": "error", - "jsdoc/require-param-description": "error", - "jsdoc/require-param-type": "off", - "jsdoc/require-returns": "error", - "jsdoc/require-returns-description": "error", - "jsdoc/require-returns-type": "off", - "jsdoc/require-hyphen-before-param-description": ["error", "always"], - }, - }, -]; diff --git a/examples/typescript/legacy/clients/axios/index.ts b/examples/typescript/legacy/clients/axios/index.ts deleted file mode 100644 index 2f03b5889e..0000000000 --- a/examples/typescript/legacy/clients/axios/index.ts +++ /dev/null @@ -1,46 +0,0 @@ -import axios from "axios"; -import { config } from "dotenv"; -import { withPaymentInterceptor, decodeXPaymentResponse, createSigner, type Hex } from "x402-axios"; - -config(); - -const privateKey = process.env.PRIVATE_KEY as Hex | string; -const baseURL = process.env.RESOURCE_SERVER_URL as string; // e.g. https://example.com -const endpointPath = process.env.ENDPOINT_PATH as string; // e.g. /weather - -if (!baseURL || !privateKey || !endpointPath) { - console.error("Missing required environment variables"); - process.exit(1); -} - -/** - * This example shows how to use the x402-axios package to make a request to a resource server that requires a payment. - * - * To run this example, you need to set the following environment variables: - * - PRIVATE_KEY: The private key of the signer - * - RESOURCE_SERVER_URL: The URL of the resource server - * - ENDPOINT_PATH: The path of the endpoint to call on the resource server - * - */ -async function main(): Promise { - // const signer = await createSigner("solana-devnet", privateKey); // uncomment for solana - const signer = await createSigner("base-sepolia", privateKey); - - const api = withPaymentInterceptor( - axios.create({ - baseURL, - }), - signer, - ); - - const response = await api.get(endpointPath); - console.log(response.data); - - const paymentResponseHeader = response.headers["x-payment-response"]; - if (paymentResponseHeader) { - const paymentResponse = decodeXPaymentResponse(paymentResponseHeader); - console.log(paymentResponse); - } -} - -main(); diff --git a/examples/typescript/legacy/clients/axios/multi-network-signer.ts b/examples/typescript/legacy/clients/axios/multi-network-signer.ts deleted file mode 100644 index b8daa14b5b..0000000000 --- a/examples/typescript/legacy/clients/axios/multi-network-signer.ts +++ /dev/null @@ -1,51 +0,0 @@ -import axios from "axios"; -import { config } from "dotenv"; -import { - withPaymentInterceptor, - decodeXPaymentResponse, - createSigner, - type Hex, - MultiNetworkSigner, -} from "x402-axios"; - -config(); - -const evmPrivateKey = process.env.EVM_PRIVATE_KEY as Hex; -const svmPrivateKey = process.env.SVM_PRIVATE_KEY as string; -const baseURL = process.env.RESOURCE_SERVER_URL as string; // e.g. https://example.com -const endpointPath = process.env.ENDPOINT_PATH as string; // e.g. /weather - -if (!baseURL || !evmPrivateKey || !svmPrivateKey || !endpointPath) { - console.error("Missing required environment variables"); - process.exit(1); -} - -/** - * This example shows how to use the x402-axios package to make a request to a resource server that requires a payment. - * - * To run this example, you need to set the following environment variables: - * - PRIVATE_KEY: The private key of the signer - * - RESOURCE_SERVER_URL: The URL of the resource server - * - ENDPOINT_PATH: The path of the endpoint to call on the resource server - * - */ -async function main(): Promise { - const evmSigner = await createSigner("base-sepolia", evmPrivateKey); - const svmSigner = await createSigner("solana-devnet", svmPrivateKey); - const signer = { evm: evmSigner, svm: svmSigner } as MultiNetworkSigner; - - const api = withPaymentInterceptor( - axios.create({ - baseURL, - }), - signer, - ); - - const response = await api.get(endpointPath); - console.log(response.data); - - const paymentResponse = decodeXPaymentResponse(response.headers["x-payment-response"]); - console.log(paymentResponse); -} - -main(); diff --git a/examples/typescript/legacy/clients/axios/package.json b/examples/typescript/legacy/clients/axios/package.json deleted file mode 100644 index 8d2f89bdb8..0000000000 --- a/examples/typescript/legacy/clients/axios/package.json +++ /dev/null @@ -1,30 +0,0 @@ -{ - "name": "axios-client-example", - "private": true, - "type": "module", - "scripts": { - "dev": "tsx index.ts", - "dev:multi-network-signer": "tsx multi-network-signer.ts", - "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", - "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", - "lint": "eslint . --ext .ts --fix", - "lint:check": "eslint . --ext .ts" - }, - "dependencies": { - "axios": "^1.7.9", - "dotenv": "^16.5.0", - "x402-axios": "workspace:*" - }, - "devDependencies": { - "@eslint/js": "^9.24.0", - "@typescript-eslint/eslint-plugin": "^8.29.1", - "@typescript-eslint/parser": "^8.29.1", - "eslint": "^9.24.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", - "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" - } -} diff --git a/examples/typescript/legacy/clients/cdp-sdk/.env-local b/examples/typescript/legacy/clients/cdp-sdk/.env-local deleted file mode 100644 index 6bc1d38de6..0000000000 --- a/examples/typescript/legacy/clients/cdp-sdk/.env-local +++ /dev/null @@ -1,6 +0,0 @@ -RESOURCE_SERVER_URL=http://localhost:4021 -ENDPOINT_PATH=/weather -CDP_API_KEY_ID= -CDP_API_KEY_SECRET= -CDP_WALLET_SECRET= - diff --git a/examples/typescript/legacy/clients/cdp-sdk/README.md b/examples/typescript/legacy/clients/cdp-sdk/README.md deleted file mode 100644 index 6697e306e3..0000000000 --- a/examples/typescript/legacy/clients/cdp-sdk/README.md +++ /dev/null @@ -1,82 +0,0 @@ -# cdp-sdk signer example using Axios - -This is an example showcasing using `cdp-sdk`'s server wallets as the signer for our `x402-axios` client. - -## Prerequisites - -- Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) -- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- A running x402 server (you can use the example express server at `examples/typescript/servers/express`) -- A valid Ethereum private key for making payments - -## Setup - -1. Install and build all packages from the typescript examples root: -```bash -cd ../../ -pnpm install -pnpm build -cd clients/axios -``` - -2. Copy `.env-local` to `.env` and add your Ethereum private key (remember it should have USDC on Base Sepolia, which you can provision using the [CDP Faucet](https://portal.cdp.coinbase.com/products/faucet)): -```bash -cp .env-local .env -``` - -3. Start the example client (remember you need to be running a server locally or point at an endpoint): -```bash -pnpm dev -``` - -## How It Works - -The example demonstrates how to: -1. Create a wallet client using cdp-sdk's server wallets -2. Create an Axios instance with x402 payment handling -3. Make a request to a paid endpoint -4. Handle the response or any errors - -## Example Code - -```typescript -import { config } from "dotenv"; -import { createWalletClient, http, publicActions } from "viem"; -import { privateKeyToAccount } from "viem/accounts"; -import { withPaymentInterceptor } from "x402-axios"; -import axios from "axios"; -import { baseSepolia } from "viem/chains"; - -config(); - -const { RESOURCE_SERVER_URL, CDP_API_KEY_ID, CDP_API_KEY_SECRET, CDP_WALLET_SECRET, ENDPOINT_PATH } = process.env; - -// Create a server wallet account -const client = new CdpClient({ - apiKeyId, - apiKeySecret, - walletSecret, -}); -const serverAccount = await client.evm.getOrCreateAccount({ - name: "x402-axios-example", -}) - -// Create Axios instance with payment handling -const api = withPaymentInterceptor( - axios.create({ - baseURL: RESOURCE_SERVER_URL, - }), - account -); - -// Make request to paid endpoint -api - .get(ENDPOINT_PATH) - .then(response => { - console.log(response.headers); - console.log(response.data); - }) - .catch(error => { - console.error(error.response?.data?.error); - }); -``` diff --git a/examples/typescript/legacy/clients/cdp-sdk/eslint.config.js b/examples/typescript/legacy/clients/cdp-sdk/eslint.config.js deleted file mode 100644 index ca28b5c47f..0000000000 --- a/examples/typescript/legacy/clients/cdp-sdk/eslint.config.js +++ /dev/null @@ -1,72 +0,0 @@ -import js from "@eslint/js"; -import ts from "@typescript-eslint/eslint-plugin"; -import tsParser from "@typescript-eslint/parser"; -import prettier from "eslint-plugin-prettier"; -import jsdoc from "eslint-plugin-jsdoc"; -import importPlugin from "eslint-plugin-import"; - -export default [ - { - ignores: ["dist/**", "node_modules/**"], - }, - { - files: ["**/*.ts"], - languageOptions: { - parser: tsParser, - sourceType: "module", - ecmaVersion: 2020, - globals: { - process: "readonly", - __dirname: "readonly", - module: "readonly", - require: "readonly", - Buffer: "readonly", - exports: "readonly", - setTimeout: "readonly", - clearTimeout: "readonly", - setInterval: "readonly", - clearInterval: "readonly", - }, - }, - plugins: { - "@typescript-eslint": ts, - prettier: prettier, - jsdoc: jsdoc, - import: importPlugin, - }, - rules: { - ...ts.configs.recommended.rules, - "import/first": "error", - "prettier/prettier": "error", - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_$" }], - "jsdoc/tag-lines": ["error", "any", { startLines: 1 }], - "jsdoc/check-alignment": "error", - "jsdoc/no-undefined-types": "off", - "jsdoc/check-param-names": "error", - "jsdoc/check-tag-names": "error", - "jsdoc/check-types": "error", - "jsdoc/implements-on-classes": "error", - "jsdoc/require-description": "error", - "jsdoc/require-jsdoc": [ - "error", - { - require: { - FunctionDeclaration: true, - MethodDefinition: true, - ClassDeclaration: true, - ArrowFunctionExpression: false, - FunctionExpression: false, - }, - }, - ], - "jsdoc/require-param": "error", - "jsdoc/require-param-description": "error", - "jsdoc/require-param-type": "off", - "jsdoc/require-returns": "error", - "jsdoc/require-returns-description": "error", - "jsdoc/require-returns-type": "off", - "jsdoc/require-hyphen-before-param-description": ["error", "always"], - }, - }, -]; diff --git a/examples/typescript/legacy/clients/cdp-sdk/index.ts b/examples/typescript/legacy/clients/cdp-sdk/index.ts deleted file mode 100644 index 881c6020fd..0000000000 --- a/examples/typescript/legacy/clients/cdp-sdk/index.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { CdpClient } from "@coinbase/cdp-sdk"; -import axios from "axios"; -import { config } from "dotenv"; -import { toAccount } from "viem/accounts"; -import { decodeXPaymentResponse, withPaymentInterceptor } from "x402-axios"; - -config(); - -const apiKeyId = process.env.CDP_API_KEY_ID as string; -const apiKeySecret = process.env.CDP_API_KEY_SECRET as string; -const walletSecret = process.env.CDP_WALLET_SECRET as string; -const baseURL = process.env.RESOURCE_SERVER_URL as string; // e.g. https://example.com -const endpointPath = process.env.ENDPOINT_PATH as string; // e.g. /weather - -if (!baseURL || !apiKeyId || !apiKeySecret || !walletSecret || !endpointPath) { - console.error("Missing required environment variables"); - process.exit(1); -} - -const client = new CdpClient({ - apiKeyId, - apiKeySecret, - walletSecret, -}); -const serverAccount = await client.evm.getOrCreateAccount({ - name: "x402", -}); - -const account = toAccount(serverAccount); - -const api = withPaymentInterceptor( - axios.create({ - baseURL, - }), - account, -); - -api - .get(endpointPath) - .then(response => { - console.log(response.data); - - const paymentResponse = decodeXPaymentResponse(response.headers["x-payment-response"]); - console.log(paymentResponse); - }) - .catch(error => { - console.error(error.response?.data); - }); diff --git a/examples/typescript/legacy/clients/cdp-sdk/package.json b/examples/typescript/legacy/clients/cdp-sdk/package.json deleted file mode 100644 index a97fbd0e77..0000000000 --- a/examples/typescript/legacy/clients/cdp-sdk/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "cdp-axios-client-example", - "private": true, - "type": "module", - "scripts": { - "dev": "tsx index.ts", - "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", - "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", - "lint": "eslint . --ext .ts --fix", - "lint:check": "eslint . --ext .ts" - }, - "dependencies": { - "@coinbase/cdp-sdk": "^1.16.0", - "axios": "^1.7.9", - "dotenv": "^16.5.0", - "viem": "^2.21.26", - "x402-axios": "workspace:*" - }, - "devDependencies": { - "@eslint/js": "^9.24.0", - "@typescript-eslint/eslint-plugin": "^8.29.1", - "@typescript-eslint/parser": "^8.29.1", - "eslint": "^9.24.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", - "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" - } -} diff --git a/examples/typescript/legacy/clients/cdp-sdk/tsconfig.json b/examples/typescript/legacy/clients/cdp-sdk/tsconfig.json deleted file mode 100644 index 1bdf94ca8d..0000000000 --- a/examples/typescript/legacy/clients/cdp-sdk/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ES2022", - "moduleResolution": "bundler", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true, - "strict": true, - "resolveJsonModule": true, - "baseUrl": ".", - "types": ["node"] - }, - "include": ["index.ts"] -} diff --git a/examples/typescript/legacy/clients/chainlink-vrf-nft/.env-local b/examples/typescript/legacy/clients/chainlink-vrf-nft/.env-local deleted file mode 100644 index b1b62ce13c..0000000000 --- a/examples/typescript/legacy/clients/chainlink-vrf-nft/.env-local +++ /dev/null @@ -1,2 +0,0 @@ -PRIVATE_KEY= -PROVIDER_URL= \ No newline at end of file diff --git a/examples/typescript/legacy/clients/chainlink-vrf-nft/README.md b/examples/typescript/legacy/clients/chainlink-vrf-nft/README.md deleted file mode 100644 index ff938932dd..0000000000 --- a/examples/typescript/legacy/clients/chainlink-vrf-nft/README.md +++ /dev/null @@ -1,106 +0,0 @@ -# VRF NFT Minting Example (via x402 Payment) - -This example demonstrates how a client pays USDC via the `x402` protocol (`exact` scheme) to a custom resource server. This resource server, upon successful payment verification and settlement via a facilitator, then uses its own funds to pay ETH and mint a VRF NFT to the client's address. - -Based on the value returned by the VRF result, one of four characters will be selected for the NFT. The NFT and its image can be viewed on [OpenSea](https://testnets.opensea.io/) by connecting to Base Sepolia and searching for the NFT contract address. The source code for the contract can be viewed [here](https://sepolia.basescan.org/address/0xcD8841f9a8Dbc483386fD80ab6E9FD9656Da39A2#code). - -## Architecture - -This example involves three components running concurrently: - -1. **Facilitator Server (`examples/typescript/facilitator.ts`):** A standard x402 facilitator server responsible for verifying payment signatures (`/verify`) and settling USDC payments (`/settle`) by calling `transferWithAuthorization` on the USDC contract. The Facilitator responds to requests from the VRF Resource Server -2. **VRF Resource Server (`resource.ts`):** A custom HTTP server (using Hono) that: - - Exposes a `/request-mint` endpoint. - - Handles initial requests by responding with `402 Payment Required`, providing the necessary `PaymentDetails` (USDC amount, recipient address, etc.). - - Receives subsequent requests containing the `X-PAYMENT` header (sent by the client's interceptor, implmented in `x402/axios`). - - Calls the **Facilitator's** `/verify` endpoint to validate the client's payment. - - If valid, it extracts the client's address (`from`) from the payment payload. - - Uses its _own wallet_ (funded with ETH) and `viem` to call `requestNFT(address _recipient)` on the target NFT contract, passing the client's address and the required ETH value. - - Calls the **Facilitator's** `/settle` endpoint to trigger the actual USDC transfer from the client to the resource server's wallet. - - Responds to the client with the outcome (including minting and settlement transaction hashes). -3. **Client (`client.ts`):** A script that: - - Uses `axios` with the `x402/axios` interceptor. The implementation of this custom interceptor is in `/typescript/packages/x402-axios` - - Makes a request to the **Resource Server's** `/request-mint` endpoint. - - The interceptor automatically handles the `402` response, prompts the client's wallet (via `viem`) to sign the EIP-3009 authorization for the USDC payment, constructs the `X-PAYMENT` header, and retries the request. - -## Setup - -1. **Install and Build Parent Dependencies:** - - ```bash - cd typescript - npx pnpm install - npx pnpm build - ``` - -2. **Install and Build Example Dependencies:** - - ```bash - cd ../examples/typescript - npx pnpm install - npx pnpm build - ``` - -3. **Install This Project's Dependencies:** - - ```bash - cd clients/chainlink-vrf-nft - pnpm install - ``` - -4. **Environment Variables (`example/.env`):** Create a `.env` file in the `example` directory with the following variables (replace placeholder values): - - ```dotenv - # Wallet that pays the USDC (needs USDC and ETH for gas) - PRIVATE_KEY=0xYOUR_CLIENT_PRIVATE_KEY - - # HTTP RPC endpoint for the blockchain network (e.g., Base Sepolia) - # Must be accessible by all components - PROVIDER_URL=https://base-sepolia.g.alchemy.com/v2/YOUR_ALCHEMY_KEY - ``` - -## Running the Example - -You need three separate terminals, all navigated to the `example` directory. - -1. **Terminal 1: Start Facilitator:** - - Start a new terminal instance - - ```bash - cd examples/typescript/facilitator - cp .env-local .env - ``` - - Fill in the value for `PRIVATE_KEY=` in the `.env` file then run: - - ```bash - pnpm dev - ``` - - Check that your terminal shows something along the lines of `Server listening at http://localhost:<>` - -2. **Terminal 2: Start VRF Resource Server:** - - Start a new terminal instance - - ```bash - cd examples/typescript/clients/chainlink-vrf-nft - npx pnpm install - pnpm run resource - ``` - -3. **Terminal 3: Run VRF Client:** - - Start a new terminal instance - - ```bash - cd examples/typescript/clients/chainlink-vrf-nft - pnpm run client - ``` - -## Expected Output - -- **Facilitator Terminal:** Logs for starting. -- **Resource Server Terminal:** Logs for starting, receiving the client request, calling facilitator `/verify`, calling the NFT contract, calling facilitator `/settle`, and responding 200 OK to the client. -- **Client Terminal:** Logs attempting the request, followed by the success response (Status 200) from the resource server, including the NFT mint transaction hash. diff --git a/examples/typescript/legacy/clients/chainlink-vrf-nft/client.ts b/examples/typescript/legacy/clients/chainlink-vrf-nft/client.ts deleted file mode 100644 index a8efde2bd9..0000000000 --- a/examples/typescript/legacy/clients/chainlink-vrf-nft/client.ts +++ /dev/null @@ -1,85 +0,0 @@ -import dotenv from "dotenv"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import { baseSepolia } from "viem/chains"; -import { privateKeyToAccount } from "viem/accounts"; -import { http, publicActions, createWalletClient, Hex } from "viem"; -import axios from "axios"; -import { withPaymentInterceptor } from "x402-axios"; - -// --- Load .env --- -const __filename_env = fileURLToPath(import.meta.url); -const __dirname_env = path.dirname(__filename_env); -const envPath = path.resolve(__dirname_env, "./.env"); -dotenv.config({ path: envPath }); -// --------------------------- - -// --- Environment Variable Checks --- -let clientPrivateKey = process.env.PRIVATE_KEY as Hex | undefined; -// if not prefixed, add 0x as prefix -if (clientPrivateKey && !clientPrivateKey.startsWith("0x")) { - clientPrivateKey = "0x" + clientPrivateKey; -} - -const providerUrl = process.env.PROVIDER_URL; - -if (!clientPrivateKey || !providerUrl) { - console.error("Missing PRIVATE_KEY or PROVIDER_URL in .env file"); - process.exit(1); -} -// ---------------------------------------- - -// --- Viem Client Setup --- -const clientAccount = privateKeyToAccount(clientPrivateKey as Hex); -const clientWallet = createWalletClient({ - account: clientAccount, - chain: baseSepolia, - transport: http(providerUrl), -}).extend(publicActions); - -// --- Axios Setup with x402 Interceptor --- -const resourceServerPort = 4023; // Port for the VRF resource server -const resourceServerUrl = `http://localhost:${resourceServerPort}`; -const requestMintUrl = `${resourceServerUrl}/request-mint`; - -let axiosInstance = axios.create(); -// Apply the x402 interceptor to handle payments -axiosInstance = withPaymentInterceptor(axiosInstance, clientWallet); - -// --- Main Execution --- -async function makeMintRequest() { - console.log( - `Client: Requesting NFT mint from ${requestMintUrl} using wallet ${clientAccount.address}`, - ); - - try { - // Make the POST request. The x402 interceptor handles the 402 payment flow. - const response = await axiosInstance.post(requestMintUrl, {}); - - console.log("Client: Success! Resource Server Response:"); - console.log(" Status:", response.status); - console.log(" Data:", JSON.stringify(response.data, null, 2)); - console.log( - "Check the NFT on testnet.opensea.io, using the NFT Contract's address: '0xcD8841f9a8Dbc483386fD80ab6E9FD9656Da39A2'. You can also check the NFT contract's transactions on Base Sepolia's explorer: https://sepolia.basescan.org/address/0xcD8841f9a8Dbc483386fD80ab6E9FD9656Da39A2.", - ); - } catch (error: any) { - console.error("Client: Request failed!"); - if (axios.isAxiosError(error)) { - console.error(` Error: ${error.message}`); - if (error.response) { - console.error(` Status: ${error.response.status}`); - console.error(` Data: ${JSON.stringify(error.response.data, null, 2)}`); - if (error.response.status === 402) { - console.error(" (Payment was required but failed. Check facilitator/resource logs)"); - } - } else { - console.error(" (No response received from server)"); - } - } else { - console.error(" Unexpected Error:", error); - } - process.exit(1); - } -} - -makeMintRequest(); diff --git a/examples/typescript/legacy/clients/chainlink-vrf-nft/package-lock.json b/examples/typescript/legacy/clients/chainlink-vrf-nft/package-lock.json deleted file mode 100644 index 3a04a05570..0000000000 --- a/examples/typescript/legacy/clients/chainlink-vrf-nft/package-lock.json +++ /dev/null @@ -1,1165 +0,0 @@ -{ - "name": "vrfnft-example", - "version": "0.1.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "vrfnft-example", - "version": "0.1.0", - "dependencies": { - "@hono/node-server": "^1.13.8", - "dotenv": "^16.4.5", - "hono": "^4.7.2", - "viem": "^2.23.5", - "x402": "file:../../../../typescript/packages/x402" - }, - "devDependencies": { - "@types/node": "^22.13.5", - "tsx": "^4.19.3" - } - }, - "../../../../typescript/packages/x402": { - "version": "0.2.0", - "license": "Apache-2.0", - "dependencies": { - "@coinbase/cdp-sdk": "^1.1.1", - "axios": "^1.7.9", - "viem": "^2.21.26", - "zod": "^3.24.2" - }, - "devDependencies": { - "@eslint/js": "^9.24.0", - "@types/node": "^22.13.4", - "@typescript-eslint/eslint-plugin": "^8.29.1", - "@typescript-eslint/parser": "^8.29.1", - "eslint": "^9.24.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", - "prettier": "3.5.2", - "tsx": "^4.19.2", - "typescript": "^5.7.3", - "vite": "^6.2.6", - "vite-tsconfig-paths": "^5.1.4", - "vitest": "^3.0.5" - } - }, - "../../../../typescript/packages/x402/node_modules/@coinbase/cdp-sdk": { - "resolved": "../../node_modules/.pnpm/@coinbase+cdp-sdk@1.1.2_bufferutil@4.0.9_typescript@5.8.3_utf-8-validate@5.0.10_zod@3.24.3/node_modules/@coinbase/cdp-sdk", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/@eslint/js": { - "resolved": "../../node_modules/.pnpm/@eslint+js@9.24.0/node_modules/@eslint/js", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/@types/node": { - "resolved": "../../node_modules/.pnpm/@types+node@22.14.1/node_modules/@types/node", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/@typescript-eslint/eslint-plugin": { - "resolved": "../../node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.30.1_@typescript-eslint+parser@8.30.1_eslint@9.24.0__beb2a5db574f326f24c476c3022a6373/node_modules/@typescript-eslint/eslint-plugin", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/@typescript-eslint/parser": { - "resolved": "../../node_modules/.pnpm/@typescript-eslint+parser@8.30.1_eslint@9.24.0_jiti@1.21.7__typescript@5.8.3/node_modules/@typescript-eslint/parser", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/axios": { - "resolved": "../../node_modules/.pnpm/axios@1.8.4/node_modules/axios", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/eslint": { - "resolved": "../../node_modules/.pnpm/eslint@9.24.0_jiti@1.21.7/node_modules/eslint", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/eslint-plugin-import": { - "resolved": "../../node_modules/.pnpm/eslint-plugin-import@2.31.0_@typescript-eslint+parser@8.30.1_eslint@9.24.0_jiti@1.21.7__047cccc7d02cbbe44b50dd3c9d1bc175/node_modules/eslint-plugin-import", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/eslint-plugin-jsdoc": { - "resolved": "../../node_modules/.pnpm/eslint-plugin-jsdoc@50.6.9_eslint@9.24.0_jiti@1.21.7_/node_modules/eslint-plugin-jsdoc", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/eslint-plugin-prettier": { - "resolved": "../../node_modules/.pnpm/eslint-plugin-prettier@5.2.6_eslint@9.24.0_jiti@1.21.7__prettier@3.5.2/node_modules/eslint-plugin-prettier", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/prettier": { - "resolved": "../../node_modules/.pnpm/prettier@3.5.2/node_modules/prettier", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/tsx": { - "resolved": "../../node_modules/.pnpm/tsx@4.19.3/node_modules/tsx", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/typescript": { - "resolved": "../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/viem": { - "resolved": "../../node_modules/.pnpm/viem@2.27.2_bufferutil@4.0.9_typescript@5.8.3_utf-8-validate@5.0.10_zod@3.24.3/node_modules/viem", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/vite": { - "resolved": "../../node_modules/.pnpm/vite@6.3.2_@types+node@22.14.1_jiti@1.21.7_tsx@4.19.3_yaml@2.7.1/node_modules/vite", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/vite-tsconfig-paths": { - "resolved": "../../node_modules/.pnpm/vite-tsconfig-paths@5.1.4_typescript@5.8.3_vite@6.3.2_@types+node@22.14.1_jiti@1.21.7_tsx@4.19.3_yaml@2.7.1_/node_modules/vite-tsconfig-paths", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/vitest": { - "resolved": "../../node_modules/.pnpm/vitest@3.1.1_@types+node@22.14.1_jiti@1.21.7_tsx@4.19.3_yaml@2.7.1/node_modules/vitest", - "link": true - }, - "../../../../typescript/packages/x402/node_modules/zod": { - "resolved": "../../node_modules/.pnpm/zod@3.24.3/node_modules/zod", - "link": true - }, - "../../node_modules/.pnpm/@coinbase+cdp-sdk@1.1.2_bufferutil@4.0.9_typescript@5.8.3_utf-8-validate@5.0.10_zod@3.24.3/node_modules/@coinbase/cdp-sdk": { - "version": "1.1.2", - "license": "MIT", - "dependencies": { - "@solana/web3.js": "^1.98.0", - "abitype": "1.0.6", - "axios": "^1.8.2", - "jose": "^6.0.8", - "md5": "^2.3.0", - "viem": "^2.21.26" - }, - "devDependencies": { - "@changesets/changelog-github": "^0.5.1", - "@changesets/cli": "^2.28.1", - "@faker-js/faker": "^9.6.0", - "@types/node": "^20.12.11", - "@typescript-eslint/eslint-plugin": "^7.18.0", - "@typescript-eslint/parser": "^7.18.0", - "@vitest/coverage-v8": "^1.4.0", - "bs58": "^6.0.0", - "dotenv": "^16.4.7", - "eslint": "^8.57.1", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-jsdoc": "^48.11.0", - "eslint-plugin-prettier": "^5.2.5", - "msw": "^2.7.3", - "orval": "^7.6.0", - "prettier": "^3.2.5", - "tsx": "^4.19.3", - "typedoc": "^0.27.2", - "typescript": "^5.4.5", - "uuid": "^11.1.0", - "vitest": "^1.4.0" - } - }, - "../../node_modules/.pnpm/@eslint+js@9.24.0/node_modules/@eslint/js": { - "version": "9.24.0", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "../../node_modules/.pnpm/@hono+node-server@1.14.1_hono@4.7.7/node_modules/@hono/node-server": { - "version": "1.14.1", - "license": "MIT", - "devDependencies": { - "@hono/eslint-config": "^1.0.1", - "@types/jest": "^29.5.3", - "@types/node": "^20.10.0", - "@types/supertest": "^2.0.12", - "@whatwg-node/fetch": "^0.9.14", - "eslint": "^9.10.0", - "hono": "^4.4.10", - "jest": "^29.6.1", - "np": "^7.7.0", - "prettier": "^3.2.4", - "publint": "^0.1.16", - "supertest": "^6.3.3", - "ts-jest": "^29.1.1", - "tsup": "^7.2.0", - "typescript": "^5.3.2" - }, - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "../../node_modules/.pnpm/@types+node@22.14.1/node_modules/@types/node": { - "version": "22.14.1", - "dev": true, - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "../../node_modules/.pnpm/@typescript-eslint+eslint-plugin@8.30.1_@typescript-eslint+parser@8.30.1_eslint@9.24.0__beb2a5db574f326f24c476c3022a6373/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.30.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "8.30.1", - "@typescript-eslint/type-utils": "8.30.1", - "@typescript-eslint/utils": "8.30.1", - "@typescript-eslint/visitor-keys": "8.30.1", - "graphemer": "^1.4.0", - "ignore": "^5.3.1", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.0.1" - }, - "devDependencies": { - "@jest/types": "29.6.3", - "@types/marked": "^5.0.2", - "@types/mdast": "^4.0.3", - "@types/natural-compare": "*", - "@typescript-eslint/rule-schema-to-typescript-types": "8.30.1", - "@typescript-eslint/rule-tester": "8.30.1", - "ajv": "^6.12.6", - "cross-env": "^7.0.3", - "cross-fetch": "*", - "eslint": "*", - "jest": "29.7.0", - "jest-specific-snapshot": "^8.0.0", - "json-schema": "*", - "markdown-table": "^3.0.3", - "marked": "^5.1.2", - "mdast-util-from-markdown": "^2.0.0", - "mdast-util-mdx": "^3.0.0", - "micromark-extension-mdxjs": "^3.0.0", - "prettier": "^3.2.5", - "rimraf": "*", - "title-case": "^3.0.3", - "tsx": "*", - "typescript": "*", - "unist-util-visit": "^5.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "../../node_modules/.pnpm/@typescript-eslint+parser@8.30.1_eslint@9.24.0_jiti@1.21.7__typescript@5.8.3/node_modules/@typescript-eslint/parser": { - "version": "8.30.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.30.1", - "@typescript-eslint/types": "8.30.1", - "@typescript-eslint/typescript-estree": "8.30.1", - "@typescript-eslint/visitor-keys": "8.30.1", - "debug": "^4.3.4" - }, - "devDependencies": { - "@vitest/coverage-v8": "^3.1.1", - "glob": "*", - "prettier": "^3.2.5", - "rimraf": "*", - "typescript": "*", - "vitest": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0", - "typescript": ">=4.8.4 <5.9.0" - } - }, - "../../node_modules/.pnpm/axios@1.8.4/node_modules/axios": { - "version": "1.8.4", - "license": "MIT", - "dependencies": { - "follow-redirects": "^1.15.6", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" - }, - "devDependencies": { - "@babel/core": "^7.23.9", - "@babel/preset-env": "^7.23.9", - "@commitlint/cli": "^17.8.1", - "@commitlint/config-conventional": "^17.8.1", - "@release-it/conventional-changelog": "^5.1.1", - "@rollup/plugin-alias": "^5.1.0", - "@rollup/plugin-babel": "^5.3.1", - "@rollup/plugin-commonjs": "^15.1.0", - "@rollup/plugin-json": "^4.1.0", - "@rollup/plugin-multi-entry": "^4.1.0", - "@rollup/plugin-node-resolve": "^9.0.0", - "abortcontroller-polyfill": "^1.7.5", - "auto-changelog": "^2.4.0", - "body-parser": "^1.20.2", - "chalk": "^5.3.0", - "coveralls": "^3.1.1", - "cross-env": "^7.0.3", - "dev-null": "^0.1.1", - "dtslint": "^4.2.1", - "es6-promise": "^4.2.8", - "eslint": "^8.56.0", - "express": "^4.18.2", - "formdata-node": "^5.0.1", - "formidable": "^2.1.2", - "fs-extra": "^10.1.0", - "get-stream": "^3.0.0", - "gulp": "^4.0.2", - "gzip-size": "^7.0.0", - "handlebars": "^4.7.8", - "husky": "^8.0.3", - "istanbul-instrumenter-loader": "^3.0.1", - "jasmine-core": "^2.99.1", - "karma": "^6.3.17", - "karma-chrome-launcher": "^3.2.0", - "karma-firefox-launcher": "^2.1.2", - "karma-jasmine": "^1.1.2", - "karma-jasmine-ajax": "^0.1.13", - "karma-rollup-preprocessor": "^7.0.8", - "karma-safari-launcher": "^1.0.0", - "karma-sauce-launcher": "^4.3.6", - "karma-sinon": "^1.0.5", - "karma-sourcemap-loader": "^0.3.8", - "memoizee": "^0.4.15", - "minimist": "^1.2.8", - "mocha": "^10.3.0", - "multer": "^1.4.4", - "pretty-bytes": "^6.1.1", - "release-it": "^15.11.0", - "rollup": "^2.79.1", - "rollup-plugin-auto-external": "^2.0.0", - "rollup-plugin-bundle-size": "^1.0.3", - "rollup-plugin-terser": "^7.0.2", - "sinon": "^4.5.0", - "stream-throttle": "^0.1.3", - "string-replace-async": "^3.0.2", - "terser-webpack-plugin": "^4.2.3", - "typescript": "^4.9.5" - } - }, - "../../node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv": { - "version": "16.5.0", - "license": "BSD-2-Clause", - "devDependencies": { - "@types/node": "^18.11.3", - "decache": "^4.6.2", - "sinon": "^14.0.1", - "standard": "^17.0.0", - "standard-version": "^9.5.0", - "tap": "^19.2.0", - "typescript": "^4.8.4" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://dotenvx.com" - } - }, - "../../node_modules/.pnpm/eslint-plugin-import@2.31.0_@typescript-eslint+parser@8.30.1_eslint@9.24.0_jiti@1.21.7__047cccc7d02cbbe44b50dd3c9d1bc175/node_modules/eslint-plugin-import": { - "version": "2.31.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@rtsao/scc": "^1.1.0", - "array-includes": "^3.1.8", - "array.prototype.findlastindex": "^1.2.5", - "array.prototype.flat": "^1.3.2", - "array.prototype.flatmap": "^1.3.2", - "debug": "^3.2.7", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.9", - "eslint-module-utils": "^2.12.0", - "hasown": "^2.0.2", - "is-core-module": "^2.15.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.fromentries": "^2.0.8", - "object.groupby": "^1.0.3", - "object.values": "^1.2.0", - "semver": "^6.3.1", - "string.prototype.trimend": "^1.0.8", - "tsconfig-paths": "^3.15.0" - }, - "devDependencies": { - "@angular-eslint/template-parser": "^13.5.0", - "@eslint/import-test-order-redirect-scoped": "file:./tests/files/order-redirect-scoped", - "@test-scope/some-module": "file:./tests/files/symlinked-module", - "@typescript-eslint/parser": "^2.23.0 || ^3.3.0 || ^4.29.3 || ^5.10.0", - "babel-cli": "^6.26.0", - "babel-core": "^6.26.3", - "babel-eslint": "=8.0.3 || ^8.2.6", - "babel-plugin-istanbul": "^4.1.6", - "babel-plugin-module-resolver": "^2.7.1", - "babel-preset-airbnb": "^2.6.0", - "babel-preset-flow": "^6.23.0", - "babel-register": "^6.26.0", - "babylon": "^6.18.0", - "chai": "^4.3.10", - "cross-env": "^4.0.0", - "escope": "^3.6.0", - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9", - "eslint-doc-generator": "^1.6.1", - "eslint-import-resolver-node": "file:./resolvers/node", - "eslint-import-resolver-typescript": "^1.0.2 || ^1.1.1", - "eslint-import-resolver-webpack": "file:./resolvers/webpack", - "eslint-import-test-order-redirect": "file:./tests/files/order-redirect", - "eslint-module-utils": "file:./utils", - "eslint-plugin-eslint-plugin": "^2.3.0", - "eslint-plugin-import": "2.x", - "eslint-plugin-json": "^2.1.2", - "find-babel-config": "=1.2.0", - "fs-copy-file-sync": "^1.1.1", - "glob": "^7.2.3", - "in-publish": "^2.0.1", - "jackspeak": "=2.1.1", - "jsonc-parser": "=3.2.0", - "linklocal": "^2.8.2", - "lodash.isarray": "^4.0.0", - "markdownlint-cli": "~0.35", - "mocha": "^3.5.3", - "npm-which": "^3.0.1", - "nyc": "^11.9.0", - "redux": "^3.7.2", - "rimraf": "^2.7.1", - "safe-publish-latest": "^2.0.0", - "sinon": "^2.4.1", - "typescript": "^2.8.1 || ~3.9.5 || ~4.5.2", - "typescript-eslint-parser": "^15 || ^20 || ^22" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9" - } - }, - "../../node_modules/.pnpm/eslint-plugin-jsdoc@50.6.9_eslint@9.24.0_jiti@1.21.7_/node_modules/eslint-plugin-jsdoc": { - "version": "50.6.9", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "@es-joy/jsdoccomment": "~0.49.0", - "are-docs-informative": "^0.0.2", - "comment-parser": "1.4.1", - "debug": "^4.3.6", - "escape-string-regexp": "^4.0.0", - "espree": "^10.1.0", - "esquery": "^1.6.0", - "parse-imports": "^2.1.1", - "semver": "^7.6.3", - "spdx-expression-parse": "^4.0.0", - "synckit": "^0.9.1" - }, - "devDependencies": { - "@babel/cli": "^7.24.8", - "@babel/core": "^7.25.2", - "@babel/eslint-parser": "^7.25.1", - "@babel/node": "^7.25.0", - "@babel/plugin-syntax-class-properties": "^7.12.13", - "@babel/plugin-transform-flow-strip-types": "^7.25.2", - "@babel/preset-env": "^7.25.3", - "@es-joy/escodegen": "^3.5.1", - "@es-joy/jsdoc-eslint-parser": "^0.21.1", - "@hkdobrev/run-if-changed": "^0.6.0", - "@semantic-release/commit-analyzer": "^13.0.0", - "@semantic-release/github": "^11.0.0", - "@semantic-release/npm": "^12.0.1", - "@types/chai": "^4.3.17", - "@types/debug": "^4.1.12", - "@types/eslint": "^9.6.0", - "@types/espree": "^10.1.0", - "@types/esquery": "^1.5.4", - "@types/estree": "^1.0.5", - "@types/json-schema": "^7.0.15", - "@types/lodash.defaultsdeep": "^4.6.9", - "@types/mocha": "^10.0.7", - "@types/node": "^22.2.0", - "@types/semver": "^7.5.8", - "@types/spdx-expression-parse": "^3.0.5", - "@typescript-eslint/types": "^8.1.0", - "babel-plugin-add-module-exports": "^1.0.4", - "babel-plugin-istanbul": "^7.0.0", - "babel-plugin-transform-import-meta": "^2.2.1", - "c8": "^10.1.2", - "camelcase": "^8.0.0", - "chai": "^5.1.1", - "cross-env": "^7.0.3", - "decamelize": "^6.0.0", - "eslint": "9.9.0", - "eslint-config-canonical": "~43.0.15", - "gitdown": "^4.1.1", - "glob": "^10.4.2", - "globals": "^15.9.0", - "husky": "^9.1.4", - "jsdoc-type-pratt-parser": "^4.1.0", - "json-schema": "^0.4.0", - "lint-staged": "^15.2.9", - "lodash.defaultsdeep": "^4.6.1", - "mocha": "^10.7.3", - "open-editor": "^5.0.0", - "replace": "^1.2.2", - "rimraf": "^5.0.7", - "semantic-release": "^24.1.1", - "typescript": "5.5.x", - "typescript-eslint": "^8.1.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" - } - }, - "../../node_modules/.pnpm/eslint-plugin-prettier@5.2.6_eslint@9.24.0_jiti@1.21.7__prettier@3.5.2/node_modules/eslint-plugin-prettier": { - "version": "5.2.6", - "dev": true, - "license": "MIT", - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.11.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": ">= 7.0.0 <10.0.0 || >=10.1.0", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, - "../../node_modules/.pnpm/eslint@9.24.0_jiti@1.21.7/node_modules/eslint": { - "version": "9.24.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.2.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.20.0", - "@eslint/config-helpers": "^0.2.0", - "@eslint/core": "^0.12.0", - "@eslint/eslintrc": "^3.3.1", - "@eslint/js": "9.24.0", - "@eslint/plugin-kit": "^0.2.7", - "@humanfs/node": "^0.16.6", - "@humanwhocodes/module-importer": "^1.0.1", - "@humanwhocodes/retry": "^0.4.2", - "@types/estree": "^1.0.6", - "@types/json-schema": "^7.0.15", - "ajv": "^6.12.4", - "chalk": "^4.0.0", - "cross-spawn": "^7.0.6", - "debug": "^4.3.2", - "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.3.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", - "esquery": "^1.5.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", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.2", - "natural-compare": "^1.4.0", - "optionator": "^0.9.3" - }, - "bin": { - "eslint": "bin/eslint.js" - }, - "devDependencies": { - "@arethetypeswrong/cli": "^0.17.0", - "@babel/core": "^7.4.3", - "@babel/preset-env": "^7.4.3", - "@cypress/webpack-preprocessor": "^6.0.2", - "@eslint/json": "^0.11.0", - "@trunkio/launcher": "^1.3.0", - "@types/node": "^22.13.14", - "@typescript-eslint/parser": "^8.4.0", - "babel-loader": "^8.0.5", - "c8": "^7.12.0", - "chai": "^4.0.1", - "cheerio": "^0.22.0", - "common-tags": "^1.8.0", - "core-js": "^3.1.3", - "cypress": "^14.1.0", - "ejs": "^3.0.2", - "eslint": "file:.", - "eslint-config-eslint": "file:packages/eslint-config-eslint", - "eslint-plugin-eslint-plugin": "^6.0.0", - "eslint-plugin-expect-type": "^0.6.0", - "eslint-plugin-yml": "^1.14.0", - "eslint-release": "^3.3.0", - "eslint-rule-composer": "^0.3.0", - "eslump": "^3.0.0", - "esprima": "^4.0.1", - "fast-glob": "^3.2.11", - "fs-teardown": "^0.1.3", - "glob": "^10.0.0", - "globals": "^15.0.0", - "got": "^11.8.3", - "gray-matter": "^4.0.3", - "jiti": "^2.1.0", - "knip": "^5.32.0", - "lint-staged": "^11.0.0", - "load-perf": "^0.2.0", - "markdown-it": "^12.2.0", - "markdown-it-container": "^3.0.0", - "marked": "^4.0.8", - "metascraper": "^5.25.7", - "metascraper-description": "^5.25.7", - "metascraper-image": "^5.29.3", - "metascraper-logo": "^5.25.7", - "metascraper-logo-favicon": "^5.25.7", - "metascraper-title": "^5.25.7", - "mocha": "^10.7.3", - "node-polyfill-webpack-plugin": "^1.0.3", - "npm-license": "^0.3.3", - "pirates": "^4.0.5", - "progress": "^2.0.3", - "proxyquire": "^2.0.1", - "recast": "^0.23.0", - "regenerator-runtime": "^0.14.0", - "semver": "^7.5.3", - "shelljs": "^0.9.0", - "sinon": "^11.0.0", - "typescript": "^5.3.3", - "webpack": "^5.23.0", - "webpack-cli": "^4.5.0", - "yorkie": "^2.0.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" - }, - "peerDependencies": { - "jiti": "*" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - } - } - }, - "../../node_modules/.pnpm/hono@4.7.7/node_modules/hono": { - "version": "4.7.7", - "license": "MIT", - "devDependencies": { - "@hono/eslint-config": "^1.0.2", - "@hono/node-server": "^1.13.5", - "@types/glob": "^8.1.0", - "@types/jsdom": "^21.1.7", - "@types/node": "20.11.4", - "@types/supertest": "^2.0.16", - "@vitest/coverage-v8": "^3.0.5", - "arg": "^5.0.2", - "bun-types": "^1.1.39", - "esbuild": "^0.15.18", - "eslint": "^9.10.0", - "glob": "^11.0.0", - "jsdom": "^22.1.0", - "msw": "^2.6.0", - "np": "10.2.0", - "prettier": "^2.6.2", - "publint": "^0.1.16", - "supertest": "^6.3.4", - "typescript": "^5.3.3", - "vite-plugin-fastly-js-compute": "^0.4.2", - "vitest": "^3.0.5", - "wrangler": "3.58.0", - "ws": "^8.18.0", - "zod": "^3.23.8" - }, - "engines": { - "node": ">=16.9.0" - } - }, - "../../node_modules/.pnpm/prettier@3.5.2/node_modules/prettier": { - "version": "3.5.2", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" - } - }, - "../../node_modules/.pnpm/tsx@4.19.3/node_modules/tsx": { - "version": "4.19.3", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "~0.25.0", - "get-tsconfig": "^4.7.5" - }, - "bin": { - "tsx": "dist/cli.mjs" - }, - "engines": { - "node": ">=18.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - } - }, - "../../node_modules/.pnpm/typescript@5.8.3/node_modules/typescript": { - "version": "5.8.3", - "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "devDependencies": { - "@dprint/formatter": "^0.4.1", - "@dprint/typescript": "0.93.3", - "@esfx/canceltoken": "^1.0.0", - "@eslint/js": "^9.17.0", - "@octokit/rest": "^21.0.2", - "@types/chai": "^4.3.20", - "@types/diff": "^5.2.3", - "@types/minimist": "^1.2.5", - "@types/mocha": "^10.0.10", - "@types/ms": "^0.7.34", - "@types/node": "latest", - "@types/source-map-support": "^0.5.10", - "@types/which": "^3.0.4", - "@typescript-eslint/rule-tester": "^8.18.1", - "@typescript-eslint/type-utils": "^8.18.1", - "@typescript-eslint/utils": "^8.18.1", - "azure-devops-node-api": "^14.1.0", - "c8": "^10.1.3", - "chai": "^4.5.0", - "chalk": "^4.1.2", - "chokidar": "^3.6.0", - "diff": "^5.2.0", - "dprint": "^0.47.6", - "esbuild": "^0.24.0", - "eslint": "^9.17.0", - "eslint-formatter-autolinkable-stylish": "^1.4.0", - "eslint-plugin-regexp": "^2.7.0", - "fast-xml-parser": "^4.5.1", - "glob": "^10.4.5", - "globals": "^15.13.0", - "hereby": "^1.10.0", - "jsonc-parser": "^3.3.1", - "knip": "^5.41.0", - "minimist": "^1.2.8", - "mocha": "^10.8.2", - "mocha-fivemat-progress-reporter": "^0.1.0", - "monocart-coverage-reports": "^2.11.4", - "ms": "^2.1.3", - "playwright": "^1.49.1", - "source-map-support": "^0.5.21", - "tslib": "^2.8.1", - "typescript": "^5.7.2", - "typescript-eslint": "^8.18.1", - "which": "^3.0.1" - }, - "engines": { - "node": ">=14.17" - } - }, - "../../node_modules/.pnpm/viem@2.27.2_bufferutil@4.0.9_typescript@5.8.3_utf-8-validate@5.0.10_zod@3.24.3/node_modules/viem": { - "version": "2.27.2", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/wevm" - } - ], - "license": "MIT", - "dependencies": { - "@noble/curves": "1.8.1", - "@noble/hashes": "1.7.1", - "@scure/bip32": "1.6.2", - "@scure/bip39": "1.5.4", - "abitype": "1.0.8", - "isows": "1.0.6", - "ox": "0.6.9", - "ws": "8.18.1" - }, - "peerDependencies": { - "typescript": ">=5.0.4" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } - }, - "../../node_modules/.pnpm/vite-tsconfig-paths@5.1.4_typescript@5.8.3_vite@6.3.2_@types+node@22.14.1_jiti@1.21.7_tsx@4.19.3_yaml@2.7.1_/node_modules/vite-tsconfig-paths": { - "version": "5.1.4", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.1.1", - "globrex": "^0.1.2", - "tsconfck": "^3.0.3" - }, - "devDependencies": { - "@alloc/fast-rimraf": "^1.0.8", - "@types/debug": "^4.1.5", - "@types/globrex": "^0.1.0", - "@types/node": "^22.2.0", - "esbuild": "^0.11.12", - "execa": "^9.5.1", - "klona": "^2.0.4", - "prettier": "^2.8.7", - "rollup": "^2.45.2", - "tsup": "^6.5.0", - "typescript": "^5.7.2", - "vite": "^6.0.2", - "vite-tsconfig-paths": "link:.", - "vitest": "^2.1.8" - }, - "peerDependencies": { - "vite": "*" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } - } - }, - "../../node_modules/.pnpm/vite@6.3.2_@types+node@22.14.1_jiti@1.21.7_tsx@4.19.3_yaml@2.7.1/node_modules/vite": { - "version": "6.3.2", - "dev": true, - "license": "MIT", - "dependencies": { - "esbuild": "^0.25.0", - "fdir": "^6.4.3", - "picomatch": "^4.0.2", - "postcss": "^8.5.3", - "rollup": "^4.34.9", - "tinyglobby": "^0.2.12" - }, - "bin": { - "vite": "bin/vite.js" - }, - "devDependencies": { - "@ampproject/remapping": "^2.3.0", - "@babel/parser": "^7.27.0", - "@jridgewell/trace-mapping": "^0.3.25", - "@polka/compression": "^1.0.0-next.25", - "@rollup/plugin-alias": "^5.1.1", - "@rollup/plugin-commonjs": "^28.0.3", - "@rollup/plugin-dynamic-import-vars": "2.1.4", - "@rollup/plugin-json": "^6.1.0", - "@rollup/plugin-node-resolve": "16.0.1", - "@rollup/pluginutils": "^5.1.4", - "@types/escape-html": "^1.0.4", - "@types/pnpapi": "^0.0.5", - "artichokie": "^0.3.1", - "cac": "^6.7.14", - "chokidar": "^3.6.0", - "connect": "^3.7.0", - "convert-source-map": "^2.0.0", - "cors": "^2.8.5", - "cross-spawn": "^7.0.6", - "debug": "^4.4.0", - "dep-types": "link:./src/types", - "dotenv": "^16.5.0", - "dotenv-expand": "^12.0.2", - "es-module-lexer": "^1.6.0", - "escape-html": "^1.0.3", - "estree-walker": "^3.0.3", - "etag": "^1.8.1", - "http-proxy": "^1.18.1", - "launch-editor-middleware": "^2.10.0", - "lightningcss": "^1.29.3", - "magic-string": "^0.30.17", - "mlly": "^1.7.4", - "mrmime": "^2.0.1", - "nanoid": "^5.1.5", - "open": "^10.1.1", - "parse5": "^7.2.1", - "pathe": "^2.0.3", - "periscopic": "^4.0.2", - "picocolors": "^1.1.1", - "postcss-import": "^16.1.0", - "postcss-load-config": "^6.0.1", - "postcss-modules": "^6.0.1", - "resolve.exports": "^2.0.3", - "rollup-plugin-dts": "^6.2.1", - "rollup-plugin-esbuild": "^6.2.1", - "rollup-plugin-license": "^3.6.0", - "sass": "^1.86.3", - "sass-embedded": "^1.86.3", - "sirv": "^3.0.1", - "source-map-support": "^0.5.21", - "strip-literal": "^3.0.0", - "terser": "^5.39.0", - "tsconfck": "^3.1.5", - "tslib": "^2.8.1", - "types": "link:./types", - "ufo": "^1.6.1", - "ws": "^8.18.1" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "jiti": ">=1.21.0", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "sass-embedded": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.16.0", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "lightningcss": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "../../node_modules/.pnpm/vitest@3.1.1_@types+node@22.14.1_jiti@1.21.7_tsx@4.19.3_yaml@2.7.1/node_modules/vitest": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@vitest/expect": "3.1.1", - "@vitest/mocker": "3.1.1", - "@vitest/pretty-format": "^3.1.1", - "@vitest/runner": "3.1.1", - "@vitest/snapshot": "3.1.1", - "@vitest/spy": "3.1.1", - "@vitest/utils": "3.1.1", - "chai": "^5.2.0", - "debug": "^4.4.0", - "expect-type": "^1.2.0", - "magic-string": "^0.30.17", - "pathe": "^2.0.3", - "std-env": "^3.8.1", - "tinybench": "^2.9.0", - "tinyexec": "^0.3.2", - "tinypool": "^1.0.2", - "tinyrainbow": "^2.0.0", - "vite": "^5.0.0 || ^6.0.0", - "vite-node": "3.1.1", - "why-is-node-running": "^2.3.0" - }, - "bin": { - "vitest": "vitest.mjs" - }, - "devDependencies": { - "@ampproject/remapping": "^2.3.0", - "@antfu/install-pkg": "^1.0.0", - "@edge-runtime/vm": "^5.0.0", - "@sinonjs/fake-timers": "14.0.0", - "@types/debug": "^4.1.12", - "@types/estree": "^1.0.7", - "@types/istanbul-lib-coverage": "^2.0.6", - "@types/istanbul-reports": "^3.0.4", - "@types/jsdom": "^21.1.7", - "@types/micromatch": "^4.0.9", - "@types/node": "^22.13.13", - "@types/prompts": "^2.4.9", - "@types/sinonjs__fake-timers": "^8.1.5", - "acorn-walk": "^8.3.4", - "birpc": "0.2.19", - "cac": "^6.7.14", - "chai-subset": "^1.6.0", - "find-up": "^6.3.0", - "flatted": "^3.3.3", - "get-tsconfig": "^4.10.0", - "happy-dom": "^17.4.4", - "jsdom": "^26.0.0", - "local-pkg": "^1.1.1", - "micromatch": "^4.0.8", - "pretty-format": "^29.7.0", - "prompts": "^2.4.2", - "strip-literal": "^3.0.0", - "tinyglobby": "^0.2.12", - "ws": "^8.18.1" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22.0.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "@edge-runtime/vm": "*", - "@types/debug": "^4.1.12", - "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "3.1.1", - "@vitest/ui": "3.1.1", - "happy-dom": "*", - "jsdom": "*" - }, - "peerDependenciesMeta": { - "@edge-runtime/vm": { - "optional": true - }, - "@types/debug": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitest/browser": { - "optional": true - }, - "@vitest/ui": { - "optional": true - }, - "happy-dom": { - "optional": true - }, - "jsdom": { - "optional": true - } - } - }, - "../../node_modules/.pnpm/zod@3.24.3/node_modules/zod": { - "version": "3.24.3", - "license": "MIT", - "devDependencies": { - "@babel/core": "^7.22.5", - "@babel/preset-env": "^7.22.5", - "@babel/preset-typescript": "^7.22.5", - "@jest/globals": "^29.4.3", - "@rollup/plugin-typescript": "^8.2.0", - "@standard-schema/spec": "^1.0.0-beta.4", - "@swc/core": "^1.3.66", - "@swc/jest": "^0.2.26", - "@types/benchmark": "^2.1.0", - "@types/jest": "^29.2.2", - "@types/node": "14", - "@typescript-eslint/eslint-plugin": "^5.15.0", - "@typescript-eslint/parser": "^5.15.0", - "babel-jest": "^29.5.0", - "benchmark": "^2.1.4", - "dependency-cruiser": "^9.19.0", - "eslint": "^8.11.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-ban": "^1.6.0", - "eslint-plugin-import": "^2.25.4", - "eslint-plugin-simple-import-sort": "^7.0.0", - "eslint-plugin-unused-imports": "^2.0.0", - "husky": "^7.0.4", - "jest": "^29.3.1", - "lint-staged": "^12.3.7", - "netlify-cli": "^17.26.2", - "nodemon": "^2.0.15", - "prettier": "^2.6.0", - "pretty-quick": "^3.1.3", - "rollup": "^2.70.1", - "ts-jest": "^29.1.0", - "ts-morph": "^14.0.0", - "ts-node": "^10.9.1", - "tslib": "^2.3.1", - "tsx": "^3.8.0", - "typescript": "^5.0.0", - "vitest": "^0.32.2" - }, - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/@hono/node-server": { - "resolved": "../../node_modules/.pnpm/@hono+node-server@1.14.1_hono@4.7.7/node_modules/@hono/node-server", - "link": true - }, - "node_modules/@types/node": { - "resolved": "../../node_modules/.pnpm/@types+node@22.14.1/node_modules/@types/node", - "link": true - }, - "node_modules/dotenv": { - "resolved": "../../node_modules/.pnpm/dotenv@16.5.0/node_modules/dotenv", - "link": true - }, - "node_modules/hono": { - "resolved": "../../node_modules/.pnpm/hono@4.7.7/node_modules/hono", - "link": true - }, - "node_modules/tsx": { - "resolved": "../../node_modules/.pnpm/tsx@4.19.3/node_modules/tsx", - "link": true - }, - "node_modules/viem": { - "resolved": "../../node_modules/.pnpm/viem@2.27.2_bufferutil@4.0.9_typescript@5.8.3_utf-8-validate@5.0.10_zod@3.24.3/node_modules/viem", - "link": true - }, - "node_modules/x402": { - "resolved": "../../../../typescript/packages/x402", - "link": true - } - } -} \ No newline at end of file diff --git a/examples/typescript/legacy/clients/chainlink-vrf-nft/package.json b/examples/typescript/legacy/clients/chainlink-vrf-nft/package.json deleted file mode 100644 index 08a41c3f2b..0000000000 --- a/examples/typescript/legacy/clients/chainlink-vrf-nft/package.json +++ /dev/null @@ -1,24 +0,0 @@ -{ - "name": "vrfnft-example", - "version": "0.1.0", - "private": true, - "description": "Example demonstrating x402 payment for NFT minting", - "type": "module", - "scripts": { - "resource": "tsx resource.ts", - "client": "tsx client.ts" - }, - "dependencies": { - "dotenv": "^16.4.5", - "hono": "^4.7.2", - "@hono/node-server": "^1.13.8", - "viem": "^2.23.5", - "x402": "workspace:*", - "axios": "^1.7.9", - "x402-axios": "workspace:*" - }, - "devDependencies": { - "tsx": "^4.19.3", - "@types/node": "^22.13.5" - } -} \ No newline at end of file diff --git a/examples/typescript/legacy/clients/chainlink-vrf-nft/resource.ts b/examples/typescript/legacy/clients/chainlink-vrf-nft/resource.ts deleted file mode 100644 index 184908ba0a..0000000000 --- a/examples/typescript/legacy/clients/chainlink-vrf-nft/resource.ts +++ /dev/null @@ -1,287 +0,0 @@ -import dotenv from "dotenv"; -import path from "node:path"; -import { fileURLToPath } from "node:url"; -import { Buffer } from "node:buffer"; -import axios from "axios"; -import { serve } from "@hono/node-server"; -import { Hono } from "hono"; -import { logger } from "hono/logger"; -import { createWalletClient, http, publicActions, Hex, parseAbiItem, parseEther } from "viem"; -import { privateKeyToAccount } from "viem/accounts"; -import { baseSepolia } from "viem/chains"; - -// --- Types for Payment Handling --- -type PaymentDetails = { - scheme: string; - network: string; - maxAmountRequired: string; // Amount in wei - resource: string; - description: string; - mimeType: string; - payTo: Hex; - asset: Hex; - maxTimeoutSeconds: number; - outputSchema: object; - extra: object; -}; - -type ExactEvmPayload = { - signature: Hex; - authorization: { - from: Hex; - to: Hex; - value: string; - validAfter: string; - validBefore: string; - nonce: Hex; - version: string; - }; -}; - -type XPaymentHeader = { - x402Version: number; - scheme: string; - network?: string; // Expecting network name from x402-axios - networkId?: string; // Keep for type flexibility, but validation uses network - payload: ExactEvmPayload; - resource: string; -}; -// --------------------------- - -// --- Load .env --- -const __filename_env = fileURLToPath(import.meta.url); -const __dirname_env = path.dirname(__filename_env); -const envPath = path.resolve(__dirname_env, "./.env"); -dotenv.config({ path: envPath }); -// --------------------------- - -// --- Environment Variable Checks --- -let resourceServerPrivateKey = process.env.PRIVATE_KEY; -// if not prefixed, add 0x as prefix -if (resourceServerPrivateKey && !resourceServerPrivateKey.startsWith("0x")) { - resourceServerPrivateKey = "0x" + resourceServerPrivateKey; -} - -const providerUrl = process.env.PROVIDER_URL; - -if (!resourceServerPrivateKey || !providerUrl) { - console.error("Missing PRIVATE_KEY or PROVIDER_URL in .env file"); - process.exit(1); -} -// ---------------------------------------- - -// --- Constants and Setup --- -const PORT = 4023; -const FACILITATOR_PORT = 3000; -const FACILITATOR_URL = `http://localhost:${FACILITATOR_PORT}`; -const NFT_CONTRACT_ADDRESS = "0xcD8841f9a8Dbc483386fD80ab6E9FD9656Da39A2" as Hex; -const USDC_CONTRACT_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" as Hex; // Base Sepolia USDC -const REQUIRED_USDC_PAYMENT = "50000"; // 0.05 USDC (50000 wei, assuming 6 decimals) -const PAYMENT_RECIPIENT_ADDRESS = "0x52eE5a881287486573cF5CB5e7E7D92F30b03014" as Hex; // TODO @dev - put in your second wallet address as Resource server wallet -const MINT_ETH_VALUE_STR = "0.01"; // Estimated ETH needed for VRF fee -const SCHEME = "exact"; - -// --- Viem Client for Resource Server --- -const resourceServerAccount = privateKeyToAccount(resourceServerPrivateKey as Hex); -const resourceServerWalletClient = createWalletClient({ - account: resourceServerAccount, - chain: baseSepolia, - transport: http(providerUrl), -}).extend(publicActions); - -// --- NFT Contract ABI --- -const nftContractAbi = [ - parseAbiItem( - "function requestNFT(address _recipient) external payable returns (uint256 requestId)", - ), -]; - -// --- Payment Details object (matching PaymentRequirementsSchema) --- -// This format is needed for both the 402 response (for x402-axios) -// and the facilitator calls (for its internal validation). -const paymentDetailsRequired: PaymentDetails = { - scheme: SCHEME, - network: baseSepolia.network, // Use network name string - maxAmountRequired: REQUIRED_USDC_PAYMENT, - resource: `http://localhost:${PORT}/request-mint`, - description: "Request to mint a VRF NFT", - mimeType: "application/json", - payTo: PAYMENT_RECIPIENT_ADDRESS, - maxTimeoutSeconds: 60, - asset: USDC_CONTRACT_ADDRESS, - outputSchema: {}, - extra: { - name: "", - version: "2" - }, -}; - -// --- Hono App --- -const app = new Hono(); -app.use("*", logger()); - -// --- POST /request-mint Endpoint --- -app.post("/request-mint", async c => { - console.log("INFO ResourceServer: Received POST /request-mint"); - const paymentHeaderBase64 = c.req.header("X-PAYMENT"); - - // 1. Return 402 if no payment header as per the x402 spec. - if (!paymentHeaderBase64) { - console.log("INFO ResourceServer: No X-PAYMENT header found. Responding 402."); - console.info("Resource Server sent back: ", { - x402Version: 1, - accepts: [paymentDetailsRequired], - error: "Payment required", - }); - // Use the single, correctly formatted details object - return c.json( - { x402Version: 1, accepts: [paymentDetailsRequired], error: "Payment required" }, - 402, - ); - } - - // 2. Decode Payment Header - let paymentHeader: XPaymentHeader; - try { - const paymentHeaderJson = Buffer.from(paymentHeaderBase64, "base64").toString("utf-8"); - paymentHeader = JSON.parse(paymentHeaderJson); - console.log("DEBUG: Decoded X-PAYMENT header:", JSON.stringify(paymentHeader, null, 2)); // Log the decoded payment header - // Basic validation - check network name now - if ( - paymentHeader.scheme !== SCHEME || - paymentHeader.network !== baseSepolia.network || - !paymentHeader.payload?.authorization?.from - ) { - throw new Error("Invalid or incomplete payment header content."); - } - } catch (err: any) { - console.error("ERROR ResourceServer: Error decoding/parsing X-PAYMENT header:", err); - return c.json({ error: "Invalid payment header format.", details: err.message }, 400); - } - - // >>> Decode payment header for facilitator calls <<< - // Note @dev : This should technically be caught by the previous block, but as a safeguard: - let decodedPaymentPayload: XPaymentHeader; - try { - const paymentHeaderJson = Buffer.from(paymentHeaderBase64, "base64").toString("utf-8"); - // We could validate this against PaymentPayloadSchema here, but facilitator also validates - decodedPaymentPayload = JSON.parse(paymentHeaderJson); - } catch (err: any) { - console.error( - "ERROR ResourceServer: Double-check failed on decoding/parsing X-PAYMENT header:", - err, - ); - return c.json( - { error: "Invalid payment header format (internal parse).", details: err.message }, - 400, - ); - } - - // 3. Verify Payment with Facilitator - try { - console.log(`INFO ResourceServer: Verifying payment with Facilitator at ${FACILITATOR_URL}...`); - // Send the single, correctly formatted details object - const verifyResponse = await axios.post(`${FACILITATOR_URL}/verify`, { - paymentPayload: decodedPaymentPayload, - paymentRequirements: paymentDetailsRequired, - }); - const verificationResult: { isValid: boolean; invalidReason: string | null } = - verifyResponse.data; - console.log("INFO ResourceServer: Facilitator /verify response:", verificationResult); - if (!verificationResult?.isValid) { - console.log("INFO ResourceServer: Payment verification failed. Responding 402."); - // Use the single, correctly formatted details object - return c.json( - { - x402Version: 1, - accepts: [paymentDetailsRequired], - error: "Payment verification failed.", - details: verificationResult?.invalidReason || "Unknown", - }, - 402, - ); - } - } catch (err: any) { - console.error( - "ERROR ResourceServer: Error calling facilitator /verify:", - err.response?.data || err.message, - ); - return c.json({ error: "Facilitator verification call failed." }, 500); - } - - // 4. Mint NFT (Verification Passed) - const recipientAddress = decodedPaymentPayload.payload.authorization.from; - let mintTxHash: Hex | null = null; - try { - console.log( - `INFO ResourceServer: Initiating NFT mint for ${recipientAddress} on contract ${NFT_CONTRACT_ADDRESS}...`, - ); - mintTxHash = await resourceServerWalletClient.writeContract({ - address: NFT_CONTRACT_ADDRESS, - abi: nftContractAbi, - functionName: "requestNFT", - args: [recipientAddress], - value: parseEther(MINT_ETH_VALUE_STR), // Include estimated ETH value - }); - console.log(`INFO ResourceServer: NFT Mint transaction sent: ${mintTxHash}`); - } catch (err: any) { - console.error("ERROR ResourceServer: Error sending NFT mint transaction:", err); - return c.json({ error: "Failed to initiate NFT minting.", details: err.message }, 500); - } - - // 5. Settle Payment with Facilitator - let settlementResult: { success: boolean; error: string | null; txHash: Hex | null } = { - success: false, - error: "Settlement not attempted", - txHash: null, - }; - try { - console.log(`INFO ResourceServer: Settling payment with Facilitator at ${FACILITATOR_URL}...`); - // Send the single, correctly formatted details object - const settleResponse = await axios.post(`${FACILITATOR_URL}/settle`, { - paymentPayload: decodedPaymentPayload, - paymentRequirements: paymentDetailsRequired, - }); - settlementResult = settleResponse.data; - console.log("INFO ResourceServer: Facilitator /settle response:", settlementResult); - if (!settlementResult?.success) { - console.error("WARN ResourceServer: Facilitator settlement failed:", settlementResult?.error); - } - } catch (err: any) { - // Log settlement error but don't necessarily fail the request for the client - console.error( - "ERROR ResourceServer: Error calling facilitator /settle:", - err.response?.data || err.message, - ); - } - - // 6. Respond to Client - console.log("INFO ResourceServer: Responding 200 OK to client."); - return c.json({ - message: "NFT mint request initiated successfully.", - nftMintTxHash: mintTxHash, - }); -}); - -// --- Fallback Handler --- -// Catches any requests not matching defined routes -app.all("*", c => { - console.log( - `INFO ResourceServer: Received ${c.req.method} on unhandled path ${c.req.url}. Responding 404.`, - ); - return c.json({ error: "Not Found" }, 404); -}); - -// --- Start Server --- -console.log(`VRF NFT Resource Server running on port ${PORT}`); -console.log(` - Resource Server Wallet: ${resourceServerAccount.address}`); -console.log(` - NFT Contract: ${NFT_CONTRACT_ADDRESS}`); -console.log( - ` - Payment Required: ${REQUIRED_USDC_PAYMENT} wei USDC (${USDC_CONTRACT_ADDRESS}) to ${PAYMENT_RECIPIENT_ADDRESS}`, -); -console.log(` - Facilitator URL: ${FACILITATOR_URL}`); - -serve({ - port: PORT, - fetch: app.fetch, -}); diff --git a/examples/typescript/legacy/clients/fetch/.env-local b/examples/typescript/legacy/clients/fetch/.env-local deleted file mode 100644 index 3d2e1855d1..0000000000 --- a/examples/typescript/legacy/clients/fetch/.env-local +++ /dev/null @@ -1,3 +0,0 @@ -RESOURCE_SERVER_URL=http://localhost:4021 -ENDPOINT_PATH=/weather -PRIVATE_KEY= diff --git a/examples/typescript/legacy/clients/fetch/README.md b/examples/typescript/legacy/clients/fetch/README.md deleted file mode 100644 index f04ed55166..0000000000 --- a/examples/typescript/legacy/clients/fetch/README.md +++ /dev/null @@ -1,75 +0,0 @@ -# x402-fetch Example Client - -This is an example client that demonstrates how to use the `x402-fetch` package to make HTTP requests to endpoints protected by the x402 payment protocol. - -## Prerequisites - -- Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) -- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- A running x402 server (you can use the example express server at `examples/typescript/servers/express`) -- A valid Ethereum private key for making payments - -## Setup - -1. Install and build all packages from the typescript examples root: -```bash -cd ../../ -pnpm install -pnpm build -cd clients/fetch -``` - -2. Copy `.env-local` to `.env` and add your Ethereum private key: -```bash -cp .env-local .env -``` - -3. Start the example client: -```bash -pnpm dev -``` - -## How It Works - -The example demonstrates how to: -1. Create a wallet client using viem -2. Wrap the native fetch function with x402 payment handling -3. Make a request to a paid endpoint -4. Handle the response or any errors - -## Example Code - -```typescript -import { config } from "dotenv"; -import { createWalletClient, http } from "viem"; -import { privateKeyToAccount } from "viem/accounts"; -import { wrapFetchWithPayment } from "x402-fetch"; -import { baseSepolia } from "viem/chains"; - -config(); - -const { RESOURCE_SERVER_URL, PRIVATE_KEY, ENDPOINT_PATH } = process.env; - -// Create wallet client -const account = privateKeyToAccount(PRIVATE_KEY as `0x${string}`); -const client = createWalletClient({ - account, - transport: http(), - chain: baseSepolia, -}); - -// Wrap fetch with payment handling -const fetchWithPay = wrapFetchWithPayment(fetch, client); - -// Make request to paid endpoint -fetchWithPay(`${RESOURCE_SERVER_URL}${ENDPOINT_PATH}`, { - method: "GET", -}) - .then(async response => { - const body = await response.json(); - console.log(body); - }) - .catch(error => { - console.error(error.response?.data?.error); - }); -``` diff --git a/examples/typescript/legacy/clients/fetch/index.ts b/examples/typescript/legacy/clients/fetch/index.ts deleted file mode 100644 index 2ec6075729..0000000000 --- a/examples/typescript/legacy/clients/fetch/index.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { config } from "dotenv"; -import { decodeXPaymentResponse, wrapFetchWithPayment, createSigner, type Hex } from "x402-fetch"; - -config(); - -const privateKey = process.env.PRIVATE_KEY as Hex | string; -const baseURL = process.env.RESOURCE_SERVER_URL as string; // e.g. https://example.com -const endpointPath = process.env.ENDPOINT_PATH as string; // e.g. /weather -const url = `${baseURL}${endpointPath}`; // e.g. https://example.com/weather - -if (!baseURL || !privateKey || !endpointPath) { - console.error("Missing required environment variables"); - process.exit(1); -} - -/** - * This example shows how to use the x402-fetch package to make a request to a resource server that requires a payment. - * - * To run this example, you need to set the following environment variables: - * - PRIVATE_KEY: The private key of the signer - * - RESOURCE_SERVER_URL: The URL of the resource server - * - ENDPOINT_PATH: The path of the endpoint to call on the resource server - */ -async function main(): Promise { - // const signer = await createSigner("solana-devnet", privateKey); // uncomment for solana - const signer = await createSigner("base-sepolia", privateKey); - const fetchWithPayment = wrapFetchWithPayment(fetch, signer); - - const response = await fetchWithPayment(url, { method: "GET" }); - const body = await response.json(); - console.log(body); - - const paymentResponseHeader = response.headers.get("x-payment-response"); - if (paymentResponseHeader) { - const paymentResponse = decodeXPaymentResponse(paymentResponseHeader); - console.log(paymentResponse); - } -} - -main().catch(error => { - console.error(error?.response?.data?.error ?? error); - process.exit(1); -}); diff --git a/examples/typescript/legacy/clients/fetch/multi-network-signer.ts b/examples/typescript/legacy/clients/fetch/multi-network-signer.ts deleted file mode 100644 index 9c6ca2de47..0000000000 --- a/examples/typescript/legacy/clients/fetch/multi-network-signer.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { config } from "dotenv"; -import { - decodeXPaymentResponse, - wrapFetchWithPayment, - createSigner, - type Hex, - type MultiNetworkSigner, -} from "x402-fetch"; - -config(); - -const evmPrivateKey = process.env.EVM_PRIVATE_KEY as Hex; -const svmPrivateKey = process.env.SVM_PRIVATE_KEY as string; -const baseURL = process.env.RESOURCE_SERVER_URL as string; // e.g. https://example.com -const endpointPath = process.env.ENDPOINT_PATH as string; // e.g. /weather -const url = `${baseURL}${endpointPath}`; // e.g. https://example.com/weather - -if (!baseURL || !evmPrivateKey || !svmPrivateKey || !endpointPath) { - console.error("Missing required environment variables"); - process.exit(1); -} - -/** - * This example shows how to use the x402-fetch package to make a request to a resource server that requires a payment. - * - * To run this example, you need to set the following environment variables: - * - PRIVATE_KEY: The private key of the signer - * - RESOURCE_SERVER_URL: The URL of the resource server - * - ENDPOINT_PATH: The path of the endpoint to call on the resource server - */ -async function main(): Promise { - const evmSigner = await createSigner("base-sepolia", evmPrivateKey); - const svmSigner = await createSigner("solana-devnet", svmPrivateKey); - const signer = { evm: evmSigner, svm: svmSigner } as MultiNetworkSigner; - const fetchWithPayment = wrapFetchWithPayment(fetch, signer); - - const response = await fetchWithPayment(url, { method: "GET" }); - const body = await response.json(); - console.log(body); - - const paymentResponse = decodeXPaymentResponse(response.headers.get("x-payment-response")!); - console.log(paymentResponse); -} - -main().catch(error => { - console.error(error?.response?.data?.error ?? error); - process.exit(1); -}); diff --git a/examples/typescript/legacy/clients/fetch/package.json b/examples/typescript/legacy/clients/fetch/package.json deleted file mode 100644 index 99cfcda3e0..0000000000 --- a/examples/typescript/legacy/clients/fetch/package.json +++ /dev/null @@ -1,29 +0,0 @@ -{ - "name": "fetch-client-example", - "private": true, - "type": "module", - "scripts": { - "dev": "tsx index.ts", - "dev:multi-network-signer": "tsx multi-network-signer.ts", - "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", - "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", - "lint": "eslint . --ext .ts --fix", - "lint:check": "eslint . --ext .ts" - }, - "dependencies": { - "dotenv": "^16.4.7", - "x402-fetch": "workspace:*" - }, - "devDependencies": { - "@eslint/js": "^9.24.0", - "@typescript-eslint/eslint-plugin": "^8.29.1", - "@typescript-eslint/parser": "^8.29.1", - "eslint": "^9.24.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", - "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" - } -} diff --git a/examples/typescript/legacy/dynamic_agent/.env-local b/examples/typescript/legacy/dynamic_agent/.env-local deleted file mode 100644 index e65f662af3..0000000000 --- a/examples/typescript/legacy/dynamic_agent/.env-local +++ /dev/null @@ -1,5 +0,0 @@ -WEATHER_API_KEY="get from weatherapi.com" -PRIVATE_KEY="generate with viem or cast" -MARKETSTACK_API_KEY="get from marketstack.com" -ANTHROPIC_API_KEY="get from anthropic.com" -PAY_TO_ADDRESS="0xYourAddress" diff --git a/examples/typescript/legacy/dynamic_agent/.gitignore b/examples/typescript/legacy/dynamic_agent/.gitignore deleted file mode 100644 index 79829eefbc..0000000000 --- a/examples/typescript/legacy/dynamic_agent/.gitignore +++ /dev/null @@ -1 +0,0 @@ -proxies/proxy diff --git a/examples/typescript/legacy/dynamic_agent/README.md b/examples/typescript/legacy/dynamic_agent/README.md deleted file mode 100644 index f01a9c1c6b..0000000000 --- a/examples/typescript/legacy/dynamic_agent/README.md +++ /dev/null @@ -1,128 +0,0 @@ -# Dynamic Agent - -This example demonstrates an agent that can perform multi-tool tasks, without prior knowledge of the tools available to it. Each tool is paid for on a per-request basis using x402. - -## Run - -(All steps run from `examples/typescript/dynamic_agent`) - -1. Install dependencies - -```bash -pnpm install -``` - -2. Configure environment variables - -```bash -cp .env-local .env -``` - -Follow instructions in `.env` to get required API keys to proxy (they're all free). -Add your Ethereum development private key to `.env` (remember it should have USDC on Base Sepolia, which you can provision using the [CDP Faucet](https://portal.cdp.coinbase.com/products/faucet)): - -3. Start index server - -This server mocks an index of tools that an agent may access via http. - -``` -pnpm run index-server -``` - -4. Run the agent - -In a new terminal, run - -``` -pnpm run agent -``` - -You should see the agent query the index server to see what tools are available, then pay to use several tools. -Then in the agent's terminal you should see something like: - -``` -Available Resources: [ - { - resourceUrl: 'http://localhost:4021/weather', - resourceDescription: "Returns the 7 day forecast for weather in a city. Must include city as a query parameter escaped properly to be url safe (ex: 'http://localhost:4021/weather?city=London')", - price: { amount: 0.01, currency: 'USD' } - }, - { - resourceUrl: 'http://localhost:4021/stock', - resourceDescription: "Returns the last 5 days of stock data for a given stock symbol. Must include symbol as a query parameter escaped properly to be url safe (ex: 'http://localhost:4021/stock?symbol=AAPL')", - price: { amount: 0.05, currency: 'USD' } - } -] -Making http call to http://localhost:4021/weather?city=San%20Francisco -Making http call to http://localhost:4021/stock?symbol=SPY -StopEvent { - data: { - result: "Based on the current weather in San Francisco (partly cloudy with a temperature of 60.1°F) and the SPY stock price (which closed at $566.76 today), here's a weather and stock market pun:\n" + - '\n' + - '"The market is looking partly BULL-dy today, with SPY reaching new heights while San Francisco stays in the COLDateral damage of mild temperatures!"\n' + - '\n' + - 'This pun combines:\n' + - '1. "Partly cloudy" weather condition with "partly BULL-dy" (playing on bullish market)\n' + - '2. "COLDateral" combines the cool temperature with "collateral"\n' + - '3. References both the high stock price and mild weather conditions' - }, - displayName: 'StopEvent' -} -``` - -## How it works - -The agent has 2 generic tools, neither of which are directly related to the task to perform: - -```typescript -const indexTool = tool( - async () => { - const response = await axiosWithPayment.get("http://localhost:4021/"); - const data = await response.data; - console.log("Available Resources:", data); - return data; - }, - { - name: "api-index", - description: - "Returns to you a list of all the APIs available for you to access", - parameters: z.object({}), - } -); - -const httpTool = tool( - async ({ url }: { url: string }) => { - console.log("Making http call to", url); - const response = await axiosWithPayment.get(url); - const data = await response.data; - return data; - }, - { - name: "make-http-request", - description: "Allows you to make http calls to different APIs", - parameters: z.object({ - url: z.string({ description: "The URL of the API to call" }), - }), - } -); - -const bot = agent({ - llm, - tools: [indexTool, httpTool], - timeout: 100000, -}); -``` - -`indexTool` makes a call to the index and receives a list of available tools, `httpTool` allows the agent to pay for http requests via x402. - -With these 2 tools and a small system prompt, the agent can now dynamically perform tasks with tools without tools being known to it ahead of time in code. - -```typescript -const response = await bot.run(` - You are a helpful assistant. You have access to an index of APIs you can use to dynamically get data. - - Make a pun based on the weather in San Francisco and the price of SPY -`); - -console.log(response); -``` diff --git a/examples/typescript/legacy/dynamic_agent/agent.ts b/examples/typescript/legacy/dynamic_agent/agent.ts deleted file mode 100644 index 57e5a74344..0000000000 --- a/examples/typescript/legacy/dynamic_agent/agent.ts +++ /dev/null @@ -1,70 +0,0 @@ -/** Dynamic Agent - * Example of an agent that has dynamic, discoverable tools, enabled by x402 payments. - */ -import axios from "axios"; -import { withPaymentInterceptor } from "x402-axios"; -import { baseSepolia } from "viem/chains"; -import { privateKeyToAccount } from "viem/accounts"; -import { http, publicActions, createWalletClient } from "viem"; -import { Hex } from "viem"; -import { Anthropic } from "@llamaindex/anthropic"; -import { agent, tool } from "llamaindex"; -import { z } from "zod"; - -const wallet = createWalletClient({ - chain: baseSepolia, - transport: http(), - account: privateKeyToAccount(process.env.PRIVATE_KEY as Hex), -}).extend(publicActions); - -const axiosWithPayment = withPaymentInterceptor(axios.create({}), wallet); - -const llm = new Anthropic({ - apiKey: process.env.ANTHROPIC_API_KEY, - model: "claude-3-5-sonnet-20241022", -}); - -const indexTool = tool( - async () => { - const response = await axiosWithPayment.get("http://localhost:4021/"); - const data = await response.data; - console.log("Available Resources:", data); - return data; - }, - { - name: "api-index", - description: - "Returns to you a list of all the APIs available for you to access", - parameters: z.object({}), - } -); - -const httpTool = tool( - async ({ url }: { url: string }) => { - console.log("Making http call to", url); - const response = await axiosWithPayment.get(url); - const data = await response.data; - return data; - }, - { - name: "make-http-request", - description: "Allows you to make http calls to different APIs", - parameters: z.object({ - url: z.string({ description: "The URL of the API to call" }), - }), - } -); - -const bot = agent({ - llm, - tools: [indexTool, httpTool], - timeout: 100000, -}); - -const response = await bot.run(` - You are a helpful assistant. You have access to an index of APIs you can use to dynamically get data. - - Make a pun based on the weather in San Francisco and the price of SPY -`); - -console.log(response); diff --git a/examples/typescript/legacy/dynamic_agent/discover_server.ts b/examples/typescript/legacy/dynamic_agent/discover_server.ts deleted file mode 100644 index c44430207d..0000000000 --- a/examples/typescript/legacy/dynamic_agent/discover_server.ts +++ /dev/null @@ -1,95 +0,0 @@ -/** This file is a server that proxies a few services and serves an index with descriptions of the resources available. - * - * - * - */ - -import { Hono } from "hono"; -import { serve } from "@hono/node-server"; -import { logger } from "hono/logger"; -import { paymentMiddleware } from "x402-hono"; - -const app = new Hono(); -const port = 4021; -app.use("*", logger()); - -type IndexEntry = { - resourceUrl: string; - resourceDescription: string; - price: { - amount: number; - currency: string; - }; -}; - -app.use( - paymentMiddleware(process.env.PAY_TO_ADDRESS as `0x${string}`, { - "/weather": "$0.01", - "/stock": "$0.05", - }) -); - -app.get("/", (c) => { - const resources: IndexEntry[] = [ - { - resourceUrl: "http://localhost:4021/weather", - resourceDescription: - "Returns the 7 day forecast for weather in a city. Must include city as a query parameter escaped properly to be url safe (ex: 'http://localhost:4021/weather?city=London')", - price: { - amount: 0.01, - currency: "USD", - }, - }, - { - resourceUrl: "http://localhost:4021/stock", - resourceDescription: - "Returns the last 5 days of stock data for a given stock symbol. Must include symbol as a query parameter escaped properly to be url safe (ex: 'http://localhost:4021/stock?symbol=AAPL')", - price: { - amount: 0.05, - currency: "USD", - }, - }, - ]; - return c.json(resources); -}); - - -app.get("/weather", async (c) => { - const city = c.req.query("city"); - console.log("City", city); - const url = `http://api.weatherapi.com/v1/forecast.json?key=${process.env.WEATHER_API_KEY}&q=${city}&days=7`; - - const response = await fetch(url); - const data = await response.json(); - - return c.json(data); -}); - - -app.get("/stock", async (c) => { - const symbol = c.req.query("symbol")?.toUpperCase(); - if (!symbol) { - return c.json({ error: "Symbol is required" }, 400); - } - const url = `https://api.marketstack.com/v2/eod?access_key=${process.env.MARKETSTACK_API_KEY}&symbols=${symbol}`; - const response = await fetch(url); - const data = await response.json(); - const last5Days = data.data.slice(0, 5); - const last5DaysWithPrices = last5Days.map((day) => ({ - open: day.open, - close: day.close, - high: day.high, - low: day.low, - volume: day.volume, - date: day.date, - symbol: day.symbol, - })); - return c.json(last5DaysWithPrices); -}); - -console.log(`Resource running on port ${port}`); - -serve({ - port: port, - fetch: app.fetch, -}); diff --git a/examples/typescript/legacy/dynamic_agent/package-lock.json b/examples/typescript/legacy/dynamic_agent/package-lock.json deleted file mode 100644 index fc6c56ed9f..0000000000 --- a/examples/typescript/legacy/dynamic_agent/package-lock.json +++ /dev/null @@ -1,1610 +0,0 @@ -{ - "name": "dynamic_agent", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "dynamic_agent", - "version": "1.0.0", - "license": "ISC", - "dependencies": { - "@anthropic-ai/sdk": "^0.39.0", - "@hono/node-server": "^1.14.1", - "@llamaindex/anthropic": "^0.3.3", - "hono": "^4.7.7", - "llamaindex": "^0.10.2", - "x402": "file:../../packages/typescript/x402", - "zod": "^3.24.3" - } - }, - "../../packages/typescript/x402": { - "version": "0.1.2", - "license": "Apache-2.0", - "dependencies": { - "@hono/node-server": "^1.13.8", - "axios": "^1.7.9", - "express": "^4.18.2", - "hono": "^4.7.1", - "viem": "^2.23.1", - "zod": "^3.24.2" - }, - "devDependencies": { - "@types/express": "^4.17.21", - "@types/node": "^22.13.4", - "prettier": "3.5.2", - "tsx": "^4.19.2", - "typescript": "^5.7.3", - "vite-tsconfig-paths": "^5.1.4", - "vitest": "^3.0.5" - } - }, - "node_modules/@anthropic-ai/sdk": { - "version": "0.39.0", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.39.0.tgz", - "integrity": "sha512-eMyDIPRZbt1CCLErRCi3exlAvNkBtRe+kW5vvJyef93PmNr/clstYgHhtvmkxN82nlKgzyGPCyGxrm0JQ1ZIdg==", - "license": "MIT", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" - } - }, - "node_modules/@aws-crypto/sha256-js": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", - "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", - "license": "Apache-2.0", - "dependencies": { - "@aws-crypto/util": "^5.2.0", - "@aws-sdk/types": "^3.222.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=16.0.0" - } - }, - "node_modules/@aws-crypto/util": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", - "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", - "license": "Apache-2.0", - "dependencies": { - "@aws-sdk/types": "^3.222.0", - "@smithy/util-utf8": "^2.0.0", - "tslib": "^2.6.2" - } - }, - "node_modules/@aws-sdk/types": { - "version": "3.775.0", - "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.775.0.tgz", - "integrity": "sha512-ZoGKwa4C9fC9Av6bdfqcW6Ix5ot05F/S4VxWR2nHuMv7hzfmAjTOcUiWT7UR4hM/U0whf84VhDtXN/DWAk52KA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/types": "^4.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@hono/node-server": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.14.1.tgz", - "integrity": "sha512-vmbuM+HPinjWzPe7FFPWMMQMsbKE9gDPhaH0FFdqbGpkT5lp++tcWDTxwBl5EgS5y6JVgIaCdjeHRfQ4XRBRjQ==", - "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@llamaindex/anthropic": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@llamaindex/anthropic/-/anthropic-0.3.3.tgz", - "integrity": "sha512-rdTsuDr4N8+aw1dF0TqcZTzZs3RoYlsI94mLcKAyn3rHxVOA2PC2ki2kf5jms7KW8KjF+yBgB03hgNXq9ewOKg==", - "dependencies": { - "@anthropic-ai/sdk": "0.37.0", - "@llamaindex/core": "0.6.2", - "@llamaindex/env": "0.1.29", - "remeda": "^2.17.3" - } - }, - "node_modules/@llamaindex/anthropic/node_modules/@anthropic-ai/sdk": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.37.0.tgz", - "integrity": "sha512-tHjX2YbkUBwEgg0JZU3EFSSAQPoK4qQR/NFYa8Vtzd5UAyXzZksCw2In69Rml4R/TyHPBfRYaLK35XiOe33pjw==", - "license": "MIT", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" - } - }, - "node_modules/@llamaindex/cloud": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/@llamaindex/cloud/-/cloud-4.0.3.tgz", - "integrity": "sha512-pUHX8Ecs4WAXIoAcegPzuxz05SsufU5+HAdb9H/gowLB1rydQOJjk2CvBuzgQbbablmggvCBpt/tpdEZYOKd2w==", - "license": "MIT", - "peerDependencies": { - "@llamaindex/core": "0.6.2", - "@llamaindex/env": "0.1.29" - } - }, - "node_modules/@llamaindex/core": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/@llamaindex/core/-/core-0.6.2.tgz", - "integrity": "sha512-e0NH7X1C8yq9sCqj1Ys9jL9rITCXBKfZwmKnTHYxpXorPeuNmlFmuoogahJTwLNsILBDTOVAUexO88SqmAFUrA==", - "dependencies": { - "@llamaindex/env": "0.1.29", - "@types/node": "^22.9.0", - "magic-bytes.js": "^1.10.0", - "zod": "^3.23.8", - "zod-to-json-schema": "^3.23.3" - } - }, - "node_modules/@llamaindex/core/node_modules/@types/node": { - "version": "22.14.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz", - "integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/@llamaindex/core/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, - "node_modules/@llamaindex/env": { - "version": "0.1.29", - "resolved": "https://registry.npmjs.org/@llamaindex/env/-/env-0.1.29.tgz", - "integrity": "sha512-GoITt+QLDNIhu2i1sGsPH8tHH13Gxp4i4ofMFlefrHagytvF761MG7nvTAQVIqP9kxBYk4dnSQ3lQnVPFAfMZQ==", - "dependencies": { - "@aws-crypto/sha256-js": "^5.2.0", - "js-tiktoken": "^1.0.12", - "pathe": "^1.1.2" - }, - "peerDependencies": { - "@huggingface/transformers": "^3.0.2", - "gpt-tokenizer": "^2.5.0" - }, - "peerDependenciesMeta": { - "@huggingface/transformers": { - "optional": true - }, - "gpt-tokenizer": { - "optional": true - } - } - }, - "node_modules/@llamaindex/node-parser": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/@llamaindex/node-parser/-/node-parser-2.0.2.tgz", - "integrity": "sha512-pWqEfFRMW5TFzbDyEDWqhipR9P/HBF2C+pEeTroyRACZtKJLbeg3R3e2g4gmfnPxmxQIXkGn2UFK8Io4nwVNOg==", - "dependencies": { - "html-to-text": "^9.0.5" - }, - "peerDependencies": { - "@llamaindex/core": "0.6.2", - "@llamaindex/env": "0.1.29", - "tree-sitter": "^0.22.0", - "web-tree-sitter": "^0.24.3" - } - }, - "node_modules/@llamaindex/openai": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/@llamaindex/openai/-/openai-0.3.4.tgz", - "integrity": "sha512-LelkRYljVfasllJY1fNNOqud141ggqlEhHci+3O5kY92MLcSUMlJ5477kkpRdxA80su6sKfocu1dcwSARijWpA==", - "dependencies": { - "@llamaindex/core": "0.6.2", - "@llamaindex/env": "0.1.29", - "openai": "^4.90.0" - } - }, - "node_modules/@llamaindex/workflow": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@llamaindex/workflow/-/workflow-1.0.3.tgz", - "integrity": "sha512-GzYzLfn12BTQiLVwFr9tGl1Sa7PPVErLLQAJMgvfjUK8cv764SpJGqln8iKTxnKF05HcRrmJeE7ZD9Lzpf7UrA==", - "peerDependencies": { - "@llamaindex/core": "0.6.2", - "@llamaindex/env": "0.1.29", - "zod": "^3.23.8" - } - }, - "node_modules/@selderee/plugin-htmlparser2": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@selderee/plugin-htmlparser2/-/plugin-htmlparser2-0.11.0.tgz", - "integrity": "sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==", - "license": "MIT", - "dependencies": { - "domhandler": "^5.0.3", - "selderee": "^0.11.0" - }, - "funding": { - "url": "https://ko-fi.com/killymxi" - } - }, - "node_modules/@smithy/is-array-buffer": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", - "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/types": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.2.0.tgz", - "integrity": "sha512-7eMk09zQKCO+E/ivsjQv+fDlOupcFUCSC/L2YUPgwhvowVGWbPQHjEFcmjt7QQ4ra5lyowS92SV53Zc6XD4+fg==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@smithy/util-buffer-from": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", - "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/is-array-buffer": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@smithy/util-utf8": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", - "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", - "license": "Apache-2.0", - "dependencies": { - "@smithy/util-buffer-from": "^2.2.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@types/lodash": { - "version": "4.17.16", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.16.tgz", - "integrity": "sha512-HX7Em5NYQAXKW+1T+FiuG27NGwzJfCX3s1GjOa7ujxZa52kjJLOr4FUxT+giF6Tgxv1e+/czV/iTtBw27WTU9g==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "18.19.86", - "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.86.tgz", - "integrity": "sha512-fifKayi175wLyKyc5qUfyENhQ1dCNI1UNjp653d8kuYcPQN5JhX3dGuP/XmvPTg/xRBn1VTLpbmi+H/Mr7tLfQ==", - "license": "MIT", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", - "license": "MIT", - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "license": "MIT", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/agentkeepalive": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", - "license": "MIT", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/ajv": { - "version": "8.17.1", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.17.1.tgz", - "integrity": "sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/ansi-regex": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.1.0.tgz", - "integrity": "sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "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/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "license": "MIT" - }, - "node_modules/base64-js": { - "version": "1.5.1", - "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", - "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "license": "MIT" - }, - "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/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "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/dom-serializer": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", - "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.2", - "entities": "^4.2.0" - }, - "funding": { - "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" - } - }, - "node_modules/domelementtype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", - "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "BSD-2-Clause" - }, - "node_modules/domhandler": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", - "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", - "license": "BSD-2-Clause", - "dependencies": { - "domelementtype": "^2.3.0" - }, - "engines": { - "node": ">= 4" - }, - "funding": { - "url": "https://github.com/fb55/domhandler?sponsor=1" - } - }, - "node_modules/domutils": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", - "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", - "license": "BSD-2-Clause", - "dependencies": { - "dom-serializer": "^2.0.0", - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3" - }, - "funding": { - "url": "https://github.com/fb55/domutils?sponsor=1" - } - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, - "node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/entities": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", - "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", - "license": "BSD-2-Clause", - "engines": { - "node": ">=0.12" - }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-uri": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.0.6.tgz", - "integrity": "sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data-encoder": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", - "license": "MIT" - }, - "node_modules/formdata-node": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", - "license": "MIT", - "dependencies": { - "node-domexception": "1.0.0", - "web-streams-polyfill": "4.0.0-beta.3" - }, - "engines": { - "node": ">= 12.20" - } - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.1.tgz", - "integrity": "sha512-zrQDm8XPnYEKawJScsnM0QzobJxlT/kHOOlRTio8IH/GrmxRE5fjllkzdaHclIuNjUQTJYH2xHNIGfdpJkDJUw==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "license": "MIT", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "license": "MIT", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/hono": { - "version": "4.7.7", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.7.7.tgz", - "integrity": "sha512-2PCpQRbN87Crty8/L/7akZN3UyZIAopSoRxCwRbJgUuV1+MHNFHzYFxZTg4v/03cXUm+jce/qa2VSBZpKBm3Qw==", - "license": "MIT", - "engines": { - "node": ">=16.9.0" - } - }, - "node_modules/html-to-text": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/html-to-text/-/html-to-text-9.0.5.tgz", - "integrity": "sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==", - "license": "MIT", - "dependencies": { - "@selderee/plugin-htmlparser2": "^0.11.0", - "deepmerge": "^4.3.1", - "dom-serializer": "^2.0.0", - "htmlparser2": "^8.0.2", - "selderee": "^0.11.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/htmlparser2": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", - "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", - "funding": [ - "https://github.com/fb55/htmlparser2?sponsor=1", - { - "type": "github", - "url": "https://github.com/sponsors/fb55" - } - ], - "license": "MIT", - "dependencies": { - "domelementtype": "^2.3.0", - "domhandler": "^5.0.3", - "domutils": "^3.0.1", - "entities": "^4.4.0" - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "license": "MIT", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jackspeak": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.1.0.tgz", - "integrity": "sha512-9DDdhb5j6cpeitCbvLO7n7J4IxnbM6hoF6O1g4HQ5TfhvvKN8ywDM7668ZhMHRqVmxqhps/F6syWK2KcPxYlkw==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/js-tiktoken": { - "version": "1.0.19", - "resolved": "https://registry.npmjs.org/js-tiktoken/-/js-tiktoken-1.0.19.tgz", - "integrity": "sha512-XC63YQeEcS47Y53gg950xiZ4IWmkfMe4p2V9OSaBt26q+p47WHn18izuXzSclCI73B7yGqtfRsT6jcZQI0y08g==", - "license": "MIT", - "dependencies": { - "base64-js": "^1.5.1" - } - }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", - "license": "MIT" - }, - "node_modules/leac": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/leac/-/leac-0.6.0.tgz", - "integrity": "sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==", - "license": "MIT", - "funding": { - "url": "https://ko-fi.com/killymxi" - } - }, - "node_modules/llamaindex": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/llamaindex/-/llamaindex-0.10.2.tgz", - "integrity": "sha512-tUbb+HYaQ+WP1f4NrYnEOIgPPRUePh3sPnOf/wbxTYAyZTnREpSiwCfLUGgYOiIYKK5PS7Oo/eTZCP7jpi7gSA==", - "license": "MIT", - "dependencies": { - "@llamaindex/cloud": "4.0.3", - "@llamaindex/core": "0.6.2", - "@llamaindex/env": "0.1.29", - "@llamaindex/node-parser": "2.0.2", - "@llamaindex/openai": "0.3.4", - "@llamaindex/workflow": "1.0.3", - "@types/lodash": "^4.17.7", - "@types/node": "^22.9.0", - "ajv": "^8.17.1", - "lodash": "^4.17.21", - "magic-bytes.js": "^1.10.0" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/llamaindex/node_modules/@types/node": { - "version": "22.14.1", - "resolved": "https://registry.npmjs.org/@types/node/-/node-22.14.1.tgz", - "integrity": "sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==", - "license": "MIT", - "dependencies": { - "undici-types": "~6.21.0" - } - }, - "node_modules/llamaindex/node_modules/undici-types": { - "version": "6.21.0", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", - "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", - "license": "MIT" - }, - "node_modules/lodash": { - "version": "4.17.21", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", - "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", - "license": "MIT" - }, - "node_modules/lru-cache": { - "version": "11.1.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.1.0.tgz", - "integrity": "sha512-QIXZUBJUx+2zHUdQujWejBkcD9+cs94tLn0+YL8UrCh+D5sCXZ4c7LaEH48pNwRY3MLDgqUFyhlCyjJPf1WP0A==", - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/magic-bytes.js": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/magic-bytes.js/-/magic-bytes.js-1.11.0.tgz", - "integrity": "sha512-nVmadqN9gam80tdnn74qjFCKgldwzv1+96XmeCvR3bY7wNn2PjHMnRakOWC6+32g133vgZOjUiYgswIxohffzA==", - "license": "MIT", - "dependencies": { - "rimraf": "^6.0.1" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "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/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/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, - "node_modules/node-addon-api": { - "version": "8.3.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-8.3.1.tgz", - "integrity": "sha512-lytcDEdxKjGJPTLEfW4mYMigRezMlyJY8W4wxJK8zE533Jlb8L8dRuObJFWg2P+AuOIxoCgKF+2Oq4d4Zd0OUA==", - "license": "MIT", - "peer": true, - "engines": { - "node": "^18 || ^20 || >= 21" - } - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "deprecated": "Use your platform's native DOMException instead", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "license": "MIT", - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "license": "MIT", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/node-gyp-build": { - "version": "4.8.4", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", - "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", - "license": "MIT", - "peer": true, - "bin": { - "node-gyp-build": "bin.js", - "node-gyp-build-optional": "optional.js", - "node-gyp-build-test": "build-test.js" - } - }, - "node_modules/openai": { - "version": "4.95.1", - "resolved": "https://registry.npmjs.org/openai/-/openai-4.95.1.tgz", - "integrity": "sha512-IqJy+ymeW+k/Wq+2YVN3693OQMMcODRtHEYOlz263MdUwnN/Dwdl9c2EXSxLLtGEHkSHAfvzpDMHI5MaWJKXjQ==", - "license": "Apache-2.0", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" - }, - "bin": { - "openai": "bin/cli" - }, - "peerDependencies": { - "ws": "^8.18.0", - "zod": "^3.23.8" - }, - "peerDependenciesMeta": { - "ws": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/package-json-from-dist": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz", - "integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==", - "license": "BlueOak-1.0.0" - }, - "node_modules/parseley": { - "version": "0.12.1", - "resolved": "https://registry.npmjs.org/parseley/-/parseley-0.12.1.tgz", - "integrity": "sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==", - "license": "MIT", - "dependencies": { - "leac": "^0.6.0", - "peberminta": "^0.9.0" - }, - "funding": { - "url": "https://ko-fi.com/killymxi" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/pathe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", - "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "license": "MIT" - }, - "node_modules/peberminta": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/peberminta/-/peberminta-0.9.0.tgz", - "integrity": "sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==", - "license": "MIT", - "funding": { - "url": "https://ko-fi.com/killymxi" - } - }, - "node_modules/remeda": { - "version": "2.21.3", - "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.21.3.tgz", - "integrity": "sha512-XXrZdLA10oEOQhLLzEJEiFFSKi21REGAkHdImIb4rt/XXy8ORGXh5HCcpUOsElfPNDb+X6TA/+wkh+p2KffYmg==", - "license": "MIT", - "dependencies": { - "type-fest": "^4.39.1" - } - }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/rimraf": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-6.0.1.tgz", - "integrity": "sha512-9dkvaxAsk/xNXSJzMgFqqMCuFgt2+KsOFek3TMLfo8NCPfWpBmqwyNn5Y+NX56QUYfCtsyhF3ayiboEoUmJk/A==", - "license": "ISC", - "dependencies": { - "glob": "^11.0.0", - "package-json-from-dist": "^1.0.0" - }, - "bin": { - "rimraf": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/selderee": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/selderee/-/selderee-0.11.0.tgz", - "integrity": "sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==", - "license": "MIT", - "dependencies": { - "parseley": "^0.12.0" - }, - "funding": { - "url": "https://ko-fi.com/killymxi" - } - }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/string-width-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/string-width-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT" - }, - "node_modules/tree-sitter": { - "version": "0.22.4", - "resolved": "https://registry.npmjs.org/tree-sitter/-/tree-sitter-0.22.4.tgz", - "integrity": "sha512-usbHZP9/oxNsUY65MQUsduGRqDHQOou1cagUSwjhoSYAmSahjQDAVsh9s+SlZkn8X8+O1FULRGwHu7AFP3kjzg==", - "hasInstallScript": true, - "license": "MIT", - "peer": true, - "dependencies": { - "node-addon-api": "^8.3.0", - "node-gyp-build": "^4.8.4" - } - }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/type-fest": { - "version": "4.40.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.40.0.tgz", - "integrity": "sha512-ABHZ2/tS2JkvH1PEjxFDTUWC8dB5OsIGZP4IFLhR293GqT5Y5qB1WwL2kMPYhQW9DVgVD8Hd7I8gjwPIf5GFkw==", - "license": "(MIT OR CC0-1.0)", - "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "license": "MIT" - }, - "node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/web-tree-sitter": { - "version": "0.24.7", - "resolved": "https://registry.npmjs.org/web-tree-sitter/-/web-tree-sitter-0.24.7.tgz", - "integrity": "sha512-CdC/TqVFbXqR+C51v38hv6wOPatKEUGxa39scAeFSm98wIhZxAYonhRQPSMmfZ2w7JDI0zQDdzdmgtNk06/krQ==", - "license": "MIT", - "peer": true - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "license": "MIT" - }, - "node_modules/wrap-ansi-cjs/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/wrap-ansi-cjs/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/x402": { - "resolved": "../../packages/typescript/x402", - "link": true - }, - "node_modules/zod": { - "version": "3.24.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-3.24.3.tgz", - "integrity": "sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/colinhacks" - } - }, - "node_modules/zod-to-json-schema": { - "version": "3.24.5", - "resolved": "https://registry.npmjs.org/zod-to-json-schema/-/zod-to-json-schema-3.24.5.tgz", - "integrity": "sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==", - "license": "ISC", - "peerDependencies": { - "zod": "^3.24.1" - } - } - } -} diff --git a/examples/typescript/legacy/dynamic_agent/package.json b/examples/typescript/legacy/dynamic_agent/package.json deleted file mode 100644 index d9af61fbef..0000000000 --- a/examples/typescript/legacy/dynamic_agent/package.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "name": "dynamic_agent", - "version": "1.0.0", - "description": "", - "license": "ISC", - "author": "", - "type": "module", - "main": "index.js", - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1", - "index-server": "tsx --env-file=.env discover_server.ts", - "agent": "tsx --env-file=.env agent.ts" - }, - "dependencies": { - "@anthropic-ai/sdk": "^0.39.0", - "@hono/node-server": "^1.14.1", - "@llamaindex/anthropic": "^0.3.3", - "@types/node": "^22.15.3", - "axios": "^1.8.4", - "hono": "^4.7.7", - "llamaindex": "^0.10.2", - "viem": "^2.28.3", - "x402": "workspace:*", - "x402-axios": "workspace:*", - "x402-hono": "workspace:*", - "zod": "^3.24.3" - }, - "devDependencies": { - "@eslint/js": "^9.24.0", - "@typescript-eslint/eslint-plugin": "^8.29.1", - "@typescript-eslint/parser": "^8.29.1", - "eslint": "^9.24.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", - "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" - } -} diff --git a/examples/typescript/legacy/dynamic_agent/tsconfig.json b/examples/typescript/legacy/dynamic_agent/tsconfig.json deleted file mode 100644 index 0e28a92d2d..0000000000 --- a/examples/typescript/legacy/dynamic_agent/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ES2020", - "moduleResolution": "bundler", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true, - "strict": true, - "resolveJsonModule": true, - "baseUrl": ".", - "types": ["node"] - }, - "include": ["discover_server.ts", "agent.ts"] -} diff --git a/examples/typescript/legacy/facilitator/.env-local b/examples/typescript/legacy/facilitator/.env-local deleted file mode 100644 index 63f7008a14..0000000000 --- a/examples/typescript/legacy/facilitator/.env-local +++ /dev/null @@ -1,3 +0,0 @@ -EVM_PRIVATE_KEY=0xYourPrivateKey -SVM_PRIVATE_KEY=base58EncodedSolanaPrivateKey -PORT=3002 \ No newline at end of file diff --git a/examples/typescript/legacy/facilitator/README.md b/examples/typescript/legacy/facilitator/README.md deleted file mode 100644 index 9b83067176..0000000000 --- a/examples/typescript/legacy/facilitator/README.md +++ /dev/null @@ -1,123 +0,0 @@ -# x402 Facilitator Example - -This is an example implementation of an x402 facilitator service that handles payment verification and settlement for the x402 payment protocol. This implementation is for learning purposes and demonstrates how to build a facilitator service. - -For production use, we recommend using: - -- Testnet: https://x402.org/facilitator -- Production: https://api.cdp.coinbase.com/platform/v2/x402 - -## Overview - -The facilitator provides two main endpoints: - -- `/verify`: Verifies x402 payment payloads -- `/settle`: Settles x402 payments by signing and broadcasting transactions -- `/supported`: Returns the payment kinds that are supported by the facilitator - -This example demonstrates how to: - -1. Set up a basic Express server to handle x402 payment verification and settlement -2. Integrate with the x402 protocol's verification and settlement functions -3. Handle payment payload validation and error cases - -## Prerequisites - -- Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) -- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- A valid Ethereum private key and/or Solana private key -- Base Sepolia testnet ETH and/or Solana Devnet SOL for transaction fees - -## Setup - -1. Install and build all packages from the typescript examples root: - -```bash -cd .. -pnpm install -pnpm build -cd facilitator -``` - -2. Create a `.env` file with the following variables: - -```env -EVM_PRIVATE_KEY=0xYourPrivateKey -SVM_PRIVATE_KEY=base58EncodedSolanaPrivateKey -``` - -3. Start the server: - -```bash -pnpm dev -``` - -The server will start on http://localhost:3000 - -## API Endpoints - -### GET /supported - -Returns information the payment kinds that the facilitator supports. - -Sample Response - -```json5 -[ - { - "x402Version": 1, - "scheme": "exact", - "network": "base-sepolia" - "extra": {} - }, - { - "x402Version": 1, - "scheme": "exact", - "network": "solana-devnet" - "extra": { - "feePayer": "SolanaAddress" - } - }, -] -``` - -### GET /verify - -Returns information about the verify endpoint. - -### POST /verify - -Verifies an x402 payment payload. - -Request body: - -```typescript -{ - payload: string; // x402 payment payload - details: PaymentRequirements; // Payment requirements -} -``` - -### GET /settle - -Returns information about the settle endpoint. - -### POST /settle - -Settles an x402 payment by signing and broadcasting the transaction. - -Request body: - -```typescript -{ - payload: string; // x402 payment payload - details: PaymentRequirements; // Payment requirements -} -``` - -## Learning Resources - -This example is designed to help you understand how x402 facilitators work. For more information about the x402 protocol and its implementation, visit: - -- [x402 Protocol Documentation](https://x402.org) -- [Coinbase Developer Platform](https://www.coinbase.com/developer-platform) diff --git a/examples/typescript/legacy/facilitator/index.ts b/examples/typescript/legacy/facilitator/index.ts deleted file mode 100644 index 12bf4b59eb..0000000000 --- a/examples/typescript/legacy/facilitator/index.ts +++ /dev/null @@ -1,158 +0,0 @@ -/* eslint-env node */ -import { config } from "dotenv"; -import express, { Request, Response } from "express"; -import { verify, settle } from "x402/facilitator"; -import { - PaymentRequirementsSchema, - type PaymentRequirements, - type PaymentPayload, - PaymentPayloadSchema, - createConnectedClient, - createSigner, - SupportedEVMNetworks, - SupportedSVMNetworks, - Signer, - ConnectedClient, - SupportedPaymentKind, - isSvmSignerWallet, - type X402Config, -} from "x402/types"; - -config(); - -const EVM_PRIVATE_KEY = process.env.EVM_PRIVATE_KEY || ""; -const SVM_PRIVATE_KEY = process.env.SVM_PRIVATE_KEY || ""; -const SVM_RPC_URL = process.env.SVM_RPC_URL || ""; - -if (!EVM_PRIVATE_KEY && !SVM_PRIVATE_KEY) { - console.error("Missing required environment variables"); - process.exit(1); -} - -// Create X402 config with custom RPC URL if provided -const x402Config: X402Config | undefined = SVM_RPC_URL - ? { svmConfig: { rpcUrl: SVM_RPC_URL } } - : undefined; - -const app = express(); - -// Configure express to parse JSON bodies -app.use(express.json()); - -type VerifyRequest = { - paymentPayload: PaymentPayload; - paymentRequirements: PaymentRequirements; -}; - -type SettleRequest = { - paymentPayload: PaymentPayload; - paymentRequirements: PaymentRequirements; -}; - -app.get("/verify", (req: Request, res: Response) => { - res.json({ - endpoint: "/verify", - description: "POST to verify x402 payments", - body: { - paymentPayload: "PaymentPayload", - paymentRequirements: "PaymentRequirements", - }, - }); -}); - -app.post("/verify", async (req: Request, res: Response) => { - try { - const body: VerifyRequest = req.body; - const paymentRequirements = PaymentRequirementsSchema.parse(body.paymentRequirements); - const paymentPayload = PaymentPayloadSchema.parse(body.paymentPayload); - - // use the correct client/signer based on the requested network - // svm verify requires a Signer because it signs & simulates the txn - let client: Signer | ConnectedClient; - if (SupportedEVMNetworks.includes(paymentRequirements.network)) { - client = createConnectedClient(paymentRequirements.network); - } else if (SupportedSVMNetworks.includes(paymentRequirements.network)) { - client = await createSigner(paymentRequirements.network, SVM_PRIVATE_KEY); - } else { - throw new Error("Invalid network"); - } - - // verify - const valid = await verify(client, paymentPayload, paymentRequirements, x402Config); - res.json(valid); - } catch (error) { - console.error("error", error); - res.status(400).json({ error: "Invalid request" }); - } -}); - -app.get("/settle", (req: Request, res: Response) => { - res.json({ - endpoint: "/settle", - description: "POST to settle x402 payments", - body: { - paymentPayload: "PaymentPayload", - paymentRequirements: "PaymentRequirements", - }, - }); -}); - -app.get("/supported", async (req: Request, res: Response) => { - let kinds: SupportedPaymentKind[] = []; - - // evm - if (EVM_PRIVATE_KEY) { - kinds.push({ - x402Version: 1, - scheme: "exact", - network: "base-sepolia", - }); - } - - // svm - if (SVM_PRIVATE_KEY) { - const signer = await createSigner("solana-devnet", SVM_PRIVATE_KEY); - const feePayer = isSvmSignerWallet(signer) ? signer.address : undefined; - - kinds.push({ - x402Version: 1, - scheme: "exact", - network: "solana-devnet", - extra: { - feePayer, - }, - }); - } - res.json({ - kinds, - }); -}); - -app.post("/settle", async (req: Request, res: Response) => { - try { - const body: SettleRequest = req.body; - const paymentRequirements = PaymentRequirementsSchema.parse(body.paymentRequirements); - const paymentPayload = PaymentPayloadSchema.parse(body.paymentPayload); - - // use the correct private key based on the requested network - let signer: Signer; - if (SupportedEVMNetworks.includes(paymentRequirements.network)) { - signer = await createSigner(paymentRequirements.network, EVM_PRIVATE_KEY); - } else if (SupportedSVMNetworks.includes(paymentRequirements.network)) { - signer = await createSigner(paymentRequirements.network, SVM_PRIVATE_KEY); - } else { - throw new Error("Invalid network"); - } - - // settle - const response = await settle(signer, paymentPayload, paymentRequirements, x402Config); - res.json(response); - } catch (error) { - console.error("error", error); - res.status(400).json({ error: `Invalid request: ${error}` }); - } -}); - -app.listen(process.env.PORT || 3000, () => { - console.log(`Server listening at http://localhost:${process.env.PORT || 3000}`); -}); diff --git a/examples/typescript/legacy/fullstack/auth_based_pricing/.env-local b/examples/typescript/legacy/fullstack/auth_based_pricing/.env-local deleted file mode 100644 index 15d2162651..0000000000 --- a/examples/typescript/legacy/fullstack/auth_based_pricing/.env-local +++ /dev/null @@ -1,21 +0,0 @@ -# Server Configuration -JWT_SECRET="your-super-secret-jwt-key-at-least-32-characters-long-CHANGE-THIS" -DEMO_SERVER_PORT="4021" - -# Wallet that will pay for the x402 calls in the client simulation part of the demo -# IMPORTANT: Use a testnet private key with test funds only for this demo. -# This represents the "user's" wallet in a scripted scenario. -CLIENT_SIM_PRIVATE_KEY="0xyour_client_private_key_for_signing_and_x402_payments_CHANGE_THIS" - -# Business details for receiving x402 payments -# This is the wallet address your server/business will receive payments to. -BUSINESS_WALLET_ADDRESS="0xyour_business_wallet_address_to_receive_payments_CHANGE_THIS" - -# Network for x402 payments (must match what your facilitator & business wallet support) -# e.g., "base-sepolia", "base" -X402_NETWORK="base-sepolia" - -# (Optional) If your x402 facilitator requires an API key for your business to register resources -## TODO fix and change to CDP_API_KEY_NAME and CDP_API_KEY_SECRET -# CDP_API_KEY_ID="your_facilitator_api_key_name_if_needed" -# CDP_API_KEY_SECRET="your_facilitator_api_key_secret_if_needed" diff --git a/examples/typescript/legacy/fullstack/auth_based_pricing/.gitignore b/examples/typescript/legacy/fullstack/auth_based_pricing/.gitignore deleted file mode 100644 index 88793db521..0000000000 --- a/examples/typescript/legacy/fullstack/auth_based_pricing/.gitignore +++ /dev/null @@ -1,54 +0,0 @@ -# Node.js -node_modules/ -npm-debug.log* -yarn-debug.log* -yarn-error.log* -package-lock.json - -# TypeScript -dist/ -build/ -*.tsbuildinfo - -# Environment variables -.env -.env*.local -.env.*.local -!.env.example -!.env.production.local -# If you want to commit .env.production.local, specify it here. - -# Logs -logs -*.log -*.log.[0-9] -*.log.[0-9][0-9] -*.log.[0-9][0-9][0-9] -*.log.[0-9][0-9][0-9][0-9] -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json -pids -*.pid -*.seed -*.pid.lock - -# OS generated files -.DS_Store -Thumbs.db -ehthumbs.db -ehthumbs_vista.db -._* - -# Editor directories and files -.vscode/ -*.suo -*.ntvs* -*.njsproj -*.sln -*.sw? - -# Optional: IntelliJ IDEA -# .idea/ \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/auth_based_pricing/README.md b/examples/typescript/legacy/fullstack/auth_based_pricing/README.md deleted file mode 100644 index 251eb64520..0000000000 --- a/examples/typescript/legacy/fullstack/auth_based_pricing/README.md +++ /dev/null @@ -1,159 +0,0 @@ -# SIWE + JWT + Conditional x402 Demo - -This project demonstrates a pattern for combining Sign-In with Ethereum (SIWE), JWT-based session management, and dynamic, conditional pricing for API endpoints using x402 payments. It includes a Hono backend server and a separate client script to simulate user interactions. - -## Core Concepts - -1. **Wallet Authentication (SIWE)**: - * Users prove ownership of a wallet address by signing a server-issued EIP-4361 compliant message. - * The `siwe` library is used on both server and client for message creation and verification. - -2. **JWT for Sessions**: - * Upon successful SIWE message verification, the server issues a JSON Web Token (JWT). - * This JWT is sent by the client in subsequent requests (in the `Authorization: Bearer ` header) to access protected or feature-enhanced endpoints. - -3. **x402 Programmable Payments**: - * API endpoints can require micropayments for access using the [x402 standard](https://x402.dev). - * This demo shows manual x402 challenge/verification handling on the server for maximum control, inspired by the x402 SDK's advanced examples. - -4. **Conditional x402 Pricing**: - * The `/demo-weather` endpoint dynamically adjusts its price based on JWT authentication: - * **Authenticated users (with JWT):** $0.01. - * **Unauthenticated users (no JWT):** $0.10. - -## Project Structure - -``` -siwe-x402-jwt-demo/ -├── .env-local # Local environment variables (gitignored) -├── package.json # Project dependencies and scripts -├── tsconfig.json # TypeScript configuration -├── README.md # This file -├── backend.ts # Hono server with SIWE auth and manual x402 logic -├── client.ts # Script to simulate client login and API calls -``` - -## Prerequisites - -* Node.js (v18+ recommended) -* npm or yarn -* A testnet wallet with some test ETH (e.g., on Base Sepolia) for `CLIENT_SIM_PRIVATE_KEY` to make x402 payments. - -## Setup - -1. **Clone/Setup Files**: Ensure all project files are in place. - -2. **Install dependencies**: - ```bash - npm install - ``` - -3. **Set up environment variables**: - * Create a file named `.env-local` in the project root. - * Populate it with your secrets (refer to `.env.example` or previous instructions for required variables like `JWT_SECRET`, `DEMO_SERVER_PORT`, `CLIENT_SIM_PRIVATE_KEY`, `BUSINESS_WALLET_ADDRESS`, `FACILITATOR_URL`, `X402_NETWORK`). - * **Crucially**, `CLIENT_SIM_PRIVATE_KEY` needs to be a funded testnet wallet private key. - -## Running the Demo - -You'll need two terminal windows: - -1. **Terminal 1: Start the Backend Server** - * For development with auto-reloading: - ```bash - npm run dev:server - ``` - * Or, to run the built version (after `npm run build`): - ```bash - npm run start:server - ``` - * The server will start (default: `http://localhost:3000`). - -2. **Terminal 2: Run the Client Simulation** - * Once the server is running, execute the client script: - * For direct TypeScript execution: - ```bash - npm run dev:client - ``` - * Or, to run the built version (after `npm run build`): - ```bash - npm run start:client - ``` - -## Expected Output & Flow - -* **Server Terminal**: Shows server startup logs, SIWE nonce issuance, SIWE verification results, JWT pricing decisions, x402 payment verification, and settlement logs. -* **Client Terminal**: Shows the client simulation steps: - 1. Attempting SIWE login (requesting nonce, signing, verifying). - 2. Logging the received JWT upon successful login. - 3. Calling `/demo-weather` WITH the JWT: - * Server should apply the $0.01 price. - * Client handles the 402 challenge and pays $0.01. - * Logs the weather data and the `x-payment-response` for the $0.01 payment. - 4. Calling `/demo-weather` WITHOUT the JWT: - * Server should apply the $0.10 price. - * Client handles the 402 challenge and pays $0.10. - * Logs the weather data and the `x-payment-response` for the $0.10 payment. - -This demonstrates the end-to-end flow of wallet authentication, JWT-based sessions, and dynamic, conditional x402 payments. - -## Migrating to Base Mainnet with the CDP Facilitator - -To use x402 payments on Base mainnet (instead of Sepolia testnet), follow these steps: - -### 1. Environment Variable Changes - -- In your `.env` (or environment), set: - ``` - X402_NETWORK=base - BUSINESS_WALLET_ADDRESS= - CLIENT_SIM_PRIVATE_KEY= - ``` -- **Remove or ignore** any `FACILITATOR_URL` variable. The CDP facilitator is imported from `@coinbase/x402` in code. - -### 2. Code Changes in `backend.ts` (don't forget to run `npm run build`) - -- **Facilitator Import:** - ```ts - import { facilitator } from "@coinbase/x402"; - const { verify: verifyX402Payment, settle: settleX402Payment } = useFacilitator(facilitator); - ``` -- **Network:** - Ensure `X402_NETWORK` is set to `'base'` (not `'base-sepolia'`). -- **Asset:** - Make sure your price string (e.g., `$0.01`) maps to a supported asset on Base mainnet (typically USDC). The asset address is handled by the x402 SDK, but your wallet must have the correct token. -- **Funding:** - Both `BUSINESS_WALLET_ADDRESS` and the client wallet must be funded with USDC on Base mainnet. - -### 3. Code Changes in `client.ts` - -- **Chain ID:** - ```ts - import { base } from 'viem/chains'; - const chainId = base.id; // 8453 for Base mainnet - ``` -- **Private Key:** - The `CLIENT_SIM_PRIVATE_KEY` must be funded on Base mainnet with USDC. - -### 4. Troubleshooting 500 Errors - -- **Facilitator/Network Mismatch:** - - Ensure you are using the mainnet facilitator from `@coinbase/x402` and not a testnet URL. - - `X402_NETWORK` must be `'base'`. -- **Asset Issues:** - - If your price string or asset is not supported on Base, payments will fail. -- **Wallet Funding:** - - Both business and client wallets must have USDC on Base mainnet. -- **Error Logging:** - - Check server logs for error details. Add more logging in `backend.ts` if needed. -- **Client Chain ID:** - - Ensure the client uses the correct chain ID (8453 for Base mainnet). - -If you encounter persistent 500 errors, check the logs for messages from the facilitator or asset processing functions. Most issues are due to misconfiguration of environment variables, unsupported assets, or lack of wallet funding. - -## Notes & Further Development - -* **Nonce Store**: The server's nonce store is in-memory. For production, use a persistent, time-to-live (TTL) store like Redis. -* **SIWE Message Fields**: The client constructs a SIWE message with basic fields. Ensure `domain`, `uri`, `chainId`, `issuedAt`, and `expirationTime` (optional) are robustly handled and verified by the server in a production setting according to EIP-4361 best practices. -* **Error Handling**: The demo has basic error logging. Production systems need comprehensive error handling and user feedback. -* **Security**: `JWT_SECRET` must be strong and kept confidential. Private keys should never be hardcoded directly in client-side code for real applications; use browser wallet extensions. `CLIENT_SIM_PRIVATE_KEY` is for this demo's automation only. -* **x402 SDKs**: Ensure you are using compatible versions of `x402`, `x402-fetch`, and any Hono-specific x402 integrations if you deviate from this demo's manual server-side handling. diff --git a/examples/typescript/legacy/fullstack/auth_based_pricing/backend.ts b/examples/typescript/legacy/fullstack/auth_based_pricing/backend.ts deleted file mode 100644 index 9c34fb1c2a..0000000000 --- a/examples/typescript/legacy/fullstack/auth_based_pricing/backend.ts +++ /dev/null @@ -1,319 +0,0 @@ -import { Hono, Context as HonoContext } from 'hono'; -import { serve } from '@hono/node-server'; -import { sign, verify as verifyJwtSignature } from 'hono/jwt'; -import { config } from 'dotenv'; -import { Hex } from 'viem'; -import { SiweMessage, generateNonce } from 'siwe'; - -import { - PaymentRequirements, - Price as X402Price, - Network as X402Network, - Resource as X402Resource, - PaymentPayload, - settleResponseHeader, - ERC20TokenAmount -} from 'x402/types'; -import { useFacilitator } from 'x402/verify'; -import { exact } from 'x402/schemes'; -import { processPriceToAtomicAmount } from 'x402/shared'; -// uncomment to use the CDP Base mainnet facilitator -//import { facilitator } from "@coinbase/x402"; - - -// --- Environment Variable Loading --- -config(); // Load .env or .env-local - -// --- Configuration Constants --- -const JWT_SECRET = process.env.JWT_SECRET as string; -const DEMO_SERVER_PORT = parseInt(process.env.DEMO_SERVER_PORT || '3000', 10); -const BUSINESS_WALLET_ADDRESS = process.env.BUSINESS_WALLET_ADDRESS as Hex; // Wallet to receive payments -const FACILITATOR_URL = 'https://x402.org/facilitator'; // x402 Sepolia Facilitator -const X402_NETWORK = process.env.X402_NETWORK as X402Network; // Network for x402 payments (e.g., 'base-sepolia', 'base') -const X402_VERSION = 1; // Standard x402 version - -// Validate essential configuration -if (!JWT_SECRET || !BUSINESS_WALLET_ADDRESS || !FACILITATOR_URL || !X402_NETWORK) { - console.error('CRITICAL ERROR: Missing essential server environment variables. Check .env-local or .env file.'); - process.exit(1); -} - -// --- Hono App & x402 Facilitator Setup --- -const app = new Hono(); -// Initialize x402 facilitator client for payment verification and settlement -// for mainnet, use the CDP Base mainnet facilitator as follows: -// const { verify: verifyX402Payment, settle: settleX402Payment } = useFacilitator(facilitator); -const { verify: verifyX402Payment, settle: settleX402Payment } = useFacilitator({ url: FACILITATOR_URL }); - -// --- SIWE Nonce Store (In-Memory for Demo) --- -// IMPORTANT: For production, use a persistent store (e.g., Redis, DB) with proper TTL management for nonces. -const issuedNonces = new Set(); -const NONCE_EXPIRATION_TIME_MS = 5 * 60 * 1000; // Nonces expire after 5 minutes - -// --- Helper: Create x402 Exact Payment Requirements --- -/** - * Constructs the payment requirements object for an x402 payment. - * @param price The price for the resource (e.g., '$0.10'). - * @param network The blockchain network for the payment. - * @param resource The URL or identifier of the resource being accessed. - * @param description A description for the payment. - * @returns PaymentRequirements object for the x402 challenge. - */ -function createExactPaymentRequirements( - price: X402Price, - network: X402Network, - resource: X402Resource, - description = "", -): PaymentRequirements { - const atomicAmountForAsset = processPriceToAtomicAmount(price, network); - if ("error" in atomicAmountForAsset) { - console.error("[X402Svc] Error processing price to atomic amount:", atomicAmountForAsset.error); - throw new Error(`Failed to process price: ${atomicAmountForAsset.error}`); - } - const { maxAmountRequired, asset } = atomicAmountForAsset; - const erc20Asset = asset as ERC20TokenAmount["asset"]; - return { - scheme: "exact", - network, - maxAmountRequired, - resource, - description, - mimeType: "application/json", // Content type of the protected resource - payTo: BUSINESS_WALLET_ADDRESS, - maxTimeoutSeconds: 60, // Client has 60s to complete payment after challenge - asset: erc20Asset.address, // e.g., USDC contract address on the specified network - outputSchema: undefined, // Optional: JSON schema for the expected response after payment - extra: { name: erc20Asset.eip712.name, version: erc20Asset.eip712.version }, // EIP-712 domain info for the payment asset - }; -} - -// --- Helper: Handle x402 Payment Flow (Verification & Challenge Response) --- -interface X402HandlingResult { - success: boolean; - response?: Response; // Pre-formatted Hono Response for 402 challenges or errors - decodedPayment?: PaymentPayload; // Validated and decoded payment from X-PAYMENT header - verifiedPayer?: Hex; // Wallet address of the payer, verified by facilitator -} - -/** - * Handles the x402 payment verification logic. - * Checks for X-PAYMENT header, decodes it, verifies with facilitator. - * Returns a success status or a pre-formatted 402 Hono Response object. - */ -async function handleX402PaymentVerification( - c: HonoContext, - paymentRequirements: PaymentRequirements[], -): Promise { - const paymentHeader = c.req.header('X-PAYMENT'); - - // If no payment header, issue a 402 challenge with payment requirements - if (!paymentHeader) { - console.log('[X402Svc] No X-PAYMENT header. Responding with 402 challenge.'); - return { - success: false, - response: c.json({ - x402Version: X402_VERSION, - error: "X-PAYMENT header is required", - accepts: paymentRequirements - }, 402) - }; - } - - // Decode the payment header - let decodedPayment: PaymentPayload; - try { - decodedPayment = exact.evm.decodePayment(paymentHeader); - } catch (error: any) { - console.error('[X402Svc] Error decoding X-PAYMENT header:', error.message); - return { - success: false, - response: c.json({ - x402Version: X402_VERSION, - error: error.message || "Invalid or malformed X-PAYMENT header", - accepts: paymentRequirements - }, 402) - }; - } - - // Verify the decoded payment with the facilitator - try { - const verificationResponse = await verifyX402Payment(decodedPayment, paymentRequirements[0]); - if (!verificationResponse.isValid) { - console.warn('[X402Svc] Payment verification failed by facilitator:', verificationResponse.invalidReason); - return { - success: false, - response: c.json({ - x402Version: X402_VERSION, - error: verificationResponse.invalidReason, - accepts: paymentRequirements, - payer: verificationResponse.payer - }, 402) - }; - } - console.log('[X402Svc] Payment verified successfully by facilitator for payer:', verificationResponse.payer); - return { - success: true, - decodedPayment: decodedPayment, - verifiedPayer: verificationResponse.payer as Hex - }; - } catch (error: any) { - console.error('[X402Svc] Critical error during facilitator payment verification process:', error.message); - return { - success: false, - response: c.json({ - x402Version: X402_VERSION, - error: error.message || "Facilitator verification process failed", - accepts: paymentRequirements - }, 500) // Use 500 for server-side errors with facilitator - }; - } -} - -// --- SIWE Authentication Endpoints --- - -// Endpoint for clients to request a unique nonce for SIWE message construction -app.get('/auth/nonce', async (c) => { - const nonce = generateNonce(); // Generate a cryptographically secure nonce - issuedNonces.add(nonce); - // Schedule nonce removal to prevent store bloat and enforce expiration - setTimeout(() => issuedNonces.delete(nonce), NONCE_EXPIRATION_TIME_MS); - console.log(`[AuthSvc] SIWE Nonce issued: ${nonce}`); - return c.text(nonce); // Return nonce as plain text -}); - -// Endpoint for clients to submit a signed SIWE message for verification -app.post('/auth/verify-siwe', async (c) => { - const { message, signature } = await c.req.json<{ message: string; signature: Hex }>(); - if (!message || !signature) return c.json({ error: 'SIWE message and signature are required' }, 400); - - try { - const siweMessage = new SiweMessage(message); // Parse the client-provided EIP-4361 message - - // Validate nonce: ensure it was issued by this server and hasn't expired/been used - if (!issuedNonces.has(siweMessage.nonce)) { - console.warn(`[AuthSvc] Attempt to use invalid, expired, or already used SIWE nonce: ${siweMessage.nonce}`); - return c.json({ error: 'Invalid, expired, or already used nonce. Please request a new one.' }, 403); - } - - // Verify the SIWE message (checks signature, nonce against message, domain, time constraints, etc.) - const { success: verificationSuccess, error: verificationError, data: verifiedSiweMessage } = await siweMessage.verify({ - signature, - nonce: siweMessage.nonce, // Crucial: ensure nonce being verified is the one from the message body - // domain: 'expected.domain.com', // Optional: verify against expected domain - // time: new Date() // Optional: verify against current time for issuedAt, expirationTime, notBefore - }); - - if (!verificationSuccess) { - console.warn(`[AuthSvc] SIWE message verification failed for address ${siweMessage.address}:`, verificationError); - return c.json({ error: 'SIWE message verification failed.', details: verificationError?.type || 'Unknown SIWE error' }, 401); - } - - // SIWE verification successful, invalidate the nonce immediately to prevent replay attacks - issuedNonces.delete(siweMessage.nonce); - const walletAddress = verifiedSiweMessage.address as Hex; // Use address from verified data - console.log(`[AuthSvc] Successful SIWE verification for ${walletAddress}`); - - // Issue JWT for session management - const payload = { - sub: walletAddress.toLowerCase(), // Subject: user's wallet address - iat: Math.floor(Date.now() / 1000), // Issued At: current time - exp: Math.floor(Date.now() / 1000) + (60 * 60 * 24), // Expiration Time: 24 hours - }; - const token = await sign(payload, JWT_SECRET); - - return c.json({ success: true, message: 'Login successful via SIWE', token }); - - } catch (error: any) { - console.error('[AuthSvc] Critical error during SIWE verification process:', error); - return c.json({ error: 'SIWE verification process failed due to a server error.', details: error.message }, 500); - } -}); - -// --- x402 Gated Demo Endpoint (/demo-weather) with Conditional Pricing --- -app.get('/demo-weather', async (c: HonoContext) => { - // 1. Determine Price Conditionally based on JWT authentication - const authHeader = c.req.header('Authorization'); - let isAuthenticated = false; - let priceString: X402Price = '$0.10'; // Default price for unauthenticated users - - if (authHeader && authHeader.startsWith('Bearer ')) { - const token = authHeader.substring(7); - try { - const payload = await verifyJwtSignature(token, JWT_SECRET); // Verify the JWT - if (payload && payload.sub) { // Check for subject (wallet address) in JWT - isAuthenticated = true; - priceString = '$0.01'; // Discounted price for authenticated users - console.log(`[X402Svc] User ${payload.sub} is authenticated via JWT. Applying discounted price: ${priceString}`); - } - } catch (err) { - // JWT invalid or expired, treat as unauthenticated for pricing - console.log('[X402Svc] JWT verification failed for pricing. Applying default price.'); - } - } - if (!isAuthenticated) { - console.log(`[X402Svc] User not authenticated via JWT. Applying default price: ${priceString}`); - } - - // 2. Construct Payment Requirements for the determined price - const resourceUrl = c.req.url as X402Resource; // The resource being accessed - let paymentRequirements: PaymentRequirements[]; - try { - paymentRequirements = [createExactPaymentRequirements(priceString, X402_NETWORK, resourceUrl, 'Access to premium demo weather forecast')]; - } catch (error: any) { - console.error('[X402Svc] Error creating payment requirements for /demo-weather:', error.message); - return c.json({ error: 'Server error: Could not create payment requirements.' }, 500); - } - - // 3. Handle x402 Payment Flow (Verification/Challenge) - const x402Result = await handleX402PaymentVerification(c, paymentRequirements); - - // If payment verification failed or a challenge was issued, return the 402 response - if (!x402Result.success || !x402Result.decodedPayment || !x402Result.verifiedPayer) { - return x402Result.response!; - } - - // 4. Settle Payment (Good practice after successful verification) - try { - const settlement = await settleX402Payment(x402Result.decodedPayment, paymentRequirements[0]); - const paymentResponseHeaderVal = settleResponseHeader(settlement); - c.header('X-PAYMENT-RESPONSE', paymentResponseHeaderVal); // Send settlement confirmation to client - console.log('[X402Svc] /demo-weather: Payment settled. X-PAYMENT-RESPONSE header set.'); - } catch (error: any) { - console.error('[X402Svc] /demo-weather: Payment settlement failed (after verification). This is a server-side issue:', error.message); - // Note: Content is still served as payment was verified. Settlement failure is logged. - } - - // 5. Return Resource (Weather Data) - console.log('[DemoSvc] /demo-weather: Access granted. Payment successful.'); - const weatherReport = { - location: 'Demo City', - temperature: '72°F', - condition: 'Sunny with x402 skies!', - message: 'This is a mock weather report. Payment was successful!', - pricePaid: priceString, // Reflect the price that was required for this access - payer: x402Result.verifiedPayer // The verified wallet address that paid - }; - return c.json(weatherReport); -}); - -// --- Main Server Start Function --- -async function main() { - serve({ - fetch: app.fetch, - port: DEMO_SERVER_PORT, - }, (info) => { - console.log(`🚀 SIWE-JWT-x402 Demo Server running on http://localhost:${info.port}`); - console.log('----------------------------------------------------------------------'); - console.log('🔑 JWT Secret:', JWT_SECRET ? 'LOADED' : 'MISSING - Server will fail!'); - console.log('💼 Business Wallet:', BUSINESS_WALLET_ADDRESS || 'MISSING - Payments will fail!'); - console.log('🌍 x402 Network:', X402_NETWORK || 'MISSING - Payments will fail!'); - console.log('----------------------------------------------------------------------'); - console.log('💡 To test, run the client script in a separate terminal: npm run dev:client'); - console.log('----------------------------------------------------------------------'); - }); -} - -main().catch(err => { - console.error('💥 Failed to start server:', err); - process.exit(1); -}); \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/auth_based_pricing/client.ts b/examples/typescript/legacy/fullstack/auth_based_pricing/client.ts deleted file mode 100644 index 3382035bf0..0000000000 --- a/examples/typescript/legacy/fullstack/auth_based_pricing/client.ts +++ /dev/null @@ -1,161 +0,0 @@ -import { config } from 'dotenv'; -import { Hex, PrivateKeyAccount } from 'viem'; // Removed createWalletClient, http as not directly used here -import { privateKeyToAccount } from 'viem/accounts'; -import { baseSepolia, base } from 'viem/chains'; -import { SiweMessage } from 'siwe'; -import _fetch from 'node-fetch'; // Using ESM-compatible import for node-fetch -import { wrapFetchWithPayment, decodeXPaymentResponse } from 'x402-fetch'; -import { fileURLToPath } from 'url'; - -// --- Environment Variable Loading --- -config(); // Load .env-local or .env - -// --- Configuration Constants --- -const DEMO_SERVER_PORT = parseInt(process.env.DEMO_SERVER_PORT || '3000', 10); -const CLIENT_SIM_PRIVATE_KEY = process.env.CLIENT_SIM_PRIVATE_KEY as Hex; - -// Validate essential client configuration -if (!CLIENT_SIM_PRIVATE_KEY) { - console.error('CRITICAL ERROR: Missing CLIENT_SIM_PRIVATE_KEY environment variable for client simulation. Check .env-local or .env file.'); - process.exit(1); -} - -// --- Main Client Simulation Function --- -async function runClientDemo() { - console.log('\n🚀 --- Starting Client Simulation --- 🚀'); - - // Setup client wallet from private key (for demo purposes) - // In a real app, this would come from a browser wallet extension (e.g., MetaMask) - const clientWalletAccount = privateKeyToAccount(CLIENT_SIM_PRIVATE_KEY); - const clientWalletAddress = clientWalletAccount.address; - console.log(`[ClientSim] Using wallet address for simulation: ${clientWalletAddress}`); - - const serverBaseUrl = `http://localhost:${DEMO_SERVER_PORT}`; - const chainId = baseSepolia.id; // Chain ID for SIWE message (must match server if verified strictly) - let jwtToken: string | null = null; - - // --- Step 1: SIWE Login Flow --- - console.log('\n🔄 [ClientSim] Step 1: Attempting SIWE Login...'); - try { - // 1a. Request nonce from the server - console.log(`[ClientSim] Requesting nonce from ${serverBaseUrl}/auth/nonce...`); - const nonceResponse = await _fetch(`${serverBaseUrl}/auth/nonce`); - if (!nonceResponse.ok) { - throw new Error(`Nonce request failed: ${nonceResponse.status} ${await nonceResponse.text()}`); - } - const nonce = await nonceResponse.text(); - console.log(`[ClientSim] ✅ Received SIWE nonce: ${nonce}`); - - // 1b. Client constructs the SIWE message parameters - const siweMessageParams = { - domain: 'localhost', // IMPORTANT: Should match the domain the server expects/verifies - address: clientWalletAddress, - statement: 'Sign in with Ethereum to the demo app.', - uri: serverBaseUrl, // The URI a user is logging into - version: '1', // SIWE version - chainId: chainId, // Chain ID - nonce: nonce, // Server-issued nonce - issuedAt: new Date().toISOString(), // Current time - // expirationTime: new Date(Date.now() + NONCE_EXPIRATION_TIME_MS).toISOString(), // Optional: if server checks it - }; - const siweMessage = new SiweMessage(siweMessageParams); - const messageToSign = siweMessage.prepareMessage(); // Formats the EIP-4361 message string - console.log(`[ClientSim] Prepared SIWE message to sign:\n${messageToSign}`); - - // 1c. Client signs the SIWE message (simulating wallet interaction) - const signature = await clientWalletAccount.signMessage({ message: messageToSign }); - console.log(`[ClientSim] ✅ SIWE Message signed. Signature: ${signature.substring(0,10)}...`); - - // 1d. Client sends the SIWE message and signature to the server for verification - console.log(`[ClientSim] Verifying signature with server at ${serverBaseUrl}/auth/verify-siwe...`); - const verifyResponse = await _fetch(`${serverBaseUrl}/auth/verify-siwe`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ message: messageToSign, signature }), // Send the message string client signed - }); - const loginData = await verifyResponse.json() as { success?: boolean; token?: string; error?: string, message?: string, details?: string }; - if (!verifyResponse.ok || !loginData.success || !loginData.token) { - throw new Error(`SIWE Login failed: ${loginData.error || loginData.message || loginData.details || 'Unknown SIWE login error'} (Status: ${verifyResponse.status})`); - } - jwtToken = loginData.token; - console.log('[ClientSim] ✅ SIWE Login successful! JWT obtained.'); - // console.log('[ClientSim] JWT:', jwtToken); // Optionally log the full JWT for debugging - } catch (error) { - console.error('[ClientSim] ❌ SIWE Login flow error:', error); - // If login fails, we might not want to proceed with x402 calls that rely on JWT for discount - } - - // --- Setup x402-fetch for subsequent calls --- - // This wraps the standard fetch with x402 payment handling capabilities using the client's wallet. - const fetchWithClientPayment = wrapFetchWithPayment(_fetch as any, clientWalletAccount); - - // --- Step 2: Call /demo-weather WITH JWT (Authenticated - Expecting Discounted Price) --- - if (jwtToken) { - console.log('\n🔄 [ClientSim] Step 2: Calling /demo-weather WITH JWT (expecting $0.01 price from server)...'); - try { - const response = await fetchWithClientPayment(`${serverBaseUrl}/demo-weather`, { - method: 'GET', - headers: { 'Authorization': `Bearer ${jwtToken}` }, // Include JWT for authentication - }); - - const x402RespHeader = response.headers.get('x-payment-response'); - - if (!response.ok) { - // This block might be hit if x402-fetch fails to handle the 402 automatically, or for other errors. - const errText = await response.text(); - console.error(`[ClientSim] ❌ Error from server (authenticated call): ${response.status} - ${errText}`); - // Log x-payment-response even on error, if present, for debugging x402 client issues - if (x402RespHeader) console.error('[ClientSim] x-payment-response (on error):', decodeXPaymentResponse(x402RespHeader)); - throw new Error(`Authenticated /demo-weather call failed: ${response.status}`); - } - - const weatherData = await response.json(); - console.log('[ClientSim] ✅ Weather data (authenticated):', weatherData); - if (x402RespHeader) { - console.log('[ClientSim] ✅ x-payment-response (authenticated):', decodeXPaymentResponse(x402RespHeader)); - } - } catch (error: any) { - console.error('[ClientSim] ❌ Error during authenticated /demo-weather call:', error.message); - } - } else { - console.warn('\n[ClientSim] Skipping authenticated /demo-weather call because JWT was not obtained.'); - } - - // --- Step 3: Call /demo-weather WITHOUT JWT (Unauthenticated - Expecting Regular Price) --- - console.log('\n🔄 [ClientSim] Step 3: Calling /demo-weather WITHOUT JWT (expecting $0.10 price from server)...'); - try { - const response = await fetchWithClientPayment(`${serverBaseUrl}/demo-weather`, { method: 'GET' }); - - const x402RespHeader = response.headers.get('x-payment-response'); - - if (!response.ok) { - const errText = await response.text(); - console.error(`[ClientSim] ❌ Error from server (unauthenticated call): ${response.status} - ${errText}`); - if (x402RespHeader) console.error('[ClientSim] x-payment-response (on error):', decodeXPaymentResponse(x402RespHeader)); - throw new Error(`Unauthenticated /demo-weather call failed: ${response.status}`); - } - - const weatherData = await response.json(); - console.log('[ClientSim] ✅ Weather data (unauthenticated):', weatherData); - if (x402RespHeader) { - console.log('[ClientSim] ✅ x-payment-response (unauthenticated):', decodeXPaymentResponse(x402RespHeader)); - } - } catch (error: any) { - console.error('[ClientSim] ❌ Error during unauthenticated /demo-weather call:', error.message); - } - console.log('\n🏁 --- Client Simulation Ended --- 🏁'); -} - -// --- Script Execution Check (ESM Compatible) --- -// This ensures runClientDemo() is called only when the script is executed directly. -const currentFilePath = fileURLToPath(import.meta.url); -// In Node.js ESM, `process.argv[1]` should be the path to the executed script file. -// For `node dist/client.js`, `process.argv[1]` is `.../dist/client.js` -// For `tsx src/client.ts`, `tsx` might make `process.argv[1]` point to `.../src/client.ts` or the tsx shim. -// A more robust check might involve `endsWith` if paths differ slightly during dev (tsx) vs prod (node). -if (process.argv[1] && fileURLToPath(`file://${process.argv[1]}`) === currentFilePath) { - runClientDemo().catch(err => { - console.error("💥 Client Simulation CRASHED:", err); - process.exit(1); // Exit with error code if client demo crashes - }); -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/auth_based_pricing/package.json b/examples/typescript/legacy/fullstack/auth_based_pricing/package.json deleted file mode 100644 index 7af8fa1298..0000000000 --- a/examples/typescript/legacy/fullstack/auth_based_pricing/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "auth-based-pricing", - "version": "1.0.0", - "description": "Demo of Sign-In with Ethereum (SIWE), JWT authentication, and conditional x402 payments.", - "main": "dist/backend.js", - "type": "module", - "scripts": { - "build": "tsc", - "start:server": "node dist/backend.js", - "dev:server": "tsx watch backend.ts", - "start:client": "node dist/client.js", - "dev:client": "tsx client.ts", - "dev": "npm run dev:server" - }, - "keywords": [ - "siwe", - "jwt", - "x402", - "hono", - "web3", - "auth" - ], - "author": "Your Name", - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.11.2", - "dotenv": "^16.4.5", - "hono": "^4.4.0", - "node-fetch": "^3.3.2", - "siwe": "^2.3.2", - "viem": "^2.13.8", - "x402": "workspace:*", - "x402-fetch": "workspace:*", - "x402-hono": "workspace:*" - }, - "devDependencies": { - "@types/node": "^20.14.2", - "@types/node-fetch": "^2.6.11", - "tsx": "^4.11.0", - "typescript": "^5.4.5" - } -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/.env.example b/examples/typescript/legacy/fullstack/browser-wallet-example/.env.example deleted file mode 100644 index 110277b54a..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/.env.example +++ /dev/null @@ -1,4 +0,0 @@ -FACILITATOR_URL=https://x402.org/facilitator -NETWORK=base-sepolia -ADDRESS=0x_YOUR_WALLET_ADDRESS_HERE -PORT=3001 \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/.gitignore b/examples/typescript/legacy/fullstack/browser-wallet-example/.gitignore deleted file mode 100644 index b32e6b9373..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/.gitignore +++ /dev/null @@ -1,105 +0,0 @@ -# Dependencies -node_modules/ -.pnp -.pnp.js - -# Testing -coverage/ -.nyc_output/ - -# Production build files -dist/ -build/ -out/ -.next/ -.nuxt/ -.cache/ -.parcel-cache/ - -# Environment files -.env -.env.local -.env.development.local -.env.test.local -.env.production.local - -# Logs -logs/ -*.log -npm-debug.log* -yarn-debug.log* -yarn-error.log* -lerna-debug.log* -.pnpm-debug.log* - -# OS files -.DS_Store -Thumbs.db -*.swp -*.swo -*~ - -# IDE files -.vscode/ -.idea/ -*.sublime-project -*.sublime-workspace -.project -.classpath -.c9/ -*.launch -.settings/ -*.iml - -# Temporary files -*.tmp -*.temp -.tmp/ -.temp/ - -# TypeScript -*.tsbuildinfo -.tsc_cache/ - -# Optional npm cache directory -.npm - -# Optional eslint cache -.eslintcache - -# Optional stylelint cache -.stylelintcache - -# Yarn -.yarn/cache -.yarn/unplugged -.yarn/build-state.yml -.yarn/install-state.gz -.pnp.* - -# Misc -.sass-cache/ -.connect.history-api-fallback -*.pid -*.seed -*.pid.lock - -# Mac files -.AppleDouble -.LSOverride -Icon -._* - -# Windows files -Desktop.ini -ehthumbs.db -ehthumbs_vista.db -*.stackdump -[Dd]esktop.ini -$RECYCLE.BIN/ - -# Linux files -.fuse_hidden* -.directory -.Trash-* -.nfs* \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/README.md b/examples/typescript/legacy/fullstack/browser-wallet-example/README.md deleted file mode 100644 index 4d1d779f91..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/README.md +++ /dev/null @@ -1,175 +0,0 @@ -# x402 Browser Wallet Payment Template - -> 🛠️ **A starter template for building payment-enabled applications with x402** - -This is a simplified scaffolding project demonstrating [x402 payment protocol](https://x402.org) integration with browser wallet support. Use this as a foundation to build your own micropayment-enabled services, SaaS applications, or any project that needs frictionless web payments. - -## What is x402? - -x402 is a payments protocol for the internet built on HTTP. It enables: -- **1 line of code** to accept digital dollars -- **No fees**, 2 second settlement -- **$0.001 minimum** payments - -Learn more at [x402.org](https://x402.org) or check out the [GitHub repository](https://github.com/coinbase/x402). - -## This Template Includes - -✅ **Two Payment Models** ready to customize: -- **24-Hour Session** ($1.00): Time-based access perfect for SaaS -- **One-Time Access** ($0.10): Single-use payments for actions or content - -✅ **Complete Implementation**: -- Server with x402 payment middleware (Hono) -- React client with wallet integration (Viem) -- Session management and validation -- Clean, modern UI ready to customize - -✅ **Developer Friendly**: -- TypeScript throughout -- Easy to extend and modify -- Well-documented code -- Production-ready patterns - -## Quick Start - -### 1. Install Dependencies - -```bash -pnpm install:all -``` - -### 2. Configure the Server - -Create `.env`: -```env -FACILITATOR_URL=https://x402.org/facilitator -NETWORK=base-sepolia -ADDRESS=0x_YOUR_WALLET_ADDRESS_HERE -PORT=3001 -``` - -### 3. Run Both Server and Client - -```bash -pnpm dev -``` - -This starts: -- Server on http://localhost:3001 -- Client on http://localhost:5173 - -## How It Works - -### Payment Flow - -1. **Connect Wallet**: User connects browser wallet to the app -2. **Choose Payment Type**: - - **24-Hour Session**: Pay $1.00 to get a session ID valid for 24 hours - - **One-Time Access**: Pay $0.10 for single-use access (valid for 5 minutes) -3. **Sign Payment**: User signs the payment request -4. **Receive Session ID**: After payment, user gets a session ID -5. **Validate Session**: Use the session ID to access protected resources - -### Session Types - -#### 24-Hour Session -- **Price**: $1.00 -- **Duration**: 24 hours from purchase -- **Usage**: Unlimited during the valid period -- **Use Case**: Users who need extended access - -#### One-Time Access -- **Price**: $0.10 -- **Duration**: 5 minutes to use -- **Usage**: Single use only -- **Use Case**: Quick one-off actions or trials - -## API Endpoints - -### Free Endpoints - -- `GET /api/health` - Server health check -- `GET /api/payment-options` - Available payment options -- `GET /api/session/:sessionId` - Validate a session -- `GET /api/sessions` - List active sessions - -### Paid Endpoints - -- `POST /api/pay/session` - Purchase 24-hour session ($1.00) -- `POST /api/pay/onetime` - Purchase one-time access ($0.10) - -## Client Features - -1. **Wallet Connection**: Connect/disconnect wallet -2. **Payment Options**: Clear display of both payment types -3. **Session Validation**: Input field to check session validity -4. **Active Sessions**: Display of all active sessions -5. **Real-time Updates**: Session list updates after purchases - -## Testing - -1. Get Base Sepolia ETH from [Coinbase Faucet](https://www.coinbase.com/faucets/base-ethereum-sepolia-faucet) -2. Get Base Sepolia USDC from [Circle Faucet](https://faucet.circle.com/) -3. Connect browser wallet to the app -4. Purchase a session or one-time access -5. Use the session validator to check your session -6. Watch one-time sessions expire after use - -## Use This Template For - -This scaffolding is perfect as a starting point for: - -- **SaaS Applications**: Implement day passes, premium features, or usage-based billing -- **Content Platforms**: Charge for articles, videos, or exclusive content -- **API Services**: Monetize your API with per-call or time-based pricing -- **Digital Tools**: Add trial periods or one-time purchase options -- **Gaming**: Implement in-game purchases or pay-to-play mechanics -- **Any Web Service**: If you can imagine it, you can charge for it with x402 - -## Customization Guide - -### Changing Payment Models - -The template uses two payment types, but you can easily modify them: - -```typescript -// In server/index.ts, customize your payment endpoints: -"/api/pay/custom": { - price: "$0.50", // Your price - network, -} -``` - -### Adding New Features - -1. **New Payment Tiers**: Add more options in the payment middleware -2. **Different Session Durations**: Modify the expiration logic -3. **Custom Validation**: Extend the session validation system -4. **Database Integration**: Replace in-memory storage with your database -5. **User Authentication**: Add user accounts and payment history - -### Styling and Branding - -The UI is intentionally minimal so you can add your own design system. All styles are in `client/src/App.css`. - -## Get Help - -Building something with x402? We're here to help! - -- 📚 **Documentation**: [x402.org](https://x402.org) -- 💻 **Source Code**: [github.com/coinbase/x402](https://github.com/coinbase/x402) -- 💬 **Community**: [Join our Discord](https://discord.gg/invite/cdp) -- 🐛 **Issues**: [GitHub Issues](https://github.com/coinbase/x402/issues) - -## Contributing - -Found a bug or have an improvement for this template? Please open an issue or submit a PR! - -## License - -This template is open source and available under the same license as the x402 protocol. See the [x402 repository](https://github.com/coinbase/x402) for details. - ---- - -**Ready to build?** Fork this template and start accepting payments in minutes! 🚀 diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/client/index.html b/examples/typescript/legacy/fullstack/browser-wallet-example/client/index.html deleted file mode 100644 index c1d248c586..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/client/index.html +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - x402 Browser Wallet Example - - -
- - - \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/App.css b/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/App.css deleted file mode 100644 index 0661546199..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/App.css +++ /dev/null @@ -1,449 +0,0 @@ -/* Reset and Base Styles */ -* { - box-sizing: border-box; - margin: 0; - padding: 0; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; - background-color: #f5f5f5; - color: #333; - line-height: 1.6; -} - -/* App Container */ -.app { - max-width: 1200px; - margin: 0 auto; - padding: 20px; -} - -/* Header */ -header { - text-align: center; - margin-bottom: 40px; - padding: 30px; - background: white; - border-radius: 10px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); -} - -header h1 { - color: #2c3e50; - margin-bottom: 10px; -} - -header p { - color: #7f8c8d; -} - -.server-status { - margin-top: 20px; - padding: 10px; - background: #f8f9fa; - border-radius: 5px; - font-size: 14px; -} - -/* Sections */ -section { - margin-bottom: 40px; - padding: 30px; - background: white; - border-radius: 10px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); -} - -section h2 { - color: #2c3e50; - margin-bottom: 20px; - padding-bottom: 10px; - border-bottom: 2px solid #ecf0f1; -} - -/* Wallet Connect */ -.wallet-section { - text-align: center; -} - -.wallet-connect { - display: inline-block; -} - -.connect-btn { - background: #3498db; - color: white; - border: none; - padding: 12px 24px; - border-radius: 5px; - font-size: 16px; - cursor: pointer; - transition: background 0.3s; -} - -.connect-btn:hover { - background: #2980b9; -} - -.connect-btn:disabled { - background: #95a5a6; - cursor: not-allowed; -} - -.wallet-connected { - display: inline-block; -} - -.wallet-info { - display: flex; - align-items: center; - gap: 10px; - padding: 10px 20px; - background: #e8f5e9; - border-radius: 5px; - border: 1px solid #4caf50; -} - -.status-indicator { - color: #4caf50; - font-size: 20px; -} - -.address { - font-family: monospace; - color: #2e7d32; -} - -.disconnect-btn { - background: none; - border: none; - color: #e74c3c; - cursor: pointer; - text-decoration: underline; -} - -/* Pricing Grid */ -.pricing-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: 20px; -} - -.pricing-card { - padding: 20px; - border: 2px solid #ecf0f1; - border-radius: 8px; - text-align: center; - transition: transform 0.3s, box-shadow 0.3s; -} - -.pricing-card:hover { - transform: translateY(-5px); - box-shadow: 0 5px 20px rgba(0, 0, 0, 0.1); -} - -.pricing-card h3 { - color: #2c3e50; - margin-bottom: 10px; -} - -.price { - font-size: 28px; - font-weight: bold; - color: #3498db; - margin: 10px 0; -} - -.description { - color: #7f8c8d; - margin-bottom: 20px; -} - -.action-btn { - background: #27ae60; - color: white; - border: none; - padding: 10px 20px; - border-radius: 5px; - font-size: 16px; - cursor: pointer; - transition: background 0.3s; - width: 100%; -} - -.action-btn:hover { - background: #229954; -} - -.action-btn:disabled { - background: #95a5a6; - cursor: not-allowed; -} - -/* Results */ -.result-card { - margin-bottom: 20px; - padding: 20px; - background: #f8f9fa; - border-radius: 8px; - border-left: 4px solid #3498db; -} - -.result-card h3 { - color: #2c3e50; - margin-bottom: 10px; -} - -.result-card pre { - background: #2c3e50; - color: #ecf0f1; - padding: 15px; - border-radius: 5px; - overflow-x: auto; - margin-top: 10px; -} - -/* Sessions */ -.sessions-section ul { - list-style: none; -} - -.sessions-section li { - padding: 10px; - background: #f8f9fa; - margin-bottom: 10px; - border-radius: 5px; - font-family: monospace; -} - -/* Error Messages */ -.error-message, -.error { - color: #e74c3c; - margin-top: 10px; - padding: 10px; - background: #ffebee; - border-radius: 5px; - font-size: 14px; -} - -/* Footer */ -footer { - text-align: center; - margin-top: 40px; - padding: 20px; - color: #7f8c8d; - background: white; - border-radius: 10px; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1); -} - -/* Builder Resources */ -.builder-resources { - margin-top: 2rem; - padding-top: 2rem; - border-top: 1px solid #e9ecef; -} - -.builder-resources h3 { - color: #2c3e50; - margin-bottom: 0.5rem; -} - -.builder-resources p { - color: #718096; - margin-bottom: 1rem; -} - -.resource-links { - display: flex; - gap: 1.5rem; - justify-content: center; - flex-wrap: wrap; -} - -.resource-links a { - display: inline-flex; - align-items: center; - gap: 0.5rem; - padding: 0.75rem 1.5rem; - background: #f8f9fa; - border: 1px solid #e9ecef; - border-radius: 8px; - color: #3182ce; - text-decoration: none; - font-weight: 500; - transition: all 0.2s; -} - -.resource-links a:hover { - background: #e9ecef; - transform: translateY(-2px); - box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); -} - -/* Payment section styling */ -.payment-section, -.validation-section { - background: white; - border-radius: 12px; - padding: 2rem; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); -} - -.payment-grid { - display: grid; - grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); - gap: 1.5rem; - margin-top: 1.5rem; -} - -.payment-card { - background: #f8f9fa; - border: 1px solid #e9ecef; - border-radius: 8px; - padding: 1.5rem; - text-align: center; -} - -.payment-card h3 { - color: #2d3748; - margin-bottom: 0.5rem; -} - -.payment-card .price { - font-size: 2rem; - font-weight: bold; - color: #3182ce; - margin: 0.5rem 0; -} - -.payment-card .description { - color: #718096; - margin-bottom: 1rem; -} - -/* Session validation section */ -.validation-section { - margin-top: 2rem; -} - -.session-validator { - display: flex; - gap: 1rem; - margin-top: 1rem; -} - -.session-input { - flex: 1; - padding: 0.75rem; - border: 1px solid #e2e8f0; - border-radius: 6px; - font-size: 1rem; - font-family: monospace; -} - -.session-input:focus { - outline: none; - border-color: #3182ce; - box-shadow: 0 0 0 3px rgba(49, 130, 206, 0.1); -} - -.validate-btn { - padding: 0.75rem 1.5rem; - background: #3182ce; - color: white; - border: none; - border-radius: 6px; - font-weight: 500; - cursor: pointer; - transition: background 0.2s; -} - -.validate-btn:hover { - background: #2c5282; -} - -.validation-result { - margin-top: 1rem; - padding: 1rem; - border-radius: 6px; - border: 1px solid; -} - -.validation-result.success { - background: #f0fdf4; - border-color: #22c55e; - color: #166534; -} - -.validation-result.error { - background: #fef2f2; - border-color: #ef4444; - color: #991b1b; -} - -.session-details, -.access-details { - margin-top: 0.5rem; - padding: 0.5rem; - background: rgba(0, 0, 0, 0.05); - border-radius: 4px; - font-size: 0.9rem; -} - -/* Active sessions styling */ -.sessions-section { - background: white; - border-radius: 12px; - padding: 2rem; - margin-top: 2rem; - box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05); -} - -.sessions-list { - display: flex; - flex-direction: column; - gap: 0.75rem; - margin-top: 1rem; -} - -.session-item { - display: flex; - align-items: center; - gap: 1rem; - padding: 1rem; - background: #f8f9fa; - border: 1px solid #e9ecef; - border-radius: 6px; -} - -.session-item code { - font-family: monospace; - font-size: 0.85rem; - color: #4a5568; - flex: 1; -} - -.session-type { - padding: 0.25rem 0.75rem; - border-radius: 4px; - font-size: 0.85rem; - font-weight: 500; -} - -.session-type.24hour { - background: #dbeafe; - color: #1e40af; -} - -.session-type.onetime { - background: #fef3c7; - color: #92400e; -} - -.session-expires { - font-size: 0.85rem; - color: #718096; -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/App.tsx b/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/App.tsx deleted file mode 100644 index 435e5608d5..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/App.tsx +++ /dev/null @@ -1,261 +0,0 @@ -import React, { useState, useEffect } from 'react'; -import { WalletConnect } from './components/WalletConnect'; -import { useWallet } from './contexts/WalletContext'; -import { api, updateApiClient, type PaymentOption, type Session } from './services/api'; -import './App.css'; - -function App() { - const { walletClient } = useWallet(); - const [serverStatus, setServerStatus] = useState('checking...'); - const [paymentOptions, setPaymentOptions] = useState([]); - const [sessions, setSessions] = useState([]); - const [loading, setLoading] = useState(null); - const [sessionInput, setSessionInput] = useState(''); - const [validationResult, setValidationResult] = useState(null); - - // Update API client when wallet changes - useEffect(() => { - updateApiClient(walletClient); - }, [walletClient]); - - // Check server health on mount - useEffect(() => { - checkServerHealth(); - loadPaymentOptions(); - loadActiveSessions(); - }, []); - - const checkServerHealth = async () => { - try { - const health = await api.getHealth(); - setServerStatus(`✅ Connected to ${health.config.network}`); - } catch (error) { - setServerStatus('❌ Server offline'); - } - }; - - const loadPaymentOptions = async () => { - try { - const data = await api.getPaymentOptions(); - setPaymentOptions(data.options); - } catch (error) { - console.error('Failed to load payment options:', error); - } - }; - - const loadActiveSessions = async () => { - try { - const data = await api.getActiveSessions(); - setSessions(data.sessions); - } catch (error) { - console.error('Failed to load sessions:', error); - } - }; - - const handle24HourSession = async () => { - setLoading('session'); - try { - const result = await api.purchase24HourSession(); - await loadActiveSessions(); - setValidationResult({ - type: 'success', - message: result.message, - session: result.session, - }); - } catch (error: any) { - setValidationResult({ - type: 'error', - message: error.message || 'Failed to purchase session', - }); - } finally { - setLoading(null); - } - }; - - const handleOneTimeAccess = async () => { - setLoading('onetime'); - try { - const result = await api.purchaseOneTimeAccess(); - await loadActiveSessions(); - setValidationResult({ - type: 'success', - message: result.message, - access: result.access, - }); - } catch (error: any) { - setValidationResult({ - type: 'error', - message: error.message || 'Failed to purchase access', - }); - } finally { - setLoading(null); - } - }; - - const validateSession = async () => { - if (!sessionInput.trim()) { - setValidationResult({ - type: 'error', - message: 'Please enter a session ID', - }); - return; - } - - try { - const result = await api.validateSession(sessionInput); - setValidationResult(result); - if (result.valid && result.session?.type === 'onetime') { - // Refresh sessions since one-time was just used - await loadActiveSessions(); - } - } catch (error: any) { - setValidationResult({ - type: 'error', - message: error.message || 'Failed to validate session', - }); - } - }; - - return ( -
-
-

x402 Payment Template

-

Build your own payment-enabled app with this starter template

-
{serverStatus}
-
- -
-
-

1. Connect Your Wallet

- -
- -
-

2. Payment Options

-
- {paymentOptions.map((option) => ( -
-

{option.name}

-

{option.price}

-

{option.description}

- - {option.endpoint === '/api/pay/session' && ( - - )} - - {option.endpoint === '/api/pay/onetime' && ( - - )} -
- ))} -
-
- -
-

3. Validate Session

-
- setSessionInput(e.target.value)} - onKeyPress={(e) => e.key === 'Enter' && validateSession()} - className="session-input" - /> - -
- - {validationResult && ( -
- {validationResult.message &&

{validationResult.message}

} - {validationResult.error &&

❌ {validationResult.error}

} - {validationResult.valid && ( -
-

✅ Session is valid!

- {validationResult.session && ( -
-

Type: {validationResult.session.type}

-

Created: {new Date(validationResult.session.createdAt).toLocaleString()}

-

Expires: {new Date(validationResult.session.expiresAt).toLocaleString()}

- {validationResult.session.remainingTime && ( -

Remaining: {Math.floor(validationResult.session.remainingTime / 1000 / 60)} minutes

- )} -
- )} -
- )} - {validationResult.session && !validationResult.valid && ( -
-

Session ID: {validationResult.session.id}

-

Type: {validationResult.session.type}

-

Status: {validationResult.error}

-
- )} - {validationResult.access && ( -
-

Access ID: {validationResult.access.id}

-

Valid for: {validationResult.access.validFor}

-
- )} -
- )} -
- - {sessions.length > 0 && ( -
-

Active Sessions

-
- {sessions.map((session) => ( -
- {session.id} - {session.type} - - Expires: {new Date(session.expiresAt).toLocaleString()} - -
- ))} -
-
- )} -
- - -
- ); -} - -export default App; \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/components/WalletConnect.tsx b/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/components/WalletConnect.tsx deleted file mode 100644 index af0c361c1c..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/components/WalletConnect.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from 'react'; -import { useWallet } from '../contexts/WalletContext'; - -export function WalletConnect() { - const { isConnected, address, isConnecting, error, connectWallet, disconnectWallet } = useWallet(); - - const formatAddress = (addr: string) => { - return `${addr.slice(0, 6)}...${addr.slice(-4)}`; - }; - - if (isConnected && address) { - return ( -
-
- - {formatAddress(address)} - -
-
- ); - } - - return ( -
- - {error && ( -
- {error} -
- )} -
- ); -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/contexts/WalletContext.tsx b/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/contexts/WalletContext.tsx deleted file mode 100644 index 2f93356c0d..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/contexts/WalletContext.tsx +++ /dev/null @@ -1,191 +0,0 @@ -import React, { createContext, useContext, useState, useCallback, useEffect } from 'react'; -import { createWalletClient, custom, type WalletClient } from 'viem'; -import { baseSepolia } from 'viem/chains'; -import type { Hex } from 'viem'; - -interface WalletContextType { - isConnected: boolean; - address: Hex | null; - walletClient: WalletClient | null; - error: string | null; - isConnecting: boolean; - connectWallet: () => Promise; - disconnectWallet: () => void; -} - -const WalletContext = createContext(undefined); - -export function WalletProvider({ children }: { children: React.ReactNode }) { - const [isConnected, setIsConnected] = useState(false); - const [address, setAddress] = useState(null); - const [walletClient, setWalletClient] = useState(null); - const [error, setError] = useState(null); - const [isConnecting, setIsConnecting] = useState(false); - - // Check if wallet is already connected on mount - useEffect(() => { - checkConnection(); - }, []); - - const checkConnection = async () => { - if (typeof window.ethereum !== 'undefined') { - try { - const accounts = await window.ethereum.request({ - method: 'eth_accounts' - }) as string[]; - - if (accounts.length > 0) { - const client = createWalletClient({ - account: accounts[0] as Hex, - chain: baseSepolia, - transport: custom(window.ethereum) - }); - - setWalletClient(client); - setAddress(accounts[0] as Hex); - setIsConnected(true); - } - } catch (err) { - console.error('Failed to check wallet connection:', err); - } - } - }; - - const connectWallet = useCallback(async () => { - setError(null); - setIsConnecting(true); - - try { - if (typeof window.ethereum === 'undefined') { - throw new Error('Please install MetaMask or another Ethereum wallet'); - } - - // Request account access - const accounts = await window.ethereum.request({ - method: 'eth_requestAccounts' - }) as string[]; - - if (accounts.length === 0) { - throw new Error('No accounts found'); - } - - // Check if on correct network (Base Sepolia) - const chainId = await window.ethereum.request({ - method: 'eth_chainId' - }) as string; - - const baseSepoliaChainIdHex = '0x14a34'; // 84532 in hex - - if (chainId !== baseSepoliaChainIdHex) { - try { - await window.ethereum.request({ - method: 'wallet_switchEthereumChain', - params: [{ chainId: baseSepoliaChainIdHex }], - }); - } catch (switchError: any) { - // This error code indicates that the chain has not been added to browser wallet - if (switchError.code === 4902) { - await window.ethereum.request({ - method: 'wallet_addEthereumChain', - params: [{ - chainId: baseSepoliaChainIdHex, - chainName: 'Base Sepolia', - nativeCurrency: { - name: 'Ethereum', - symbol: 'ETH', - decimals: 18, - }, - rpcUrls: ['https://sepolia.base.org'], - blockExplorerUrls: ['https://sepolia.basescan.org'], - }], - }); - } else { - throw switchError; - } - } - } - - // Create viem wallet client - const client = createWalletClient({ - account: accounts[0] as Hex, - chain: baseSepolia, - transport: custom(window.ethereum) - }); - - setWalletClient(client); - setAddress(accounts[0] as Hex); - setIsConnected(true); - } catch (err: any) { - setError(err.message || 'Failed to connect wallet'); - console.error('Wallet connection error:', err); - } finally { - setIsConnecting(false); - } - }, []); - - const disconnectWallet = useCallback(() => { - setWalletClient(null); - setAddress(null); - setIsConnected(false); - setError(null); - }, []); - - // Listen for account changes - useEffect(() => { - if (typeof window.ethereum !== 'undefined') { - const handleAccountsChanged = async (accounts: string[]) => { - if (accounts.length === 0) { - disconnectWallet(); - } else if (accounts[0] !== address) { - // Re-connect with new account - const client = createWalletClient({ - account: accounts[0] as Hex, - chain: baseSepolia, - transport: custom(window.ethereum) - }); - - setWalletClient(client); - setAddress(accounts[0] as Hex); - setIsConnected(true); - } - }; - - const handleChainChanged = () => { - - window.location.reload(); - }; - - window.ethereum.on('accountsChanged', handleAccountsChanged); - window.ethereum.on('chainChanged', handleChainChanged); - - return () => { - window.ethereum.removeListener('accountsChanged', handleAccountsChanged); - window.ethereum.removeListener('chainChanged', handleChainChanged); - }; - } - }, [address, disconnectWallet]); - - const value: WalletContextType = { - isConnected, - address, - walletClient, - error, - isConnecting, - connectWallet, - disconnectWallet, - }; - - return ( - - {children} - - ); -} - -export function useWallet() { - const context = useContext(WalletContext); - if (context === undefined) { - throw new Error('useWallet must be used within a WalletProvider'); - } - return context; -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/main.tsx b/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/main.tsx deleted file mode 100644 index 7c97c0ce42..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/main.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import React from 'react'; -import ReactDOM from 'react-dom/client'; -import App from './App'; -import { WalletProvider } from './contexts/WalletContext'; - -ReactDOM.createRoot(document.getElementById('root')!).render( - - - - - -); \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/services/api.ts b/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/services/api.ts deleted file mode 100644 index f3fe9b195a..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/services/api.ts +++ /dev/null @@ -1,92 +0,0 @@ -import axios from "axios"; -import type { AxiosInstance } from "axios"; -import type { WalletClient } from "viem"; -import { withPaymentInterceptor } from "x402-axios"; - -const API_BASE_URL = import.meta.env.VITE_API_BASE_URL || "http://localhost:3001"; - -// Base axios instance without payment interceptor -const baseApiClient = axios.create({ - baseURL: API_BASE_URL, - headers: { - "Content-Type": "application/json", - }, -}); - -// This will be dynamically set based on wallet connection -let apiClient: AxiosInstance = baseApiClient; - -// Update the API client with a wallet -export function updateApiClient(walletClient: WalletClient | null) { - if (walletClient && walletClient.account) { - // Create axios instance with x402 payment interceptor - apiClient = withPaymentInterceptor(baseApiClient, walletClient as any); - console.log("💳 API client updated with wallet:", walletClient.account.address); - } else { - // No wallet connected - reset to base client - apiClient = baseApiClient; - console.log("⚠️ API client reset - no wallet connected"); - } -} - -// API endpoints -export const api = { - // Free endpoints - getHealth: async () => { - const response = await apiClient.get("/api/health"); - return response.data; - }, - - getPaymentOptions: async () => { - const response = await apiClient.get("/api/payment-options"); - return response.data; - }, - - validateSession: async (sessionId: string) => { - const response = await apiClient.get(`/api/session/${sessionId}`); - return response.data; - }, - - getActiveSessions: async () => { - const response = await apiClient.get("/api/sessions"); - return response.data; - }, - - // Paid endpoints - purchase24HourSession: async () => { - console.log("🔐 Purchasing 24-hour session access..."); - const response = await apiClient.post("/api/pay/session"); - console.log("✅ 24-hour session created:", response.data); - return response.data; - }, - - purchaseOneTimeAccess: async () => { - console.log("⚡ Purchasing one-time access..."); - const response = await apiClient.post("/api/pay/onetime"); - console.log("✅ One-time access granted:", response.data); - return response.data; - }, -}; - -// Types for API responses -export interface PaymentOption { - name: string; - endpoint: string; - price: string; - description: string; -} - -export interface Session { - id: string; - type: "24hour" | "onetime"; - createdAt: string; - expiresAt: string; - validFor?: string; - remainingTime?: number; -} - -export interface SessionValidation { - valid: boolean; - error?: string; - session?: Session; -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/types/window.d.ts b/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/types/window.d.ts deleted file mode 100644 index 26b3f52a67..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/types/window.d.ts +++ /dev/null @@ -1,13 +0,0 @@ -interface EthereumProvider { - request: (args: { method: string; params?: any[] }) => Promise; - on: (event: string, handler: (...args: any[]) => void) => void; - removeListener: (event: string, handler: (...args: any[]) => void) => void; -} - -declare global { - interface Window { - ethereum?: EthereumProvider; - } -} - -export {}; \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/vite-env.d.ts b/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/vite-env.d.ts deleted file mode 100644 index 3c62869cc6..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/client/src/vite-env.d.ts +++ /dev/null @@ -1,9 +0,0 @@ -/// - -interface ImportMetaEnv { - readonly VITE_API_BASE_URL: string -} - -interface ImportMeta { - readonly env: ImportMetaEnv -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/client/tsconfig.json b/examples/typescript/legacy/fullstack/browser-wallet-example/client/tsconfig.json deleted file mode 100644 index b359b287be..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/client/tsconfig.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ESNext", - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "jsx": "react-jsx", - "moduleResolution": "node", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "resolveJsonModule": true, - "isolatedModules": true, - "noEmit": true - }, - "include": ["src/**/*"], - "exclude": ["node_modules"] -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/package.json b/examples/typescript/legacy/fullstack/browser-wallet-example/package.json deleted file mode 100644 index f557964d21..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/package.json +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "browser-wallet-x402-example", - "version": "1.0.0", - "description": "Example of x402 payments with browser wallet integration", - "private": true, - "scripts": { - "dev": "concurrently \"pnpm dev:server\" \"pnpm dev:client\"", - "dev:server": "tsx watch server/index.ts", - "dev:client": "vite", - "install:all": "pnpm install && cd server && pnpm install && cd ../client && pnpm install", - "preview": "cd client && pnpm preview" - }, - "dependencies": { - "@hono/node-server": "^1.14.0", - "dotenv": "^16.6.1", - "hono": "^4.6.17", - "react": "^18.3.1", - "react-dom": "^18.3.1", - "viem": "^2.31.3", - "axios": "^1.10.0", - "uuid": "^11.0.6", - "x402-axios": "workspace:*", - "x402-hono": "workspace:*" - }, - "devDependencies": { - "@types/node": "^22.15.3", - "@types/react": "^18.3.17", - "@types/react-dom": "^18.3.5", - "@types/uuid": "^10.0.0", - "@vitejs/plugin-react": "^4.4.1", - "concurrently": "^8.2.2", - "tsx": "^4.19.2", - "typescript": "^5.8.3", - "vite": "^6.3.5" - } -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/server/README.md b/examples/typescript/legacy/fullstack/browser-wallet-example/server/README.md deleted file mode 100644 index 27dcbf50ef..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/server/README.md +++ /dev/null @@ -1,35 +0,0 @@ -# x402 Server Example - -This server demonstrates x402 payment integration with multiple pricing tiers. - -## Setup - -1. Create a `.env` file: -```env -FACILITATOR_URL=https://x402.org/facilitator -NETWORK=base-sepolia -ADDRESS=0x_YOUR_WALLET_ADDRESS_HERE -PORT=3001 -``` - -2. Install dependencies: -```bash -npm install -``` - -3. Run the server: -```bash -npm run dev -``` - -## Endpoints - -### Free Endpoints -- `GET /api/health` - Server health check -- `GET /api/pricing` - Get pricing information -- `GET /api/session/:sessionId` - Check session status - -### Paid Endpoints -- `POST /api/premium/content` - Access premium content ($0.10) -- `POST /api/premium/action` - Perform premium action ($1.00) -- `POST /api/premium/subscribe` - Monthly subscription ($5.00) \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/server/index.ts b/examples/typescript/legacy/fullstack/browser-wallet-example/server/index.ts deleted file mode 100644 index e319417549..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/server/index.ts +++ /dev/null @@ -1,235 +0,0 @@ -import { config } from "dotenv"; -import { Hono } from "hono"; -import { serve } from "@hono/node-server"; -import { cors } from "hono/cors"; -import { paymentMiddleware, Network, Resource } from "x402-hono"; -import { v4 as uuidv4 } from "uuid"; - -config(); - -// Configuration from environment variables -const facilitatorUrl = process.env.FACILITATOR_URL as Resource || "https://x402.org/facilitator"; -const payTo = process.env.ADDRESS as `0x${string}`; -const network = (process.env.NETWORK as Network) || "base-sepolia"; -const port = parseInt(process.env.PORT || "3001"); - -if (!payTo) { - console.error("❌ Please set your wallet ADDRESS in the .env file"); - process.exit(1); -} - -const app = new Hono(); - -// Enable CORS for frontend -app.use("/*", cors({ - origin: ["http://localhost:5173", "http://localhost:3000"], - credentials: true, -})); - -// Simple in-memory storage for sessions (use Redis/DB in production) -interface Session { - id: string; - createdAt: Date; - expiresAt: Date; - type: "24hour" | "onetime"; - used?: boolean; -} - -const sessions = new Map(); - -// Configure x402 payment middleware with two payment options -app.use( - paymentMiddleware( - payTo, - { - // 24-hour session access - "/api/pay/session": { - price: "$1.00", - network, - }, - // One-time access/payment - "/api/pay/onetime": { - price: "$0.10", - network, - }, - }, - { - url: facilitatorUrl, - }, - ), -); - -// Free endpoint - health check -app.get("/api/health", (c) => { - return c.json({ - status: "ok", - message: "Server is running", - config: { - network, - payTo, - facilitator: facilitatorUrl, - }, - }); -}); - -// Free endpoint - get payment options -app.get("/api/payment-options", (c) => { - return c.json({ - options: [ - { - name: "24-Hour Access", - endpoint: "/api/pay/session", - price: "$1.00", - description: "Get a session ID for 24 hours of unlimited access", - }, - { - name: "One-Time Access", - endpoint: "/api/pay/onetime", - price: "$0.10", - description: "Single use payment for immediate access", - }, - ], - }); -}); - -// Paid endpoint - 24-hour session access ($1.00) -app.post("/api/pay/session", (c) => { - const sessionId = uuidv4(); - const now = new Date(); - const expiresAt = new Date(now.getTime() + 24 * 60 * 60 * 1000); // 24 hours - - const session: Session = { - id: sessionId, - createdAt: now, - expiresAt, - type: "24hour", - }; - - sessions.set(sessionId, session); - - return c.json({ - success: true, - sessionId, - message: "24-hour access granted!", - session: { - id: sessionId, - type: "24hour", - createdAt: now.toISOString(), - expiresAt: expiresAt.toISOString(), - validFor: "24 hours", - }, - }); -}); - -// Paid endpoint - one-time access/payment ($0.10) -app.post("/api/pay/onetime", async (c) => { - const sessionId = uuidv4(); - const now = new Date(); - - const session: Session = { - id: sessionId, - createdAt: now, - expiresAt: new Date(now.getTime() + 5 * 60 * 1000), // 5 minutes to use - type: "onetime", - used: false, - }; - - sessions.set(sessionId, session); - - return c.json({ - success: true, - sessionId, - message: "One-time access granted!", - access: { - id: sessionId, - type: "onetime", - createdAt: now.toISOString(), - validFor: "5 minutes (single use)", - }, - }); -}); - -// Free endpoint - validate session -app.get("/api/session/:sessionId", (c) => { - const sessionId = c.req.param("sessionId"); - const session = sessions.get(sessionId); - - if (!session) { - return c.json({ valid: false, error: "Session not found" }, 404); - } - - const now = new Date(); - const isExpired = now > session.expiresAt; - const isUsed = session.type === "onetime" && session.used; - - if (isExpired || isUsed) { - return c.json({ - valid: false, - error: isExpired ? "Session expired" : "One-time access already used", - session: { - id: session.id, - type: session.type, - createdAt: session.createdAt.toISOString(), - expiresAt: session.expiresAt.toISOString(), - used: session.used, - } - }); - } - - // Mark one-time sessions as used - if (session.type === "onetime") { - session.used = true; - sessions.set(sessionId, session); - } - - return c.json({ - valid: true, - session: { - id: session.id, - type: session.type, - createdAt: session.createdAt.toISOString(), - expiresAt: session.expiresAt.toISOString(), - remainingTime: session.expiresAt.getTime() - now.getTime(), - }, - }); -}); - -// Free endpoint - list active sessions (for demo purposes) -app.get("/api/sessions", (c) => { - const activeSessions = Array.from(sessions.values()) - .filter(session => { - const isExpired = new Date() > session.expiresAt; - const isUsed = session.type === "onetime" && session.used; - return !isExpired && !isUsed; - }) - .map(session => ({ - id: session.id, - type: session.type, - createdAt: session.createdAt.toISOString(), - expiresAt: session.expiresAt.toISOString(), - })); - - return c.json({ sessions: activeSessions }); -}); - -console.log(` -🚀 x402 Payment Template Server -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -💰 Accepting payments to: ${payTo} -🔗 Network: ${network} -🌐 Port: ${port} -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -📋 Payment Options: - - 24-Hour Session: $1.00 - - One-Time Access: $0.10 -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -🛠️ This is a template! Customize it for your app. -📚 Learn more: https://x402.org -💬 Get help: https://discord.gg/invite/cdp -━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ -`); - -serve({ - fetch: app.fetch, - port, -}); \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/server/tsconfig.json b/examples/typescript/legacy/fullstack/browser-wallet-example/server/tsconfig.json deleted file mode 100644 index 8ad0a25847..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/server/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "bundler", - "outDir": "./dist", - "strict": true, - "esModuleInterop": true, - "skipLibCheck": true, - "forceConsistentCasingInFileNames": true, - "types": ["node"] - }, - "include": ["*.ts"], - "exclude": ["node_modules"] -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/browser-wallet-example/vite.config.ts b/examples/typescript/legacy/fullstack/browser-wallet-example/vite.config.ts deleted file mode 100644 index 8e7361c8c2..0000000000 --- a/examples/typescript/legacy/fullstack/browser-wallet-example/vite.config.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { defineConfig } from 'vite' -import react from '@vitejs/plugin-react' - -export default defineConfig({ - root: 'client', - plugins: [react()], - server: { - port: 5173, - }, -}) \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/.eslintrc.json b/examples/typescript/legacy/fullstack/farcaster-miniapp/.eslintrc.json deleted file mode 100644 index 3350ae4409..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/.eslintrc.json +++ /dev/null @@ -1,4 +0,0 @@ -{ - "extends": ["next/core-web-vitals", "next/typescript"], - "ignorePatterns": ["next-env.d.ts"] -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/.gitignore b/examples/typescript/legacy/fullstack/farcaster-miniapp/.gitignore deleted file mode 100644 index 504d5073b1..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js -.yarn/install-state.gz - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env* - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/.prettierrc b/examples/typescript/legacy/fullstack/farcaster-miniapp/.prettierrc deleted file mode 100644 index 0967ef424b..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/.prettierrc +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/.yarnrc.yml b/examples/typescript/legacy/fullstack/farcaster-miniapp/.yarnrc.yml deleted file mode 100644 index ff3530a648..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/.yarnrc.yml +++ /dev/null @@ -1,2 +0,0 @@ -# You can remove this file if you don't want to use Yarn package manager. -nodeLinker: node-modules diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/README.md b/examples/typescript/legacy/fullstack/farcaster-miniapp/README.md deleted file mode 100644 index 55683ec31c..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/README.md +++ /dev/null @@ -1,318 +0,0 @@ -# x402 Farcaster Mini App Example - -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-onchain --mini`](), configured with [MiniKit](https://docs.base.org/builderkits/minikit/overview) and [OnchainKit](https://www.base.org/builders/onchainkit). It demonstrates how to build a [Farcaster Mini App](https://miniapps.farcaster.xyz/) with x402 payment-protected API endpoints, showcasing seamless integration between Farcaster's social platform and x402's payment protocol. - -## Features - -- 🚀 **Farcaster Mini App**: Native-like app experience within Farcaster -- 💳 **x402 Payments**: Seamless payment processing on Base network -- 🔗 **Wallet Integration**: Connect with Coinbase Wallet via OnchainKit -- 🛡️ **Protected API Routes**: Server-side payment verification with x402 middleware -- 📱 **Responsive Design**: Optimized for mobile and desktop experiences -- 🔔 **Background Notifications**: Redis-backed notification system using Upstash -- 🎨 **Custom Theming**: Pixel font integration with Pixelify Sans and dark/light mode support - -## Tech Stack - -- **Frontend**: Next.js 15, React 19, TypeScript -- **Styling**: Tailwind CSS -- **Wallet**: OnchainKit, Coinbase Wallet, Wagmi -- **Payments**: x402 protocol with Base network -- **Farcaster**: Frame SDK for Mini App detection and integration -- **Notifications**: Redis/Upstash for background notifications - -## Prerequisites - -- Node.js 22+ -- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- Coinbase Wallet -- API keys (see Environment Setup) - -## Getting Started - -1. Install dependencies: - -```bash -npm install -# or -yarn install -# or -pnpm install -# or -bun install -``` - -2. Install and build all packages from the typescript examples root: - -```bash -cd ../../ -pnpm install -pnpm build -cd fullstack/farcaster-miniapp -``` - -3. Copy environment variables: - -```bash -cp env.example .env.local -``` - -4. Configure your environment variables (see Environment Setup below) - -5. Start the development server: - -```bash -pnpm dev -``` - -6. Open [http://localhost:3000](http://localhost:3000) with your browser - -## Environment Setup - -Configure the following variables in your `.env.local`: - -### Required Variables - -```bash -# OnchainKit Configuration -NEXT_PUBLIC_ONCHAINKIT_API_KEY=your_onchainkit_api_key_here -NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME=x402 Mini App - -# x402 Payment Configuration -RESOURCE_WALLET_ADDRESS=0x0000000000000000000000000000000000000000 -NETWORK=base-sepolia - -# CDP Wallet Configuration (required for x402 base mainnet settlements) -CDP_API_KEY_ID=your_cdp_api_key_id_here -CDP_API_KEY_SECRET=your_cdp_api_key_secret_here -CDP_WALLET_SECRET=your_cdp_wallet_secret_here -``` - -### Farcaster Frame Configuration - -You can regenerate the FARCASTER Account Association environment variables by running `npx create-onchain --manifest` in your project directory. - -The environment variables enable the following features: - -- Frame metadata - Sets up the Frame Embed that will be shown when you cast your frame -- Account association - Allows users to add your frame to their account, enables notifications -- Redis API keys - Enable Webhooks and background notifications for your application by storing users notification details - -```bash -# Shared/OnchainKit variables -NEXT_PUBLIC_URL= -NEXT_PUBLIC_ICON_URL= - -# Frame metadata -FARCASTER_HEADER= -FARCASTER_PAYLOAD= -FARCASTER_SIGNATURE= -NEXT_PUBLIC_APP_ICON= -NEXT_PUBLIC_APP_SUBTITLE= -NEXT_PUBLIC_APP_DESCRIPTION= -NEXT_PUBLIC_APP_SPLASH_IMAGE= -NEXT_PUBLIC_SPLASH_BACKGROUND_COLOR= -NEXT_PUBLIC_APP_PRIMARY_CATEGORY= -NEXT_PUBLIC_APP_HERO_IMAGE= -NEXT_PUBLIC_APP_TAGLINE= -NEXT_PUBLIC_APP_OG_TITLE= -NEXT_PUBLIC_APP_OG_DESCRIPTION= -NEXT_PUBLIC_APP_OG_IMAGE= - -# Redis config -REDIS_URL= -REDIS_TOKEN= -``` - -### Getting API Keys - -1. **CDP API Keys**: Get from [Coinbase Developer Platform](https://portal.cdp.coinbase.com/projects/overview) -2. **OnchainKit API Key**: Get from [OnchainKit](https://onchainkit.xyz) -3. **Resource Wallet Address**: Your wallet address to receive payments -4. **Network**: Use `base-sepolia` for testing, `base` for production - -## How It Works - -### Farcaster Mini App Integration - -The app uses the Farcaster Frame SDK to detect when it's running within a Mini App context: - -```typescript -import { sdk } from "@farcaster/frame-sdk"; - -// Initialize and detect Mini App context -await sdk.actions.ready(); -const isInMiniApp = await sdk.isInMiniApp(); -``` - -### x402 Payment Protection - -The `/api/protected` endpoint is protected using x402 middleware: - -```typescript -// middleware.ts -export const middleware = paymentMiddleware( - payTo, - { - "/api/protected": { - price: "$0.01", - network, - config: { - description: "Protected route", - }, - }, - }, - facilitator, -); -``` - -### Client-Side Payment Handling - -The frontend uses `x402-fetch` to automatically handle payments when calling protected endpoints: - -```typescript -import { wrapFetchWithPayment } from "x402-fetch"; - -const fetchWithPayment = wrapFetchWithPayment(fetch, walletClient); -const response = await fetchWithPayment("/api/protected"); -``` - -## Template Features - -### Frame Configuration - -- `.well-known/farcaster.json` endpoint configured for Frame metadata and account association -- Frame metadata automatically added to page headers in `layout.tsx` - -### Background Notifications - -- Redis-backed notification system using Upstash -- Ready-to-use notification endpoints in `api/notify` and `api/webhook` -- Notification client utilities in `lib/notification-client.ts` - -### Theming - -- Custom theme defined in `theme.css` with OnchainKit variables -- Pixel font integration with Pixelify Sans -- Dark/light mode support through OnchainKit - -### MiniKit Provider - -The app is wrapped with `MiniKitProvider` in `providers.tsx`, configured with: - -- OnchainKit integration -- Access to Frames context -- Sets up Wagmi Connectors -- Sets up Frame SDK listeners -- Applies Safe Area Insets - -## Example Flow - -1. **User opens the Mini App** in Farcaster -2. **Connect wallet** using OnchainKit's Wallet component -3. **Call protected API** - the app automatically: - - Detects payment requirement (402 response) - - Creates and signs payment transaction - - Retries request with payment header - - Receives protected content - -## Response Format - -### Payment Required (402) - -```json -{ - "error": "X-PAYMENT header is required", - "paymentRequirements": { - "scheme": "exact", - "network": "base-sepolia", - "maxAmountRequired": "10000", - "resource": "http://localhost:3000/api/protected", - "description": "Protected route", - "payTo": "0xYourAddress", - "maxTimeoutSeconds": 60 - } -} -``` - -### Successful Response - -```json -{ - "message": "Protected content accessed successfully", - "timestamp": "2024-01-01T00:00:00Z" -} -``` - -## Extending the Example - -### Adding More Protected Routes - -Update the middleware configuration: - -```typescript -export const middleware = paymentMiddleware( - payTo, - { - "/api/protected": { - price: "$0.01", - network, - config: { - description: "Protected route", - }, - }, - "/api/premium": { - price: "$0.10", - network, - config: { - description: "Premium content access", - }, - }, - }, - facilitator, -); - -export const config = { - matcher: ["/api/protected", "/api/premium"], - runtime: "nodejs", -}; -``` - -### Customizing for Your Mini App - -1. **Remove the DemoComponents**: - - Delete `components/DemoComponents.tsx` - - Remove demo-related imports from `page.tsx` - -2. **Start building your Frame**: - - Modify `page.tsx` to create your Frame UI - - Update theme variables in `theme.css` - - Adjust MiniKit configuration in `providers.tsx` - -3. **Update the project name** in environment variables -4. **Modify the UI** to match your app's branding -5. **Add your own protected endpoints** following the x402 pattern -6. **Integrate with Farcaster data** using the Frame SDK -7. **Deploy to your domain** for Mini App distribution - -8. **Add your frame to your account**: - - Cast your frame to see it in action - - Share your frame with others to start building your community - -## Publishing Your Mini App - -1. **Deploy your app** to a public domain -2. **Submit to Farcaster** for Mini App discovery -3. **Configure your domain** in the Farcaster Mini App settings -4. **Test the full flow** in the Farcaster app - -## Resources - -- [Farcaster Mini Apps Documentation](https://miniapps.farcaster.xyz/) -- [x402 Protocol Documentation](https://x402.com) -- [OnchainKit Documentation](https://onchainkit.xyz) -- [Coinbase Developer Platform](https://portal.cdp.coinbase.com/) -- [MiniKit Documentation](https://docs.base.org/builderkits/minikit/overview) -- [OnchainKit Documentation](https://docs.base.org/builderkits/onchainkit/getting-started) -- [Next.js Documentation](https://nextjs.org/docs) -- [Tailwind CSS Documentation](https://tailwindcss.com/docs) diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/.well-known/farcaster.json/route.ts b/examples/typescript/legacy/fullstack/farcaster-miniapp/app/.well-known/farcaster.json/route.ts deleted file mode 100644 index 8a3ea53efd..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/.well-known/farcaster.json/route.ts +++ /dev/null @@ -1,45 +0,0 @@ -/// - -function withValidProperties( - properties: Record, -) { - return Object.fromEntries( - Object.entries(properties).filter(([key, value]) => { - if (Array.isArray(value)) { - return value.length > 0; - } - return !!value; - }), - ); -} - -export async function GET() { - const URL = process.env.NEXT_PUBLIC_URL; - - return Response.json({ - accountAssociation: { - header: process.env.FARCASTER_HEADER, - payload: process.env.FARCASTER_PAYLOAD, - signature: process.env.FARCASTER_SIGNATURE, - }, - frame: withValidProperties({ - version: "1", - name: process.env.NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME, - subtitle: process.env.NEXT_PUBLIC_APP_SUBTITLE, - description: process.env.NEXT_PUBLIC_APP_DESCRIPTION, - screenshotUrls: [], - iconUrl: process.env.NEXT_PUBLIC_APP_ICON, - splashImageUrl: process.env.NEXT_PUBLIC_APP_SPLASH_IMAGE, - splashBackgroundColor: process.env.NEXT_PUBLIC_SPLASH_BACKGROUND_COLOR, - homeUrl: URL, - webhookUrl: `${URL}/api/webhook`, - primaryCategory: process.env.NEXT_PUBLIC_APP_PRIMARY_CATEGORY, - tags: [], - heroImageUrl: process.env.NEXT_PUBLIC_APP_HERO_IMAGE, - tagline: process.env.NEXT_PUBLIC_APP_TAGLINE, - ogTitle: process.env.NEXT_PUBLIC_APP_OG_TITLE, - ogDescription: process.env.NEXT_PUBLIC_APP_OG_DESCRIPTION, - ogImageUrl: process.env.NEXT_PUBLIC_APP_OG_IMAGE, - }), - }); -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/api/notify/route.ts b/examples/typescript/legacy/fullstack/farcaster-miniapp/app/api/notify/route.ts deleted file mode 100644 index 0f79ee76b4..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/api/notify/route.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { sendFrameNotification } from "@/lib/notification-client"; -import { NextResponse } from "next/server"; - -export async function POST(request: Request) { - try { - const body = await request.json(); - const { fid, notification } = body; - - const result = await sendFrameNotification({ - fid, - title: notification.title, - body: notification.body, - notificationDetails: notification.notificationDetails, - }); - - if (result.state === "error") { - return NextResponse.json({ error: result.error }, { status: 500 }); - } - - return NextResponse.json({ success: true }, { status: 200 }); - } catch (error) { - return NextResponse.json( - { - error: error instanceof Error ? error.message : "Unknown error", - }, - { status: 400 }, - ); - } -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/api/protected/route.ts b/examples/typescript/legacy/fullstack/farcaster-miniapp/app/api/protected/route.ts deleted file mode 100644 index 4e930a60ba..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/api/protected/route.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { NextResponse } from "next/server"; - -/** - * Protected API endpoint that requires x402 payment to access. - * This route demonstrates how to protect API endpoints with payment requirements. - * - * @returns {Promise} JSON response indicating success or error - */ -export async function GET() { - try { - console.log("Protected route accessed successfully"); - - return NextResponse.json({ - success: true, - message: "Protected action completed successfully", - timestamp: new Date().toISOString(), - }); - } catch (error) { - console.error("Error in protected route:", error); - return NextResponse.json( - { - error: "Internal server error", - details: error instanceof Error ? error.message : "Unknown error", - }, - { status: 500 }, - ); - } -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/api/webhook/route.ts b/examples/typescript/legacy/fullstack/farcaster-miniapp/app/api/webhook/route.ts deleted file mode 100644 index fd166a9997..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/api/webhook/route.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { - setUserNotificationDetails, - deleteUserNotificationDetails, -} from "@/lib/notification"; -import { sendFrameNotification } from "@/lib/notification-client"; -import { http } from "viem"; -import { createPublicClient } from "viem"; -import { optimism } from "viem/chains"; - -const appName = process.env.NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME; - -const KEY_REGISTRY_ADDRESS = "0x00000000Fc1237824fb747aBDE0FF18990E59b7e"; - -const KEY_REGISTRY_ABI = [ - { - inputs: [ - { name: "fid", type: "uint256" }, - { name: "key", type: "bytes" }, - ], - name: "keyDataOf", - outputs: [ - { - components: [ - { name: "state", type: "uint8" }, - { name: "keyType", type: "uint32" }, - ], - name: "", - type: "tuple", - }, - ], - stateMutability: "view", - type: "function", - }, -] as const; - -async function verifyFidOwnership(fid: number, appKey: `0x${string}`) { - const client = createPublicClient({ - chain: optimism, - transport: http(), - }); - - try { - const result = await client.readContract({ - address: KEY_REGISTRY_ADDRESS, - abi: KEY_REGISTRY_ABI, - functionName: "keyDataOf", - args: [BigInt(fid), appKey], - }); - - return result.state === 1 && result.keyType === 1; - } catch (error) { - console.error("Key Registry verification failed:", error); - return false; - } -} - -function decode(encoded: string) { - return JSON.parse(Buffer.from(encoded, "base64url").toString("utf-8")); -} - -export async function POST(request: Request) { - const requestJson = await request.json(); - - const { header: encodedHeader, payload: encodedPayload } = requestJson; - - const headerData = decode(encodedHeader); - const event = decode(encodedPayload); - - const { fid, key } = headerData; - - const valid = await verifyFidOwnership(fid, key); - - if (!valid) { - return Response.json( - { success: false, error: "Invalid FID ownership" }, - { status: 401 }, - ); - } - - switch (event.event) { - case "frame_added": - console.log( - "frame_added", - "event.notificationDetails", - event.notificationDetails, - ); - if (event.notificationDetails) { - await setUserNotificationDetails(fid, event.notificationDetails); - await sendFrameNotification({ - fid, - title: `Welcome to ${appName}`, - body: `Thank you for adding ${appName}`, - }); - } else { - await deleteUserNotificationDetails(fid); - } - - break; - case "frame_removed": { - console.log("frame_removed"); - await deleteUserNotificationDetails(fid); - break; - } - case "notifications_enabled": { - console.log("notifications_enabled", event.notificationDetails); - await setUserNotificationDetails(fid, event.notificationDetails); - await sendFrameNotification({ - fid, - title: `Welcome to ${appName}`, - body: `Thank you for enabling notifications for ${appName}`, - }); - - break; - } - case "notifications_disabled": { - console.log("notifications_disabled"); - await deleteUserNotificationDetails(fid); - - break; - } - } - - return Response.json({ success: true }); -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/globals.css b/examples/typescript/legacy/fullstack/farcaster-miniapp/app/globals.css deleted file mode 100644 index e597b8211f..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/globals.css +++ /dev/null @@ -1,70 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -/* Base styles */ -html { - scroll-behavior: smooth; -} - -body { - font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen', - 'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue', - sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; - min-height: 100vh; - min-height: 100dvh; -} - -/* Mini app optimizations */ -@media (max-width: 768px) { - - button, - [role="button"] { - min-height: 44px; - min-width: 44px; - } - - input, - textarea, - select { - font-size: 16px; - } -} - -/* Custom scrollbar */ -::-webkit-scrollbar { - width: 6px; -} - -::-webkit-scrollbar-track { - background: transparent; -} - -::-webkit-scrollbar-thumb { - background: rgba(148, 163, 184, 0.3); - border-radius: 3px; -} - -::-webkit-scrollbar-thumb:hover { - background: rgba(148, 163, 184, 0.5); -} - -/* Focus styles */ -button:focus-visible, -input:focus-visible, -textarea:focus-visible, -select:focus-visible { - outline: 2px solid #3b82f6; - outline-offset: 2px; -} - -/* Reduced motion support */ -@media (prefers-reduced-motion: reduce) { - * { - animation-duration: 0.01ms !important; - animation-iteration-count: 1 !important; - transition-duration: 0.01ms !important; - } -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/layout.tsx b/examples/typescript/legacy/fullstack/farcaster-miniapp/app/layout.tsx deleted file mode 100644 index c0f0f6ff2c..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/layout.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import "./theme.css"; -import "@coinbase/onchainkit/styles.css"; -import type { Metadata, Viewport } from "next"; -import { Inter } from "next/font/google"; -import "./globals.css"; -import { Providers } from "./providers"; - -const inter = Inter({ subsets: ["latin"] }); - -export const metadata: Metadata = { - title: "x402 Mini App Template", - description: - "A clean template with x402, OnchainKit, and Farcaster as a mini app.", - keywords: ["mini app", "x402", "onchainkit", "farcaster", "web3"], - authors: [{ name: "Example Team" }], - - // Open Graph metadata for social sharing and embeds - openGraph: { - title: "x402 Mini App Template", - description: - "A clean template with x402, OnchainKit, and Farcaster as a mini app.", - type: "website", - url: process.env.NEXT_PUBLIC_URL || "https://example.com/", - siteName: "x402 Mini App", - images: [ - { - url: process.env.NEXT_PUBLIC_APP_HERO_IMAGE || "/app-logo.png", - width: 1200, - height: 630, - alt: "x402 Mini App Template", - }, - ], - }, - - // Twitter Card metadata - twitter: { - card: "summary_large_image", - title: "x402 Mini App Template", - description: - "A clean template with x402, OnchainKit, and Farcaster as a mini app.", - images: [process.env.NEXT_PUBLIC_APP_HERO_IMAGE || "/app-logo.png"], - }, - - appleWebApp: { - capable: true, - statusBarStyle: "default", - title: process.env.NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME || "x402 Mini App", - }, - formatDetection: { - telephone: false, - }, - robots: { - index: false, - follow: false, - }, - - // Farcaster Frame metadata - other: { - "fc:frame": JSON.stringify({ - version: "next", - imageUrl: process.env.NEXT_PUBLIC_APP_HERO_IMAGE, - button: { - title: `Launch ${process.env.NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME || "x402 Mini App"}`, - action: { - type: "launch_frame", - name: - process.env.NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME || "x402 Mini App", - url: process.env.NEXT_PUBLIC_URL, - splashImageUrl: process.env.NEXT_PUBLIC_SPLASH_IMAGE, - splashBackgroundColor: - process.env.NEXT_PUBLIC_SPLASH_BACKGROUND_COLOR, - }, - }, - }), - }, -}; - -export const viewport: Viewport = { - width: "device-width", - initialScale: 1, - maximumScale: 1, - userScalable: false, - viewportFit: "cover", - themeColor: [ - { media: "(prefers-color-scheme: light)", color: "#ffffff" }, - { media: "(prefers-color-scheme: dark)", color: "#0f172a" }, - ], -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - {/* Additional meta tags for mini app embedding */} - - - - - - {/* Prevent zooming and ensure proper scaling in mini apps */} - - - {/* Favicon and app icons */} - - - - - - - {/* Preconnect to external domains for better performance */} - - - - - - {children} - - - ); -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/page.tsx b/examples/typescript/legacy/fullstack/farcaster-miniapp/app/page.tsx deleted file mode 100644 index a518a7647a..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/page.tsx +++ /dev/null @@ -1,291 +0,0 @@ -"use client"; - -import { - useMiniKit, - useAddFrame, -} from "@coinbase/onchainkit/minikit"; -import { - Name, - Identity, - Address, - Avatar, - EthBalance, -} from "@coinbase/onchainkit/identity"; -import { - ConnectWallet, - Wallet, - WalletDropdown, - WalletDropdownDisconnect, -} from "@coinbase/onchainkit/wallet"; -import { useEffect, useMemo, useState, useCallback } from "react"; -import { useAccount } from "wagmi"; -import { sdk } from "@farcaster/frame-sdk"; -import { wrapFetchWithPayment } from "x402-fetch"; -import { getWalletClient } from "wagmi/actions"; -import { createConfig, http } from "@wagmi/core"; -import { base, baseSepolia } from "@wagmi/core/chains"; -import { createClient } from "viem"; - -export default function App() { - const { setFrameReady, isFrameReady, context } = useMiniKit(); - const [frameAdded, setFrameAdded] = useState(false); - const [isInMiniApp, setIsInMiniApp] = useState(false); - const [isLoading, setIsLoading] = useState(false); - const [message, setMessage] = useState(""); - const { address, isConnected, connector, chainId } = useAccount(); - - const addFrame = useAddFrame(); - - const config = createConfig({ - chains: [base, baseSepolia], - client({ chain }) { - return createClient({ chain, transport: http() }); - }, - }); - - // Initialize Farcaster Mini App SDK - useEffect(() => { - const initMiniApp = async () => { - try { - await sdk.actions.ready(); - const isInMiniApp = await sdk.isInMiniApp(); - setIsInMiniApp(isInMiniApp); - } catch (error) { - console.log('Not running in Mini App context or SDK not available:', error); - } - }; - - initMiniApp(); - }, []); - - useEffect(() => { - if (!isFrameReady) { - setFrameReady(); - } - }, [setFrameReady, isFrameReady]); - - const handleAddFrame = useCallback(async () => { - const frameAdded = await addFrame(); - setFrameAdded(Boolean(frameAdded)); - }, [addFrame]); - - const handleProtectedAction = useCallback(async () => { - if (!isConnected) { - setMessage("Please connect your wallet first"); - return; - } - - setIsLoading(true); - setMessage(""); - - const walletClient = await getWalletClient(config, { - account: address, - chainId: chainId, - connector: connector, - }); - - if (!walletClient) { - setMessage("Wallet client not available"); - return; - } - - // For x402-fetch, we need to pass the wallet client's account - const fetchWithPayment = wrapFetchWithPayment( - fetch, - walletClient as unknown as Parameters[1] - ); - - try { - const response = await fetchWithPayment("/api/protected", { - method: "GET", - }); - - if (!response.ok) { - console.log(response) - throw new Error(`HTTP error! status: ${response.status}`); - } - - const data = await response.json(); - setMessage(`Success! Response: ${JSON.stringify(data)}`); - } catch (error) { - console.error("Error calling protected API:", error); - setMessage( - `Error: ${error instanceof Error ? error.message : "Unknown error"}` - ); - } finally { - setIsLoading(false); - } - }, [isConnected, address, chainId, connector, config]); - - const saveFrameButton = useMemo(() => { - if (context && !context.client.added) { - return ( - - ); - } - - if (frameAdded) { - return ( -
- - - - Saved -
- ); - } - - return null; - }, [context, frameAdded, handleAddFrame]); - - return ( -
- {/* Header */} -
-
-
-
-

x402 Mini App Template

-

- {isInMiniApp ? 'Running as Mini App' : 'Running in browser'} -

-
- -
-
- - - - - - - - -
- - - - - -
-
{saveFrameButton}
-
-
-
-
- -
-
- {/* Hero Section */} -
-

- Welcome to Your Mini App -

-

- This is a clean template with x402, OnchainKit, and Farcaster as a mini app. -

-
- - {/* Connection Status */} -
-

- Connection Status -

-
-
- Wallet Connected: - - {isConnected ? 'Yes' : 'No'} - -
- {isConnected && ( - <> -
- Address: - - {address?.slice(0, 6)}...{address?.slice(-4)} - -
-
- Chain ID: - {chainId} -
- - )} -
- Mini App Context: - - {isInMiniApp ? 'Yes' : 'No'} - -
-
-
- - {/* Protected Action */} -
-

- Protected Action -

-

- This button calls the x402 protected API endpoint. -

- - {message && ( -
-
- {message.startsWith('Error') ? ( - - - - ) : ( - - - - )} - {message} -
-
- )} -
- - {/* Instructions */} -
-

- Getting Started -

-
-

• Connect your wallet using the button in the header

-

• The app will automatically detect if it's running in a Farcaster Mini App

-

• Use the "Call Protected API" button to test the protected endpoint

-

• Customize this template by adding your own features and logic

-
-
-
-
-
- ); -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/providers.tsx b/examples/typescript/legacy/fullstack/farcaster-miniapp/app/providers.tsx deleted file mode 100644 index 321da36ee1..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/providers.tsx +++ /dev/null @@ -1,23 +0,0 @@ -"use client"; - -import { base } from "wagmi/chains"; -import { MiniKitProvider } from "@coinbase/onchainkit/minikit"; - -export function Providers({ children }: { children: React.ReactNode }) { - return ( - - {children} - - ); -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/theme.css b/examples/typescript/legacy/fullstack/farcaster-miniapp/app/theme.css deleted file mode 100644 index d1524b5cff..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/app/theme.css +++ /dev/null @@ -1,137 +0,0 @@ -@import url("https://fonts.googleapis.com/css2?family=Geist:wght@100..900&display=swap"); - -@tailwind base; -@tailwind components; -@tailwind utilities; - -:root { - --app-background: #ffffff; - --app-foreground: #111111; - --app-foreground-muted: #58585c; - --app-accent: #0052ff; - --app-accent-hover: #0047e1; - --app-accent-active: #003db8; - --app-accent-light: #e6edff; - --app-gray: #f5f5f5; - --app-gray-dark: #e0e0e0; - --app-card-bg: rgba(255, 255, 255, 0.4); - --app-card-border: rgba(0, 0, 0, 0.1); -} - -@media (prefers-color-scheme: dark) { - :root { - --app-background: #111111; - --app-foreground: #ffffff; - --app-foreground-muted: #c8c8d1; - --app-accent: #0052ff; - --app-accent-hover: #0047e1; - --app-accent-active: #003db8; - --app-accent-light: #1e293b; - --app-gray: #1e1e1e; - --app-gray-dark: #2e2e2e; - --app-card-bg: rgba(17, 17, 17, 0.4); - --app-card-border: rgba(115, 115, 115, 0.5); - } -} - -.mini-app-theme { - --ock-font-family: "Geist", sans-serif; - --ock-border-radius: 0.75rem; - --ock-border-radius-inner: 0.5rem; - - /* Text colors */ - --ock-text-inverse: var(--app-background); - --ock-text-foreground: var(--app-foreground); - --ock-text-foreground-muted: var(--app-foreground-muted); - --ock-text-error: #ef4444; - --ock-text-primary: var(--app-accent); - --ock-text-success: #22c55e; - --ock-text-warning: #f59e0b; - --ock-text-disabled: #a1a1aa; - - /* Background colors */ - --ock-bg-default: var(--app-background); - --ock-bg-default-hover: var(--app-gray); - --ock-bg-default-active: var(--app-gray-dark); - --ock-bg-alternate: var(--app-gray); - --ock-bg-alternate-hover: var(--app-gray-dark); - --ock-bg-alternate-active: var(--app-gray-dark); - --ock-bg-inverse: var(--app-foreground); - --ock-bg-inverse-hover: #2a2a2a; - --ock-bg-inverse-active: #3a3a3a; - --ock-bg-primary: var(--app-accent); - --ock-bg-primary-hover: var(--app-accent-hover); - --ock-bg-primary-active: var(--app-accent-active); - --ock-bg-primary-washed: var(--app-accent-light); - --ock-bg-primary-disabled: #80a8ff; - --ock-bg-secondary: var(--app-gray); - --ock-bg-secondary-hover: var(--app-gray-dark); - --ock-bg-secondary-active: #d1d1d1; - --ock-bg-error: #fee2e2; - --ock-bg-warning: #fef3c7; - --ock-bg-success: #dcfce7; - --ock-bg-default-reverse: var(--app-foreground); - - /* Icon colors */ - --ock-icon-color-primary: var(--app-accent); - --ock-icon-color-foreground: var(--app-foreground); - --ock-icon-color-foreground-muted: #71717a; - --ock-icon-color-inverse: var(--app-background); - --ock-icon-color-error: #ef4444; - --ock-icon-color-success: #22c55e; - --ock-icon-color-warning: #f59e0b; - - /* Line colors */ - --ock-line-primary: var(--app-accent); - --ock-line-default: var(--app-gray-dark); - --ock-line-heavy: #a1a1aa; - --ock-line-inverse: #d4d4d8; -} - -* { - touch-action: manipulation; -} - -body { - color: var(--app-foreground); - background: var(--app-background); - font-family: var(--font-geist-sans), sans-serif; - font-optical-sizing: auto; - font-weight: 400; - font-style: normal; -} - -@layer utilities { - .text-balance { - text-wrap: balance; - } -} - -.animate-fade-in { - animation: fadeIn 0.5s ease-in-out; -} - -.animate-fade-out { - animation: fadeOut 3s forwards; -} - -@keyframes fadeIn { - from { - opacity: 0; - } - to { - opacity: 1; - } -} - -@keyframes fadeOut { - 0% { - opacity: 1; - } - 50% { - opacity: 1; - } - 100% { - opacity: 0; - } -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/env.example b/examples/typescript/legacy/fullstack/farcaster-miniapp/env.example deleted file mode 100644 index 6ac4ab87aa..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/env.example +++ /dev/null @@ -1,18 +0,0 @@ -# OnchainKit Configuration -NEXT_PUBLIC_ONCHAINKIT_API_KEY=your_onchainkit_api_key_here -NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME=x402 Mini App Template - -# App URLs and Images -NEXT_PUBLIC_URL=http://localhost:3002 -NEXT_PUBLIC_APP_HERO_IMAGE=https://example.com/app-logo.png -NEXT_PUBLIC_SPLASH_IMAGE=https://example.com/app-logo-200x200.png -NEXT_PUBLIC_SPLASH_BACKGROUND_COLOR=#3b82f6 -NEXT_PUBLIC_ICON_URL=https://example.com/app-logo.png - -# x402 Payment Configuration -RESOURCE_WALLET_ADDRESS=0x0000000000000000000000000000000000000000 -NETWORK=base-sepolia - -# CDP Wallet Configuration (required for x402 base mainnet settlements) -CDP_API_KEY_ID=your_cdp_api_key_id_here -CDP_API_KEY_SECRET=your_cdp_api_key_secret_here \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/lib/notification-client.ts b/examples/typescript/legacy/fullstack/farcaster-miniapp/lib/notification-client.ts deleted file mode 100644 index 74071566e8..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/lib/notification-client.ts +++ /dev/null @@ -1,67 +0,0 @@ -import { - FrameNotificationDetails, - type SendNotificationRequest, - sendNotificationResponseSchema, -} from "@farcaster/frame-sdk"; -import { getUserNotificationDetails } from "@/lib/notification"; - -const appUrl = process.env.NEXT_PUBLIC_URL || ""; - -type SendFrameNotificationResult = - | { - state: "error"; - error: unknown; - } - | { state: "no_token" } - | { state: "rate_limit" } - | { state: "success" }; - -export async function sendFrameNotification({ - fid, - title, - body, - notificationDetails, -}: { - fid: number; - title: string; - body: string; - notificationDetails?: FrameNotificationDetails | null; -}): Promise { - if (!notificationDetails) { - notificationDetails = await getUserNotificationDetails(fid); - } - if (!notificationDetails) { - return { state: "no_token" }; - } - - const response = await fetch(notificationDetails.url, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - notificationId: crypto.randomUUID(), - title, - body, - targetUrl: appUrl, - tokens: [notificationDetails.token], - } satisfies SendNotificationRequest), - }); - - const responseJson = await response.json(); - - if (response.status === 200) { - const responseBody = sendNotificationResponseSchema.safeParse(responseJson); - if (responseBody.success === false) { - return { state: "error", error: responseBody.error.errors }; - } - - if (responseBody.data.result.rateLimitedTokens.length) { - return { state: "rate_limit" }; - } - - return { state: "success" }; - } - - return { state: "error", error: responseJson }; -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/lib/notification.ts b/examples/typescript/legacy/fullstack/farcaster-miniapp/lib/notification.ts deleted file mode 100644 index 569690c12d..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/lib/notification.ts +++ /dev/null @@ -1,42 +0,0 @@ -import type { FrameNotificationDetails } from "@farcaster/frame-sdk"; -import { redis } from "./redis"; - -const notificationServiceKey = - process.env.NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME ?? "minikit"; - -function getUserNotificationDetailsKey(fid: number): string { - return `${notificationServiceKey}:user:${fid}`; -} - -export async function getUserNotificationDetails( - fid: number, -): Promise { - if (!redis) { - return null; - } - - return await redis.get( - getUserNotificationDetailsKey(fid), - ); -} - -export async function setUserNotificationDetails( - fid: number, - notificationDetails: FrameNotificationDetails, -): Promise { - if (!redis) { - return; - } - - await redis.set(getUserNotificationDetailsKey(fid), notificationDetails); -} - -export async function deleteUserNotificationDetails( - fid: number, -): Promise { - if (!redis) { - return; - } - - await redis.del(getUserNotificationDetailsKey(fid)); -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/lib/redis.ts b/examples/typescript/legacy/fullstack/farcaster-miniapp/lib/redis.ts deleted file mode 100644 index 95ab7bcccc..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/lib/redis.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Redis } from "@upstash/redis"; - -if (!process.env.REDIS_URL || !process.env.REDIS_TOKEN) { - console.warn( - "REDIS_URL or REDIS_TOKEN environment variable is not defined, please add to enable background notifications and webhooks.", - ); -} - -export const redis = - process.env.REDIS_URL && process.env.REDIS_TOKEN - ? new Redis({ - url: process.env.REDIS_URL, - token: process.env.REDIS_TOKEN, - }) - : null; diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/middleware.ts b/examples/typescript/legacy/fullstack/farcaster-miniapp/middleware.ts deleted file mode 100644 index 7ec7ee57e6..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/middleware.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Address } from "viem"; -import { paymentMiddleware } from "x402-next"; - -const payTo = process.env.RESOURCE_WALLET_ADDRESS as Address; -const network = (process.env.NETWORK || "base-sepolia") as - | "base" - | "base-sepolia"; - -// Validate required environment variables -if (!payTo || payTo === "0x0000000000000000000000000000000000000000") { - console.warn( - "RESOURCE_WALLET_ADDRESS not set or is default value. Please set a valid wallet address.", - ); -} - -export const middleware = paymentMiddleware(payTo, { - "/api/protected": { - price: "$0.01", - network, - config: { - description: "Protected route", - }, - }, -}); - -// Configure which paths the middleware should run on -export const config = { - matcher: ["/api/protected"], - runtime: "nodejs", -}; diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/next.config.mjs b/examples/typescript/legacy/fullstack/farcaster-miniapp/next.config.mjs deleted file mode 100644 index 0a7c9af751..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/next.config.mjs +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = { -}; - -export default nextConfig; diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/package.json b/examples/typescript/legacy/fullstack/farcaster-miniapp/package.json deleted file mode 100644 index 39bdf7c951..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/package.json +++ /dev/null @@ -1,44 +0,0 @@ -{ - "name": "x402-mini-app", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", - "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", - "lint": "eslint . --ext .ts --fix", - "lint:check": "eslint . --ext .ts" - }, - "dependencies": { - "@coinbase/onchainkit": "^0.38.14", - "@farcaster/frame-sdk": "^0.0.60", - "@tanstack/react-query": "^5", - "@upstash/redis": "^1.34.4", - "@wagmi/core": "^2.17.1", - "next": "15.5.9", - "react": "19.2.3", - "react-dom": "19.2.3", - "react-hot-toast": "^2.5.2", - "viem": "^2.27.2", - "wagmi": "^2.14.11", - "x402-fetch": "workspace:*", - "x402-next": "workspace:*" - }, - "devDependencies": { - "@types/node": "^20.17.30", - "@types/react": "^19", - "@types/react-dom": "^19", - "eslint": "^8", - "eslint-config-next": "15.5.7", - "eslint-config-prettier": "^10.1.1", - "eslint-plugin-prettier": "^5.2.3", - "eslint-plugin-react": "^7.37.4", - "eslint-plugin-react-hooks": "^5.2.0", - "postcss": "^8", - "prettier": "^3.5.3", - "tailwindcss": "^3.4.1", - "typescript": "^5" - } -} diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/postcss.config.mjs b/examples/typescript/legacy/fullstack/farcaster-miniapp/postcss.config.mjs deleted file mode 100644 index 1a69fd2a45..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/postcss.config.mjs +++ /dev/null @@ -1,8 +0,0 @@ -/** @type {import('postcss-load-config').Config} */ -const config = { - plugins: { - tailwindcss: {}, - }, -}; - -export default config; diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/public/hero.png b/examples/typescript/legacy/fullstack/farcaster-miniapp/public/hero.png deleted file mode 100644 index c5ec486188..0000000000 Binary files a/examples/typescript/legacy/fullstack/farcaster-miniapp/public/hero.png and /dev/null differ diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/public/icon.png b/examples/typescript/legacy/fullstack/farcaster-miniapp/public/icon.png deleted file mode 100644 index 4e3c828cfc..0000000000 Binary files a/examples/typescript/legacy/fullstack/farcaster-miniapp/public/icon.png and /dev/null differ diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/public/logo.png b/examples/typescript/legacy/fullstack/farcaster-miniapp/public/logo.png deleted file mode 100644 index f2738288f2..0000000000 Binary files a/examples/typescript/legacy/fullstack/farcaster-miniapp/public/logo.png and /dev/null differ diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/public/screenshot.png b/examples/typescript/legacy/fullstack/farcaster-miniapp/public/screenshot.png deleted file mode 100644 index 46987b6ee2..0000000000 Binary files a/examples/typescript/legacy/fullstack/farcaster-miniapp/public/screenshot.png and /dev/null differ diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/public/splash.png b/examples/typescript/legacy/fullstack/farcaster-miniapp/public/splash.png deleted file mode 100644 index 1575951b71..0000000000 Binary files a/examples/typescript/legacy/fullstack/farcaster-miniapp/public/splash.png and /dev/null differ diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/tailwind.config.ts b/examples/typescript/legacy/fullstack/farcaster-miniapp/tailwind.config.ts deleted file mode 100644 index 483994ffa6..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/tailwind.config.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { Config } from "tailwindcss"; - -const config: Config = { - content: [ - "./pages/**/*.{js,ts,jsx,tsx,mdx}", - "./components/**/*.{js,ts,jsx,tsx,mdx}", - "./app/**/*.{js,ts,jsx,tsx,mdx}", - ], - theme: { - extend: { - colors: { - background: "var(--background)", - foreground: "var(--foreground)", - }, - animation: { - "fade-out": "1s fadeOut 3s ease-out forwards", - }, - keyframes: { - fadeOut: { - "0%": { opacity: "1" }, - "100%": { opacity: "0" }, - }, - }, - }, - }, - plugins: [], -}; -export default config; diff --git a/examples/typescript/legacy/fullstack/farcaster-miniapp/tsconfig.json b/examples/typescript/legacy/fullstack/farcaster-miniapp/tsconfig.json deleted file mode 100644 index 64c21044c4..0000000000 --- a/examples/typescript/legacy/fullstack/farcaster-miniapp/tsconfig.json +++ /dev/null @@ -1,27 +0,0 @@ -{ - "compilerOptions": { - "lib": ["dom", "dom.iterable", "esnext"], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": ["./*"] - }, - "target": "ES2017" - }, - "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], - "exclude": ["node_modules"] -} diff --git a/examples/typescript/legacy/fullstack/next-advanced/.eslintrc.json b/examples/typescript/legacy/fullstack/next-advanced/.eslintrc.json deleted file mode 100644 index 3722418549..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": ["next/core-web-vitals", "next/typescript"] -} diff --git a/examples/typescript/legacy/fullstack/next-advanced/.gitignore b/examples/typescript/legacy/fullstack/next-advanced/.gitignore deleted file mode 100644 index 504d5073b1..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/.gitignore +++ /dev/null @@ -1,36 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.js -.yarn/install-state.gz - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* - -# local env files -.env* - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/examples/typescript/legacy/fullstack/next-advanced/.yarnrc.yml b/examples/typescript/legacy/fullstack/next-advanced/.yarnrc.yml deleted file mode 100644 index 14fd359c8f..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/.yarnrc.yml +++ /dev/null @@ -1,2 +0,0 @@ -# You can remove this file if you don't want to use Yarn package manager. -nodeLinker: node-modules \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/next-advanced/README.md b/examples/typescript/legacy/fullstack/next-advanced/README.md deleted file mode 100644 index 57f1fd7451..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/README.md +++ /dev/null @@ -1,28 +0,0 @@ -# [WIP] Native Next.js example - -This is an example of integrating x402 deeply into an existing next.js codebase. We will provide helpers that simply this in the next release of `x402-next`. - -## Setup - -1. Install and build all packages - -```bash -cd ../../../../typescript -pnpm install -pnpm build -cd ../examples/typescript/fullstack/next-advanced -``` - -2. `pnpm run dev` - -3. Visit `http://localhost:3000/protected` - -## How this works - -This approach has 3 parts: - -1. a middleware (`middleware.ts`) that checks for a session cookie representing payment. If not present, it returns the `app/paywall/page.tsx` page. - -2. `app/paywall/page.tsx` contains client side code for creating a payment - -3. a server action that receives the signed payment (typically included in an `x-payment` header). It then verifies and settles payment, before setting a cookie to auth the session, and redirecting to the proper `/protected` endpoints. diff --git a/examples/typescript/legacy/fullstack/next-advanced/app/actions.ts b/examples/typescript/legacy/fullstack/next-advanced/app/actions.ts deleted file mode 100644 index 0b7c5b66d0..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/app/actions.ts +++ /dev/null @@ -1,52 +0,0 @@ -"use server"; - -import { cookies } from "next/headers"; -import { redirect } from "next/navigation"; -import { useFacilitator } from "x402/verify"; -import { PaymentRequirements } from "x402/types"; -import { exact } from "x402/schemes"; - -export async function verifyPayment(payload: string): Promise { - // right now this needs to be defined in 2 places, we'll clean this up with a proper nextjs abstraction - const paymentRequirements: PaymentRequirements = { - scheme: "exact", - network: "base-sepolia", - maxAmountRequired: "10000", - resource: "https://example.com", - description: "Payment for a service", - mimeType: "text/html", - payTo: "0x209693Bc6afc0C5328bA36FaF03C514EF312287C", - maxTimeoutSeconds: 60, - asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", - outputSchema: undefined, - extra: { - name: "USDC", - version: "2", - }, - }; - - const { verify, settle } = useFacilitator(); // eslint-disable-line - - try { - const payment = exact.evm.decodePayment(payload); - const valid = await verify(payment, paymentRequirements); - if (!valid.isValid) { - throw new Error(valid.invalidReason); - } - - const settleResponse = await settle(payment, paymentRequirements); - - if (!settleResponse.success) { - throw new Error(settleResponse.errorReason); - } - } catch (error) { - console.error({ error }); - return `Error: ${error}`; - } - - const cookieStore = await cookies(); - // This should be a JWT signed by the server following best practices for a session token - // See: https://nextjs.org/docs/app/guides/authentication#stateless-sessions - cookieStore.set("payment-session", payload); - redirect("/protected"); -} diff --git a/examples/typescript/legacy/fullstack/next-advanced/app/globals.css b/examples/typescript/legacy/fullstack/next-advanced/app/globals.css deleted file mode 100644 index 13d40b8920..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/app/globals.css +++ /dev/null @@ -1,27 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -:root { - --background: #ffffff; - --foreground: #171717; -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #0a0a0a; - --foreground: #ededed; - } -} - -body { - color: var(--foreground); - background: var(--background); - font-family: Arial, Helvetica, sans-serif; -} - -@layer utilities { - .text-balance { - text-wrap: balance; - } -} diff --git a/examples/typescript/legacy/fullstack/next-advanced/app/layout.tsx b/examples/typescript/legacy/fullstack/next-advanced/app/layout.tsx deleted file mode 100644 index 1463d3a2fa..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/app/layout.tsx +++ /dev/null @@ -1,23 +0,0 @@ -import '@coinbase/onchainkit/styles.css'; -import type { Metadata } from 'next'; -import './globals.css'; -import { Providers } from './providers'; - -export const metadata: Metadata = { - title: process.env.NEXT_PUBLIC_ONCHAINKIT_PROJECT_NAME, - description: 'Generated by `create-onchain`, a Next.js template for OnchainKit', -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - {children} - - - ); -} diff --git a/examples/typescript/legacy/fullstack/next-advanced/app/page.tsx b/examples/typescript/legacy/fullstack/next-advanced/app/page.tsx deleted file mode 100644 index 28173badf8..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/app/page.tsx +++ /dev/null @@ -1,149 +0,0 @@ -"use client"; - -import { - ConnectWallet, - Wallet, - WalletDropdown, - WalletDropdownLink, - WalletDropdownDisconnect, -} from "@coinbase/onchainkit/wallet"; -import { - Address, - Avatar, - Name, - Identity, - EthBalance, -} from "@coinbase/onchainkit/identity"; -import ArrowSvg from "./svg/ArrowSvg"; -import ImageSvg from "./svg/Image"; -import OnchainkitSvg from "./svg/OnchainKit"; -import Link from "next/link"; - -const components = [ - { - name: "Transaction", - url: "https://onchainkit.xyz/transaction/transaction", - }, - { name: "Swap", url: "https://onchainkit.xyz/swap/swap" }, - { name: "Checkout", url: "https://onchainkit.xyz/checkout/checkout" }, - { name: "Wallet", url: "https://onchainkit.xyz/wallet/wallet" }, - { name: "Identity", url: "https://onchainkit.xyz/identity/identity" }, -]; - -const templates = [ - { name: "NFT", url: "https://github.com/coinbase/onchain-app-template" }, - { - name: "Commerce", - url: "https://github.com/coinbase/onchain-commerce-template", - }, - { name: "Fund", url: "https://github.com/fakepixels/fund-component" }, -]; - -export default function App() { - return ( -
-
-
-
- - - - - - - - - -
- - - - Wallet - - - - -
-
-
- -
-
- - Paywall Demo - - -
- -
-
- - - -
-

- Get started by editing - - app/page.tsx - - . -

-
-
-
-
-

- Explore components -

- -
-
-

- Explore templates -

- -
-
-
-
-
-
-
- ); -} diff --git a/examples/typescript/legacy/fullstack/next-advanced/app/paywall/page.tsx b/examples/typescript/legacy/fullstack/next-advanced/app/paywall/page.tsx deleted file mode 100644 index 60bfffc622..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/app/paywall/page.tsx +++ /dev/null @@ -1,121 +0,0 @@ -"use client"; - -import { Wallet } from "@coinbase/onchainkit/wallet"; -import { useState } from "react"; -import { verifyPayment } from "../actions"; -import { PaymentRequirements, PaymentPayload } from "x402/types"; -import { preparePaymentHeader } from "x402/client"; -import { getNetworkId } from "x402/shared"; -import { exact } from "x402/schemes"; -import { useAccount, useSignTypedData } from "wagmi"; - -function PaymentForm({ - paymentRequirements, -}: { - paymentRequirements: PaymentRequirements; -}) { - const { address, isConnected } = useAccount(); - const [isProcessing, setIsProcessing] = useState(false); - const { isError, isSuccess, signTypedDataAsync } = useSignTypedData(); - - if (!address || !isConnected) { - return ( -
- -

Please connect your wallet to proceed with payment.

-
- ); - } - - const unSignedPaymentHeader = preparePaymentHeader( - address, - 1, - paymentRequirements - ); - - const eip712Data = { - types: { - TransferWithAuthorization: [ - { name: "from", type: "address" }, - { name: "to", type: "address" }, - { name: "value", type: "uint256" }, - { name: "validAfter", type: "uint256" }, - { name: "validBefore", type: "uint256" }, - { name: "nonce", type: "bytes32" }, - ], - }, - domain: { - name: paymentRequirements.extra?.name, - version: paymentRequirements.extra?.version, - chainId: getNetworkId(paymentRequirements.network), - verifyingContract: paymentRequirements.asset as `0x${string}`, - }, - primaryType: "TransferWithAuthorization" as const, - message: unSignedPaymentHeader.payload.authorization, - }; - - async function handlePayment() { - setIsProcessing(true); - const signature = await signTypedDataAsync(eip712Data); - - const paymentPayload: PaymentPayload = { - ...unSignedPaymentHeader, - payload: { - ...unSignedPaymentHeader.payload, - signature, - }, - }; - - const payment: string = exact.evm.encodePayment(paymentPayload); - - const verifyPaymentWithPayment = verifyPayment.bind(null, payment); - const result = await verifyPaymentWithPayment(); - console.log("result", result); - setIsProcessing(false); - } - - return ( -
- -

- {paymentRequirements.maxAmountRequired} to {paymentRequirements.payTo}{" "} - for {paymentRequirements.description} -

- - - {isProcessing &&

Processing...

} - {isSuccess &&

Signed...

} - {isError &&

Payment failed

} -
- ); -} - -export default function Paywall() { - const paymentRequirements: PaymentRequirements = { - scheme: "exact", - network: "base-sepolia", - maxAmountRequired: "10000", - resource: "https://example.com", - description: "Payment for a service", - mimeType: "text/html", - payTo: "0x209693Bc6afc0C5328bA36FaF03C514EF312287C", - maxTimeoutSeconds: 60, - asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", - outputSchema: undefined, - extra: { - name: "USDC", - version: "2", - }, - }; - return ( -
- -
- ); -} diff --git a/examples/typescript/legacy/fullstack/next-advanced/app/protected/page.tsx b/examples/typescript/legacy/fullstack/next-advanced/app/protected/page.tsx deleted file mode 100644 index 878f8bdc45..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/app/protected/page.tsx +++ /dev/null @@ -1,31 +0,0 @@ -'use client'; - -import { useState } from 'react'; - -export default function ProtectedPage() { - const [count, setCount] = useState(0); - - return ( -
-
-

Protected Content

-

- Your payment was successful! Enjoy this banger song. -

-
-

Counter: {count}

- -
- - -
-
- ); -} diff --git a/examples/typescript/legacy/fullstack/next-advanced/app/providers.tsx b/examples/typescript/legacy/fullstack/next-advanced/app/providers.tsx deleted file mode 100644 index 92084bed04..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/app/providers.tsx +++ /dev/null @@ -1,23 +0,0 @@ -'use client'; - -import { base } from 'wagmi/chains'; -import { OnchainKitProvider } from '@coinbase/onchainkit'; - -export function Providers(props: { children: React.ReactNode }) { - return ( - - {props.children} - - ); -} - diff --git a/examples/typescript/legacy/fullstack/next-advanced/app/svg/ArrowSvg.tsx b/examples/typescript/legacy/fullstack/next-advanced/app/svg/ArrowSvg.tsx deleted file mode 100644 index d278242d90..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/app/svg/ArrowSvg.tsx +++ /dev/null @@ -1,18 +0,0 @@ -export default function ArrowSvg() { - return ( - - Arrow SVG - - - ); -} diff --git a/examples/typescript/legacy/fullstack/next-advanced/app/svg/Image.tsx b/examples/typescript/legacy/fullstack/next-advanced/app/svg/Image.tsx deleted file mode 100644 index 9b7e6889a8..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/app/svg/Image.tsx +++ /dev/null @@ -1,45 +0,0 @@ -export default function ImageSvg() { - return ( - - - - - - - - - - - - - - - - - - - - ); -} diff --git a/examples/typescript/legacy/fullstack/next-advanced/app/svg/OnchainKit.tsx b/examples/typescript/legacy/fullstack/next-advanced/app/svg/OnchainKit.tsx deleted file mode 100644 index 6417cc3e52..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/app/svg/OnchainKit.tsx +++ /dev/null @@ -1,54 +0,0 @@ -export default function OnchainkitSvg({ className = '' }) { - return ( - - Onchainkit SVG - - - - - - - - - - - - ); -} diff --git a/examples/typescript/legacy/fullstack/next-advanced/middleware.ts b/examples/typescript/legacy/fullstack/next-advanced/middleware.ts deleted file mode 100644 index a3432e399c..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/middleware.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { NextResponse } from "next/server"; -import { NextRequest } from "next/server"; - -// export const middleware = paymentMiddleware( -// payTo, -// { -// "/protected": { -// price: "$0.01", -// network, -// config: { -// description: "Access to protected content", -// }, -// }, -// }, -// { -// url: facilitatorUrl, -// }, -// ); - -export const middleware = async (request: NextRequest) => { - const paymentHeader = request.cookies.get("payment-session"); - if (!paymentHeader) { - return NextResponse.rewrite(new URL("/paywall", request.url)); - } - - return NextResponse.next(); -}; - -// Configure which paths the middleware should run on -export const config = { - matcher: ["/protected/:path*"], -}; diff --git a/examples/typescript/legacy/fullstack/next-advanced/next.config.mjs b/examples/typescript/legacy/fullstack/next-advanced/next.config.mjs deleted file mode 100644 index 0a7c9af751..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/next.config.mjs +++ /dev/null @@ -1,5 +0,0 @@ -/** @type {import('next').NextConfig} */ -const nextConfig = { -}; - -export default nextConfig; diff --git a/examples/typescript/legacy/fullstack/next-advanced/package.json b/examples/typescript/legacy/fullstack/next-advanced/package.json deleted file mode 100644 index a86bd1ae4b..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "next-advanced", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "next dev", - "build": "next build", - "start": "next start", - "lint": "next lint" - }, - "dependencies": { - "@coinbase/onchainkit": "0.38.14", - "next": "15.5.9", - "react": "19.2.3", - "react-dom": "19.2.3", - "@tanstack/react-query": "^5", - "viem": "^2.21.26", - "wagmi": "^2.15.6", - "x402": "workspace:*" - }, - "devDependencies": { - "@types/node": "^20", - "@types/react": "^19", - "@types/react-dom": "^19", - "eslint-config-next": "15.5.7", - "postcss": "^8", - "tailwindcss": "^3.4.1", - "typescript": "^5", - "eslint": "^8" - } -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/next-advanced/postcss.config.mjs b/examples/typescript/legacy/fullstack/next-advanced/postcss.config.mjs deleted file mode 100644 index 1a69fd2a45..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/postcss.config.mjs +++ /dev/null @@ -1,8 +0,0 @@ -/** @type {import('postcss-load-config').Config} */ -const config = { - plugins: { - tailwindcss: {}, - }, -}; - -export default config; diff --git a/examples/typescript/legacy/fullstack/next-advanced/tailwind.config.ts b/examples/typescript/legacy/fullstack/next-advanced/tailwind.config.ts deleted file mode 100644 index 91a0333d3b..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/tailwind.config.ts +++ /dev/null @@ -1,22 +0,0 @@ -import type { Config } from "tailwindcss"; - -const config: Config = { - content: [ - "./pages/**/*.{js,ts,jsx,tsx,mdx}", - "./components/**/*.{js,ts,jsx,tsx,mdx}", - "./app/**/*.{js,ts,jsx,tsx,mdx}", - ], - theme: { - extend: { - fontFamily: { - sans: ['DM Sans', 'sans-serif'], - }, - colors: { - background: "var(--background)", - foreground: "var(--foreground)", - }, - }, - }, - plugins: [], -}; -export default config; diff --git a/examples/typescript/legacy/fullstack/next-advanced/tsconfig.json b/examples/typescript/legacy/fullstack/next-advanced/tsconfig.json deleted file mode 100644 index d81d4ee14e..0000000000 --- a/examples/typescript/legacy/fullstack/next-advanced/tsconfig.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "compilerOptions": { - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "preserve", - "incremental": true, - "plugins": [ - { - "name": "next" - } - ], - "paths": { - "@/*": [ - "./*" - ] - }, - "target": "ES2017" - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx", - ".next/types/**/*.ts" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/examples/typescript/legacy/fullstack/next/.env-local b/examples/typescript/legacy/fullstack/next/.env-local deleted file mode 100644 index 922c516362..0000000000 --- a/examples/typescript/legacy/fullstack/next/.env-local +++ /dev/null @@ -1,3 +0,0 @@ -NEXT_PUBLIC_FACILITATOR_URL=https://x402.org/facilitator -NETWORK=base-sepolia -RESOURCE_WALLET_ADDRESS= diff --git a/examples/typescript/legacy/fullstack/next/.gitignore b/examples/typescript/legacy/fullstack/next/.gitignore deleted file mode 100644 index fec566d8ae..0000000000 --- a/examples/typescript/legacy/fullstack/next/.gitignore +++ /dev/null @@ -1,41 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/versions - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# env files (can opt-in for committing if needed) -.env -.env.* -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/examples/typescript/legacy/fullstack/next/.prettierignore b/examples/typescript/legacy/fullstack/next/.prettierignore deleted file mode 100644 index 5bd240ba90..0000000000 --- a/examples/typescript/legacy/fullstack/next/.prettierignore +++ /dev/null @@ -1,8 +0,0 @@ -docs/ -dist/ -node_modules/ -coverage/ -.github/ -src/client -**/**/*.json -*.md \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/next/.prettierrc b/examples/typescript/legacy/fullstack/next/.prettierrc deleted file mode 100644 index ffb416b74b..0000000000 --- a/examples/typescript/legacy/fullstack/next/.prettierrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": false, - "trailingComma": "all", - "bracketSpacing": true, - "arrowParens": "avoid", - "printWidth": 100, - "proseWrap": "never" -} diff --git a/examples/typescript/legacy/fullstack/next/README.md b/examples/typescript/legacy/fullstack/next/README.md deleted file mode 100644 index 286d0e25d3..0000000000 --- a/examples/typescript/legacy/fullstack/next/README.md +++ /dev/null @@ -1,156 +0,0 @@ -# x402-next Example App - -This is a Next.js application that demonstrates how to use the `x402-next` middleware to implement paywall functionality in your Next.js routes. - -## Prerequisites - -- Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) -- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- A valid Ethereum address for receiving payments - -## Setup - -1. Copy `.env-local` to `.env` and add your Ethereum address to receive payments: - -```bash -cp .env-local .env -``` - -2. Install and build all packages from the typescript examples root: -```bash -cd ../../ -pnpm install -pnpm build -cd fullstack/next -``` - -2. Install and start the Next.js example: -```bash -pnpm dev -``` - -## Example Routes - -The app includes protected routes that require payment to access: - -### Protected Page Route -The `/protected` route requires a payment of $0.01 to access. The page route is protected using the x402-next middleware: - -```typescript -// middleware.ts -import { paymentMiddleware, Network, Resource } from "x402-next"; - -const facilitatorUrl = process.env.NEXT_PUBLIC_FACILITATOR_URL as Resource; -const payTo = process.env.RESOURCE_WALLET_ADDRESS as Address; -const network = process.env.NETWORK as Network; - -export const middleware = paymentMiddleware( - payTo, - { - "/protected": { - price: "$0.01", - network, - config: { - description: "Access to protected content", - }, - }, - }, - { - url: facilitatorUrl, - }, -); - -// Configure which paths the middleware should run on -export const config = { - matcher: ["/protected/:path*"], - runtime: "nodejs", -}; -``` - -### Protected API Route -The `/api/weather` API route requires a payment of $0.01 to access. The API route is protected using the x402-next route wrapper. This is the recommened approach to protect API routes as it guarantees payment settlement only AFTER successful API responses (status < 400). API routes can also be protected by the x402-next middleware, however this will charge clients for failed API responses. - -```typescript -// app/api/weather/route.ts -import { NextRequest, NextResponse } from "next/server"; -import { withX402, Network, Resource } from "x402-next"; - -const handler = async (_: NextRequest) => { - return NextResponse.json({ - report: { weather: "sunny", temperature: 70 } - }); -}; - -export const GET = withX402( - handler, - payTo, - { - price: "$0.01", - network, - config: { description: "Access to weather API" } - }, - { url: facilitatorUrl }, - { appName: "Next x402 Demo", appLogo: "/x402-icon-blue.png" } -); -``` - -## Response Format - -### Payment Required (402) -```json -{ - "error": "X-PAYMENT header is required", - "paymentRequirements": { - "scheme": "exact", - "network": "base", - "maxAmountRequired": "1000", - "resource": "http://localhost:3000/protected", - "description": "Access to protected content", - "mimeType": "", - "payTo": "0xYourAddress", - "maxTimeoutSeconds": 60, - "asset": "0x...", - "outputSchema": null, - "extra": null - } -} -``` - -### Successful Response -```ts -// Headers -{ - "X-PAYMENT-RESPONSE": "..." // Encoded response object -} -``` - -## Extending the Example - -To add more protected routes, update the middleware configuration: - -```typescript -export const middleware = paymentMiddleware( - payTo, - { - "/protected": { - price: "$0.01", - network, - config: { - description: "Access to protected content", - }, - }, - "/api/premium": { - price: "$0.10", - network, - config: { - description: "Premium API access", - }, - }, - } -); - -export const config = { - matcher: ["/protected/:path*", "/api/premium/:path*"], - runtime: "nodejs", -}; -``` diff --git a/examples/typescript/legacy/fullstack/next/app/api/weather/route.ts b/examples/typescript/legacy/fullstack/next/app/api/weather/route.ts deleted file mode 100644 index ba83d2e6e5..0000000000 --- a/examples/typescript/legacy/fullstack/next/app/api/weather/route.ts +++ /dev/null @@ -1,49 +0,0 @@ -import { NextRequest, NextResponse } from "next/server"; -import { withX402, Network, Resource } from "x402-next"; -import { Address } from "viem"; - -const facilitatorUrl = process.env.NEXT_PUBLIC_FACILITATOR_URL as Resource; -const payTo = process.env.RESOURCE_WALLET_ADDRESS as Address; -const network = process.env.NETWORK as Network; - -/** - * Weather API endpoint handler - * - * @param {NextRequest} _ - The incoming request object - * @returns JSON response with weather data - */ -const handler = async (_: NextRequest) => { - const response = NextResponse.json( - { - report: { - weather: "sunny", - temperature: 70, - }, - }, - { status: 200 }, - ); - return response; -}; - -/** - * Protected weather API endpoint - * Payment is only settled after successful response (status < 400) - */ -export const GET = withX402( - handler, - payTo, - { - price: "$0.01", - network, - config: { - description: "Access to weather API", - }, - }, - { - url: facilitatorUrl, - }, - { - appName: "Next x402 Demo", - appLogo: "/x402-icon-blue.png", - }, -); diff --git a/examples/typescript/legacy/fullstack/next/app/assets/x402_wordmark_dark.png b/examples/typescript/legacy/fullstack/next/app/assets/x402_wordmark_dark.png deleted file mode 100644 index 07066e2c13..0000000000 Binary files a/examples/typescript/legacy/fullstack/next/app/assets/x402_wordmark_dark.png and /dev/null differ diff --git a/examples/typescript/legacy/fullstack/next/app/assets/x402_wordmark_dark.svg b/examples/typescript/legacy/fullstack/next/app/assets/x402_wordmark_dark.svg deleted file mode 100644 index 00477f842b..0000000000 --- a/examples/typescript/legacy/fullstack/next/app/assets/x402_wordmark_dark.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - - diff --git a/examples/typescript/legacy/fullstack/next/app/assets/x402_wordmark_light.svg b/examples/typescript/legacy/fullstack/next/app/assets/x402_wordmark_light.svg deleted file mode 100644 index dc526be279..0000000000 --- a/examples/typescript/legacy/fullstack/next/app/assets/x402_wordmark_light.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/next/app/favicon.ico b/examples/typescript/legacy/fullstack/next/app/favicon.ico deleted file mode 100644 index a122eaf5a1..0000000000 Binary files a/examples/typescript/legacy/fullstack/next/app/favicon.ico and /dev/null differ diff --git a/examples/typescript/legacy/fullstack/next/app/globals.css b/examples/typescript/legacy/fullstack/next/app/globals.css deleted file mode 100644 index e4793b23bc..0000000000 --- a/examples/typescript/legacy/fullstack/next/app/globals.css +++ /dev/null @@ -1,33 +0,0 @@ -@tailwind base; -@tailwind components; -@tailwind utilities; - -:root { - --background: #ffffff; - --foreground: #171717; -} - -@media (prefers-color-scheme: dark) { - :root { - --background: #1a1a2e; - --foreground: #ededed; - } -} - -body { - color: var(--foreground); - background: var(--background); - font-family: Arial, Helvetica, sans-serif; -} - -@layer utilities { - .full-bleed { - width: 100vw; - margin-left: calc(50% - 50vw); - } - - .unset-full-bleed { - width: unset; - margin-left: unset; - } -} diff --git a/examples/typescript/legacy/fullstack/next/app/layout.tsx b/examples/typescript/legacy/fullstack/next/app/layout.tsx deleted file mode 100644 index 26396a893a..0000000000 --- a/examples/typescript/legacy/fullstack/next/app/layout.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; -import "./globals.css"; - -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); - -export const metadata: Metadata = { - title: 'x402.org', - description: 'A chain-agnostic protocol for web payments', -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - - - - - - - - - {children} - - - ); -} diff --git a/examples/typescript/legacy/fullstack/next/app/page.tsx b/examples/typescript/legacy/fullstack/next/app/page.tsx deleted file mode 100644 index 34fc13970b..0000000000 --- a/examples/typescript/legacy/fullstack/next/app/page.tsx +++ /dev/null @@ -1,51 +0,0 @@ -import Link from 'next/link'; -import WordmarkCondensed from './assets/x402_wordmark_light.svg'; - -export default function Home() { - return ( -
-
- {/* Hero Section */} -
-
-
- -
-

- Fullstack demo powered by Next.js -

-
- - Live demo - -
-
-
-
- -
- ); -} diff --git a/examples/typescript/legacy/fullstack/next/app/protected/page.tsx b/examples/typescript/legacy/fullstack/next/app/protected/page.tsx deleted file mode 100644 index 7ec0e00ede..0000000000 --- a/examples/typescript/legacy/fullstack/next/app/protected/page.tsx +++ /dev/null @@ -1,16 +0,0 @@ -export default function ProtectedPage() { - return ( -
-
-

Protected Content

-

- Your payment was successful! Enjoy this banger song. -

- - -
-
- ); -} diff --git a/examples/typescript/legacy/fullstack/next/middleware.ts b/examples/typescript/legacy/fullstack/next/middleware.ts deleted file mode 100644 index 52700b416e..0000000000 --- a/examples/typescript/legacy/fullstack/next/middleware.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Address } from "viem"; -import { paymentMiddleware, Network, Resource } from "x402-next"; - -const facilitatorUrl = process.env.NEXT_PUBLIC_FACILITATOR_URL as Resource; -const payTo = process.env.RESOURCE_WALLET_ADDRESS as Address; -const network = process.env.NETWORK as Network; - -export const middleware = paymentMiddleware( - payTo, - { - "/protected": { - price: "$0.01", - network, - config: { - description: "Access to protected content", - }, - }, - }, - { - url: facilitatorUrl, - }, - { - appName: "Next x402 Demo", - appLogo: "/x402-icon-blue.png", - }, -); - -// Configure which paths the middleware should run on -export const config = { - matcher: ["/protected/:path*"], - runtime: "nodejs", -}; diff --git a/examples/typescript/legacy/fullstack/next/next.config.ts b/examples/typescript/legacy/fullstack/next/next.config.ts deleted file mode 100644 index d12c5817d6..0000000000 --- a/examples/typescript/legacy/fullstack/next/next.config.ts +++ /dev/null @@ -1,21 +0,0 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - turbopack: { - rules: { - "*.svg": { - loaders: ["@svgr/webpack"], - as: "*.js", - }, - }, - }, - webpack(config) { - config.module.rules.push({ - test: /\.svg$/, - use: ["@svgr/webpack"], - }); - return config; - }, -}; - -export default nextConfig; diff --git a/examples/typescript/legacy/fullstack/next/postcss.config.mjs b/examples/typescript/legacy/fullstack/next/postcss.config.mjs deleted file mode 100644 index 1a69fd2a45..0000000000 --- a/examples/typescript/legacy/fullstack/next/postcss.config.mjs +++ /dev/null @@ -1,8 +0,0 @@ -/** @type {import('postcss-load-config').Config} */ -const config = { - plugins: { - tailwindcss: {}, - }, -}; - -export default config; diff --git a/examples/typescript/legacy/fullstack/next/public/apple-touch-icon.png b/examples/typescript/legacy/fullstack/next/public/apple-touch-icon.png deleted file mode 100644 index 52917ace05..0000000000 Binary files a/examples/typescript/legacy/fullstack/next/public/apple-touch-icon.png and /dev/null differ diff --git a/examples/typescript/legacy/fullstack/next/public/favicon-96x96.png b/examples/typescript/legacy/fullstack/next/public/favicon-96x96.png deleted file mode 100644 index d38b95dec2..0000000000 Binary files a/examples/typescript/legacy/fullstack/next/public/favicon-96x96.png and /dev/null differ diff --git a/examples/typescript/legacy/fullstack/next/public/favicon.svg b/examples/typescript/legacy/fullstack/next/public/favicon.svg deleted file mode 100644 index d113dd27c8..0000000000 --- a/examples/typescript/legacy/fullstack/next/public/favicon.svg +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/next/public/site.webmanifest b/examples/typescript/legacy/fullstack/next/public/site.webmanifest deleted file mode 100644 index d851629d5b..0000000000 --- a/examples/typescript/legacy/fullstack/next/public/site.webmanifest +++ /dev/null @@ -1,21 +0,0 @@ -{ - "name": "x402.org", - "short_name": "x402", - "icons": [ - { - "src": "/web-app-manifest-192x192.png", - "sizes": "192x192", - "type": "image/png", - "purpose": "maskable" - }, - { - "src": "/web-app-manifest-512x512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ], - "theme_color": "#ffffff", - "background_color": "#ffffff", - "display": "standalone" -} \ No newline at end of file diff --git a/examples/typescript/legacy/fullstack/next/public/web-app-manifest-192x192.png b/examples/typescript/legacy/fullstack/next/public/web-app-manifest-192x192.png deleted file mode 100644 index 113ef76d57..0000000000 Binary files a/examples/typescript/legacy/fullstack/next/public/web-app-manifest-192x192.png and /dev/null differ diff --git a/examples/typescript/legacy/fullstack/next/public/web-app-manifest-512x512.png b/examples/typescript/legacy/fullstack/next/public/web-app-manifest-512x512.png deleted file mode 100644 index 95fca1f1f7..0000000000 Binary files a/examples/typescript/legacy/fullstack/next/public/web-app-manifest-512x512.png and /dev/null differ diff --git a/examples/typescript/legacy/fullstack/next/tailwind.config.ts b/examples/typescript/legacy/fullstack/next/tailwind.config.ts deleted file mode 100644 index 1362b8826a..0000000000 --- a/examples/typescript/legacy/fullstack/next/tailwind.config.ts +++ /dev/null @@ -1,18 +0,0 @@ -import type { Config } from "tailwindcss"; - -export default { - content: [ - "./pages/**/*.{js,ts,jsx,tsx,mdx}", - "./components/**/*.{js,ts,jsx,tsx,mdx}", - "./app/**/*.{js,ts,jsx,tsx,mdx}", - ], - theme: { - extend: { - colors: { - background: "var(--background)", - foreground: "var(--foreground)", - }, - }, - }, - plugins: [], -} satisfies Config; diff --git a/examples/typescript/legacy/fullstack/next/types/svg.d.ts b/examples/typescript/legacy/fullstack/next/types/svg.d.ts deleted file mode 100644 index 12f38a6048..0000000000 --- a/examples/typescript/legacy/fullstack/next/types/svg.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module "*.svg" { - import React from "react"; - const SVG: React.FC>; - export default SVG; -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/.env.example b/examples/typescript/legacy/mcp-embedded-wallet/.env.example deleted file mode 100644 index d3d8566e2a..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/.env.example +++ /dev/null @@ -1,3 +0,0 @@ -VITE_CDP_PROJECT_ID= -CDP_API_KEY_ID= -CDP_API_KEY_SECRET= \ No newline at end of file diff --git a/examples/typescript/legacy/mcp-embedded-wallet/.gitignore b/examples/typescript/legacy/mcp-embedded-wallet/.gitignore deleted file mode 100644 index 123daffdbc..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/.gitignore +++ /dev/null @@ -1,4 +0,0 @@ -dist/ -logs/ -node_modules/ -.env diff --git a/examples/typescript/legacy/mcp-embedded-wallet/.prettierignore b/examples/typescript/legacy/mcp-embedded-wallet/.prettierignore deleted file mode 100644 index 5bd240ba90..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/.prettierignore +++ /dev/null @@ -1,8 +0,0 @@ -docs/ -dist/ -node_modules/ -coverage/ -.github/ -src/client -**/**/*.json -*.md \ No newline at end of file diff --git a/examples/typescript/legacy/mcp-embedded-wallet/.prettierrc b/examples/typescript/legacy/mcp-embedded-wallet/.prettierrc deleted file mode 100644 index ffb416b74b..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/.prettierrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": false, - "trailingComma": "all", - "bracketSpacing": true, - "arrowParens": "avoid", - "printWidth": 100, - "proseWrap": "never" -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/README.md b/examples/typescript/legacy/mcp-embedded-wallet/README.md deleted file mode 100644 index 1c669ec86c..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/README.md +++ /dev/null @@ -1,163 +0,0 @@ -# x402-MCP - -## Development - -```bash -pnpm install && node node_modules/electron/install.js -``` - -Develop the electron app - -```bash -pnpm run dev -``` - -Run the mcp server (rebuilds assets and starts the mcp server + electron app) - -```bash -pnpm run build # builds the assets -pnpm run mcp # starts the mcp server + electron app using the built assets -``` - -Add as an MCP server for Claude, in `claude_desktop_config.json` (`cmd + ,` -> Developer -> Edit Config) - -```json -{ - "mcpServers": { - "x402-wallet": { - "command": "pnpm", - "args": [ - "--silent", - "-C", - "/examples/typescript/mcp-embedded-wallet", - "run", - "mcp" - ], - "env": {} - } - } -} -``` - -Then restart Claude. - -Note that Claude will run an instance of the MCP server on startup, so you don't need to have it running in the background. You will need to rebuild the assets and restart Claude in order to see changes. - -## How does this work? - -This is an mcp server that also happens to be an electron app. It uses an embedded wallet stored in -the electron browser process to sign requests while being sandboxed from the rest of the OS. The MCP server can request signatures via the main process <-> renderer process IPC bridge. - -Basically there are 2 processes (the mcp server + electron main process) and the electron renderer (which is a chromium browser window), communication between them looks like this: - -```mermaid -sequenceDiagram - actor Human - participant Claude - participant mcpServer - participant electronRenderer - - Human ->> Claude: Sign a message - Claude ->> mcpServer: use tool sign_message - mcpServer ->> electronRenderer: IPC `signMessage(message)` - electronRenderer ->> electronRenderer: signs message with embedded wallet - electronRenderer ->> mcpServer: signed message - mcpServer ->> Claude: signed message - Claude ->> Human: "I have signed your message: 0x..." -``` - -How do I add a new capability that gets exposed via MCP to Claude? - -Great question. Right now you need to change a few files. - -1. `preload.ts` - this is run on electron window creation and registers functions in the namespace allowing for IPC. You need to add a new IPC callback here. This code is executed in the electron window (exposed via `window.electron`) - -```typescript -contextBridge.exposeInMainWorld("electron", { - OnSignMessage: callback => - ipcRenderer.on("sign-message", (event, message) => { - callback(message).then(signature => { - console.log("sign-message-response", signature); - // Send message back to main process - ipcRenderer.send("sign-message-response", signature); - }); - }), - // Above: existing full example. Below: your fancy new thing ( the most minimal example) - OnMyNewIPCHandler: callback => icpRenderer.on("my-message", (event, message) => { - callback(message) - }); - // Gotchya: functions can't use async syntax -}); -``` - -If you want bi-dreictional communication you need something like `ipcRenderer.send("sign-message-response", signature);` - -2. implement the callback in `src/ipc.ts`, then register it in `src/main.tsx`. The function in `ipc.ts` can - be a full TS async function, but it is executed outside to context of the react render tree (using zustand stores for state syncing to react is recommended) - -```typescript -// src/ipc.ts -export async function myNewIPCHandler() { - // ... -} - -// src/main.ts -window.electron.OnSignMessage(signMessage); -window.electron.OnMyNewIPCHandlder(myNewIPCHand;er) -``` - -We now have everything we need on the renderer side. - -3. Set up call from electron - -Call from electron live in `operations` in `electron.ts` just for convenience. -You might add something like this - -```typescript - myNewIPCHandler: { - title: "My New IPC Handler", - description: "My new IPC handler", - tool: async (message: string): Promise => { - logger.info("myNewIPCHandler called", message); - mainWindow?.webContents.send("my-message", message); - return new Promise(resolve => { - ipcMain.once("my-message-response", (event, response) => { - logger.info("my-message-response from main", response); - resolve(response); - }); - }); - }, - }, -``` - -The key lines are - -```typescript -// Send a message via IPC to the OnMyNewIPCHandler callback we instrumented -mainWindow?.webContents.send("my-message", message); - -// (optional) wait for a response. Note: .once vs .on -ipcMain.once("my-message-response", (event, response) => {}); -``` - -4. Expose calls via MCP - -You now have a function `operations.myNewIPCHandler.tool` that can be called from the node process, but accesses state in the browser context. And you can call it from the MCP server. - -```typescript -server.registerTool( - "sign_message", - { - title: operations.signMessage.title, - description: operations.signMessage.description, - }, - async () => { - logger.info("sign_message tool called"); - return { - content: [ - { type: "text", text: await operations.signMessage.tool("hello") }, - ], - }; - } -); -``` diff --git a/examples/typescript/legacy/mcp-embedded-wallet/TODO.md b/examples/typescript/legacy/mcp-embedded-wallet/TODO.md deleted file mode 100644 index ca821a43d9..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/TODO.md +++ /dev/null @@ -1,84 +0,0 @@ -# x402-MCP Enhancement Plan - -## 1. Fix Current UX Issues -- [ ] Convert OTP input in SignIn.tsx to text input for paste support -- [x] Add logout button functionality to Wallet.tsx using CDP hooks - -## 2. Discovery List Tool -### MCP Layer -- [x] Add discovery_list tool registration in mcp.ts - - Added tool registration with JSON response - - Implemented operations.discoveryList handler -- [ ] Define discovery metadata schema - - Need to document the DiscoveryListResponse and BazaarItem types - - Need to specify format for Claude instructions - -### Electron Layer -- [x] Add discovery operations handler in electron.ts - - Added discoveryList operation - - Added type imports -- [x] Implement IPC bridge for discovery metadata - - Added OnDiscoveryList to preload.ts - - Updated ElectronWindow interface - - Created discovery.ts with facilitator integration - -### Frontend -- [x] Create DiscoveryModal.tsx component - - Added modal with item list display - - Implemented loading and error states - - Added copy functionality -- [x] Add discovery button to Wallet.tsx - - Added button with modal integration - - Maintained existing wallet functionality -- [x] Implement CDP hooks for discovery metadata - - Using getDiscoveryList from discovery.ts -- [x] Add copy helper for Claude instructions - - Added copy button for item data - -## 3. HTTP Request with Payment Tool -### Setup -- [x] Create Viem ToAccount wrapper for cdp-core -- [x] Implement x402 client integration -- [x] Define payment flow types and interfaces - -### Implementation -- [ ] Add http_request_with_payment tool to mcp.ts -- [ ] Create RequestHandler.ts for payment processing -- [ ] Integrate with policy engine checks -- [ ] Add payment request UI components - -## 4. Policy Engine + Signature Modal -### Core Components -- [ ] Create PolicyStore.ts using Zustand -- [ ] Implement policy rule validation logic -- [ ] Create PolicyModal.tsx for configuration -- [ ] Create SignatureConfirmModal.tsx for manual approvals - -### Integration -- [ ] Inject policy checks into signMessage flow (ipc.ts) -- [ ] Add policy configuration UI to Wallet.tsx -- [ ] Implement auto-signing rules for EIP-3009 USDC - -## 5. Call Functionality -### Core -- [ ] Add general purpose signing operations -- [ ] Extend policy engine for call validation -- [ ] Implement transaction preview logic - -### UI -- [ ] Create CallModal.tsx for transaction preview -- [ ] Integrate with existing signature flow -- [ ] Add call history tracking - -## 6. CDP/Coinbase Branding -- [ ] Add @coinbase/design-system dependency -- [ ] Create theme.ts for consistent styling -- [ ] Apply branding to all modals and components -- [ ] Implement responsive design -- [ ] Add loading states and error handling - -## Notes -- Implementation order should follow the numbered sections -- Each feature should include tests and documentation -- Policy engine should be extensible for future rule types -- All UI components should follow Coinbase design guidelines diff --git a/examples/typescript/legacy/mcp-embedded-wallet/electron.ts b/examples/typescript/legacy/mcp-embedded-wallet/electron.ts deleted file mode 100644 index 4dbb0d1331..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/electron.ts +++ /dev/null @@ -1,396 +0,0 @@ -import type { IpcMainEvent } from "electron"; -import { app, ipcMain, BrowserWindow, Menu } from "electron"; -import path from "path"; -import { logger } from "./logger"; -import { X402RequestParams } from "./src/utils/x402Client"; - -type BeforeSendHeadersDetails = { - requestHeaders: Record; -}; - -type HeadersReceivedDetails = { - responseHeaders: Record; -}; - -type BeforeSendHeadersCallback = (details: { - requestHeaders: Record; -}) => void; -type HeadersReceivedCallback = (details: { - responseHeaders: Record; -}) => void; - -export interface DiscoveryListResponse { - x402Version: number; - items: Array<{ - type: string; - resource: string; - x402Version: number; - accepts: Array<{ - scheme: "exact"; - description: string; - network: "base-sepolia" | "base"; - maxAmountRequired: string; - resource: string; - mimeType: string; - payTo: string; - maxTimeoutSeconds: number; - asset: string; - outputSchema?: Record; - extra?: Record; - }>; - lastUpdated: number; - metadata?: Record; - }>; - pagination: { - limit: number; - offset: number; - total: number; - }; -} - -let mainWindow: BrowserWindow | null = null; - -// Platform-specific constants -const isMac = process.platform === "darwin"; -const cmdOrCtrl = isMac ? "Command" : "Ctrl"; - -// Helper function for focused window operations -const withFocusedWindow = (callback: (window: BrowserWindow) => void) => { - const focusedWindow = BrowserWindow.getFocusedWindow(); - if (focusedWindow) { - callback(focusedWindow); - } -}; - -// Quit when all windows are closed. -app.on("window-all-closed", function () { - if (process.platform != "darwin") app.quit(); -}); - -/** - * Creates the main application window with appropriate settings and menu configuration. - * Sets up CORS handling and window event listeners. - * - * @returns {void} - */ -function createWindow() { - logger.info("Creating window"); - mainWindow = new BrowserWindow({ - show: false, - width: 800, - height: 600, - webPreferences: { - nodeIntegration: false, - contextIsolation: true, - preload: path.join(import.meta.dirname, "preload.js"), // Changed from .ts to .js - webSecurity: false, // Disable web security for development - }, - }); - - // Disable CORS for all origins - mainWindow.webContents.session.webRequest.onBeforeSendHeaders( - (details: BeforeSendHeadersDetails, callback: BeforeSendHeadersCallback) => { - callback({ - requestHeaders: { - ...details.requestHeaders, - "Access-Control-Allow-Origin": "*", - }, - }); - }, - ); - - mainWindow.webContents.session.webRequest.onHeadersReceived( - (details: HeadersReceivedDetails, callback: HeadersReceivedCallback) => { - callback({ - responseHeaders: { - ...details.responseHeaders, - "Access-Control-Allow-Origin": ["*"], - "Access-Control-Allow-Headers": ["*"], - "Access-Control-Allow-Methods": ["*"], - }, - }); - }, - ); - - if (!mainWindow) { - throw new Error("Failed to create main window"); - } - - // Menu is basically just used to test IPC communication from main node process to renderer process - const menu = Menu.buildFromTemplate([ - { - label: app.name, - submenu: [ - { - click: () => mainWindow?.webContents.send("sign-message", "Hello, world!"), - label: "Sign Message", - }, - { - type: "separator", - }, - { - label: "Quit", - accelerator: `${cmdOrCtrl}+Q`, - click: function () { - app.quit(); - }, - }, - ], - }, - { - label: "Edit", - submenu: [ - { - label: "Undo", - accelerator: `${cmdOrCtrl}+Z`, - role: "undo", - }, - { - label: "Redo", - accelerator: isMac ? "Shift+Command+Z" : "Ctrl+Y", - role: "redo", - }, - { - type: "separator", - }, - { - label: "Cut", - accelerator: `${cmdOrCtrl}+X`, - role: "cut", - }, - { - label: "Copy", - accelerator: `${cmdOrCtrl}+C`, - role: "copy", - }, - { - label: "Paste", - accelerator: `${cmdOrCtrl}+V`, - role: "paste", - }, - { - label: "Select All", - accelerator: `${cmdOrCtrl}+A`, - role: "selectAll", - }, - ], - }, - { - label: "View", - submenu: [ - { - label: "Reload", - accelerator: `${cmdOrCtrl}+R`, - click: function () { - withFocusedWindow(focusedWindow => { - focusedWindow.webContents.reloadIgnoringCache(); - }); - }, - }, - { - label: "Toggle DevTools", - accelerator: isMac ? "Alt+Command+I" : "Ctrl+Shift+I", - click: function () { - withFocusedWindow(focusedWindow => { - focusedWindow.webContents.toggleDevTools(); - }); - }, - }, - ], - }, - { - label: "Window", - submenu: [ - { - label: "Minimize", - accelerator: `${cmdOrCtrl}+M`, - role: "minimize", - }, - { - label: "Close", - accelerator: `${cmdOrCtrl}+W`, - role: "close", - }, - ...(isMac - ? [ - { - type: "separator" as const, - }, - { - label: "Bring All to Front", - role: "front" as const, - }, - ] - : []), - ], - }, - ]); - Menu.setApplicationMenu(menu); - - // Open DevTools in development - if (process.env.NODE_ENV === "development") { - mainWindow.webContents.openDevTools(); - mainWindow.show(); - mainWindow.loadURL("http://localhost:3000"); - } else { - mainWindow.loadFile(path.join(import.meta.dirname, "dist/index.html")); - } - - mainWindow.on("closed", () => { - mainWindow = null; - }); -} - -/** - * Launches the application, ensuring only a single instance is running. - * Handles window creation, activation, and quit events. - * - * @returns {void} - */ -export function launchApp() { - // Prevent multiple instances of the app - var gotLock = app.requestSingleInstanceLock(); - if (!gotLock) { - app.quit(); - } else { - app.on("second-instance", () => { - // Someone tried to run a second instance, we should focus our window. - if (mainWindow) { - if (mainWindow.isMinimized()) mainWindow.restore(); - mainWindow.focus(); - } - }); - - // Launch app on first instance - app.whenReady().then(() => { - if (!mainWindow) { - createWindow(); - } - - // On macOS, re-create a window when dock icon is clicked - app.on("activate", () => { - if (BrowserWindow.getAllWindows().length === 0) { - createWindow(); - } - mainWindow?.show(); - }); - }); - - // Quit when all windows are closed, except on macOS - app.on("window-all-closed", () => { - if (process.platform !== "darwin") { - app.quit(); - } - }); - } -} - -/** - * Closes the application by closing the main window and quitting the app. - * - * @returns {void} - */ -export function closeApp() { - if (mainWindow) { - mainWindow.close(); - } - app.quit(); -} - -/** - * Focuses the application window, restoring it if minimized or creating it if not exists. - * - * @returns {void} - */ -export function focusApp() { - if (mainWindow) { - if (mainWindow.isMinimized()) { - mainWindow.restore(); - } - mainWindow.focus(); - mainWindow.show(); - } else { - launchApp(); - } - mainWindow?.show(); -} - -export const operations = { - signMessage: { - title: "Sign Message", - description: "Sign a message with the user's private key", - tool: async (message: string): Promise => { - mainWindow?.webContents.send("sign-message", message); - return new Promise(resolve => { - ipcMain.once("sign-message-response", (_event: IpcMainEvent, signature: string) => { - logger.info("sign-message-response from main", signature); - resolve(signature); - }); - }); - }, - }, - - discoveryList: { - title: "Discovery List", - description: "Get list of available discovery items", - tool: async (): Promise => { - logger.info("discoveryList called"); - mainWindow?.webContents.send("discovery-list"); - return new Promise(resolve => { - ipcMain.once( - "discovery-list-response", - (_event: IpcMainEvent, items: DiscoveryListResponse) => { - logger.info("discovery-list-response from main", items); - resolve(items); - }, - ); - }); - }, - }, - - makeX402Request: { - title: "Make HTTP Request with X402 Payment", - description: "Make an HTTP request to an X402-enabled endpoint, handling any required payments", - tool: async (params: X402RequestParams): Promise => { - logger.info("makeX402Request called", params); - mainWindow?.webContents.send("make-x402-request", params); - return new Promise((resolve, reject) => { - ipcMain.once( - "make-x402-request-response", - (_event: IpcMainEvent, result: { error?: string; data?: unknown }) => { - logger.info("make-x402-request-response from main", result); - if (result.error) { - reject(new Error(result.error)); - } else { - resolve(result); - } - }, - ); - }); - }, - }, - - getWalletAddress: { - title: "Get Wallet Address", - description: "Get the user's wallet address", - tool: async (): Promise => { - logger.info("getWalletAddress called"); - mainWindow?.webContents.send("get-wallet-address"); - return new Promise((resolve, reject) => { - ipcMain.once( - "get-wallet-address-response", - (_event: IpcMainEvent, result: { error?: string; data?: string }) => { - logger.info("get-wallet-address-response from main", result); - if (result.error) { - reject(new Error(result.error)); - } else if (result.data) { - resolve(result.data); - } else { - reject(new Error("No wallet address received")); - } - }, - ); - }); - }, - }, -}; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/index.html b/examples/typescript/legacy/mcp-embedded-wallet/index.html deleted file mode 100644 index 20c712e1a2..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/index.html +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - x402 MCP - -
- - - - diff --git a/examples/typescript/legacy/mcp-embedded-wallet/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/index.ts deleted file mode 100644 index 5d672b96eb..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/index.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { closeApp, launchApp } from "./electron"; -import { launchMcp } from "./mcp"; -import { logger } from "./logger"; - -// Handle process termination -process.on("disconnect", function () { - closeApp(); - process.exit(); -}); - -process.on("SIGTERM", () => { - closeApp(); - process.exit(0); -}); - -process.on("SIGINT", () => { - closeApp(); - process.exit(0); -}); - -// Prevent the Node.js process from exiting while MCP server is running -process.stdin.resume(); - -/** - * Main entry point for the application. Launches both the Electron app and MCP server. - * Handles any startup errors and exits the process if initialization fails. - * - * @returns {Promise} Resolves when both app and MCP server are launched - */ -async function main() { - try { - logger.info("Starting app"); - await launchApp(); - logger.info("Starting MCP server"); - await launchMcp(); - } catch (error) { - logger.error("Failed to start:", error); - process.exit(1); - } -} - -main(); diff --git a/examples/typescript/legacy/mcp-embedded-wallet/logger.ts b/examples/typescript/legacy/mcp-embedded-wallet/logger.ts deleted file mode 100644 index 90707c3bdd..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/logger.ts +++ /dev/null @@ -1,11 +0,0 @@ -import winston from "winston"; - -export const logger = winston.createLogger({ - level: "info", - format: winston.format.json(), - transports: [ - new winston.transports.File({ - filename: "./logs/mcp.log", - }), - ], -}); diff --git a/examples/typescript/legacy/mcp-embedded-wallet/mcp.ts b/examples/typescript/legacy/mcp-embedded-wallet/mcp.ts deleted file mode 100644 index 3692d3fcf7..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/mcp.ts +++ /dev/null @@ -1,181 +0,0 @@ -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import { z } from "zod"; -import { focusApp, operations } from "./electron"; -import { logger } from "./logger"; -import { useFacilitator } from "x402/verify"; -import { ipcMain } from "electron"; - -// Create an MCP server -const server = new McpServer({ - name: "x402-mcp", - version: "1.0.0", -}); - -// Input schema for the x402 request tool -const x402RequestSchema = z.object({ - baseURL: z.string().url(), - path: z.string(), - method: z.enum(["GET", "POST", "PUT", "DELETE", "PATCH"]), - queryParams: z.record(z.string()).optional(), - body: z.unknown().optional(), - correlationId: z - .string() - .optional() - .describe("Optional correlation ID to group related x402 operations together"), - maxAmountPerRequest: z.number().optional().describe("Optional max amount per request"), - paymentRequirements: z - .array(z.any()) - .optional() - .describe( - "Optional payment requirements from discovery endpoint - when provided, skips initial 402 discovery", - ), -}); - -// Input schema for the sign message tool -const signMessageSchema = z.object({ - message: z.string().describe("The message to sign").default("hello"), -}); - -// Register tools -server.registerTool( - "make_http_request_with_x402", - { - title: operations.makeX402Request.title, - description: operations.makeX402Request.description, - inputSchema: x402RequestSchema.shape, - }, - async params => { - logger.info("make_http_request_with_x402 tool called", params); - try { - const response = await operations.makeX402Request.tool(params); - return { - content: [ - { - type: "text", - text: JSON.stringify(response, null, 2), - }, - ], - }; - } catch (error) { - logger.error("x402 request failed", error); - throw error; - } - }, -); - -server.registerTool( - "discovery_list", - { - title: operations.discoveryList.title, - description: operations.discoveryList.description, - }, - async () => { - logger.info("discovery_list tool called"); - const items = await operations.discoveryList.tool(); - return { - content: [ - { - type: "text", - text: JSON.stringify(items, null, 2), - }, - ], - }; - }, -); - -server.registerTool( - "sign_message", - { - title: operations.signMessage.title, - description: operations.signMessage.description, - inputSchema: signMessageSchema.shape, - }, - async params => { - logger.info("sign_message tool called", params); - const validatedParams = signMessageSchema.parse(params || {}); - const { message } = validatedParams; - return { - content: [{ type: "text", text: await operations.signMessage.tool(message) }], - }; - }, -); - -server.registerTool( - "get_wallet_address", - { - title: "Get Wallet Address", - description: "Get the wallet address", - }, - async params => { - logger.info("get_wallet_address tool called", params); - try { - const address = await operations.getWalletAddress.tool(); - return { - content: [{ type: "text", text: address }], - }; - } catch (error) { - logger.error("get_wallet_address failed", error); - throw error; - } - }, -); - -server.registerTool( - "show_wallet_app", - { - title: "Show Wallet App", - description: "Shows the user the wallet interface", - }, - async () => { - logger.info("show_wallet_app tool called"); - focusApp(); - return { content: [{ type: "text", text: "Wallet app launched" }] }; - }, -); - -// Add discovery list handler -ipcMain.handle("get-discovery-list", async () => { - try { - const facilitator = { - url: "https://x402.org/facilitator" as `${string}://${string}`, // <--- Use a facilitator with discovery support here - }; - const { list } = useFacilitator(facilitator); - return await list(); - } catch (error) { - console.error("Failed to fetch discovery list:", error); - throw error; - } -}); - -/** - * Launches the Model Context Protocol (MCP) server with configured tools and handlers. - * Sets up stdin/stdout transport, error handling, and keeps the process alive until terminated. - * - * @returns {Promise} Resolves when the server is shut down gracefully - */ -export async function launchMcp() { - // Start receiving messages on stdin and sending messages on stdout - const transport = new StdioServerTransport(); - - try { - logger.info("Initializing server..."); - await server.connect(transport); - logger.info("Server started and connected successfully"); - - // Set up error handling - process.on("uncaughtException", error => { - logger.error("Uncaught exception:", error); - process.exit(1); - }); - - // Keep the process alive until explicitly terminated - await new Promise(resolve => { - process.on("SIGTERM", () => resolve(undefined)); - process.on("SIGINT", () => resolve(undefined)); - }); - } catch (error) { - logger.error("Failed to start MCP server:", error); - process.exit(1); - } -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/package.json b/examples/typescript/legacy/mcp-embedded-wallet/package.json deleted file mode 100644 index 68674e2c61..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/package.json +++ /dev/null @@ -1,72 +0,0 @@ -{ - "name": "x402-mcp-embedded-wallet", - "productName": "x402 MCP With Embedded Wallet", - "version": "1.0.0", - "description": "", - "main": "index.ts", - "type": "module", - "private": true, - "scripts": { - "electron": "NODE_ENV=development NODE_OPTIONS=\"--import tsx\" electron index.ts", - "electron:testnet": "VITE_TESTNET=true NODE_ENV=development NODE_OPTIONS=\"--import tsx\" electron index.ts", - "build": "vite build", - "mcp": "NODE_ENV=production NODE_OPTIONS=\"--import tsx\" electron index.ts", - "mcp:testnet": "VITE_TESTNET=true NODE_ENV=production NODE_OPTIONS=\"--import tsx\" electron index.ts", - "watch": "tsc -w", - "site": "vite", - "clean": "rm -rf dist", - "dev": "concurrently 'pnpm electron' 'pnpm site'", - "format": "prettier -c .prettierrc --write \"**/*.{ts,tsx,js,cjs,json,md}\"", - "format:check": "prettier -c .prettierrc --check \"**/*.{ts,tsx,js,cjs,json,md}\"", - "lint": "eslint . --ext .ts,.tsx --fix", - "lint:check": "eslint . --ext .ts,.tsx" - }, - "keywords": [], - "author": "", - "license": "ISC", - "packageManager": "pnpm@10.11.1", - "dependencies": { - "@coinbase/cdp-core": "^0.0.18", - "@coinbase/cdp-hooks": "^0.0.18", - "@coinbase/cdp-react": "^0.0.18", - "@modelcontextprotocol/sdk": "^1.15.1", - "@radix-ui/react-form": "^0.1.7", - "@radix-ui/react-icons": "^1.3.2", - "@radix-ui/themes": "^3.2.1", - "axios": "^1.10.0", - "electron-builder": "^26.0.12", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "react-qr-code": "^2.0.15", - "turbo": "^2.5.5", - "viem": "^2.21.26", - "winston": "^3.17.0", - "x402": "workspace:*", - "x402-axios": "workspace:*", - "zod": "^3.23.8", - "zustand": "^5.0.6" - }, - "devDependencies": { - "@eslint/js": "^9.24.0", - "@types/node": "^24.0.13", - "@types/react": "19.2.1", - "@types/react-dom": "19.2.1", - "@typescript-eslint/eslint-plugin": "^8.29.1", - "@typescript-eslint/parser": "^8.29.1", - "@vitejs/plugin-react": "^4.7.0", - "concurrently": "^9.2.0", - "electron": "^37.2.1", - "electron-is-dev": "^3.0.1", - "eslint": "^9.24.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", - "prettier": "3.5.2", - "tsx": "^4.20.3", - "typescript": "^5.8.3", - "vite": "^7.0.5" - }, - "onlyBuiltDependencies": [ - "electron" - ] -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/pnpm-lock.yaml b/examples/typescript/legacy/mcp-embedded-wallet/pnpm-lock.yaml deleted file mode 100644 index b81e3b757f..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/pnpm-lock.yaml +++ /dev/null @@ -1,10190 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@coinbase/cdp-core': - specifier: ^0.0.18 - version: 0.0.18(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@coinbase/cdp-hooks': - specifier: ^0.0.18 - version: 0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(react@18.3.1) - '@coinbase/cdp-react': - specifier: ^0.0.18 - version: 0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(@coinbase/cdp-hooks@0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(react@18.3.1))(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@coinbase/x402': - specifier: 0.4.3 - version: 0.4.3(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.0(react@18.3.1))(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@modelcontextprotocol/sdk': - specifier: ^1.15.1 - version: 1.16.0 - '@radix-ui/react-form': - specifier: ^0.1.7 - version: 0.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-icons': - specifier: ^1.3.2 - version: 1.3.2(react@18.3.1) - '@radix-ui/themes': - specifier: ^3.2.1 - version: 3.2.1(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - axios: - specifier: ^1.10.0 - version: 1.10.0 - electron-builder: - specifier: ^26.0.12 - version: 26.0.12(electron-builder-squirrel-windows@26.0.12) - react: - specifier: ^18.2.0 - version: 18.3.1 - react-dom: - specifier: ^18.2.0 - version: 18.3.1(react@18.3.1) - turbo: - specifier: ^2.5.5 - version: 2.5.5 - viem: - specifier: ^2.21.26 - version: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - winston: - specifier: ^3.17.0 - version: 3.17.0 - x402: - specifier: 0.4.3 - version: 0.4.3(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.0(react@18.3.1))(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10) - x402-axios: - specifier: 0.4.2 - version: 0.4.2(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.0(react@18.3.1))(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10) - zod: - specifier: ^3.23.8 - version: 3.25.76 - zustand: - specifier: ^5.0.6 - version: 5.0.6(@types/react@19.1.8)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - devDependencies: - '@types/node': - specifier: ^24.0.13 - version: 24.1.0 - '@types/react': - specifier: ^19.1.8 - version: 19.1.8 - '@types/react-dom': - specifier: ^19.1.6 - version: 19.1.6(@types/react@19.1.8) - '@vitejs/plugin-react': - specifier: ^4.7.0 - version: 4.7.0(vite@7.0.5(@types/node@24.1.0)(tsx@4.20.3)) - concurrently: - specifier: ^9.2.0 - version: 9.2.0 - electron: - specifier: ^37.2.1 - version: 37.2.3 - electron-is-dev: - specifier: ^3.0.1 - version: 3.0.1 - tsx: - specifier: ^4.20.3 - version: 4.20.3 - typescript: - specifier: ^5.8.3 - version: 5.8.3 - vite: - specifier: ^7.0.5 - version: 7.0.5(@types/node@24.1.0)(tsx@4.20.3) - -packages: - - 7zip-bin@5.2.0: - resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==} - - '@adraffy/ens-normalize@1.11.0': - resolution: {integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==} - - '@ampproject/remapping@2.3.0': - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} - - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.28.0': - resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.28.0': - resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.28.0': - resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.27.3': - resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.27.6': - resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.28.0': - resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.28.2': - resolution: {integrity: sha512-KHp2IflsnGywDjBWDkR9iEqiWSpc8GIi0lgTT3mOElT0PP1tG26P4tmFI2YvAdzgq9RGyoHZQEIEdZy6Ec5xCA==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.28.0': - resolution: {integrity: sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.28.1': - resolution: {integrity: sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==} - engines: {node: '>=6.9.0'} - - '@base-org/account@1.1.1': - resolution: {integrity: sha512-IfVJPrDPhHfqXRDb89472hXkpvJuQQR7FDI9isLPHEqSYt/45whIoBxSPgZ0ssTt379VhQo4+87PWI1DoLSfAQ==} - - '@coinbase/cdp-api-client@0.0.18': - resolution: {integrity: sha512-E+AU1oLU4UTKS/mWDcLsbmGWRK9iR542TfwBI62yH73A0TVshTxMlCCw/LaLe8LrqUIo9C4lmtGJerJoJN3OVA==} - - '@coinbase/cdp-core@0.0.18': - resolution: {integrity: sha512-kcdeqckZUJTle4YaH4bV1xHxkSHltIJf1REZ+U6/5SJ+qCiRz88QI1mFTF3/FQ6DhkvsS9Z57AahNXvOElFG2g==} - - '@coinbase/cdp-hooks@0.0.18': - resolution: {integrity: sha512-SpHq5jb3S/cXmAtDkOZsC6zUHjKEGfTfYsxtL3bs5lJXRJ7CiqDjyeTuKRZuTP2dhm1VbBM/3RUEs8WAS1Spiw==} - peerDependencies: - '@coinbase/cdp-core': ^0.0.18 - react: '>=18.2.0' - - '@coinbase/cdp-react@0.0.18': - resolution: {integrity: sha512-1t8soyd0io0KISBsOFUiJD+6xrfGxnqvMjf2XFMjwaB6bsXWsYvRPd8V+cnA7dpe7xoZJ85ZJkNT0UT61V8vNA==} - peerDependencies: - '@coinbase/cdp-core': ^0.0.18 - '@coinbase/cdp-hooks': ^0.0.18 - react: '>=18.2.0' - - '@coinbase/cdp-sdk@1.30.0': - resolution: {integrity: sha512-uVByA4XLLzs2b1SES51izsapj3wt+lOAJI0xbE4MNb4D3tzV5RJ2+O7+SDJaQXU4jjn9KsdVvvDSpSU+nM81Zg==} - - '@coinbase/wallet-sdk@3.9.3': - resolution: {integrity: sha512-N/A2DRIf0Y3PHc1XAMvbBUu4zisna6qAdqABMZwBMNEfWrXpAwx16pZGkYCLGE+Rvv1edbcB2LYDRnACNcmCiw==} - - '@coinbase/wallet-sdk@4.3.6': - resolution: {integrity: sha512-4q8BNG1ViL4mSAAvPAtpwlOs1gpC+67eQtgIwNvT3xyeyFFd+guwkc8bcX5rTmQhXpqnhzC4f0obACbP9CqMSA==} - - '@coinbase/x402@0.4.3': - resolution: {integrity: sha512-1E77B0W12qpXH2Em8Z4CJLRUnumzn+YCyedIN2dnHMHh9bfCDfdmjTZJACl4Wxv3zUErX+Zl4JafjkrpQ94Yvw==} - - '@colors/colors@1.6.0': - resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} - engines: {node: '>=0.1.90'} - - '@dabh/diagnostics@2.0.3': - resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} - - '@develar/schema-utils@2.6.5': - resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} - engines: {node: '>= 8.9.0'} - - '@ecies/ciphers@0.2.4': - resolution: {integrity: sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==} - engines: {bun: '>=1', deno: '>=2', node: '>=16'} - peerDependencies: - '@noble/ciphers': ^1.0.0 - - '@electron/asar@3.2.18': - resolution: {integrity: sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg==} - engines: {node: '>=10.12.0'} - hasBin: true - - '@electron/asar@3.4.1': - resolution: {integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==} - engines: {node: '>=10.12.0'} - hasBin: true - - '@electron/fuses@1.8.0': - resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==} - hasBin: true - - '@electron/get@2.0.3': - resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} - engines: {node: '>=12'} - - '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': - resolution: {tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2} - version: 10.2.0-electron.1 - engines: {node: '>=12.13.0'} - hasBin: true - - '@electron/notarize@2.5.0': - resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==} - engines: {node: '>= 10.0.0'} - - '@electron/osx-sign@1.3.1': - resolution: {integrity: sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==} - engines: {node: '>=12.0.0'} - hasBin: true - - '@electron/rebuild@3.7.0': - resolution: {integrity: sha512-VW++CNSlZwMYP7MyXEbrKjpzEwhB5kDNbzGtiPEjwYysqyTCF+YbNJ210Dj3AjWsGSV4iEEwNkmJN9yGZmVvmw==} - engines: {node: '>=12.13.0'} - hasBin: true - - '@electron/universal@2.0.1': - resolution: {integrity: sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==} - engines: {node: '>=16.4'} - - '@electron/windows-sign@1.2.2': - resolution: {integrity: sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==} - engines: {node: '>=14.14'} - hasBin: true - - '@esbuild/aix-ppc64@0.25.8': - resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.25.8': - resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.25.8': - resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.25.8': - resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.25.8': - resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.8': - resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.25.8': - resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.8': - resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.25.8': - resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.25.8': - resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.25.8': - resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.25.8': - resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.25.8': - resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.25.8': - resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.8': - resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.25.8': - resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.25.8': - resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.8': - resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.8': - resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.8': - resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.8': - resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.8': - resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.25.8': - resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.25.8': - resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.25.8': - resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.25.8': - resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@ethereumjs/common@3.2.0': - resolution: {integrity: sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==} - - '@ethereumjs/rlp@4.0.1': - resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} - engines: {node: '>=14'} - hasBin: true - - '@ethereumjs/tx@4.2.0': - resolution: {integrity: sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==} - engines: {node: '>=14'} - - '@ethereumjs/util@8.1.0': - resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} - engines: {node: '>=14'} - - '@floating-ui/core@1.7.2': - resolution: {integrity: sha512-wNB5ooIKHQc+Kui96jE/n69rHFWAVoxn5CAzL1Xdd8FG03cgY3MLO+GF9U3W737fYDSgPWA6MReKhBQBop6Pcw==} - - '@floating-ui/dom@1.7.2': - resolution: {integrity: sha512-7cfaOQuCS27HD7DX+6ib2OrnW+b4ZBwDNnCcT0uTyidcmyWb03FnQqJybDBoCnpdxwBSfA94UAYlRCt7mV+TbA==} - - '@floating-ui/react-dom@2.1.4': - resolution: {integrity: sha512-JbbpPhp38UmXDDAu60RJmbeme37Jbgsm7NrHGgzYYFKmblzRUh6Pa641dII6LsjwF4XlScDrde2UAzDo/b9KPw==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/utils@0.2.10': - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - - '@gar/promisify@1.1.3': - resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} - - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@jridgewell/gen-mapping@0.3.12': - resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.4': - resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} - - '@jridgewell/trace-mapping@0.3.29': - resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} - - '@lit-labs/ssr-dom-shim@1.4.0': - resolution: {integrity: sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==} - - '@lit/reactive-element@2.1.1': - resolution: {integrity: sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==} - - '@malept/cross-spawn-promise@2.0.0': - resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==} - engines: {node: '>= 12.13.0'} - - '@malept/flatpak-bundler@0.4.0': - resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} - engines: {node: '>= 10.0.0'} - - '@metamask/eth-json-rpc-provider@1.0.1': - resolution: {integrity: sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA==} - engines: {node: '>=14.0.0'} - - '@metamask/json-rpc-engine@7.3.3': - resolution: {integrity: sha512-dwZPq8wx9yV3IX2caLi9q9xZBw2XeIoYqdyihDDDpuHVCEiqadJLwqM3zy+uwf6F1QYQ65A8aOMQg1Uw7LMLNg==} - engines: {node: '>=16.0.0'} - - '@metamask/json-rpc-engine@8.0.2': - resolution: {integrity: sha512-IoQPmql8q7ABLruW7i4EYVHWUbF74yrp63bRuXV5Zf9BQwcn5H9Ww1eLtROYvI1bUXwOiHZ6qT5CWTrDc/t/AA==} - engines: {node: '>=16.0.0'} - - '@metamask/json-rpc-middleware-stream@7.0.2': - resolution: {integrity: sha512-yUdzsJK04Ev98Ck4D7lmRNQ8FPioXYhEUZOMS01LXW8qTvPGiRVXmVltj2p4wrLkh0vW7u6nv0mNl5xzC5Qmfg==} - engines: {node: '>=16.0.0'} - - '@metamask/object-multiplex@2.1.0': - resolution: {integrity: sha512-4vKIiv0DQxljcXwfpnbsXcfa5glMj5Zg9mqn4xpIWqkv6uJ2ma5/GtUfLFSxhlxnR8asRMv8dDmWya1Tc1sDFA==} - engines: {node: ^16.20 || ^18.16 || >=20} - - '@metamask/onboarding@1.0.1': - resolution: {integrity: sha512-FqHhAsCI+Vacx2qa5mAFcWNSrTcVGMNjzxVgaX8ECSny/BJ9/vgXP9V7WF/8vb9DltPeQkxr+Fnfmm6GHfmdTQ==} - - '@metamask/providers@16.1.0': - resolution: {integrity: sha512-znVCvux30+3SaUwcUGaSf+pUckzT5ukPRpcBmy+muBLC0yaWnBcvDqGfcsw6CBIenUdFrVoAFa8B6jsuCY/a+g==} - engines: {node: ^18.18 || >=20} - - '@metamask/rpc-errors@6.4.0': - resolution: {integrity: sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg==} - engines: {node: '>=16.0.0'} - - '@metamask/safe-event-emitter@2.0.0': - resolution: {integrity: sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==} - - '@metamask/safe-event-emitter@3.1.2': - resolution: {integrity: sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA==} - engines: {node: '>=12.0.0'} - - '@metamask/sdk-communication-layer@0.32.0': - resolution: {integrity: sha512-dmj/KFjMi1fsdZGIOtbhxdg3amxhKL/A5BqSU4uh/SyDKPub/OT+x5pX8bGjpTL1WPWY/Q0OIlvFyX3VWnT06Q==} - peerDependencies: - cross-fetch: ^4.0.0 - eciesjs: '*' - eventemitter2: ^6.4.9 - readable-stream: ^3.6.2 - socket.io-client: ^4.5.1 - - '@metamask/sdk-install-modal-web@0.32.0': - resolution: {integrity: sha512-TFoktj0JgfWnQaL3yFkApqNwcaqJ+dw4xcnrJueMP3aXkSNev2Ido+WVNOg4IIMxnmOrfAC9t0UJ0u/dC9MjOQ==} - - '@metamask/sdk@0.32.0': - resolution: {integrity: sha512-WmGAlP1oBuD9hk4CsdlG1WJFuPtYJY+dnTHJMeCyohTWD2GgkcLMUUuvu9lO1/NVzuOoSi1OrnjbuY1O/1NZ1g==} - - '@metamask/superstruct@3.2.1': - resolution: {integrity: sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g==} - engines: {node: '>=16.0.0'} - - '@metamask/utils@5.0.2': - resolution: {integrity: sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==} - engines: {node: '>=14.0.0'} - - '@metamask/utils@8.5.0': - resolution: {integrity: sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==} - engines: {node: '>=16.0.0'} - - '@metamask/utils@9.3.0': - resolution: {integrity: sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==} - engines: {node: '>=16.0.0'} - - '@modelcontextprotocol/sdk@1.16.0': - resolution: {integrity: sha512-8ofX7gkZcLj9H9rSd50mCgm3SSF8C7XoclxJuLoV0Cz3rEQ1tv9MZRYYvJtm9n1BiEQQMzSmE/w2AEkNacLYfg==} - engines: {node: '>=18'} - - '@noble/ciphers@1.2.1': - resolution: {integrity: sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==} - engines: {node: ^14.21.3 || >=16} - - '@noble/ciphers@1.3.0': - resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} - engines: {node: ^14.21.3 || >=16} - - '@noble/curves@1.4.2': - resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} - - '@noble/curves@1.8.0': - resolution: {integrity: sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==} - engines: {node: ^14.21.3 || >=16} - - '@noble/curves@1.8.1': - resolution: {integrity: sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==} - engines: {node: ^14.21.3 || >=16} - - '@noble/curves@1.9.2': - resolution: {integrity: sha512-HxngEd2XUcg9xi20JkwlLCtYwfoFw4JGkuZpT+WlsPD4gB/cxkvTD8fSsoAnphGZhFdZYKeQIPCuFlWPm1uE0g==} - engines: {node: ^14.21.3 || >=16} - - '@noble/curves@1.9.4': - resolution: {integrity: sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==} - engines: {node: ^14.21.3 || >=16} - - '@noble/hashes@1.4.0': - resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} - engines: {node: '>= 16'} - - '@noble/hashes@1.7.0': - resolution: {integrity: sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==} - engines: {node: ^14.21.3 || >=16} - - '@noble/hashes@1.7.1': - resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} - engines: {node: ^14.21.3 || >=16} - - '@noble/hashes@1.8.0': - resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} - engines: {node: ^14.21.3 || >=16} - - '@npmcli/fs@2.1.2': - resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - '@npmcli/move-file@2.0.1': - resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - deprecated: This functionality has been moved to @npmcli/fs - - '@paulmillr/qr@0.2.1': - resolution: {integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==} - deprecated: 'The package is now available as "qr": npm install qr' - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@radix-ui/colors@3.0.0': - resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==} - - '@radix-ui/number@1.1.1': - resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - - '@radix-ui/primitive@1.1.2': - resolution: {integrity: sha512-XnbHrrprsNqZKQhStrSwgRUQzoCI1glLzdw79xiZPoofhGICeZRSQ3dIxAKH1gb3OHfNf4d6f+vAv3kil2eggA==} - - '@radix-ui/react-accessible-icon@1.1.7': - resolution: {integrity: sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-accordion@1.2.11': - resolution: {integrity: sha512-l3W5D54emV2ues7jjeG1xcyN7S3jnK3zE2zHqgn0CmMsy9lNJwmgcrmaxS+7ipw15FAivzKNzH3d5EcGoFKw0A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-alert-dialog@1.1.14': - resolution: {integrity: sha512-IOZfZ3nPvN6lXpJTBCunFQPRSvK8MDgSc1FB85xnIpUKOw9en0dJj8JmCAxV7BiZdtYlUpmrQjoTFkVYtdoWzQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-arrow@1.1.7': - resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-aspect-ratio@1.1.7': - resolution: {integrity: sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-avatar@1.1.10': - resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-checkbox@1.3.2': - resolution: {integrity: sha512-yd+dI56KZqawxKZrJ31eENUwqc1QSqg4OZ15rybGjF2ZNwMO+wCyHzAVLRp9qoYJf7kYy0YpZ2b0JCzJ42HZpA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-collapsible@1.1.11': - resolution: {integrity: sha512-2qrRsVGSCYasSz1RFOorXwl0H7g7J1frQtgpQgYrt+MOidtPAINHn9CPovQXb83r8ahapdx3Tu0fa/pdFFSdPg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-collection@1.1.7': - resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context-menu@2.2.15': - resolution: {integrity: sha512-UsQUMjcYTsBjTSXw0P3GO0werEQvUY2plgRQuKoCTtkNr45q1DiL51j4m7gxhABzZ0BadoXNsIbg7F3KwiUBbw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dialog@1.1.14': - resolution: {integrity: sha512-+CpweKjqpzTmwRwcYECQcNYbI8V9VSQt0SNFKeEBLgfucbsLssU6Ppq7wUdNXEGb573bMjFhVjKVll8rmV6zMw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dismissable-layer@1.1.10': - resolution: {integrity: sha512-IM1zzRV4W3HtVgftdQiiOmA0AdJlCtMLe00FXaHwgt3rAnNsIyDqshvkIW3hj/iu5hu8ERP7KIYki6NkqDxAwQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-dropdown-menu@2.1.15': - resolution: {integrity: sha512-mIBnOjgwo9AH3FyKaSWoSu/dYj6VdhJ7frEPiGTeXCdUFHjl9h3mFh2wwhEtINOmYXWhdpf1rY2minFsmaNgVQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-focus-guards@1.1.2': - resolution: {integrity: sha512-fyjAACV62oPV925xFCrH8DR5xWhg9KYtJT4s3u54jxp+L/hbpTY2kIeEFFbFe+a/HCE94zGQMZLIpVTPVZDhaA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-focus-scope@1.1.7': - resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-form@0.1.7': - resolution: {integrity: sha512-IXLKFnaYvFg/KkeV5QfOX7tRnwHXp127koOFUjLWMTrRv5Rny3DQcAtIFFeA/Cli4HHM8DuJCXAUsgnFVJndlw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-hover-card@1.1.14': - resolution: {integrity: sha512-CPYZ24Mhirm+g6D8jArmLzjYu4Eyg3TTUHswR26QgzXBHBe64BO/RHOJKzmF/Dxb4y4f9PKyJdwm/O/AhNkb+Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-icons@1.3.2': - resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==} - peerDependencies: - react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc - - '@radix-ui/react-id@1.1.1': - resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-label@2.1.7': - resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-menu@2.1.15': - resolution: {integrity: sha512-tVlmA3Vb9n8SZSd+YSbuFR66l87Wiy4du+YE+0hzKQEANA+7cWKH1WgqcEX4pXqxUFQKrWQGHdvEfw00TjFiew==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-menubar@1.1.15': - resolution: {integrity: sha512-Z71C7LGD+YDYo3TV81paUs8f3Zbmkvg6VLRQpKYfzioOE6n7fOhA3ApK/V/2Odolxjoc4ENk8AYCjohCNayd5A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-navigation-menu@1.2.13': - resolution: {integrity: sha512-WG8wWfDiJlSF5hELjwfjSGOXcBR/ZMhBFCGYe8vERpC39CQYZeq1PQ2kaYHdye3V95d06H89KGMsVCIE4LWo3g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-one-time-password-field@0.1.7': - resolution: {integrity: sha512-w1vm7AGI8tNXVovOK7TYQHrAGpRF7qQL+ENpT1a743De5Zmay2RbWGKAiYDKIyIuqptns+znCKwNztE2xl1n0Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-password-toggle-field@0.1.2': - resolution: {integrity: sha512-F90uYnlBsLPU1UbSLciLsWQmk8+hdWa6SFw4GXaIdNWxFxI5ITKVdAG64f+Twaa9ic6xE7pqxPyUmodrGjT4pQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popover@1.1.14': - resolution: {integrity: sha512-ODz16+1iIbGUfFEfKx2HTPKizg2MN39uIOV8MXeHnmdd3i/N9Wt7vU46wbHsqA0xoaQyXVcs0KIlBdOA2Y95bw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popper@1.2.7': - resolution: {integrity: sha512-IUFAccz1JyKcf/RjB552PlWwxjeCJB8/4KxT7EhBHOJM+mN7LdW+B3kacJXILm32xawcMMjb2i0cIZpo+f9kiQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-portal@1.1.9': - resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-presence@1.1.4': - resolution: {integrity: sha512-ueDqRbdc4/bkaQT3GIpLQssRlFgWaL/U2z/S31qRwwLWoxHLgry3SIfCwhxeQNbirEUXFa+lq3RL3oBYXtcmIA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-progress@1.1.7': - resolution: {integrity: sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-radio-group@1.3.7': - resolution: {integrity: sha512-9w5XhD0KPOrm92OTTE0SysH3sYzHsSTHNvZgUBo/VZ80VdYyB5RneDbc0dKpURS24IxkoFRu/hI0i4XyfFwY6g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-roving-focus@1.1.10': - resolution: {integrity: sha512-dT9aOXUen9JSsxnMPv/0VqySQf5eDQ6LCk5Sw28kamz8wSOW2bJdlX2Bg5VUIIcV+6XlHpWTIuTPCf/UNIyq8Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-scroll-area@1.2.9': - resolution: {integrity: sha512-YSjEfBXnhUELsO2VzjdtYYD4CfQjvao+lhhrX5XsHD7/cyUNzljF1FHEbgTPN7LH2MClfwRMIsYlqTYpKTTe2A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-select@2.2.5': - resolution: {integrity: sha512-HnMTdXEVuuyzx63ME0ut4+sEMYW6oouHWNGUZc7ddvUWIcfCva/AMoqEW/3wnEllriMWBa0RHspCYnfCWJQYmA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-separator@1.1.7': - resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slider@1.3.5': - resolution: {integrity: sha512-rkfe2pU2NBAYfGaxa3Mqosi7VZEWX5CxKaanRv0vZd4Zhl9fvQrg0VM93dv3xGLGfrHuoTRF3JXH8nb9g+B3fw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-switch@1.2.5': - resolution: {integrity: sha512-5ijLkak6ZMylXsaImpZ8u4Rlf5grRmoc0p0QeX9VJtlrM4f5m3nCTX8tWga/zOA8PZYIR/t0p2Mnvd7InrJ6yQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-tabs@1.1.12': - resolution: {integrity: sha512-GTVAlRVrQrSw3cEARM0nAx73ixrWDPNZAruETn3oHCNP6SbZ/hNxdxp+u7VkIEv3/sFoLq1PfcHrl7Pnp0CDpw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toast@1.2.14': - resolution: {integrity: sha512-nAP5FBxBJGQ/YfUB+r+O6USFVkWq3gAInkxyEnmvEV5jtSbfDhfa4hwX8CraCnbjMLsE7XSf/K75l9xXY7joWg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toggle-group@1.1.10': - resolution: {integrity: sha512-kiU694Km3WFLTC75DdqgM/3Jauf3rD9wxeS9XtyWFKsBUeZA337lC+6uUazT7I1DhanZ5gyD5Stf8uf2dbQxOQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toggle@1.1.9': - resolution: {integrity: sha512-ZoFkBBz9zv9GWer7wIjvdRxmh2wyc2oKWw6C6CseWd6/yq1DK/l5lJ+wnsmFwJZbBYqr02mrf8A2q/CVCuM3ZA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toolbar@1.1.10': - resolution: {integrity: sha512-jiwQsduEL++M4YBIurjSa+voD86OIytCod0/dbIxFZDLD8NfO1//keXYMfsW8BPcfqwoNjt+y06XcJqAb4KR7A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-tooltip@1.2.7': - resolution: {integrity: sha512-Ap+fNYwKTYJ9pzqW+Xe2HtMRbQ/EeWkj2qykZ6SuEV4iS/o1bZI5ssJbk4D2r8XuDuOBVz/tIx2JObtuqU+5Zw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-is-hydrated@0.1.0': - resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-previous@1.1.1': - resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-rect@1.1.1': - resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-size@1.1.1': - resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-visually-hidden@1.2.3': - resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/rect@1.1.1': - resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - - '@radix-ui/themes@3.2.1': - resolution: {integrity: sha512-WJL2YKAGItkunwm3O4cLTFKCGJTfAfF6Hmq7f5bCo1ggqC9qJQ/wfg/25AAN72aoEM1yqXZQ+pslsw48AFR0Xg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: 16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@reown/appkit-common@1.7.8': - resolution: {integrity: sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==} - - '@reown/appkit-controllers@1.7.8': - resolution: {integrity: sha512-IdXlJlivrlj6m63VsGLsjtPHHsTWvKGVzWIP1fXZHVqmK+rZCBDjCi9j267Rb9/nYRGHWBtlFQhO8dK35WfeDA==} - - '@reown/appkit-pay@1.7.8': - resolution: {integrity: sha512-OSGQ+QJkXx0FEEjlpQqIhT8zGJKOoHzVnyy/0QFrl3WrQTjCzg0L6+i91Ad5Iy1zb6V5JjqtfIFpRVRWN4M3pw==} - - '@reown/appkit-polyfills@1.7.8': - resolution: {integrity: sha512-W/kq786dcHHAuJ3IV2prRLEgD/2iOey4ueMHf1sIFjhhCGMynMkhsOhQMUH0tzodPqUgAC494z4bpIDYjwWXaA==} - - '@reown/appkit-scaffold-ui@1.7.8': - resolution: {integrity: sha512-RCeHhAwOrIgcvHwYlNWMcIDibdI91waaoEYBGw71inE0kDB8uZbE7tE6DAXJmDkvl0qPh+DqlC4QbJLF1FVYdQ==} - - '@reown/appkit-ui@1.7.8': - resolution: {integrity: sha512-1hjCKjf6FLMFzrulhl0Y9Vb9Fu4royE+SXCPSWh4VhZhWqlzUFc7kutnZKx8XZFVQH4pbBvY62SpRC93gqoHow==} - - '@reown/appkit-utils@1.7.8': - resolution: {integrity: sha512-8X7UvmE8GiaoitCwNoB86pttHgQtzy4ryHZM9kQpvjQ0ULpiER44t1qpVLXNM4X35O0v18W0Dk60DnYRMH2WRw==} - peerDependencies: - valtio: 1.13.2 - - '@reown/appkit-wallet@1.7.8': - resolution: {integrity: sha512-kspz32EwHIOT/eg/ZQbFPxgXq0B/olDOj3YMu7gvLEFz4xyOFd/wgzxxAXkp5LbG4Cp++s/elh79rVNmVFdB9A==} - - '@reown/appkit@1.7.8': - resolution: {integrity: sha512-51kTleozhA618T1UvMghkhKfaPcc9JlKwLJ5uV+riHyvSoWPKPRIa5A6M1Wano5puNyW0s3fwywhyqTHSilkaA==} - - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - - '@rollup/rollup-android-arm-eabi@4.45.1': - resolution: {integrity: sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.45.1': - resolution: {integrity: sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.45.1': - resolution: {integrity: sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.45.1': - resolution: {integrity: sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.45.1': - resolution: {integrity: sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.45.1': - resolution: {integrity: sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.45.1': - resolution: {integrity: sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.45.1': - resolution: {integrity: sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.45.1': - resolution: {integrity: sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.45.1': - resolution: {integrity: sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loongarch64-gnu@4.45.1': - resolution: {integrity: sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-powerpc64le-gnu@4.45.1': - resolution: {integrity: sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.45.1': - resolution: {integrity: sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.45.1': - resolution: {integrity: sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.45.1': - resolution: {integrity: sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.45.1': - resolution: {integrity: sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.45.1': - resolution: {integrity: sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-win32-arm64-msvc@4.45.1': - resolution: {integrity: sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.45.1': - resolution: {integrity: sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.45.1': - resolution: {integrity: sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==} - cpu: [x64] - os: [win32] - - '@safe-global/safe-apps-provider@0.18.6': - resolution: {integrity: sha512-4LhMmjPWlIO8TTDC2AwLk44XKXaK6hfBTWyljDm0HQ6TWlOEijVWNrt2s3OCVMSxlXAcEzYfqyu1daHZooTC2Q==} - - '@safe-global/safe-apps-sdk@9.1.0': - resolution: {integrity: sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q==} - - '@safe-global/safe-gateway-typescript-sdk@3.23.1': - resolution: {integrity: sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw==} - engines: {node: '>=16'} - - '@scure/base@1.1.9': - resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} - - '@scure/base@1.2.6': - resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} - - '@scure/bip32@1.4.0': - resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} - - '@scure/bip32@1.6.2': - resolution: {integrity: sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==} - - '@scure/bip32@1.7.0': - resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} - - '@scure/bip39@1.3.0': - resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} - - '@scure/bip39@1.5.4': - resolution: {integrity: sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==} - - '@scure/bip39@1.6.0': - resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} - - '@sindresorhus/is@4.6.0': - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} - - '@socket.io/component-emitter@3.1.2': - resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - - '@solana/buffer-layout-utils@0.2.0': - resolution: {integrity: sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==} - engines: {node: '>= 10'} - - '@solana/buffer-layout@4.0.1': - resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} - engines: {node: '>=5.10'} - - '@solana/codecs-core@2.0.0-rc.1': - resolution: {integrity: sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==} - peerDependencies: - typescript: '>=5' - - '@solana/codecs-core@2.3.0': - resolution: {integrity: sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/codecs-data-structures@2.0.0-rc.1': - resolution: {integrity: sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog==} - peerDependencies: - typescript: '>=5' - - '@solana/codecs-numbers@2.0.0-rc.1': - resolution: {integrity: sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==} - peerDependencies: - typescript: '>=5' - - '@solana/codecs-numbers@2.3.0': - resolution: {integrity: sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/codecs-strings@2.0.0-rc.1': - resolution: {integrity: sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g==} - peerDependencies: - fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5' - - '@solana/codecs@2.0.0-rc.1': - resolution: {integrity: sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ==} - peerDependencies: - typescript: '>=5' - - '@solana/errors@2.0.0-rc.1': - resolution: {integrity: sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==} - hasBin: true - peerDependencies: - typescript: '>=5' - - '@solana/errors@2.3.0': - resolution: {integrity: sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==} - engines: {node: '>=20.18.0'} - hasBin: true - peerDependencies: - typescript: '>=5.3.3' - - '@solana/options@2.0.0-rc.1': - resolution: {integrity: sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA==} - peerDependencies: - typescript: '>=5' - - '@solana/spl-token-group@0.0.7': - resolution: {integrity: sha512-V1N/iX7Cr7H0uazWUT2uk27TMqlqedpXHRqqAbVO2gvmJyT0E0ummMEAVQeXZ05ZhQ/xF39DLSdBp90XebWEug==} - engines: {node: '>=16'} - peerDependencies: - '@solana/web3.js': ^1.95.3 - - '@solana/spl-token-metadata@0.1.6': - resolution: {integrity: sha512-7sMt1rsm/zQOQcUWllQX9mD2O6KhSAtY1hFR2hfFwgqfFWzSY9E9GDvFVNYUI1F0iQKcm6HmePU9QbKRXTEBiA==} - engines: {node: '>=16'} - peerDependencies: - '@solana/web3.js': ^1.95.3 - - '@solana/spl-token@0.4.13': - resolution: {integrity: sha512-cite/pYWQZZVvLbg5lsodSovbetK/eA24gaR0eeUeMuBAMNrT8XFCwaygKy0N2WSg3gSyjjNpIeAGBAKZaY/1w==} - engines: {node: '>=16'} - peerDependencies: - '@solana/web3.js': ^1.95.5 - - '@solana/web3.js@1.98.4': - resolution: {integrity: sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==} - - '@swc/helpers@0.5.17': - resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} - - '@szmarczak/http-timer@4.0.6': - resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} - engines: {node: '>=10'} - - '@tanstack/query-core@5.83.1': - resolution: {integrity: sha512-OG69LQgT7jSp+5pPuCfzltq/+7l2xoweggjme9vlbCPa/d7D7zaqv5vN/S82SzSYZ4EDLTxNO1PWrv49RAS64Q==} - - '@tanstack/react-query@5.84.0': - resolution: {integrity: sha512-iPycFGLq5lltDE16Jf13Nx7SOvtfoopfOH/+Ahbdd+z4QqOfYu/SOkY86AVYVcKjneuqPxTm8e85lSGhwe0cog==} - peerDependencies: - react: ^18 || ^19 - - '@tootallnate/once@2.0.0': - resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} - engines: {node: '>= 10'} - - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.20.7': - resolution: {integrity: sha512-dkO5fhS7+/oos4ciWxyEyjWe48zmG6wbCheo/G2ZnHx4fs3EU6YC6UM8rk56gAjNJ9P3MTH2jo5jb92/K6wbng==} - - '@types/cacheable-request@6.0.3': - resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} - - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/fs-extra@9.0.13': - resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} - - '@types/http-cache-semantics@4.0.4': - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} - - '@types/keyv@3.1.4': - resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} - - '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - - '@types/node@12.20.55': - resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - - '@types/node@22.16.5': - resolution: {integrity: sha512-bJFoMATwIGaxxx8VJPeM8TonI8t579oRvgAuT8zFugJsJZgzqv0Fu8Mhp68iecjzG7cnN3mO2dJQ5uUM2EFrgQ==} - - '@types/node@24.1.0': - resolution: {integrity: sha512-ut5FthK5moxFKH2T1CUOC6ctR67rQRvvHdFLCD2Ql6KXmMuCrjsSsRI9UsLCm9M18BMwClv4pn327UvB7eeO1w==} - - '@types/plist@3.0.5': - resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==} - - '@types/react-dom@19.1.6': - resolution: {integrity: sha512-4hOiT/dwO8Ko0gV1m/TJZYk3y0KBnY9vzDh7W+DH17b2HFSOGgdj33dhihPeuy3l0q23+4e+hoXHV6hCC4dCXw==} - peerDependencies: - '@types/react': ^19.0.0 - - '@types/react@19.1.8': - resolution: {integrity: sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g==} - - '@types/responselike@1.0.3': - resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} - - '@types/triple-beam@1.3.5': - resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} - - '@types/trusted-types@2.0.7': - resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - - '@types/uuid@8.3.4': - resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} - - '@types/verror@1.10.11': - resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==} - - '@types/ws@7.4.7': - resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} - - '@types/ws@8.18.1': - resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - - '@types/yauzl@2.10.3': - resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} - - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - - '@wagmi/connectors@5.9.1': - resolution: {integrity: sha512-o50e6reSYkVi2d72WWwbKSZ7xgLAeQ1Ja64tTWq3UhU1XtJPvQXWieCInIGInOajAAsZsYCPKYrPj6WoSl0Hqw==} - peerDependencies: - '@wagmi/core': 2.18.1 - typescript: '>=5.0.4' - viem: 2.x - peerDependenciesMeta: - typescript: - optional: true - - '@wagmi/core@2.18.1': - resolution: {integrity: sha512-mU+qXeeY2/0lq8bf4uFm5RtMrc8FgOToqzMVMf6MzNdNbKxpNlmlbuTyRbyd9cxn4UnYa6+S6Bmx1x42FV7w3g==} - peerDependencies: - '@tanstack/query-core': '>=5.0.0' - typescript: '>=5.0.4' - viem: 2.x - peerDependenciesMeta: - '@tanstack/query-core': - optional: true - typescript: - optional: true - - '@walletconnect/core@2.21.0': - resolution: {integrity: sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==} - engines: {node: '>=18'} - - '@walletconnect/core@2.21.1': - resolution: {integrity: sha512-Tp4MHJYcdWD846PH//2r+Mu4wz1/ZU/fr9av1UWFiaYQ2t2TPLDiZxjLw54AAEpMqlEHemwCgiRiAmjR1NDdTQ==} - engines: {node: '>=18'} - - '@walletconnect/environment@1.0.1': - resolution: {integrity: sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==} - - '@walletconnect/ethereum-provider@2.21.1': - resolution: {integrity: sha512-SSlIG6QEVxClgl1s0LMk4xr2wg4eT3Zn/Hb81IocyqNSGfXpjtawWxKxiC5/9Z95f1INyBD6MctJbL/R1oBwIw==} - - '@walletconnect/events@1.0.1': - resolution: {integrity: sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==} - - '@walletconnect/heartbeat@1.2.2': - resolution: {integrity: sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==} - - '@walletconnect/jsonrpc-http-connection@1.0.8': - resolution: {integrity: sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==} - - '@walletconnect/jsonrpc-provider@1.0.14': - resolution: {integrity: sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==} - - '@walletconnect/jsonrpc-types@1.0.4': - resolution: {integrity: sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==} - - '@walletconnect/jsonrpc-utils@1.0.8': - resolution: {integrity: sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==} - - '@walletconnect/jsonrpc-ws-connection@1.0.16': - resolution: {integrity: sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==} - - '@walletconnect/keyvaluestorage@1.1.1': - resolution: {integrity: sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==} - peerDependencies: - '@react-native-async-storage/async-storage': 1.x - peerDependenciesMeta: - '@react-native-async-storage/async-storage': - optional: true - - '@walletconnect/logger@2.1.2': - resolution: {integrity: sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==} - - '@walletconnect/relay-api@1.0.11': - resolution: {integrity: sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==} - - '@walletconnect/relay-auth@1.1.0': - resolution: {integrity: sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==} - - '@walletconnect/safe-json@1.0.2': - resolution: {integrity: sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==} - - '@walletconnect/sign-client@2.21.0': - resolution: {integrity: sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==} - - '@walletconnect/sign-client@2.21.1': - resolution: {integrity: sha512-QaXzmPsMnKGV6tc4UcdnQVNOz4zyXgarvdIQibJ4L3EmLat73r5ZVl4c0cCOcoaV7rgM9Wbphgu5E/7jNcd3Zg==} - - '@walletconnect/time@1.0.2': - resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} - - '@walletconnect/types@2.21.0': - resolution: {integrity: sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==} - - '@walletconnect/types@2.21.1': - resolution: {integrity: sha512-UeefNadqP6IyfwWC1Yi7ux+ljbP2R66PLfDrDm8izmvlPmYlqRerJWJvYO4t0Vvr9wrG4Ko7E0c4M7FaPKT/sQ==} - - '@walletconnect/universal-provider@2.21.0': - resolution: {integrity: sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==} - - '@walletconnect/universal-provider@2.21.1': - resolution: {integrity: sha512-Wjx9G8gUHVMnYfxtasC9poGm8QMiPCpXpbbLFT+iPoQskDDly8BwueWnqKs4Mx2SdIAWAwuXeZ5ojk5qQOxJJg==} - - '@walletconnect/utils@2.21.0': - resolution: {integrity: sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==} - - '@walletconnect/utils@2.21.1': - resolution: {integrity: sha512-VPZvTcrNQCkbGOjFRbC24mm/pzbRMUq2DSQoiHlhh0X1U7ZhuIrzVtAoKsrzu6rqjz0EEtGxCr3K1TGRqDG4NA==} - - '@walletconnect/window-getters@1.0.1': - resolution: {integrity: sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==} - - '@walletconnect/window-metadata@1.0.1': - resolution: {integrity: sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==} - - '@xmldom/xmldom@0.8.10': - resolution: {integrity: sha512-2WALfTl4xo2SkGCYRt6rDTFfk9R1czmBvUQy12gK2KuRKIpWEhcbbzy8EZXtz/jkRqHX8bFEc6FC1HjX4TUWYw==} - engines: {node: '>=10.0.0'} - - abbrev@1.1.1: - resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} - - abitype@1.0.6: - resolution: {integrity: sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3 >=3.22.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - - abitype@1.0.8: - resolution: {integrity: sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3 >=3.22.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} - - agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - - agentkeepalive@4.6.0: - resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} - engines: {node: '>= 8.0.0'} - - aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} - - ajv-keywords@3.5.2: - resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} - peerDependencies: - ajv: ^6.9.1 - - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.1.0: - resolution: {integrity: sha512-7HSX4QQb4CspciLpVFwyRe79O3xsIZDDLER21kERQ71oaPodF8jL725AgJMFAYbooIqolJoRLuM81SpeUkpkvA==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - app-builder-bin@5.0.0-alpha.12: - resolution: {integrity: sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==} - - app-builder-lib@26.0.12: - resolution: {integrity: sha512-+/CEPH1fVKf6HowBUs6LcAIoRcjeqgvAeoSE+cl7Y7LndyQ9ViGPYibNk7wmhMHzNgHIuIbw4nWADPO+4mjgWw==} - engines: {node: '>=14.0.0'} - peerDependencies: - dmg-builder: 26.0.12 - electron-builder-squirrel-windows: 26.0.12 - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} - - assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} - - astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} - - async-exit-hook@2.0.1: - resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==} - engines: {node: '>=0.12.0'} - - async-mutex@0.2.6: - resolution: {integrity: sha512-Hs4R+4SPgamu6rSGW8C7cV9gaWUKEHykfzCCvIRuaVv636Ju10ZdeUbvb4TBEW0INuq2DHZqXbK4Nd3yG4RaRw==} - - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} - - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - - at-least-node@1.0.0: - resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} - engines: {node: '>= 4.0.0'} - - atomic-sleep@1.0.0: - resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} - engines: {node: '>=8.0.0'} - - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - axios@1.10.0: - resolution: {integrity: sha512-/1xYAC4MP/HEG+3duIhFr4ZQXR4sQXOIe+o6sdqzeykGLx6Upp/1p8MHqhINOvGeP7xyNHe7tsiJByc4SSVUxw==} - - axios@1.11.0: - resolution: {integrity: sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - base-x@3.0.11: - resolution: {integrity: sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==} - - base-x@5.0.1: - resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==} - - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - - big.js@6.2.2: - resolution: {integrity: sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==} - - bigint-buffer@1.1.5: - resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} - engines: {node: '>= 10.0.0'} - - bignumber.js@9.3.1: - resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} - - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} - - bn.js@5.2.2: - resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} - - body-parser@2.2.0: - resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} - engines: {node: '>=18'} - - boolean@3.2.0: - resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. - - borsh@0.7.0: - resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} - - bowser@2.11.0: - resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - - browserslist@4.25.1: - resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - bs58@4.0.1: - resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} - - bs58@6.0.0: - resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} - - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} - - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} - - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - - bufferutil@4.0.9: - resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==} - engines: {node: '>=6.14.2'} - - builder-util-runtime@9.3.1: - resolution: {integrity: sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==} - engines: {node: '>=12.0.0'} - - builder-util@26.0.11: - resolution: {integrity: sha512-xNjXfsldUEe153h1DraD0XvDOpqGR0L5eKFkdReB7eFW5HqysDZFfly4rckda6y9dF39N3pkPlOblcfHKGw+uA==} - - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} - - cacache@16.1.3: - resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - cacheable-lookup@5.0.4: - resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} - engines: {node: '>=10.6.0'} - - cacheable-request@7.0.4: - resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} - engines: {node: '>=8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} - - caniuse-lite@1.0.30001727: - resolution: {integrity: sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - chalk@5.4.1: - resolution: {integrity: sha512-zgVZuo2WcZgfUEmsn6eO3kINexW8RAE4maiQ8QNs8CtpPCSyMiYsULR3HQYkm3w8FIA3SberyMJMSldGsW+U3w==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - - charenc@0.0.2: - resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} - - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} - - chromium-pickle-js@0.2.0: - resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} - - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} - - classnames@2.5.1: - resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} - - clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} - - cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} - - cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} - - cli-truncate@2.1.0: - resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} - engines: {node: '>=8'} - - cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} - - clone-response@1.0.3: - resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} - - clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} - - clsx@1.2.1: - resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} - engines: {node: '>=6'} - - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@3.2.1: - resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} - - colorspace@1.1.4: - resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} - - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} - - commander@12.1.0: - resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} - engines: {node: '>=18'} - - commander@14.0.0: - resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} - engines: {node: '>=20'} - - commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - - commander@5.1.0: - resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} - engines: {node: '>= 6'} - - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} - - compare-version@0.1.2: - resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} - engines: {node: '>=0.10.0'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - concurrently@9.2.0: - resolution: {integrity: sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==} - engines: {node: '>=18'} - hasBin: true - - config-file-ts@0.2.8-rc1: - resolution: {integrity: sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==} - - content-disposition@1.0.0: - resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} - engines: {node: '>= 0.6'} - - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cookie-es@1.2.2: - resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} - - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} - - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} - - core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} - - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} - - crc-32@1.2.2: - resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} - engines: {node: '>=0.8'} - hasBin: true - - crc@3.8.0: - resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==} - - cross-dirname@0.1.0: - resolution: {integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==} - - cross-fetch@3.2.0: - resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} - - cross-fetch@4.1.0: - resolution: {integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - crossws@0.3.5: - resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} - - crypt@0.0.2: - resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} - - csstype@3.1.3: - resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - - date-fns@2.30.0: - resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} - engines: {node: '>=0.11'} - - dayjs@1.11.13: - resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - - debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - - decode-uri-component@0.2.2: - resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} - engines: {node: '>=0.10'} - - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - - defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} - - defer-to-connect@2.0.1: - resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} - engines: {node: '>=10'} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - - delay@5.0.0: - resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} - engines: {node: '>=10'} - - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} - - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} - - derive-valtio@0.1.0: - resolution: {integrity: sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==} - peerDependencies: - valtio: '*' - - destr@2.0.5: - resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - - detect-browser@5.3.0: - resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==} - - detect-libc@2.0.4: - resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} - engines: {node: '>=8'} - - detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - - detect-node@2.1.0: - resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} - - dijkstrajs@1.0.3: - resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} - - dir-compare@4.2.0: - resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} - - dmg-builder@26.0.12: - resolution: {integrity: sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==} - - dmg-license@1.0.11: - resolution: {integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==} - engines: {node: '>=8'} - os: [darwin] - hasBin: true - - dotenv-expand@11.0.7: - resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} - engines: {node: '>=12'} - - dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} - engines: {node: '>=12'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - duplexify@4.1.3: - resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} - - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - eciesjs@0.4.15: - resolution: {integrity: sha512-r6kEJXDKecVOCj2nLMuXK/FCPeurW33+3JRpfXVbjLja3XUYFfD9I/JBreH6sUyzcm3G/YQboBjMla6poKeSdA==} - engines: {bun: '>=1', deno: '>=2', node: '>=16'} - - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - - ejs@3.1.10: - resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} - engines: {node: '>=0.10.0'} - hasBin: true - - electron-builder-squirrel-windows@26.0.12: - resolution: {integrity: sha512-kpwXM7c/ayRUbYVErQbsZ0nQZX4aLHQrPEG9C4h9vuJCXylwFH8a7Jgi2VpKIObzCXO7LKHiCw4KdioFLFOgqA==} - - electron-builder@26.0.12: - resolution: {integrity: sha512-cD1kz5g2sgPTMFHjLxfMjUK5JABq3//J4jPswi93tOPFz6btzXYtK5NrDt717NRbukCUDOrrvmYVOWERlqoiXA==} - engines: {node: '>=14.0.0'} - hasBin: true - - electron-is-dev@3.0.1: - resolution: {integrity: sha512-8TjjAh8Ec51hUi3o4TaU0mD3GMTOESi866oRNavj9A3IQJ7pmv+MJVmdZBFGw4GFT36X7bkqnuDNYvkQgvyI8Q==} - engines: {node: '>=18'} - - electron-publish@26.0.11: - resolution: {integrity: sha512-a8QRH0rAPIWH9WyyS5LbNvW9Ark6qe63/LqDB7vu2JXYpi0Gma5Q60Dh4tmTqhOBQt0xsrzD8qE7C+D7j+B24A==} - - electron-to-chromium@1.5.189: - resolution: {integrity: sha512-y9D1ntS1ruO/pZ/V2FtLE+JXLQe28XoRpZ7QCCo0T8LdQladzdcOVQZH/IWLVJvCw12OGMb6hYOeOAjntCmJRQ==} - - electron-winstaller@5.4.0: - resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} - engines: {node: '>=8.0.0'} - - electron@37.2.3: - resolution: {integrity: sha512-JRKKn8cRDXDfkC+oWISbYs+c+L6RA776JM0NiB9bn2yV8H/LnBUlVPzKKfsXgrUIokN4YcbCw694vfAdEJwtGw==} - engines: {node: '>= 12.20.55'} - hasBin: true - - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - - enabled@2.0.0: - resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} - - encode-utf8@1.0.3: - resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} - - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} - - encoding@0.1.13: - resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} - - end-of-stream@1.4.5: - resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - - engine.io-client@6.6.3: - resolution: {integrity: sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==} - - engine.io-parser@5.2.3: - resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} - engines: {node: '>=10.0.0'} - - env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} - - err-code@2.0.3: - resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} - - es-toolkit@1.33.0: - resolution: {integrity: sha512-X13Q/ZSc+vsO1q600bvNK4bxgXMkHcf//RxCmYDaRY5DAcT+eoXjY5hoAPGMdRnWQjvyLEcyauG3b6hz76LNqg==} - - es6-error@4.1.1: - resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} - - es6-promise@4.2.8: - resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} - - es6-promisify@5.0.0: - resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} - - esbuild@0.25.8: - resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} - - eth-block-tracker@7.1.0: - resolution: {integrity: sha512-8YdplnuE1IK4xfqpf4iU7oBxnOYAc35934o083G8ao+8WM8QQtt/mVlAY6yIAdY1eMeLqg4Z//PZjJGmWGPMRg==} - engines: {node: '>=14.0.0'} - - eth-json-rpc-filters@6.0.1: - resolution: {integrity: sha512-ITJTvqoCw6OVMLs7pI8f4gG92n/St6x80ACtHodeS+IXmO0w+t1T5OOzfSt7KLSMLRkVUoexV7tztLgDxg+iig==} - engines: {node: '>=14.0.0'} - - eth-query@2.1.2: - resolution: {integrity: sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA==} - - eth-rpc-errors@4.0.3: - resolution: {integrity: sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==} - - ethereum-cryptography@2.2.1: - resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} - - eventemitter2@6.4.9: - resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} - - eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} - - eventsource-parser@3.0.3: - resolution: {integrity: sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA==} - engines: {node: '>=20.0.0'} - - eventsource@3.0.7: - resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} - engines: {node: '>=18.0.0'} - - exponential-backoff@3.1.2: - resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} - - express-rate-limit@7.5.1: - resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} - engines: {node: '>= 16'} - peerDependencies: - express: '>= 4.11' - - express@5.1.0: - resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} - engines: {node: '>= 18'} - - extension-port-stream@3.0.0: - resolution: {integrity: sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==} - engines: {node: '>=12.0.0'} - - extract-zip@2.0.1: - resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} - engines: {node: '>= 10.17.0'} - hasBin: true - - extsprintf@1.4.1: - resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==} - engines: {'0': node >=0.6.0} - - eyes@0.1.8: - resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} - engines: {node: '> 0.1.90'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-redact@3.5.0: - resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} - engines: {node: '>=6'} - - fast-safe-stringify@2.1.1: - resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - - fast-stable-stringify@1.0.0: - resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} - - fastestsmallesttextencoderdecoder@1.0.22: - resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} - - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} - - fdir@6.4.6: - resolution: {integrity: sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - fecha@4.2.3: - resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} - - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} - - filelist@1.0.4: - resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} - - filter-obj@1.1.0: - resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} - engines: {node: '>=0.10.0'} - - finalhandler@2.1.0: - resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} - engines: {node: '>= 0.8'} - - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} - - fn.name@1.1.0: - resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} - - follow-redirects@1.15.9: - resolution: {integrity: sha512-gew4GsXizNgdoRyqmyfMHyAmXsZDk6mHkSxZFCzW9gwlbtOW44CDtYavM+y+72qD/Vq2l550kMF52DT8fOLJqQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - - form-data@4.0.4: - resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} - engines: {node: '>= 6'} - - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} - - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} - - fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} - - fs-extra@11.3.0: - resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} - engines: {node: '>=14.14'} - - fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} - - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} - - fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} - - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - get-stream@5.2.0: - resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} - engines: {node: '>=8'} - - get-tsconfig@4.10.1: - resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} - - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} - hasBin: true - - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - - glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} - deprecated: Glob versions prior to v9 are no longer supported - - global-agent@3.0.0: - resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} - engines: {node: '>=10.0'} - - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - got@11.8.6: - resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} - engines: {node: '>=10.19.0'} - - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - - h3@1.15.4: - resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - hosted-git-info@4.1.0: - resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} - engines: {node: '>=10'} - - http-cache-semantics@4.2.0: - resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} - - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} - - http-proxy-agent@5.0.0: - resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} - engines: {node: '>= 6'} - - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - - http2-wrapper@1.0.3: - resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} - engines: {node: '>=10.19.0'} - - https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - humanize-ms@1.2.1: - resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} - - iconv-corefoundation@1.1.7: - resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==} - engines: {node: ^8.11.2 || >=10} - os: [darwin] - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - idb-keyval@6.2.1: - resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==} - - idb-keyval@6.2.2: - resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==} - - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - infer-owner@1.0.4: - resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} - - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - - ip-address@9.0.5: - resolution: {integrity: sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==} - engines: {node: '>= 12'} - - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} - - iron-webcrypto@1.2.1: - resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} - - is-arguments@1.2.0: - resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} - engines: {node: '>= 0.4'} - - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} - - is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - is-ci@3.0.1: - resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} - hasBin: true - - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} - - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} - engines: {node: '>= 0.4'} - - is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} - - is-lambda@1.0.1: - resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} - - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} - - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} - - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} - engines: {node: '>=10'} - - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - - isbinaryfile@4.0.10: - resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} - engines: {node: '>= 8.0.0'} - - isbinaryfile@5.0.4: - resolution: {integrity: sha512-YKBKVkKhty7s8rxddb40oOkuP0NbaeXrQvLin6QMHL7Ypiy2RW9LwOVrVgZRyOrhQlayMd9t+D8yDy8MKFTSDQ==} - engines: {node: '>= 18.0.0'} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - isomorphic-ws@4.0.1: - resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} - peerDependencies: - ws: '*' - - isows@1.0.6: - resolution: {integrity: sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==} - peerDependencies: - ws: '*' - - isows@1.0.7: - resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} - peerDependencies: - ws: '*' - - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - - jake@10.9.2: - resolution: {integrity: sha512-2P4SQ0HrLQ+fw6llpLnOaGAvN2Zu6778SJMrCUwns4fOoG9ayrTiZk3VV8sCPkVZF8ab0zksVpS8FDY5pRCNBA==} - engines: {node: '>=10'} - hasBin: true - - jayson@4.2.0: - resolution: {integrity: sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==} - engines: {node: '>=8'} - hasBin: true - - jose@6.0.12: - resolution: {integrity: sha512-T8xypXs8CpmiIi78k0E+Lk7T2zlK4zDyg+o1CZ4AkOHgDg98ogdP2BeZ61lTFKFyoEwJ9RgAgN+SdM3iPgNonQ==} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true - - jsbn@1.1.0: - resolution: {integrity: sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==} - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-rpc-engine@6.1.0: - resolution: {integrity: sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==} - engines: {node: '>=10.0.0'} - - json-rpc-random-id@1.0.1: - resolution: {integrity: sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} - - jsonfile@6.1.0: - resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} - - keccak@3.0.4: - resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} - engines: {node: '>=10.0.0'} - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - keyvaluestorage-interface@1.0.0: - resolution: {integrity: sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==} - - kuler@2.0.0: - resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} - - lazy-val@1.0.5: - resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} - - lit-element@4.2.1: - resolution: {integrity: sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==} - - lit-html@3.3.1: - resolution: {integrity: sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==} - - lit@3.3.0: - resolution: {integrity: sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==} - - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} - - logform@2.7.0: - resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} - engines: {node: '>= 12.0.0'} - - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true - - lowercase-keys@2.0.0: - resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} - engines: {node: '>=8'} - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} - - lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} - - make-fetch-happen@10.2.1: - resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - matcher@3.0.0: - resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} - engines: {node: '>=10'} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - md5@2.3.0: - resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} - - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} - - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} - - micro-ftch@0.3.1: - resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} - - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} - - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} - - mime-types@3.0.1: - resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} - engines: {node: '>= 0.6'} - - mime@2.6.0: - resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} - engines: {node: '>=4.0.0'} - hasBin: true - - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} - - mimic-response@1.0.1: - resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} - engines: {node: '>=4'} - - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - - minimatch@10.0.3: - resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} - engines: {node: 20 || >=22} - - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} - - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass-collect@1.0.2: - resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} - engines: {node: '>= 8'} - - minipass-fetch@2.1.2: - resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - minipass-flush@1.0.5: - resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} - engines: {node: '>= 8'} - - minipass-pipeline@1.2.4: - resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} - engines: {node: '>=8'} - - minipass-sized@1.0.3: - resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} - engines: {node: '>=8'} - - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} - - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} - - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} - - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} - - mipd@0.0.7: - resolution: {integrity: sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true - - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - multiformats@9.9.0: - resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} - - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - - node-abi@3.75.0: - resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==} - engines: {node: '>=10'} - - node-addon-api@1.7.2: - resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==} - - node-addon-api@2.0.2: - resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} - - node-api-version@0.2.1: - resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==} - - node-fetch-native@1.6.6: - resolution: {integrity: sha512-8Mc2HhqPdlIfedsuZoc3yioPuzp6b+L5jRCRY1QzuWZh2EGJVQrGppC6V6cF0bLdbW0+O2YpqCA25aF/1lvipQ==} - - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - - node-gyp-build@4.8.4: - resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} - hasBin: true - - node-mock-http@1.0.2: - resolution: {integrity: sha512-zWaamgDUdo9SSLw47we78+zYw/bDr5gH8pH7oRRs8V3KmBtu8GLgGIbV2p/gRPd3LWpEOpjQj7X1FOU3VFMJ8g==} - - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - - nopt@6.0.0: - resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - hasBin: true - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - normalize-url@6.1.0: - resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} - engines: {node: '>=10'} - - obj-multiplex@1.0.0: - resolution: {integrity: sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA==} - - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - ofetch@1.4.1: - resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} - - on-exit-leak-free@0.2.0: - resolution: {integrity: sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==} - - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} - - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - - one-time@1.0.0: - resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} - - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} - - ora@5.4.1: - resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} - engines: {node: '>=10'} - - ox@0.6.7: - resolution: {integrity: sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - ox@0.6.9: - resolution: {integrity: sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - ox@0.8.1: - resolution: {integrity: sha512-e+z5epnzV+Zuz91YYujecW8cF01mzmrUtWotJ0oEPym/G82uccs7q0WDHTYL3eiONbTUEvcZrptAKLgTBD3u2A==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - - p-cancelable@2.1.1: - resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} - engines: {node: '>=8'} - - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} - - p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} - - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} - - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - path-to-regexp@8.2.0: - resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} - engines: {node: '>=16'} - - pe-library@0.4.1: - resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} - engines: {node: '>=12', npm: '>=6'} - - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} - - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} - - pify@3.0.0: - resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} - engines: {node: '>=4'} - - pify@5.0.0: - resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} - engines: {node: '>=10'} - - pino-abstract-transport@0.5.0: - resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==} - - pino-std-serializers@4.0.0: - resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==} - - pino@7.11.0: - resolution: {integrity: sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==} - hasBin: true - - pkce-challenge@5.0.0: - resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} - engines: {node: '>=16.20.0'} - - plist@3.1.0: - resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} - engines: {node: '>=10.4.0'} - - pngjs@5.0.0: - resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} - engines: {node: '>=10.13.0'} - - pony-cause@2.1.11: - resolution: {integrity: sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==} - engines: {node: '>=12.0.0'} - - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - - postject@1.0.0-alpha.6: - resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} - engines: {node: '>=14.0.0'} - hasBin: true - - preact@10.24.2: - resolution: {integrity: sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==} - - preact@10.27.0: - resolution: {integrity: sha512-/DTYoB6mwwgPytiqQTh/7SFRL98ZdiD8Sk8zIUVOxtwq4oWcwrcd1uno9fE/zZmUaUrFNYzbH14CPebOz9tZQw==} - - proc-log@2.0.1: - resolution: {integrity: sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - - process-warning@1.0.0: - resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} - - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - - promise-inflight@1.0.1: - resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} - peerDependencies: - bluebird: '*' - peerDependenciesMeta: - bluebird: - optional: true - - promise-retry@2.0.1: - resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} - engines: {node: '>=10'} - - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} - - proxy-compare@2.6.0: - resolution: {integrity: sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==} - - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - - pump@3.0.3: - resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - qrcode@1.5.3: - resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} - engines: {node: '>=10.13.0'} - hasBin: true - - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} - engines: {node: '>=0.6'} - - query-string@7.1.3: - resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} - engines: {node: '>=6'} - - quick-format-unescaped@4.0.4: - resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} - - quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} - engines: {node: '>=10'} - - radix-ui@1.4.2: - resolution: {integrity: sha512-fT/3YFPJzf2WUpqDoQi005GS8EpCi+53VhcLaHUj5fwkPYiZAjk1mSxFvbMA8Uq71L03n+WysuYC+mlKkXxt/Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - radix3@1.1.2: - resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} - - raw-body@3.0.0: - resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} - engines: {node: '>= 0.8'} - - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} - peerDependencies: - react: ^18.3.1 - - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} - - react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true - - react-remove-scroll@2.7.1: - resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} - engines: {node: '>=0.10.0'} - - read-binary-file-arch@1.0.6: - resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} - hasBin: true - - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} - - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - - real-require@0.1.0: - resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==} - engines: {node: '>= 12.13.0'} - - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - - require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - - resedit@1.7.2: - resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==} - engines: {node: '>=12', npm: '>=6'} - - resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - - responselike@2.0.1: - resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} - - restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} - - retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} - - rimraf@2.6.3: - resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - roarr@2.15.4: - resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} - engines: {node: '>=8.0'} - - rollup@4.45.1: - resolution: {integrity: sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} - - rpc-websockets@9.1.3: - resolution: {integrity: sha512-I+kNjW0udB4Fetr3vvtRuYZJS0PcSPyyvBcH5sDdoV8DFs5E4W2pTr7aiMlKfPxANTClP9RlqCPolj9dd5MsEA==} - - rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - - safe-stable-stringify@2.5.0: - resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} - engines: {node: '>=10'} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - sanitize-filename@1.6.3: - resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} - - sax@1.4.1: - resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} - - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} - - semver-compare@1.0.0: - resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} - - semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} - engines: {node: '>=10'} - hasBin: true - - send@1.2.0: - resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} - engines: {node: '>= 18'} - - serialize-error@7.0.1: - resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} - engines: {node: '>=10'} - - serve-static@2.2.0: - resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} - engines: {node: '>= 18'} - - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - - sha.js@2.4.12: - resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} - engines: {node: '>= 0.10'} - hasBin: true - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} - engines: {node: '>= 0.4'} - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} - - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} - - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} - - simple-update-notifier@2.0.0: - resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} - engines: {node: '>=10'} - - slice-ansi@3.0.0: - resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} - engines: {node: '>=8'} - - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} - - socket.io-client@4.8.1: - resolution: {integrity: sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==} - engines: {node: '>=10.0.0'} - - socket.io-parser@4.2.4: - resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} - engines: {node: '>=10.0.0'} - - socks-proxy-agent@7.0.0: - resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} - engines: {node: '>= 10'} - - socks@2.8.6: - resolution: {integrity: sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} - - sonic-boom@2.8.0: - resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==} - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - split-on-first@1.1.0: - resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} - engines: {node: '>=6'} - - split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} - - sprintf-js@1.1.3: - resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} - - ssri@9.0.1: - resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - stack-trace@0.0.10: - resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} - - stat-mode@1.0.0: - resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} - engines: {node: '>= 6'} - - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} - - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} - - stream-chain@2.2.5: - resolution: {integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==} - - stream-json@1.9.1: - resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==} - - stream-shift@1.0.3: - resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} - - strict-uri-encode@2.0.0: - resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} - engines: {node: '>=4'} - - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} - - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} - - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} - - sumchecker@3.0.1: - resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} - engines: {node: '>= 8.0'} - - superstruct@1.0.4: - resolution: {integrity: sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==} - engines: {node: '>=14.0.0'} - - superstruct@2.0.2: - resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} - engines: {node: '>=14.0.0'} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} - engines: {node: '>=10'} - - temp-file@3.4.0: - resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} - - temp@0.9.4: - resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} - engines: {node: '>=6.0.0'} - - text-encoding-utf-8@1.0.2: - resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} - - text-hex@1.0.0: - resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} - - thread-stream@0.15.2: - resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==} - - tiny-async-pool@1.3.0: - resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==} - - tinyglobby@0.2.14: - resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} - engines: {node: '>=12.0.0'} - - tmp-promise@3.0.3: - resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} - - tmp@0.2.3: - resolution: {integrity: sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==} - engines: {node: '>=14.14'} - - to-buffer@1.2.1: - resolution: {integrity: sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==} - engines: {node: '>= 0.4'} - - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} - - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - - triple-beam@1.4.1: - resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} - engines: {node: '>= 14.0.0'} - - truncate-utf8-bytes@1.0.2: - resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} - - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tsx@4.20.3: - resolution: {integrity: sha512-qjbnuR9Tr+FJOMBqJCW5ehvIo/buZq7vH7qD7JziU98h6l3qGy0a/yPFjwO+y0/T7GFpNgNAvEcPPVfyT8rrPQ==} - engines: {node: '>=18.0.0'} - hasBin: true - - turbo-darwin-64@2.5.5: - resolution: {integrity: sha512-RYnTz49u4F5tDD2SUwwtlynABNBAfbyT2uU/brJcyh5k6lDLyNfYKdKmqd3K2ls4AaiALWrFKVSBsiVwhdFNzQ==} - cpu: [x64] - os: [darwin] - - turbo-darwin-arm64@2.5.5: - resolution: {integrity: sha512-Tk+ZeSNdBobZiMw9aFypQt0DlLsWSFWu1ymqsAdJLuPoAH05qCfYtRxE1pJuYHcJB5pqI+/HOxtJoQ40726Btw==} - cpu: [arm64] - os: [darwin] - - turbo-linux-64@2.5.5: - resolution: {integrity: sha512-2/XvMGykD7VgsvWesZZYIIVXMlgBcQy+ZAryjugoTcvJv8TZzSU/B1nShcA7IAjZ0q7OsZ45uP2cOb8EgKT30w==} - cpu: [x64] - os: [linux] - - turbo-linux-arm64@2.5.5: - resolution: {integrity: sha512-DW+8CjCjybu0d7TFm9dovTTVg1VRnlkZ1rceO4zqsaLrit3DgHnN4to4uwyuf9s2V/BwS3IYcRy+HG9BL596Iw==} - cpu: [arm64] - os: [linux] - - turbo-windows-64@2.5.5: - resolution: {integrity: sha512-q5p1BOy8ChtSZfULuF1BhFMYIx6bevXu4fJ+TE/hyNfyHJIfjl90Z6jWdqAlyaFLmn99X/uw+7d6T/Y/dr5JwQ==} - cpu: [x64] - os: [win32] - - turbo-windows-arm64@2.5.5: - resolution: {integrity: sha512-AXbF1KmpHUq3PKQwddMGoKMYhHsy5t1YBQO8HZ04HLMR0rWv9adYlQ8kaeQJTko1Ay1anOBFTqaxfVOOsu7+1Q==} - cpu: [arm64] - os: [win32] - - turbo@2.5.5: - resolution: {integrity: sha512-eZ7wI6KjtT1eBqCnh2JPXWNUAxtoxxfi6VdBdZFvil0ychCOTxbm7YLRBi1JSt7U3c+u3CLxpoPxLdvr/Npr3A==} - hasBin: true - - type-fest@0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} - - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} - - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} - engines: {node: '>= 0.4'} - - typescript@5.8.3: - resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} - engines: {node: '>=14.17'} - hasBin: true - - ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} - - uint8arrays@3.1.0: - resolution: {integrity: sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==} - - uncrypto@0.1.3: - resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - - undici-types@7.8.0: - resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} - - unique-filename@2.0.1: - resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - unique-slug@3.0.0: - resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} - - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} - - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} - - unstorage@1.16.1: - resolution: {integrity: sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==} - peerDependencies: - '@azure/app-configuration': ^1.8.0 - '@azure/cosmos': ^4.2.0 - '@azure/data-tables': ^13.3.0 - '@azure/identity': ^4.6.0 - '@azure/keyvault-secrets': ^4.9.0 - '@azure/storage-blob': ^12.26.0 - '@capacitor/preferences': ^6.0.3 || ^7.0.0 - '@deno/kv': '>=0.9.0' - '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 - '@planetscale/database': ^1.19.0 - '@upstash/redis': ^1.34.3 - '@vercel/blob': '>=0.27.1' - '@vercel/kv': ^1.0.1 - aws4fetch: ^1.0.20 - db0: '>=0.2.1' - idb-keyval: ^6.2.1 - ioredis: ^5.4.2 - uploadthing: ^7.4.4 - peerDependenciesMeta: - '@azure/app-configuration': - optional: true - '@azure/cosmos': - optional: true - '@azure/data-tables': - optional: true - '@azure/identity': - optional: true - '@azure/keyvault-secrets': - optional: true - '@azure/storage-blob': - optional: true - '@capacitor/preferences': - optional: true - '@deno/kv': - optional: true - '@netlify/blobs': - optional: true - '@planetscale/database': - optional: true - '@upstash/redis': - optional: true - '@vercel/blob': - optional: true - '@vercel/kv': - optional: true - aws4fetch: - optional: true - db0: - optional: true - idb-keyval: - optional: true - ioredis: - optional: true - uploadthing: - optional: true - - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - use-callback-ref@1.3.3: - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - use-sidecar@1.1.3: - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - use-sync-external-store@1.2.0: - resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 - - use-sync-external-store@1.4.0: - resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - use-sync-external-store@1.5.0: - resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - - utf-8-validate@5.0.10: - resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} - engines: {node: '>=6.14.2'} - - utf8-byte-length@1.0.5: - resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - util@0.12.5: - resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true - - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true - - valtio@1.13.2: - resolution: {integrity: sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=16.8' - react: '>=16.8' - peerDependenciesMeta: - '@types/react': - optional: true - react: - optional: true - - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} - - verror@1.10.1: - resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==} - engines: {node: '>=0.6.0'} - - viem@2.23.2: - resolution: {integrity: sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - - viem@2.33.0: - resolution: {integrity: sha512-SxBM3CmeU+LWLlBclV9MPdbuFV8mQEl0NeRc9iyYU4a7Xb5sr5oku3s/bRGTPpEP+1hCAHYpM09/ui3/dQ6EsA==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - - vite@7.0.5: - resolution: {integrity: sha512-1mncVwJxy2C9ThLwz0+2GKZyEXuC3MyWtAAlNftlZZXZDP3AJt5FmwcMit/IGGaNZ8ZOB2BNO/HFUB+CpN0NQw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - wagmi@2.16.1: - resolution: {integrity: sha512-iUdaoe/xd5NiNRW72QVctZs+962EORJKAvJTCsmf9n6TnEApPlENuvVRJKgobI4cGUgi5scWAstpLprB+RRo9Q==} - peerDependencies: - '@tanstack/react-query': '>=5.0.0' - react: '>=18' - typescript: '>=5.0.4' - viem: 2.x - peerDependenciesMeta: - typescript: - optional: true - - wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} - - webextension-polyfill@0.10.0: - resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - - which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} - engines: {node: '>= 0.4'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - winston-transport@4.9.0: - resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} - engines: {node: '>= 12.0.0'} - - winston@3.17.0: - resolution: {integrity: sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==} - engines: {node: '>= 12.0.0'} - - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} - - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} - - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} - - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - - ws@7.5.10: - resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} - engines: {node: '>=8.3.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - ws@8.17.1: - resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - ws@8.18.2: - resolution: {integrity: sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - - x402-axios@0.4.2: - resolution: {integrity: sha512-6aaVrSq/w43xtOz7KCI5SRcd+8EEj6q3ZEALJbcjlM6oAi30wTiZOCrH6UEMpLYSyEGMt1Jl25AL3tuwJXTumA==} - - x402@0.4.3: - resolution: {integrity: sha512-GbIgX2EZYAOZX1ZrEYIVXtjDKLtNuwp7lUlM3dCJAF5TqELP+bDrLy3UsypzNcJoHPVvNa+jB4BPZ83/W2nZDA==} - - xmlbuilder@15.1.1: - resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} - engines: {node: '>=8.0'} - - xmlhttprequest-ssl@2.1.2: - resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} - engines: {node: '>=0.4.0'} - - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - - y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} - - yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} - - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - - yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} - engines: {node: '>=8'} - - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} - - yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zod-to-json-schema@3.24.6: - resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} - peerDependencies: - zod: ^3.24.1 - - zod@3.22.4: - resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - - zustand@5.0.0: - resolution: {integrity: sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - - zustand@5.0.3: - resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - - zustand@5.0.6: - resolution: {integrity: sha512-ihAqNeUVhe0MAD+X8M5UzqyZ9k3FFZLBTtqo6JLPwV53cbRB/mJwBI0PxcIgqhBBHlEs8G45OTDTMq3gNcLq3A==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - -snapshots: - - 7zip-bin@5.2.0: {} - - '@adraffy/ens-normalize@1.11.0': {} - - '@ampproject/remapping@2.3.0': - dependencies: - '@jridgewell/gen-mapping': 0.3.12 - '@jridgewell/trace-mapping': 0.3.29 - - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.27.1 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.28.0': {} - - '@babel/core@7.28.0': - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.0 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0) - '@babel/helpers': 7.27.6 - '@babel/parser': 7.28.0 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.0 - '@babel/types': 7.28.1 - convert-source-map: 2.0.0 - debug: 4.4.1 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.28.0': - dependencies: - '@babel/parser': 7.28.0 - '@babel/types': 7.28.1 - '@jridgewell/gen-mapping': 0.3.12 - '@jridgewell/trace-mapping': 0.3.29 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.27.2': - dependencies: - '@babel/compat-data': 7.28.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.25.1 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.27.1': - dependencies: - '@babel/traverse': 7.28.0 - '@babel/types': 7.28.1 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.27.3(@babel/core@7.28.0)': - dependencies: - '@babel/core': 7.28.0 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-plugin-utils@7.27.1': {} - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.27.1': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.27.6': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.1 - - '@babel/parser@7.28.0': - dependencies: - '@babel/types': 7.28.1 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.0)': - dependencies: - '@babel/core': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.0)': - dependencies: - '@babel/core': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/runtime@7.28.2': {} - - '@babel/template@7.27.2': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.0 - '@babel/types': 7.28.1 - - '@babel/traverse@7.28.0': - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.0 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.0 - '@babel/template': 7.27.2 - '@babel/types': 7.28.1 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.28.1': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - - '@base-org/account@1.1.1(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.8.3)(zod@3.25.76) - preact: 10.24.2 - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.3(@types/react@19.1.8)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - - '@coinbase/cdp-api-client@0.0.18': - dependencies: - axios: 1.11.0 - transitivePeerDependencies: - - debug - - '@coinbase/cdp-core@0.0.18(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@coinbase/cdp-api-client': 0.0.18 - jose: 6.0.12 - ox: 0.8.1(typescript@5.8.3)(zod@3.25.76) - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.6(@types/react@19.1.8)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - debug - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - - '@coinbase/cdp-hooks@0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(react@18.3.1)': - dependencies: - '@coinbase/cdp-core': 0.0.18(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) - react: 18.3.1 - - '@coinbase/cdp-react@0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(@coinbase/cdp-hooks@0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(react@18.3.1))(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@coinbase/cdp-core': 0.0.18(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@coinbase/cdp-hooks': 0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(react@18.3.1) - '@radix-ui/react-dialog': 1.1.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-form': 0.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-one-time-password-field': 0.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - - react-dom - - '@coinbase/cdp-sdk@1.30.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10)': - dependencies: - '@solana/spl-token': 0.4.13(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - abitype: 1.0.6(typescript@5.8.3)(zod@3.25.76) - axios: 1.11.0 - jose: 6.0.12 - md5: 2.3.0 - uncrypto: 0.1.3 - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - zod: 3.25.76 - transitivePeerDependencies: - - bufferutil - - debug - - encoding - - fastestsmallesttextencoderdecoder - - typescript - - utf-8-validate - - '@coinbase/wallet-sdk@3.9.3': - dependencies: - bn.js: 5.2.2 - buffer: 6.0.3 - clsx: 1.2.1 - eth-block-tracker: 7.1.0 - eth-json-rpc-filters: 6.0.1 - eventemitter3: 5.0.1 - keccak: 3.0.4 - preact: 10.27.0 - sha.js: 2.4.12 - transitivePeerDependencies: - - supports-color - - '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.8.3)(zod@3.25.76) - preact: 10.24.2 - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.3(@types/react@19.1.8)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - - '@coinbase/x402@0.4.3(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.0(react@18.3.1))(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)': - dependencies: - '@coinbase/cdp-sdk': 1.30.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10) - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - x402: 0.4.3(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.0(react@18.3.1))(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10) - zod: 3.25.76 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - supports-color - - typescript - - uploadthing - - utf-8-validate - - '@colors/colors@1.6.0': {} - - '@dabh/diagnostics@2.0.3': - dependencies: - colorspace: 1.1.4 - enabled: 2.0.0 - kuler: 2.0.0 - - '@develar/schema-utils@2.6.5': - dependencies: - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) - - '@ecies/ciphers@0.2.4(@noble/ciphers@1.3.0)': - dependencies: - '@noble/ciphers': 1.3.0 - - '@electron/asar@3.2.18': - dependencies: - commander: 5.1.0 - glob: 7.2.3 - minimatch: 3.1.2 - - '@electron/asar@3.4.1': - dependencies: - commander: 5.1.0 - glob: 7.2.3 - minimatch: 3.1.2 - - '@electron/fuses@1.8.0': - dependencies: - chalk: 4.1.2 - fs-extra: 9.1.0 - minimist: 1.2.8 - - '@electron/get@2.0.3': - dependencies: - debug: 4.4.1 - env-paths: 2.2.1 - fs-extra: 8.1.0 - got: 11.8.6 - progress: 2.0.3 - semver: 6.3.1 - sumchecker: 3.0.1 - optionalDependencies: - global-agent: 3.0.0 - transitivePeerDependencies: - - supports-color - - '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': - dependencies: - env-paths: 2.2.1 - exponential-backoff: 3.1.2 - glob: 8.1.0 - graceful-fs: 4.2.11 - make-fetch-happen: 10.2.1 - nopt: 6.0.0 - proc-log: 2.0.1 - semver: 7.7.2 - tar: 6.2.1 - which: 2.0.2 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron/notarize@2.5.0': - dependencies: - debug: 4.4.1 - fs-extra: 9.1.0 - promise-retry: 2.0.1 - transitivePeerDependencies: - - supports-color - - '@electron/osx-sign@1.3.1': - dependencies: - compare-version: 0.1.2 - debug: 4.4.1 - fs-extra: 10.1.0 - isbinaryfile: 4.0.10 - minimist: 1.2.8 - plist: 3.1.0 - transitivePeerDependencies: - - supports-color - - '@electron/rebuild@3.7.0': - dependencies: - '@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2 - '@malept/cross-spawn-promise': 2.0.0 - chalk: 4.1.2 - debug: 4.4.1 - detect-libc: 2.0.4 - fs-extra: 10.1.0 - got: 11.8.6 - node-abi: 3.75.0 - node-api-version: 0.2.1 - ora: 5.4.1 - read-binary-file-arch: 1.0.6 - semver: 7.7.2 - tar: 6.2.1 - yargs: 17.7.2 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron/universal@2.0.1': - dependencies: - '@electron/asar': 3.2.18 - '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.1 - dir-compare: 4.2.0 - fs-extra: 11.3.0 - minimatch: 9.0.5 - plist: 3.1.0 - transitivePeerDependencies: - - supports-color - - '@electron/windows-sign@1.2.2': - dependencies: - cross-dirname: 0.1.0 - debug: 4.4.1 - fs-extra: 11.3.0 - minimist: 1.2.8 - postject: 1.0.0-alpha.6 - transitivePeerDependencies: - - supports-color - optional: true - - '@esbuild/aix-ppc64@0.25.8': - optional: true - - '@esbuild/android-arm64@0.25.8': - optional: true - - '@esbuild/android-arm@0.25.8': - optional: true - - '@esbuild/android-x64@0.25.8': - optional: true - - '@esbuild/darwin-arm64@0.25.8': - optional: true - - '@esbuild/darwin-x64@0.25.8': - optional: true - - '@esbuild/freebsd-arm64@0.25.8': - optional: true - - '@esbuild/freebsd-x64@0.25.8': - optional: true - - '@esbuild/linux-arm64@0.25.8': - optional: true - - '@esbuild/linux-arm@0.25.8': - optional: true - - '@esbuild/linux-ia32@0.25.8': - optional: true - - '@esbuild/linux-loong64@0.25.8': - optional: true - - '@esbuild/linux-mips64el@0.25.8': - optional: true - - '@esbuild/linux-ppc64@0.25.8': - optional: true - - '@esbuild/linux-riscv64@0.25.8': - optional: true - - '@esbuild/linux-s390x@0.25.8': - optional: true - - '@esbuild/linux-x64@0.25.8': - optional: true - - '@esbuild/netbsd-arm64@0.25.8': - optional: true - - '@esbuild/netbsd-x64@0.25.8': - optional: true - - '@esbuild/openbsd-arm64@0.25.8': - optional: true - - '@esbuild/openbsd-x64@0.25.8': - optional: true - - '@esbuild/openharmony-arm64@0.25.8': - optional: true - - '@esbuild/sunos-x64@0.25.8': - optional: true - - '@esbuild/win32-arm64@0.25.8': - optional: true - - '@esbuild/win32-ia32@0.25.8': - optional: true - - '@esbuild/win32-x64@0.25.8': - optional: true - - '@ethereumjs/common@3.2.0': - dependencies: - '@ethereumjs/util': 8.1.0 - crc-32: 1.2.2 - - '@ethereumjs/rlp@4.0.1': {} - - '@ethereumjs/tx@4.2.0': - dependencies: - '@ethereumjs/common': 3.2.0 - '@ethereumjs/rlp': 4.0.1 - '@ethereumjs/util': 8.1.0 - ethereum-cryptography: 2.2.1 - - '@ethereumjs/util@8.1.0': - dependencies: - '@ethereumjs/rlp': 4.0.1 - ethereum-cryptography: 2.2.1 - micro-ftch: 0.3.1 - - '@floating-ui/core@1.7.2': - dependencies: - '@floating-ui/utils': 0.2.10 - - '@floating-ui/dom@1.7.2': - dependencies: - '@floating-ui/core': 1.7.2 - '@floating-ui/utils': 0.2.10 - - '@floating-ui/react-dom@2.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/dom': 1.7.2 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - - '@floating-ui/utils@0.2.10': {} - - '@gar/promisify@1.1.3': {} - - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 - - '@isaacs/cliui@8.0.2': - dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.0 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 - - '@jridgewell/gen-mapping@0.3.12': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.4 - '@jridgewell/trace-mapping': 0.3.29 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.4': {} - - '@jridgewell/trace-mapping@0.3.29': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.4 - - '@lit-labs/ssr-dom-shim@1.4.0': {} - - '@lit/reactive-element@2.1.1': - dependencies: - '@lit-labs/ssr-dom-shim': 1.4.0 - - '@malept/cross-spawn-promise@2.0.0': - dependencies: - cross-spawn: 7.0.6 - - '@malept/flatpak-bundler@0.4.0': - dependencies: - debug: 4.4.1 - fs-extra: 9.1.0 - lodash: 4.17.21 - tmp-promise: 3.0.3 - transitivePeerDependencies: - - supports-color - - '@metamask/eth-json-rpc-provider@1.0.1': - dependencies: - '@metamask/json-rpc-engine': 7.3.3 - '@metamask/safe-event-emitter': 3.1.2 - '@metamask/utils': 5.0.2 - transitivePeerDependencies: - - supports-color - - '@metamask/json-rpc-engine@7.3.3': - dependencies: - '@metamask/rpc-errors': 6.4.0 - '@metamask/safe-event-emitter': 3.1.2 - '@metamask/utils': 8.5.0 - transitivePeerDependencies: - - supports-color - - '@metamask/json-rpc-engine@8.0.2': - dependencies: - '@metamask/rpc-errors': 6.4.0 - '@metamask/safe-event-emitter': 3.1.2 - '@metamask/utils': 8.5.0 - transitivePeerDependencies: - - supports-color - - '@metamask/json-rpc-middleware-stream@7.0.2': - dependencies: - '@metamask/json-rpc-engine': 8.0.2 - '@metamask/safe-event-emitter': 3.1.2 - '@metamask/utils': 8.5.0 - readable-stream: 3.6.2 - transitivePeerDependencies: - - supports-color - - '@metamask/object-multiplex@2.1.0': - dependencies: - once: 1.4.0 - readable-stream: 3.6.2 - - '@metamask/onboarding@1.0.1': - dependencies: - bowser: 2.11.0 - - '@metamask/providers@16.1.0': - dependencies: - '@metamask/json-rpc-engine': 8.0.2 - '@metamask/json-rpc-middleware-stream': 7.0.2 - '@metamask/object-multiplex': 2.1.0 - '@metamask/rpc-errors': 6.4.0 - '@metamask/safe-event-emitter': 3.1.2 - '@metamask/utils': 8.5.0 - detect-browser: 5.3.0 - extension-port-stream: 3.0.0 - fast-deep-equal: 3.1.3 - is-stream: 2.0.1 - readable-stream: 3.6.2 - webextension-polyfill: 0.10.0 - transitivePeerDependencies: - - supports-color - - '@metamask/rpc-errors@6.4.0': - dependencies: - '@metamask/utils': 9.3.0 - fast-safe-stringify: 2.1.1 - transitivePeerDependencies: - - supports-color - - '@metamask/safe-event-emitter@2.0.0': {} - - '@metamask/safe-event-emitter@3.1.2': {} - - '@metamask/sdk-communication-layer@0.32.0(cross-fetch@4.1.0(encoding@0.1.13))(eciesjs@0.4.15)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - bufferutil: 4.0.9 - cross-fetch: 4.1.0(encoding@0.1.13) - date-fns: 2.30.0 - debug: 4.4.1 - eciesjs: 0.4.15 - eventemitter2: 6.4.9 - readable-stream: 3.6.2 - socket.io-client: 4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - utf-8-validate: 5.0.10 - uuid: 8.3.2 - transitivePeerDependencies: - - supports-color - - '@metamask/sdk-install-modal-web@0.32.0': - dependencies: - '@paulmillr/qr': 0.2.1 - - '@metamask/sdk@0.32.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)': - dependencies: - '@babel/runtime': 7.28.2 - '@metamask/onboarding': 1.0.1 - '@metamask/providers': 16.1.0 - '@metamask/sdk-communication-layer': 0.32.0(cross-fetch@4.1.0(encoding@0.1.13))(eciesjs@0.4.15)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@metamask/sdk-install-modal-web': 0.32.0 - '@paulmillr/qr': 0.2.1 - bowser: 2.11.0 - cross-fetch: 4.1.0(encoding@0.1.13) - debug: 4.4.1 - eciesjs: 0.4.15 - eth-rpc-errors: 4.0.3 - eventemitter2: 6.4.9 - obj-multiplex: 1.0.0 - pump: 3.0.3 - readable-stream: 3.6.2 - socket.io-client: 4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - tslib: 2.8.1 - util: 0.12.5 - uuid: 8.3.2 - transitivePeerDependencies: - - bufferutil - - encoding - - supports-color - - utf-8-validate - - '@metamask/superstruct@3.2.1': {} - - '@metamask/utils@5.0.2': - dependencies: - '@ethereumjs/tx': 4.2.0 - '@types/debug': 4.1.12 - debug: 4.4.1 - semver: 7.7.2 - superstruct: 1.0.4 - transitivePeerDependencies: - - supports-color - - '@metamask/utils@8.5.0': - dependencies: - '@ethereumjs/tx': 4.2.0 - '@metamask/superstruct': 3.2.1 - '@noble/hashes': 1.8.0 - '@scure/base': 1.2.6 - '@types/debug': 4.1.12 - debug: 4.4.1 - pony-cause: 2.1.11 - semver: 7.7.2 - uuid: 9.0.1 - transitivePeerDependencies: - - supports-color - - '@metamask/utils@9.3.0': - dependencies: - '@ethereumjs/tx': 4.2.0 - '@metamask/superstruct': 3.2.1 - '@noble/hashes': 1.8.0 - '@scure/base': 1.2.6 - '@types/debug': 4.1.12 - debug: 4.4.1 - pony-cause: 2.1.11 - semver: 7.7.2 - uuid: 9.0.1 - transitivePeerDependencies: - - supports-color - - '@modelcontextprotocol/sdk@1.16.0': - dependencies: - ajv: 6.12.6 - content-type: 1.0.5 - cors: 2.8.5 - cross-spawn: 7.0.6 - eventsource: 3.0.7 - eventsource-parser: 3.0.3 - express: 5.1.0 - express-rate-limit: 7.5.1(express@5.1.0) - pkce-challenge: 5.0.0 - raw-body: 3.0.0 - zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) - transitivePeerDependencies: - - supports-color - - '@noble/ciphers@1.2.1': {} - - '@noble/ciphers@1.3.0': {} - - '@noble/curves@1.4.2': - dependencies: - '@noble/hashes': 1.4.0 - - '@noble/curves@1.8.0': - dependencies: - '@noble/hashes': 1.7.0 - - '@noble/curves@1.8.1': - dependencies: - '@noble/hashes': 1.7.1 - - '@noble/curves@1.9.2': - dependencies: - '@noble/hashes': 1.8.0 - - '@noble/curves@1.9.4': - dependencies: - '@noble/hashes': 1.8.0 - - '@noble/hashes@1.4.0': {} - - '@noble/hashes@1.7.0': {} - - '@noble/hashes@1.7.1': {} - - '@noble/hashes@1.8.0': {} - - '@npmcli/fs@2.1.2': - dependencies: - '@gar/promisify': 1.1.3 - semver: 7.7.2 - - '@npmcli/move-file@2.0.1': - dependencies: - mkdirp: 1.0.4 - rimraf: 3.0.2 - - '@paulmillr/qr@0.2.1': {} - - '@pkgjs/parseargs@0.11.0': - optional: true - - '@radix-ui/colors@3.0.0': {} - - '@radix-ui/number@1.1.1': {} - - '@radix-ui/primitive@1.1.2': {} - - '@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-accordion@1.2.11(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collapsible': 1.1.11(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-alert-dialog@1.1.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-dialog': 1.1.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-checkbox@1.3.2(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-collapsible@1.1.11(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.1.8)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-context-menu@2.2.15(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-context@1.1.2(@types/react@19.1.8)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-dialog@1.1.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@19.1.8)(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-direction@1.1.1(@types/react@19.1.8)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-dismissable-layer@1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-dropdown-menu@2.1.15(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-focus-guards@1.1.2(@types/react@19.1.8)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-form@0.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-label': 2.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-hover-card@1.1.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-icons@1.3.2(react@18.3.1)': - dependencies: - react: 18.3.1 - - '@radix-ui/react-id@1.1.1(@types/react@19.1.8)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-label@2.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-menu@2.1.15(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@19.1.8)(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-menubar@1.1.15(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-navigation-menu@1.2.13(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-one-time-password-field@0.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-password-toggle-field@0.1.2(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-popover@1.1.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@19.1.8)(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-popper@1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/react-dom': 2.1.4(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/rect': 1.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-presence@1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-progress@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-radio-group@1.3.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-roving-focus@1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-scroll-area@1.2.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-select@2.2.5(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@19.1.8)(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-separator@1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-slider@1.3.5(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-slot@1.2.3(@types/react@19.1.8)(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-switch@1.2.5(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-tabs@1.1.12(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-toast@1.2.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-toggle-group@1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-toggle@1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-toolbar@1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle-group': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-tooltip@1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.1.8)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.1.8)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.1.8)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.1.8)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.1.8)(react@18.3.1)': - dependencies: - react: 18.3.1 - use-sync-external-store: 1.5.0(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.1.8)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-use-previous@1.1.1(@types/react@19.1.8)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-use-rect@1.1.1(@types/react@19.1.8)(react@18.3.1)': - dependencies: - '@radix-ui/rect': 1.1.1 - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-use-size@1.1.1(@types/react@19.1.8)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 19.1.8 - - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@radix-ui/rect@1.1.1': {} - - '@radix-ui/themes@3.2.1(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/colors': 3.0.0 - classnames: 2.5.1 - radix-ui: 1.4.2(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll-bar: 2.3.8(@types/react@19.1.8)(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.22.4)': - dependencies: - big.js: 6.2.2 - dayjs: 1.11.13 - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.22.4) - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - zod - - '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - big.js: 6.2.2 - dayjs: 1.11.13 - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - zod - - '@reown/appkit-controllers@1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - valtio: 1.13.2(@types/react@19.1.8)(react@18.3.1) - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - - '@reown/appkit-pay@1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.8)(react@18.3.1))(zod@3.25.76) - lit: 3.3.0 - valtio: 1.13.2(@types/react@19.1.8)(react@18.3.1) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - - '@reown/appkit-polyfills@1.7.8': - dependencies: - buffer: 6.0.3 - - '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.8)(react@18.3.1))(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.8)(react@18.3.1))(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - lit: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - valtio - - zod - - '@reown/appkit-ui@1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - lit: 3.3.0 - qrcode: 1.5.3 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - - '@reown/appkit-utils@1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.8)(react@18.3.1))(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - valtio: 1.13.2(@types/react@19.1.8)(react@18.3.1) - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - - '@reown/appkit-wallet@1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.22.4) - '@reown/appkit-polyfills': 1.7.8 - '@walletconnect/logger': 2.1.2 - zod: 3.22.4 - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - '@reown/appkit@1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-pay': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.8)(react@18.3.1))(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.8)(react@18.3.1))(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@walletconnect/types': 2.21.0 - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - bs58: 6.0.0 - valtio: 1.13.2(@types/react@19.1.8)(react@18.3.1) - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - - '@rolldown/pluginutils@1.0.0-beta.27': {} - - '@rollup/rollup-android-arm-eabi@4.45.1': - optional: true - - '@rollup/rollup-android-arm64@4.45.1': - optional: true - - '@rollup/rollup-darwin-arm64@4.45.1': - optional: true - - '@rollup/rollup-darwin-x64@4.45.1': - optional: true - - '@rollup/rollup-freebsd-arm64@4.45.1': - optional: true - - '@rollup/rollup-freebsd-x64@4.45.1': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.45.1': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.45.1': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.45.1': - optional: true - - '@rollup/rollup-linux-loongarch64-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-powerpc64le-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.45.1': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.45.1': - optional: true - - '@rollup/rollup-linux-x64-musl@4.45.1': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.45.1': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.45.1': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.45.1': - optional: true - - '@safe-global/safe-apps-provider@0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - events: 3.3.0 - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - zod - - '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@safe-global/safe-gateway-typescript-sdk': 3.23.1 - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - zod - - '@safe-global/safe-gateway-typescript-sdk@3.23.1': {} - - '@scure/base@1.1.9': {} - - '@scure/base@1.2.6': {} - - '@scure/bip32@1.4.0': - dependencies: - '@noble/curves': 1.4.2 - '@noble/hashes': 1.4.0 - '@scure/base': 1.1.9 - - '@scure/bip32@1.6.2': - dependencies: - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 - '@scure/base': 1.2.6 - - '@scure/bip32@1.7.0': - dependencies: - '@noble/curves': 1.9.4 - '@noble/hashes': 1.8.0 - '@scure/base': 1.2.6 - - '@scure/bip39@1.3.0': - dependencies: - '@noble/hashes': 1.4.0 - '@scure/base': 1.1.9 - - '@scure/bip39@1.5.4': - dependencies: - '@noble/hashes': 1.7.1 - '@scure/base': 1.2.6 - - '@scure/bip39@1.6.0': - dependencies: - '@noble/hashes': 1.8.0 - '@scure/base': 1.2.6 - - '@sindresorhus/is@4.6.0': {} - - '@socket.io/component-emitter@3.1.2': {} - - '@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)': - dependencies: - '@solana/buffer-layout': 4.0.1 - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - bigint-buffer: 1.1.5 - bignumber.js: 9.3.1 - transitivePeerDependencies: - - bufferutil - - encoding - - typescript - - utf-8-validate - - '@solana/buffer-layout@4.0.1': - dependencies: - buffer: 6.0.3 - - '@solana/codecs-core@2.0.0-rc.1(typescript@5.8.3)': - dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.8.3) - typescript: 5.8.3 - - '@solana/codecs-core@2.3.0(typescript@5.8.3)': - dependencies: - '@solana/errors': 2.3.0(typescript@5.8.3) - typescript: 5.8.3 - - '@solana/codecs-data-structures@2.0.0-rc.1(typescript@5.8.3)': - dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.8.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.8.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.8.3) - typescript: 5.8.3 - - '@solana/codecs-numbers@2.0.0-rc.1(typescript@5.8.3)': - dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.8.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.8.3) - typescript: 5.8.3 - - '@solana/codecs-numbers@2.3.0(typescript@5.8.3)': - dependencies: - '@solana/codecs-core': 2.3.0(typescript@5.8.3) - '@solana/errors': 2.3.0(typescript@5.8.3) - typescript: 5.8.3 - - '@solana/codecs-strings@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)': - dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.8.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.8.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.8.3) - fastestsmallesttextencoderdecoder: 1.0.22 - typescript: 5.8.3 - - '@solana/codecs@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)': - dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.8.3) - '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.8.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.8.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/options': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - '@solana/errors@2.0.0-rc.1(typescript@5.8.3)': - dependencies: - chalk: 5.4.1 - commander: 12.1.0 - typescript: 5.8.3 - - '@solana/errors@2.3.0(typescript@5.8.3)': - dependencies: - chalk: 5.4.1 - commander: 14.0.0 - typescript: 5.8.3 - - '@solana/options@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)': - dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.8.3) - '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.8.3) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.8.3) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/errors': 2.0.0-rc.1(typescript@5.8.3) - typescript: 5.8.3 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - '@solana/spl-token-group@0.0.7(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)': - dependencies: - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - typescript - - '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)': - dependencies: - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - typescript - - '@solana/spl-token@0.4.13(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3)(utf-8-validate@5.0.10)': - dependencies: - '@solana/buffer-layout': 4.0.1 - '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - '@solana/spl-token-group': 0.0.7(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.8.3) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10) - buffer: 6.0.3 - transitivePeerDependencies: - - bufferutil - - encoding - - fastestsmallesttextencoderdecoder - - typescript - - utf-8-validate - - '@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)': - dependencies: - '@babel/runtime': 7.28.2 - '@noble/curves': 1.9.4 - '@noble/hashes': 1.8.0 - '@solana/buffer-layout': 4.0.1 - '@solana/codecs-numbers': 2.3.0(typescript@5.8.3) - agentkeepalive: 4.6.0 - bn.js: 5.2.2 - borsh: 0.7.0 - bs58: 4.0.1 - buffer: 6.0.3 - fast-stable-stringify: 1.0.0 - jayson: 4.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - node-fetch: 2.7.0(encoding@0.1.13) - rpc-websockets: 9.1.3 - superstruct: 2.0.2 - transitivePeerDependencies: - - bufferutil - - encoding - - typescript - - utf-8-validate - - '@swc/helpers@0.5.17': - dependencies: - tslib: 2.8.1 - - '@szmarczak/http-timer@4.0.6': - dependencies: - defer-to-connect: 2.0.1 - - '@tanstack/query-core@5.83.1': {} - - '@tanstack/react-query@5.84.0(react@18.3.1)': - dependencies: - '@tanstack/query-core': 5.83.1 - react: 18.3.1 - - '@tootallnate/once@2.0.0': {} - - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.28.0 - '@babel/types': 7.28.1 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.20.7 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.28.1 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.28.0 - '@babel/types': 7.28.1 - - '@types/babel__traverse@7.20.7': - dependencies: - '@babel/types': 7.28.1 - - '@types/cacheable-request@6.0.3': - dependencies: - '@types/http-cache-semantics': 4.0.4 - '@types/keyv': 3.1.4 - '@types/node': 24.1.0 - '@types/responselike': 1.0.3 - - '@types/connect@3.4.38': - dependencies: - '@types/node': 24.1.0 - - '@types/debug@4.1.12': - dependencies: - '@types/ms': 2.1.0 - - '@types/estree@1.0.8': {} - - '@types/fs-extra@9.0.13': - dependencies: - '@types/node': 24.1.0 - - '@types/http-cache-semantics@4.0.4': {} - - '@types/keyv@3.1.4': - dependencies: - '@types/node': 24.1.0 - - '@types/ms@2.1.0': {} - - '@types/node@12.20.55': {} - - '@types/node@22.16.5': - dependencies: - undici-types: 6.21.0 - - '@types/node@24.1.0': - dependencies: - undici-types: 7.8.0 - - '@types/plist@3.0.5': - dependencies: - '@types/node': 24.1.0 - xmlbuilder: 15.1.1 - optional: true - - '@types/react-dom@19.1.6(@types/react@19.1.8)': - dependencies: - '@types/react': 19.1.8 - - '@types/react@19.1.8': - dependencies: - csstype: 3.1.3 - - '@types/responselike@1.0.3': - dependencies: - '@types/node': 24.1.0 - - '@types/triple-beam@1.3.5': {} - - '@types/trusted-types@2.0.7': {} - - '@types/uuid@8.3.4': {} - - '@types/verror@1.10.11': - optional: true - - '@types/ws@7.4.7': - dependencies: - '@types/node': 24.1.0 - - '@types/ws@8.18.1': - dependencies: - '@types/node': 24.1.0 - - '@types/yauzl@2.10.3': - dependencies: - '@types/node': 24.1.0 - optional: true - - '@vitejs/plugin-react@4.7.0(vite@7.0.5(@types/node@24.1.0)(tsx@4.20.3))': - dependencies: - '@babel/core': 7.28.0 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.0) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.0) - '@rolldown/pluginutils': 1.0.0-beta.27 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 7.0.5(@types/node@24.1.0)(tsx@4.20.3) - transitivePeerDependencies: - - supports-color - - '@wagmi/connectors@5.9.1(@types/react@19.1.8)(@wagmi/core@2.18.1(@tanstack/query-core@5.83.1)(@types/react@19.1.8)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(viem@2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': - dependencies: - '@base-org/account': 1.1.1(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.8)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@metamask/sdk': 0.32.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.18.1(@tanstack/query-core@5.83.1)(@types/react@19.1.8)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - immer - - ioredis - - react - - supports-color - - uploadthing - - use-sync-external-store - - utf-8-validate - - zod - - '@wagmi/core@2.18.1(@tanstack/query-core@5.83.1)(@types/react@19.1.8)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.8.3) - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.0(@types/react@19.1.8)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)) - optionalDependencies: - '@tanstack/query-core': 5.83.1 - typescript: 5.8.3 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - - '@walletconnect/core@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 - '@walletconnect/relay-api': 1.0.11 - '@walletconnect/relay-auth': 1.1.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0 - '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/window-getters': 1.0.1 - es-toolkit: 1.33.0 - events: 3.3.0 - uint8arrays: 3.1.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - - '@walletconnect/core@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 - '@walletconnect/relay-api': 1.0.11 - '@walletconnect/relay-auth': 1.1.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1 - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/window-getters': 1.0.1 - es-toolkit: 1.33.0 - events: 3.3.0 - uint8arrays: 3.1.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - - '@walletconnect/environment@1.0.1': - dependencies: - tslib: 1.14.1 - - '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit': 1.7.8(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1 - '@walletconnect/universal-provider': 2.21.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - - '@walletconnect/events@1.0.1': - dependencies: - keyvaluestorage-interface: 1.0.0 - tslib: 1.14.1 - - '@walletconnect/heartbeat@1.2.2': - dependencies: - '@walletconnect/events': 1.0.1 - '@walletconnect/time': 1.0.2 - events: 3.3.0 - - '@walletconnect/jsonrpc-http-connection@1.0.8(encoding@0.1.13)': - dependencies: - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/safe-json': 1.0.2 - cross-fetch: 3.2.0(encoding@0.1.13) - events: 3.3.0 - transitivePeerDependencies: - - encoding - - '@walletconnect/jsonrpc-provider@1.0.14': - dependencies: - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/safe-json': 1.0.2 - events: 3.3.0 - - '@walletconnect/jsonrpc-types@1.0.4': - dependencies: - events: 3.3.0 - keyvaluestorage-interface: 1.0.0 - - '@walletconnect/jsonrpc-utils@1.0.8': - dependencies: - '@walletconnect/environment': 1.0.1 - '@walletconnect/jsonrpc-types': 1.0.4 - tslib: 1.14.1 - - '@walletconnect/jsonrpc-ws-connection@1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10)': - dependencies: - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/safe-json': 1.0.2 - events: 3.3.0 - ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@walletconnect/keyvaluestorage@1.1.1': - dependencies: - '@walletconnect/safe-json': 1.0.2 - idb-keyval: 6.2.2 - unstorage: 1.16.1(idb-keyval@6.2.2) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - db0 - - ioredis - - uploadthing - - '@walletconnect/logger@2.1.2': - dependencies: - '@walletconnect/safe-json': 1.0.2 - pino: 7.11.0 - - '@walletconnect/relay-api@1.0.11': - dependencies: - '@walletconnect/jsonrpc-types': 1.0.4 - - '@walletconnect/relay-auth@1.1.0': - dependencies: - '@noble/curves': 1.8.0 - '@noble/hashes': 1.7.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - uint8arrays: 3.1.0 - - '@walletconnect/safe-json@1.0.2': - dependencies: - tslib: 1.14.1 - - '@walletconnect/sign-client@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/core': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/logger': 2.1.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0 - '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - - '@walletconnect/sign-client@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/core': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/logger': 2.1.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1 - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - - '@walletconnect/time@1.0.2': - dependencies: - tslib: 1.14.1 - - '@walletconnect/types@2.21.0': - dependencies: - '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - db0 - - ioredis - - uploadthing - - '@walletconnect/types@2.21.1': - dependencies: - '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - db0 - - ioredis - - uploadthing - - '@walletconnect/universal-provider@2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.0 - '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - es-toolkit: 1.33.0 - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - - '@walletconnect/universal-provider@2.21.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1 - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - es-toolkit: 1.33.0 - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - - '@walletconnect/utils@2.21.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@noble/ciphers': 1.2.1 - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/relay-api': 1.0.11 - '@walletconnect/relay-auth': 1.1.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0 - '@walletconnect/window-getters': 1.0.1 - '@walletconnect/window-metadata': 1.0.1 - bs58: 6.0.0 - detect-browser: 5.3.0 - query-string: 7.1.3 - uint8arrays: 3.1.0 - viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - - '@walletconnect/utils@2.21.1(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@noble/ciphers': 1.2.1 - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1 - '@walletconnect/relay-api': 1.0.11 - '@walletconnect/relay-auth': 1.1.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1 - '@walletconnect/window-getters': 1.0.1 - '@walletconnect/window-metadata': 1.0.1 - bs58: 6.0.0 - detect-browser: 5.3.0 - query-string: 7.1.3 - uint8arrays: 3.1.0 - viem: 2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - - '@walletconnect/window-getters@1.0.1': - dependencies: - tslib: 1.14.1 - - '@walletconnect/window-metadata@1.0.1': - dependencies: - '@walletconnect/window-getters': 1.0.1 - tslib: 1.14.1 - - '@xmldom/xmldom@0.8.10': {} - - abbrev@1.1.1: {} - - abitype@1.0.6(typescript@5.8.3)(zod@3.25.76): - optionalDependencies: - typescript: 5.8.3 - zod: 3.25.76 - - abitype@1.0.8(typescript@5.8.3)(zod@3.22.4): - optionalDependencies: - typescript: 5.8.3 - zod: 3.22.4 - - abitype@1.0.8(typescript@5.8.3)(zod@3.25.76): - optionalDependencies: - typescript: 5.8.3 - zod: 3.25.76 - - accepts@2.0.0: - dependencies: - mime-types: 3.0.1 - negotiator: 1.0.0 - - agent-base@6.0.2: - dependencies: - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - agent-base@7.1.4: {} - - agentkeepalive@4.6.0: - dependencies: - humanize-ms: 1.2.1 - - aggregate-error@3.1.0: - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - - ajv-keywords@3.5.2(ajv@6.12.6): - dependencies: - ajv: 6.12.6 - - ajv@6.12.6: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - ansi-regex@5.0.1: {} - - ansi-regex@6.1.0: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@6.2.1: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 - - app-builder-bin@5.0.0-alpha.12: {} - - app-builder-lib@26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12): - dependencies: - '@develar/schema-utils': 2.6.5 - '@electron/asar': 3.2.18 - '@electron/fuses': 1.8.0 - '@electron/notarize': 2.5.0 - '@electron/osx-sign': 1.3.1 - '@electron/rebuild': 3.7.0 - '@electron/universal': 2.0.1 - '@malept/flatpak-bundler': 0.4.0 - '@types/fs-extra': 9.0.13 - async-exit-hook: 2.0.1 - builder-util: 26.0.11 - builder-util-runtime: 9.3.1 - chromium-pickle-js: 0.2.0 - config-file-ts: 0.2.8-rc1 - debug: 4.4.1 - dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12) - dotenv: 16.6.1 - dotenv-expand: 11.0.7 - ejs: 3.1.10 - electron-builder-squirrel-windows: 26.0.12(dmg-builder@26.0.12) - electron-publish: 26.0.11 - fs-extra: 10.1.0 - hosted-git-info: 4.1.0 - is-ci: 3.0.1 - isbinaryfile: 5.0.4 - js-yaml: 4.1.0 - json5: 2.2.3 - lazy-val: 1.0.5 - minimatch: 10.0.3 - plist: 3.1.0 - resedit: 1.7.2 - semver: 7.7.2 - tar: 6.2.1 - temp-file: 3.4.0 - tiny-async-pool: 1.3.0 - transitivePeerDependencies: - - bluebird - - supports-color - - argparse@2.0.1: {} - - aria-hidden@1.2.6: - dependencies: - tslib: 2.8.1 - - assert-plus@1.0.0: - optional: true - - astral-regex@2.0.0: - optional: true - - async-exit-hook@2.0.1: {} - - async-mutex@0.2.6: - dependencies: - tslib: 2.8.1 - - async@3.2.6: {} - - asynckit@0.4.0: {} - - at-least-node@1.0.0: {} - - atomic-sleep@1.0.0: {} - - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - axios@1.10.0: - dependencies: - follow-redirects: 1.15.9 - form-data: 4.0.4 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - - axios@1.11.0: - dependencies: - follow-redirects: 1.15.9 - form-data: 4.0.4 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - - balanced-match@1.0.2: {} - - base-x@3.0.11: - dependencies: - safe-buffer: 5.2.1 - - base-x@5.0.1: {} - - base64-js@1.5.1: {} - - big.js@6.2.2: {} - - bigint-buffer@1.1.5: - dependencies: - bindings: 1.5.0 - - bignumber.js@9.3.1: {} - - bindings@1.5.0: - dependencies: - file-uri-to-path: 1.0.0 - - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - - bn.js@5.2.2: {} - - body-parser@2.2.0: - dependencies: - bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.1 - http-errors: 2.0.0 - iconv-lite: 0.6.3 - on-finished: 2.4.1 - qs: 6.14.0 - raw-body: 3.0.0 - type-is: 2.0.1 - transitivePeerDependencies: - - supports-color - - boolean@3.2.0: - optional: true - - borsh@0.7.0: - dependencies: - bn.js: 5.2.2 - bs58: 4.0.1 - text-encoding-utf-8: 1.0.2 - - bowser@2.11.0: {} - - brace-expansion@1.1.12: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.2: - dependencies: - balanced-match: 1.0.2 - - browserslist@4.25.1: - dependencies: - caniuse-lite: 1.0.30001727 - electron-to-chromium: 1.5.189 - node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.25.1) - - bs58@4.0.1: - dependencies: - base-x: 3.0.11 - - bs58@6.0.0: - dependencies: - base-x: 5.0.1 - - buffer-crc32@0.2.13: {} - - buffer-from@1.1.2: {} - - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - buffer@6.0.3: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - - bufferutil@4.0.9: - dependencies: - node-gyp-build: 4.8.4 - - builder-util-runtime@9.3.1: - dependencies: - debug: 4.4.1 - sax: 1.4.1 - transitivePeerDependencies: - - supports-color - - builder-util@26.0.11: - dependencies: - 7zip-bin: 5.2.0 - '@types/debug': 4.1.12 - app-builder-bin: 5.0.0-alpha.12 - builder-util-runtime: 9.3.1 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.1 - fs-extra: 10.1.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - is-ci: 3.0.1 - js-yaml: 4.1.0 - sanitize-filename: 1.6.3 - source-map-support: 0.5.21 - stat-mode: 1.0.0 - temp-file: 3.4.0 - tiny-async-pool: 1.3.0 - transitivePeerDependencies: - - supports-color - - bytes@3.1.2: {} - - cacache@16.1.3: - dependencies: - '@npmcli/fs': 2.1.2 - '@npmcli/move-file': 2.0.1 - chownr: 2.0.0 - fs-minipass: 2.1.0 - glob: 8.1.0 - infer-owner: 1.0.4 - lru-cache: 7.18.3 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - mkdirp: 1.0.4 - p-map: 4.0.0 - promise-inflight: 1.0.1 - rimraf: 3.0.2 - ssri: 9.0.1 - tar: 6.2.1 - unique-filename: 2.0.1 - transitivePeerDependencies: - - bluebird - - cacheable-lookup@5.0.4: {} - - cacheable-request@7.0.4: - dependencies: - clone-response: 1.0.3 - get-stream: 5.2.0 - http-cache-semantics: 4.2.0 - keyv: 4.5.4 - lowercase-keys: 2.0.0 - normalize-url: 6.1.0 - responselike: 2.0.1 - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - camelcase@5.3.1: {} - - caniuse-lite@1.0.30001727: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - chalk@5.4.1: {} - - charenc@0.0.2: {} - - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - - chownr@2.0.0: {} - - chromium-pickle-js@0.2.0: {} - - ci-info@3.9.0: {} - - classnames@2.5.1: {} - - clean-stack@2.2.0: {} - - cli-cursor@3.1.0: - dependencies: - restore-cursor: 3.1.0 - - cli-spinners@2.9.2: {} - - cli-truncate@2.1.0: - dependencies: - slice-ansi: 3.0.0 - string-width: 4.2.3 - optional: true - - cliui@6.0.0: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 6.2.0 - - cliui@8.0.1: - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - - clone-response@1.0.3: - dependencies: - mimic-response: 1.0.1 - - clone@1.0.4: {} - - clsx@1.2.1: {} - - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-name@1.1.3: {} - - color-name@1.1.4: {} - - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - - color@3.2.1: - dependencies: - color-convert: 1.9.3 - color-string: 1.9.1 - - colorspace@1.1.4: - dependencies: - color: 3.2.1 - text-hex: 1.0.0 - - combined-stream@1.0.8: - dependencies: - delayed-stream: 1.0.0 - - commander@12.1.0: {} - - commander@14.0.0: {} - - commander@2.20.3: {} - - commander@5.1.0: {} - - commander@9.5.0: - optional: true - - compare-version@0.1.2: {} - - concat-map@0.0.1: {} - - concurrently@9.2.0: - dependencies: - chalk: 4.1.2 - lodash: 4.17.21 - rxjs: 7.8.2 - shell-quote: 1.8.3 - supports-color: 8.1.1 - tree-kill: 1.2.2 - yargs: 17.7.2 - - config-file-ts@0.2.8-rc1: - dependencies: - glob: 10.4.5 - typescript: 5.8.3 - - content-disposition@1.0.0: - dependencies: - safe-buffer: 5.2.1 - - content-type@1.0.5: {} - - convert-source-map@2.0.0: {} - - cookie-es@1.2.2: {} - - cookie-signature@1.2.2: {} - - cookie@0.7.2: {} - - core-util-is@1.0.2: {} - - cors@2.8.5: - dependencies: - object-assign: 4.1.1 - vary: 1.1.2 - - crc-32@1.2.2: {} - - crc@3.8.0: - dependencies: - buffer: 5.7.1 - optional: true - - cross-dirname@0.1.0: - optional: true - - cross-fetch@3.2.0(encoding@0.1.13): - dependencies: - node-fetch: 2.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding - - cross-fetch@4.1.0(encoding@0.1.13): - dependencies: - node-fetch: 2.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - crossws@0.3.5: - dependencies: - uncrypto: 0.1.3 - - crypt@0.0.2: {} - - csstype@3.1.3: {} - - date-fns@2.30.0: - dependencies: - '@babel/runtime': 7.28.2 - - dayjs@1.11.13: {} - - debug@4.3.7: - dependencies: - ms: 2.1.3 - - debug@4.4.1: - dependencies: - ms: 2.1.3 - - decamelize@1.2.0: {} - - decode-uri-component@0.2.2: {} - - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - - defaults@1.0.4: - dependencies: - clone: 1.0.4 - - defer-to-connect@2.0.1: {} - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - optional: true - - defu@6.1.4: {} - - delay@5.0.0: {} - - delayed-stream@1.0.0: {} - - depd@2.0.0: {} - - derive-valtio@0.1.0(valtio@1.13.2(@types/react@19.1.8)(react@18.3.1)): - dependencies: - valtio: 1.13.2(@types/react@19.1.8)(react@18.3.1) - - destr@2.0.5: {} - - detect-browser@5.3.0: {} - - detect-libc@2.0.4: {} - - detect-node-es@1.1.0: {} - - detect-node@2.1.0: - optional: true - - dijkstrajs@1.0.3: {} - - dir-compare@4.2.0: - dependencies: - minimatch: 3.1.2 - p-limit: 3.1.0 - - dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12): - dependencies: - app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12) - builder-util: 26.0.11 - builder-util-runtime: 9.3.1 - fs-extra: 10.1.0 - iconv-lite: 0.6.3 - js-yaml: 4.1.0 - optionalDependencies: - dmg-license: 1.0.11 - transitivePeerDependencies: - - bluebird - - electron-builder-squirrel-windows - - supports-color - - dmg-license@1.0.11: - dependencies: - '@types/plist': 3.0.5 - '@types/verror': 1.10.11 - ajv: 6.12.6 - crc: 3.8.0 - iconv-corefoundation: 1.1.7 - plist: 3.1.0 - smart-buffer: 4.2.0 - verror: 1.10.1 - optional: true - - dotenv-expand@11.0.7: - dependencies: - dotenv: 16.6.1 - - dotenv@16.6.1: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - duplexify@4.1.3: - dependencies: - end-of-stream: 1.4.5 - inherits: 2.0.4 - readable-stream: 3.6.2 - stream-shift: 1.0.3 - - eastasianwidth@0.2.0: {} - - eciesjs@0.4.15: - dependencies: - '@ecies/ciphers': 0.2.4(@noble/ciphers@1.3.0) - '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.4 - '@noble/hashes': 1.8.0 - - ee-first@1.1.1: {} - - ejs@3.1.10: - dependencies: - jake: 10.9.2 - - electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12): - dependencies: - app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12) - builder-util: 26.0.11 - electron-winstaller: 5.4.0 - transitivePeerDependencies: - - bluebird - - dmg-builder - - supports-color - - electron-builder@26.0.12(electron-builder-squirrel-windows@26.0.12): - dependencies: - app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12) - builder-util: 26.0.11 - builder-util-runtime: 9.3.1 - chalk: 4.1.2 - dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12) - fs-extra: 10.1.0 - is-ci: 3.0.1 - lazy-val: 1.0.5 - simple-update-notifier: 2.0.0 - yargs: 17.7.2 - transitivePeerDependencies: - - bluebird - - electron-builder-squirrel-windows - - supports-color - - electron-is-dev@3.0.1: {} - - electron-publish@26.0.11: - dependencies: - '@types/fs-extra': 9.0.13 - builder-util: 26.0.11 - builder-util-runtime: 9.3.1 - chalk: 4.1.2 - form-data: 4.0.4 - fs-extra: 10.1.0 - lazy-val: 1.0.5 - mime: 2.6.0 - transitivePeerDependencies: - - supports-color - - electron-to-chromium@1.5.189: {} - - electron-winstaller@5.4.0: - dependencies: - '@electron/asar': 3.4.1 - debug: 4.4.1 - fs-extra: 7.0.1 - lodash: 4.17.21 - temp: 0.9.4 - optionalDependencies: - '@electron/windows-sign': 1.2.2 - transitivePeerDependencies: - - supports-color - - electron@37.2.3: - dependencies: - '@electron/get': 2.0.3 - '@types/node': 22.16.5 - extract-zip: 2.0.1 - transitivePeerDependencies: - - supports-color - - emoji-regex@8.0.0: {} - - emoji-regex@9.2.2: {} - - enabled@2.0.0: {} - - encode-utf8@1.0.3: {} - - encodeurl@2.0.0: {} - - encoding@0.1.13: - dependencies: - iconv-lite: 0.6.3 - optional: true - - end-of-stream@1.4.5: - dependencies: - once: 1.4.0 - - engine.io-client@6.6.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.3.7 - engine.io-parser: 5.2.3 - ws: 8.17.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - xmlhttprequest-ssl: 2.1.2 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - engine.io-parser@5.2.3: {} - - env-paths@2.2.1: {} - - err-code@2.0.3: {} - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - es-set-tostringtag@2.1.0: - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - es-toolkit@1.33.0: {} - - es6-error@4.1.1: - optional: true - - es6-promise@4.2.8: {} - - es6-promisify@5.0.0: - dependencies: - es6-promise: 4.2.8 - - esbuild@0.25.8: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.8 - '@esbuild/android-arm': 0.25.8 - '@esbuild/android-arm64': 0.25.8 - '@esbuild/android-x64': 0.25.8 - '@esbuild/darwin-arm64': 0.25.8 - '@esbuild/darwin-x64': 0.25.8 - '@esbuild/freebsd-arm64': 0.25.8 - '@esbuild/freebsd-x64': 0.25.8 - '@esbuild/linux-arm': 0.25.8 - '@esbuild/linux-arm64': 0.25.8 - '@esbuild/linux-ia32': 0.25.8 - '@esbuild/linux-loong64': 0.25.8 - '@esbuild/linux-mips64el': 0.25.8 - '@esbuild/linux-ppc64': 0.25.8 - '@esbuild/linux-riscv64': 0.25.8 - '@esbuild/linux-s390x': 0.25.8 - '@esbuild/linux-x64': 0.25.8 - '@esbuild/netbsd-arm64': 0.25.8 - '@esbuild/netbsd-x64': 0.25.8 - '@esbuild/openbsd-arm64': 0.25.8 - '@esbuild/openbsd-x64': 0.25.8 - '@esbuild/openharmony-arm64': 0.25.8 - '@esbuild/sunos-x64': 0.25.8 - '@esbuild/win32-arm64': 0.25.8 - '@esbuild/win32-ia32': 0.25.8 - '@esbuild/win32-x64': 0.25.8 - - escalade@3.2.0: {} - - escape-html@1.0.3: {} - - escape-string-regexp@4.0.0: - optional: true - - etag@1.8.1: {} - - eth-block-tracker@7.1.0: - dependencies: - '@metamask/eth-json-rpc-provider': 1.0.1 - '@metamask/safe-event-emitter': 3.1.2 - '@metamask/utils': 5.0.2 - json-rpc-random-id: 1.0.1 - pify: 3.0.0 - transitivePeerDependencies: - - supports-color - - eth-json-rpc-filters@6.0.1: - dependencies: - '@metamask/safe-event-emitter': 3.1.2 - async-mutex: 0.2.6 - eth-query: 2.1.2 - json-rpc-engine: 6.1.0 - pify: 5.0.0 - - eth-query@2.1.2: - dependencies: - json-rpc-random-id: 1.0.1 - xtend: 4.0.2 - - eth-rpc-errors@4.0.3: - dependencies: - fast-safe-stringify: 2.1.1 - - ethereum-cryptography@2.2.1: - dependencies: - '@noble/curves': 1.4.2 - '@noble/hashes': 1.4.0 - '@scure/bip32': 1.4.0 - '@scure/bip39': 1.3.0 - - eventemitter2@6.4.9: {} - - eventemitter3@5.0.1: {} - - events@3.3.0: {} - - eventsource-parser@3.0.3: {} - - eventsource@3.0.7: - dependencies: - eventsource-parser: 3.0.3 - - exponential-backoff@3.1.2: {} - - express-rate-limit@7.5.1(express@5.1.0): - dependencies: - express: 5.1.0 - - express@5.1.0: - dependencies: - accepts: 2.0.0 - body-parser: 2.2.0 - content-disposition: 1.0.0 - content-type: 1.0.5 - cookie: 0.7.2 - cookie-signature: 1.2.2 - debug: 4.4.1 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - finalhandler: 2.1.0 - fresh: 2.0.0 - http-errors: 2.0.0 - merge-descriptors: 2.0.0 - mime-types: 3.0.1 - on-finished: 2.4.1 - once: 1.4.0 - parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.14.0 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.0 - serve-static: 2.2.0 - statuses: 2.0.2 - type-is: 2.0.1 - vary: 1.1.2 - transitivePeerDependencies: - - supports-color - - extension-port-stream@3.0.0: - dependencies: - readable-stream: 3.6.2 - webextension-polyfill: 0.10.0 - - extract-zip@2.0.1: - dependencies: - debug: 4.4.1 - get-stream: 5.2.0 - yauzl: 2.10.0 - optionalDependencies: - '@types/yauzl': 2.10.3 - transitivePeerDependencies: - - supports-color - - extsprintf@1.4.1: - optional: true - - eyes@0.1.8: {} - - fast-deep-equal@3.1.3: {} - - fast-json-stable-stringify@2.1.0: {} - - fast-redact@3.5.0: {} - - fast-safe-stringify@2.1.1: {} - - fast-stable-stringify@1.0.0: {} - - fastestsmallesttextencoderdecoder@1.0.22: {} - - fd-slicer@1.1.0: - dependencies: - pend: 1.2.0 - - fdir@6.4.6(picomatch@4.0.3): - optionalDependencies: - picomatch: 4.0.3 - - fecha@4.2.3: {} - - file-uri-to-path@1.0.0: {} - - filelist@1.0.4: - dependencies: - minimatch: 5.1.6 - - filter-obj@1.1.0: {} - - finalhandler@2.1.0: - dependencies: - debug: 4.4.1 - encodeurl: 2.0.0 - escape-html: 1.0.3 - on-finished: 2.4.1 - parseurl: 1.3.3 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - find-up@4.1.0: - dependencies: - locate-path: 5.0.0 - path-exists: 4.0.0 - - fn.name@1.1.0: {} - - follow-redirects@1.15.9: {} - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - - foreground-child@3.3.1: - dependencies: - cross-spawn: 7.0.6 - signal-exit: 4.1.0 - - form-data@4.0.4: - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - - forwarded@0.2.0: {} - - fresh@2.0.0: {} - - fs-extra@10.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs-extra@11.3.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs-extra@7.0.1: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@9.1.0: - dependencies: - at-least-node: 1.0.0 - graceful-fs: 4.2.11 - jsonfile: 6.1.0 - universalify: 2.0.1 - - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - - fs.realpath@1.0.0: {} - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - gensync@1.0.0-beta.2: {} - - get-caller-file@2.0.5: {} - - get-intrinsic@1.3.0: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-nonce@1.0.1: {} - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - get-stream@5.2.0: - dependencies: - pump: 3.0.3 - - get-tsconfig@4.10.1: - dependencies: - resolve-pkg-maps: 1.0.0 - - glob@10.4.5: - dependencies: - foreground-child: 3.3.1 - jackspeak: 3.4.3 - minimatch: 9.0.5 - minipass: 7.1.2 - package-json-from-dist: 1.0.1 - path-scurry: 1.11.1 - - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - glob@8.1.0: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - - global-agent@3.0.0: - dependencies: - boolean: 3.2.0 - es6-error: 4.1.1 - matcher: 3.0.0 - roarr: 2.15.4 - semver: 7.7.2 - serialize-error: 7.0.1 - optional: true - - globalthis@1.0.4: - dependencies: - define-properties: 1.2.1 - gopd: 1.2.0 - optional: true - - gopd@1.2.0: {} - - got@11.8.6: - dependencies: - '@sindresorhus/is': 4.6.0 - '@szmarczak/http-timer': 4.0.6 - '@types/cacheable-request': 6.0.3 - '@types/responselike': 1.0.3 - cacheable-lookup: 5.0.4 - cacheable-request: 7.0.4 - decompress-response: 6.0.0 - http2-wrapper: 1.0.3 - lowercase-keys: 2.0.0 - p-cancelable: 2.1.1 - responselike: 2.0.1 - - graceful-fs@4.2.11: {} - - h3@1.15.4: - dependencies: - cookie-es: 1.2.2 - crossws: 0.3.5 - defu: 6.1.4 - destr: 2.0.5 - iron-webcrypto: 1.2.1 - node-mock-http: 1.0.2 - radix3: 1.1.2 - ufo: 1.6.1 - uncrypto: 0.1.3 - - has-flag@4.0.0: {} - - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - hosted-git-info@4.1.0: - dependencies: - lru-cache: 6.0.0 - - http-cache-semantics@4.2.0: {} - - http-errors@2.0.0: - dependencies: - depd: 2.0.0 - inherits: 2.0.4 - setprototypeof: 1.2.0 - statuses: 2.0.1 - toidentifier: 1.0.1 - - http-proxy-agent@5.0.0: - dependencies: - '@tootallnate/once': 2.0.0 - agent-base: 6.0.2 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.4 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - http2-wrapper@1.0.3: - dependencies: - quick-lru: 5.1.1 - resolve-alpn: 1.2.1 - - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.4 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - humanize-ms@1.2.1: - dependencies: - ms: 2.1.3 - - iconv-corefoundation@1.1.7: - dependencies: - cli-truncate: 2.1.0 - node-addon-api: 1.7.2 - optional: true - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - idb-keyval@6.2.1: {} - - idb-keyval@6.2.2: {} - - ieee754@1.2.1: {} - - imurmurhash@0.1.4: {} - - indent-string@4.0.0: {} - - infer-owner@1.0.4: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - - inherits@2.0.4: {} - - ip-address@9.0.5: - dependencies: - jsbn: 1.1.0 - sprintf-js: 1.1.3 - - ipaddr.js@1.9.1: {} - - iron-webcrypto@1.2.1: {} - - is-arguments@1.2.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-arrayish@0.3.2: {} - - is-buffer@1.1.6: {} - - is-callable@1.2.7: {} - - is-ci@3.0.1: - dependencies: - ci-info: 3.9.0 - - is-fullwidth-code-point@3.0.0: {} - - is-generator-function@1.1.0: - dependencies: - call-bound: 1.0.4 - get-proto: 1.0.1 - has-tostringtag: 1.0.2 - safe-regex-test: 1.1.0 - - is-interactive@1.0.0: {} - - is-lambda@1.0.1: {} - - is-promise@4.0.0: {} - - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - is-stream@2.0.1: {} - - is-typed-array@1.1.15: - dependencies: - which-typed-array: 1.1.19 - - is-unicode-supported@0.1.0: {} - - isarray@1.0.0: {} - - isarray@2.0.5: {} - - isbinaryfile@4.0.10: {} - - isbinaryfile@5.0.4: {} - - isexe@2.0.0: {} - - isomorphic-ws@4.0.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)): - dependencies: - ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) - - isows@1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)): - dependencies: - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - - isows@1.0.7(ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)): - dependencies: - ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) - - jackspeak@3.4.3: - dependencies: - '@isaacs/cliui': 8.0.2 - optionalDependencies: - '@pkgjs/parseargs': 0.11.0 - - jake@10.9.2: - dependencies: - async: 3.2.6 - chalk: 4.1.2 - filelist: 1.0.4 - minimatch: 3.1.2 - - jayson@4.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): - dependencies: - '@types/connect': 3.4.38 - '@types/node': 12.20.55 - '@types/ws': 7.4.7 - commander: 2.20.3 - delay: 5.0.0 - es6-promisify: 5.0.0 - eyes: 0.1.8 - isomorphic-ws: 4.0.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - json-stringify-safe: 5.0.1 - stream-json: 1.9.1 - uuid: 8.3.2 - ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - jose@6.0.12: {} - - js-tokens@4.0.0: {} - - js-yaml@4.1.0: - dependencies: - argparse: 2.0.1 - - jsbn@1.1.0: {} - - jsesc@3.1.0: {} - - json-buffer@3.0.1: {} - - json-rpc-engine@6.1.0: - dependencies: - '@metamask/safe-event-emitter': 2.0.0 - eth-rpc-errors: 4.0.3 - - json-rpc-random-id@1.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-stringify-safe@5.0.1: {} - - json5@2.2.3: {} - - jsonfile@4.0.0: - optionalDependencies: - graceful-fs: 4.2.11 - - jsonfile@6.1.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - - keccak@3.0.4: - dependencies: - node-addon-api: 2.0.2 - node-gyp-build: 4.8.4 - readable-stream: 3.6.2 - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - keyvaluestorage-interface@1.0.0: {} - - kuler@2.0.0: {} - - lazy-val@1.0.5: {} - - lit-element@4.2.1: - dependencies: - '@lit-labs/ssr-dom-shim': 1.4.0 - '@lit/reactive-element': 2.1.1 - lit-html: 3.3.1 - - lit-html@3.3.1: - dependencies: - '@types/trusted-types': 2.0.7 - - lit@3.3.0: - dependencies: - '@lit/reactive-element': 2.1.1 - lit-element: 4.2.1 - lit-html: 3.3.1 - - locate-path@5.0.0: - dependencies: - p-locate: 4.1.0 - - lodash@4.17.21: {} - - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 - - logform@2.7.0: - dependencies: - '@colors/colors': 1.6.0 - '@types/triple-beam': 1.3.5 - fecha: 4.2.3 - ms: 2.1.3 - safe-stable-stringify: 2.5.0 - triple-beam: 1.4.1 - - loose-envify@1.4.0: - dependencies: - js-tokens: 4.0.0 - - lowercase-keys@2.0.0: {} - - lru-cache@10.4.3: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - lru-cache@6.0.0: - dependencies: - yallist: 4.0.0 - - lru-cache@7.18.3: {} - - make-fetch-happen@10.2.1: - dependencies: - agentkeepalive: 4.6.0 - cacache: 16.1.3 - http-cache-semantics: 4.2.0 - http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 - is-lambda: 1.0.1 - lru-cache: 7.18.3 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-fetch: 2.1.2 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - negotiator: 0.6.4 - promise-retry: 2.0.1 - socks-proxy-agent: 7.0.0 - ssri: 9.0.1 - transitivePeerDependencies: - - bluebird - - supports-color - - matcher@3.0.0: - dependencies: - escape-string-regexp: 4.0.0 - optional: true - - math-intrinsics@1.1.0: {} - - md5@2.3.0: - dependencies: - charenc: 0.0.2 - crypt: 0.0.2 - is-buffer: 1.1.6 - - media-typer@1.1.0: {} - - merge-descriptors@2.0.0: {} - - micro-ftch@0.3.1: {} - - mime-db@1.52.0: {} - - mime-db@1.54.0: {} - - mime-types@2.1.35: - dependencies: - mime-db: 1.52.0 - - mime-types@3.0.1: - dependencies: - mime-db: 1.54.0 - - mime@2.6.0: {} - - mimic-fn@2.1.0: {} - - mimic-response@1.0.1: {} - - mimic-response@3.1.0: {} - - minimatch@10.0.3: - dependencies: - '@isaacs/brace-expansion': 5.0.0 - - minimatch@3.1.2: - dependencies: - brace-expansion: 1.1.12 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.2 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.2 - - minimist@1.2.8: {} - - minipass-collect@1.0.2: - dependencies: - minipass: 3.3.6 - - minipass-fetch@2.1.2: - dependencies: - minipass: 3.3.6 - minipass-sized: 1.0.3 - minizlib: 2.1.2 - optionalDependencies: - encoding: 0.1.13 - - minipass-flush@1.0.5: - dependencies: - minipass: 3.3.6 - - minipass-pipeline@1.2.4: - dependencies: - minipass: 3.3.6 - - minipass-sized@1.0.3: - dependencies: - minipass: 3.3.6 - - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - - minipass@5.0.0: {} - - minipass@7.1.2: {} - - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - - mipd@0.0.7(typescript@5.8.3): - optionalDependencies: - typescript: 5.8.3 - - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 - - mkdirp@1.0.4: {} - - ms@2.1.3: {} - - multiformats@9.9.0: {} - - nanoid@3.3.11: {} - - negotiator@0.6.4: {} - - negotiator@1.0.0: {} - - node-abi@3.75.0: - dependencies: - semver: 7.7.2 - - node-addon-api@1.7.2: - optional: true - - node-addon-api@2.0.2: {} - - node-api-version@0.2.1: - dependencies: - semver: 7.7.2 - - node-fetch-native@1.6.6: {} - - node-fetch@2.7.0(encoding@0.1.13): - dependencies: - whatwg-url: 5.0.0 - optionalDependencies: - encoding: 0.1.13 - - node-gyp-build@4.8.4: {} - - node-mock-http@1.0.2: {} - - node-releases@2.0.19: {} - - nopt@6.0.0: - dependencies: - abbrev: 1.1.1 - - normalize-path@3.0.0: {} - - normalize-url@6.1.0: {} - - obj-multiplex@1.0.0: - dependencies: - end-of-stream: 1.4.5 - once: 1.4.0 - readable-stream: 2.3.8 - - object-assign@4.1.1: {} - - object-inspect@1.13.4: {} - - object-keys@1.1.1: - optional: true - - ofetch@1.4.1: - dependencies: - destr: 2.0.5 - node-fetch-native: 1.6.6 - ufo: 1.6.1 - - on-exit-leak-free@0.2.0: {} - - on-finished@2.4.1: - dependencies: - ee-first: 1.1.1 - - once@1.4.0: - dependencies: - wrappy: 1.0.2 - - one-time@1.0.0: - dependencies: - fn.name: 1.1.0 - - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - - ora@5.4.1: - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - - ox@0.6.7(typescript@5.8.3)(zod@3.25.76): - dependencies: - '@adraffy/ens-normalize': 1.11.0 - '@noble/curves': 1.9.4 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.0.8(typescript@5.8.3)(zod@3.25.76) - eventemitter3: 5.0.1 - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - zod - - ox@0.6.9(typescript@5.8.3)(zod@3.25.76): - dependencies: - '@adraffy/ens-normalize': 1.11.0 - '@noble/curves': 1.9.4 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.0.8(typescript@5.8.3)(zod@3.25.76) - eventemitter3: 5.0.1 - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - zod - - ox@0.8.1(typescript@5.8.3)(zod@3.22.4): - dependencies: - '@adraffy/ens-normalize': 1.11.0 - '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.4 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.0.8(typescript@5.8.3)(zod@3.22.4) - eventemitter3: 5.0.1 - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - zod - - ox@0.8.1(typescript@5.8.3)(zod@3.25.76): - dependencies: - '@adraffy/ens-normalize': 1.11.0 - '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.4 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.0.8(typescript@5.8.3)(zod@3.25.76) - eventemitter3: 5.0.1 - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - zod - - p-cancelable@2.1.1: {} - - p-limit@2.3.0: - dependencies: - p-try: 2.2.0 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@4.1.0: - dependencies: - p-limit: 2.3.0 - - p-map@4.0.0: - dependencies: - aggregate-error: 3.1.0 - - p-try@2.2.0: {} - - package-json-from-dist@1.0.1: {} - - parseurl@1.3.3: {} - - path-exists@4.0.0: {} - - path-is-absolute@1.0.1: {} - - path-key@3.1.1: {} - - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.2 - - path-to-regexp@8.2.0: {} - - pe-library@0.4.1: {} - - pend@1.2.0: {} - - picocolors@1.1.1: {} - - picomatch@2.3.1: {} - - picomatch@4.0.3: {} - - pify@3.0.0: {} - - pify@5.0.0: {} - - pino-abstract-transport@0.5.0: - dependencies: - duplexify: 4.1.3 - split2: 4.2.0 - - pino-std-serializers@4.0.0: {} - - pino@7.11.0: - dependencies: - atomic-sleep: 1.0.0 - fast-redact: 3.5.0 - on-exit-leak-free: 0.2.0 - pino-abstract-transport: 0.5.0 - pino-std-serializers: 4.0.0 - process-warning: 1.0.0 - quick-format-unescaped: 4.0.4 - real-require: 0.1.0 - safe-stable-stringify: 2.5.0 - sonic-boom: 2.8.0 - thread-stream: 0.15.2 - - pkce-challenge@5.0.0: {} - - plist@3.1.0: - dependencies: - '@xmldom/xmldom': 0.8.10 - base64-js: 1.5.1 - xmlbuilder: 15.1.1 - - pngjs@5.0.0: {} - - pony-cause@2.1.11: {} - - possible-typed-array-names@1.1.0: {} - - postcss@8.5.6: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - postject@1.0.0-alpha.6: - dependencies: - commander: 9.5.0 - optional: true - - preact@10.24.2: {} - - preact@10.27.0: {} - - proc-log@2.0.1: {} - - process-nextick-args@2.0.1: {} - - process-warning@1.0.0: {} - - progress@2.0.3: {} - - promise-inflight@1.0.1: {} - - promise-retry@2.0.1: - dependencies: - err-code: 2.0.3 - retry: 0.12.0 - - proxy-addr@2.0.7: - dependencies: - forwarded: 0.2.0 - ipaddr.js: 1.9.1 - - proxy-compare@2.6.0: {} - - proxy-from-env@1.1.0: {} - - pump@3.0.3: - dependencies: - end-of-stream: 1.4.5 - once: 1.4.0 - - punycode@2.3.1: {} - - qrcode@1.5.3: - dependencies: - dijkstrajs: 1.0.3 - encode-utf8: 1.0.3 - pngjs: 5.0.0 - yargs: 15.4.1 - - qs@6.14.0: - dependencies: - side-channel: 1.1.0 - - query-string@7.1.3: - dependencies: - decode-uri-component: 0.2.2 - filter-obj: 1.1.0 - split-on-first: 1.1.0 - strict-uri-encode: 2.0.0 - - quick-format-unescaped@4.0.4: {} - - quick-lru@5.1.1: {} - - radix-ui@1.4.2(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@radix-ui/primitive': 1.1.2 - '@radix-ui/react-accessible-icon': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-accordion': 1.2.11(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-alert-dialog': 1.1.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-aspect-ratio': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-avatar': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-checkbox': 1.3.2(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-collapsible': 1.1.11(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-context-menu': 2.2.15(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-dialog': 1.1.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-dropdown-menu': 2.1.15(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-form': 0.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-hover-card': 1.1.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-label': 2.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-menu': 2.1.15(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-menubar': 1.1.15(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-navigation-menu': 1.2.13(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-one-time-password-field': 0.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-password-toggle-field': 0.1.2(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popover': 1.1.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popper': 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.4(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-progress': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-radio-group': 1.3.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-scroll-area': 1.2.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-select': 2.2.5(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slider': 1.3.5(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-switch': 1.2.5(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-tabs': 1.1.12(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toast': 1.2.14(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle': 1.1.9(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle-group': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toolbar': 1.1.10(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-tooltip': 1.2.7(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.1.8)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.1.6(@types/react@19.1.8))(@types/react@19.1.8)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - '@types/react-dom': 19.1.6(@types/react@19.1.8) - - radix3@1.1.2: {} - - range-parser@1.2.1: {} - - raw-body@3.0.0: - dependencies: - bytes: 3.1.2 - http-errors: 2.0.0 - iconv-lite: 0.6.3 - unpipe: 1.0.0 - - react-dom@18.3.1(react@18.3.1): - dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 - - react-refresh@0.17.0: {} - - react-remove-scroll-bar@2.3.8(@types/react@19.1.8)(react@18.3.1): - dependencies: - react: 18.3.1 - react-style-singleton: 2.2.3(@types/react@19.1.8)(react@18.3.1) - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.1.8 - - react-remove-scroll@2.7.1(@types/react@19.1.8)(react@18.3.1): - dependencies: - react: 18.3.1 - react-remove-scroll-bar: 2.3.8(@types/react@19.1.8)(react@18.3.1) - react-style-singleton: 2.2.3(@types/react@19.1.8)(react@18.3.1) - tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.1.8)(react@18.3.1) - use-sidecar: 1.1.3(@types/react@19.1.8)(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - - react-style-singleton@2.2.3(@types/react@19.1.8)(react@18.3.1): - dependencies: - get-nonce: 1.0.1 - react: 18.3.1 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.1.8 - - react@18.3.1: - dependencies: - loose-envify: 1.4.0 - - read-binary-file-arch@1.0.6: - dependencies: - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - readable-stream@2.3.8: - dependencies: - core-util-is: 1.0.2 - inherits: 2.0.4 - isarray: 1.0.0 - process-nextick-args: 2.0.1 - safe-buffer: 5.1.2 - string_decoder: 1.1.1 - util-deprecate: 1.0.2 - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 - - readdirp@4.1.2: {} - - real-require@0.1.0: {} - - require-directory@2.1.1: {} - - require-main-filename@2.0.0: {} - - resedit@1.7.2: - dependencies: - pe-library: 0.4.1 - - resolve-alpn@1.2.1: {} - - resolve-pkg-maps@1.0.0: {} - - responselike@2.0.1: - dependencies: - lowercase-keys: 2.0.0 - - restore-cursor@3.1.0: - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - - retry@0.12.0: {} - - rimraf@2.6.3: - dependencies: - glob: 7.2.3 - - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - - roarr@2.15.4: - dependencies: - boolean: 3.2.0 - detect-node: 2.1.0 - globalthis: 1.0.4 - json-stringify-safe: 5.0.1 - semver-compare: 1.0.0 - sprintf-js: 1.1.3 - optional: true - - rollup@4.45.1: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.45.1 - '@rollup/rollup-android-arm64': 4.45.1 - '@rollup/rollup-darwin-arm64': 4.45.1 - '@rollup/rollup-darwin-x64': 4.45.1 - '@rollup/rollup-freebsd-arm64': 4.45.1 - '@rollup/rollup-freebsd-x64': 4.45.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.45.1 - '@rollup/rollup-linux-arm-musleabihf': 4.45.1 - '@rollup/rollup-linux-arm64-gnu': 4.45.1 - '@rollup/rollup-linux-arm64-musl': 4.45.1 - '@rollup/rollup-linux-loongarch64-gnu': 4.45.1 - '@rollup/rollup-linux-powerpc64le-gnu': 4.45.1 - '@rollup/rollup-linux-riscv64-gnu': 4.45.1 - '@rollup/rollup-linux-riscv64-musl': 4.45.1 - '@rollup/rollup-linux-s390x-gnu': 4.45.1 - '@rollup/rollup-linux-x64-gnu': 4.45.1 - '@rollup/rollup-linux-x64-musl': 4.45.1 - '@rollup/rollup-win32-arm64-msvc': 4.45.1 - '@rollup/rollup-win32-ia32-msvc': 4.45.1 - '@rollup/rollup-win32-x64-msvc': 4.45.1 - fsevents: 2.3.3 - - router@2.2.0: - dependencies: - debug: 4.4.1 - depd: 2.0.0 - is-promise: 4.0.0 - parseurl: 1.3.3 - path-to-regexp: 8.2.0 - transitivePeerDependencies: - - supports-color - - rpc-websockets@9.1.3: - dependencies: - '@swc/helpers': 0.5.17 - '@types/uuid': 8.3.4 - '@types/ws': 8.18.1 - buffer: 6.0.3 - eventemitter3: 5.0.1 - uuid: 8.3.2 - ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - bufferutil: 4.0.9 - utf-8-validate: 5.0.10 - - rxjs@7.8.2: - dependencies: - tslib: 2.8.1 - - safe-buffer@5.1.2: {} - - safe-buffer@5.2.1: {} - - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 - - safe-stable-stringify@2.5.0: {} - - safer-buffer@2.1.2: {} - - sanitize-filename@1.6.3: - dependencies: - truncate-utf8-bytes: 1.0.2 - - sax@1.4.1: {} - - scheduler@0.23.2: - dependencies: - loose-envify: 1.4.0 - - semver-compare@1.0.0: - optional: true - - semver@5.7.2: {} - - semver@6.3.1: {} - - semver@7.7.2: {} - - send@1.2.0: - dependencies: - debug: 4.4.1 - encodeurl: 2.0.0 - escape-html: 1.0.3 - etag: 1.8.1 - fresh: 2.0.0 - http-errors: 2.0.0 - mime-types: 3.0.1 - ms: 2.1.3 - on-finished: 2.4.1 - range-parser: 1.2.1 - statuses: 2.0.2 - transitivePeerDependencies: - - supports-color - - serialize-error@7.0.1: - dependencies: - type-fest: 0.13.1 - optional: true - - serve-static@2.2.0: - dependencies: - encodeurl: 2.0.0 - escape-html: 1.0.3 - parseurl: 1.3.3 - send: 1.2.0 - transitivePeerDependencies: - - supports-color - - set-blocking@2.0.0: {} - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - setprototypeof@1.2.0: {} - - sha.js@2.4.12: - dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - to-buffer: 1.2.1 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - shell-quote@1.8.3: {} - - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - signal-exit@3.0.7: {} - - signal-exit@4.1.0: {} - - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - - simple-update-notifier@2.0.0: - dependencies: - semver: 7.7.2 - - slice-ansi@3.0.0: - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - optional: true - - smart-buffer@4.2.0: {} - - socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.3.7 - engine.io-client: 6.6.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) - socket.io-parser: 4.2.4 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - socket.io-parser@4.2.4: - dependencies: - '@socket.io/component-emitter': 3.1.2 - debug: 4.3.7 - transitivePeerDependencies: - - supports-color - - socks-proxy-agent@7.0.0: - dependencies: - agent-base: 6.0.2 - debug: 4.4.1 - socks: 2.8.6 - transitivePeerDependencies: - - supports-color - - socks@2.8.6: - dependencies: - ip-address: 9.0.5 - smart-buffer: 4.2.0 - - sonic-boom@2.8.0: - dependencies: - atomic-sleep: 1.0.0 - - source-map-js@1.2.1: {} - - source-map-support@0.5.21: - dependencies: - buffer-from: 1.1.2 - source-map: 0.6.1 - - source-map@0.6.1: {} - - split-on-first@1.1.0: {} - - split2@4.2.0: {} - - sprintf-js@1.1.3: {} - - ssri@9.0.1: - dependencies: - minipass: 3.3.6 - - stack-trace@0.0.10: {} - - stat-mode@1.0.0: {} - - statuses@2.0.1: {} - - statuses@2.0.2: {} - - stream-chain@2.2.5: {} - - stream-json@1.9.1: - dependencies: - stream-chain: 2.2.5 - - stream-shift@1.0.3: {} - - strict-uri-encode@2.0.0: {} - - string-width@4.2.3: - dependencies: - emoji-regex: 8.0.0 - is-fullwidth-code-point: 3.0.0 - strip-ansi: 6.0.1 - - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.0 - - string_decoder@1.1.1: - dependencies: - safe-buffer: 5.1.2 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 - - strip-ansi@6.0.1: - dependencies: - ansi-regex: 5.0.1 - - strip-ansi@7.1.0: - dependencies: - ansi-regex: 6.1.0 - - sumchecker@3.0.1: - dependencies: - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - superstruct@1.0.4: {} - - superstruct@2.0.2: {} - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 - - tar@6.2.1: - dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - - temp-file@3.4.0: - dependencies: - async-exit-hook: 2.0.1 - fs-extra: 10.1.0 - - temp@0.9.4: - dependencies: - mkdirp: 0.5.6 - rimraf: 2.6.3 - - text-encoding-utf-8@1.0.2: {} - - text-hex@1.0.0: {} - - thread-stream@0.15.2: - dependencies: - real-require: 0.1.0 - - tiny-async-pool@1.3.0: - dependencies: - semver: 5.7.2 - - tinyglobby@0.2.14: - dependencies: - fdir: 6.4.6(picomatch@4.0.3) - picomatch: 4.0.3 - - tmp-promise@3.0.3: - dependencies: - tmp: 0.2.3 - - tmp@0.2.3: {} - - to-buffer@1.2.1: - dependencies: - isarray: 2.0.5 - safe-buffer: 5.2.1 - typed-array-buffer: 1.0.3 - - toidentifier@1.0.1: {} - - tr46@0.0.3: {} - - tree-kill@1.2.2: {} - - triple-beam@1.4.1: {} - - truncate-utf8-bytes@1.0.2: - dependencies: - utf8-byte-length: 1.0.5 - - tslib@1.14.1: {} - - tslib@2.8.1: {} - - tsx@4.20.3: - dependencies: - esbuild: 0.25.8 - get-tsconfig: 4.10.1 - optionalDependencies: - fsevents: 2.3.3 - - turbo-darwin-64@2.5.5: - optional: true - - turbo-darwin-arm64@2.5.5: - optional: true - - turbo-linux-64@2.5.5: - optional: true - - turbo-linux-arm64@2.5.5: - optional: true - - turbo-windows-64@2.5.5: - optional: true - - turbo-windows-arm64@2.5.5: - optional: true - - turbo@2.5.5: - optionalDependencies: - turbo-darwin-64: 2.5.5 - turbo-darwin-arm64: 2.5.5 - turbo-linux-64: 2.5.5 - turbo-linux-arm64: 2.5.5 - turbo-windows-64: 2.5.5 - turbo-windows-arm64: 2.5.5 - - type-fest@0.13.1: - optional: true - - type-is@2.0.1: - dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 - mime-types: 3.0.1 - - typed-array-buffer@1.0.3: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-typed-array: 1.1.15 - - typescript@5.8.3: {} - - ufo@1.6.1: {} - - uint8arrays@3.1.0: - dependencies: - multiformats: 9.9.0 - - uncrypto@0.1.3: {} - - undici-types@6.21.0: {} - - undici-types@7.8.0: {} - - unique-filename@2.0.1: - dependencies: - unique-slug: 3.0.0 - - unique-slug@3.0.0: - dependencies: - imurmurhash: 0.1.4 - - universalify@0.1.2: {} - - universalify@2.0.1: {} - - unpipe@1.0.0: {} - - unstorage@1.16.1(idb-keyval@6.2.2): - dependencies: - anymatch: 3.1.3 - chokidar: 4.0.3 - destr: 2.0.5 - h3: 1.15.4 - lru-cache: 10.4.3 - node-fetch-native: 1.6.6 - ofetch: 1.4.1 - ufo: 1.6.1 - optionalDependencies: - idb-keyval: 6.2.2 - - update-browserslist-db@1.1.3(browserslist@4.25.1): - dependencies: - browserslist: 4.25.1 - escalade: 3.2.0 - picocolors: 1.1.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - use-callback-ref@1.3.3(@types/react@19.1.8)(react@18.3.1): - dependencies: - react: 18.3.1 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.1.8 - - use-sidecar@1.1.3(@types/react@19.1.8)(react@18.3.1): - dependencies: - detect-node-es: 1.1.0 - react: 18.3.1 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.1.8 - - use-sync-external-store@1.2.0(react@18.3.1): - dependencies: - react: 18.3.1 - - use-sync-external-store@1.4.0(react@18.3.1): - dependencies: - react: 18.3.1 - - use-sync-external-store@1.5.0(react@18.3.1): - dependencies: - react: 18.3.1 - - utf-8-validate@5.0.10: - dependencies: - node-gyp-build: 4.8.4 - - utf8-byte-length@1.0.5: {} - - util-deprecate@1.0.2: {} - - util@0.12.5: - dependencies: - inherits: 2.0.4 - is-arguments: 1.2.0 - is-generator-function: 1.1.0 - is-typed-array: 1.1.15 - which-typed-array: 1.1.19 - - uuid@8.3.2: {} - - uuid@9.0.1: {} - - valtio@1.13.2(@types/react@19.1.8)(react@18.3.1): - dependencies: - derive-valtio: 0.1.0(valtio@1.13.2(@types/react@19.1.8)(react@18.3.1)) - proxy-compare: 2.6.0 - use-sync-external-store: 1.2.0(react@18.3.1) - optionalDependencies: - '@types/react': 19.1.8 - react: 18.3.1 - - vary@1.1.2: {} - - verror@1.10.1: - dependencies: - assert-plus: 1.0.0 - core-util-is: 1.0.2 - extsprintf: 1.4.1 - optional: true - - viem@2.23.2(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76): - dependencies: - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 - '@scure/bip32': 1.6.2 - '@scure/bip39': 1.5.4 - abitype: 1.0.8(typescript@5.8.3)(zod@3.25.76) - isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.6.7(typescript@5.8.3)(zod@3.25.76) - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - - viem@2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.22.4): - dependencies: - '@noble/curves': 1.9.2 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.0.8(typescript@5.8.3)(zod@3.22.4) - isows: 1.0.7(ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.8.1(typescript@5.8.3)(zod@3.22.4) - ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - - viem@2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76): - dependencies: - '@noble/curves': 1.9.2 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.0.8(typescript@5.8.3)(zod@3.25.76) - isows: 1.0.7(ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.8.1(typescript@5.8.3)(zod@3.25.76) - ws: 8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - - vite@7.0.5(@types/node@24.1.0)(tsx@4.20.3): - dependencies: - esbuild: 0.25.8 - fdir: 6.4.6(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.45.1 - tinyglobby: 0.2.14 - optionalDependencies: - '@types/node': 24.1.0 - fsevents: 2.3.3 - tsx: 4.20.3 - - wagmi@2.16.1(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.0(react@18.3.1))(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76): - dependencies: - '@tanstack/react-query': 5.84.0(react@18.3.1) - '@wagmi/connectors': 5.9.1(@types/react@19.1.8)(@wagmi/core@2.18.1(@tanstack/query-core@5.83.1)(@types/react@19.1.8)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(utf-8-validate@5.0.10)(viem@2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) - '@wagmi/core': 2.18.1(@tanstack/query-core@5.83.1)(@types/react@19.1.8)(react@18.3.1)(typescript@5.8.3)(use-sync-external-store@1.4.0(react@18.3.1))(viem@2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76)) - react: 18.3.1 - use-sync-external-store: 1.4.0(react@18.3.1) - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - optionalDependencies: - typescript: 5.8.3 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - immer - - ioredis - - supports-color - - uploadthing - - utf-8-validate - - zod - - wcwidth@1.0.1: - dependencies: - defaults: 1.0.4 - - webextension-polyfill@0.10.0: {} - - webidl-conversions@3.0.1: {} - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - which-module@2.0.1: {} - - which-typed-array@1.1.19: - dependencies: - available-typed-arrays: 1.0.7 - call-bind: 1.0.8 - call-bound: 1.0.4 - for-each: 0.3.5 - get-proto: 1.0.1 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - winston-transport@4.9.0: - dependencies: - logform: 2.7.0 - readable-stream: 3.6.2 - triple-beam: 1.4.1 - - winston@3.17.0: - dependencies: - '@colors/colors': 1.6.0 - '@dabh/diagnostics': 2.0.3 - async: 3.2.6 - is-stream: 2.0.1 - logform: 2.7.0 - one-time: 1.0.0 - readable-stream: 3.6.2 - safe-stable-stringify: 2.5.0 - stack-trace: 0.0.10 - triple-beam: 1.4.1 - winston-transport: 4.9.0 - - wrap-ansi@6.2.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@7.0.0: - dependencies: - ansi-styles: 4.3.0 - string-width: 4.2.3 - strip-ansi: 6.0.1 - - wrap-ansi@8.1.0: - dependencies: - ansi-styles: 6.2.1 - string-width: 5.1.2 - strip-ansi: 7.1.0 - - wrappy@1.0.2: {} - - ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10): - optionalDependencies: - bufferutil: 4.0.9 - utf-8-validate: 5.0.10 - - ws@8.17.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): - optionalDependencies: - bufferutil: 4.0.9 - utf-8-validate: 5.0.10 - - ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): - optionalDependencies: - bufferutil: 4.0.9 - utf-8-validate: 5.0.10 - - ws@8.18.2(bufferutil@4.0.9)(utf-8-validate@5.0.10): - optionalDependencies: - bufferutil: 4.0.9 - utf-8-validate: 5.0.10 - - x402-axios@0.4.2(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.0(react@18.3.1))(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10): - dependencies: - axios: 1.11.0 - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - x402: 0.4.3(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.0(react@18.3.1))(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10) - zod: 3.25.76 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - immer - - ioredis - - react - - supports-color - - typescript - - uploadthing - - utf-8-validate - - x402@0.4.3(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.0(react@18.3.1))(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10): - dependencies: - viem: 2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76) - wagmi: 2.16.1(@tanstack/query-core@5.83.1)(@tanstack/react-query@5.84.0(react@18.3.1))(@types/react@19.1.8)(bufferutil@4.0.9)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.3)(utf-8-validate@5.0.10)(viem@2.33.0(bufferutil@4.0.9)(typescript@5.8.3)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) - zod: 3.25.76 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - immer - - ioredis - - react - - supports-color - - typescript - - uploadthing - - utf-8-validate - - xmlbuilder@15.1.1: {} - - xmlhttprequest-ssl@2.1.2: {} - - xtend@4.0.2: {} - - y18n@4.0.3: {} - - y18n@5.0.8: {} - - yallist@3.1.1: {} - - yallist@4.0.0: {} - - yargs-parser@18.1.3: - dependencies: - camelcase: 5.3.1 - decamelize: 1.2.0 - - yargs-parser@21.1.1: {} - - yargs@15.4.1: - dependencies: - cliui: 6.0.0 - decamelize: 1.2.0 - find-up: 4.1.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - require-main-filename: 2.0.0 - set-blocking: 2.0.0 - string-width: 4.2.3 - which-module: 2.0.1 - y18n: 4.0.3 - yargs-parser: 18.1.3 - - yargs@17.7.2: - dependencies: - cliui: 8.0.1 - escalade: 3.2.0 - get-caller-file: 2.0.5 - require-directory: 2.1.1 - string-width: 4.2.3 - y18n: 5.0.8 - yargs-parser: 21.1.1 - - yauzl@2.10.0: - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 - - yocto-queue@0.1.0: {} - - zod-to-json-schema@3.24.6(zod@3.25.76): - dependencies: - zod: 3.25.76 - - zod@3.22.4: {} - - zod@3.25.76: {} - - zustand@5.0.0(@types/react@19.1.8)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)): - optionalDependencies: - '@types/react': 19.1.8 - react: 18.3.1 - use-sync-external-store: 1.4.0(react@18.3.1) - - zustand@5.0.3(@types/react@19.1.8)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)): - optionalDependencies: - '@types/react': 19.1.8 - react: 18.3.1 - use-sync-external-store: 1.4.0(react@18.3.1) - - zustand@5.0.6(@types/react@19.1.8)(react@18.3.1)(use-sync-external-store@1.4.0(react@18.3.1)): - optionalDependencies: - '@types/react': 19.1.8 - react: 18.3.1 - use-sync-external-store: 1.4.0(react@18.3.1) diff --git a/examples/typescript/legacy/mcp-embedded-wallet/preload.js b/examples/typescript/legacy/mcp-embedded-wallet/preload.js deleted file mode 100644 index b612c91cf4..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/preload.js +++ /dev/null @@ -1,55 +0,0 @@ -const { contextBridge, ipcRenderer } = require("electron"); - -contextBridge.exposeInMainWorld("electron", { - ipcRenderer: { - invoke: (channel, ...args) => ipcRenderer.invoke(channel, ...args), - on: (channel, func) => { - ipcRenderer.on(channel, (event, ...args) => func(...args)); - }, - once: (channel, func) => { - ipcRenderer.once(channel, (event, ...args) => func(...args)); - }, - send: (channel, ...args) => ipcRenderer.send(channel, ...args), - }, - OnSignMessage: callback => - ipcRenderer.on("sign-message", (_event, message) => { - callback(message).then(signature => { - console.log("sign-message-response", signature); - ipcRenderer.send("sign-message-response", signature); - }); - }), - - OnDiscoveryList: callback => - ipcRenderer.on("discovery-list", _event => { - callback().then(items => { - console.log("discovery-list-response", items); - ipcRenderer.send("discovery-list-response", items); - }); - }), - - OnMakeX402Request: callback => - ipcRenderer.on("make-x402-request", (_event, params) => { - callback(params) - .then(result => { - console.log("make-x402-request-response", result); - ipcRenderer.send("make-x402-request-response", result); - }) - .catch(error => { - console.error("make-x402-request-error", error); - ipcRenderer.send("make-x402-request-response", { error: error.message }); - }); - }), - - OnGetWalletAddress: callback => - ipcRenderer.on("get-wallet-address", _event => { - callback() - .then(address => { - console.log("get-wallet-address-response", address); - ipcRenderer.send("get-wallet-address-response", address); - }) - .catch(error => { - console.error("get-wallet-address-error", error); - ipcRenderer.send("get-wallet-address-response", { error: error.message }); - }); - }), -}); diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/.eslintrc.json b/examples/typescript/legacy/mcp-embedded-wallet/src/.eslintrc.json deleted file mode 100644 index 1cb47f426c..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/.eslintrc.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "parser": "@typescript-eslint/parser", - "extends": [ - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "plugin:prettier/recommended", - "plugin:jsdoc/recommended", - "plugin:import/recommended", - "plugin:import/typescript", - "plugin:react/recommended", - "plugin:react/jsx-runtime", - "plugin:react-hooks/recommended", - "plugin:css-modules/recommended" - ], - "plugins": ["@typescript-eslint", "prettier", "import", "unused-imports", "css-modules"], - "env": { - "es6": true - }, - "parserOptions": { - "ecmaVersion": 2020, - "sourceType": "module" - }, - "rules": { - "multiline-comment-style": ["error", "starred-block"], - "prettier/prettier": "error", - "@typescript-eslint/member-ordering": "error", - "import/order": [ - "error", - { - "groups": [ - "builtin", - "external", - "internal", - ["parent", "sibling"], - "index", - "object", - "type" - ], - "newlines-between": "always", - "alphabetize": { - "order": "asc", - "caseInsensitive": true - } - } - ], - - // Unused imports rules - "no-unused-vars": "off", // Turned off as unused-imports/no-unused-vars will handle this - "@typescript-eslint/no-unused-vars": "off", // Turned off as unused-imports/no-unused-vars will handle this - "unused-imports/no-unused-imports": "error", - "unused-imports/no-unused-vars": [ - "error", - { - "vars": "all", - "varsIgnorePattern": "^_", - "args": "after-used", - "argsIgnorePattern": "^_", - "caughtErrors": "all", - "caughtErrorsIgnorePattern": "^_" - } - ] - }, - "overrides": [ - { - "files": ["src/index.ts"], - "rules": { - "no-restricted-syntax": [ - "error", - { - "selector": "ExportAllDeclaration", - "message": "Export * statements are not allowed. Use named exports instead." - } - ] - } - } - ], - "ignorePatterns": [ - "**/*.test.tsx", - "**/*.test.ts" - ], - "settings": { - "import/resolver": { - "node": { - "extensions": [".js", ".jsx", ".ts", ".tsx"] - } - }, - "typescript": { - "project": "./tsconfig.json" - } - } -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/.prettierrc b/examples/typescript/legacy/mcp-embedded-wallet/src/.prettierrc deleted file mode 100644 index fae203e568..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/.prettierrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": false, - "trailingComma": "all", - "bracketSpacing": true, - "arrowParens": "avoid", - "printWidth": 100, - "proseWrap": "never" -} \ No newline at end of file diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/App.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/App.tsx deleted file mode 100644 index 13292e3377..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/App.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import { useEvmAddress, useIsSignedIn } from "@coinbase/cdp-hooks"; -import { SignIn } from "@coinbase/cdp-react"; -import { OperationsList } from "./components/OperationsList"; -import { Header } from "./components/Header"; -import { Box, Flex } from "@radix-ui/themes"; - -/** - * Root application component that handles authentication state and layout. - * Shows sign-in screen when not authenticated, or the main app interface when signed in. - * - * @returns {JSX.Element} The rendered application component - */ -export function App() { - const signedIn = useIsSignedIn(); - const { evmAddress: address } = useEvmAddress(); - - return ( - - {signedIn && address ? ( - -
- - - ) : ( - - - - )} - - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/ChainProvider.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/ChainProvider.tsx deleted file mode 100644 index a02bca716b..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/ChainProvider.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import { createContext, useContext, ReactNode } from "react"; -import { Chain } from "viem"; -import { base, baseSepolia } from "viem/chains"; - -export type SupportedChainId = "base" | "base-sepolia"; - -type ChainContextType = Chain; - -const ChainContext = createContext(undefined); - -interface ChainProviderProps { - children: ReactNode; - chain: SupportedChainId; -} - -/** - * Provider component that manages the current blockchain chain context. - * Makes the selected chain configuration available to child components. - * - * @param root0 - Component props - * @param root0.children - Child components that will have access to the chain context - * @param root0.chain - The selected chain identifier (base or base-sepolia) - * @returns {JSX.Element} The provider component with its children - */ -export function ChainProvider({ children, chain }: ChainProviderProps) { - const viemChain: Chain = chain === "base" ? base : baseSepolia; - - return {children}; -} - -/** - * Hook to access the current blockchain chain configuration from the ChainProvider context. - * Must be used within a ChainProvider component. - * - * @returns {Chain} The current chain configuration - * @throws {Error} If used outside of a ChainProvider - */ -export function useChain(): ChainContextType { - const context = useContext(ChainContext); - if (context === undefined) { - throw new Error("useChain must be used within a ChainProvider"); - } - return context; -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/cdpConfig.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/cdpConfig.ts deleted file mode 100644 index b911b2842d..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/cdpConfig.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Config } from "@coinbase/cdp-hooks"; - -export const CDP_CONFIG: Config = { - projectId: import.meta.env.VITE_CDP_PROJECT_ID, - basePath: import.meta.env.VITE_CDP_BASE_PATH, - useMock: import.meta.env.VITE_USE_MOCK === "true", -}; - -export const APP_CONFIG = { - name: "x402 MCP", // the name of your application - logoUrl: "https://picsum.photos/64", // logo will be displayed in select components -}; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/BudgetModal/BudgetModal.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/BudgetModal/BudgetModal.tsx deleted file mode 100644 index d0fbae5b60..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/BudgetModal/BudgetModal.tsx +++ /dev/null @@ -1,237 +0,0 @@ -"use client"; - -import { useState, useEffect, ChangeEvent } from "react"; -import { Dialog, Flex, IconButton, Text, Card, TextField } from "@radix-ui/themes"; - -import { Cross2Icon } from "@radix-ui/react-icons"; -import { useEvmAddress } from "@coinbase/cdp-hooks"; -import { useBudgetStore } from "../../stores/budget"; -import { formatUSDC, parseUSDC } from "../../utils/chainConfig"; -import { Button } from "../Button"; - -interface BudgetModalProps { - isOpen: boolean; - onClose?: () => void; -} - -/** - * Budget configuration modal for setting session budget and per-operation limit. - * - * @param {object} root0 - Props object. - * @param {boolean} root0.isOpen - Whether the modal is open. - * @param {() => void} [root0.onClose] - Optional close handler. - * @returns {JSX.Element | null} Modal content when open, otherwise null. - */ -export function BudgetModal({ isOpen, onClose }: BudgetModalProps) { - const { evmAddress: fromAddress } = useEvmAddress(); - const sessionBudgetAtomic = useBudgetStore(state => state.sessionBudgetAtomic); - const setSessionBudgetAtomic = useBudgetStore(state => state.setSessionBudgetAtomic); - const perRequestMaxAtomic = useBudgetStore(state => state.perRequestMaxAtomic); - const setPerRequestMaxAtomic = useBudgetStore(state => state.setPerRequestMaxAtomic); - - // Local display values in USDC (human units) - const [sessionBudgetDisplay, setSessionBudgetDisplay] = useState(""); - const [perRequestMaxDisplay, setPerRequestMaxDisplay] = useState(""); - const [sessionBudgetError, setSessionBudgetError] = useState(null); - const [perRequestMaxError, setPerRequestMaxError] = useState(null); - const [sessionBudgetSuccess, setSessionBudgetSuccess] = useState(false); - const [perRequestMaxSuccess, setPerRequestMaxSuccess] = useState(false); - - const handleSessionBudgetChange = (e: ChangeEvent) => { - setSessionBudgetDisplay(e.target.value); - setSessionBudgetError(null); - }; - - const handlePerRequestMaxChange = (e: ChangeEvent) => { - setPerRequestMaxDisplay(e.target.value); - setPerRequestMaxError(null); - }; - - const resetForm = () => { - setSessionBudgetDisplay(sessionBudgetAtomic ? formatUSDC(sessionBudgetAtomic) : ""); - setPerRequestMaxDisplay(perRequestMaxAtomic ? formatUSDC(perRequestMaxAtomic) : ""); - }; - - const handleClose = () => { - resetForm(); - onClose?.(); - }; - - const validateSessionBudget = (): boolean => { - // Validate session budget - const sessionAtomic = parseUSDC(sessionBudgetDisplay); - if (!sessionAtomic) { - setSessionBudgetError("Enter a valid session budget"); - return false; - } - if (BigInt(sessionAtomic) <= 0n) { - setSessionBudgetError("Session budget must be greater than 0"); - return false; - } - setSessionBudgetError(null); - return true; - }; - - const validatePerRequestMax = (): boolean => { - // Validate per-request max - const perReqAtomic = parseUSDC(perRequestMaxDisplay); - if (!perReqAtomic) { - setPerRequestMaxError("Enter a valid max amount per operation"); - return false; - } - if (BigInt(perReqAtomic) <= 0n) { - setPerRequestMaxError("Max amount per operation must be greater than 0"); - return false; - } - if (BigInt(perReqAtomic) > BigInt(sessionBudgetAtomic ?? 0n)) { - setPerRequestMaxError("Max per operation cannot exceed the session budget"); - return false; - } - - setPerRequestMaxError(null); - return true; - }; - - const handleSaveSessionBudget = async () => { - if (!validateSessionBudget() || !fromAddress) return; - - setSessionBudgetError(null); - - try { - const sessionAtomic = parseUSDC(sessionBudgetDisplay); - if (!sessionAtomic) return; - - setSessionBudgetAtomic(sessionAtomic); - } catch (err) { - console.error("Error saving session budget:", err); - } finally { - setSessionBudgetSuccess(true); - } - }; - - const handleSavePerRequestMax = async () => { - if (!validatePerRequestMax() || !fromAddress) return; - - setPerRequestMaxError(null); - - try { - const perReqAtomic = parseUSDC(perRequestMaxDisplay); - if (!perReqAtomic) return; - - setPerRequestMaxAtomic(perReqAtomic); - } catch (err) { - console.error("Error saving per-request max:", err); - } finally { - setPerRequestMaxSuccess(true); - } - }; - - // Auto-reset success states after 1s so button text returns to "Save" - useEffect(() => { - if (!sessionBudgetSuccess) return; - const timeoutId = setTimeout(() => setSessionBudgetSuccess(false), 1000); - return () => clearTimeout(timeoutId); - }, [sessionBudgetSuccess]); - - useEffect(() => { - if (!perRequestMaxSuccess) return; - const timeoutId = setTimeout(() => setPerRequestMaxSuccess(false), 1000); - return () => clearTimeout(timeoutId); - }, [perRequestMaxSuccess]); - - // Initialize display values when modal opens or store values change - useEffect(() => { - if (!isOpen) return; - setSessionBudgetDisplay(sessionBudgetAtomic ? formatUSDC(sessionBudgetAtomic) : ""); - setPerRequestMaxDisplay(perRequestMaxAtomic ? formatUSDC(perRequestMaxAtomic) : ""); - }, [isOpen, sessionBudgetAtomic, perRequestMaxAtomic]); - - if (!isOpen) return null; - - return ( - - - Set spending rules - - - - - - - - - - - - - Session budget - - - The amount of USDC you are willing to spend in this session. - - - - - - $ - - - USDC - - - - - {sessionBudgetError && ( - - {sessionBudgetError} - - )} - - - - - - - - - - Max amount per operation - - - The maximum amount of USDC you are willing to spend per operation. - - - - - - $ - - - USDC - - - - - {perRequestMaxError && ( - - {perRequestMaxError} - - )} - - - - - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/BudgetModal/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/BudgetModal/index.ts deleted file mode 100644 index 9c6588a1c4..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/BudgetModal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { BudgetModal } from "./BudgetModal"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Button/Button.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/Button/Button.tsx deleted file mode 100644 index 53a893ccf7..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Button/Button.tsx +++ /dev/null @@ -1,14 +0,0 @@ -import React from "react"; -import { Button as RadixButton, ButtonProps } from "@radix-ui/themes"; - -export const Button = React.forwardRef, ButtonProps>( - ({ children, ...props }, ref) => { - return ( - - {children} - - ); - }, -); - -Button.displayName = "Button"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Button/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/Button/index.ts deleted file mode 100644 index e22c29adcf..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Button/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./Button"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/DiscoveryModal/DiscoveryModal.module.css b/examples/typescript/legacy/mcp-embedded-wallet/src/components/DiscoveryModal/DiscoveryModal.module.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/DiscoveryModal/DiscoveryModal.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/DiscoveryModal/DiscoveryModal.tsx deleted file mode 100644 index dcd41e3202..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/DiscoveryModal/DiscoveryModal.tsx +++ /dev/null @@ -1,267 +0,0 @@ -"use client"; - -import { useEffect, useState } from "react"; -import { - ChevronDownIcon, - ChevronUpIcon, - CopyIcon, - CheckIcon, - ClipboardCopyIcon, - Cross2Icon, -} from "@radix-ui/react-icons"; -import { - Badge, - Card, - Dialog, - Flex, - Heading, - IconButton, - Table, - Text, - Tooltip, -} from "@radix-ui/themes"; -import { getDiscoveryList } from "../../services/discovery"; -import { Button } from "../Button"; - -interface DiscoveryItem { - type: string; - resource: string; - x402Version: number; - accepts: Array<{ - scheme: "exact"; - description: string; - network: "base-sepolia" | "base"; - maxAmountRequired: string; - resource: string; - mimeType: string; - payTo: string; - maxTimeoutSeconds: number; - asset: string; - outputSchema?: Record; - extra?: Record; - }>; - lastUpdated: string; - metadata?: Record; -} - -interface DiscoveryResponse { - x402Version: number; - items: DiscoveryItem[]; - pagination: { - limit: number; - offset: number; - total: number; - }; -} - -interface DiscoveryModalProps { - isOpen: boolean; - onClose?: () => void; -} - -/** - * Modal component that displays a list of discovered x402 resources and their payment requirements. - * Allows users to view detailed information about each resource, copy asset addresses, and generate prompts. - * - * @param root0 - Component props - * @param root0.isOpen - Whether the modal is currently visible - * @param root0.onClose - Optional callback function to handle modal close events - * @returns {JSX.Element | null} The modal component when open, null when closed - */ -export function DiscoveryModal({ isOpen, onClose }: DiscoveryModalProps) { - const [items, setItems] = useState([]); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [expandedItems, setExpandedItems] = useState>({}); - const [copiedAssets, setCopiedAssets] = useState>({}); - const [copiedPrompt, setCopiedPrompt] = useState>({}); - - useEffect(() => { - if (isOpen) { - loadDiscoveryItems(); - } - }, [isOpen]); - - const loadDiscoveryItems = async () => { - setLoading(true); - setError(null); - try { - const response = (await getDiscoveryList()) as DiscoveryResponse; - setItems(response.items); - } catch (err) { - setError("Failed to load discovery items"); - console.error(err); - } finally { - setLoading(false); - } - }; - - const toggleExpand = (resource: string) => { - setExpandedItems(prev => ({ - ...prev, - [resource]: !prev[resource], - })); - }; - - const copyToClipboard = (text: string, key: string) => { - navigator.clipboard.writeText(text); - - if (key.startsWith("asset:")) { - setCopiedAssets(prev => ({ ...prev, [key.replace("asset:", "")]: true })); - setTimeout(() => { - setCopiedAssets(prev => ({ ...prev, [key.replace("asset:", "")]: false })); - }, 2000); - } else if (key.startsWith("prompt:")) { - setCopiedPrompt(prev => ({ ...prev, [key.replace("prompt:", "")]: true })); - setTimeout(() => { - setCopiedPrompt(prev => ({ ...prev, [key.replace("prompt:", "")]: false })); - }, 2000); - } - }; - - const truncateAddress = (address: string) => { - if (!address || address.length < 10) return address; - return `${address.slice(0, 6)}...${address.slice(-4)}`; - }; - - const generatePrompt = (item: DiscoveryItem, acceptIndex: number) => { - const accept = item.accepts[acceptIndex]; - const promptText = `Make an HTTP request to ${ - item.resource - } using the following request structure: ${ - accept.outputSchema?.input - ? JSON.stringify(accept.outputSchema.input, null, 2) - : "No input schema provided" - }. Full metadata about the resource is: ${JSON.stringify(item, null, 2)}`; - - return promptText; - }; - - const handleCopyPrompt = (item: DiscoveryItem, acceptIndex: number) => { - const promptText = generatePrompt(item, acceptIndex); - copyToClipboard(promptText, `prompt:${item.resource}-${acceptIndex}`); - }; - - if (!isOpen) return null; - - return ( - <> - - Discovered Resources - onClose?.()}> - - - - - - {loading && Loading...} - {error && {error}} - - {items.map(item => ( - - - - - {item.resource} - - {item.accepts[0].description && {item.accepts[0].description}} - - - - {item.type.toUpperCase()} - - - {item.accepts[0].network.toUpperCase()} - - - - - - {expandedItems[item.resource] && ( - <> - - Accepts - - - {item.accepts.length > 0 ? ( - - - - Network - Scheme - Amount - Asset - {/* Only show description column if it differs from resource description */} - {item.accepts.some( - a => a.description !== item.accepts[0].description, - ) && Description} - Actions - - - - {item.accepts.map((accept, index) => ( - - {accept.network} - {accept.scheme} - {accept.maxAmountRequired} - - {accept.asset}

}> - - {truncateAddress(accept.asset || "")} - - -
-
- - Copy prompt to clipboard

}> - -
-
-
- ))} -
-
- ) : ( - No accept entries available - )} -
- - )} -
- ))} -
- - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/DiscoveryModal/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/DiscoveryModal/index.ts deleted file mode 100644 index 8d2cca6785..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/DiscoveryModal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./DiscoveryModal"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/GroupedOperation/GroupedOperation.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/GroupedOperation/GroupedOperation.tsx deleted file mode 100644 index 7de974b69b..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/GroupedOperation/GroupedOperation.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { useState } from "react"; -import { Card, Flex, Text, Box } from "@radix-ui/themes"; -import { ChevronDownIcon, ChevronRightIcon } from "@radix-ui/react-icons"; -import { Operation } from "../../stores/operations"; -import { HttpOperationDetails, WalletOperationDetails } from "../OperationDetails"; -import { - getPaymentAmount, - getGroupStatus, - getTargetUrl, - getStatusText, -} from "../../utils/x402Utils"; -import { OperationBadge } from "../OperationBadge"; - -type GroupedOperationProps = { - operations: Operation[]; -}; - -/** - * Renders the appropriate operation details component based on the operation type. - * - * @param operation - The operation to render details for - * @param allOperations - All operations in the current group for context - * @returns {JSX.Element | undefined} The rendered operation details component - */ -function renderOperationDetails(operation: Operation, allOperations: Operation[]) { - if (operation.type === "http") { - return ; - } else if (operation.type === "wallet") { - return ; - } -} - -/** - * A collapsible component that displays a group of related operations. - * Shows a summary of the operations' status and target URL when collapsed, - * and detailed information for each operation when expanded. - * - * @param root0 - Component props - * @param root0.operations - Array of operations that belong to the same group - * @returns {JSX.Element} The rendered grouped operations component - */ -export function GroupedOperation({ operations }: GroupedOperationProps) { - const [isExpanded, setIsExpanded] = useState(false); - - const paymentAmount = getPaymentAmount(operations); - const groupStatus = getGroupStatus(operations); - const targetUrl = getTargetUrl(operations); - const statusText = getStatusText(groupStatus, paymentAmount); - - // Sort operations by timestamp within the group - const sortedOperations = [...operations].sort( - (a, b) => a.timestamp.getTime() - b.timestamp.getTime(), - ); - - return ( - - setIsExpanded(!isExpanded)} - style={{ cursor: "pointer" }} - > - - - {statusText} {targetUrl !== "Unknown" ? `for ${new URL(targetUrl).pathname}` : ""} - - - {targetUrl !== "Unknown" ? `${new URL(targetUrl).hostname}` : ""} - - - - - {isExpanded ? : } - - - - {isExpanded && ( - - {sortedOperations.map((operation, index) => ( - - {renderOperationDetails(operation, operations)} - - ))} - - )} - - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/GroupedOperation/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/GroupedOperation/index.ts deleted file mode 100644 index 42b4087a71..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/GroupedOperation/index.ts +++ /dev/null @@ -1 +0,0 @@ -export { GroupedOperation } from "./GroupedOperation"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/Header.module.css b/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/Header.module.css deleted file mode 100644 index 1600470a11..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/Header.module.css +++ /dev/null @@ -1,13 +0,0 @@ -.spin { - animation: spin 1s linear; - transform-origin: center; -} - -@keyframes spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} \ No newline at end of file diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/Header.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/Header.tsx deleted file mode 100644 index 8aa50111fd..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/Header.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import { useEvmAddress, useIsSignedIn } from "@coinbase/cdp-hooks"; -import { useState } from "react"; -import { DiscoveryModal } from "../DiscoveryModal"; -import { Dialog, Flex } from "@radix-ui/themes"; - -import { Button } from "../Button"; -import { SessionSpendingTracker } from "../SessionSpendingTracker"; -import { TestX402Button } from "./TestX402Button"; -import { Wallet } from "../Wallet"; - -export const Header = () => { - const signedIn = useIsSignedIn(); - const { evmAddress: address } = useEvmAddress(); - - const [isDiscoveryOpen, setIsDiscoveryOpen] = useState(false); - - return ( - signedIn && - address && ( - - - - - - - - - - - - setIsDiscoveryOpen(false)} /> - - - {process.env.NODE_ENV === "development" && } - - - ) - ); -}; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/TestX402Button.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/TestX402Button.tsx deleted file mode 100644 index c56fcdd05c..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/TestX402Button.tsx +++ /dev/null @@ -1,29 +0,0 @@ -import { Button } from "../Button"; -import { makeX402Request } from "../../utils/x402Client"; - -/** - * Button to send a test x402 request to the demo endpoint. - * - * @returns {JSX.Element} Rendered test button. - */ -export function TestX402Button() { - const handleTestX402 = async () => { - try { - await makeX402Request({ - baseURL: "https://x402-demo-discovery-endpoint.vercel.app", - path: "/protected", - method: "GET", - correlationId: `manual-test-${Date.now()}`, - }); - } catch (e) { - // Errors will be reflected in the Operations list via existing handlers - console.error(e); - } - }; - - return ( - - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/index.ts deleted file mode 100644 index 9e08a64dbf..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Header/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./Header"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationBadge/OperationBadge.module.css b/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationBadge/OperationBadge.module.css deleted file mode 100644 index d232c3e47b..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationBadge/OperationBadge.module.css +++ /dev/null @@ -1,3 +0,0 @@ -.badge { - font-variant: small-caps; -} \ No newline at end of file diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationBadge/OperationBadge.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationBadge/OperationBadge.tsx deleted file mode 100644 index 0989a43096..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationBadge/OperationBadge.tsx +++ /dev/null @@ -1,178 +0,0 @@ -import { Badge } from "@radix-ui/themes"; -import { Operation, HttpOperation } from "../../stores/operations"; -import styles from "./OperationBadge.module.css"; - -/** - * Determines if an HTTP operation represents the initial 402 discovery request. - * Checks for 402 error status, payment requirements, and if it's the first operation in its correlation group. - * - * @param operation - The HTTP operation to check - * @param allOperations - All operations in the group for correlation checking - * @returns {boolean} True if this is the initial 402 discovery request - */ -export function isInitial402Discovery( - operation: HttpOperation, - allOperations: Operation[], -): boolean { - if (operation.status !== "error" || !operation.errorMessage?.includes("402")) { - return false; - } - - // Check if this operation has payment requirements (indicates 402 discovery) - if (!operation.paymentRequirements?.length) { - return false; - } - - // Check if this is the first operation in the correlation group - const correlatedOps = allOperations - .filter(op => op.correlationId === operation.correlationId) - .sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime()); - - return correlatedOps[0] === operation; -} - -/** - * Determines the overall status of a group of operations. - * Ignores expected 402 discovery operations and prioritizes errors over pending states. - * - * @param operations - Array of operations to check status for - * @returns {"success" | "error" | "pending"} The aggregated status of all operations - */ -function getGroupStatus(operations: Operation[]): "success" | "error" | "pending" { - // Filter out expected 402 discovery operations when determining group status - const significantOperations = operations.filter(op => { - // If it's an HTTP operation that's an initial 402 discovery, don't count it as an error - if (op.type === "http" && op.status === "error") { - return !isInitial402Discovery(op as HttpOperation, operations); - } - return true; - }); - - // Check for any actual errors (not including 402 discovery) - if (significantOperations.some(op => op.status === "error")) { - return "error"; - } - - // Check for pending operations - if (significantOperations.some(op => op.status === "pending")) { - return "pending"; - } - - return "success"; -} - -/** - * Gets the badge color and text for a single operation. - * Handles special case for 402 discovery operations and maps status to appropriate colors. - * - * @param operation - The operation to get badge info for - * @param allOperations - All operations in the group for 402 discovery checking - * @returns {{ color: "blue" | "green" | "red" | "orange"; text: string }} Badge display information - */ -function getOperationBadgeInfo( - operation: Operation, - allOperations: Operation[], -): { - color: "blue" | "green" | "red" | "orange"; - text: string; -} { - if ( - operation.type === "http" && - isInitial402Discovery(operation as HttpOperation, allOperations) - ) { - return { color: "blue", text: "payment required" }; - } - - const color = (() => { - switch (operation.status) { - case "success": - return "green"; - case "error": - return "red"; - default: - return "orange"; - } - })(); - return { color, text: operation.status }; -} - -/** - * Gets the badge color and text for a group of operations. - * Aggregates status of all operations and provides user-friendly status text. - * - * @param operations - Array of operations to get group badge info for - * @returns {{ color: "blue" | "green" | "red" | "orange"; text: string }} Badge display information - */ -function getGroupBadgeInfo(operations: Operation[]): { - color: "blue" | "green" | "red" | "orange"; - text: string; -} { - const groupStatus = getGroupStatus(operations); - - const color = (() => { - switch (groupStatus) { - case "success": - return "green"; - case "error": - return "red"; - default: - return "orange"; - } - })(); - - // More descriptive text for groups - const text = (() => { - switch (groupStatus) { - case "success": - return "completed"; - case "error": - return "failed"; - default: - return "in progress"; - } - })(); - - return { color, text }; -} - -type OperationBadgeProps = { - operation?: Operation; - operations?: Operation[]; - allOperations?: Operation[]; - variant?: "operation" | "group"; -}; - -/** - * A badge component that displays the status of either a single operation or a group of operations. - * Changes color and text based on operation status and handles special cases like 402 discovery. - * - * @param root0 - Component props - * @param root0.operation - Single operation to display status for (when variant is "operation") - * @param root0.operations - Array of operations to show group status for (when variant is "group") - * @param root0.allOperations - All operations in context for correlation checking - * @param root0.variant - Whether to show status for a single operation or group ("operation" | "group") - * @returns {JSX.Element} The rendered badge component - */ -export function OperationBadge({ - operation, - operations, - allOperations = [], - variant = "operation", -}: OperationBadgeProps) { - let badgeInfo: { color: "blue" | "green" | "red" | "orange"; text: string }; - - if (variant === "group" && operations) { - badgeInfo = getGroupBadgeInfo(operations); - } else if (variant === "operation" && operation) { - badgeInfo = getOperationBadgeInfo(operation, allOperations); - } else { - // Fallback - badgeInfo = { color: "orange", text: "unknown" }; - } - - return ( - - {badgeInfo.text} - - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationBadge/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationBadge/index.ts deleted file mode 100644 index d53b712854..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationBadge/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./OperationBadge"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationDetails/HttpOperationDetails.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationDetails/HttpOperationDetails.tsx deleted file mode 100644 index 9ecca5a720..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationDetails/HttpOperationDetails.tsx +++ /dev/null @@ -1,68 +0,0 @@ -import { Flex, Text, Link } from "@radix-ui/themes"; -import { ExternalLinkIcon } from "@radix-ui/react-icons"; -import { HttpOperation, Operation } from "../../stores/operations"; -import { OperationBadge, isInitial402Discovery } from "../OperationBadge"; -import { getBlockExplorerUrl, formatUSDC } from "../../utils/chainConfig"; - -type HttpOperationDetailsProps = { - operation: HttpOperation; - allOperations: Operation[]; -}; - -/** - * Component that displays detailed information about an HTTP operation. - * Shows the operation description, status, URL, payment requirements, settlement info, and any errors. - * Handles special cases like 402 discovery responses. - * - * @param root0 - Component props - * @param root0.operation - The HTTP operation to display details for - * @param root0.allOperations - All operations in the group for context and 402 discovery checking - * @returns {JSX.Element} The rendered operation details component - */ -export function HttpOperationDetails({ operation, allOperations }: HttpOperationDetailsProps) { - return ( - - - - {operation.description} - - - - - {operation.method} {operation.url} - - {operation.paymentRequirements && ( - - Payment required: ${formatUSDC(operation.paymentRequirements[0].maxAmountRequired)} USDC - - )} - {operation.settlementInfo && ( - - Transaction:{" "} - - - {operation.settlementInfo.transaction.slice(0, 10)}... - - - {" "} - on {operation.settlementInfo.network} - - )} - - {operation.timestamp.toLocaleString()} - - {operation.errorMessage && !isInitial402Discovery(operation, allOperations) && ( - - Error: {operation.errorMessage} - - )} - - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationDetails/WalletOperationDetails.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationDetails/WalletOperationDetails.tsx deleted file mode 100644 index fd0e2b0baa..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationDetails/WalletOperationDetails.tsx +++ /dev/null @@ -1,72 +0,0 @@ -import { Flex, Text, Box, Link } from "@radix-ui/themes"; -import { ExternalLinkIcon } from "@radix-ui/react-icons"; -import { WalletOperation, Operation } from "../../stores/operations"; -import { OperationBadge } from "../OperationBadge"; - -type WalletOperationDetailsProps = { - operation: WalletOperation; - allOperations: Operation[]; -}; - -/** - * Component that displays detailed information about a wallet operation. - * Shows operation description, status, wallet address, messages, signatures, - * authorization data, transaction details, and any errors. - * - * @param root0 - Component props - * @param root0.operation - The wallet operation to display details for - * @param root0.allOperations - All operations in the group for context - * @returns {JSX.Element} The rendered wallet operation details component - */ -export function WalletOperationDetails({ operation, allOperations }: WalletOperationDetailsProps) { - return ( - - - - {operation.description} - - - - - Address: {operation.address} - - {operation.message && ( - - Message: {operation.message} - - )} - {operation.signature && ( - - Signature: {operation.signature.slice(0, 50)}...{operation.signature.slice(-10)} - - )} - {operation.authorizationData && ( - - - Authorization: {operation.authorizationData.value} units to{" "} - {operation.authorizationData.to.slice(0, 8)}... - - - )} - {operation.transactionHash && operation.blockExplorerUrl && ( - - Transaction:{" "} - - - {operation.transactionHash.slice(0, 10)}...{operation.transactionHash.slice(-10)} - - - - - )} - - {operation.timestamp.toLocaleString()} - - {operation.errorMessage && ( - - Error: {operation.errorMessage} - - )} - - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationDetails/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationDetails/index.ts deleted file mode 100644 index 2d2012cdd2..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationDetails/index.ts +++ /dev/null @@ -1,2 +0,0 @@ -export * from "./WalletOperationDetails"; -export * from "./HttpOperationDetails"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationsList/OperationsList.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationsList/OperationsList.tsx deleted file mode 100644 index a6a7cc6710..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationsList/OperationsList.tsx +++ /dev/null @@ -1,96 +0,0 @@ -import { useOperationStore, Operation } from "../../stores/operations"; -import { Card, Heading } from "@radix-ui/themes"; -import { GroupedOperation } from "../GroupedOperation"; -import { HttpOperationDetails, WalletOperationDetails } from "../OperationDetails"; - -/** - * Renders the appropriate operation details component based on operation type. - * Delegates rendering to either HttpOperationDetails or WalletOperationDetails. - * - * @param operation - The operation to render details for - * @param allOperations - All operations in the system for context - * @returns {JSX.Element | undefined} The rendered operation details component - */ -function renderOperationDetails(operation: Operation, allOperations: Operation[]) { - if (operation.type === "http") { - return ; - } else if (operation.type === "wallet") { - return ; - } -} - -/** - * Component that displays a chronological list of operations, both grouped and individual. - * Groups related operations by correlationId and sorts them by timestamp. - * Handles both HTTP and wallet operations, displaying them with appropriate details. - * - * @returns {JSX.Element} The rendered list of operations - */ -export function OperationsList() { - const operations = useOperationStore(state => state.operations); - - // Group operations by correlationId - const groupedOperations = new Map(); - const ungroupedOperations: Operation[] = []; - - operations.forEach(operation => { - if (operation.correlationId) { - if (!groupedOperations.has(operation.correlationId)) { - groupedOperations.set(operation.correlationId, []); - } - groupedOperations.get(operation.correlationId)!.push(operation); - } else { - ungroupedOperations.push(operation); - } - }); - - // Create a combined list of all operations (grouped and ungrouped) with timestamps - const allOperationItems: Array<{ - type: "group" | "single"; - timestamp: Date; - correlationId?: string; - operations?: Operation[]; - operation?: Operation; - }> = [ - // Add grouped operations - ...Array.from(groupedOperations.entries()).map(([correlationId, ops]) => ({ - type: "group" as const, - timestamp: ops.reduce((earliest, op) => (op.timestamp < earliest.timestamp ? op : earliest)) - .timestamp, - correlationId, - operations: ops, - })), - // Add ungrouped operations - ...ungroupedOperations.map(operation => ({ - type: "single" as const, - timestamp: operation.timestamp, - operation, - })), - ]; - - // Sort all items by timestamp (most recent first) - const sortedAllOperations = allOperationItems.sort( - (a, b) => b.timestamp.getTime() - a.timestamp.getTime(), - ); - - return ( -
- - Recent Operations - - - {/* Combined list of grouped and ungrouped operations */} - {sortedAllOperations.map((item, index) => { - if (item.type === "group") { - return ; - } else { - return ( - - {renderOperationDetails(item.operation!, operations)} - - ); - } - })} -
- ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationsList/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationsList/index.ts deleted file mode 100644 index 308a2b7d7d..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/OperationsList/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./OperationsList"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/ReceiveModal/ReceiveModal.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/ReceiveModal/ReceiveModal.tsx deleted file mode 100644 index 89eec76273..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/ReceiveModal/ReceiveModal.tsx +++ /dev/null @@ -1,72 +0,0 @@ -"use client"; - -import { Dialog, Flex, IconButton, Text, Card, Tooltip, Button } from "@radix-ui/themes"; -import { Cross2Icon, ClipboardCopyIcon, CheckIcon } from "@radix-ui/react-icons"; -import QRCode from "react-qr-code"; -import { useEvmAddress } from "@coinbase/cdp-hooks"; -import { useMemo, useState } from "react"; -import { useChain } from "../../ChainProvider"; - -interface ReceiveModalProps { - isOpen: boolean; - onClose?: () => void; -} - -/** - * Modal that displays a QR code and address for receiving assets. - * - * @param {object} root0 - Props object. - * @param {boolean} root0.isOpen - Whether the modal is open. - * @param {() => void} [root0.onClose] - Optional close handler. - * @returns {JSX.Element | null} Modal content when open, otherwise null. - */ -export function ReceiveModal({ isOpen, onClose }: ReceiveModalProps) { - const { evmAddress } = useEvmAddress(); - const [copied, setCopied] = useState(false); - const chain = useChain(); - const qrCodeValue = useMemo(() => { - if (!evmAddress) return ""; - return `ethereum:${evmAddress}@${chain.id}`; - }, [evmAddress, chain]); - - const handleCopy = () => { - if (!evmAddress) return; - navigator.clipboard.writeText(evmAddress); - setCopied(true); - setTimeout(() => setCopied(false), 1000); - }; - - if (!isOpen) return null; - - return ( - <> - - Receive Assets - - - - - - - - - - - Scan to receive - -
- -
- - {evmAddress} - - - - -
-
- - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/SessionSpendingTracker/SessionSpendingTracker.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/SessionSpendingTracker/SessionSpendingTracker.tsx deleted file mode 100644 index 70b5bb0643..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/SessionSpendingTracker/SessionSpendingTracker.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import { useMemo, useState } from "react"; -import { Text, Flex, Dialog } from "@radix-ui/themes"; -import { formatUSDC } from "../../utils/chainConfig"; -import { useBudgetStore } from "../../stores/budget"; -import { BudgetModal } from "../BudgetModal"; -import { Button } from "../Button"; - -export const SessionSpendingTracker = () => { - const sessionSpentAtomic = useBudgetStore(state => state.sessionSpentAtomic); - const sessionBudgetAtomic = useBudgetStore(state => state.sessionBudgetAtomic); - - const [isBudgetOpen, setIsBudgetOpen] = useState(false); - const totalSpent = useMemo(() => { - try { - return BigInt(sessionSpentAtomic || "0"); - } catch { - return 0n; - } - }, [sessionSpentAtomic]); - - const formattedRemaining = useMemo(() => { - if (!sessionBudgetAtomic) return null; - try { - const remaining = BigInt(sessionBudgetAtomic) - totalSpent; - if (remaining <= 0n) return "0.00"; - return formatUSDC(remaining.toString()); - } catch { - return null; - } - }, [sessionBudgetAtomic, totalSpent]); - - return ( - - - - - - - setIsBudgetOpen(false)} /> - - - - ); -}; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/SessionSpendingTracker/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/SessionSpendingTracker/index.ts deleted file mode 100644 index 05c2d6a9b4..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/SessionSpendingTracker/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./SessionSpendingTracker"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/SignIn.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/SignIn.tsx deleted file mode 100644 index 475aa14da2..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/SignIn.tsx +++ /dev/null @@ -1,146 +0,0 @@ -import React from "react"; -import { useSignInWithEmail, useVerifyEmailOTP } from "@coinbase/cdp-hooks"; -import { useCallback, useMemo, useState } from "react"; - -/** - * A multi-step authentication component that handles email-based sign-in flow. - * - * The component manages three states: - * 1. Initial state: Displays a welcome screen with a sign-in button - * 2. Email input: Collects and validates the user's email address - * 3. OTP verification: Validates the one-time password sent to the user's email - * - * Features: - * - Email validation using regex - * - 6-digit OTP validation - * - Loading states during API calls - * - Error handling for failed authentication attempts - * - Cancelable workflow with state reset - * - * @returns {JSX.Element} The rendered sign-in form component - */ -export default function SignIn() { - const [email, setEmail] = useState(""); - const [otp, setOtp] = useState(""); - const [flowId, setFlowId] = useState(""); - const [step, setStep] = useState<"email" | "otp">("email"); - const [isLoading, setIsLoading] = useState(false); - - const emailIsValid = useMemo(() => { - return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email); - }, [email]); - - const otpIsValid = useMemo(() => { - return otp.length === 6; - }, [otp]); - - const signIn = useSignInWithEmail(); - const verifyEmailOTP = useVerifyEmailOTP(); - - const handleEmailSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setIsLoading(true); - - try { - const { flowId } = await signIn({ - email, - }); - - setFlowId(flowId); - setIsLoading(false); - setStep("otp"); - } catch (error) { - console.error(error); - setIsLoading(false); - } - }; - - const handleOtpSubmit = async (e: React.FormEvent) => { - e.preventDefault(); - setIsLoading(true); - - try { - await verifyEmailOTP({ - flowId, - otp, - }); - - handleClose(); - } catch (error) { - console.error(error); - setIsLoading(false); - } - }; - - const handleClose = useCallback(() => { - setStep("email"); - setEmail(""); - setOtp(""); - setFlowId(""); - }, []); - - return ( -
- {step === "email" && ( -
-
-
- - setEmail(e.target.value)} - style={{ width: "100%", padding: "0.5rem" }} - /> -
- -
-
- )} - {step === "otp" && ( -
-
-
- - setOtp(e.target.value)} - required - style={{ width: "100%", padding: "0.5rem" }} - /> -
-

We sent a code to {email}

- - -
-
- )} -
- ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/SignOutButton/SignOutButton.module.css b/examples/typescript/legacy/mcp-embedded-wallet/src/components/SignOutButton/SignOutButton.module.css deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/SignOutButton/SignOutButton.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/SignOutButton/SignOutButton.tsx deleted file mode 100644 index da460ab170..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/SignOutButton/SignOutButton.tsx +++ /dev/null @@ -1,32 +0,0 @@ -import { useSignOut } from "@coinbase/cdp-hooks"; -import { type ReactNode } from "react"; - -import { Button } from "../Button"; - -export type SignOutButtonProps = { - children?: ReactNode; - onSuccess?: () => void; -}; - -/** - * A button component that handles user sign-out functionality. - * Uses CDP hooks for sign-out and supports custom content and success callback. - * - * @param root0 - Component props - * @param root0.children - Optional custom content to display in the button - * @param root0.onSuccess - Optional callback function to execute after successful sign-out - * @returns {JSX.Element} The rendered sign-out button component - */ -export function SignOutButton({ children, onSuccess }: SignOutButtonProps) { - const { signOut } = useSignOut(); - - const handleSignOut = async () => { - await signOut(); - onSuccess?.(); - }; - return ( - - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/SignOutButton/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/SignOutButton/index.ts deleted file mode 100644 index 7e1dee0e37..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/SignOutButton/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./SignOutButton"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Wallet/Wallet.module.css b/examples/typescript/legacy/mcp-embedded-wallet/src/components/Wallet/Wallet.module.css deleted file mode 100644 index b41c873acd..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Wallet/Wallet.module.css +++ /dev/null @@ -1,13 +0,0 @@ -.spin { - animation: spin 1s linear; - transform-origin: center; -} - -@keyframes spin { - from { - transform: rotate(0deg); - } - to { - transform: rotate(360deg); - } -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Wallet/Wallet.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/Wallet/Wallet.tsx deleted file mode 100644 index e2d73e402d..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Wallet/Wallet.tsx +++ /dev/null @@ -1,132 +0,0 @@ -import { useCurrentUser, useEvmAddress } from "@coinbase/cdp-hooks"; - -import { Dialog, Flex, Grid, Popover, Separator, Text, Tooltip } from "@radix-ui/themes"; -import { Button } from "../Button"; -import { - CheckIcon, - ClipboardCopyIcon, - ReloadIcon, - ArrowUpIcon, - ArrowDownIcon, -} from "@radix-ui/react-icons"; -import { useChain } from "../../ChainProvider"; -import { useUSDCBalance } from "../../utils/balanceChecker"; -import { useState } from "react"; -import styles from "./Wallet.module.css"; -import { SignOutButton } from "../SignOutButton"; -import { WithdrawModal } from "../WithdrawModal"; -import { ReceiveModal } from "../ReceiveModal/ReceiveModal"; - -/** - * A component that displays the user's connected wallet address. - * Uses CDP hooks to access the EVM address and displays it in a formatted layout. - * - * @returns {JSX.Element} Wallet popover with address, balance, and actions. - */ -export function Wallet() { - const { evmAddress } = useEvmAddress(); - const chain = useChain(); - const { formattedBalance, refreshBalance } = useUSDCBalance(evmAddress as `0x${string}`, chain); - - const { currentUser } = useCurrentUser(); - const email = currentUser?.authenticationMethods.email?.email; - const truncatedAddress = evmAddress ? `${evmAddress.slice(0, 10)}...${evmAddress.slice(-8)}` : ""; - - const [isSpinning, setIsSpinning] = useState(false); - const [isCopied, setIsCopied] = useState(false); - const copyIcon = isCopied ? : ; - - const [isWithdrawOpen, setIsWithdrawOpen] = useState(false); - const [isReceiveOpen, setIsReceiveOpen] = useState(false); - - const handleCopy = () => { - navigator.clipboard.writeText(evmAddress || ""); - setIsCopied(true); - setTimeout(() => setIsCopied(false), 1000); - }; - - const handleRefresh = () => { - setIsSpinning(true); - refreshBalance(); - // Reset spin state after animation completes - setTimeout(() => setIsSpinning(false), 1000); - }; - - return ( - - - - - e.preventDefault()}> - - - - Address - - - - {truncatedAddress} - - - - - - - - - Wallet balance - - - ${formattedBalance} USDC - - - - - - - - - - - - - - - setIsWithdrawOpen(false)} /> - - - - - - - - - setIsReceiveOpen(false)} /> - - - - - - - - - - - - - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Wallet/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/Wallet/index.ts deleted file mode 100644 index 7397bec794..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/Wallet/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./Wallet"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/WithdrawModal/WithdrawModal.module.css b/examples/typescript/legacy/mcp-embedded-wallet/src/components/WithdrawModal/WithdrawModal.module.css deleted file mode 100644 index 2affe980ba..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/WithdrawModal/WithdrawModal.module.css +++ /dev/null @@ -1,21 +0,0 @@ -.input { - width: calc(100% - 26px); - padding: 8px 12px; - margin-right: 26px; - border-radius: 6px; - border: 1px solid var(--gray-a7); - background-color: var(--color-page-background); - font-size: 14px; - line-height: 1.25; - color: var(--gray-12); - outline: none; -} - -.input:hover { - border-color: var(--gray-a8); -} - -.input:focus { - border-color: var(--gray-a8); - box-shadow: 0 0 0 1px var(--gray-a8); -} \ No newline at end of file diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/WithdrawModal/WithdrawModal.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/components/WithdrawModal/WithdrawModal.tsx deleted file mode 100644 index 8cc216f19d..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/WithdrawModal/WithdrawModal.tsx +++ /dev/null @@ -1,244 +0,0 @@ -"use client"; - -import { useState, useEffect, ChangeEvent } from "react"; -import { Dialog, Flex, IconButton, Text, Select, Button, Card, Link } from "@radix-ui/themes"; - -import { Cross2Icon } from "@radix-ui/react-icons"; -import { useEvmAddress } from "@coinbase/cdp-hooks"; -import { getBalance, sendWithdrawal, Asset } from "../../services/withdrawalService"; -import styles from "./WithdrawModal.module.css"; -import { Address } from "viem"; -import { useChain } from "../../ChainProvider"; -import { getBlockExplorerUrl } from "../../utils/chainConfig"; - -interface WithdrawModalProps { - isOpen: boolean; - onClose?: () => void; -} - -/** - * Modal component for withdrawing assets (ETH/USDC) to another address. - * Handles balance checking, input validation, transaction submission, and transaction tracking. - * Supports both ETH and USDC withdrawals with real-time balance updates. - * - * @param root0 - Component props - * @param root0.isOpen - Whether the withdrawal modal is currently visible - * @param root0.onClose - Optional callback function to handle modal close events - * @returns {JSX.Element | null} The rendered modal component when open, null when closed - */ -export function WithdrawModal({ isOpen, onClose }: WithdrawModalProps) { - const { evmAddress: fromAddress } = useEvmAddress(); - const [toAddress, setToAddress] = useState(""); - const [amount, setAmount] = useState(""); - const [selectedAsset, setSelectedAsset] = useState("ETH"); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(null); - const [txHash, setTxHash] = useState(null); - const [currentBalance, setCurrentBalance] = useState(null); - const [loadingBalance, setLoadingBalance] = useState(false); - - const resetForm = () => { - setToAddress(""); - setAmount(""); - setSelectedAsset("ETH"); - setError(null); - setTxHash(null); - setCurrentBalance(null); - }; - - const chain = useChain(); - - const fetchBalance = async () => { - if (!fromAddress || !chain) return; - - setLoadingBalance(true); - try { - const balance = await getBalance(fromAddress, selectedAsset, chain); - setCurrentBalance(balance); - } catch (err) { - console.error("Error fetching balance:", err); - setCurrentBalance(null); - } finally { - setLoadingBalance(false); - } - }; - - // Fetch balance when asset changes or modal opens - useEffect(() => { - if (isOpen && fromAddress) { - fetchBalance(); - // Reset amount when asset changes - setAmount(""); - } - }, [isOpen, selectedAsset, fromAddress]); - - const handleClose = () => { - resetForm(); - onClose?.(); - }; - - const validateForm = (): boolean => { - if (!toAddress) { - setError("To address is required"); - return false; - } - - if (!toAddress.match(/^0x[a-fA-F0-9]{40}$/)) { - setError("Invalid address format"); - return false; - } - - if (!amount || parseFloat(amount) <= 0) { - setError("Amount must be greater than 0"); - return false; - } - - return true; - }; - - const handleWithdraw = async () => { - if (!validateForm() || !fromAddress || !chain) return; - - setLoading(true); - setError(null); - - try { - // Check balance before withdrawal - const balance = await getBalance(fromAddress, selectedAsset, chain); - const amountNum = parseFloat(amount); - const balanceNum = parseFloat(balance); - - if (amountNum > balanceNum) { - throw new Error(`Insufficient ${selectedAsset} balance. Available: ${balance}`); - } - - // Send withdrawal transaction - const hash = await sendWithdrawal({ - toAddress: toAddress as Address, - amount, - asset: selectedAsset, - chain, - }); - - setTxHash(hash); - } catch (err) { - setError(err instanceof Error ? err.message : "Failed to process withdrawal"); - } finally { - setLoading(false); - } - }; - - if (!isOpen) return null; - - return ( - <> - - Send Assets - - - - - - - - - - - - From - - - {fromAddress} - - - - - - To - - ) => setToAddress(e.target.value)} - /> - - - - - Asset - - setSelectedAsset(value)} - > - - - ETH - USDC - - - - - - - Amount - - ) => setAmount(e.target.value)} - /> - - - {loadingBalance - ? "Loading balance..." - : currentBalance - ? `Available: ${currentBalance} ${selectedAsset}` - : "Unable to fetch balance"} - - {currentBalance && ( - - )} - - - - {error && ( - - {error} - - )} - - {txHash && ( - - - Transaction submitted - - - View on Block Explorer - - - )} - - - - - - ); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/components/WithdrawModal/index.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/components/WithdrawModal/index.ts deleted file mode 100644 index f86a30c0df..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/components/WithdrawModal/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from "./WithdrawModal"; diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/main.module.css b/examples/typescript/legacy/mcp-embedded-wallet/src/main.module.css deleted file mode 100644 index 71a6c3bd03..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/main.module.css +++ /dev/null @@ -1,77 +0,0 @@ -:root, .light, .light-theme { - --blue-1: #fcfdff; - --blue-2: #f5faff; - --blue-3: #eaf2ff; - --blue-4: #daeaff; - --blue-5: #c8e0ff; - --blue-6: #b3d2ff; - --blue-7: #98c0ff; - --blue-8: #73a5ff; - --blue-9: #0052ff; - --blue-10: #0148e0; - --blue-11: #0f54ec; - --blue-12: #0e2b6c; - - --blue-a1: #0055ff03; - --blue-a2: #0080ff0a; - --blue-a3: #0062ff15; - --blue-a4: #006fff25; - --blue-a5: #0070ff37; - --blue-a6: #0069ff4c; - --blue-a7: #0064ff67; - --blue-a8: #005bff8c; - --blue-a9: #0052ff; - --blue-a10: #0047e0fe; - --blue-a11: #0049ebf0; - --blue-a12: #001f63f1; - - --blue-contrast: #fff; - --blue-surface: #f3f9ffcc; - --blue-indicator: #0052ff; - --blue-track: #0052ff; - - --cursor-button: pointer; - } - - @supports (color: color(display-p3 1 1 1)) { - @media (color-gamut: p3) { - :root, .light, .light-theme { - --blue-1: oklch(99.4% 0.0022 262.9); - --blue-2: oklch(98.3% 0.011 262.9); - --blue-3: oklch(96.1% 0.0234 262.9); - --blue-4: oklch(93.6% 0.0459 262.9); - --blue-5: oklch(90.4% 0.0693 262.9); - --blue-6: oklch(86.3% 0.0958 262.9); - --blue-7: oklch(80.7% 0.1173 262.9); - --blue-8: oklch(73.1% 0.1538 262.9); - --blue-9: oklch(52.8% 0.2628 262.9); - --blue-10: oklch(48% 0.2374 262.9); - --blue-11: oklch(51.5% 0.2374 262.9); - --blue-12: oklch(31.4% 0.1182 262.9); - - --blue-a1: color(display-p3 0.0235 0.349 1 / 0.012); - --blue-a2: color(display-p3 0.0235 0.4588 0.8941 / 0.036); - --blue-a3: color(display-p3 0.0078 0.3569 0.9529 / 0.079); - --blue-a4: color(display-p3 0.0078 0.3569 0.9451 / 0.134); - --blue-a5: color(display-p3 0.0078 0.3647 0.9412 / 0.197); - --blue-a6: color(display-p3 0.0039 0.3451 0.9451 / 0.275); - --blue-a7: color(display-p3 0.0039 0.3294 0.949 / 0.373); - --blue-a8: color(display-p3 0 0.298 0.949 / 0.506); - --blue-a9: color(display-p3 0 0.2157 0.9529 / 0.871); - --blue-a10: color(display-p3 0 0.1882 0.8275 / 0.891); - --blue-a11: color(display-p3 0 0.2078 0.8706 / 0.851); - --blue-a12: color(display-p3 0 0.0863 0.3529 / 0.914); - - --blue-contrast: #fff; - --blue-surface: color(display-p3 0.9569 0.9725 1 / 0.8); - --blue-indicator: oklch(52.8% 0.2628 262.9); - --blue-track: oklch(52.8% 0.2628 262.9); - - --cursor-button: pointer; - } - } - } - -body { - margin: 0; -} \ No newline at end of file diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/main.tsx b/examples/typescript/legacy/mcp-embedded-wallet/src/main.tsx deleted file mode 100644 index 28176f06cb..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/main.tsx +++ /dev/null @@ -1,41 +0,0 @@ -import React from "react"; -import ReactDOM from "react-dom/client"; -import { CDPReactProvider } from "@coinbase/cdp-react"; -import { Theme } from "@radix-ui/themes"; - -import { App } from "./App"; -import { APP_CONFIG, CDP_CONFIG } from "./cdpConfig"; -import { ChainProvider } from "./ChainProvider"; -import { ElectronWindow } from "./window"; - -import { getDiscoveryList } from "./services/discovery"; -import { getWalletAddress, signMessage } from "./services/walletService"; - -import { makeX402Request } from "./utils/x402Client"; - -import "@radix-ui/themes/styles.css"; -import "./main.module.css"; - -const chain = import.meta.env.VITE_TESTNET ? "base-sepolia" : "base"; - -ReactDOM.createRoot(document.getElementById("root")!).render( - - - - - - - - - , -); - -/* -Set up callbacks for the main node process to communicate to the browser window for signing -*/ -declare let window: ElectronWindow; - -window.electron.OnSignMessage(signMessage); -window.electron.OnDiscoveryList(getDiscoveryList); -window.electron.OnMakeX402Request(makeX402Request); -window.electron.OnGetWalletAddress(getWalletAddress); diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/package.json b/examples/typescript/legacy/mcp-embedded-wallet/src/package.json deleted file mode 100644 index 1d403061ef..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "cdp-app-example", - "version": "0.0.1", - "type": "module", - "private": true, - "scripts": { - "dev": "vite", - "build": "tsc && vite build", - "serve": "vite preview", - "test": "vitest" - }, - "dependencies": { - "@coinbase/cdp-hooks": "workspace:*", - "@coinbase/cdp-react": "workspace:*", - "@coinbase/cdp-wagmi": "workspace:*", - "@mantine/core": "^8.1.1", - "@tabler/icons-react": "^3.34.0", - "@tanstack/react-query": "^5.81.2", - "@tanstack/react-router": "^1.123.2", - "react": "^18.2.0", - "react-dom": "^18.2.0", - "viem": "^2.31.3", - "wagmi": "^2.15.6" - }, - "devDependencies": { - "@tanstack/router-plugin": "^1.123.2", - "@types/react": "^18.2.43", - "@types/react-dom": "^18.2.17", - "@vitejs/plugin-react": "^4.2.1", - "jsdom": "^24.0.0", - "postcss": "^8.5.6", - "postcss-preset-mantine": "^1.17.0", - "postcss-simple-vars": "^7.0.1", - "typescript": "^5.8.3", - "vite": "^5.0.8", - "vitest": "^3.2.2" - } -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/services/discovery.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/services/discovery.ts deleted file mode 100644 index 9d973b446e..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/services/discovery.ts +++ /dev/null @@ -1,28 +0,0 @@ -import type { DiscoveryListResponse } from "../../electron"; - -declare global { - interface Window { - electron: { - ipcRenderer: { - invoke(channel: "get-discovery-list"): Promise; - invoke(channel: string, ...args: unknown[]): Promise; - }; - }; - } -} - -/** - * Fetches the list of available x402 discovery items through the Electron IPC bridge. - * Communicates with the main process to get the current discovery list. - * - * @returns {Promise} A promise that resolves to the discovery list response - * @throws {Error} If the discovery list fetch fails - */ -export async function getDiscoveryList(): Promise { - try { - return await window.electron.ipcRenderer.invoke("get-discovery-list"); - } catch (error) { - console.error("Failed to fetch discovery list:", error); - throw error; - } -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/services/walletService.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/services/walletService.ts deleted file mode 100644 index de8ec9e561..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/services/walletService.ts +++ /dev/null @@ -1,105 +0,0 @@ -import { signEvmMessage, getCurrentUser as getCDPUser } from "@coinbase/cdp-core"; -import { operationStore, AuthorizationData } from "../stores/operations"; -import { Address } from "viem"; - -/** - * Signs a message using the CDP SDK and tracks the operation in the store. - * Creates a pending operation, signs the message, and updates the operation status. - * - * @param message - The message to be signed - * @param correlationId - Optional ID to correlate this operation with others - * @param authorizationData - Optional payment authorization data for x402 - * @returns {Promise} The signature of the signed message - * @throws {Error} If signing fails or user is not found - */ -export async function signMessage( - message: string, - correlationId?: string, - authorizationData?: AuthorizationData, -): Promise { - // Get user address for the operation - const userAddress = await getWalletAddress(); - - // Add pending operation to store - operationStore.getState().addWalletOperation( - `Signing message: ${message}`, - "pending", - "sign", - userAddress, - message, - undefined, // signature (will be filled in after signing) - undefined, // errorMessage - correlationId, - authorizationData, - ); - - try { - // Sign the message using CDP SDK - const result = await signEvmMessage({ - evmAccount: userAddress as Address, - message, - }); - - // Update operation with success - operationStore - .getState() - .updateWalletOperation(operationStore.getState().operations.length - 1, { - description: `Message signed successfully`, - status: "success", - signature: result.signature, - }); - - return result.signature; - } catch (error) { - // Update operation with error - operationStore - .getState() - .updateWalletOperation(operationStore.getState().operations.length - 1, { - status: "error", - errorMessage: error instanceof Error ? error.message : "Unknown error", - }); - throw error; - } -} - -/** - * Specialized function for signing x402 payment authorizations. - * Converts authorization data to JSON and signs it, tracking the operation with specific x402 context. - * - * @param correlationId - ID to correlate this payment authorization with other operations - * @param authorizationData - Payment authorization details to be signed - * @returns {Promise} The signature of the payment authorization - * @throws {Error} If signing fails or user is not found - */ -export async function signX402Payment( - correlationId: string, - authorizationData: AuthorizationData, -): Promise { - // Use the regular signMessage function with X402 context - const message = JSON.stringify(authorizationData); - - // Sign the message with correlation context - const signature = await signMessage(message, correlationId, authorizationData); - - // Update the description to be more specific for X402 - operationStore.getState().updateWalletOperation(operationStore.getState().operations.length - 1, { - description: `Payment authorization signed successfully`, - }); - - return signature; -} - -/** - * Retrieves the user's EVM wallet address from CDP. - * Gets the first EVM account from the current CDP user. - * - * @returns {Promise} The user's EVM wallet address - * @throws {Error} If user is not found or CDP SDK is not initialized - */ -export async function getWalletAddress(): Promise { - const user = await getCDPUser(); - if (!user) { - throw new Error("User not found - CDP SDK may not be initialized"); - } - return user.evmAccounts?.[0] as Address; -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/services/withdrawalService.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/services/withdrawalService.ts deleted file mode 100644 index 5555eeb565..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/services/withdrawalService.ts +++ /dev/null @@ -1,152 +0,0 @@ -import { getCurrentUser, toViemAccount } from "@coinbase/cdp-core"; -import { - createPublicClient, - createWalletClient, - http, - parseAbi, - formatUnits, - parseUnits, - Address, - LocalAccount, - Chain, -} from "viem"; -import { CHAIN_CONFIGS } from "../utils/chainConfig"; - -export type Asset = "ETH" | "USDC"; - -/** - * Gets the token configuration for a specific asset on a given chain. - * Handles both native ETH and ERC20 tokens like USDC. - * - * @param chain - The blockchain chain to get asset config for - * @param asset - The asset type (ETH or USDC) - * @returns {{ address: Address; decimals: number }} The asset's address and decimal places - * @throws {Error} If chain or token is not supported - */ -function getAssetConfig(chain: Chain, asset: Asset): { address: Address; decimals: number } { - const chainConfig = Object.values(CHAIN_CONFIGS).find(config => config.id === chain.id); - if (!chainConfig) { - throw new Error(`Chain ${chain.name} (id: ${chain.id}) not supported`); - } - - if (asset === "ETH") { - return { - address: "0x0000000000000000000000000000000000000000" as Address, - decimals: chainConfig.nativeCurrency.decimals, - }; - } - - const token = chainConfig.tokens[asset]; - if (!token) { - throw new Error(`Token ${asset} not supported on ${chain.name}`); - } - - return { - address: token.address as Address, - decimals: token.decimals, - }; -} - -// ERC20 ABI for balance and transfer operations -const erc20Abi = parseAbi([ - "function balanceOf(address owner) view returns (uint256)", - "function decimals() view returns (uint8)", - "function transfer(address to, uint256 amount) returns (bool)", -]); - -export interface WithdrawalConfig { - toAddress: Address; - amount: string; - asset: Asset; - chain: Chain; -} - -/** - * Retrieves the balance of a specific asset for a given address on a chain. - * Handles both native ETH balance queries and ERC20 token balance checks. - * - * @param address - The address to check balance for - * @param asset - The asset type (ETH or USDC) to check - * @param chain - The blockchain chain to query - * @returns {Promise} The formatted balance with appropriate decimal places - * @throws {Error} If balance check fails or chain/token is not supported - */ -export async function getBalance(address: Address, asset: Asset, chain: Chain): Promise { - const assetConfig = getAssetConfig(chain, asset); - - const publicClient = createPublicClient({ - chain, - transport: http(), - }); - - try { - if (asset === "ETH") { - const balance = await publicClient.getBalance({ address }); - return formatUnits(balance, assetConfig.decimals); - } else { - const [rawBalance] = await Promise.all([ - publicClient.readContract({ - address: assetConfig.address, - abi: erc20Abi, - functionName: "balanceOf", - args: [address as Address], - }), - ]); - return formatUnits(rawBalance, assetConfig.decimals); - } - } catch (error) { - console.error("Error fetching balance:", error); - throw new Error(`Failed to fetch ${asset} balance on ${chain.name}`); - } -} - -/** - * Sends a withdrawal transaction for ETH or ERC20 tokens. - * Uses CDP for account access and viem for transaction handling. - * - * @param root0 - Withdrawal configuration object - * @param root0.toAddress - The recipient's address - * @param root0.amount - The amount to send (in human-readable format) - * @param root0.asset - The asset type (ETH or USDC) to send - * @param root0.chain - The blockchain chain to send on - * @returns {Promise<`0x${string}`>} The transaction hash - * @throws {Error} If transaction fails, user not found, or chain/token not supported - */ -export async function sendWithdrawal({ - toAddress, - amount, - asset, - chain, -}: WithdrawalConfig): Promise<`0x${string}`> { - const assetConfig = getAssetConfig(chain, asset); - const user = await getCurrentUser(); - if (!user?.evmAccounts?.[0]) { - throw new Error("No CDP user or EVM accounts found"); - } - - const account = await toViemAccount(user.evmAccounts[0]); - const walletClient = createWalletClient({ - account: account as LocalAccount, - chain, - transport: http(), - }); - - try { - if (asset === "ETH") { - return await walletClient.sendTransaction({ - to: toAddress as Address, - value: parseUnits(amount, assetConfig.decimals), - }); - } else { - return await walletClient.writeContract({ - address: assetConfig.address, - abi: erc20Abi, - functionName: "transfer", - args: [toAddress as Address, parseUnits(amount, assetConfig.decimals)], - }); - } - } catch (error) { - console.error("Error sending withdrawal:", error); - throw new Error(`Failed to send ${asset} withdrawal on ${chain.name}`); - } -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/stores/budget.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/stores/budget.ts deleted file mode 100644 index 2a532d3c0b..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/stores/budget.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { createStore } from "zustand/vanilla"; -import { useStore } from "zustand/react"; - -export interface BudgetStoreState { - perRequestMaxAtomic: string | null; - sessionBudgetAtomic: string | null; - sessionSpentAtomic: string; - setPerRequestMaxAtomic: (value: string | null) => void; - setSessionBudgetAtomic: (value: string | null) => void; - setSessionSpentAtomic: (value: string) => void; - addSpentAtomic: (value: string) => void; - resetSessionSpent: () => void; -} - -export const budgetStore = createStore(set => ({ - perRequestMaxAtomic: "50000", - sessionBudgetAtomic: "5000000", - sessionSpentAtomic: "0", - setPerRequestMaxAtomic: (value: string | null) => - set(state => ({ ...state, perRequestMaxAtomic: value })), - setSessionBudgetAtomic: (value: string | null) => - set(state => ({ ...state, sessionBudgetAtomic: value })), - setSessionSpentAtomic: (value: string) => set(state => ({ ...state, sessionSpentAtomic: value })), - addSpentAtomic: (value: string) => - set(state => { - const current = BigInt(state.sessionSpentAtomic || "0"); - const increment = BigInt(value); - const updated = (current + increment).toString(); - return { ...state, sessionSpentAtomic: updated }; - }), - resetSessionSpent: () => set(state => ({ ...state, sessionSpentAtomic: "0" })), -})); - -export const useBudgetStore = (selector: (state: BudgetStoreState) => T) => - useStore(budgetStore, selector); diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/stores/operations.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/stores/operations.ts deleted file mode 100644 index 603cadd33d..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/stores/operations.ts +++ /dev/null @@ -1,195 +0,0 @@ -import { createStore } from "zustand/vanilla"; -import { useStore } from "zustand/react"; - -type OperationStatus = "pending" | "success" | "error"; - -// X402 Payment Requirements (from 402 response) -export interface PaymentRequirements { - scheme: "exact"; - network: string; - maxAmountRequired: string; // Atomic units - resource: string; - description: string; - mimeType: string; - payTo: string; - maxTimeoutSeconds: number; - asset: string; // Token contract address - // eslint-disable-next-line @typescript-eslint/no-explicit-any - extra?: Record; -} - -// Settlement info (from X-PAYMENT-RESPONSE header) -export interface SettlementInfo { - success: boolean; - transaction: string; // Transaction hash - network: string; - payer: string; // Wallet address -} - -// EIP-3009 authorization data -export interface AuthorizationData { - from: string; - to: string; - value: string; - validAfter: string; - validBefore: string; - nonce: string; -} - -// Base operation properties shared by all operation types -interface BaseOperation { - description: string; - status: OperationStatus; - timestamp: Date; - correlationId?: string; // Links related operations together -} - -// HTTP/Protocol request operation -export interface HttpOperation extends BaseOperation { - type: "http"; - method: string; // GET, POST, etc. - url: string; // The full URL that was requested - errorMessage?: string; // Error details if status is "error" - - // X402 specific fields - maxAmountPerRequest?: number; // Max amount per request - paymentRequirements?: PaymentRequirements[]; // From 402 response 'accepts' - selectedPayment?: PaymentRequirements; // Which payment option was chosen - settlementInfo?: SettlementInfo; // From X-PAYMENT-RESPONSE header -} - -// Wallet action operation (signatures, etc.) -export interface WalletOperation extends BaseOperation { - type: "wallet"; - action: "sign" | "send" | "approve"; // Type of wallet action - address: string; // Wallet address - message?: string; // Message that was signed (for sign actions) - signature?: string; // Resulting signature (for sign actions) - errorMessage?: string; // Error details if status is "error" - - // X402 specific fields - authorizationData?: AuthorizationData; // EIP-3009 authorization that was signed - transactionHash?: string; // Transaction hash when payment is settled - blockExplorerUrl?: string; // Link to view transaction on block explorer -} - -// Union type for all operations -export type Operation = HttpOperation | WalletOperation; - -export interface OperationStore { - operationCount: number; - operations: Operation[]; - addHttpOperation: ( - description: string, - status: OperationStatus, - method: string, - url: string, - errorMessage?: string, - correlationId?: string, - maxAmountPerRequest?: number, - paymentRequirements?: PaymentRequirements[], - selectedPayment?: PaymentRequirements, - settlementInfo?: SettlementInfo, - ) => void; - addWalletOperation: ( - description: string, - status: OperationStatus, - action: "sign" | "send" | "approve", - address: string, - message?: string, - signature?: string, - errorMessage?: string, - correlationId?: string, - authorizationData?: AuthorizationData, - ) => void; - updateHttpOperation: (index: number, updates: Partial>) => void; - updateWalletOperation: (index: number, updates: Partial>) => void; -} - -// Create the store using createStore for better external access -export const operationStore = createStore(set => ({ - operationCount: 0, - operations: [], - - addHttpOperation: ( - description: string, - status: OperationStatus, - method: string, - url: string, - errorMessage?: string, - correlationId?: string, - maxAmountPerRequest?: number, - paymentRequirements?: PaymentRequirements[], - selectedPayment?: PaymentRequirements, - settlementInfo?: SettlementInfo, - ) => - set(state => ({ - operationCount: state.operationCount + 1, - operations: [ - ...state.operations, - { - type: "http", - description, - status, - timestamp: new Date(), - method, - url, - errorMessage, - correlationId, - maxAmountPerRequest, - paymentRequirements, - selectedPayment, - settlementInfo, - }, - ], - })), - - addWalletOperation: ( - description: string, - status: OperationStatus, - action: "sign" | "send" | "approve", - address: string, - message?: string, - signature?: string, - errorMessage?: string, - correlationId?: string, - authorizationData?: AuthorizationData, - ) => - set(state => ({ - operationCount: state.operationCount + 1, - operations: [ - ...state.operations, - { - type: "wallet", - description, - status, - timestamp: new Date(), - action, - address, - message, - signature, - errorMessage, - correlationId, - authorizationData, - }, - ], - })), - - updateHttpOperation: (index: number, updates: Partial>) => - set(state => ({ - operations: state.operations.map((operation, i) => - i === index && operation.type === "http" ? { ...operation, ...updates } : operation, - ), - })), - - updateWalletOperation: (index: number, updates: Partial>) => - set(state => ({ - operations: state.operations.map((operation, i) => - i === index && operation.type === "wallet" ? { ...operation, ...updates } : operation, - ), - })), -})); - -// Hook for React components -export const useOperationStore = (selector: (state: OperationStore) => T) => - useStore(operationStore, selector); diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/stores/x402_flow.md b/examples/typescript/legacy/mcp-embedded-wallet/src/stores/x402_flow.md deleted file mode 100644 index 30b39b7be0..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/stores/x402_flow.md +++ /dev/null @@ -1,355 +0,0 @@ -# X402 Payment Protocol Flow & Types Guide - -This guide explains the complete x402 request/response flow and type definitions for building an MCP (Model Context Protocol) server that interfaces with resource servers and handles x402 payments. - -## Overview - -The x402 protocol enables HTTP resources to require payment using the existing `402 Payment Required` status code. It's a two-phase protocol: **Discovery/Challenge** and **Payment/Settlement**. - -## Complete Request/Response Flow - -### Phase 1: Discovery & Payment Challenge - -#### 1.1 Initial Request (No Payment) -```http -GET /protected-resource HTTP/1.1 -Host: api.example.com -``` - -#### 1.2 Server Response (402 Payment Required) -```http -HTTP/1.1 402 Payment Required -Content-Type: application/json - -{ - "x402Version": 1, - "error": "X-PAYMENT header is required", - "accepts": [ - { - "scheme": "exact", - "network": "base-sepolia", - "maxAmountRequired": "1000000", // 1 USDC in atomic units (6 decimals) - "resource": "/protected-resource", - "description": "Access to premium API endpoint", - "mimeType": "application/json", - "payTo": "0x742d35Cc64C3E3b24a3A4c1537e2b68b5e04e7A2", - "maxTimeoutSeconds": 60, - "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // USDC contract - "extra": { - "name": "USDC", - "version": "2" - } - } - ] -} -``` - -### Phase 2: Payment & Settlement - -#### 2.1 Payment Request with X-PAYMENT Header -```http -GET /protected-resource HTTP/1.1 -Host: api.example.com -X-PAYMENT: eyJ4NDAyVmVyc2lvbiI6MSwic2NoZW1lIjoiZXhhY3QiLCJuZXR3b3JrIjoiYmFzZS1zZXBvbGlhIiwicGF5bG9hZCI6eyJzaWduYXR1cmUiOiIweDJkNmE3NTg4ZDZhY2NhNTA1Y2JmMGQ5YTRhMjI3ZTBjNTJjNmMzNDAwOGM4ZTg5ODZhMTI4MzI1OTc2NDE3MzYwOGEyY2U2NDk2NjQyZTM3N2Q2ZGE4ZGJiZjU4MzZlOWJkMTUwOTJmOWVjYWIwNWRlZDNkNjI5M2FmMTQ4YjU3MWMiLCJhdXRob3JpemF0aW9uIjp7ImZyb20iOiIweDg1N2IwNjUxOUU5MWUzQTU0NTM4NzkxYkRiYjBFMjIzNzNlMzZiNjYiLCJ0byI6IjB4MjA5NjkzQmM2YWZjMEM1MzI4YkEzNkZhRjAzQzUxNEVGMzEyMjg3QyIsInZhbHVlIjoiMTAwMDAiLCJ2YWxpZEFmdGVyIjoiMTc0MDY3MjA4OSIsInZhbGlkQmVmb3JlIjoiMTc0MDY3MjE1NCIsIm5vbmNlIjoiMHhmMzc0NjYxM2MyZDkyMGI1ZmRhYmMwODU2ZjJhZWIyZDRmODhlZTYwMzdiOGNjNWQwNGE3MWE0NDYyZjEzNDgwIn19fQ== -Access-Control-Expose-Headers: X-PAYMENT-RESPONSE -``` - -#### 2.2 Server Success Response with Settlement -```http -HTTP/1.1 200 OK -Content-Type: application/json -X-PAYMENT-RESPONSE: eyJzdWNjZXNzIjp0cnVlLCJ0cmFuc2FjdGlvbiI6IjB4YWJjZGVmMTIzNDU2Nzg5MCIsIm5ldHdvcmsiOiJiYXNlLXNlcG9saWEiLCJwYXllciI6IjB4ODU3YjA2NTE5RTkxZTNBNTQ1Mzg3OTFiRGJiMEUyMjM3M2UzNmI2NiJ9 - -{ - "message": "Protected endpoint accessed successfully", - "timestamp": "2024-01-01T00:00:00Z", - "data": { ... } -} -``` - -## Key Type Definitions - -### Core Types - -```typescript -// Main payment requirements structure -interface PaymentRequirements { - scheme: "exact"; // Payment scheme - network: Network; // Blockchain network - maxAmountRequired: string; // Amount in atomic units - resource: string; // URL path being paid for - description: string; // Human-readable description - mimeType: string; // Expected response MIME type - payTo: string; // Recipient address - maxTimeoutSeconds: number; // Payment validity window - asset: string; // Token contract address - outputSchema?: Record; // Optional response schema - extra?: Record; // Scheme-specific data (EIP-712 domain) -} - -// 402 Payment Required Response -interface PaymentRequiredResponse { - x402Version: number; - error: string; - accepts: PaymentRequirements[]; -} - -// Payment payload in X-PAYMENT header (base64 encoded) -interface PaymentPayload { - x402Version: number; - scheme: "exact"; - network: Network; - payload: ExactEvmPayload; -} - -// EVM "exact" scheme payload -interface ExactEvmPayload { - signature: string; // EIP-3009 signature - authorization: { - from: string; // Payer address - to: string; // Recipient address - value: string; // Amount in atomic units - validAfter: string; // Unix timestamp - validBefore: string; // Unix timestamp - nonce: string; // Unique nonce - }; -} - -// Settlement response in X-PAYMENT-RESPONSE header (base64 encoded) -interface SettlementResponse { - success: boolean; - transaction: string; // Transaction hash - network: Network; - payer: string; // Payer address -} -``` - -### Network Types - -```typescript -type Network = - | "base" // Base mainnet - | "base-sepolia" // Base testnet - | "avalanche" - | "avalanche-fuji" - | "iotex" - | "iotex-testnet"; - -// Chain ID mappings -const ChainIdToNetwork: Record = { - 8453: "base", - 84532: "base-sepolia", - 43114: "avalanche", - 43113: "avalanche-fuji", - 4689: "iotex", - // ... -}; -``` - -### Amount Handling - -```typescript -// maxAmountRequired is ALWAYS in atomic units of the specified asset -// - USDC: 6 decimals, so $1.00 = "1000000" -// - ETH: 18 decimals, so 1 ETH = "1000000000000000000" -// - Other tokens: varies by token.decimals - -// Example price conversion -function usdToAtomicAmount(usd: number, decimals: number): string { - return (usd * 10 ** decimals).toString(); -} - -// $0.10 USDC = "100000" (0.10 * 10^6) -// $1.00 USDC = "1000000" (1.00 * 10^6) -``` - -## MCP Implementation Requirements - -For your MCP server to interface with x402 resource servers, you'll need to implement: - -### 1. Client-Side Payment Handling - -```typescript -class X402MCPClient { - async makeRequest(url: string, options?: RequestInit): Promise { - // 1. Make initial request - const response = await fetch(url, options); - - // 2. Handle 402 Payment Required - if (response.status === 402) { - const paymentData = await response.json() as PaymentRequiredResponse; - - // 3. Select payment requirements - const selectedRequirement = this.selectPaymentRequirement(paymentData.accepts); - - // 4. Create payment header - const paymentHeader = await this.createPaymentHeader( - paymentData.x402Version, - selectedRequirement - ); - - // 5. Retry with payment - return fetch(url, { - ...options, - headers: { - ...options?.headers, - 'X-PAYMENT': paymentHeader, - 'Access-Control-Expose-Headers': 'X-PAYMENT-RESPONSE' - } - }); - } - - return response; - } - - private selectPaymentRequirement(accepts: PaymentRequirements[]): PaymentRequirements { - // Priority: USDC -> Base network -> lowest amount - return accepts - .filter(req => req.asset.includes('USDC') || req.network === 'base') - .sort((a, b) => parseInt(a.maxAmountRequired) - parseInt(b.maxAmountRequired))[0]; - } - - private async createPaymentHeader(version: number, requirements: PaymentRequirements): Promise { - // Create EIP-3009 authorization and signature - const authorization = { - from: this.walletAddress, - to: requirements.payTo, - value: requirements.maxAmountRequired, - validAfter: Math.floor(Date.now() / 1000).toString(), - validBefore: Math.floor((Date.now() + 60000) / 1000).toString(), // 1 min validity - nonce: this.generateNonce() - }; - - const signature = await this.signAuthorization(authorization, requirements.extra); - - const payload: PaymentPayload = { - x402Version: version, - scheme: "exact", - network: requirements.network, - payload: { signature, authorization } - }; - - return btoa(JSON.stringify(payload)); - } -} -``` - -### 2. Server-Side Payment Verification (if hosting resources) - -```typescript -class X402MCPServer { - async handleRequest(request: Request): Promise { - const paymentHeader = request.headers.get('X-PAYMENT'); - - if (!paymentHeader) { - return this.create402Response(); - } - - // Decode and verify payment - const payment = this.decodePaymentHeader(paymentHeader); - const verification = await this.verifyPayment(payment); - - if (!verification.isValid) { - return this.create402Response(verification.invalidReason); - } - - // Process request - const response = await this.processRequest(request); - - // Settle payment and add response header - const settlement = await this.settlePayment(payment); - if (settlement.success) { - response.headers.set('X-PAYMENT-RESPONSE', btoa(JSON.stringify(settlement))); - response.headers.set('Access-Control-Expose-Headers', 'X-PAYMENT-RESPONSE'); - } - - return response; - } - - private create402Response(error = "X-PAYMENT header is required"): Response { - const paymentRequired: PaymentRequiredResponse = { - x402Version: 1, - error, - accepts: [{ - scheme: "exact", - network: "base-sepolia", - maxAmountRequired: "100000", // $0.10 USDC - resource: "/protected-resource", - description: "Access to MCP resource", - mimeType: "application/json", - payTo: this.recipientAddress, - maxTimeoutSeconds: 60, - asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // Base Sepolia USDC - extra: { name: "USDC", version: "2" } - }] - }; - - return new Response(JSON.stringify(paymentRequired), { - status: 402, - headers: { 'Content-Type': 'application/json' } - }); - } -} -``` - -### 3. Facilitator Integration - -You'll also need to integrate with a facilitator service for verification and settlement: - -```typescript -class FacilitatorClient { - async verify(payment: PaymentPayload, requirements: PaymentRequirements): Promise { - const response = await fetch(`${this.facilitatorUrl}/verify`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ paymentPayload: payment, paymentRequirements: requirements }) - }); - return response.json(); - } - - async settle(payment: PaymentPayload, requirements: PaymentRequirements): Promise { - const response = await fetch(`${this.facilitatorUrl}/settle`, { - method: 'POST', - headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ paymentPayload: payment, paymentRequirements: requirements }) - }); - return response.json(); - } -} -``` - -### 4. Error Handling - -Key error scenarios to handle: - -```typescript -const ErrorReasons = [ - "insufficient_funds", - "invalid_exact_evm_payload_authorization_valid_after", - "invalid_exact_evm_payload_authorization_valid_before", - "invalid_exact_evm_payload_authorization_value", - "invalid_exact_evm_payload_signature", - "invalid_exact_evm_payload_recipient_mismatch", - "invalid_network", - "invalid_payload", - "invalid_payment_requirements", - "invalid_scheme", - "unsupported_scheme", - "invalid_x402_version", - "invalid_transaction_state", - "unexpected_verify_error", - "unexpected_settle_error" -] as const; -``` - -## Summary - -The x402 protocol provides a standardized way to monetize HTTP resources using blockchain payments. Your MCP server needs to: - -1. **Handle 402 responses** by parsing payment requirements -2. **Create payment headers** using EIP-3009 signatures -3. **Retry requests** with X-PAYMENT headers -4. **Process settlement responses** from X-PAYMENT-RESPONSE headers -5. **Integrate with facilitators** for verification and settlement - -The protocol is designed to be gasless for both clients and servers, with facilitators handling the on-chain transactions. \ No newline at end of file diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/balanceChecker.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/utils/balanceChecker.ts deleted file mode 100644 index 7b1f65469d..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/balanceChecker.ts +++ /dev/null @@ -1,209 +0,0 @@ -import { useCallback, useState, useEffect } from "react"; -import { createPublicClient, http, parseUnits, publicActions, Address, Chain } from "viem"; -import { getUSDCBalance } from "x402/shared/evm"; -import { formatUSDC } from "./chainConfig"; - -export interface BalanceCheckResult { - isSufficient: boolean; - formattedBalance: string; - balance: bigint; -} - -/** - * Check USDC balance for a given address - * - * @param address - The wallet address to check - * @param chain - Chain object - * @returns Promise with balance as bigint - */ -export const checkUSDCBalance = async (address: Address, chain: Chain): Promise => { - if (!address) { - return 0n; - } - - const publicClient = createPublicClient({ - chain, - transport: http(), - }).extend(publicActions); - - return await getUSDCBalance(publicClient, address); -}; - -/** - * Check USDC balance and determine if sufficient for payment - * - * @param walletAddress - The wallet address to check - * @param requiredAmount - The amount required (in USDC units, not atomic units) - * @param chain - Chain object - * @returns Promise with balance check result - */ -export async function checkUSDCBalanceForPayment( - walletAddress: Address, - requiredAmount: string, - chain: Chain, -): Promise { - try { - const publicClient = createPublicClient({ - chain, - transport: http(), - }).extend(publicActions); - const currentBalance = await getUSDCBalance(publicClient, walletAddress); - const requiredBigInt = parseUnits(requiredAmount, 6); - - const isSufficient = currentBalance >= requiredBigInt; - - const formattedBalance = formatUSDC(currentBalance.toString()); - const formattedRequiredAmount = formatUSDC(requiredBigInt.toString()); - - console.log( - `USDC Balance check: ${formattedBalance} available, ${formattedRequiredAmount} required (sufficient: ${isSufficient})`, - ); - - return { - isSufficient, - formattedBalance, - balance: currentBalance, - }; - } catch (error) { - console.error("Failed to check USDC balance:", error); - // If balance check fails, assume insufficient to be safe - return { - isSufficient: false, - balance: 0n, - formattedBalance: "0", - }; - } -} - -/** - * Check USDC balance and determine if sufficient for payment (atomic units version) - * - * @param walletAddress - The wallet address to check - * @param requiredAmountAtomic - The amount required in atomic units (e.g., "1000" for 0.001 USDC) - * @param chain - Chain object - * @returns Promise with balance check result - */ -export async function checkUSDCBalanceForPaymentAtomic( - walletAddress: Address, - requiredAmountAtomic: string, - chain: Chain, -): Promise { - try { - const publicClient = createPublicClient({ - chain, - transport: http(), - }).extend(publicActions); - const currentBalance = await getUSDCBalance(publicClient, walletAddress); // bigint - const requiredBigInt = BigInt(requiredAmountAtomic); - - const isSufficient = currentBalance >= requiredBigInt; - - const formattedBalance = formatUSDC(currentBalance.toString()); - - console.log( - `USDC Balance check (atomic): ${currentBalance} available, ${requiredBigInt} required (sufficient: ${isSufficient})`, - ); - - return { - isSufficient, - formattedBalance, - balance: currentBalance, - }; - } catch (error) { - console.error("Failed to check USDC balance (atomic):", error); - // If balance check fails, assume insufficient to be safe - return { - isSufficient: false, - balance: 0n, - formattedBalance: "0", - }; - } -} - -/** - * React hook for managing USDC balance checking - * - * @param address - The wallet address to check - * @param paymentChain - The chain to check balance on (Base or Base Sepolia) - * @returns Object with balance data and refresh function - */ -export function useUSDCBalance(address: Address | undefined, paymentChain: Chain) { - const [formattedBalance, setFormattedBalance] = useState(""); - const [isLoading, setIsLoading] = useState(false); - const [error, setError] = useState(null); - - const refreshBalance = useCallback(async () => { - if (!address) { - setFormattedBalance(""); - return; - } - - setIsLoading(true); - setError(null); - - try { - const publicClient = createPublicClient({ - chain: paymentChain, - transport: http(), - }).extend(publicActions); - const balance = await getUSDCBalance(publicClient, address); - console.log("Balance:", balance); - setFormattedBalance(formatUSDC(balance.toString())); - } catch (err) { - const errorMessage = err instanceof Error ? err.message : "Failed to fetch balance"; - setError(errorMessage); - console.error("Error fetching USDC balance:", err); - } finally { - setIsLoading(false); - } - }, [address, paymentChain]); - - // Auto-refresh balance when address changes - useEffect(() => { - refreshBalance(); - }, [refreshBalance]); - - return { - formattedBalance, - isLoading, - error, - refreshBalance, - }; -} - -/** - * Check if wallet has sufficient USDC balance for a payment - * - * @param address - The wallet address - * @param amount - Required amount in USDC - * @param chain - Chain object - * @param chainName - Name of the chain for error messages - * @returns Promise that resolves if balance is sufficient, throws if not - */ -export async function ensureSufficientUSDCBalance( - address: Address, - amount: number, - chain: Chain, - chainName?: string, -): Promise { - const publicClient = createPublicClient({ - chain, - transport: http(), - }).extend(publicActions); - const defaultChainName = chain.name; - const finalChainName = chainName || defaultChainName; - - const balance = await getUSDCBalance(publicClient, address); - - if (balance === 0n) { - throw new Error(`Insufficient balance. Make sure you have USDC on ${finalChainName}`); - } - - const requiredAmount = parseUnits(amount.toString(), 6); - if (balance < requiredAmount) { - const formattedBalance = formatUSDC(balance.toString()); - throw new Error( - `Insufficient USDC balance. You have ${formattedBalance} but need ${amount} USDC`, - ); - } -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/chainConfig.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/utils/chainConfig.ts deleted file mode 100644 index 83caf17d4d..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/chainConfig.ts +++ /dev/null @@ -1,165 +0,0 @@ -export interface ChainConfig { - id: number; - name: string; - blockExplorerUrl: string; - nativeCurrency: { - symbol: string; - decimals: number; - }; - tokens: { - USDC?: { - address: string; - decimals: number; - }; - ETH?: { - address: string; - decimals: number; - }; - }; -} - -export const CHAIN_CONFIGS: Record = { - base: { - id: 8453, - name: "Base", - blockExplorerUrl: "https://basescan.org/tx/", - nativeCurrency: { - symbol: "ETH", - decimals: 18, - }, - tokens: { - USDC: { - address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - decimals: 6, - }, - }, - }, - "base-sepolia": { - id: 84532, - name: "Base Sepolia", - blockExplorerUrl: "https://sepolia.basescan.org/tx/", - nativeCurrency: { - symbol: "ETH", - decimals: 18, - }, - tokens: { - USDC: { - address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", - decimals: 6, - }, - }, - }, -}; - -/** - * Generates a block explorer URL for a transaction on a specific network. - * Falls back to Base network if the specified network is not found. - * - * @param network - The network identifier (e.g., "base" or "base-sepolia") - * @param txHash - The transaction hash to generate URL for - * @returns {string} The complete block explorer URL for the transaction - */ -export function getBlockExplorerUrl(network: string, txHash: string): string { - const chainConfig = CHAIN_CONFIGS[network] || CHAIN_CONFIGS["base"]; // Default to base - return `${chainConfig.blockExplorerUrl}${txHash}`; -} - -/** - * Gets the decimal places for a token on a specific network. - * Matches token address case-insensitively against known tokens. - * Falls back to USDC decimals (6) if network or token not found. - * - * @param network - The network identifier (e.g., "base" or "base-sepolia") - * @param tokenAddress - The token contract address to look up - * @returns {number} The number of decimal places for the token - */ -export function getTokenDecimals(network: string, tokenAddress: string): number { - const chainConfig = CHAIN_CONFIGS[network]; - if (!chainConfig) return 6; // Default to USDC decimals - - // Check if it matches known token addresses - for (const tokenInfo of Object.values(chainConfig.tokens)) { - if (tokenInfo && tokenInfo.address.toLowerCase() === tokenAddress.toLowerCase()) { - return tokenInfo.decimals; - } - } - - // Default to USDC decimals if not found - return chainConfig.tokens.USDC?.decimals || 6; -} - -/** - * Formats a USDC amount from atomic units to human-readable format. - * Converts from base units (6 decimals) and formats with appropriate decimal places. - * Shows 2-4 decimal places, with minimum 2 decimals for consistent display. - * - * @param atomicAmount - The amount in USDC atomic units (6 decimal places) - * @returns {string} The formatted amount with appropriate decimal places - */ -export function formatUSDC(atomicAmount: string | bigint): string { - try { - const rawString = - typeof atomicAmount === "bigint" ? atomicAmount.toString() : String(atomicAmount).trim(); - if (!rawString) return "0.00"; - - // If safely representable as Number, use toLocaleString for consistent formatting - // Max safe integer is ~9e15, our amounts are expected to be small (a few thousand USD => <= 2e9 atomic) - if (/^-?\d+$/.test(rawString)) { - const asInt = Number(rawString); - if (Number.isSafeInteger(asInt)) { - const amount = asInt / 1e6; - return amount.toLocaleString("en-US", { - minimumFractionDigits: 2, - maximumFractionDigits: 4, - }); - } - } - - // Fallback: BigInt-safe manual formatting for very large inputs - let s = rawString; - let negative = false; - if (s.startsWith("-")) { - negative = true; - s = s.slice(1); - } - if (!/^\d+$/.test(s)) return "0.00"; - - s = s.replace(/^0+/, ""); - if (s === "") s = "0"; - - const hasFraction = s.length > 6; - const integerPart = hasFraction ? s.slice(0, -6) : "0"; - const fracPart = hasFraction ? s.slice(-6) : s.padStart(6, "0"); - - const trimmed = fracPart.replace(/0+$/, ""); - const targetLen = Math.min(4, Math.max(2, trimmed.length)); - const displayFrac = fracPart.slice(0, targetLen); - - const withCommas = integerPart.replace(/\B(?=(\d{3})+(?!\d))/g, ","); - return `${negative ? "-" : ""}${withCommas}.${displayFrac}`; - } catch { - return "0.00"; - } -} - -/** - * Parses a USDC amount in human-readable form to atomic units (6 decimals). - * Accepts up to 6 decimal places; returns null for invalid input. - * - * @param input - The human-readable USDC amount (e.g., "1", "1.23", "0.001") - * @returns {string | null} The atomic units as a string, or null if invalid - */ -export function parseUSDC(input: string): string | null { - const sanitized = input.replace(/,/g, "").trim(); - if (sanitized === "") return null; - if (!/^\d*(\.\d{0,6})?$/.test(sanitized)) return null; - const [whole, fracRaw] = sanitized.split("."); - const frac = (fracRaw || "").padEnd(6, "0").slice(0, 6); - try { - const wholePart = BigInt(whole || "0") * 1000000n; - const fracPart = BigInt(frac || "0"); - return (wholePart + fracPart).toString(); - } catch { - return null; - } -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/paymentInterceptor.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/utils/paymentInterceptor.ts deleted file mode 100644 index bb6428095f..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/paymentInterceptor.ts +++ /dev/null @@ -1,388 +0,0 @@ -import { AxiosInstance } from "axios"; -import { Chain } from "viem"; -import { PaymentRequirements } from "x402/types"; -import { operationStore } from "../stores/operations"; -import { budgetStore } from "../stores/budget"; -import { checkUSDCBalanceForPaymentAtomic } from "./balanceChecker"; -import { formatUSDC } from "./chainConfig"; - -/** - * Custom error class for payment interceptor failures. - * Indicates that the error has already been handled by the interceptor - * and operations have been updated accordingly. - */ -export class PaymentInterceptorError extends Error { - public readonly handledByInterceptor = true; - - /** - * Creates a new PaymentInterceptorError instance. - * - * @param message - The error message describing what went wrong - */ - constructor(message: string) { - super(message); - this.name = "PaymentInterceptorError"; - } -} - -/** - * Creates Axios interceptors to handle x402 payment flow. - * Handles 402 responses, balance checks, and payment retries. - * - * @param instance - Axios instance to add interceptors to - * @param correlationId - Correlation ID for tracking operations - * @param accountAddress - Wallet address for balance checking - * @param chain - The blockchain chain to use for transactions - * @param maxAmountPerRequest - Optional max amount per request - * @param preDiscoveredPaymentRequirements - Optional pre-discovered payment requirements to handle proactively - * @returns {AxiosInstance} The same axios instance with interceptors added - */ -export function createPaymentTrackingInterceptor( - instance: AxiosInstance, - correlationId: string, - accountAddress: string, - chain: Chain, - maxAmountPerRequest?: number, - preDiscoveredPaymentRequirements?: PaymentRequirements[], -): AxiosInstance { - // Add response interceptor to handle 402 errors and track payment flow - instance.interceptors.response.use( - response => response, - async error => { - if (error.response?.status === 402 && error.response?.data?.accepts) { - console.log(`Payment interceptor will handle 402 for correlation ${correlationId}`); - - // Extract payment requirements - const paymentRequirements = error.response.data.accepts; - const selectedPayment = paymentRequirements?.[0]; - - // Update the pending HTTP operation to show discovery - await updateOperationForDiscovery(correlationId, paymentRequirements, selectedPayment); - - // Perform budget checks - if (maxAmountPerRequest && selectedPayment) { - try { - await performBudgetChecks(correlationId, maxAmountPerRequest, selectedPayment); - console.log(`Budget check passed - payment flow will continue`); - } catch (error) { - // Budget check failed, request will not proceed - throw error; - } - } - - // Perform upfront balance checking - if (selectedPayment) { - try { - await performBalanceChecks(correlationId, accountAddress, selectedPayment, chain); - console.log(`Balance check passed - payment flow will continue`); - } catch (error) { - // Balance check failed, request will not proceed - throw error; - } - } - } - return Promise.reject(error); - }, - ); - - // Add request interceptor to handle pre-discovered payment requirements and track payment retries - instance.interceptors.request.use( - async config => { - // Handle pre-discovered payment requirements - proactively create payment - if ( - preDiscoveredPaymentRequirements && - preDiscoveredPaymentRequirements.length > 0 && - !config.headers?.["X-PAYMENT"] - ) { - console.log( - `Proactively creating payment for pre-discovered requirements (correlation ${correlationId})`, - ); - - const selectedPayment = preDiscoveredPaymentRequirements[0]; - - // Update operation to show we're creating payment authorization - await updateOperationForDiscovery( - correlationId, - preDiscoveredPaymentRequirements, - selectedPayment, - ); - - // Perform budget checks - if (maxAmountPerRequest && selectedPayment) { - try { - await performBudgetChecks(correlationId, maxAmountPerRequest, selectedPayment); - console.log(`Budget check passed - payment flow will continue`); - } catch (error) { - // Budget check failed, request will not proceed - throw error; - } - } - - // Perform balance checks - try { - await performBalanceChecks(correlationId, accountAddress, selectedPayment, chain); - console.log(`Balance check passed - payment flow will continue`); - } catch (error) { - // Balance check failed, request will not proceed - throw error; - } - } - - // Check if this request has an X-PAYMENT header (indicates retry after payment) - if (config.headers?.["X-PAYMENT"] || config.headers?.["x-payment"]) { - console.log(`Retrying request with payment header for correlation ${correlationId}`); - updateOperationForPaymentRetry(correlationId); - } - return config; - }, - error => Promise.reject(error), - ); - - return instance; -} - -/** - * Updates operations store when a 402 payment requirement is discovered. - * Updates the pending HTTP operation with payment details and requirements. - * - * @param correlationId - ID to correlate this operation with others - * @param paymentRequirements - Array of available payment options from the 402 response - * @param selectedPayment - The selected payment option to process - * @returns {Promise} Resolves when operations are updated - */ -async function updateOperationForDiscovery( - correlationId: string, - paymentRequirements: PaymentRequirements[], - selectedPayment: PaymentRequirements, -): Promise { - const currentOperations = operationStore.getState().operations; - const pendingOpIndex = currentOperations.findIndex( - op => op.correlationId === correlationId && op.status === "pending" && op.type === "http", - ); - - if (pendingOpIndex !== -1) { - const paymentAmountFormatted = formatUSDC(selectedPayment.maxAmountRequired); - - operationStore.getState().updateHttpOperation(pendingOpIndex, { - description: `Payment required: $${paymentAmountFormatted} USDC`, - status: "pending", - paymentRequirements: paymentRequirements, - selectedPayment: selectedPayment, - }); - } - - console.log( - `Payment required: ${selectedPayment?.maxAmountRequired} ${selectedPayment?.asset} on ${selectedPayment?.network}`, - ); -} - -/** - * Performs comprehensive balance checks before attempting payment. - * Verifies USDC balance is sufficient and updates operations accordingly. - * - * @param correlationId - ID to correlate this operation with others - * @param accountAddress - The wallet address to check balance for - * @param selectedPayment - The payment requirements to check balance against - * @param chain - The blockchain chain to check balance on - * @returns {Promise} Resolves when balance checks are complete - * @throws {PaymentInterceptorError} If balance is insufficient - */ -async function performBalanceChecks( - correlationId: string, - accountAddress: string, - selectedPayment: PaymentRequirements, - chain: Chain, -): Promise { - const balanceCheck = await checkUSDCBalanceForPaymentAtomic( - accountAddress as `0x${string}`, - selectedPayment.maxAmountRequired, - chain, - ); - - const formattedPaymentAmount = formatUSDC(selectedPayment.maxAmountRequired); - - if (!balanceCheck.isSufficient) { - const errorMessage = `Insufficient USDC balance (need ${formatUSDC( - selectedPayment.maxAmountRequired, - )}, have ${balanceCheck.formattedBalance})`; - - console.error(`Balance check failed: ${errorMessage}`); - - // Update operations to show insufficient balance - await updateOperationsForInsufficientBalance(correlationId, errorMessage, accountAddress); - - throw new PaymentInterceptorError(errorMessage); - } - - console.log( - `Balance check passed: ${balanceCheck.formattedBalance} available, ${formattedPaymentAmount} required`, - ); - - const description = `Processing payment: $${formattedPaymentAmount} USDC`; - - operationStore - .getState() - .addWalletOperation( - description, - "pending", - "sign", - accountAddress, - undefined, - undefined, - undefined, - correlationId, - ); -} - -/** - * Updates operations when insufficient balance is detected. - * Updates both HTTP and wallet operations to reflect the balance error. - * - * @param correlationId - ID to correlate this operation with others - * @param errorMessage - The error message explaining the insufficient balance - * @param accountAddress - The wallet address that had insufficient balance - * @returns {Promise} Resolves when operations are updated - */ -async function updateOperationsForInsufficientBalance( - correlationId: string, - errorMessage: string, - accountAddress: string, -): Promise { - const description = `Payment failed - insufficient USDC balance`; - // Update HTTP operation - const currentOperations = operationStore.getState().operations; - const pendingOpIndex = currentOperations.findIndex( - op => op.correlationId === correlationId && op.status === "pending" && op.type === "http", - ); - - if (pendingOpIndex !== -1) { - operationStore.getState().updateHttpOperation(pendingOpIndex, { - description, - status: "error", - errorMessage: errorMessage, - }); - } - - // Add wallet operation showing the balance failure - operationStore - .getState() - .addWalletOperation( - description, - "error", - "sign", - accountAddress, - errorMessage, - undefined, - undefined, - correlationId, - ); -} - -/** - * Updates operations when a payment retry is attempted. - * Marks the pending wallet operation as completed successfully. - * - * @param correlationId - ID to correlate this operation with others - * @returns {void} No return value - */ -function updateOperationForPaymentRetry(correlationId: string): void { - // Update the pending wallet operation to show payment authorization completed - const currentOperations = operationStore.getState().operations; - const pendingWalletOpIndex = currentOperations.findIndex( - op => op.correlationId === correlationId && op.status === "pending" && op.type === "wallet", - ); - - if (pendingWalletOpIndex !== -1) { - operationStore.getState().updateWalletOperation(pendingWalletOpIndex, { - description: `Payment authorization completed`, - status: "success", - }); - } - - // Note: We don't add a new HTTP operation here since it would be redundant - // The original HTTP operation will be updated to success when the request completes -} - -/** - * Performs budget checks before attempting payment. - * Verifies that the max amount per request is not exceeded. - * - * @param correlationId - ID to correlate this operation with others - * @param maxAmountPerRequest - The max amount per request - * @param selectedPayment - The selected payment option to check against - */ -async function performBudgetChecks( - correlationId: string, - maxAmountPerRequest: number, - selectedPayment: PaymentRequirements, -) { - console.log("Performing budget checks"); - if (maxAmountPerRequest && selectedPayment) { - const selectedPaymentAmount = Number(selectedPayment.maxAmountRequired); - - console.log( - `Max amount per request: ${maxAmountPerRequest}, selected payment: ${selectedPaymentAmount}`, - ); - - if (selectedPaymentAmount > maxAmountPerRequest) { - const errorMessage = `Payment required: $${formatUSDC( - selectedPayment.maxAmountRequired, - )} is greater than max amount per request: $${formatUSDC(maxAmountPerRequest.toString())}`; - - console.error(`Budget check failed: ${errorMessage}`); - - // Update operations to show insufficient budget - await updateOperationForBudgetCheckFailure(correlationId, errorMessage); - - throw new PaymentInterceptorError(errorMessage); - } - - const { sessionBudgetAtomic, sessionSpentAtomic } = budgetStore.getState(); - if (sessionBudgetAtomic) { - const remaining = Number(sessionBudgetAtomic) - Number(sessionSpentAtomic || "0"); - if (selectedPaymentAmount > remaining) { - const errorMessage = `Payment required: $${formatUSDC( - selectedPayment.maxAmountRequired, - )} exceeds remaining session budget: $${formatUSDC(remaining.toString())}`; - - console.error(`Budget check failed: ${errorMessage}`); - - await updateOperationForBudgetCheckFailure(correlationId, errorMessage); - - throw new PaymentInterceptorError(errorMessage); - } - } - } else { - console.log("No max amount per request or selected payment found"); - } -} - -/** - * Updates operations when budget check fails. - * Updates both HTTP and wallet operations to reflect the budget error. - * - * @param correlationId - ID to correlate this operation with others - * @param errorMessage - The error message explaining the budget error - * @returns {Promise} Resolves when operations are updated - */ -async function updateOperationForBudgetCheckFailure( - correlationId: string, - errorMessage: string, -): Promise { - const description = "Payment failed - insufficient budget"; - // Update HTTP operation - const currentOperations = operationStore.getState().operations; - const pendingOpIndex = currentOperations.findIndex( - op => op.correlationId === correlationId && op.status === "pending" && op.type === "http", - ); - - console.log("pendingOpIndex", pendingOpIndex); - - if (pendingOpIndex !== -1) { - operationStore.getState().updateHttpOperation(pendingOpIndex, { - description, - status: "error", - errorMessage: errorMessage, - }); - } -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/x402Client.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/utils/x402Client.ts deleted file mode 100644 index 4f862a6ff2..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/x402Client.ts +++ /dev/null @@ -1,279 +0,0 @@ -import axios from "axios"; -import { base, baseSepolia } from "viem/chains"; -import { withPaymentInterceptor } from "x402-axios"; -import { PaymentRequirements } from "x402/types"; -import { budgetStore } from "../stores/budget"; -import { operationStore, SettlementInfo } from "../stores/operations"; -import { getBlockExplorerUrl, formatUSDC } from "./chainConfig"; -import { createPaymentTrackingInterceptor, PaymentInterceptorError } from "./paymentInterceptor"; -import { handle402Error, handleNon402Error, type ErrorHandlingContext } from "./x402ErrorHandler"; -import { getCurrentUser, toViemAccount } from "@coinbase/cdp-core"; - -// Helper types for the MCP tool -export type X402RequestParams = { - baseURL: string; - path: string; - method: "GET" | "POST" | "PUT" | "DELETE" | "PATCH"; - queryParams?: Record; - body?: unknown; - correlationId?: string; - maxAmountPerRequest?: number; - paymentRequirements?: PaymentRequirements[]; // Can be provided via discovery or directly -}; - -/** - * Makes an HTTP request with x402 payment handling capabilities. - * Handles payment requirements, tracks operations, and manages payment flow. - * - * @param root0 - The request configuration object - * @param root0.baseURL - The base URL for the request - * @param root0.path - The path to append to the base URL - * @param root0.method - The HTTP method to use - * @param root0.queryParams - Optional query parameters to include in the URL - * @param root0.body - Optional request body data - * @param root0.correlationId - Optional ID to correlate operations (auto-generated if not provided) - * @param root0.maxAmountPerRequest - Optional max amount per request - * @param root0.paymentRequirements - Optional pre-discovered payment requirements - * @returns {Promise<{status: number; statusText: string; data: unknown; headers: Record}>} The response data - * @throws {PaymentInterceptorError} If payment requirements cannot be met - * @throws {Error} If the request fails for any other reason - */ -export async function makeX402Request({ - baseURL, - path, - method, - queryParams, - body, - correlationId, - maxAmountPerRequest, - paymentRequirements, -}: X402RequestParams) { - const user = await getCurrentUser(); - if (!user || !user.evmAccounts || user.evmAccounts.length === 0) { - throw new Error("No CDP user or EVM accounts found"); - } - - const evmAccount = user.evmAccounts[0]; - const account = await toViemAccount(evmAccount); - - const chain = import.meta.env.VITE_TESTNET ? baseSepolia : base; - - // Generate correlation ID if not provided - const finalCorrelationId = - correlationId || `x402-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; - - // Resolve max per-request budget: use explicit param if provided, otherwise pull from store (atomic) - const storePerRequestMaxAtomic = budgetStore.getState().perRequestMaxAtomic; - const effectiveMaxAmountPerRequest = - typeof maxAmountPerRequest === "number" - ? maxAmountPerRequest - : storePerRequestMaxAtomic - ? Number(storePerRequestMaxAtomic) - : undefined; - - // Create axios instance with payment tracking interceptors - const axiosInstance = axios.create({ baseURL }); - const trackedInstance = createPaymentTrackingInterceptor( - axiosInstance, - finalCorrelationId, - account.address, - chain, - effectiveMaxAmountPerRequest, - paymentRequirements, // Pass pre-discovered payment requirements - ); - // Cast to any to work around axios version mismatch between dependencies - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const fetchWithPayment = withPaymentInterceptor(trackedInstance as any, account as any); - - try { - // Add initial operation (interceptor will handle payment logic) - if (paymentRequirements && paymentRequirements.length > 0) { - console.log( - `Making ${method} request to ${baseURL}${path} with pre-discovered payment requirements`, - ); - - operationStore - .getState() - .addHttpOperation( - `Making ${method} request to ${baseURL}${path} (payment required)`, - "pending", - method, - `${baseURL}${path}`, - undefined, - finalCorrelationId, - maxAmountPerRequest, - paymentRequirements, - paymentRequirements[0], - undefined, - ); - } else { - console.log(`Making ${method} request to ${baseURL}${path}`); - - operationStore - .getState() - .addHttpOperation( - `Making ${method} request to ${baseURL}${path}`, - "pending", - method, - `${baseURL}${path}`, - undefined, - finalCorrelationId, - ); - } - - // Make the request (interceptor and x402 library will handle payment flow) - const response = await fetchWithPayment(path, { - method, - params: queryParams, - data: body, - }); - - if (response.status !== 200) { - throw new Error(`HTTP error! status: ${response.status}`); - } - - // Extract settlement info from X-PAYMENT-RESPONSE header - let settlementInfo: SettlementInfo | undefined; - const paymentResponseHeader = - response.headers["x-payment-response"] || response.headers["X-PAYMENT-RESPONSE"]; - if (paymentResponseHeader) { - try { - settlementInfo = JSON.parse(atob(paymentResponseHeader)); - console.log(`Settlement info captured:`, settlementInfo); - } catch (error) { - console.warn("Failed to parse X-PAYMENT-RESPONSE header:", error); - } - } - - // Update operation to success with settlement info - await updateOperationForSuccess(finalCorrelationId, method, baseURL, path, settlementInfo); - - return { - status: response.status, - statusText: response.statusText, - data: response.data, - headers: response.headers, - }; - } catch (error) { - // Check if this error was already handled by the payment interceptor - if (error instanceof PaymentInterceptorError) { - // Operations have already been updated by the interceptor, just re-throw - console.log(`Payment interceptor already handled error: ${error.message}`); - throw error; - } - - const errorMessage = error instanceof Error ? error.message : String(error); - const fullUrl = `${baseURL}${path}`; - const is402Error = errorMessage.includes("402") || errorMessage.includes("Payment Required"); - - // Create error context - const errorContext: ErrorHandlingContext = { - correlationId: finalCorrelationId, - fullUrl, - method, - baseURL, - path, - queryParams, - body, - }; - - // Route to appropriate error handler - if (is402Error) { - handle402Error(error, errorContext); - } else { - handleNon402Error(error, errorContext); - } - } -} - -/** - * Updates operation status to success and handles settlement information. - * Updates both HTTP and wallet operations if present, or creates a new success operation. - * - * @param correlationId - ID to correlate this operation with others - * @param method - The HTTP method that was used (GET, POST, etc.) - * @param baseURL - The base URL of the request - * @param path - The path component of the request URL - * @param settlementInfo - Optional settlement information from the payment response - * @returns {Promise} Resolves when operations are updated - */ -async function updateOperationForSuccess( - correlationId: string, - method: string, - baseURL: string, - path: string, - settlementInfo?: SettlementInfo, -): Promise { - const currentOperations = operationStore.getState().operations; - - // Find all pending operations with this correlation ID - const pendingOperations = currentOperations.filter( - op => op.correlationId === correlationId && op.status === "pending", - ); - - // Update operations to success - prioritize payment flow over generic success - let httpOperationUpdated = false; - - pendingOperations.forEach(operation => { - const index = currentOperations.indexOf(operation); - - if (operation.type === "wallet") { - // Update wallet operation to show payment completed - let blockExplorerUrl: string | undefined; - - if (settlementInfo?.transaction && settlementInfo?.network) { - blockExplorerUrl = getBlockExplorerUrl(settlementInfo.network, settlementInfo.transaction); - console.log( - `Transaction completed: ${settlementInfo.transaction} on ${settlementInfo.network}`, - ); - } - - operationStore.getState().updateWalletOperation(index, { - description: `Payment completed successfully`, - status: "success", - errorMessage: undefined, // Clear any previous error message - transactionHash: settlementInfo?.transaction, - blockExplorerUrl: blockExplorerUrl, - }); - } else if (operation.type === "http" && !httpOperationUpdated) { - // Only update the first HTTP operation to avoid duplicates - operationStore.getState().updateHttpOperation(index, { - description: `Payment required: ${ - operation.selectedPayment - ? formatUSDC(operation.selectedPayment.maxAmountRequired) - : "unknown amount" - }`, - status: "success", - errorMessage: undefined, // Clear any previous error message - settlementInfo: settlementInfo, // Add settlement info with transaction hash - }); - httpOperationUpdated = true; - - // Increment session spent using the selected payment's maxAmountRequired (atomic) - const amountAtomic = operation.selectedPayment?.maxAmountRequired; - if (amountAtomic) { - try { - budgetStore.getState().addSpentAtomic(amountAtomic); - } catch { - // ignore budget update failures - } - } - } - }); - - // If no pending operations were found, add a fallback success operation - if (pendingOperations.length === 0) { - operationStore.getState().addHttpOperation( - `Successfully completed ${method} request to ${baseURL}${path}`, - "success", - method, - `${baseURL}${path}`, - undefined, - correlationId, - undefined, // maxAmountPerRequest - undefined, // paymentRequirements - undefined, // selectedPayment - settlementInfo, // Include settlement info - ); - } -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/x402ErrorHandler.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/utils/x402ErrorHandler.ts deleted file mode 100644 index c868b13c7f..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/x402ErrorHandler.ts +++ /dev/null @@ -1,291 +0,0 @@ -import { AxiosError } from "axios"; -import { operationStore } from "../stores/operations"; -import { type x402Response } from "x402/types"; - -export interface ErrorHandlingContext { - correlationId: string; - fullUrl: string; - method: string; - baseURL: string; - path: string; - queryParams?: Record; - body?: unknown; -} - -/** - * Handles 402 Payment Required errors with server response parsing. - * Checks if payment was already attempted and updates operations accordingly. - * - * @param error - The error object from the failed request - * @param context - The context object containing request details - * @throws {Error} Re-throws the original error for the payment interceptor to handle - */ -export function handle402Error(error: unknown, context: ErrorHandlingContext): void { - console.log( - `402 Payment Required for ${context.fullUrl} (correlationId: ${context.correlationId})`, - ); - - // Check if payment was already attempted but rejected by server - const currentOperations = operationStore.getState().operations; - const hasSuccessfulPayment = currentOperations.some( - op => - op.correlationId === context.correlationId && - op.type === "wallet" && - op.status === "success" && - op.description.includes("Payment authorization completed"), - ); - - if (hasSuccessfulPayment) { - handlePaymentRejection(error, context.correlationId); - } else { - console.log( - `Initial 402 for correlation ${context.correlationId} - payment interceptor will attempt payment`, - ); - } - - // Always let payment interceptor handle 402s - throw error; -} - -/** - * Handles payment rejection after successful signing. - * Parses server error messages and updates operations with specific error details. - * - * @param error - The error object containing server response data - * @param correlationId - ID to correlate this operation with others - * @returns {void} No return value - */ -function handlePaymentRejection(error: unknown, correlationId: string): void { - console.log(`Payment was signed but rejected by server for correlation ${correlationId}`); - - // Parse server's specific error message - let serverError = "Unknown server error"; - let description = "Payment rejected by server"; - - if (error && typeof error === "object" && "response" in error) { - const axiosError = error as AxiosError; - const responseData = axiosError.response?.data as x402Response; - - console.log(`Server response data:`, JSON.stringify(responseData, null, 2)); - - if (responseData?.error) { - const serverErrorCode = responseData.error; - console.log(`Server rejection reason: ${serverErrorCode}`); - - switch (serverErrorCode) { - case "insufficient_funds": - const accepts = responseData.accepts?.[0]; - const amount = accepts?.maxAmountRequired || "unknown amount"; - const asset = accepts?.extra?.name || accepts?.asset || "tokens"; - serverError = `Insufficient ${asset} in wallet (${amount} required)`; - description = `Payment failed - insufficient ${asset} balance`; - break; - case "invalid_payment": - serverError = "Invalid payment signature"; - description = "Payment failed - invalid payment signature"; - break; - case "payment_expired": - serverError = "Payment authorization expired"; - description = "Payment failed - payment authorization expired"; - break; - default: - serverError = `Server error: ${serverErrorCode}`; - description = `Payment failed - ${serverErrorCode}`; - } - } - } - - // Update pending wallet operation to show rejection - const currentOperations = operationStore.getState().operations; - const pendingWalletOpIndex = currentOperations.findIndex( - op => op.correlationId === correlationId && op.status === "pending" && op.type === "wallet", - ); - - if (pendingWalletOpIndex !== -1) { - operationStore.getState().updateWalletOperation(pendingWalletOpIndex, { - description, - status: "error", - errorMessage: serverError, - }); - } -} - -/** - * Handles non-402 errors such as wallet errors, insufficient balance, etc. - * Categorizes errors, updates operations, and logs error details. - * - * @param error - The error object from the failed request - * @param context - The context object containing request details - * @throws {Error} Throws a wrapped error with additional context - */ -export function handleNon402Error(error: unknown, context: ErrorHandlingContext): void { - const errorMessage = error instanceof Error ? error.message : String(error); - - console.log( - `Non-402 error for ${context.fullUrl} (correlationId: ${context.correlationId}): ${errorMessage}`, - ); - - // Check for wallet-related errors - const walletErrorType = categorizeWalletError(errorMessage); - - if (walletErrorType) { - updateWalletOperationForError(context.correlationId, walletErrorType, errorMessage); - } - - // Update HTTP operation to show failure - updateHttpOperationForError(context, errorMessage); - - // Log error details for debugging - logErrorDetails(error, context); - - throw new Error(`X402 request failed: ${errorMessage}`); -} - -/** - * Categorizes wallet errors for better error messages. - * Analyzes error message content to determine specific error types. - * - * @param errorMessage - The error message to analyze - * @returns {string | null} The categorized error type or null if unrecognized - */ -function categorizeWalletError(errorMessage: string): string | null { - const lowerError = errorMessage.toLowerCase(); - - if ( - lowerError.includes("insufficient") && - (lowerError.includes("balance") || lowerError.includes("funds")) - ) { - return "insufficient_balance"; - } - - if ( - (lowerError.includes("insufficient") && - (lowerError.includes("gas") || lowerError.includes("eth"))) || - lowerError.includes("out of gas") || - lowerError.includes("gas limit") || - lowerError.includes("intrinsic gas") - ) { - return "insufficient_gas"; - } - - if (lowerError.includes("user rejected") || lowerError.includes("user denied")) { - return "user_rejected"; - } - - if ( - lowerError.includes("payment failed") || - lowerError.includes("signature") || - lowerError.includes("unauthorized") - ) { - return "general_wallet_error"; - } - - return null; -} - -/** - * Updates wallet operation based on error type. - * Sets appropriate error descriptions based on the error category. - * - * @param correlationId - ID to correlate this operation with others - * @param errorType - The categorized type of error (e.g., 'insufficient_balance') - * @param errorMessage - The detailed error message - * @returns {void} No return value - */ -function updateWalletOperationForError( - correlationId: string, - errorType: string, - errorMessage: string, -): void { - const currentOperations = operationStore.getState().operations; - const pendingWalletOpIndex = currentOperations.findIndex( - op => op.correlationId === correlationId && op.status === "pending" && op.type === "wallet", - ); - - if (pendingWalletOpIndex !== -1) { - let description = "Payment failed"; - - switch (errorType) { - case "insufficient_balance": - description = "Payment failed - insufficient wallet balance"; - break; - case "insufficient_gas": - description = "Payment failed - insufficient ETH for gas fees"; - break; - case "user_rejected": - description = "Payment cancelled by user"; - break; - default: - description = "Payment failed"; - } - - operationStore.getState().updateWalletOperation(pendingWalletOpIndex, { - description, - status: "error", - errorMessage: errorMessage, - }); - } -} - -/** - * Updates HTTP operation to show failure. - * Updates existing operation or creates a new error operation if none exists. - * - * @param context - The context object containing request details - * @param errorMessage - The error message to display - * @returns {void} No return value - */ -function updateHttpOperationForError(context: ErrorHandlingContext, errorMessage: string): void { - const currentOperations = operationStore.getState().operations; - const pendingOpIndex = [...currentOperations] - .reverse() - .findIndex( - op => - op.correlationId === context.correlationId && op.status === "pending" && op.type === "http", - ); - - if (pendingOpIndex !== -1) { - const actualIndex = currentOperations.length - 1 - pendingOpIndex; - operationStore.getState().updateHttpOperation(actualIndex, { - description: `Failed ${context.method} request to ${context.path}`, - status: "error", - errorMessage: errorMessage, - }); - } else { - // Fallback: add new error operation - operationStore - .getState() - .addHttpOperation( - `Failed ${context.method} request to ${context.path}`, - "error", - context.method, - context.fullUrl, - errorMessage, - context.correlationId, - ); - } -} - -/** - * Logs error details for debugging purposes. - * Formats and logs both error and context information. - * - * @param error - The error object to log - * @param context - The context object containing request details - * @returns {void} No return value - */ -function logErrorDetails(error: unknown, context: ErrorHandlingContext): void { - console.info("Request error:", error); - - const errorDetails = { - baseURL: context.baseURL, - path: context.path, - method: context.method, - queryParams: context.queryParams, - body: context.body, - correlationId: context.correlationId, - error: JSON.stringify(error, null, 2), - }; - - console.error("X402 request error details:", JSON.stringify(errorDetails, null, 2)); -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/x402Utils.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/utils/x402Utils.ts deleted file mode 100644 index 41fae02f02..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/utils/x402Utils.ts +++ /dev/null @@ -1,103 +0,0 @@ -import { Operation, HttpOperation } from "../stores/operations"; -import { formatUSDC } from "./chainConfig"; - -/** - * Extracts and formats the payment amount from a group of operations. - * Looks for HTTP operations with payment requirements and formats the amount. - * - * @param operations - Array of operations to search through - * @returns {string} The formatted payment amount or "Unknown" if not found - */ -export function getPaymentAmount(operations: Operation[]): string { - // Find the operation with payment requirements (402 response) - const paymentOp = operations.find( - op => op.type === "http" && op.paymentRequirements?.length, - ) as HttpOperation; - - if (!paymentOp?.selectedPayment) { - return "Unknown"; - } - - return formatUSDC(paymentOp.selectedPayment.maxAmountRequired); -} - -/** - * Determines the overall status of a group of operations. - * Analyzes operation sequence to determine if the group is successful, pending, or has errors. - * Special handling for initial 402 discovery which is considered part of success flow. - * - * @param operations - Array of operations to analyze - * @returns {"success" | "error" | "pending"} The overall status of the operation group - */ -export function getGroupStatus(operations: Operation[]): "success" | "error" | "pending" { - // Sort operations by timestamp to identify the flow sequence - const sortedOps = [...operations].sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime()); - - if (sortedOps.some(op => op.status === "pending")) { - return "pending"; - } - - // If we can't determine payment amount, that's an error condition - const paymentAmount = getPaymentAmount(operations); - if (paymentAmount === "Unknown") { - return "error"; - } - - // Check if any operation is a real error (excluding initial 402 discovery) - const hasRealError = sortedOps.some((op, index) => { - if (op.status === "error") { - // Special case: Initial HTTP request with 402 error is discovery phase (success) - if ( - op.type === "http" && - op.errorMessage?.includes("402") && - index === 0 && // First operation in the group - (op as HttpOperation).paymentRequirements?.length - ) { - return false; // This is expected discovery, not a failure - } - - // Any other error is a real failure - return true; - } - return false; - }); - - return hasRealError ? "error" : "success"; -} - -/** - * Gets the target URL from a group of operations. - * Finds the first HTTP operation and extracts its URL. - * - * @param operations - Array of operations to search through - * @returns {string} The target URL or "Unknown" if not found - */ -export function getTargetUrl(operations: Operation[]): string { - // Find the first HTTP operation - const httpOp = operations.find(op => op.type === "http") as HttpOperation; - return httpOp?.url || "Unknown"; -} - -/** - * Generates a human-readable status message based on operation status and payment amount. - * Formats the message differently for success, error, and pending states. - * - * @param status - The current status of the operation group - * @param paymentAmount - The formatted payment amount - * @returns {string} A human-readable status message - */ -export function getStatusText( - status: "success" | "error" | "pending", - paymentAmount: string, -): string { - switch (status) { - case "success": - return `Sent $${paymentAmount} USDC`; - case "error": - return paymentAmount !== "Unknown" - ? `Failed to send ${paymentAmount}` - : "Failed to send payment"; - case "pending": - return `Sending $${paymentAmount} USDC`; - } -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/vite-env.d.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/vite-env.d.ts deleted file mode 100644 index 986042d2bc..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/vite-env.d.ts +++ /dev/null @@ -1,11 +0,0 @@ -/// - -interface ImportMetaEnv { - readonly VITE_CDP_PROJECT_ID: string; - readonly VITE_CDP_BASE_PATH: string; - // Add more env variables as needed -} - -interface ImportMeta { - readonly env: ImportMetaEnv; -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/src/window.ts b/examples/typescript/legacy/mcp-embedded-wallet/src/window.ts deleted file mode 100644 index 718858440a..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/src/window.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { ListDiscoveryResourcesResponse } from "x402/types"; -import { X402RequestParams } from "./utils/x402Client"; - -export interface ElectronWindow extends Window { - electron: { - ipcRenderer: { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - invoke: (channel: string, ...args: any[]) => Promise; - }; - OnSignMessage: (callback: (message: string) => Promise) => void; - OnDiscoveryList: (callback: () => Promise) => void; - // eslint-disable-next-line @typescript-eslint/no-explicit-any - OnMakeX402Request: (callback: (params: X402RequestParams) => Promise) => void; - OnGetWalletAddress: (callback: () => Promise) => void; - }; -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/tsconfig.json b/examples/typescript/legacy/mcp-embedded-wallet/tsconfig.json deleted file mode 100644 index c6b49c8baa..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/tsconfig.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "useDefineForClassFields": true, - "lib": ["ES2020", "DOM", "DOM.Iterable"], - "module": "ESNext", - "skipLibCheck": true, - "moduleResolution": "bundler", - "allowImportingTsExtensions": true, - "resolveJsonModule": true, - "noEmit": true, - "jsx": "react-jsx", - "strict": true, - "noUnusedLocals": true, - "noUnusedParameters": true, - "noFallthroughCasesInSwitch": true - }, - "include": ["src"] -} diff --git a/examples/typescript/legacy/mcp-embedded-wallet/vite.config.ts b/examples/typescript/legacy/mcp-embedded-wallet/vite.config.ts deleted file mode 100644 index 63350fc67b..0000000000 --- a/examples/typescript/legacy/mcp-embedded-wallet/vite.config.ts +++ /dev/null @@ -1,17 +0,0 @@ -import react from "@vitejs/plugin-react"; -import { defineConfig } from "vite"; - -export default defineConfig({ - plugins: [react()], - server: { - port: 3000, - headers: { - // Allow all origins in development to support localhost x402 requests - "Access-Control-Allow-Origin": "*", - }, - }, - build: { - outDir: "dist", - }, - base: "", -}); diff --git a/examples/typescript/legacy/mcp/.env-local b/examples/typescript/legacy/mcp/.env-local deleted file mode 100644 index 3d2e1855d1..0000000000 --- a/examples/typescript/legacy/mcp/.env-local +++ /dev/null @@ -1,3 +0,0 @@ -RESOURCE_SERVER_URL=http://localhost:4021 -ENDPOINT_PATH=/weather -PRIVATE_KEY= diff --git a/examples/typescript/legacy/mcp/.prettierignore b/examples/typescript/legacy/mcp/.prettierignore deleted file mode 100644 index 5bd240ba90..0000000000 --- a/examples/typescript/legacy/mcp/.prettierignore +++ /dev/null @@ -1,8 +0,0 @@ -docs/ -dist/ -node_modules/ -coverage/ -.github/ -src/client -**/**/*.json -*.md \ No newline at end of file diff --git a/examples/typescript/legacy/mcp/.prettierrc b/examples/typescript/legacy/mcp/.prettierrc deleted file mode 100644 index ffb416b74b..0000000000 --- a/examples/typescript/legacy/mcp/.prettierrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": false, - "trailingComma": "all", - "bracketSpacing": true, - "arrowParens": "avoid", - "printWidth": 100, - "proseWrap": "never" -} diff --git a/examples/typescript/legacy/mcp/README.md b/examples/typescript/legacy/mcp/README.md deleted file mode 100644 index abf8592354..0000000000 --- a/examples/typescript/legacy/mcp/README.md +++ /dev/null @@ -1,146 +0,0 @@ -# x402 MCP Example Client - -This is an example client that demonstrates how to use the x402 payment protocol with the Model Context Protocol (MCP) to make paid API requests through an MCP server. - -## Prerequisites - -- Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) -- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- A running x402 server (you can use the example express server at `examples/typescript/servers/express`) -- A valid Ethereum private key for making payments -- Claude Desktop with MCP support - -## Setup - -1. Install and build all packages from the typescript examples root: -```bash -cd ../../ -pnpm install -pnpm build -cd clients/mcp -``` - -2. Copy `.env-local` to `.env` and add your Ethereum private key: -```bash -cp .env-local .env -``` - -3. Configure Claude Desktop MCP settings: -```json -{ - "mcpServers": { - "demo": { - "command": "pnpm", - "args": [ - "--silent", - "-C", - "/examples/typescript/mcp", - "dev" - ], - "env": { - "PRIVATE_KEY": "", - "RESOURCE_SERVER_URL": "http://localhost:4021", - "ENDPOINT_PATH": "/weather" - } - } - } -} -``` - -4. Start the example client (remember to be running a server or pointing to one in the .env file): -```bash -pnpm dev -``` - -## How It Works - -The example demonstrates how to: -1. Create a wallet client using viem -2. Set up an MCP server with x402 payment handling -3. Create a tool that makes paid API requests -4. Handle responses and errors through the MCP protocol - -## Example Code - -```typescript -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import axios from "axios"; -import { createWalletClient, Hex, http, publicActions } from "viem"; -import { privateKeyToAccount } from "viem/accounts"; -import { baseSepolia } from "viem/chains"; -import { withPaymentInterceptor } from "x402-axios"; - -// Create wallet client -const wallet = createWalletClient({ - chain: baseSepolia, - transport: http(), - account: privateKeyToAccount(PRIVATE_KEY as Hex), -}).extend(publicActions); - -// Create Axios instance with payment handling -const client = withPaymentInterceptor(axios.create({ baseURL: RESOURCE_SERVER_URL }), wallet); - -// Create MCP server -const server = new McpServer({ - name: "x402 MCP Client Demo", - version: "1.0.0", -}); - -// Add tool for making paid requests -server.tool("get-data-from-resource-server", "Get data from the resource server (in this example, the weather)", {}, async () => { - const res = await client.post(`${ENDPOINT_PATH}`); - return { - content: [{ type: "text", text: JSON.stringify(res.data) }], - }; -}); - -// Connect to MCP transport -const transport = new StdioServerTransport(); -await server.connect(transport); -``` - -## Response Handling - -### Payment Required (402) -When a payment is required, the MCP server will: -1. Receive the 402 response -2. Parse the payment requirements -3. Create and sign a payment header -4. Automatically retry the request with the payment header - -### Successful Response -After payment is processed, the MCP server will return the response data through the MCP protocol: -```json -{ - "content": [ - { - "type": "text", - "text": "{\"report\":{\"weather\":\"sunny\",\"temperature\":70}}" - } - ] -} -``` - -## Extending the Example - -To use this pattern in your own application: - -1. Install the required dependencies: -```bash -npm install @modelcontextprotocol/sdk x402-axios viem -``` - -2. Set up your environment variables -3. Create a wallet client -4. Set up your MCP server with x402 payment handling -5. Define your tools for making paid requests -6. Connect to the MCP transport - -## Integration with Claude Desktop - -This example is designed to work with Claude Desktop's MCP support. The MCP server will: -1. Listen for tool requests from Claude -2. Handle the payment process automatically -3. Return the response data through the MCP protocol -4. Allow Claude to process and display the results diff --git a/examples/typescript/legacy/mcp/eslint.config.js b/examples/typescript/legacy/mcp/eslint.config.js deleted file mode 100644 index 52622f9a87..0000000000 --- a/examples/typescript/legacy/mcp/eslint.config.js +++ /dev/null @@ -1,72 +0,0 @@ -import js from "@eslint/js"; -import ts from "@typescript-eslint/eslint-plugin"; -import tsParser from "@typescript-eslint/parser"; -import prettier from "eslint-plugin-prettier"; -import jsdoc from "eslint-plugin-jsdoc"; -import importPlugin from "eslint-plugin-import"; - -export default [ - { - ignores: ["dist/**", "node_modules/**"], - }, - { - files: ["**/*.ts"], - languageOptions: { - parser: tsParser, - sourceType: "module", - ecmaVersion: 2022, - globals: { - process: "readonly", - __dirname: "readonly", - module: "readonly", - require: "readonly", - Buffer: "readonly", - exports: "readonly", - setTimeout: "readonly", - clearTimeout: "readonly", - setInterval: "readonly", - clearInterval: "readonly", - }, - }, - plugins: { - "@typescript-eslint": ts, - prettier: prettier, - jsdoc: jsdoc, - import: importPlugin, - }, - rules: { - ...ts.configs.recommended.rules, - "import/first": "error", - "prettier/prettier": "error", - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_$" }], - "jsdoc/tag-lines": ["error", "any", { startLines: 1 }], - "jsdoc/check-alignment": "error", - "jsdoc/no-undefined-types": "off", - "jsdoc/check-param-names": "error", - "jsdoc/check-tag-names": "error", - "jsdoc/check-types": "error", - "jsdoc/implements-on-classes": "error", - "jsdoc/require-description": "error", - "jsdoc/require-jsdoc": [ - "error", - { - require: { - FunctionDeclaration: true, - MethodDefinition: true, - ClassDeclaration: true, - ArrowFunctionExpression: false, - FunctionExpression: false, - }, - }, - ], - "jsdoc/require-param": "error", - "jsdoc/require-param-description": "error", - "jsdoc/require-param-type": "off", - "jsdoc/require-returns": "error", - "jsdoc/require-returns-description": "error", - "jsdoc/require-returns-type": "off", - "jsdoc/require-hyphen-before-param-description": ["error", "always"], - }, - }, -]; diff --git a/examples/typescript/legacy/mcp/index.ts b/examples/typescript/legacy/mcp/index.ts deleted file mode 100644 index b473594fbd..0000000000 --- a/examples/typescript/legacy/mcp/index.ts +++ /dev/null @@ -1,50 +0,0 @@ -/** - * Need: - * - MCP server to be able to verify token (SSE should be able to do this) - * - Need client to be able to send header - * - Each client application would need to implement a wallet type - */ - -import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js"; -import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js"; -import axios from "axios"; -import { config } from "dotenv"; -import { Hex } from "viem"; -import { privateKeyToAccount } from "viem/accounts"; -import { withPaymentInterceptor } from "x402-axios"; - -config(); - -const privateKey = process.env.PRIVATE_KEY as Hex; -const baseURL = process.env.RESOURCE_SERVER_URL as string; // e.g. https://example.com -const endpointPath = process.env.ENDPOINT_PATH as string; // e.g. /weather - -if (!privateKey || !baseURL || !endpointPath) { - throw new Error("Missing environment variables"); -} - -const account = privateKeyToAccount(privateKey); - -const client = withPaymentInterceptor(axios.create({ baseURL }), account); - -// Create an MCP server -const server = new McpServer({ - name: "x402 MCP Client Demo", - version: "1.0.0", -}); - -// Add an addition tool -server.tool( - "get-data-from-resource-server", - "Get data from the resource server (in this example, the weather)", - {}, - async () => { - const res = await client.get(endpointPath); - return { - content: [{ type: "text", text: JSON.stringify(res.data) }], - }; - }, -); - -const transport = new StdioServerTransport(); -await server.connect(transport); diff --git a/examples/typescript/legacy/mcp/package.json b/examples/typescript/legacy/mcp/package.json deleted file mode 100644 index ad79c3af7a..0000000000 --- a/examples/typescript/legacy/mcp/package.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "mcp-client-example", - "private": true, - "type": "module", - "scripts": { - "dev": "tsx index.ts", - "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", - "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", - "lint": "eslint . --ext .ts --fix", - "lint:check": "eslint . --ext .ts" - }, - "dependencies": { - "@modelcontextprotocol/sdk": "^1.9.0", - "axios": "^1.8.4", - "dotenv": "^16.5.0", - "viem": "^2.26.2", - "x402-axios": "workspace:*", - "zod": "^3.24.2" - }, - "devDependencies": { - "@eslint/js": "^9.24.0", - "@typescript-eslint/eslint-plugin": "^8.29.1", - "@typescript-eslint/parser": "^8.29.1", - "eslint": "^9.24.0", - "eslint-plugin-import": "^2.31.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", - "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" - } -} diff --git a/examples/typescript/legacy/mcp/tsconfig.json b/examples/typescript/legacy/mcp/tsconfig.json deleted file mode 100644 index 1bdf94ca8d..0000000000 --- a/examples/typescript/legacy/mcp/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2022", - "module": "ES2022", - "moduleResolution": "bundler", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true, - "strict": true, - "resolveJsonModule": true, - "baseUrl": ".", - "types": ["node"] - }, - "include": ["index.ts"] -} diff --git a/examples/typescript/legacy/servers/advanced/.env-local b/examples/typescript/legacy/servers/advanced/.env-local deleted file mode 100644 index 9e299111bc..0000000000 --- a/examples/typescript/legacy/servers/advanced/.env-local +++ /dev/null @@ -1,7 +0,0 @@ -FACILITATOR_URL=https://x402.org/facilitator -NETWORK=base-sepolia -ADDRESS= - -# required if using the Base mainnet facilitator -CDP_API_KEY_ID="Coinbase Developer Platform Key" -CDP_API_KEY_SECRET="Coinbase Developer Platform Key Secret" \ No newline at end of file diff --git a/examples/typescript/legacy/servers/advanced/.prettierignore b/examples/typescript/legacy/servers/advanced/.prettierignore deleted file mode 100644 index 5bd240ba90..0000000000 --- a/examples/typescript/legacy/servers/advanced/.prettierignore +++ /dev/null @@ -1,8 +0,0 @@ -docs/ -dist/ -node_modules/ -coverage/ -.github/ -src/client -**/**/*.json -*.md \ No newline at end of file diff --git a/examples/typescript/legacy/servers/advanced/.prettierrc b/examples/typescript/legacy/servers/advanced/.prettierrc deleted file mode 100644 index ffb416b74b..0000000000 --- a/examples/typescript/legacy/servers/advanced/.prettierrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": false, - "trailingComma": "all", - "bracketSpacing": true, - "arrowParens": "avoid", - "printWidth": 100, - "proseWrap": "never" -} diff --git a/examples/typescript/legacy/servers/advanced/README.md b/examples/typescript/legacy/servers/advanced/README.md deleted file mode 100644 index 606dd6f295..0000000000 --- a/examples/typescript/legacy/servers/advanced/README.md +++ /dev/null @@ -1,176 +0,0 @@ -# x402 Advanced Resource Server Example - -This is an advanced example of an Express.js server that demonstrates how to implement paywall functionality without using middleware. This approach is useful for more complex scenarios, such as: - -- Asynchronous payment settlement -- Custom payment validation logic -- Complex routing requirements -- Integration with existing authentication systems - -## Prerequisites - -- Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) -- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- A valid Ethereum address for receiving payments -- Coinbase Developer Platform API Key & Secret (if accepting payments on Base mainnet) - -- Get them here [https://portal.cdp.coinbase.com/projects](https://portal.cdp.coinbase.com/projects) - -## Setup - -1. Copy `.env-local` to `.env` and add your Ethereum address: - -```bash -cp .env-local .env -``` - -2. Install and build all packages from the typescript examples root: -```bash -cd ../../ -pnpm install -pnpm build -cd servers/advanced -``` - -3. Run the server -```bash -pnpm install -pnpm dev -``` - -## Implementation Overview - -This advanced implementation provides a structured approach to handling payments with: - -1. Helper functions for creating payment requirements and verifying payments -2. Support for delayed payment settlement -3. Dynamic pricing capabilities -4. Multiple payment requirement options -5. Proper error handling and response formatting -6. Integration with the x402 facilitator service - -## Testing the Server - -You can test the server using one of the example clients: - -### Using the Fetch Client -```bash -cd ../../clients/fetch -# Ensure .env is setup -pnpm install -pnpm dev -``` - -### Using the Axios Client -```bash -cd ../../clients/axios -# Ensure .env is setup -pnpm install -pnpm dev -``` - -## Example Endpoints - -The server includes example endpoints that demonstrate different payment scenarios: - -### Delayed Settlement -- `/delayed-settlement` - Demonstrates asynchronous payment processing -- Returns the weather data immediately without waiting for payment settlement -- Processes payment asynchronously in the background -- Useful for scenarios where immediate response is critical and payment settlement can be handled later - -### Dynamic Pricing -- `/dynamic-price` - Shows how to implement variable pricing based on request parameters -- Accepts a `multiplier` query parameter to adjust the base price -- Demonstrates how to calculate and validate payments with dynamic amounts -- Useful for implementing tiered pricing or demand-based pricing models - -### Multiple Payment Requirements -- `/multiple-payment-requirements` - Illustrates how to accept multiple payment options -- Allows clients to pay using different assets (e.g., USDC or USDT) -- Supports multiple networks (e.g., Base and Base Sepolia) -- Useful for providing flexibility in payment methods and networks - -## Response Format - -### Payment Required (402) -```json -{ - "x402Version": 1, - "error": "X-PAYMENT header is required", - "accepts": [ - { - "scheme": "exact", - "network": "base-sepolia", - "maxAmountRequired": "1000", - "resource": "http://localhost:3001/weather", - "description": "Access to weather data", - "mimeType": "", - "payTo": "0xYourAddress", - "maxTimeoutSeconds": 60, - "asset": "0x...", - "outputSchema": null, - "extra": { - "name": "USD Coin", - "version": "1" - } - } - ] -} -``` - -### Successful Response -```json -// Body -{ - "report": { - "weather": "sunny", - "temperature": 70 - } -} -// Headers -{ - "X-PAYMENT-RESPONSE": "..." // Encoded response object -} -``` - -## Extending the Example - -To add more paid endpoints with delayed payment settlement, you can follow this pattern: - -```typescript -app.get("/your-endpoint", async (req, res) => { - const resource = `${req.protocol}://${req.headers.host}${req.originalUrl}` as Resource; - const paymentRequirements = [createExactPaymentRequirements( - "$0.001", // Your price - "base-sepolia", // Your network - resource, - "Description of your resource" - )]; - - const isValid = await verifyPayment(req, res, paymentRequirements); - if (!isValid) return; - - // Return your protected resource immediately - res.json({ - // Your response data - }); - - // Process payment asynchronously - try { - const settleResponse = await settle( - exact.evm.decodePayment(req.header("X-PAYMENT")!), - paymentRequirements[0] - ); - const responseHeader = settleResponseHeader(settleResponse); - // In a real application, you would store this response header - // and associate it with the payment for later verification - console.log("Payment settled:", responseHeader); - } catch (error) { - console.error("Payment settlement failed:", error); - // In a real application, you would handle the failed payment - // by marking it for retry or notifying the user - } -}); -``` - -For dynamic pricing or multiple payment requirements, refer to the `/dynamic-price` and `/multiple-payment-requirements` endpoints in the example code for implementation details. diff --git a/examples/typescript/legacy/servers/advanced/index.ts b/examples/typescript/legacy/servers/advanced/index.ts deleted file mode 100644 index 0bed76646b..0000000000 --- a/examples/typescript/legacy/servers/advanced/index.ts +++ /dev/null @@ -1,276 +0,0 @@ -import { config } from "dotenv"; -import express from "express"; -import { exact } from "x402/schemes"; -import { - Network, - PaymentPayload, - PaymentRequirements, - Price, - Resource, - settleResponseHeader, -} from "x402/types"; -import { useFacilitator } from "x402/verify"; -import { processPriceToAtomicAmount, findMatchingPaymentRequirements } from "x402/shared"; - -config(); - -const facilitatorUrl = process.env.FACILITATOR_URL as Resource; -const payTo = process.env.ADDRESS as `0x${string}`; - -if (!facilitatorUrl || !payTo) { - console.error("Missing required environment variables"); - process.exit(1); -} - -const app = express(); -const { verify, settle } = useFacilitator({ url: facilitatorUrl }); -const x402Version = 1; - -/** - * Creates payment requirements for a given price and network - * - * @param price - The price to be paid for the resource - * @param network - The blockchain network to use for payment - * @param resource - The resource being accessed - * @param description - Optional description of the payment - * @returns An array of payment requirements - */ -function createExactPaymentRequirements( - price: Price, - network: Network, - resource: Resource, - description = "", -): PaymentRequirements { - const atomicAmountForAsset = processPriceToAtomicAmount(price, network); - if ("error" in atomicAmountForAsset) { - throw new Error(atomicAmountForAsset.error); - } - const { maxAmountRequired, asset } = atomicAmountForAsset; - - return { - scheme: "exact", - network, - maxAmountRequired, - resource, - description, - mimeType: "", - payTo: payTo, - maxTimeoutSeconds: 60, - asset: asset.address, - outputSchema: undefined, - extra: { - name: asset.eip712.name, - version: asset.eip712.version, - }, - }; -} - -/** - * Verifies a payment and handles the response - * - * @param req - The Express request object - * @param res - The Express response object - * @param paymentRequirements - The payment requirements to verify against - * @returns A promise that resolves to true if payment is valid, false otherwise - */ -async function verifyPayment( - req: express.Request, - res: express.Response, - paymentRequirements: PaymentRequirements[], -): Promise { - const payment = req.header("X-PAYMENT"); - if (!payment) { - res.status(402).json({ - x402Version, - error: "X-PAYMENT header is required", - accepts: paymentRequirements, - }); - return false; - } - - let decodedPayment: PaymentPayload; - try { - decodedPayment = exact.evm.decodePayment(payment); - decodedPayment.x402Version = x402Version; - } catch (error) { - res.status(402).json({ - x402Version, - error: error || "Invalid or malformed payment header", - accepts: paymentRequirements, - }); - return false; - } - - try { - const selectedPaymentRequirement = - findMatchingPaymentRequirements(paymentRequirements, decodedPayment) || - paymentRequirements[0]; - const response = await verify(decodedPayment, selectedPaymentRequirement); - if (!response.isValid) { - res.status(402).json({ - x402Version, - error: response.invalidReason, - accepts: paymentRequirements, - payer: response.payer, - }); - return false; - } - } catch (error) { - res.status(402).json({ - x402Version, - error, - accepts: paymentRequirements, - }); - return false; - } - - return true; -} - -// Delayed settlement example endpoint -app.get("/delayed-settlement", async (req, res) => { - const resource = `${req.protocol}://${req.headers.host}${req.originalUrl}` as Resource; - const paymentRequirements = [ - createExactPaymentRequirements( - "$0.001", - // network: "base" // uncomment for Base mainnet - "base-sepolia", - resource, - "Access to weather data (async)", - ), - ]; - - const isValid = await verifyPayment(req, res, paymentRequirements); - if (!isValid) return; - - // Return weather data immediately - res.json({ - report: { - weather: "sunny", - temperature: 70, - }, - }); - - // Process payment asynchronously - try { - const settleResponse = await settle( - exact.evm.decodePayment(req.header("X-PAYMENT")!), - paymentRequirements[0], - ); - const responseHeader = settleResponseHeader(settleResponse); - // In a real application, you would store this response header - // and associate it with the payment for later verification - console.log("Payment settled:", responseHeader); - } catch (error) { - console.error("Payment settlement failed:", error); - // In a real application, you would handle the failed payment - // by marking it for retry or notifying the user - } -}); - -// Dynamic price example endpoint -app.get("/dynamic-price", async (req, res) => { - // Use query params, body, or external factors to determine if price is impacted - const multiplier = parseInt((req.query.multiplier as string) ?? "1"); - // Adjust pricing based on impact from inputs - const price = 0.001 * multiplier; - - const resource = `${req.protocol}://${req.headers.host}${req.originalUrl}` as Resource; - const paymentRequirements = [ - createExactPaymentRequirements( - price, // Expect dynamic pricing - // network: "base" // uncomment for Base mainnet - "base-sepolia", - resource, - "Access to weather data", - ), - ]; - - const isValid = await verifyPayment(req, res, paymentRequirements); - if (!isValid) return; - - try { - // Process payment synchronously - const settleResponse = await settle( - exact.evm.decodePayment(req.header("X-PAYMENT")!), - paymentRequirements[0], - ); - const responseHeader = settleResponseHeader(settleResponse); - res.setHeader("X-PAYMENT-RESPONSE", responseHeader); - - // Return the weather data - res.json({ - report: { - success: "sunny", - temperature: 70, - }, - }); - } catch (error) { - res.status(402).json({ - x402Version, - error, - accepts: paymentRequirements, - }); - } -}); - -// Multiple payment requirements example endpoint -app.get("/multiple-payment-requirements", async (req, res) => { - const resource = `${req.protocol}://${req.headers.host}${req.originalUrl}` as Resource; - - // Payment requirements is an array. You can mix and match tokens, prices, and networks. - const paymentRequirements = [ - createExactPaymentRequirements("$0.001", "base", resource), - createExactPaymentRequirements( - { - amount: "1000", - asset: { - address: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", - decimals: 6, - eip712: { - name: "USDC", - version: "2", - }, - }, - }, - // network: "base" // uncomment for Base mainnet - "base-sepolia", - resource, - ), - ]; - - const isValid = await verifyPayment(req, res, paymentRequirements); - if (!isValid) return; - - try { - // Process payment synchronously - const decodedPayment = exact.evm.decodePayment(req.header("X-PAYMENT")!); - - // Find the matching payment requirement - const selectedPaymentRequirement = - findMatchingPaymentRequirements(paymentRequirements, decodedPayment) || - paymentRequirements[0]; - - const settleResponse = await settle(decodedPayment, selectedPaymentRequirement); - const responseHeader = settleResponseHeader(settleResponse); - res.setHeader("X-PAYMENT-RESPONSE", responseHeader); - - // Return the weather data - res.json({ - report: { - success: "sunny", - temperature: 70, - }, - }); - } catch (error) { - res.status(402).json({ - x402Version, - error, - accepts: paymentRequirements, - }); - } -}); - -app.listen(4021, () => { - console.log(`Server listening at http://localhost:4021`); -}); diff --git a/examples/typescript/legacy/servers/advanced/tsconfig.json b/examples/typescript/legacy/servers/advanced/tsconfig.json deleted file mode 100644 index 78f9479b1b..0000000000 --- a/examples/typescript/legacy/servers/advanced/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ES2020", - "moduleResolution": "bundler", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true, - "strict": true, - "resolveJsonModule": true, - "baseUrl": ".", - "types": ["node"] - }, - "include": ["index.ts"] -} diff --git a/examples/typescript/legacy/servers/express/.env-local b/examples/typescript/legacy/servers/express/.env-local deleted file mode 100644 index 9e299111bc..0000000000 --- a/examples/typescript/legacy/servers/express/.env-local +++ /dev/null @@ -1,7 +0,0 @@ -FACILITATOR_URL=https://x402.org/facilitator -NETWORK=base-sepolia -ADDRESS= - -# required if using the Base mainnet facilitator -CDP_API_KEY_ID="Coinbase Developer Platform Key" -CDP_API_KEY_SECRET="Coinbase Developer Platform Key Secret" \ No newline at end of file diff --git a/examples/typescript/legacy/servers/express/.prettierignore b/examples/typescript/legacy/servers/express/.prettierignore deleted file mode 100644 index 5bd240ba90..0000000000 --- a/examples/typescript/legacy/servers/express/.prettierignore +++ /dev/null @@ -1,8 +0,0 @@ -docs/ -dist/ -node_modules/ -coverage/ -.github/ -src/client -**/**/*.json -*.md \ No newline at end of file diff --git a/examples/typescript/legacy/servers/express/.prettierrc b/examples/typescript/legacy/servers/express/.prettierrc deleted file mode 100644 index ffb416b74b..0000000000 --- a/examples/typescript/legacy/servers/express/.prettierrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": false, - "trailingComma": "all", - "bracketSpacing": true, - "arrowParens": "avoid", - "printWidth": 100, - "proseWrap": "never" -} diff --git a/examples/typescript/legacy/servers/express/README.md b/examples/typescript/legacy/servers/express/README.md deleted file mode 100644 index 5adab235ce..0000000000 --- a/examples/typescript/legacy/servers/express/README.md +++ /dev/null @@ -1,146 +0,0 @@ -# x402-express Example Server - -This is an example Express.js server that demonstrates how to use the `x402-express` middleware to implement paywall functionality in your API endpoints. - -## Prerequisites - -- Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) -- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- A valid Ethereum address for receiving payments -- Coinbase Developer Platform API Key & Secret (if accepting payments on Base mainnet) - -- Get them here [https://portal.cdp.coinbase.com/projects](https://portal.cdp.coinbase.com/projects) - -## Setup - -1. Copy `.env-local` to `.env` and add your Ethereum address to receive payments: - -```bash -cp .env-local .env -``` - -2. Install and build all packages from the typescript examples root: -```bash -cd ../../ -pnpm install -pnpm build -cd servers/express -``` - -3. Run the server -```bash -pnpm install -pnpm dev -``` - -## Testing the Server - -You can test the server using one of the example clients: - -### Using the Fetch Client -```bash -cd ../clients/fetch -# Ensure .env is setup -pnpm install -pnpm dev -``` - -### Using the Axios Client -```bash -cd ../clients/axios -# Ensure .env is setup -pnpm install -pnpm dev -``` - -These clients will demonstrate how to: -1. Make an initial request to get payment requirements -2. Process the payment requirements -3. Make a second request with the payment token - -## Example Endpoint - -The server includes a single example endpoint at `/weather` that requires a payment of $0.001 to access. The endpoint returns a simple weather report. - -## Response Format - -### Payment Required (402) -```json -{ - "error": "X-PAYMENT header is required", - "paymentRequirements": { - "scheme": "exact", - "network": "base", - "maxAmountRequired": "1000", - "resource": "http://localhost:4021/weather", - "description": "", - "mimeType": "", - "payTo": "0xYourAddress", - "maxTimeoutSeconds": 60, - "asset": "0x...", - "outputSchema": null, - "extra": null - } -} -``` - -### Successful Response -```ts -// Body -{ - "report": { - "weather": "sunny", - "temperature": 70 - } -} -// Headers -{ - "X-PAYMENT-RESPONSE": "..." // Encoded response object -} -``` - -## Extending the Example - -To add more paid endpoints, follow this pattern: - -```typescript -// First, configure the payment middleware with your routes -app.use( - paymentMiddleware( - payTo, - { - // Define your routes and their payment requirements - "GET /your-endpoint": { - price: "$0.10", - network: "base-sepolia", - }, - "/premium/*": { - price: { - amount: "100000", - asset: { - address: "0xabc", - decimals: 18, - eip712: { - name: "WETH", - version: "1", - }, - }, - }, - network: "base-sepolia", - }, - }, - ), -); - -// Then define your routes as normal -app.get("/your-endpoint", (req, res) => { - res.json({ - // Your response data - }); -}); - -app.get("/premium/content", (req, res) => { - res.json({ - content: "This is premium content", - }); -}); -``` diff --git a/examples/typescript/legacy/servers/express/index.ts b/examples/typescript/legacy/servers/express/index.ts deleted file mode 100644 index 37e35d27ce..0000000000 --- a/examples/typescript/legacy/servers/express/index.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { config } from "dotenv"; -import express from "express"; -import { paymentMiddleware, Resource, type SolanaAddress } from "x402-express"; -config(); - -const facilitatorUrl = process.env.FACILITATOR_URL as Resource; -const payTo = process.env.ADDRESS as `0x${string}` | SolanaAddress; - -if (!facilitatorUrl || !payTo) { - console.error("Missing required environment variables"); - process.exit(1); -} - -const app = express(); - -app.use( - paymentMiddleware( - payTo, - { - "GET /weather": { - // USDC amount in dollars - price: "$0.001", - // network: "base" // uncomment for Base mainnet - // network: "solana" // uncomment for Solana mainnet - network: "base-sepolia", - }, - "/premium/*": { - // Define atomic amounts in any EIP-3009 token - price: { - amount: "100000", - asset: { - address: "0xabc", - decimals: 18, - // omit eip712 for Solana - eip712: { - name: "WETH", - version: "1", - }, - }, - }, - // network: "base" // uncomment for Base mainnet - // network: "solana" // uncomment for Solana mainnet - network: "base-sepolia", - }, - }, - { - url: facilitatorUrl, - }, - ), -); - -app.get("/weather", (req, res) => { - res.send({ - report: { - weather: "sunny", - temperature: 70, - }, - }); -}); - -app.get("/premium/content", (req, res) => { - res.send({ - content: "This is premium content", - }); -}); - -app.listen(4021, () => { - console.log(`Server listening at http://localhost:${4021}`); -}); diff --git a/examples/typescript/legacy/servers/express/tsconfig.json b/examples/typescript/legacy/servers/express/tsconfig.json deleted file mode 100644 index 78f9479b1b..0000000000 --- a/examples/typescript/legacy/servers/express/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ES2020", - "moduleResolution": "bundler", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true, - "strict": true, - "resolveJsonModule": true, - "baseUrl": ".", - "types": ["node"] - }, - "include": ["index.ts"] -} diff --git a/examples/typescript/legacy/servers/hono/.env-local b/examples/typescript/legacy/servers/hono/.env-local deleted file mode 100644 index 9e299111bc..0000000000 --- a/examples/typescript/legacy/servers/hono/.env-local +++ /dev/null @@ -1,7 +0,0 @@ -FACILITATOR_URL=https://x402.org/facilitator -NETWORK=base-sepolia -ADDRESS= - -# required if using the Base mainnet facilitator -CDP_API_KEY_ID="Coinbase Developer Platform Key" -CDP_API_KEY_SECRET="Coinbase Developer Platform Key Secret" \ No newline at end of file diff --git a/examples/typescript/legacy/servers/hono/.prettierignore b/examples/typescript/legacy/servers/hono/.prettierignore deleted file mode 100644 index 5bd240ba90..0000000000 --- a/examples/typescript/legacy/servers/hono/.prettierignore +++ /dev/null @@ -1,8 +0,0 @@ -docs/ -dist/ -node_modules/ -coverage/ -.github/ -src/client -**/**/*.json -*.md \ No newline at end of file diff --git a/examples/typescript/legacy/servers/hono/.prettierrc b/examples/typescript/legacy/servers/hono/.prettierrc deleted file mode 100644 index ffb416b74b..0000000000 --- a/examples/typescript/legacy/servers/hono/.prettierrc +++ /dev/null @@ -1,11 +0,0 @@ -{ - "tabWidth": 2, - "useTabs": false, - "semi": true, - "singleQuote": false, - "trailingComma": "all", - "bracketSpacing": true, - "arrowParens": "avoid", - "printWidth": 100, - "proseWrap": "never" -} diff --git a/examples/typescript/legacy/servers/hono/README.md b/examples/typescript/legacy/servers/hono/README.md deleted file mode 100644 index 34cfba8482..0000000000 --- a/examples/typescript/legacy/servers/hono/README.md +++ /dev/null @@ -1,150 +0,0 @@ -# x402-hono Example Server - -This is an example Hono server that demonstrates how to use the `x402-hono` middleware to implement paywall functionality in your API endpoints. - -## Prerequisites - -- Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) -- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) -- A valid Ethereum address for receiving payments -- Coinbase Developer Platform API Key & Secret (if accepting payments on Base mainnet) --- get them here [https://portal.cdp.coinbase.com/projects](https://portal.cdp.coinbase.com/projects) - -## Setup - -1. Copy `.env-local` to `.env` and add your Ethereum address to receive payments: - -```bash -cp .env-local .env -``` - -2. Install and build all packages from the typescript examples root: - -```bash -cd ../../ -pnpm install -pnpm build -cd servers/hono -``` - -3. Run the server - -```bash -pnpm install -pnpm dev -``` - -## Testing the Server - -You can test the server using one of the example clients: - -### Using the Fetch Client - -```bash -cd ../clients/fetch -# Ensure .env is setup -pnpm install -pnpm dev -``` - -### Using the Axios Client - -```bash -cd ../clients/axios -# Ensure .env is setup -pnpm install -pnpm dev -``` - -These clients will demonstrate how to: - -1. Make an initial request to get payment requirements -2. Process the payment requirements -3. Make a second request with the payment token - -## Example Endpoint - -The server includes a single example endpoint at `/weather` that requires a payment of $0.001 to access. The endpoint returns a simple weather report. - -## Response Format - -### Payment Required (402) - -```json -{ - "error": "X-PAYMENT header is required", - "paymentRequirements": { - "scheme": "exact", - "network": "base", - "maxAmountRequired": "1000", - "resource": "http://localhost:4021/weather", - "description": "", - "mimeType": "", - "payTo": "0xYourAddress", - "maxTimeoutSeconds": 60, - "asset": "0x...", - "outputSchema": null, - "extra": null - } -} -``` - -### Successful Response - -```ts -// Body -{ - "report": { - "weather": "sunny", - "temperature": 70 - } -} -// Headers -{ - "X-PAYMENT-RESPONSE": "..." // Encoded response object -} -``` - -## Extending the Example - -To add more paid endpoints, follow this pattern: - -```typescript -// First, configure the payment middleware with your routes -app.use( - paymentMiddleware(payTo, { - // Define your routes and their payment requirements - "/your-endpoint": { - price: "$0.10", - network, - }, - "/premium/*": { - price: { - amount: "100000", - asset: { - address: "0xabc", - decimals: 18, - eip712: { - name: "WETH", - version: "1", - }, - }, - }, - network, - }, - }), -); - -// Then define your routes as normal -app.get("/your-endpoint", c => { - return c.json({ - // Your response data - }); -}); - -app.get("/premium/content", c => { - return c.json({ - content: "This is premium content", - }); -}); -``` diff --git a/examples/typescript/legacy/servers/hono/eslint.config.js b/examples/typescript/legacy/servers/hono/eslint.config.js deleted file mode 100644 index e2fde7b3b8..0000000000 --- a/examples/typescript/legacy/servers/hono/eslint.config.js +++ /dev/null @@ -1,73 +0,0 @@ -import js from "@eslint/js"; -import ts from "@typescript-eslint/eslint-plugin"; -import tsParser from "@typescript-eslint/parser"; -import prettier from "eslint-plugin-prettier"; -import jsdoc from "eslint-plugin-jsdoc"; -import importPlugin from "eslint-plugin-import"; - -export default [ - { - ignores: ["dist/**", "node_modules/**"], - }, - { - files: ["**/*.ts"], - languageOptions: { - parser: tsParser, - sourceType: "module", - ecmaVersion: 2020, - globals: { - process: "readonly", - __dirname: "readonly", - module: "readonly", - require: "readonly", - Buffer: "readonly", - console: "readonly", - exports: "readonly", - setTimeout: "readonly", - clearTimeout: "readonly", - setInterval: "readonly", - clearInterval: "readonly", - }, - }, - plugins: { - "@typescript-eslint": ts, - prettier: prettier, - jsdoc: jsdoc, - import: importPlugin, - }, - rules: { - ...ts.configs.recommended.rules, - "import/first": "error", - "prettier/prettier": "error", - "@typescript-eslint/member-ordering": "error", - "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_$" }], - "jsdoc/tag-lines": ["error", "any", { startLines: 1 }], - "jsdoc/check-alignment": "error", - "jsdoc/no-undefined-types": "off", - "jsdoc/check-param-names": "error", - "jsdoc/check-tag-names": "error", - "jsdoc/check-types": "error", - "jsdoc/implements-on-classes": "error", - "jsdoc/require-description": "error", - "jsdoc/require-jsdoc": [ - "error", - { - require: { - FunctionDeclaration: true, - MethodDefinition: true, - ClassDeclaration: true, - ArrowFunctionExpression: false, - FunctionExpression: false, - }, - }, - ], - "jsdoc/require-param": "error", - "jsdoc/require-param-description": "error", - "jsdoc/require-param-type": "off", - "jsdoc/require-returns": "error", - "jsdoc/require-returns-description": "error", - "jsdoc/require-returns-type": "off", - "jsdoc/require-hyphen-before-param-description": ["error", "always"], - }, - }, -]; diff --git a/examples/typescript/legacy/servers/hono/index.ts b/examples/typescript/legacy/servers/hono/index.ts deleted file mode 100644 index 5a47da021d..0000000000 --- a/examples/typescript/legacy/servers/hono/index.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { config } from "dotenv"; -import { Hono } from "hono"; -import { serve } from "@hono/node-server"; -import { paymentMiddleware, Network, Resource, SolanaAddress } from "x402-hono"; - -config(); - -const facilitatorUrl = process.env.FACILITATOR_URL as Resource; -const payTo = process.env.ADDRESS as `0x${string}` | SolanaAddress; -const network = process.env.NETWORK as Network; - -if (!facilitatorUrl || !payTo || !network) { - console.error("Missing required environment variables"); - process.exit(1); -} - -const app = new Hono(); - -console.log("Server is running"); - -app.use( - paymentMiddleware( - payTo, - { - "/weather": { - price: "$0.001", - network, - }, - }, - { - url: facilitatorUrl, - }, - ), -); - -app.get("/weather", c => { - return c.json({ - report: { - weather: "sunny", - temperature: 70, - }, - }); -}); - -serve({ - fetch: app.fetch, - port: 4021, -}); diff --git a/examples/typescript/legacy/servers/hono/package.json b/examples/typescript/legacy/servers/hono/package.json deleted file mode 100644 index 4f0cefc631..0000000000 --- a/examples/typescript/legacy/servers/hono/package.json +++ /dev/null @@ -1,31 +0,0 @@ -{ - "name": "hono-server-example", - "private": true, - "type": "module", - "scripts": { - "dev": "tsx index.ts", - "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", - "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", - "lint": "eslint . --ext .ts --fix", - "lint:check": "eslint . --ext .ts" - }, - "dependencies": { - "@hono/node-server": "^1.13.8", - "dotenv": "^16.4.7", - "hono": "^4.7.1", - "x402-hono": "workspace:*" - }, - "devDependencies": { - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0", - "@eslint/js": "^9.24.0", - "eslint": "^9.24.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", - "@typescript-eslint/eslint-plugin": "^8.29.1", - "@typescript-eslint/parser": "^8.29.1", - "eslint-plugin-import": "^2.31.0", - "prettier": "3.5.2" - } -} diff --git a/examples/typescript/legacy/servers/hono/tsconfig.json b/examples/typescript/legacy/servers/hono/tsconfig.json deleted file mode 100644 index 78f9479b1b..0000000000 --- a/examples/typescript/legacy/servers/hono/tsconfig.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2020", - "module": "ES2020", - "moduleResolution": "bundler", - "esModuleInterop": true, - "forceConsistentCasingInFileNames": true, - "skipLibCheck": true, - "strict": true, - "resolveJsonModule": true, - "baseUrl": ".", - "types": ["node"] - }, - "include": ["index.ts"] -} diff --git a/examples/typescript/package.json b/examples/typescript/package.json index 25d9cef353..c75d77a4d5 100644 --- a/examples/typescript/package.json +++ b/examples/typescript/package.json @@ -14,10 +14,11 @@ "keywords": [], "author": "", "license": "ISC", - "packageManager": "pnpm@10.7.0", + "packageManager": "pnpm@11.1.1", "devDependencies": { + "prettier-linter-helpers": "^1.0.1", "tsup": "^8.4.0", "turbo": "^2.5.0", - "typescript": "^5.8.3" + "typescript": "^5.7.3" } -} \ No newline at end of file +} diff --git a/examples/typescript/pnpm-lock.yaml b/examples/typescript/pnpm-lock.yaml index 0897f2bcf7..71583637e8 100644 --- a/examples/typescript/pnpm-lock.yaml +++ b/examples/typescript/pnpm-lock.yaml @@ -8,15 +8,18 @@ importers: .: devDependencies: + prettier-linter-helpers: + specifier: ^1.0.1 + version: 1.0.1 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) turbo: specifier: ^2.5.0 version: 2.5.6 typescript: - specifier: ^5.8.3 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 ../../typescript/packages/core: dependencies: @@ -41,34 +44,34 @@ importers: version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../../typescript/packages/extensions: dependencies: @@ -78,6 +81,9 @@ importers: '@scure/base': specifier: ^1.2.6 version: 1.2.6 + '@signinwithethereum/siwe': + specifier: ^4.1.0 + version: 4.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@x402/core': specifier: workspace:~ version: link:../core @@ -87,15 +93,12 @@ importers: jose: specifier: ^5.9.6 version: 5.10.0 - siwe: - specifier: ^2.3.2 - version: 2.3.2(ethers@6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) tweetnacl: specifier: ^1.0.3 version: 1.0.3 viem: - specifier: ^2.43.5 - version: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zod: specifier: ^3.24.2 version: 3.25.76 @@ -117,46 +120,40 @@ importers: version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../../typescript/packages/http/axios: dependencies: '@x402/core': specifier: workspace:~ version: link:../../core - axios: - specifier: ^1.7.9 - version: 1.13.2 - zod: - specifier: ^3.24.2 - version: 3.25.76 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -170,39 +167,42 @@ importers: '@typescript-eslint/parser': specifier: ^8.29.1 version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + axios: + specifier: ^1.7.9 + version: 1.13.2 eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../../typescript/packages/http/express: dependencies: @@ -215,12 +215,6 @@ importers: '@x402/paywall': specifier: workspace:^ version: link:../paywall - viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zod: - specifier: ^3.24.2 - version: 3.25.76 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -242,13 +236,13 @@ importers: version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) express: specifier: ^4.18.2 version: 4.21.2 @@ -257,22 +251,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../../typescript/packages/http/fastify: dependencies: @@ -283,7 +277,7 @@ importers: specifier: workspace:~ version: link:../../extensions '@x402/paywall': - specifier: workspace:* + specifier: workspace:^ version: link:../paywall devDependencies: '@eslint/js': @@ -303,13 +297,13 @@ importers: version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) fastify: specifier: ^5.0.0 version: 5.8.2 @@ -318,34 +312,28 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../../typescript/packages/http/fetch: dependencies: '@x402/core': specifier: workspace:~ version: link:../../core - viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zod: - specifier: ^3.24.2 - version: 3.25.76 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -364,34 +352,34 @@ importers: version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../../typescript/packages/http/hono: dependencies: @@ -404,9 +392,6 @@ importers: '@x402/paywall': specifier: workspace:^ version: link:../paywall - zod: - specifier: ^3.24.2 - version: 3.25.76 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -425,13 +410,13 @@ importers: version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) hono: specifier: ^4.7.1 version: 4.10.7 @@ -440,22 +425,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../../typescript/packages/http/next: dependencies: @@ -469,11 +454,8 @@ importers: specifier: workspace:^ version: link:../paywall next: - specifier: ^16.0.10 + specifier: '>=16.0.10 <16.1.0' version: 16.0.10(@babel/core@7.28.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - zod: - specifier: ^3.24.2 - version: 3.25.76 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -492,37 +474,46 @@ importers: version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) ../../typescript/packages/http/paywall: dependencies: + '@algorandfoundation/algokit-utils': + specifier: 10.0.0-alpha.46 + version: 10.0.0-alpha.46 + '@blockshake/defly-connect': + specifier: ^1.2.1 + version: 1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@perawallet/connect': + specifier: ^1.4.2 + version: 1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@scure/base': specifier: ^1.2.6 version: 1.2.6 @@ -540,19 +531,22 @@ importers: version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) '@solana/transaction-confirmation': specifier: ^2.1.1 - version: 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/wallet-standard-features': specifier: ^1.3.0 version: 1.3.0 '@tanstack/react-query': specifier: ^5.90.7 version: 5.90.11(react@19.1.1) + '@txnlab/use-wallet': + specifier: ^4.3.1 + version: 4.6.0(@blockshake/defly-connect@1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@perawallet/connect@1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@walletconnect/sign-client@2.23.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(algosdk@3.5.2)(lute-connect@1.7.0) '@wagmi/connectors': specifier: ^5.8.1 - version: 5.9.4(@types/react@19.1.10)(@upstash/redis@1.35.3)(@wagmi/core@2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + version: 5.9.4(@types/react@19.1.10)(@wagmi/core@2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) '@wagmi/core': specifier: ^2.17.1 - version: 2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + version: 2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@wallet-standard/app': specifier: ^1.1.0 version: 1.1.0 @@ -562,22 +556,25 @@ importers: '@wallet-standard/features': specifier: ^1.1.0 version: 1.1.0 + '@walletconnect/sign-client': + specifier: ^2.23.1 + version: 2.23.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@x402/core': specifier: workspace:~ version: link:../../core + lute-connect: + specifier: ^1.6.3 + version: 1.7.0 viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) wagmi: specifier: ^2.17.1 - version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.1.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - zod: - specifier: ^3.24.2 - version: 3.25.76 + version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.1.1))(@types/react@19.1.10)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) devDependencies: '@craftamap/esbuild-plugin-html': specifier: ^0.9.0 - version: 0.9.0(bufferutil@4.0.9)(esbuild@0.25.9)(utf-8-validate@5.0.10) + version: 0.9.0(bufferutil@4.0.9)(esbuild@0.27.7)(utf-8-validate@5.0.10) '@eslint/js': specifier: ^9.24.0 version: 9.33.0 @@ -596,6 +593,9 @@ importers: '@typescript-eslint/parser': specifier: ^8.29.1 version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@x402/avm': + specifier: workspace:~ + version: link:../../mechanisms/avm '@x402/evm': specifier: workspace:~ version: link:../../mechanisms/evm @@ -606,20 +606,20 @@ importers: specifier: ^6.0.3 version: 6.0.3 esbuild: - specifier: ^0.25.4 - version: 0.25.9 + specifier: ^0.27.2 + version: 0.27.7 eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 @@ -631,155 +631,98 @@ importers: version: 19.1.1(react@19.1.1) tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) - ../../typescript/packages/legacy/x402: + ../../typescript/packages/mcp: dependencies: - '@scure/base': - specifier: ^1.2.6 - version: 1.2.6 - '@solana-program/compute-budget': - specifier: ^0.11.0 - version: 0.11.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token': - specifier: ^0.9.0 - version: 0.9.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token-2022': - specifier: ^0.6.1 - version: 0.6.1(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)) - '@solana/kit': - specifier: ^5.0.0 - version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/transaction-confirmation': - specifier: ^5.0.0 - version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/wallet-standard-features': - specifier: ^1.3.0 - version: 1.3.0 - '@wallet-standard/app': - specifier: ^1.1.0 - version: 1.1.0 - '@wallet-standard/base': - specifier: ^1.1.0 - version: 1.1.0 - '@wallet-standard/features': - specifier: ^1.1.0 - version: 1.1.0 - viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - wagmi: - specifier: ^2.15.6 - version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + '@modelcontextprotocol/sdk': + specifier: ^1.12.1 + version: 1.17.3 + '@x402/core': + specifier: workspace:~ + version: link:../core zod: specifier: ^3.24.2 version: 3.25.76 devDependencies: - '@coinbase/onchainkit': - specifier: ^0.38.14 - version: 0.38.19(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - '@craftamap/esbuild-plugin-html': - specifier: ^0.9.0 - version: 0.9.0(bufferutil@4.0.9)(esbuild@0.25.9)(utf-8-validate@5.0.10) '@eslint/js': specifier: ^9.24.0 version: 9.33.0 '@types/node': specifier: ^22.13.4 version: 22.17.2 - '@types/react': - specifier: ^19 - version: 19.1.10 - '@types/react-dom': - specifier: ^19 - version: 19.1.7(@types/react@19.1.10) '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@wagmi/connectors': - specifier: ^5.8.1 - version: 5.9.4(@types/react@19.1.10)(@upstash/redis@1.35.3)(@wagmi/core@2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) - '@wagmi/core': - specifier: ^2.17.1 - version: 2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - buffer: - specifier: ^6.0.3 - version: 6.0.3 - esbuild: - specifier: ^0.25.4 - version: 0.25.9 + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@x402/evm': + specifier: workspace:~ + version: link:../mechanisms/evm eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + express: + specifier: ^4.21.2 + version: 4.21.2 prettier: specifier: 3.5.2 version: 3.5.2 - react: - specifier: 19.2.1 - version: 19.2.1 - react-dom: - specifier: 19.2.1 - version: 19.2.1(react@19.2.1) tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 + viem: + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) - ../../typescript/packages/legacy/x402-axios: + ../../typescript/packages/mechanisms/aptos: dependencies: - axios: - specifier: ^1.7.9 - version: 1.13.2 - viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - x402: - specifier: workspace:^ - version: link:../x402 - zod: - specifier: ^3.24.2 - version: 3.25.76 + '@aptos-labs/ts-sdk': + specifier: ^5.2.1 + version: 5.2.1(got@11.8.6) + '@x402/core': + specifier: workspace:~ + version: link:../../core devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -789,122 +732,107 @@ importers: version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) - ../../typescript/packages/legacy/x402-express: + ../../typescript/packages/mechanisms/avm: dependencies: - '@coinbase/cdp-sdk': - specifier: ^1.22.0 - version: 1.36.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@solana/kit': - specifier: ^5.0.0 - version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - express: - specifier: ^4.18.2 - version: 4.21.2 - viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - x402: - specifier: workspace:^ - version: link:../x402 - zod: - specifier: ^3.24.2 - version: 3.25.76 + '@algorandfoundation/algokit-utils': + specifier: 10.0.0-alpha.46 + version: 10.0.0-alpha.46 + '@x402/core': + specifier: workspace:~ + version: link:../../core devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 - '@types/express': - specifier: ^5.0.1 - version: 5.0.3 '@types/node': specifier: ^22.13.4 version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) - ../../typescript/packages/legacy/x402-fetch: + ../../typescript/packages/mechanisms/evm: dependencies: + '@x402/core': + specifier: workspace:~ + version: link:../../core viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - x402: - specifier: workspace:^ - version: link:../x402 + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zod: specifier: ^3.24.2 version: 3.25.76 @@ -926,55 +854,43 @@ importers: version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) - ../../typescript/packages/legacy/x402-hono: + ../../typescript/packages/mechanisms/hedera: dependencies: - '@coinbase/cdp-sdk': - specifier: ^1.22.0 - version: 1.36.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@solana/kit': - specifier: ^5.0.0 - version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - hono: - specifier: ^4.7.1 - version: 4.10.7 - viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - x402: - specifier: workspace:^ - version: link:../x402 - zod: - specifier: ^3.24.2 - version: 3.25.76 + '@hiero-ledger/sdk': + specifier: 2.80.0 + version: 2.80.0(bn.js@5.2.1)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)) + '@x402/core': + specifier: workspace:* + version: link:../../core devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -984,64 +900,52 @@ importers: version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) - ../../typescript/packages/legacy/x402-next: + ../../typescript/packages/mechanisms/stellar: dependencies: - '@coinbase/cdp-sdk': - specifier: ^1.22.0 - version: 1.36.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@solana/kit': - specifier: ^5.0.0 - version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - next: - specifier: '>=15.5.9 || >=16.0.10' - version: 16.0.10(@babel/core@7.28.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - x402: - specifier: workspace:^ - version: link:../x402 - zod: - specifier: ^3.24.2 - version: 3.25.76 + '@stellar/stellar-sdk': + specifier: ^14.6.1 + version: 14.6.1 + '@x402/core': + specifier: workspace:~ + version: link:../../core devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -1051,461 +955,287 @@ importers: version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) - ../../typescript/packages/mcp: + ../../typescript/packages/mechanisms/svm: dependencies: - '@modelcontextprotocol/sdk': - specifier: ^1.12.1 - version: 1.17.3 + '@solana-program/compute-budget': + specifier: ^0.11.0 + version: 0.11.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token': + specifier: ^0.9.0 + version: 0.9.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token-2022': + specifier: ^0.6.1 + version: 0.6.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)) + '@solana/kit': + specifier: '>=5.1.0' + version: 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@x402/core': specifier: workspace:~ - version: link:../core - zod: - specifier: ^3.24.2 - version: 3.25.76 + version: link:../../core devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 + '@scure/base': + specifier: ^1.2.6 + version: 1.2.6 '@types/node': specifier: ^22.13.4 version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@x402/evm': - specifier: workspace:~ - version: link:../mechanisms/evm + version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - express: - specifier: ^4.21.2 - version: 4.21.2 + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 - viem: - specifier: ^2.27.2 - version: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) - ../../typescript/packages/mechanisms/aptos: + clients/advanced: dependencies: - '@aptos-labs/ts-sdk': - specifier: ^5.2.1 - version: 5.2.1(got@11.8.6) - '@x402/core': + '@scure/base': + specifier: ^1.2.6 + version: 1.2.6 + '@solana/kit': + specifier: ^6.1.0 + version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@x402/avm': specifier: workspace:* - version: link:../../core - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@types/node': - specifier: ^22.13.4 - version: 22.17.2 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsup: - specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) - tsx: - specifier: ^4.19.2 - version: 4.20.4 - typescript: - specifier: ^5.7.3 - version: 5.9.2 - vite: - specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - vite-tsconfig-paths: - specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) - vitest: - specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - - ../../typescript/packages/mechanisms/evm: - dependencies: - '@x402/core': - specifier: workspace:~ - version: link:../../core - viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zod: - specifier: ^3.24.2 - version: 3.25.76 - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@types/node': - specifier: ^22.13.4 - version: 22.17.2 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsup: - specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) - tsx: - specifier: ^4.19.2 - version: 4.20.4 - typescript: - specifier: ^5.7.3 - version: 5.9.2 - vite: - specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - vite-tsconfig-paths: - specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) - vitest: - specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - - ../../typescript/packages/mechanisms/stellar: - dependencies: - '@stellar/stellar-sdk': - specifier: ^14.6.1 - version: 14.6.1 - '@x402/core': + version: link:../../../../typescript/packages/mechanisms/avm + '@x402/evm': specifier: workspace:* - version: link:../../core - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@types/node': - specifier: ^22.13.4 - version: 22.17.2 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsup: - specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) - tsx: - specifier: ^4.19.2 - version: 4.20.4 - typescript: - specifier: ^5.7.3 - version: 5.9.2 - vite: - specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - vite-tsconfig-paths: - specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) - vitest: - specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - - ../../typescript/packages/mechanisms/svm: - dependencies: - '@solana-program/compute-budget': - specifier: ^0.11.0 - version: 0.11.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token': - specifier: ^0.9.0 - version: 0.9.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token-2022': - specifier: ^0.6.1 - version: 0.6.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)) - '@solana/kit': - specifier: '>=5.1.0' - version: 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@x402/core': - specifier: workspace:~ - version: link:../../core + version: link:../../../../typescript/packages/mechanisms/evm + '@x402/fetch': + specifier: workspace:* + version: link:../../../../typescript/packages/http/fetch + '@x402/hedera': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/hedera + '@x402/stellar': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/stellar + '@x402/svm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/svm + dotenv: + specifier: ^16.4.7 + version: 16.6.1 + viem: + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 - '@scure/base': - specifier: ^1.2.6 - version: 1.2.6 '@types/node': specifier: ^22.13.4 version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 - tsup: - specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 - version: 5.9.2 - vite: - specifier: ^6.2.6 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - vite-tsconfig-paths: - specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) - vitest: - specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) + version: 5.9.3 - clients/advanced: + clients/axios: dependencies: '@scure/base': specifier: ^1.2.6 version: 1.2.6 '@solana/kit': specifier: ^6.1.0 - version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) + version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@x402/axios': + specifier: workspace:* + version: link:../../../../typescript/packages/http/axios '@x402/evm': specifier: workspace:* version: link:../../../../typescript/packages/mechanisms/evm - '@x402/fetch': - specifier: workspace:* - version: link:../../../../typescript/packages/http/fetch - '@x402/stellar': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/stellar '@x402/svm': specifier: workspace:* version: link:../../../../typescript/packages/mechanisms/svm + axios: + specifier: ^1.13.2 + version: 1.13.4 dotenv: specifier: ^16.4.7 version: 16.6.1 viem: - specifier: ^2.39.0 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - clients/axios: + clients/batch-settlement: dependencies: - '@scure/base': - specifier: ^1.2.6 - version: 1.2.6 - '@solana/kit': - specifier: ^6.1.0 - version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@x402/axios': - specifier: workspace:* - version: link:../../../../typescript/packages/http/axios '@x402/evm': specifier: workspace:* version: link:../../../../typescript/packages/mechanisms/evm - '@x402/svm': + '@x402/fetch': specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/svm - axios: - specifier: ^1.13.2 - version: 1.13.2 + version: link:../../../../typescript/packages/http/fetch dotenv: specifier: ^16.4.7 version: 16.6.1 viem: - specifier: ^2.39.0 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 clients/custom: dependencies: @@ -1514,7 +1244,7 @@ importers: version: 1.2.6 '@solana/kit': specifier: ^6.1.0 - version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) + version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10) '@x402/core': specifier: workspace:* version: link:../../../../typescript/packages/core @@ -1528,39 +1258,42 @@ importers: specifier: ^16.4.7 version: 16.6.1 viem: - specifier: ^2.39.0 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 clients/fetch: dependencies: @@ -1569,7 +1302,7 @@ importers: version: 1.2.6 '@solana/kit': specifier: ^6.1.0 - version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) + version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10) '@x402/evm': specifier: workspace:* version: link:../../../../typescript/packages/mechanisms/evm @@ -1583,42 +1316,42 @@ importers: specifier: ^16.4.7 version: 16.6.1 viem: - specifier: ^2.39.0 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 '@types/node': - specifier: ^20.0.0 - version: 20.19.11 + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 clients/mcp: dependencies: @@ -1639,50 +1372,50 @@ importers: version: 16.6.1 openai: specifier: ^4.77.3 - version: 4.104.0(encoding@0.1.13)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + version: 4.104.0(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) viem: - specifier: ^2.39.0 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 clients/mcp-chatbot: dependencies: '@modelcontextprotocol/sdk': specifier: ^1.12.1 version: 1.17.3 - '@x402/core': - specifier: workspace:* - version: link:../../../../typescript/packages/core '@x402/evm': specifier: workspace:* version: link:../../../../typescript/packages/mechanisms/evm @@ -1694,41 +1427,44 @@ importers: version: 16.6.1 openai: specifier: ^4.77.3 - version: 4.104.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + version: 4.104.0(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) viem: - specifier: ^2.39.0 - version: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.20.4 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.9.2 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 clients/offer-receipt: dependencies: @@ -1737,7 +1473,7 @@ importers: version: 1.2.6 '@solana/kit': specifier: ^2.1.1 - version: 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@x402/evm': specifier: workspace:* version: link:../../../../typescript/packages/mechanisms/evm @@ -1754,42 +1490,42 @@ importers: specifier: ^16.4.7 version: 16.6.1 viem: - specifier: ^2.39.0 - version: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 '@types/node': - specifier: ^20.0.0 - version: 20.19.11 + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 clients/payment-identifier: dependencies: @@ -1806,45 +1542,51 @@ importers: specifier: ^16.4.7 version: 16.6.1 viem: - specifier: ^2.39.0 - version: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 - '@typescript-eslint/eslint-plugin': + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 + '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 clients/sign-in-with-x: dependencies: + '@scure/base': + specifier: ^1.2.6 + version: 1.2.6 '@solana/kit': specifier: ^5.1.0 - version: 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@x402/core': specifier: workspace:* version: link:../../../../typescript/packages/core @@ -1864,45 +1606,42 @@ importers: specifier: ^16.4.7 version: 16.6.1 viem: - specifier: ^2.39.0 - version: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 - '@scure/base': - specifier: ^1.2.6 - version: 1.2.6 '@types/node': - specifier: ^22.10.5 + specifier: ^22.13.4 version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 facilitator/advanced: dependencies: @@ -1911,7 +1650,10 @@ importers: version: 1.2.6 '@solana/kit': specifier: ^6.1.0 - version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) + version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@x402/avm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/avm '@x402/core': specifier: workspace:* version: link:../../../../typescript/packages/core @@ -1921,6 +1663,9 @@ importers: '@x402/extensions': specifier: workspace:* version: link:../../../../typescript/packages/extensions + '@x402/hedera': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/hedera '@x402/stellar': specifier: workspace:* version: link:../../../../typescript/packages/mechanisms/stellar @@ -1934,8 +1679,8 @@ importers: specifier: ^4.19.2 version: 4.21.2 viem: - specifier: ^2.21.54 - version: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -1944,35 +1689,35 @@ importers: specifier: ^4.17.21 version: 4.17.25 '@types/node': - specifier: ^22.10.1 + specifier: ^22.13.4 version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: - specifier: ^9.15.0 + specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.6.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: - specifier: ^3.3.3 - version: 3.6.2 + specifier: 3.5.2 + version: 3.5.2 tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.7.2 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 facilitator/basic: dependencies: @@ -1981,16 +1726,13 @@ importers: version: 1.2.6 '@solana/kit': specifier: ^6.1.0 - version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) + version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10) '@x402/core': specifier: workspace:* version: link:../../../../typescript/packages/core '@x402/evm': specifier: workspace:* version: link:../../../../typescript/packages/mechanisms/evm - '@x402/extensions': - specifier: workspace:* - version: link:../../../../typescript/packages/extensions '@x402/svm': specifier: workspace:* version: link:../../../../typescript/packages/mechanisms/svm @@ -2001,8 +1743,8 @@ importers: specifier: ^4.19.2 version: 4.21.2 viem: - specifier: ^2.21.54 - version: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -2011,47 +1753,99 @@ importers: specifier: ^4.17.21 version: 4.17.25 '@types/node': - specifier: ^22.10.1 + specifier: ^22.13.4 version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: - specifier: ^9.15.0 + specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.6.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: - specifier: ^3.3.3 - version: 3.6.2 + specifier: 3.5.2 + version: 3.5.2 tsx: + specifier: ^4.21.0 + version: 4.21.0 + typescript: + specifier: ^5.7.3 + version: 5.9.3 + + facilitator/batch-settlement: + dependencies: + '@x402/core': + specifier: workspace:* + version: link:../../../../typescript/packages/core + '@x402/evm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/evm + dotenv: + specifier: ^16.4.5 + version: 16.6.1 + express: specifier: ^4.19.2 - version: 4.20.4 + version: 4.21.2 + viem: + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + devDependencies: + '@eslint/js': + specifier: ^9.24.0 + version: 9.33.0 + '@types/express': + specifier: ^4.17.21 + version: 4.17.25 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 + '@typescript-eslint/eslint-plugin': + specifier: ^8.29.1 + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': + specifier: ^8.29.1 + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) + eslint: + specifier: ^9.24.0 + version: 9.33.0(jiti@2.6.1) + eslint-plugin-import: + specifier: ^2.31.0 + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + eslint-plugin-jsdoc: + specifier: ^50.6.9 + version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) + eslint-plugin-prettier: + specifier: ^5.2.6 + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + prettier: + specifier: 3.5.2 + version: 3.5.2 + tsx: + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.7.2 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 fullstack/miniapp: dependencies: '@coinbase/onchainkit': specifier: 1.1.2 - version: 1.1.2(@tanstack/query-core@5.90.11)(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13))(zod@4.1.13) + version: 1.1.2(@tanstack/query-core@5.90.11)(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(bufferutil@4.0.9)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13))(zod@4.1.13) '@farcaster/miniapp-sdk': specifier: 0.2.1 - version: 0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@tanstack/react-query': - specifier: ^5 - version: 5.90.11(react@19.2.3) + version: 0.2.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) '@x402/core': specifier: workspace:* version: link:../../../../typescript/packages/core @@ -2074,11 +1868,11 @@ importers: specifier: ^19.2.3 version: 19.2.3(react@19.2.3) viem: - specifier: ^2.27.2 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) wagmi: specifier: ^2.14.11 - version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) + version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -2097,25 +1891,25 @@ importers: version: 19.2.1(@types/react@19.2.1) '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-config-next: specifier: 16.0.6 - version: 16.0.6(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 16.0.6(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 @@ -2123,14 +1917,11 @@ importers: specifier: ^4.0.0 version: 4.1.17 typescript: - specifier: ^5 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 fullstack/next: dependencies: - '@heroicons/react': - specifier: ^2.2.0 - version: 2.2.0(react@19.2.3) '@x402/core': specifier: workspace:* version: link:../../../../typescript/packages/core @@ -2176,25 +1967,25 @@ importers: version: 19.1.7(@types/react@19.1.10) '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-config-next: specifier: 16.0.6 - version: 16.0.6(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 16.0.6(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 @@ -2202,41 +1993,38 @@ importers: specifier: ^4.0.0 version: 4.1.17 typescript: - specifier: ^5 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - legacy/agent: - dependencies: - '@anthropic-ai/sdk': - specifier: ^0.39.0 - version: 0.39.0(encoding@0.1.13) - '@coinbase/agentkit': - specifier: ^0.5.0 - version: 0.5.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@coinbase/agentkit-langchain': - specifier: ^0.3.0 - version: 0.3.0(@coinbase/agentkit@0.5.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10))(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - '@langchain/core': - specifier: ^0.3.43 - version: 0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - '@langchain/langgraph': - specifier: ^0.2.62 - version: 0.2.74(@langchain/core@0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod-to-json-schema@3.24.6(zod@3.25.76)) - '@langchain/openai': - specifier: ^0.5.2 - version: 0.5.18(@langchain/core@0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - dotenv: - specifier: ^16.4.7 - version: 16.6.1 - viem: - specifier: ^2.26.2 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - x402-fetch: + fullstack/next-batch-settlement-redis: + dependencies: + '@x402/core': specifier: workspace:* - version: link:../../../../typescript/packages/legacy/x402-fetch - zod: - specifier: ^3.24.2 - version: 3.25.76 + version: link:../../../../typescript/packages/core + '@x402/evm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/evm + '@x402/extensions': + specifier: workspace:* + version: link:../../../../typescript/packages/extensions + '@x402/next': + specifier: workspace:* + version: link:../../../../typescript/packages/http/next + next: + specifier: ^16.0.10 + version: 16.0.10(@babel/core@7.28.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: + specifier: ^19.2.3 + version: 19.2.3 + react-dom: + specifier: ^19.2.3 + version: 19.2.3(react@19.2.3) + redis: + specifier: ^5.12.1 + version: 5.12.1 + viem: + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -2244,796 +2032,609 @@ importers: '@types/node': specifier: ^22.13.4 version: 22.17.2 + '@types/react': + specifier: ^19 + version: 19.2.1 + '@types/react-dom': + specifier: ^19 + version: 19.2.1(@types/react@19.2.1) '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) + eslint-config-next: + specifier: 16.0.6 + version: 16.0.6(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.19.2 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 - version: 5.9.2 + version: 5.9.3 - legacy/clients/axios: + servers/advanced: dependencies: - axios: - specifier: ^1.7.9 - version: 1.13.2 + '@x402/avm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/avm + '@x402/core': + specifier: workspace:* + version: link:../../../../typescript/packages/core + '@x402/evm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/evm + '@x402/express': + specifier: workspace:* + version: link:../../../../typescript/packages/http/express + '@x402/extensions': + specifier: workspace:* + version: link:../../../../typescript/packages/extensions + '@x402/hedera': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/hedera + '@x402/stellar': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/stellar + '@x402/svm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/svm dotenv: - specifier: ^16.5.0 + specifier: ^16.4.7 version: 16.6.1 - x402-axios: - specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-axios + express: + specifier: ^4.18.2 + version: 4.21.2 devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 + '@types/express': + specifier: ^5.0.1 + version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 + tsup: + specifier: ^8.4.0 + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - legacy/clients/cdp-sdk: + servers/batch-settlement: dependencies: - '@coinbase/cdp-sdk': - specifier: ^1.16.0 - version: 1.36.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - axios: - specifier: ^1.7.9 - version: 1.13.2 + '@x402/core': + specifier: workspace:* + version: link:../../../../typescript/packages/core + '@x402/evm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/evm + '@x402/express': + specifier: workspace:* + version: link:../../../../typescript/packages/http/express dotenv: - specifier: ^16.5.0 + specifier: ^16.4.7 version: 16.6.1 + express: + specifier: ^4.18.2 + version: 4.21.2 viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - x402-axios: - specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-axios + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 + '@types/express': + specifier: ^5.0.1 + version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 + tsup: + specifier: ^8.4.0 + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - legacy/clients/chainlink-vrf-nft: + servers/bazaar: dependencies: - '@hono/node-server': - specifier: ^1.13.8 - version: 1.19.0(hono@4.10.7) - axios: - specifier: ^1.7.9 - version: 1.13.2 - dotenv: - specifier: ^16.4.5 - version: 16.6.1 - hono: - specifier: ^4.7.2 - version: 4.10.7 - viem: - specifier: ^2.23.5 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - x402: + '@x402/core': + specifier: workspace:* + version: link:../../../../typescript/packages/core + '@x402/evm': specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402 - x402-axios: + version: link:../../../../typescript/packages/mechanisms/evm + '@x402/express': specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-axios - devDependencies: - '@types/node': - specifier: ^22.13.5 - version: 22.17.2 - tsx: - specifier: ^4.19.3 - version: 4.20.4 - - legacy/clients/fetch: - dependencies: + version: link:../../../../typescript/packages/http/express + '@x402/extensions': + specifier: workspace:* + version: link:../../../../typescript/packages/extensions + '@x402/svm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/svm dotenv: specifier: ^16.4.7 version: 16.6.1 - x402-fetch: - specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-fetch + express: + specifier: ^4.18.2 + version: 4.21.2 devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 + '@types/express': + specifier: ^5.0.1 + version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 + tsup: + specifier: ^8.4.0 + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 + + servers/cloudfront-lambda-edge: {} - legacy/dynamic_agent: + servers/cloudfront-lambda-edge/cdk: dependencies: - '@anthropic-ai/sdk': - specifier: ^0.39.0 - version: 0.39.0(encoding@0.1.13) - '@hono/node-server': - specifier: ^1.14.1 - version: 1.19.0(hono@4.10.7) - '@llamaindex/anthropic': - specifier: ^0.3.3 - version: 0.3.23(@llamaindex/core@0.6.5)(@llamaindex/env@0.1.30) + aws-cdk-lib: + specifier: ^2.252.0 + version: 2.252.0(constructs@10.6.0) + constructs: + specifier: ^10.6.0 + version: 10.6.0 + devDependencies: '@types/node': - specifier: ^22.15.3 + specifier: ^22.13.4 version: 22.17.2 - axios: - specifier: ^1.8.4 - version: 1.13.2 - hono: - specifier: ^4.7.7 - version: 4.10.7 - llamaindex: - specifier: ^0.10.2 - version: 0.10.6(encoding@0.1.13)(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - viem: - specifier: ^2.28.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - x402: - specifier: workspace:* - version: link:../../../../typescript/packages/legacy/x402 - x402-axios: + aws-cdk: + specifier: ^2.1120.0 + version: 2.1120.0 + ts-node: + specifier: ^10.9.0 + version: 10.9.2(@types/node@22.17.2)(typescript@5.9.3) + typescript: + specifier: ^5.7.3 + version: 5.9.3 + + servers/cloudfront-lambda-edge/lambda: + dependencies: + '@x402/core': + specifier: ^2.11.0 + version: 2.11.0 + '@x402/evm': + specifier: ^2.11.0 + version: 2.11.0(typescript@5.9.3) + devDependencies: + '@types/aws-lambda': + specifier: ^8.10.159 + version: 8.10.161 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 + esbuild: + specifier: ^0.27.2 + version: 0.27.7 + typescript: + specifier: ^5.7.3 + version: 5.9.3 + + servers/custom: + dependencies: + '@x402/core': specifier: workspace:* - version: link:../../../../typescript/packages/legacy/x402-axios - x402-hono: + version: link:../../../../typescript/packages/core + '@x402/evm': specifier: workspace:* - version: link:../../../../typescript/packages/legacy/x402-hono - zod: - specifier: ^3.24.3 - version: 3.25.76 + version: link:../../../../typescript/packages/mechanisms/evm + dotenv: + specifier: ^16.4.7 + version: 16.6.1 + express: + specifier: ^4.18.2 + version: 4.21.2 devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 + '@types/express': + specifier: ^5.0.1 + version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 - tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.9.2) tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - legacy/facilitator: + servers/express: dependencies: + '@x402/core': + specifier: workspace:* + version: link:../../../../typescript/packages/core + '@x402/evm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/evm + '@x402/express': + specifier: workspace:* + version: link:../../../../typescript/packages/http/express + '@x402/svm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/svm dotenv: specifier: ^16.4.7 version: 16.6.1 express: specifier: ^4.18.2 version: 4.21.2 - x402: - specifier: workspace:* - version: link:../../../../typescript/packages/legacy/x402 devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 + '@types/express': + specifier: ^5.0.1 + version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 + tsup: + specifier: ^8.4.0 + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - legacy/fullstack/auth_based_pricing: + servers/fastify: dependencies: - '@hono/node-server': - specifier: ^1.11.2 - version: 1.19.0(hono@4.10.7) - dotenv: - specifier: ^16.4.5 - version: 16.6.1 - hono: - specifier: ^4.4.0 - version: 4.10.7 - node-fetch: - specifier: ^3.3.2 - version: 3.3.2 - siwe: - specifier: ^2.3.2 - version: 2.3.2(ethers@6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - viem: - specifier: ^2.13.8 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - x402: + '@x402/core': + specifier: workspace:* + version: link:../../../../typescript/packages/core + '@x402/evm': specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402 - x402-fetch: + version: link:../../../../typescript/packages/mechanisms/evm + '@x402/fastify': specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-fetch - x402-hono: + version: link:../../../../typescript/packages/http/fastify + '@x402/svm': specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-hono + version: link:../../../../typescript/packages/mechanisms/svm + dotenv: + specifier: ^16.4.7 + version: 16.6.1 + fastify: + specifier: ^5.0.0 + version: 5.8.2 devDependencies: + '@eslint/js': + specifier: ^9.24.0 + version: 9.33.0 '@types/node': - specifier: ^20.14.2 - version: 20.19.11 - '@types/node-fetch': - specifier: ^2.6.11 - version: 2.6.13 + specifier: ^22.13.4 + version: 22.17.2 + '@typescript-eslint/eslint-plugin': + specifier: ^8.29.1 + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': + specifier: ^8.29.1 + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) + eslint: + specifier: ^9.24.0 + version: 9.33.0(jiti@2.6.1) + eslint-plugin-import: + specifier: ^2.31.0 + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + eslint-plugin-jsdoc: + specifier: ^50.6.9 + version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) + eslint-plugin-prettier: + specifier: ^5.2.6 + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + prettier: + specifier: 3.5.2 + version: 3.5.2 + tsup: + specifier: ^8.4.0 + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) tsx: - specifier: ^4.11.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.4.5 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - legacy/fullstack/browser-wallet-example: + servers/hono: dependencies: '@hono/node-server': specifier: ^1.14.0 version: 1.19.0(hono@4.10.7) - axios: - specifier: ^1.10.0 - version: 1.13.2 + '@x402/core': + specifier: workspace:* + version: link:../../../../typescript/packages/core + '@x402/evm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/evm + '@x402/hono': + specifier: workspace:* + version: link:../../../../typescript/packages/http/hono + '@x402/svm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/svm dotenv: - specifier: ^16.6.1 + specifier: ^16.4.7 version: 16.6.1 hono: - specifier: ^4.6.17 + specifier: ^4.7.1 version: 4.10.7 - react: - specifier: ^18.3.1 - version: 18.3.1 - react-dom: - specifier: ^18.3.1 - version: 18.3.1(react@18.3.1) - uuid: - specifier: ^11.0.6 - version: 11.1.0 - viem: - specifier: ^2.31.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - x402-axios: - specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-axios - x402-hono: - specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-hono devDependencies: + '@eslint/js': + specifier: ^9.24.0 + version: 9.33.0 + '@types/express': + specifier: ^5.0.1 + version: 5.0.3 '@types/node': - specifier: ^22.15.3 + specifier: ^22.13.4 version: 22.17.2 - '@types/react': - specifier: ^18.3.17 - version: 18.3.27 - '@types/react-dom': - specifier: ^18.3.5 - version: 18.3.7(@types/react@18.3.27) - '@types/uuid': - specifier: ^10.0.0 - version: 10.0.0 - '@vitejs/plugin-react': - specifier: ^4.4.1 - version: 4.7.0(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) - concurrently: - specifier: ^8.2.2 - version: 8.2.2 - tsx: - specifier: ^4.19.2 - version: 4.20.4 - typescript: - specifier: ^5.8.3 - version: 5.9.2 - vite: - specifier: ^6.3.5 - version: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - - legacy/fullstack/farcaster-miniapp: - dependencies: - '@coinbase/onchainkit': - specifier: ^0.38.14 - version: 0.38.19(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - '@farcaster/frame-sdk': - specifier: ^0.0.60 - version: 0.0.60(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@tanstack/react-query': - specifier: ^5 - version: 5.90.11(react@19.2.3) - '@upstash/redis': - specifier: ^1.34.4 - version: 1.35.3 - '@wagmi/core': - specifier: ^2.17.1 - version: 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - next: - specifier: 15.5.9 - version: 15.5.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: - specifier: 19.2.3 - version: 19.2.3 - react-dom: - specifier: 19.2.3 - version: 19.2.3(react@19.2.3) - react-hot-toast: - specifier: ^2.5.2 - version: 2.6.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - viem: - specifier: ^2.27.2 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - wagmi: - specifier: ^2.14.11 - version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - x402-fetch: - specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-fetch - x402-next: - specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-next - devDependencies: - '@types/node': - specifier: ^20.17.30 - version: 20.19.11 - '@types/react': - specifier: ^19 - version: 19.1.10 - '@types/react-dom': - specifier: ^19 - version: 19.1.7(@types/react@19.1.10) + '@typescript-eslint/eslint-plugin': + specifier: ^8.29.1 + version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': + specifier: ^8.29.1 + version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: - specifier: ^8 - version: 8.57.1 - eslint-config-next: - specifier: 15.5.7 - version: 15.5.7(eslint@8.57.1)(typescript@5.9.2) - eslint-config-prettier: - specifier: ^10.1.1 - version: 10.1.8(eslint@8.57.1) + specifier: ^9.24.0 + version: 9.33.0(jiti@2.6.1) + eslint-plugin-import: + specifier: ^2.31.0 + version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + eslint-plugin-jsdoc: + specifier: ^50.6.9 + version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: - specifier: ^5.2.3 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2) - eslint-plugin-react: - specifier: ^7.37.4 - version: 7.37.5(eslint@8.57.1) - eslint-plugin-react-hooks: - specifier: ^5.2.0 - version: 5.2.0(eslint@8.57.1) - postcss: - specifier: ^8 - version: 8.5.6 + specifier: ^5.2.6 + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: - specifier: ^3.5.3 - version: 3.6.2 - tailwindcss: - specifier: ^3.4.1 - version: 3.4.17 + specifier: 3.5.2 + version: 3.5.2 + tsup: + specifier: ^8.4.0 + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) + tsx: + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - legacy/fullstack/next: + servers/mcp: dependencies: - '@heroicons/react': - specifier: ^2.2.0 - version: 2.2.0(react@19.2.3) - next: - specifier: 16.0.10 - version: 16.0.10(@babel/core@7.28.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: - specifier: 19.2.3 - version: 19.2.3 - react-dom: - specifier: 19.2.3 - version: 19.2.3(react@19.2.3) - viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - x402-next: + '@modelcontextprotocol/sdk': + specifier: ^1.12.1 + version: 1.17.3 + '@x402/core': + specifier: workspace:* + version: link:../../../../typescript/packages/core + '@x402/evm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/evm + '@x402/mcp': specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-next + version: link:../../../../typescript/packages/mcp + dotenv: + specifier: ^16.4.7 + version: 16.6.1 + express: + specifier: ^4.18.2 + version: 4.21.2 + zod: + specifier: ^3.24.3 + version: 3.25.76 devDependencies: '@eslint/js': specifier: ^9.24.0 version: 9.33.0 - '@svgr/webpack': - specifier: ^8.1.0 - version: 8.1.0(typescript@5.9.2) + '@types/express': + specifier: ^5.0.3 + version: 5.0.3 '@types/node': - specifier: ^20 - version: 20.19.11 - '@types/react': - specifier: ^19 - version: 19.1.10 - '@types/react-dom': - specifier: ^19 - version: 19.1.7(@types/react@19.1.10) + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) - eslint-config-next: - specifier: 16.0.7 - version: 16.0.7(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - postcss: - specifier: ^8 - version: 8.5.6 + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 - tailwindcss: - specifier: ^3.4.1 - version: 3.4.17 + tsx: + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - legacy/fullstack/next-advanced: + servers/offer-receipt: dependencies: - '@coinbase/onchainkit': - specifier: 0.38.14 - version: 0.38.14(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - '@tanstack/react-query': - specifier: ^5 - version: 5.90.11(react@19.2.3) - next: - specifier: 15.5.9 - version: 15.5.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: - specifier: 19.2.3 - version: 19.2.3 - react-dom: - specifier: 19.2.3 - version: 19.2.3(react@19.2.3) - viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - wagmi: - specifier: ^2.15.6 - version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - x402: + '@x402/core': specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402 - devDependencies: - '@types/node': - specifier: ^20 - version: 20.19.11 - '@types/react': - specifier: ^19 - version: 19.1.10 - '@types/react-dom': - specifier: ^19 - version: 19.1.7(@types/react@19.1.10) - eslint: - specifier: ^8 - version: 8.57.1 - eslint-config-next: - specifier: 15.5.7 - version: 15.5.7(eslint@8.57.1)(typescript@5.9.2) - postcss: - specifier: ^8 - version: 8.5.6 - tailwindcss: - specifier: ^3.4.1 - version: 3.4.17 - typescript: - specifier: ^5 - version: 5.9.2 - - legacy/mcp-embedded-wallet: - dependencies: - '@coinbase/cdp-core': - specifier: ^0.0.18 - version: 0.0.18(@types/react@19.2.1)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@coinbase/cdp-hooks': - specifier: ^0.0.18 - version: 0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.2.1)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(react@18.3.1) - '@coinbase/cdp-react': - specifier: ^0.0.18 - version: 0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.2.1)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(@coinbase/cdp-hooks@0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.2.1)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(react@18.3.1))(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@modelcontextprotocol/sdk': - specifier: ^1.15.1 - version: 1.17.3 - '@radix-ui/react-form': - specifier: ^0.1.7 - version: 0.1.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-icons': - specifier: ^1.3.2 - version: 1.3.2(react@18.3.1) - '@radix-ui/themes': - specifier: ^3.2.1 - version: 3.2.1(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - axios: - specifier: ^1.10.0 - version: 1.13.2 - electron-builder: - specifier: ^26.0.12 - version: 26.0.12(electron-builder-squirrel-windows@26.0.12) - react: - specifier: ^18.2.0 - version: 18.3.1 - react-dom: - specifier: ^18.2.0 - version: 18.3.1(react@18.3.1) - react-qr-code: - specifier: ^2.0.15 - version: 2.0.18(react@18.3.1) - turbo: - specifier: ^2.5.5 - version: 2.5.6 - viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - winston: - specifier: ^3.17.0 - version: 3.17.0 - x402: + version: link:../../../../typescript/packages/core + '@x402/evm': specifier: workspace:* - version: link:../../../../typescript/packages/legacy/x402 - x402-axios: + version: link:../../../../typescript/packages/mechanisms/evm + '@x402/express': specifier: workspace:* - version: link:../../../../typescript/packages/legacy/x402-axios - zod: - specifier: ^3.23.8 - version: 3.25.76 - zustand: - specifier: ^5.0.6 - version: 5.0.8(@types/react@19.2.1)(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)) - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@types/node': - specifier: ^24.0.13 - version: 24.3.0 - '@types/react': - specifier: 19.2.1 - version: 19.2.1 - '@types/react-dom': - specifier: 19.2.1 - version: 19.2.1(@types/react@19.2.1) - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@vitejs/plugin-react': - specifier: ^4.7.0 - version: 4.7.0(vite@7.1.3(@types/node@24.3.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) - concurrently: - specifier: ^9.2.0 - version: 9.2.0 - electron: - specifier: ^37.2.1 - version: 37.3.1 - electron-is-dev: - specifier: ^3.0.1 - version: 3.0.1 - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsx: - specifier: ^4.20.3 - version: 4.20.4 - typescript: - specifier: ^5.8.3 - version: 5.9.2 - vite: - specifier: ^7.0.5 - version: 7.1.3(@types/node@24.3.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - - legacy/servers/advanced: - dependencies: - dotenv: - specifier: ^16.4.7 - version: 16.6.1 - express: - specifier: ^4.18.2 - version: 4.21.2 - x402: + version: link:../../../../typescript/packages/http/express + '@x402/extensions': specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402 - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@types/express': - specifier: ^5.0.1 - version: 5.0.3 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.9.2) - tsx: - specifier: ^4.7.0 - version: 4.20.4 - typescript: - specifier: ^5.3.0 - version: 5.9.2 - - legacy/servers/express: - dependencies: + version: link:../../../../typescript/packages/extensions + '@x402/svm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/svm dotenv: specifier: ^16.4.7 version: 16.6.1 express: specifier: ^4.18.2 version: 4.21.2 - x402-express: - specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-express + viem: + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -3041,87 +2642,38 @@ importers: '@types/express': specifier: ^5.0.1 version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.9.2) - tsx: - specifier: ^4.7.0 - version: 4.20.4 - typescript: - specifier: ^5.3.0 - version: 5.9.2 - - legacy/servers/hono: - dependencies: - '@hono/node-server': - specifier: ^1.13.8 - version: 1.19.0(hono@4.10.7) - dotenv: - specifier: ^16.4.7 - version: 16.6.1 - hono: - specifier: ^4.7.1 - version: 4.10.7 - x402-hono: - specifier: workspace:* - version: link:../../../../../typescript/packages/legacy/x402-hono - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 - tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.9.2) tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - servers/advanced: + servers/payment-identifier: dependencies: '@x402/core': specifier: workspace:* @@ -3135,12 +2687,6 @@ importers: '@x402/extensions': specifier: workspace:* version: link:../../../../typescript/packages/extensions - '@x402/stellar': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/stellar - '@x402/svm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/svm dotenv: specifier: ^16.4.7 version: 16.6.1 @@ -3154,38 +2700,41 @@ importers: '@types/express': specifier: ^5.0.1 version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.9.2) + specifier: ^8.4.0 + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - servers/bazaar: + servers/self-facilitation: dependencies: '@x402/core': specifier: workspace:* @@ -3196,18 +2745,15 @@ importers: '@x402/express': specifier: workspace:* version: link:../../../../typescript/packages/http/express - '@x402/extensions': - specifier: workspace:* - version: link:../../../../typescript/packages/extensions - '@x402/svm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/svm dotenv: specifier: ^16.4.7 version: 16.6.1 express: specifier: ^4.18.2 version: 4.21.2 + viem: + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -3215,40 +2761,41 @@ importers: '@types/express': specifier: ^5.0.1 version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.9.2) + specifier: ^8.4.0 + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 - - servers/cloudfront-lambda-edge: {} + specifier: ^5.7.3 + version: 5.9.3 - servers/custom: + servers/sign-in-with-x: dependencies: '@x402/core': specifier: workspace:* @@ -3256,6 +2803,15 @@ importers: '@x402/evm': specifier: workspace:* version: link:../../../../typescript/packages/mechanisms/evm + '@x402/express': + specifier: workspace:* + version: link:../../../../typescript/packages/http/express + '@x402/extensions': + specifier: workspace:* + version: link:../../../../typescript/packages/extensions + '@x402/svm': + specifier: workspace:* + version: link:../../../../typescript/packages/mechanisms/svm dotenv: specifier: ^16.4.7 version: 16.6.1 @@ -3267,37 +2823,40 @@ importers: specifier: ^9.24.0 version: 9.33.0 '@types/express': - specifier: ^5.0.1 + specifier: 5.0.3 version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - servers/express: + servers/upto: dependencies: '@x402/core': specifier: workspace:* @@ -3311,9 +2870,6 @@ importers: '@x402/extensions': specifier: workspace:* version: link:../../../../typescript/packages/extensions - '@x402/svm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/svm dotenv: specifier: ^16.4.7 version: 16.6.1 @@ -3327,11454 +2883,8189 @@ importers: '@types/express': specifier: ^5.0.1 version: 5.0.3 + '@types/node': + specifier: ^22.13.4 + version: 22.17.2 '@typescript-eslint/eslint-plugin': specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/parser': specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: specifier: ^9.24.0 version: 9.33.0(jiti@2.6.1) eslint-plugin-import: specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsdoc: specifier: ^50.6.9 version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-prettier: specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) + version: 5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) prettier: specifier: 3.5.2 version: 3.5.2 tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.9.2) + specifier: ^8.4.0 + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1) tsx: - specifier: ^4.7.0 - version: 4.20.4 + specifier: ^4.21.0 + version: 4.21.0 typescript: - specifier: ^5.3.0 - version: 5.9.2 + specifier: ^5.7.3 + version: 5.9.3 - servers/fastify: - dependencies: - '@x402/core': - specifier: workspace:* - version: link:../../../../typescript/packages/core - '@x402/evm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/evm - '@x402/extensions': - specifier: workspace:* - version: link:../../../../typescript/packages/extensions - '@x402/fastify': - specifier: workspace:* - version: link:../../../../typescript/packages/http/fastify - '@x402/svm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/svm - dotenv: - specifier: ^16.4.7 - version: 16.6.1 - fastify: - specifier: ^5.0.0 - version: 5.8.2 - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.9.2) - tsx: - specifier: ^4.7.0 - version: 4.20.4 - typescript: - specifier: ^5.3.0 - version: 5.9.2 - - servers/hono: - dependencies: - '@hono/node-server': - specifier: ^1.14.0 - version: 1.19.0(hono@4.10.7) - '@x402/core': - specifier: workspace:* - version: link:../../../../typescript/packages/core - '@x402/evm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/evm - '@x402/extensions': - specifier: workspace:* - version: link:../../../../typescript/packages/extensions - '@x402/hono': - specifier: workspace:* - version: link:../../../../typescript/packages/http/hono - '@x402/svm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/svm - dotenv: - specifier: ^16.4.7 - version: 16.6.1 - hono: - specifier: ^4.7.1 - version: 4.10.7 - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@types/express': - specifier: ^5.0.1 - version: 5.0.3 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.9.2) - tsx: - specifier: ^4.7.0 - version: 4.20.4 - typescript: - specifier: ^5.3.0 - version: 5.9.2 - - servers/mcp: - dependencies: - '@modelcontextprotocol/sdk': - specifier: ^1.12.1 - version: 1.17.3 - '@x402/core': - specifier: workspace:* - version: link:../../../../typescript/packages/core - '@x402/evm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/evm - '@x402/mcp': - specifier: workspace:* - version: link:../../../../typescript/packages/mcp - dotenv: - specifier: ^16.4.7 - version: 16.6.1 - express: - specifier: ^4.18.2 - version: 4.21.2 - zod: - specifier: ^3.24.3 - version: 3.25.76 - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@types/express': - specifier: ^5.0.3 - version: 5.0.3 - '@types/node': - specifier: ^22.13.4 - version: 22.17.2 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsx: - specifier: ^4.20.4 - version: 4.20.4 - typescript: - specifier: ^5.9.2 - version: 5.9.2 - - servers/offer-receipt: - dependencies: - '@x402/core': - specifier: workspace:* - version: link:../../../../typescript/packages/core - '@x402/evm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/evm - '@x402/express': - specifier: workspace:* - version: link:../../../../typescript/packages/http/express - '@x402/extensions': - specifier: workspace:* - version: link:../../../../typescript/packages/extensions - '@x402/svm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/svm - dotenv: - specifier: ^16.4.7 - version: 16.6.1 - express: - specifier: ^4.18.2 - version: 4.21.2 - viem: - specifier: ^2.21.54 - version: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@types/express': - specifier: ^5.0.1 - version: 5.0.3 - '@types/node': - specifier: ^22.0.0 - version: 22.17.2 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsx: - specifier: ^4.7.0 - version: 4.20.4 - typescript: - specifier: ^5.3.0 - version: 5.9.2 - - servers/payment-identifier: - dependencies: - '@x402/core': - specifier: workspace:* - version: link:../../../../typescript/packages/core - '@x402/evm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/evm - '@x402/express': - specifier: workspace:* - version: link:../../../../typescript/packages/http/express - '@x402/extensions': - specifier: workspace:* - version: link:../../../../typescript/packages/extensions - dotenv: - specifier: ^16.4.7 - version: 16.6.1 - express: - specifier: ^4.18.2 - version: 4.21.2 - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@types/express': - specifier: ^5.0.1 - version: 5.0.3 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.9.2) - tsx: - specifier: ^4.7.0 - version: 4.20.4 - typescript: - specifier: ^5.3.0 - version: 5.9.2 - - servers/sign-in-with-x: - dependencies: - '@x402/core': - specifier: workspace:* - version: link:../../../../typescript/packages/core - '@x402/evm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/evm - '@x402/express': - specifier: workspace:* - version: link:../../../../typescript/packages/http/express - '@x402/extensions': - specifier: workspace:* - version: link:../../../../typescript/packages/extensions - '@x402/svm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/svm - dotenv: - specifier: ^16.4.7 - version: 16.6.1 - express: - specifier: ^4.18.2 - version: 4.21.2 - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@types/express': - specifier: 5.0.3 - version: 5.0.3 - '@types/node': - specifier: ^22.10.5 - version: 22.17.2 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsx: - specifier: ^4.7.0 - version: 4.20.4 - typescript: - specifier: ^5.3.0 - version: 5.9.2 - - servers/upto: - dependencies: - '@x402/core': - specifier: workspace:* - version: link:../../../../typescript/packages/core - '@x402/evm': - specifier: workspace:* - version: link:../../../../typescript/packages/mechanisms/evm - '@x402/express': - specifier: workspace:* - version: link:../../../../typescript/packages/http/express - '@x402/extensions': - specifier: workspace:* - version: link:../../../../typescript/packages/extensions - dotenv: - specifier: ^16.4.7 - version: 16.6.1 - express: - specifier: ^4.18.2 - version: 4.21.2 - devDependencies: - '@eslint/js': - specifier: ^9.24.0 - version: 9.33.0 - '@types/express': - specifier: ^5.0.1 - version: 5.0.3 - '@typescript-eslint/eslint-plugin': - specifier: ^8.29.1 - version: 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': - specifier: ^8.29.1 - version: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - eslint: - specifier: ^9.24.0 - version: 9.33.0(jiti@2.6.1) - eslint-plugin-import: - specifier: ^2.31.0 - version: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsdoc: - specifier: ^50.6.9 - version: 50.8.0(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-prettier: - specifier: ^5.2.6 - version: 5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2) - prettier: - specifier: 3.5.2 - version: 3.5.2 - tsup: - specifier: ^7.2.0 - version: 7.3.0(postcss@8.5.6)(typescript@5.9.2) - tsx: - specifier: ^4.7.0 - version: 4.20.4 - typescript: - specifier: ^5.3.0 - version: 5.9.2 - -packages: - - 7zip-bin@5.2.0: - resolution: {integrity: sha512-ukTPVhqG4jNzMro2qA9HSCSSVJN3aN7tlb+hfqYCt3ER0yWroeA2VR38MNrOHLQ/cVj+DaIMad0kFCtWWowh/A==} - - '@across-protocol/app-sdk@0.2.3': - resolution: {integrity: sha512-fxKYy0fKS5jbcq66gKtRYo1TWFvzeAYYPNBubrssCu7ECKFgOTT5dolPUj4Y+UwAJtVItFMvvkxO4OvMGbK7Dw==} - engines: {node: '>=18.0.0'} - peerDependencies: - viem: ^2.20.1 - - '@adraffy/ens-normalize@1.10.1': - resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} - - '@adraffy/ens-normalize@1.11.0': - resolution: {integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==} - - '@alloc/quick-lru@5.2.0': - resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} - engines: {node: '>=10'} - - '@alloralabs/allora-sdk@0.1.1': - resolution: {integrity: sha512-43+Psr16UY+xh7MWn/lZyHTQiOkn0GlKtsfj9IynfCFW3jac8R3WoP6GaIqyErmeTIBq48rURZ7KFfSiRrmNTA==} - engines: {node: '>=18'} - - '@ampproject/remapping@2.3.0': - resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} - engines: {node: '>=6.0.0'} - - '@anthropic-ai/sdk@0.39.0': - resolution: {integrity: sha512-eMyDIPRZbt1CCLErRCi3exlAvNkBtRe+kW5vvJyef93PmNr/clstYgHhtvmkxN82nlKgzyGPCyGxrm0JQ1ZIdg==} - - '@anthropic-ai/sdk@0.58.0': - resolution: {integrity: sha512-wF8w+LB0AlKVLYUQho0nbK0uDv0K5Cgb92dbh8213t4roilnQ9Tm6zndheIaUxQdoEAeb0uoOT+GkkoIkqD8+A==} - hasBin: true - - '@aptos-labs/aptos-cli@1.1.1': - resolution: {integrity: sha512-sB7CokCM6s76SLJmccysbnFR+MDik6udKfj2+9ZsmTLV0/t73veIeCDKbvWJmbW267ibx4HiGbPI7L+1+yjEbQ==} - hasBin: true - - '@aptos-labs/aptos-client@2.1.0': - resolution: {integrity: sha512-ttdY0qclRvbYAAwzijkFeipuqTfLFJnoXlNIm58tIw3DKhIlfYdR6iLqTeCpI23oOPghnO99FZecej/0MTrtuA==} - engines: {node: '>=20.0.0'} - peerDependencies: - got: ^11.8.6 - - '@aptos-labs/ts-sdk@5.2.1': - resolution: {integrity: sha512-kazYjqfsPCBx2UJI+nYUOb6Ov7q7brSgYEfxp2sP27IeJWdDNa50lfs0WIpDJ92kQxdtlm9q3ZWw7Toh9f1gxQ==} - engines: {node: '>=20.0.0'} - - '@asamuzakjp/css-color@3.2.0': - resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} - - '@aws-crypto/sha256-js@5.2.0': - resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} - engines: {node: '>=16.0.0'} - - '@aws-crypto/util@5.2.0': - resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} - - '@aws-sdk/types@3.862.0': - resolution: {integrity: sha512-Bei+RL0cDxxV+lW2UezLbCYYNeJm6Nzee0TpW0FfyTRBhH9C1XQh4+x+IClriXvgBnRquTMMYsmJfvx8iyLKrg==} - engines: {node: '>=18.0.0'} - - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.28.0': - resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.28.3': - resolution: {integrity: sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.28.3': - resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} - engines: {node: '>=6.9.0'} - - '@babel/helper-create-class-features-plugin@7.28.3': - resolution: {integrity: sha512-V9f6ZFIYSLNEbuGA/92uOvYsGCJNsuA8ESZ4ldc09bWk/j8H8TKiPw8Mk1eG6olpnO0ALHJmYfZvF4MEE4gajg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-create-regexp-features-plugin@7.27.1': - resolution: {integrity: sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-define-polyfill-provider@0.6.5': - resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==} - peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-member-expression-to-functions@7.27.1': - resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-remap-async-to-generator@7.27.1': - resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-replace-supers@7.27.1': - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.27.1': - resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helper-wrap-function@7.28.3': - resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.28.3': - resolution: {integrity: sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.28.3': - resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1': - resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': - resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': - resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': - resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.13.0 - - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3': - resolution: {integrity: sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2': - resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-import-assertions@7.27.1': - resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-typescript@7.27.1': - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-syntax-unicode-sets-regex@7.18.6': - resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-arrow-functions@7.27.1': - resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-async-generator-functions@7.28.0': - resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-async-to-generator@7.27.1': - resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-block-scoped-functions@7.27.1': - resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-block-scoping@7.28.0': - resolution: {integrity: sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-class-properties@7.27.1': - resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-class-static-block@7.28.3': - resolution: {integrity: sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.12.0 - - '@babel/plugin-transform-classes@7.28.3': - resolution: {integrity: sha512-DoEWC5SuxuARF2KdKmGUq3ghfPMO6ZzR12Dnp5gubwbeWJo4dbNWXJPVlwvh4Zlq6Z7YVvL8VFxeSOJgjsx4Sg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-computed-properties@7.27.1': - resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-destructuring@7.28.0': - resolution: {integrity: sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-dotall-regex@7.27.1': - resolution: {integrity: sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-duplicate-keys@7.27.1': - resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-dynamic-import@7.27.1': - resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-explicit-resource-management@7.28.0': - resolution: {integrity: sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-exponentiation-operator@7.27.1': - resolution: {integrity: sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-export-namespace-from@7.27.1': - resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-for-of@7.27.1': - resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-function-name@7.27.1': - resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-json-strings@7.27.1': - resolution: {integrity: sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-literals@7.27.1': - resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-logical-assignment-operators@7.27.1': - resolution: {integrity: sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-member-expression-literals@7.27.1': - resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-amd@7.27.1': - resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-commonjs@7.27.1': - resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-systemjs@7.27.1': - resolution: {integrity: sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-modules-umd@7.27.1': - resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-new-target@7.27.1': - resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1': - resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-numeric-separator@7.27.1': - resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-object-rest-spread@7.28.0': - resolution: {integrity: sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-object-super@7.27.1': - resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-optional-catch-binding@7.27.1': - resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-optional-chaining@7.27.1': - resolution: {integrity: sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-parameters@7.27.7': - resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-private-methods@7.27.1': - resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-private-property-in-object@7.27.1': - resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-property-literals@7.27.1': - resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-constant-elements@7.27.1': - resolution: {integrity: sha512-edoidOjl/ZxvYo4lSBOQGDSyToYVkTAwyVoa2tkuYTSmjrB1+uAedoL5iROVLXkxH+vRgA7uP4tMg2pUJpZ3Ug==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-display-name@7.28.0': - resolution: {integrity: sha512-D6Eujc2zMxKjfa4Zxl4GHMsmhKKZ9VpcqIchJLvwTxad9zWIYulwYItBovpDOoNLISpcZSXoDJ5gaGbQUDqViA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-development@7.27.1': - resolution: {integrity: sha512-ykDdF5yI4f1WrAolLqeF3hmYU12j9ntLQl/AOG1HAS21jxyg1Q0/J/tpREuYLfatGdGmXp/3yS0ZA76kOlVq9Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-jsx@7.27.1': - resolution: {integrity: sha512-2KH4LWGSrJIkVf5tSiBFYuXDAoWRq2MMwgivCf+93dd0GQi8RXLjKA/0EvRnVV5G0hrHczsquXuD01L8s6dmBw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-react-pure-annotations@7.27.1': - resolution: {integrity: sha512-JfuinvDOsD9FVMTHpzA/pBLisxpv1aSf+OIV8lgH3MuWrks19R27e6a6DipIg4aX1Zm9Wpb04p8wljfKrVSnPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-regenerator@7.28.3': - resolution: {integrity: sha512-K3/M/a4+ESb5LEldjQb+XSrpY0nF+ZBFlTCbSnKaYAMfD8v33O6PMs4uYnOk19HlcsI8WMu3McdFPTiQHF/1/A==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-regexp-modifiers@7.27.1': - resolution: {integrity: sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/plugin-transform-reserved-words@7.27.1': - resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-shorthand-properties@7.27.1': - resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-spread@7.27.1': - resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-sticky-regex@7.27.1': - resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-template-literals@7.27.1': - resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typeof-symbol@7.27.1': - resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-typescript@7.28.0': - resolution: {integrity: sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-escapes@7.27.1': - resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-property-regex@7.27.1': - resolution: {integrity: sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-regex@7.27.1': - resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-unicode-sets-regex@7.27.1': - resolution: {integrity: sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/preset-env@7.28.3': - resolution: {integrity: sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/preset-modules@0.1.6-no-external-plugins': - resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} - peerDependencies: - '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - - '@babel/preset-react@7.27.1': - resolution: {integrity: sha512-oJHWh2gLhU9dW9HHr42q0cI0/iHHXTLGe39qvpAZZzagHy0MzYLCnCVV0symeRvzmjHyVU7mw2K06E6u/JwbhA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/preset-typescript@7.27.1': - resolution: {integrity: sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/runtime@7.28.3': - resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.28.3': - resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.28.2': - resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} - engines: {node: '>=6.9.0'} - - '@base-org/account@1.1.1': - resolution: {integrity: sha512-IfVJPrDPhHfqXRDb89472hXkpvJuQQR7FDI9isLPHEqSYt/45whIoBxSPgZ0ssTt379VhQo4+87PWI1DoLSfAQ==} - - '@base-org/account@2.4.0': - resolution: {integrity: sha512-A4Umpi8B9/pqR78D1Yoze4xHyQaujioVRqqO3d6xuDFw9VRtjg6tK3bPlwE0aW+nVH/ntllCpPa2PbI8Rnjcug==} - - '@cfworker/json-schema@4.1.1': - resolution: {integrity: sha512-gAmrUZSGtKc3AiBL71iNWxDsyUC5uMaKKGdvzYsBoTW/xi42JQHl7eKV2OYzCUqvc+D2RCcf7EXY2iCyFIk6og==} - - '@coinbase/agentkit-langchain@0.3.0': - resolution: {integrity: sha512-h46rEd4PvNWEHF+wuIlEoKUlO13jjmZVW9doo8uvc6QG3mNx1JSZoZ4NzqBglk6mD31TPvPBmAdCKL/xbpsHwQ==} - peerDependencies: - '@coinbase/agentkit': '>=0.1.0' - - '@coinbase/agentkit@0.5.0': - resolution: {integrity: sha512-e/c+jmg7sTP4rgGLYQ94flDDPO1pyKwatJ7Hm3W9aXJ21WP6ccyEhchFwMuVtG9VVcIp8vqUYOb5+rwa0cGsgA==} - - '@coinbase/cdp-api-client@0.0.18': - resolution: {integrity: sha512-E+AU1oLU4UTKS/mWDcLsbmGWRK9iR542TfwBI62yH73A0TVshTxMlCCw/LaLe8LrqUIo9C4lmtGJerJoJN3OVA==} - - '@coinbase/cdp-core@0.0.18': - resolution: {integrity: sha512-kcdeqckZUJTle4YaH4bV1xHxkSHltIJf1REZ+U6/5SJ+qCiRz88QI1mFTF3/FQ6DhkvsS9Z57AahNXvOElFG2g==} - - '@coinbase/cdp-hooks@0.0.18': - resolution: {integrity: sha512-SpHq5jb3S/cXmAtDkOZsC6zUHjKEGfTfYsxtL3bs5lJXRJ7CiqDjyeTuKRZuTP2dhm1VbBM/3RUEs8WAS1Spiw==} - peerDependencies: - '@coinbase/cdp-core': ^0.0.18 - react: '>=18.2.0' - - '@coinbase/cdp-react@0.0.18': - resolution: {integrity: sha512-1t8soyd0io0KISBsOFUiJD+6xrfGxnqvMjf2XFMjwaB6bsXWsYvRPd8V+cnA7dpe7xoZJ85ZJkNT0UT61V8vNA==} - peerDependencies: - '@coinbase/cdp-core': ^0.0.18 - '@coinbase/cdp-hooks': ^0.0.18 - react: '>=18.2.0' - - '@coinbase/cdp-sdk@1.36.0': - resolution: {integrity: sha512-q+8KnNEZW7mFKdCw0FsZKQ0CuxP5B0JNCkj4Ucmspjbe/EM8ZXVNh1SQMISZCu7gq9KY4bJDmpGqddwtkSGL5Q==} - - '@coinbase/cdp-sdk@1.39.0': - resolution: {integrity: sha512-3RbeIGVHBlDUxRKSLSnrvpsxo7W4IIqaOHyCscX1rPL/iprL0Nh6AaL/JogC4OkHwquu7SkKWjjNDb+a5wG8gw==} - - '@coinbase/coinbase-sdk@0.20.0': - resolution: {integrity: sha512-OoMMktKbjmeEwtwQCK3kIIoX5M+hNelxAGX5Llymvw6bmyrMDaEBZ/Myga9kaLJ+7Hi5Y4jPDy4Cy2MGxxXg6w==} - - '@coinbase/onchainkit@0.38.14': - resolution: {integrity: sha512-pTSK1SHjIKFIJFI7PWQSK0MKkzZe47w/6SZ21gUmxBKpRF1+cyaH7msm74iZgjGsZBYoxsYzQ2FwqrA06wupTw==} - peerDependencies: - react: ^18 || ^19 - react-dom: ^18 || ^19 - - '@coinbase/onchainkit@0.38.19': - resolution: {integrity: sha512-4uiujoTO5/8/dpWVZoTlBC7z0Y1N5fgBYDR6pKN/r6a8pX83ObUuOSGhSzJ8Xbu8NpPU6TXX+VuzLiwiLg/irg==} - peerDependencies: - react: ^18 || ^19 - react-dom: ^18 || ^19 - - '@coinbase/onchainkit@1.1.2': - resolution: {integrity: sha512-QBH+u7wRYDBax/SNvXGPuLIJ0tAqq85tksUDervGrLRaghEUBZstmg6Qwqw1xMMsW1GNPyk8Wm0xxFqMUh26vg==} - peerDependencies: - react: ^19 - react-dom: ^19 - viem: ^2.27 - wagmi: ^2.16 - - '@coinbase/wallet-sdk@3.9.3': - resolution: {integrity: sha512-N/A2DRIf0Y3PHc1XAMvbBUu4zisna6qAdqABMZwBMNEfWrXpAwx16pZGkYCLGE+Rvv1edbcB2LYDRnACNcmCiw==} - - '@coinbase/wallet-sdk@4.3.6': - resolution: {integrity: sha512-4q8BNG1ViL4mSAAvPAtpwlOs1gpC+67eQtgIwNvT3xyeyFFd+guwkc8bcX5rTmQhXpqnhzC4f0obACbP9CqMSA==} - - '@colors/colors@1.6.0': - resolution: {integrity: sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==} - engines: {node: '>=0.1.90'} - - '@craftamap/esbuild-plugin-html@0.9.0': - resolution: {integrity: sha512-V5LFrcGXQWU1SSzYPwxEFjF8IjeXW0oTKh5c0xyhGuTNoEnjgJRNSX83HnZ5TTAutJfo/MAyWA4Z9/fIwbMhUQ==} - engines: {node: '>=18'} - peerDependencies: - esbuild: '>=0.15.10' - - '@csstools/color-helpers@5.0.2': - resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==} - engines: {node: '>=18'} - - '@csstools/css-calc@2.1.4': - resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-color-parser@3.0.10': - resolution: {integrity: sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-parser-algorithms@3.0.5': - resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-tokenizer@3.0.4': - resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} - engines: {node: '>=18'} - - '@dabh/diagnostics@2.0.3': - resolution: {integrity: sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==} - - '@develar/schema-utils@2.6.5': - resolution: {integrity: sha512-0cp4PsWQ/9avqTVMCtZ+GirikIA36ikvjtHweU4/j8yLtgObI0+JUPhYFScgwlteveGB1rt3Cm8UhN04XayDig==} - engines: {node: '>= 8.9.0'} - - '@ecies/ciphers@0.2.4': - resolution: {integrity: sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==} - engines: {bun: '>=1', deno: '>=2', node: '>=16'} - peerDependencies: - '@noble/ciphers': ^1.0.0 - - '@electron/asar@3.2.18': - resolution: {integrity: sha512-2XyvMe3N3Nrs8cV39IKELRHTYUWFKrmqqSY1U+GMlc0jvqjIVnoxhNd2H4JolWQncbJi1DCvb5TNxZuI2fEjWg==} - engines: {node: '>=10.12.0'} - hasBin: true - - '@electron/asar@3.4.1': - resolution: {integrity: sha512-i4/rNPRS84t0vSRa2HorerGRXWyF4vThfHesw0dmcWHp+cspK743UanA0suA5Q5y8kzY2y6YKrvbIUn69BCAiA==} - engines: {node: '>=10.12.0'} - hasBin: true - - '@electron/fuses@1.8.0': - resolution: {integrity: sha512-zx0EIq78WlY/lBb1uXlziZmDZI4ubcCXIMJ4uGjXzZW0nS19TjSPeXPAjzzTmKQlJUZm0SbmZhPKP7tuQ1SsEw==} - hasBin: true - - '@electron/get@2.0.3': - resolution: {integrity: sha512-Qkzpg2s9GnVV2I2BjRksUi43U5e6+zaQMcjoJy0C+C5oxaKl+fmckGDQFtRpZpZV0NQekuZZ+tGz7EA9TVnQtQ==} - engines: {node: '>=12'} - - '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': - resolution: {tarball: https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2} - version: 10.2.0-electron.1 - engines: {node: '>=12.13.0'} - hasBin: true - - '@electron/notarize@2.5.0': - resolution: {integrity: sha512-jNT8nwH1f9X5GEITXaQ8IF/KdskvIkOFfB2CvwumsveVidzpSc+mvhhTMdAGSYF3O+Nq49lJ7y+ssODRXu06+A==} - engines: {node: '>= 10.0.0'} - - '@electron/osx-sign@1.3.1': - resolution: {integrity: sha512-BAfviURMHpmb1Yb50YbCxnOY0wfwaLXH5KJ4+80zS0gUkzDX3ec23naTlEqKsN+PwYn+a1cCzM7BJ4Wcd3sGzw==} - engines: {node: '>=12.0.0'} - hasBin: true - - '@electron/rebuild@3.7.0': - resolution: {integrity: sha512-VW++CNSlZwMYP7MyXEbrKjpzEwhB5kDNbzGtiPEjwYysqyTCF+YbNJ210Dj3AjWsGSV4iEEwNkmJN9yGZmVvmw==} - engines: {node: '>=12.13.0'} - hasBin: true - - '@electron/universal@2.0.1': - resolution: {integrity: sha512-fKpv9kg4SPmt+hY7SVBnIYULE9QJl8L3sCfcBsnqbJwwBwAeTLokJ9TRt9y7bK0JAzIW2y78TVVjvnQEms/yyA==} - engines: {node: '>=16.4'} - - '@electron/windows-sign@1.2.2': - resolution: {integrity: sha512-dfZeox66AvdPtb2lD8OsIIQh12Tp0GNCRUDfBHIKGpbmopZto2/A8nSpYYLoedPIHpqkeblZ/k8OV0Gy7PYuyQ==} - engines: {node: '>=14.14'} - hasBin: true - - '@emnapi/core@1.4.5': - resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} - - '@emnapi/runtime@1.7.1': - resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} - - '@emnapi/wasi-threads@1.0.4': - resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} - - '@es-joy/jsdoccomment@0.50.2': - resolution: {integrity: sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==} - engines: {node: '>=18'} - - '@esbuild/aix-ppc64@0.19.12': - resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [aix] - - '@esbuild/aix-ppc64@0.25.9': - resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.19.12': - resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm64@0.25.9': - resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.19.12': - resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} - engines: {node: '>=12'} - cpu: [arm] - os: [android] - - '@esbuild/android-arm@0.25.9': - resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.19.12': - resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} - engines: {node: '>=12'} - cpu: [x64] - os: [android] - - '@esbuild/android-x64@0.25.9': - resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.19.12': - resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} - engines: {node: '>=12'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-arm64@0.25.9': - resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.19.12': - resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} - engines: {node: '>=12'} - cpu: [x64] - os: [darwin] - - '@esbuild/darwin-x64@0.25.9': - resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.19.12': - resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-arm64@0.25.9': - resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.19.12': - resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} - engines: {node: '>=12'} - cpu: [x64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.25.9': - resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.19.12': - resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} - engines: {node: '>=12'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm64@0.25.9': - resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.19.12': - resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} - engines: {node: '>=12'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-arm@0.25.9': - resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.19.12': - resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} - engines: {node: '>=12'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-ia32@0.25.9': - resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.19.12': - resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} - engines: {node: '>=12'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-loong64@0.25.9': - resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.19.12': - resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} - engines: {node: '>=12'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-mips64el@0.25.9': - resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.19.12': - resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} - engines: {node: '>=12'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-ppc64@0.25.9': - resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.19.12': - resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} - engines: {node: '>=12'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-riscv64@0.25.9': - resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.19.12': - resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} - engines: {node: '>=12'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-s390x@0.25.9': - resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.19.12': - resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} - engines: {node: '>=12'} - cpu: [x64] - os: [linux] - - '@esbuild/linux-x64@0.25.9': - resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.25.9': - resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.19.12': - resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} - engines: {node: '>=12'} - cpu: [x64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.25.9': - resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.25.9': - resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.19.12': - resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} - engines: {node: '>=12'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.25.9': - resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.25.9': - resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.19.12': - resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} - engines: {node: '>=12'} - cpu: [x64] - os: [sunos] - - '@esbuild/sunos-x64@0.25.9': - resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.19.12': - resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} - engines: {node: '>=12'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-arm64@0.25.9': - resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.19.12': - resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} - engines: {node: '>=12'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-ia32@0.25.9': - resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.19.12': - resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} - engines: {node: '>=12'} - cpu: [x64] - os: [win32] - - '@esbuild/win32-x64@0.25.9': - resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.7.0': - resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.1': - resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/config-array@0.21.0': - resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.3.1': - resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.15.2': - resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@2.1.4': - resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/eslintrc@3.3.1': - resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@8.57.1': - resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - '@eslint/js@9.33.0': - resolution: {integrity: sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.6': - resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.3.5': - resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@ethereumjs/common@3.2.0': - resolution: {integrity: sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==} - - '@ethereumjs/rlp@4.0.1': - resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} - engines: {node: '>=14'} - hasBin: true - - '@ethereumjs/tx@4.2.0': - resolution: {integrity: sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==} - engines: {node: '>=14'} - - '@ethereumjs/util@8.1.0': - resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} - engines: {node: '>=14'} - - '@farcaster/frame-core@0.1.8': - resolution: {integrity: sha512-Y0JATQXa/iaqH3pCp8Dby4iCQbwqw7JJaGtfzUazdr7R+zs3EDP8DYQCkqJu6iGjE9gqgecB+b+DOZpnqMTDNw==} - - '@farcaster/frame-sdk@0.0.60': - resolution: {integrity: sha512-MHQwdFT1VPe3kS0NvnORBPb/DQXr8qpdSDgIgfrdVCB8byQ5uFELlr3gQMuFYFyLFQVXgbMl75z8O6+hvorqow==} - - '@farcaster/frame-sdk@0.1.9': - resolution: {integrity: sha512-r5cAKgHn4w8Q1jaCi84uKqItfNRd6h8Lk0YyQaz5kMoEIeJ4C0gXPpyqKPYP2TVDFuvaexg2KvzCO2CQdygWyQ==} - engines: {node: '>=22.11.0'} - - '@farcaster/frame-wagmi-connector@0.0.42': - resolution: {integrity: sha512-KI6/Jai7TVOz1B166E86Pf+ehNFyknn0AzSXJ7RTeSX/Uvh1jna+DgISNpRJjV08YJHBxkynAi+kQI4dlbqJoQ==} - peerDependencies: - '@farcaster/frame-sdk': ^0.0.53 - '@wagmi/core': ^2.14.1 - viem: ^2.21.55 - - '@farcaster/miniapp-core@0.3.8': - resolution: {integrity: sha512-LaRG1L3lxHqo5pP/E2CX9hNqusR0C8hX3QTV2+hzmQJz6IGvmSpH6Q9ivlLyDfbdqokiMFo5Y3Z1EX1zBHMEQQ==} - - '@farcaster/miniapp-core@0.4.1': - resolution: {integrity: sha512-20FxHTRToYUKx7CQ8PvIy9OoQ6XjdmF1pRMS7dsj37qdqjVDeEkYoK8yXwnoReZoJRcYwIg8P3i6V8bTWNR5mg==} - - '@farcaster/miniapp-sdk@0.1.9': - resolution: {integrity: sha512-hn0dlIy0JP2Hx6PgKcn9bjYwyPS/SQgYJ/a0qjzG8ZsDfUdjsMPf3yI/jicBipTml/UUoKcbqXM68fsrsbNMKA==} - - '@farcaster/miniapp-sdk@0.2.1': - resolution: {integrity: sha512-2SnDeOtDdlN1lGQt7UyH2jkrZRQDOkmhcrlzNWazYChyPh9XfV8+9fMS+Lr/E2pEws9Q40Xl9POrCzdpUC19lg==} - - '@farcaster/miniapp-wagmi-connector@1.0.0': - resolution: {integrity: sha512-vMRZbekUUctnAUvBFhNoEsJlujRRdxop94fDy5LrKiRR9ax0wtp8gCvLYO+LpaP2PtGs0HFpRwlHNDJWvBR8bg==} - peerDependencies: - '@farcaster/miniapp-sdk': ^0.1.0 - '@wagmi/core': ^2.14.1 - viem: ^2.21.55 - - '@farcaster/quick-auth@0.0.5': - resolution: {integrity: sha512-Z8hWz/7c33zlmII2AJHja/Wz0C03mm2o+CEBtBylmiun1wC4FMgx1Fal699VQvBUG1lpcJ662WxuRNxKogktDw==} - peerDependencies: - typescript: 5.8.3 - - '@farcaster/quick-auth@0.0.6': - resolution: {integrity: sha512-tiZndhpfDtEhaKlkmS5cVDuS+A/tafqZT3y9I44rC69m3beJok6e8dIH2JhxVy3EvOWTyTBnrmNn6GOOh+qK6A==} - peerDependencies: - typescript: 5.8.3 - - '@fastify/ajv-compiler@4.0.5': - resolution: {integrity: sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A==} - - '@fastify/error@4.2.0': - resolution: {integrity: sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==} - - '@fastify/fast-json-stringify-compiler@5.0.3': - resolution: {integrity: sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ==} - - '@fastify/forwarded@3.0.1': - resolution: {integrity: sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw==} - - '@fastify/merge-json-schemas@0.2.1': - resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==} - - '@fastify/proxy-addr@5.1.0': - resolution: {integrity: sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==} - - '@floating-ui/core@1.7.3': - resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} - - '@floating-ui/dom@1.7.3': - resolution: {integrity: sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==} - - '@floating-ui/dom@1.7.4': - resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - - '@floating-ui/react-dom@2.1.5': - resolution: {integrity: sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/react-dom@2.1.6': - resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} - peerDependencies: - react: '>=16.8.0' - react-dom: '>=16.8.0' - - '@floating-ui/react@0.27.16': - resolution: {integrity: sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==} - peerDependencies: - react: '>=17.0.0' - react-dom: '>=17.0.0' - - '@floating-ui/utils@0.2.10': - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - - '@gar/promisify@1.1.3': - resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} - - '@gemini-wallet/core@0.2.0': - resolution: {integrity: sha512-vv9aozWnKrrPWQ3vIFcWk7yta4hQW1Ie0fsNNPeXnjAxkbXr2hqMagEptLuMxpEP2W3mnRu05VDNKzcvAuuZDw==} - peerDependencies: - viem: '>=2.0.0' - - '@gemini-wallet/core@0.3.2': - resolution: {integrity: sha512-Z4aHi3ECFf5oWYWM3F1rW83GJfB9OvhBYPTmb5q+VyK3uvzvS48lwo+jwh2eOoCRWEuT/crpb9Vwp2QaS5JqgQ==} - peerDependencies: - viem: '>=2.0.0' - - '@graphql-typed-document-node/core@3.2.0': - resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} - peerDependencies: - graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - - '@heroicons/react@2.2.0': - resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==} - peerDependencies: - react: '>= 16 || ^19.0.0-rc' - - '@hono/node-server@1.19.0': - resolution: {integrity: sha512-1k8/8OHf5VIymJEcJyVksFpT+AQ5euY0VA5hUkCnlKpD4mr8FSbvXaHblxeTTEr90OaqWzAkQaqD80qHZQKxBA==} - engines: {node: '>=18.14.1'} - peerDependencies: - hono: ^4 - - '@hpke/chacha20poly1305@1.7.1': - resolution: {integrity: sha512-Zp8IwRIkdCucu877wCNqDp3B8yOhAnAah/YDDkO94pPr/KKV7IGnBbpwIjDB3BsAySWBMrhhdE0JKYw3N4FCag==} - engines: {node: '>=16.0.0'} - - '@hpke/common@1.8.1': - resolution: {integrity: sha512-PSI4QSxH8XDli0TqAsWycVfrLLCM/bBe+hVlJwtuJJiKIvCaFS3CXX/WtRfJceLJye9NHc2J7GvHVCY9B1BEbA==} - engines: {node: '>=16.0.0'} - - '@hpke/core@1.7.4': - resolution: {integrity: sha512-1BfPQB7unq/tNx7eznmoFgmJlMFnymdLNNt2CQX/L8oYOfmc1+cFEItpXZ90mgthW7tB2oksy/G7Xh1t569qzA==} - engines: {node: '>=16.0.0'} - - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.6': - resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/config-array@0.13.0': - resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} - engines: {node: '>=10.10.0'} - deprecated: Use @eslint/config-array instead - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/object-schema@2.0.3': - resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} - deprecated: Use @eslint/object-schema instead - - '@humanwhocodes/retry@0.3.1': - resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} - engines: {node: '>=18.18'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - - '@img/colour@1.0.0': - resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} - engines: {node: '>=18'} - - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [darwin] - - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} - cpu: [arm64] - os: [darwin] - - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} - cpu: [arm64] - os: [linux] - - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} - cpu: [arm] - os: [linux] - - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} - cpu: [ppc64] - os: [linux] - - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} - cpu: [riscv64] - os: [linux] - - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} - cpu: [s390x] - os: [linux] - - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} - cpu: [x64] - os: [linux] - - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} - cpu: [arm64] - os: [linux] - - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} - cpu: [x64] - os: [linux] - - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm] - os: [linux] - - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ppc64] - os: [linux] - - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [riscv64] - os: [linux] - - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [s390x] - os: [linux] - - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [wasm32] - - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [win32] - - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ia32] - os: [win32] - - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [win32] - - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.30': - resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} - - '@jup-ag/api@6.0.44': - resolution: {integrity: sha512-C6oYi+wvNi07VlmWhT8+ZDMqTJuF+MiHuNBE65cYuBH6C4l0JfwpXaj6mKazAdVqVFWgngr3s2+0tdF5nDH4tA==} - - '@langchain/core@0.3.72': - resolution: {integrity: sha512-WsGWVZYnlKffj2eEfDocPNiaTRoxyYiLSQdQ7oxZvxGZBqo/90vpjbC33UGK1uPNBM4kT+pkdaol/MnvKUh8TQ==} - engines: {node: '>=18'} - - '@langchain/langgraph-checkpoint@0.0.18': - resolution: {integrity: sha512-IS7zJj36VgY+4pf8ZjsVuUWef7oTwt1y9ylvwu0aLuOn1d0fg05Om9DLm3v2GZ2Df6bhLV1kfWAM0IAl9O5rQQ==} - engines: {node: '>=18'} - peerDependencies: - '@langchain/core': '>=0.2.31 <0.4.0' - - '@langchain/langgraph-sdk@0.0.109': - resolution: {integrity: sha512-UpjL0c681CJqvKxgWD8o9fwUXRZzcDfsz8EcJ2PkXFxQFKRLe4QKZMtBr4OKFTR94pJtlOuTVla4OV5I5w+mdQ==} - peerDependencies: - '@langchain/core': '>=0.2.31 <0.4.0' - react: ^18 || ^19 - react-dom: ^18 || ^19 - peerDependenciesMeta: - '@langchain/core': - optional: true - react: - optional: true - react-dom: - optional: true - - '@langchain/langgraph@0.2.74': - resolution: {integrity: sha512-oHpEi5sTZTPaeZX1UnzfM2OAJ21QGQrwReTV6+QnX7h8nDCBzhtipAw1cK616S+X8zpcVOjgOtJuaJhXa4mN8w==} - engines: {node: '>=18'} - peerDependencies: - '@langchain/core': '>=0.2.36 <0.3.0 || >=0.3.40 < 0.4.0' - zod-to-json-schema: ^3.x - peerDependenciesMeta: - zod-to-json-schema: - optional: true - - '@langchain/openai@0.5.18': - resolution: {integrity: sha512-CX1kOTbT5xVFNdtLjnM0GIYNf+P7oMSu+dGCFxxWRa3dZwWiuyuBXCm+dToUGxDLnsHuV1bKBtIzrY1mLq/A1Q==} - engines: {node: '>=18'} - peerDependencies: - '@langchain/core': '>=0.3.58 <0.4.0' - - '@lit-labs/ssr-dom-shim@1.4.0': - resolution: {integrity: sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==} - - '@lit/reactive-element@2.1.1': - resolution: {integrity: sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==} - - '@llamaindex/anthropic@0.3.23': - resolution: {integrity: sha512-4qvRZ8cBasRdLliN5KMi1diSn+9lNFTOaUroCSwMAivRl97R1HVd+ZRfXqmorkoB2aYpG4rAZ9ycIgRNUctX8g==} - peerDependencies: - '@llamaindex/core': 0.6.20 - '@llamaindex/env': 0.1.30 - - '@llamaindex/cloud@4.0.7': - resolution: {integrity: sha512-6Ghryb1M8YHDisy4MgGHTpoUY9WQVAS1wBOI8j9fySIf/E2O50tkc15I3Tw5oTeffSdvVE9El3/L8PhZnLM48A==} - peerDependencies: - '@llamaindex/core': 0.6.5 - '@llamaindex/env': 0.1.30 - - '@llamaindex/core@0.6.5': - resolution: {integrity: sha512-72/JrB0g8Gbor6Vzrsz/UGZoNAe2RnGSfq9vfNHahgUiSU9OfQNMHEH7O/xQRrI1BAWOOfpiRv/sf3yaZNbMcw==} - - '@llamaindex/env@0.1.30': - resolution: {integrity: sha512-y6kutMcCevzbmexUgz+HXf7KiZemzAoFEYSjAILfR+cG6FmYSF8XvLbGOB34Kx8mlRi7EI8rZXpezJ5qCqOyZg==} - peerDependencies: - '@huggingface/transformers': ^3.5.0 - gpt-tokenizer: ^2.5.0 - peerDependenciesMeta: - '@huggingface/transformers': - optional: true - gpt-tokenizer: - optional: true - - '@llamaindex/node-parser@2.0.5': - resolution: {integrity: sha512-p0Y3RBQUyUp7ry5SDLuGbL0sMvokwuuxIBjXqShwSyRYlkgxM9gOUQjorO+GeeS/ltUyGeZtGox7h0+wpGV7yw==} - peerDependencies: - '@llamaindex/core': 0.6.5 - '@llamaindex/env': 0.1.30 - tree-sitter: ^0.22.0 - web-tree-sitter: ^0.24.3 - - '@llamaindex/openai@0.3.7': - resolution: {integrity: sha512-nm+DiGldp8Fobvm8sgH3D4gvpZ89RtoEfSVIBId3WFFJnn/VYwAyBPSHs3a4dSLlILnq+R7LHlbwXF4nyh1ZNg==} - peerDependencies: - '@llamaindex/core': 0.6.5 - '@llamaindex/env': 0.1.30 - - '@llamaindex/workflow@1.0.3': - resolution: {integrity: sha512-GzYzLfn12BTQiLVwFr9tGl1Sa7PPVErLLQAJMgvfjUK8cv764SpJGqln8iKTxnKF05HcRrmJeE7ZD9Lzpf7UrA==} - peerDependencies: - '@llamaindex/core': 0.6.2 - '@llamaindex/env': 0.1.29 - zod: ^3.23.8 - - '@malept/cross-spawn-promise@2.0.0': - resolution: {integrity: sha512-1DpKU0Z5ThltBwjNySMC14g0CkbyhCaz9FkhxqNsZI6uAPJXFS8cMXlBKo26FJ8ZuW6S9GCMcR9IO5k2X5/9Fg==} - engines: {node: '>= 12.13.0'} - - '@malept/flatpak-bundler@0.4.0': - resolution: {integrity: sha512-9QOtNffcOF/c1seMCDnjckb3R9WHcG34tky+FHpNKKCW0wc/scYLwMtO+ptyGUfMW0/b/n4qRiALlaFHc9Oj7Q==} - engines: {node: '>= 10.0.0'} - - '@metamask/eth-json-rpc-provider@1.0.1': - resolution: {integrity: sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA==} - engines: {node: '>=14.0.0'} - - '@metamask/json-rpc-engine@7.3.3': - resolution: {integrity: sha512-dwZPq8wx9yV3IX2caLi9q9xZBw2XeIoYqdyihDDDpuHVCEiqadJLwqM3zy+uwf6F1QYQ65A8aOMQg1Uw7LMLNg==} - engines: {node: '>=16.0.0'} - - '@metamask/json-rpc-engine@8.0.2': - resolution: {integrity: sha512-IoQPmql8q7ABLruW7i4EYVHWUbF74yrp63bRuXV5Zf9BQwcn5H9Ww1eLtROYvI1bUXwOiHZ6qT5CWTrDc/t/AA==} - engines: {node: '>=16.0.0'} - - '@metamask/json-rpc-middleware-stream@7.0.2': - resolution: {integrity: sha512-yUdzsJK04Ev98Ck4D7lmRNQ8FPioXYhEUZOMS01LXW8qTvPGiRVXmVltj2p4wrLkh0vW7u6nv0mNl5xzC5Qmfg==} - engines: {node: '>=16.0.0'} - - '@metamask/object-multiplex@2.1.0': - resolution: {integrity: sha512-4vKIiv0DQxljcXwfpnbsXcfa5glMj5Zg9mqn4xpIWqkv6uJ2ma5/GtUfLFSxhlxnR8asRMv8dDmWya1Tc1sDFA==} - engines: {node: ^16.20 || ^18.16 || >=20} - - '@metamask/onboarding@1.0.1': - resolution: {integrity: sha512-FqHhAsCI+Vacx2qa5mAFcWNSrTcVGMNjzxVgaX8ECSny/BJ9/vgXP9V7WF/8vb9DltPeQkxr+Fnfmm6GHfmdTQ==} - - '@metamask/providers@16.1.0': - resolution: {integrity: sha512-znVCvux30+3SaUwcUGaSf+pUckzT5ukPRpcBmy+muBLC0yaWnBcvDqGfcsw6CBIenUdFrVoAFa8B6jsuCY/a+g==} - engines: {node: ^18.18 || >=20} - - '@metamask/rpc-errors@6.4.0': - resolution: {integrity: sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg==} - engines: {node: '>=16.0.0'} - - '@metamask/rpc-errors@7.0.2': - resolution: {integrity: sha512-YYYHsVYd46XwY2QZzpGeU4PSdRhHdxnzkB8piWGvJW2xbikZ3R+epAYEL4q/K8bh9JPTucsUdwRFnACor1aOYw==} - engines: {node: ^18.20 || ^20.17 || >=22} - - '@metamask/safe-event-emitter@2.0.0': - resolution: {integrity: sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==} - - '@metamask/safe-event-emitter@3.1.2': - resolution: {integrity: sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA==} - engines: {node: '>=12.0.0'} - - '@metamask/sdk-analytics@0.0.5': - resolution: {integrity: sha512-fDah+keS1RjSUlC8GmYXvx6Y26s3Ax1U9hGpWb6GSY5SAdmTSIqp2CvYy6yW0WgLhnYhW+6xERuD0eVqV63QIQ==} - - '@metamask/sdk-communication-layer@0.32.0': - resolution: {integrity: sha512-dmj/KFjMi1fsdZGIOtbhxdg3amxhKL/A5BqSU4uh/SyDKPub/OT+x5pX8bGjpTL1WPWY/Q0OIlvFyX3VWnT06Q==} - peerDependencies: - cross-fetch: ^4.0.0 - eciesjs: '*' - eventemitter2: ^6.4.9 - readable-stream: ^3.6.2 - socket.io-client: ^4.5.1 - - '@metamask/sdk-communication-layer@0.33.1': - resolution: {integrity: sha512-0bI9hkysxcfbZ/lk0T2+aKVo1j0ynQVTuB3sJ5ssPWlz+Z3VwveCkP1O7EVu1tsVVCb0YV5WxK9zmURu2FIiaA==} - peerDependencies: - cross-fetch: ^4.0.0 - eciesjs: '*' - eventemitter2: ^6.4.9 - readable-stream: ^3.6.2 - socket.io-client: ^4.5.1 - - '@metamask/sdk-install-modal-web@0.32.0': - resolution: {integrity: sha512-TFoktj0JgfWnQaL3yFkApqNwcaqJ+dw4xcnrJueMP3aXkSNev2Ido+WVNOg4IIMxnmOrfAC9t0UJ0u/dC9MjOQ==} - - '@metamask/sdk-install-modal-web@0.32.1': - resolution: {integrity: sha512-MGmAo6qSjf1tuYXhCu2EZLftq+DSt5Z7fsIKr2P+lDgdTPWgLfZB1tJKzNcwKKOdf6q9Qmmxn7lJuI/gq5LrKw==} - - '@metamask/sdk@0.32.0': - resolution: {integrity: sha512-WmGAlP1oBuD9hk4CsdlG1WJFuPtYJY+dnTHJMeCyohTWD2GgkcLMUUuvu9lO1/NVzuOoSi1OrnjbuY1O/1NZ1g==} - - '@metamask/sdk@0.33.1': - resolution: {integrity: sha512-1mcOQVGr9rSrVcbKPNVzbZ8eCl1K0FATsYH3WJ/MH4WcZDWGECWrXJPNMZoEAkLxWiMe8jOQBumg2pmcDa9zpQ==} - - '@metamask/superstruct@3.2.1': - resolution: {integrity: sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g==} - engines: {node: '>=16.0.0'} - - '@metamask/utils@11.4.2': - resolution: {integrity: sha512-TygCcGmUbhmpxjYMm+mx68kRiJ80jYV54/Aa8gUFBv4cTX7ulX2XZKr8CJoJAw3K3FN5ZvCRmU0IzWZFaonwhA==} - engines: {node: ^18.18 || ^20.14 || >=22} - - '@metamask/utils@5.0.2': - resolution: {integrity: sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==} - engines: {node: '>=14.0.0'} - - '@metamask/utils@8.5.0': - resolution: {integrity: sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==} - engines: {node: '>=16.0.0'} - - '@metamask/utils@9.3.0': - resolution: {integrity: sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==} - engines: {node: '>=16.0.0'} - - '@modelcontextprotocol/sdk@1.17.3': - resolution: {integrity: sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==} - engines: {node: '>=18'} - - '@napi-rs/wasm-runtime@0.2.12': - resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - - '@next/env@15.5.9': - resolution: {integrity: sha512-4GlTZ+EJM7WaW2HEZcyU317tIQDjkQIyENDLxYJfSWlfqguN+dHkZgyQTV/7ykvobU7yEH5gKvreNrH4B6QgIg==} - - '@next/env@16.0.10': - resolution: {integrity: sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==} - - '@next/eslint-plugin-next@15.5.7': - resolution: {integrity: sha512-DtRU2N7BkGr8r+pExfuWHwMEPX5SD57FeA6pxdgCHODo+b/UgIgjE+rgWKtJAbEbGhVZ2jtHn4g3wNhWFoNBQQ==} - - '@next/eslint-plugin-next@16.0.6': - resolution: {integrity: sha512-9INsBF3/4XL0/tON8AGsh0svnTtDMLwv3iREGWnWkewGdOnd790tguzq9rX8xwrVthPyvaBHhw1ww0GZz0jO5Q==} - - '@next/eslint-plugin-next@16.0.7': - resolution: {integrity: sha512-hFrTNZcMEG+k7qxVxZJq3F32Kms130FAhG8lvw2zkKBgAcNOJIxlljNiCjGygvBshvaGBdf88q2CqWtnqezDHA==} - - '@next/swc-darwin-arm64@15.5.7': - resolution: {integrity: sha512-IZwtxCEpI91HVU/rAUOOobWSZv4P2DeTtNaCdHqLcTJU4wdNXgAySvKa/qJCgR5m6KI8UsKDXtO2B31jcaw1Yw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-arm64@16.0.10': - resolution: {integrity: sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-x64@15.5.7': - resolution: {integrity: sha512-UP6CaDBcqaCBuiq/gfCEJw7sPEoX1aIjZHnBWN9v9qYHQdMKvCKcAVs4OX1vIjeE+tC5EIuwDTVIoXpUes29lg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-darwin-x64@16.0.10': - resolution: {integrity: sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-linux-arm64-gnu@15.5.7': - resolution: {integrity: sha512-NCslw3GrNIw7OgmRBxHtdWFQYhexoUCq+0oS2ccjyYLtcn1SzGzeM54jpTFonIMUjNbHmpKpziXnpxhSWLcmBA==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-gnu@16.0.10': - resolution: {integrity: sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-musl@15.5.7': - resolution: {integrity: sha512-nfymt+SE5cvtTrG9u1wdoxBr9bVB7mtKTcj0ltRn6gkP/2Nu1zM5ei8rwP9qKQP0Y//umK+TtkKgNtfboBxRrw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-musl@16.0.10': - resolution: {integrity: sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-x64-gnu@15.5.7': - resolution: {integrity: sha512-hvXcZvCaaEbCZcVzcY7E1uXN9xWZfFvkNHwbe/n4OkRhFWrs1J1QV+4U1BN06tXLdaS4DazEGXwgqnu/VMcmqw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-gnu@16.0.10': - resolution: {integrity: sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-musl@15.5.7': - resolution: {integrity: sha512-4IUO539b8FmF0odY6/SqANJdgwn1xs1GkPO5doZugwZ3ETF6JUdckk7RGmsfSf7ws8Qb2YB5It33mvNL/0acqA==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-linux-x64-musl@16.0.10': - resolution: {integrity: sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-win32-arm64-msvc@15.5.7': - resolution: {integrity: sha512-CpJVTkYI3ZajQkC5vajM7/ApKJUOlm6uP4BknM3XKvJ7VXAvCqSjSLmM0LKdYzn6nBJVSjdclx8nYJSa3xlTgQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-arm64-msvc@16.0.10': - resolution: {integrity: sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-x64-msvc@15.5.7': - resolution: {integrity: sha512-gMzgBX164I6DN+9/PGA+9dQiwmTkE4TloBNx8Kv9UiGARsr9Nba7IpcBRA1iTV9vwlYnrE3Uy6I7Aj6qLjQuqw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@next/swc-win32-x64-msvc@16.0.10': - resolution: {integrity: sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@noble/ciphers@1.2.1': - resolution: {integrity: sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==} - engines: {node: ^14.21.3 || >=16} - - '@noble/ciphers@1.3.0': - resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} - engines: {node: ^14.21.3 || >=16} - - '@noble/curves@1.2.0': - resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} - - '@noble/curves@1.4.2': - resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} - - '@noble/curves@1.8.0': - resolution: {integrity: sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==} - engines: {node: ^14.21.3 || >=16} - - '@noble/curves@1.8.1': - resolution: {integrity: sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==} - engines: {node: ^14.21.3 || >=16} - - '@noble/curves@1.9.1': - resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} - engines: {node: ^14.21.3 || >=16} - - '@noble/curves@1.9.7': - resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} - engines: {node: ^14.21.3 || >=16} - - '@noble/hashes@1.3.2': - resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} - engines: {node: '>= 16'} - - '@noble/hashes@1.4.0': - resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} - engines: {node: '>= 16'} - - '@noble/hashes@1.7.0': - resolution: {integrity: sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==} - engines: {node: ^14.21.3 || >=16} - - '@noble/hashes@1.7.1': - resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} - engines: {node: ^14.21.3 || >=16} - - '@noble/hashes@1.8.0': - resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} - engines: {node: ^14.21.3 || >=16} - - '@nodelib/fs.scandir@2.1.5': - resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} - engines: {node: '>= 8'} - - '@nodelib/fs.stat@2.0.5': - resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} - engines: {node: '>= 8'} - - '@nodelib/fs.walk@1.2.8': - resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} - engines: {node: '>= 8'} - - '@nolyfill/is-core-module@1.0.39': - resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} - engines: {node: '>=12.4.0'} - - '@npmcli/fs@2.1.2': - resolution: {integrity: sha512-yOJKRvohFOaLqipNtwYB9WugyZKhC/DZC4VYPmpaCzDBrA8YpK3qHZ8/HGscMnE4GqbkLNuVcCnxkeQEdGt6LQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - - '@npmcli/move-file@2.0.1': - resolution: {integrity: sha512-mJd2Z5TjYWq/ttPLLGqArdtnC74J6bOzg4rMDnN+p1xTacZ2yPRCk2y0oSWQtygLR9YVQXgOcONrwtnk3JupxQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - deprecated: This functionality has been moved to @npmcli/fs - - '@opensea/seaport-js@4.0.5': - resolution: {integrity: sha512-hyJEHSCFmO7kv2G+ima0kCpt0kvLa6QOSHb1HJuLd8DS3bao0gOa/Q3AhM3xUqO6SZZ8aD9njhu1EDqjC/5pOw==} - engines: {node: '>=20.0.0'} - - '@paulmillr/qr@0.2.1': - resolution: {integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==} - deprecated: 'The package is now available as "qr": npm install qr' - - '@pinojs/redact@0.4.0': - resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} - - '@pkgjs/parseargs@0.11.0': - resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} - engines: {node: '>=14'} - - '@pkgr/core@0.2.9': - resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - - '@privy-io/api-base@1.6.0': - resolution: {integrity: sha512-ftlqjFw0Ww7Xn6Ad/1kEUsXRfKqNdmJYKat4ryJl2uPh60QXXlPfnf4y17dDFHJlnVb7qY10cCvKVz5ev5gAeg==} - - '@privy-io/public-api@2.43.1': - resolution: {integrity: sha512-zhGBTghZiwnqdA4YvrXXM7fsz3fWUltSkxNdnQTqKGb/IfV8aZ14ryuWvD4v5oPJGtqVcwKRfdDmW8TMPGZHog==} - - '@privy-io/server-auth@1.31.1': - resolution: {integrity: sha512-w0DT0VZCPcXa/Mxqzo7fhXoInX5i4J5BgvzjNsdtMuovgR790kMx/9+K/rSlgtQ/25/B7oDjoIk/f8kd5Ps6mA==} - peerDependencies: - ethers: ^6 - viem: ^2.24.1 - peerDependenciesMeta: - ethers: - optional: true - viem: - optional: true - - '@radix-ui/colors@3.0.0': - resolution: {integrity: sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==} - - '@radix-ui/number@1.1.1': - resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - - '@radix-ui/react-accessible-icon@1.1.7': - resolution: {integrity: sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-accordion@1.2.12': - resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-alert-dialog@1.1.15': - resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-arrow@1.1.7': - resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-aspect-ratio@1.1.7': - resolution: {integrity: sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-avatar@1.1.10': - resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-checkbox@1.3.3': - resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-collapsible@1.1.12': - resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-collection@1.1.7': - resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context-menu@2.2.16': - resolution: {integrity: sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dialog@1.1.15': - resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dismissable-layer@1.1.11': - resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-dropdown-menu@2.1.16': - resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-focus-guards@1.1.3': - resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-focus-scope@1.1.7': - resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-form@0.1.8': - resolution: {integrity: sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-hover-card@1.1.15': - resolution: {integrity: sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-icons@1.3.2': - resolution: {integrity: sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==} - peerDependencies: - react: ^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc - - '@radix-ui/react-id@1.1.1': - resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-label@2.1.7': - resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-menu@2.1.16': - resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-menubar@1.1.16': - resolution: {integrity: sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-navigation-menu@1.2.14': - resolution: {integrity: sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-one-time-password-field@0.1.8': - resolution: {integrity: sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-password-toggle-field@0.1.3': - resolution: {integrity: sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popover@1.1.15': - resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-popper@1.2.8': - resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-portal@1.1.9': - resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-presence@1.1.5': - resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-progress@1.1.7': - resolution: {integrity: sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-radio-group@1.3.8': - resolution: {integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-roving-focus@1.1.11': - resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-scroll-area@1.2.10': - resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-select@2.2.6': - resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-separator@1.1.7': - resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slider@1.3.6': - resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-switch@1.2.6': - resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-tabs@1.1.13': - resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toast@1.2.15': - resolution: {integrity: sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toggle-group@1.1.11': - resolution: {integrity: sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toggle@1.1.10': - resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-toolbar@1.1.11': - resolution: {integrity: sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-tooltip@1.2.8': - resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-is-hydrated@0.1.0': - resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-previous@1.1.1': - resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-rect@1.1.1': - resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-use-size@1.1.1': - resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-visually-hidden@1.2.3': - resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@radix-ui/rect@1.1.1': - resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - - '@radix-ui/themes@3.2.1': - resolution: {integrity: sha512-WJL2YKAGItkunwm3O4cLTFKCGJTfAfF6Hmq7f5bCo1ggqC9qJQ/wfg/25AAN72aoEM1yqXZQ+pslsw48AFR0Xg==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: 16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: 16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true - - '@reown/appkit-common@1.7.8': - resolution: {integrity: sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==} - - '@reown/appkit-controllers@1.7.8': - resolution: {integrity: sha512-IdXlJlivrlj6m63VsGLsjtPHHsTWvKGVzWIP1fXZHVqmK+rZCBDjCi9j267Rb9/nYRGHWBtlFQhO8dK35WfeDA==} - - '@reown/appkit-pay@1.7.8': - resolution: {integrity: sha512-OSGQ+QJkXx0FEEjlpQqIhT8zGJKOoHzVnyy/0QFrl3WrQTjCzg0L6+i91Ad5Iy1zb6V5JjqtfIFpRVRWN4M3pw==} - - '@reown/appkit-polyfills@1.7.8': - resolution: {integrity: sha512-W/kq786dcHHAuJ3IV2prRLEgD/2iOey4ueMHf1sIFjhhCGMynMkhsOhQMUH0tzodPqUgAC494z4bpIDYjwWXaA==} - - '@reown/appkit-scaffold-ui@1.7.8': - resolution: {integrity: sha512-RCeHhAwOrIgcvHwYlNWMcIDibdI91waaoEYBGw71inE0kDB8uZbE7tE6DAXJmDkvl0qPh+DqlC4QbJLF1FVYdQ==} - - '@reown/appkit-ui@1.7.8': - resolution: {integrity: sha512-1hjCKjf6FLMFzrulhl0Y9Vb9Fu4royE+SXCPSWh4VhZhWqlzUFc7kutnZKx8XZFVQH4pbBvY62SpRC93gqoHow==} - - '@reown/appkit-utils@1.7.8': - resolution: {integrity: sha512-8X7UvmE8GiaoitCwNoB86pttHgQtzy4ryHZM9kQpvjQ0ULpiER44t1qpVLXNM4X35O0v18W0Dk60DnYRMH2WRw==} - peerDependencies: - valtio: 1.13.2 - - '@reown/appkit-wallet@1.7.8': - resolution: {integrity: sha512-kspz32EwHIOT/eg/ZQbFPxgXq0B/olDOj3YMu7gvLEFz4xyOFd/wgzxxAXkp5LbG4Cp++s/elh79rVNmVFdB9A==} - - '@reown/appkit@1.7.8': - resolution: {integrity: sha512-51kTleozhA618T1UvMghkhKfaPcc9JlKwLJ5uV+riHyvSoWPKPRIa5A6M1Wano5puNyW0s3fwywhyqTHSilkaA==} - - '@rolldown/pluginutils@1.0.0-beta.27': - resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} - - '@rollup/rollup-android-arm-eabi@4.46.4': - resolution: {integrity: sha512-B2wfzCJ+ps/OBzRjeds7DlJumCU3rXMxJJS1vzURyj7+KBHGONm7c9q1TfdBl4vCuNMkDvARn3PBl2wZzuR5mw==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.46.4': - resolution: {integrity: sha512-FGJYXvYdn8Bs6lAlBZYT5n+4x0ciEp4cmttsvKAZc/c8/JiPaQK8u0c/86vKX8lA7OY/+37lIQSe0YoAImvBAA==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.46.4': - resolution: {integrity: sha512-/9qwE/BM7ATw/W/OFEMTm3dmywbJyLQb4f4v5nmOjgYxPIGpw7HaxRi6LnD4Pjn/q7k55FGeHe1/OD02w63apA==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.46.4': - resolution: {integrity: sha512-QkWfNbeRuzFnv2d0aPlrzcA3Ebq2mE8kX/5Pl7VdRShbPBjSnom7dbT8E3Jmhxo2RL784hyqGvR5KHavCJQciw==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.46.4': - resolution: {integrity: sha512-+ToyOMYnSfV8D+ckxO6NthPln/PDNp1P6INcNypfZ7muLmEvPKXqduUiD8DlJpMMT8LxHcE5W0dK9kXfJke9Zw==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.46.4': - resolution: {integrity: sha512-cGT6ey/W+sje6zywbLiqmkfkO210FgRz7tepWAzzEVgQU8Hn91JJmQWNqs55IuglG8sJdzk7XfNgmGRtcYlo1w==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.46.4': - resolution: {integrity: sha512-9fhTJyOb275w5RofPSl8lpr4jFowd+H4oQKJ9XTYzD1JWgxdZKE8bA6d4npuiMemkecQOcigX01FNZNCYnQBdA==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.46.4': - resolution: {integrity: sha512-+6kCIM5Zjvz2HwPl/udgVs07tPMIp1VU2Y0c72ezjOvSvEfAIWsUgpcSDvnC7g9NrjYR6X9bZT92mZZ90TfvXw==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.46.4': - resolution: {integrity: sha512-SWuXdnsayCZL4lXoo6jn0yyAj7TTjWE4NwDVt9s7cmu6poMhtiras5c8h6Ih6Y0Zk6Z+8t/mLumvpdSPTWub2Q==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.46.4': - resolution: {integrity: sha512-vDknMDqtMhrrroa5kyX6tuC0aRZZlQ+ipDfbXd2YGz5HeV2t8HOl/FDAd2ynhs7Ki5VooWiiZcCtxiZ4IjqZwQ==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loongarch64-gnu@4.46.4': - resolution: {integrity: sha512-mCBkjRZWhvjtl/x+Bd4fQkWZT8canStKDxGrHlBiTnZmJnWygGcvBylzLVCZXka4dco5ymkWhZlLwKCGFF4ivw==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.46.4': - resolution: {integrity: sha512-YMdz2phOTFF+Z66dQfGf0gmeDSi5DJzY5bpZyeg9CPBkV9QDzJ1yFRlmi/j7WWRf3hYIWrOaJj5jsfwgc8GTHQ==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.46.4': - resolution: {integrity: sha512-r0WKLSfFAK8ucG024v2yiLSJMedoWvk8yWqfNICX28NHDGeu3F/wBf8KG6mclghx4FsLePxJr/9N8rIj1PtCnw==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.46.4': - resolution: {integrity: sha512-IaizpPP2UQU3MNyPH1u0Xxbm73D+4OupL0bjo4Hm0496e2wg3zuvoAIhubkD1NGy9fXILEExPQy87mweujEatA==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.46.4': - resolution: {integrity: sha512-aCM29orANR0a8wk896p6UEgIfupReupnmISz6SUwMIwTGaTI8MuKdE0OD2LvEg8ondDyZdMvnaN3bW4nFbATPA==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.46.4': - resolution: {integrity: sha512-0Xj1vZE3cbr/wda8d/m+UeuSL+TDpuozzdD4QaSzu/xSOMK0Su5RhIkF7KVHFQsobemUNHPLEcYllL7ZTCP/Cg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.46.4': - resolution: {integrity: sha512-kM/orjpolfA5yxsx84kI6bnK47AAZuWxglGKcNmokw2yy9i5eHY5UAjcX45jemTJnfHAWo3/hOoRqEeeTdL5hw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-win32-arm64-msvc@4.46.4': - resolution: {integrity: sha512-cNLH4psMEsWKILW0isbpQA2OvjXLbKvnkcJFmqAptPQbtLrobiapBJVj6RoIvg6UXVp5w0wnIfd/Q56cNpF+Ew==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.46.4': - resolution: {integrity: sha512-OiEa5lRhiANpv4SfwYVgQ3opYWi/QmPDC5ve21m8G9pf6ZO+aX1g2EEF1/IFaM1xPSP7mK0msTRXlPs6mIagkg==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.46.4': - resolution: {integrity: sha512-IKL9mewGZ5UuuX4NQlwOmxPyqielvkAPUS2s1cl6yWjjQvyN3h5JTdVFGD5Jr5xMjRC8setOfGQDVgX8V+dkjg==} - cpu: [x64] - os: [win32] - - '@rtsao/scc@1.1.0': - resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - - '@rushstack/eslint-patch@1.12.0': - resolution: {integrity: sha512-5EwMtOqvJMMa3HbmxLlF74e+3/HhwBTMcvt3nqVJgGCozO6hzIPOBlwm8mGVNR9SN2IJpxSnlxczyDjcn7qIyw==} - - '@safe-global/safe-apps-provider@0.18.6': - resolution: {integrity: sha512-4LhMmjPWlIO8TTDC2AwLk44XKXaK6hfBTWyljDm0HQ6TWlOEijVWNrt2s3OCVMSxlXAcEzYfqyu1daHZooTC2Q==} - - '@safe-global/safe-apps-sdk@9.1.0': - resolution: {integrity: sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q==} - - '@safe-global/safe-gateway-typescript-sdk@3.23.1': - resolution: {integrity: sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw==} - engines: {node: '>=16'} - - '@scure/base@1.1.9': - resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} - - '@scure/base@1.2.6': - resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} - - '@scure/bip32@1.4.0': - resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} - - '@scure/bip32@1.6.2': - resolution: {integrity: sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==} - - '@scure/bip32@1.7.0': - resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} - - '@scure/bip39@1.3.0': - resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} - - '@scure/bip39@1.5.4': - resolution: {integrity: sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==} - - '@scure/bip39@1.6.0': - resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} - - '@selderee/plugin-htmlparser2@0.11.0': - resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} - - '@sindresorhus/is@4.6.0': - resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} - engines: {node: '>=10'} - - '@smithy/is-array-buffer@2.2.0': - resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} - engines: {node: '>=14.0.0'} - - '@smithy/types@4.3.2': - resolution: {integrity: sha512-QO4zghLxiQ5W9UZmX2Lo0nta2PuE1sSrXUYDoaB6HMR762C0P7v/HEPHf6ZdglTVssJG1bsrSBxdc3quvDSihw==} - engines: {node: '>=18.0.0'} - - '@smithy/util-buffer-from@2.2.0': - resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} - engines: {node: '>=14.0.0'} - - '@smithy/util-utf8@2.3.0': - resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} - engines: {node: '>=14.0.0'} - - '@socket.io/component-emitter@3.1.2': - resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - - '@solana-program/compute-budget@0.11.0': - resolution: {integrity: sha512-7f1ePqB/eURkTwTOO9TNIdUXZcyrZoX3Uy2hNo7cXMfNhPFWp9AVgIyRNBc2jf15sdUa9gNpW+PfP2iV8AYAaw==} - peerDependencies: - '@solana/kit': ^5.0 - - '@solana-program/compute-budget@0.8.0': - resolution: {integrity: sha512-qPKxdxaEsFxebZ4K5RPuy7VQIm/tfJLa1+Nlt3KNA8EYQkz9Xm8htdoEaXVrer9kpgzzp9R3I3Bh6omwCM06tQ==} - peerDependencies: - '@solana/kit': ^2.1.0 - - '@solana-program/system@0.8.1': - resolution: {integrity: sha512-71U9Mzdpw8HQtfgfJSL5xKZbLMRnza2Llsfk7gGnmg2waqK+o8MMH4YNma8xXS1UmOBptXIiNvoZ3p7cmOVktg==} - peerDependencies: - '@solana/kit': ^3.0 - - '@solana-program/token-2022@0.4.2': - resolution: {integrity: sha512-zIpR5t4s9qEU3hZKupzIBxJ6nUV5/UVyIT400tu9vT1HMs5JHxaTTsb5GUhYjiiTvNwU0MQavbwc4Dl29L0Xvw==} - peerDependencies: - '@solana/kit': ^2.1.0 - '@solana/sysvars': ^2.1.0 - - '@solana-program/token-2022@0.6.1': - resolution: {integrity: sha512-Ex02cruDMGfBMvZZCrggVR45vdQQSI/unHVpt/7HPt/IwFYB4eTlXtO8otYZyqV/ce5GqZ8S6uwyRf0zy6fdbA==} - peerDependencies: - '@solana/kit': ^5.0 - '@solana/sysvars': ^5.0 - - '@solana-program/token@0.5.1': - resolution: {integrity: sha512-bJvynW5q9SFuVOZ5vqGVkmaPGA0MCC+m9jgJj1nk5m20I389/ms69ASnhWGoOPNcie7S9OwBX0gTj2fiyWpfag==} - peerDependencies: - '@solana/kit': ^2.1.0 - - '@solana-program/token@0.6.0': - resolution: {integrity: sha512-omkZh4Tt9rre4wzWHNOhOEHyenXQku3xyc/UrKvShexA/Qlhza67q7uRwmwEDUs4QqoDBidSZPooOmepnA/jig==} - peerDependencies: - '@solana/kit': ^3.0 - - '@solana-program/token@0.9.0': - resolution: {integrity: sha512-vnZxndd4ED4Fc56sw93cWZ2djEeeOFxtaPS8SPf5+a+JZjKA/EnKqzbE1y04FuMhIVrLERQ8uR8H2h72eZzlsA==} - peerDependencies: - '@solana/kit': ^5.0 - - '@solana/accounts@2.3.0': - resolution: {integrity: sha512-QgQTj404Z6PXNOyzaOpSzjgMOuGwG8vC66jSDB+3zHaRcEPRVRd2sVSrd1U6sHtnV3aiaS6YyDuPQMheg4K2jw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/accounts@3.0.3': - resolution: {integrity: sha512-KqlePrlZaHXfu8YQTCxN204ZuVm9o68CCcUr6l27MG2cuRUtEM1Ta0iR8JFkRUAEfZJC4Cu0ZDjK/v49loXjZQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/accounts@5.0.0': - resolution: {integrity: sha512-0JzBdEobgp8NBdhhu+GgwNDh7e8KkHDsSTVZAnNQgvT3taOz0Mwv5E48MuEeDhW6DLFwWVAx/FO3pvibG/NGwA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/accounts@5.1.0': - resolution: {integrity: sha512-Q1KzykCrl/YjLUH2RXF8vPq65U/ehAV2SHZicPbZ0jvgQUU6X1+Eca+0ilxA9xH8srYn3YTVDyEs/LYdfbY/2A==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/accounts@6.1.0': - resolution: {integrity: sha512-0jhmhSSS71ClLtBQIDrLlhkiNER4M9RIXTl1eJ1yJoFlE608JaKHTjNWsdVKdke7uBD6exdjNZkIVmouQPHMcA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - - '@solana/addresses@2.3.0': - resolution: {integrity: sha512-ypTNkY2ZaRFpHLnHAgaW8a83N0/WoqdFvCqf4CQmnMdFsZSdC7qOwcbd7YzdaQn9dy+P2hybewzB+KP7LutxGA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/addresses@3.0.3': - resolution: {integrity: sha512-AuMwKhJI89ANqiuJ/fawcwxNKkSeHH9CApZd2xelQQLS7X8uxAOovpcmEgiObQuiVP944s9ScGUT62Bdul9qYg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/addresses@5.0.0': - resolution: {integrity: sha512-bVk+khc1ZZQHMri25csosM/ikuyPcB/CZidDM/ZMBX0CoJErpHJnmcID5mYOmv4/UHbqo2OANuEaGcFO0Q37sw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/addresses@5.1.0': - resolution: {integrity: sha512-X84qSZLgve9YeYsyxGI49WnfEre53tdFu4x9/4oULBgoj8d0A+P9VGLYzmRJ0YFYKRcZG7U4u3MQpI5uLZ1AsQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/addresses@6.1.0': - resolution: {integrity: sha512-QT04Vie4iICaalQQRJFMGj/P56IxXiwFtVuZHu1qjZUNmuGTOvX6G98b27RaGtLzpJ3NIku/6OtKxLUBqAKAyQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - - '@solana/assertions@2.3.0': - resolution: {integrity: sha512-Ekoet3khNg3XFLN7MIz8W31wPQISpKUGDGTylLptI+JjCDWx3PIa88xjEMqFo02WJ8sBj2NLV64Xg1sBcsHjZQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/assertions@3.0.3': - resolution: {integrity: sha512-2qspxdbWp2y62dfCIlqeWQr4g+hE8FYSSwcaP6itwMwGRb8393yDGCJfI/znuzJh6m/XVWhMHIgFgsBwnevCmg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/assertions@5.0.0': - resolution: {integrity: sha512-2kIykk90kYciQW6bp+KaE6jRd1Y2CgHPeJxxlc5chQnjhoG6eiD8VXvocs6AvqPTht0p/SoEj9jH5tT4oG/bcg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/assertions@5.1.0': - resolution: {integrity: sha512-5But2wyxuvGXMIOnD0jBMQ9yq1QQF2LSK3IbIRSkAkXbD3DS6O2tRvKUHNhogd+BpkPyCGOQHBycezgnxmStlg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/assertions@6.1.0': - resolution: {integrity: sha512-pLgxB2xxTk2QfTaWpnRpSMYgaPkKYDQgptRvbwmuDQnOW1Zopg+42MT2UrDGd3UFMML1uOFPxIwKM6m51H0uXw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - - '@solana/buffer-layout-utils@0.2.0': - resolution: {integrity: sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==} - engines: {node: '>= 10'} - - '@solana/buffer-layout@4.0.1': - resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} - engines: {node: '>=5.10'} - - '@solana/codecs-core@2.0.0-rc.1': - resolution: {integrity: sha512-bauxqMfSs8EHD0JKESaNmNuNvkvHSuN3bbWAF5RjOfDu2PugxHrvRebmYauvSumZ3cTfQ4HJJX6PG5rN852qyQ==} - peerDependencies: - typescript: '>=5' - - '@solana/codecs-core@2.3.0': - resolution: {integrity: sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/codecs-core@3.0.3': - resolution: {integrity: sha512-emKykJ3h1DmnDOY29Uv9eJXP8E/FHzvlUBJ6te+5EbKdFjj7vdlKYPfDxOI6iGdXTY+YC/ELtbNBh6QwF2uEDQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/codecs-core@5.0.0': - resolution: {integrity: sha512-rCG2d8OaamVF2/J//YyCgDqNJpUytVVltw9C8mJtEz5c6Se/LR6BFuG8g4xeJswq/ab4RFk5/HFdgbvNjKgQjA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/codecs-core@5.1.0': - resolution: {integrity: sha512-vDwi03mxWeWCS5Il6BCdNdifYdOoHVz97YOmbWGIt45b77Ivu5NUYeSD2+ccl6fSw8eYQ6QaqqKXMjbSfsXv4g==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/codecs-core@6.1.0': - resolution: {integrity: sha512-5rNnDOOm2GRFMJbd9imYCPNvGOrQ+TZ53NCkFFWbbB7f+L9KkLeuuAsDMFN1lCziJFlymvN785YtDnMeWj2W+g==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true - - '@solana/codecs-data-structures@2.0.0-rc.1': - resolution: {integrity: sha512-rinCv0RrAVJ9rE/rmaibWJQxMwC5lSaORSZuwjopSUE6T0nb/MVg6Z1siNCXhh/HFTOg0l8bNvZHgBcN/yvXog==} - peerDependencies: - typescript: '>=5' - - '@solana/codecs-data-structures@2.3.0': - resolution: {integrity: sha512-qvU5LE5DqEdYMYgELRHv+HMOx73sSoV1ZZkwIrclwUmwTbTaH8QAJURBj0RhQ/zCne7VuLLOZFFGv6jGigWhSw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/codecs-data-structures@3.0.3': - resolution: {integrity: sha512-R15cLp8riJvToXziW8lP6AMSwsztGhEnwgyGmll32Mo0Yjq+hduW2/fJrA/TJs6tA/OgTzMQjlxgk009EqZHCw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - - '@solana/codecs-data-structures@5.0.0': - resolution: {integrity: sha512-y503Pqmv0LHcfcf0vQJGaxDvydQJbyCo8nK3nxn56EhFj5lBQ1NWb3WvTd83epigwuZurW2MhJARrpikfhQglQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' +packages: - '@solana/codecs-data-structures@5.1.0': - resolution: {integrity: sha512-ftAwL/jsurFrk9kFVhkTLdQ8fGZ8I0PcbVH+V1a0dIP2aKDofGePvK0XbwZE/ohizC9gEIZxyBX5IgRKk5PXyg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@adraffy/ens-normalize@1.11.0': + resolution: {integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==} - '@solana/codecs-data-structures@6.1.0': - resolution: {integrity: sha512-1cb9g5hrrucTuGkGxqVVq7dCwSMnn4YqwTe365iKkK8HBpLBmUl8XATf1MUs5UtDun1g9eNWOL72Psr8mIUqTQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@algorandfoundation/algokit-utils@10.0.0-alpha.46': + resolution: {integrity: sha512-Lx56ET6RmrDCFGwx6qyIr7YRX3Q3MyKgqkNeumLkFHXVkqMnXnK1aLeEbV59EOK8UHQ5UPJofSj1zvRMm9Du7w==} + engines: {node: '>=20.0'} - '@solana/codecs-numbers@2.0.0-rc.1': - resolution: {integrity: sha512-J5i5mOkvukXn8E3Z7sGIPxsThRCgSdgTWJDQeZvucQ9PT6Y3HiVXJ0pcWiOWAoQ3RX8e/f4I3IC+wE6pZiJzDQ==} - peerDependencies: - typescript: '>=5' + '@algorandfoundation/xhd-wallet-api@2.0.0-canary.1': + resolution: {integrity: sha512-U6rSWMO6FKDLvMxWtfKyW5ctqSy2NrONWTU/jOA+BX0SGru0GPXsxwzFdcPa5w+X055V/xVVsr8eA3xA+m/5jA==} - '@solana/codecs-numbers@2.3.0': - resolution: {integrity: sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} - '@solana/codecs-numbers@3.0.3': - resolution: {integrity: sha512-pfXkH9J0glrM8qj6389GAn30+cJOxzXLR2FsPOHCUMXrqLhGjMMZAWhsQkpOQ37SGc/7EiQsT/gmyGC7gxHqJQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} - '@solana/codecs-numbers@5.0.0': - resolution: {integrity: sha512-a2+skRLuUK02f/XFe4L0e1+wHCyfK25PkyseFps1v1l4pvevukFwth/EhSyrs6w5CsTJRVoR7MuE3E00PM4egw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@aptos-labs/aptos-cli@1.1.1': + resolution: {integrity: sha512-sB7CokCM6s76SLJmccysbnFR+MDik6udKfj2+9ZsmTLV0/t73veIeCDKbvWJmbW267ibx4HiGbPI7L+1+yjEbQ==} + hasBin: true - '@solana/codecs-numbers@5.1.0': - resolution: {integrity: sha512-Ea5/9yjDNOrDZcI40UGzzi6Aq1JNsmzM4m5pOk6Xb3JRZ0YdKOv/MwuCqb6jRgzZ7SQjHhkfGL43kHLJA++bOw==} - engines: {node: '>=20.18.0'} + '@aptos-labs/aptos-client@2.1.0': + resolution: {integrity: sha512-ttdY0qclRvbYAAwzijkFeipuqTfLFJnoXlNIm58tIw3DKhIlfYdR6iLqTeCpI23oOPghnO99FZecej/0MTrtuA==} + engines: {node: '>=20.0.0'} peerDependencies: - typescript: '>=5.3.3' + got: ^11.8.6 - '@solana/codecs-numbers@6.1.0': - resolution: {integrity: sha512-YPQwwl6LE3igH23ah+d8kgpyE5xFcPbuwhxCDsLWqY/ESrvO/0YQSbsgIXahbhZxN59ZC4uq1LnHhBNbpCSVQg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@aptos-labs/ts-sdk@5.2.1': + resolution: {integrity: sha512-kazYjqfsPCBx2UJI+nYUOb6Ov7q7brSgYEfxp2sP27IeJWdDNa50lfs0WIpDJ92kQxdtlm9q3ZWw7Toh9f1gxQ==} + engines: {node: '>=20.0.0'} - '@solana/codecs-strings@2.0.0-rc.1': - resolution: {integrity: sha512-9/wPhw8TbGRTt6mHC4Zz1RqOnuPTqq1Nb4EyuvpZ39GW6O2t2Q7Q0XxiB3+BdoEjwA2XgPw6e2iRfvYgqty44g==} - peerDependencies: - fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5' + '@asamuzakjp/css-color@3.2.0': + resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} - '@solana/codecs-strings@2.3.0': - resolution: {integrity: sha512-y5pSBYwzVziXu521hh+VxqUtp0hYGTl1eWGoc1W+8mdvBdC1kTqm/X7aYQw33J42hw03JjryvYOvmGgk3Qz/Ug==} - engines: {node: '>=20.18.0'} - peerDependencies: - fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5.3.3' + '@aws-cdk/asset-awscli-v1@2.2.273': + resolution: {integrity: sha512-X57HYUtHt9BQrlrzUNcMyRsDUCoakYNnY6qh5lNwRCHPtQoTfXmuISkfLk0AjLkcbS5lw1LLTQFiQhTDXfiTvg==} - '@solana/codecs-strings@3.0.3': - resolution: {integrity: sha512-VHBXnnTVtcQ1j+7Vrz+qSYo38no+jiHRdGnhFspRXEHNJbllzwKqgBE7YN3qoIXH+MKxgJUcwO5KHmdzf8Wn2A==} - engines: {node: '>=20.18.0'} - peerDependencies: - fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5.3.3' + '@aws-cdk/asset-node-proxy-agent-v6@2.1.1': + resolution: {integrity: sha512-We4bmHaowOPHr+IQR4/FyTGjRfjgBj4ICMjtqmJeBDWad3Q/6St12NT07leNtyuukv2qMhtSZJQorD8KpKTwRA==} - '@solana/codecs-strings@5.0.0': - resolution: {integrity: sha512-ALkRwpV8bGR6qjAYw0YXZwp2YI4wzvKOJGmx04Ut8gMdbaUx7qOcJkhEQKI6ZVC3lAWSIS1N1wGccUZDwvfKxw==} - engines: {node: '>=20.18.0'} - peerDependencies: - fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5.3.3' + '@aws-cdk/cloud-assembly-schema@53.20.0': + resolution: {integrity: sha512-4kLAUO+I8b4nlk1Z2P4n3Ye8UtqCiXk0kJMLUThBnyHLbdz06rwAb+qlb9WZOie7NtPluemVS243ifcBh/NVsQ==} + engines: {node: '>= 18.0.0'} + bundledDependencies: + - jsonschema + - semver - '@solana/codecs-strings@5.1.0': - resolution: {integrity: sha512-014xwl5T/3VnGW0gceizF47DUs5EURRtgGmbWIR5+Z32yxgQ6hT9Zl0atZbL268RHbUQ03/J8Ush1StQgy7sfQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: '>=5.3.3' - peerDependenciesMeta: - fastestsmallesttextencoderdecoder: - optional: true + '@babel/code-frame@7.27.1': + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + engines: {node: '>=6.9.0'} - '@solana/codecs-strings@6.1.0': - resolution: {integrity: sha512-pRH5uAn4VCFUs2rYiDITyWsRnpvs3Uh/nhSc6OSP/kusghcCcCJcUzHBIjT4x08MVacXmGUlSLe/9qPQO+QK3Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - fastestsmallesttextencoderdecoder: ^1.0.22 - typescript: ^5.0.0 - peerDependenciesMeta: - fastestsmallesttextencoderdecoder: - optional: true - typescript: - optional: true + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} - '@solana/codecs@2.0.0-rc.1': - resolution: {integrity: sha512-qxoR7VybNJixV51L0G1RD2boZTcxmwUWnKCaJJExQ5qNKwbpSyDdWfFJfM5JhGyKe9DnPVOZB+JHWXnpbZBqrQ==} - peerDependencies: - typescript: '>=5' + '@babel/compat-data@7.28.0': + resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} + engines: {node: '>=6.9.0'} - '@solana/codecs@2.3.0': - resolution: {integrity: sha512-JVqGPkzoeyU262hJGdH64kNLH0M+Oew2CIPOa/9tR3++q2pEd4jU2Rxdfye9sd0Ce3XJrR5AIa8ZfbyQXzjh+g==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/core@7.28.3': + resolution: {integrity: sha512-yDBHV9kQNcr2/sUr9jghVyz9C3Y5G2zUM2H2lo+9mKv4sFgbA8s8Z9t8D1jiTkGoO/NoIfKMyKWr4s6CN23ZwQ==} + engines: {node: '>=6.9.0'} - '@solana/codecs@3.0.3': - resolution: {integrity: sha512-GOHwTlIQsCoJx9Ryr6cEf0FHKAQ7pY4aO4xgncAftrv0lveTQ1rPP2inQ1QT0gJllsIa8nwbfXAADs9nNJxQDA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/generator@7.28.3': + resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} + engines: {node: '>=6.9.0'} - '@solana/codecs@5.0.0': - resolution: {integrity: sha512-KOw0gFUSBxIMDWLJ3AkVFkEci91dw0Rpx3C6y83Our7fSW+SEP8vRZklCElieYR85LHVB1QIEhoeHR7rc+Ifkw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} - '@solana/codecs@5.1.0': - resolution: {integrity: sha512-krSuf/E2Sa/4oASZ/jb/5KGUG58m1/bQdLrKvBnoAFhYj7zZf+8V4UqHGTV5n2NCQfmMyORsg9n2saKjkUzo8w==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/helper-compilation-targets@7.27.2': + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + engines: {node: '>=6.9.0'} - '@solana/codecs@6.1.0': - resolution: {integrity: sha512-VHBS3t8fyVjE0Nqo6b4TUnzdwdRaVo+B5ufHhPLbbjkEXzz8HB4E/OBjgasn+zWGlfScfQAiBFOsfZjbVWu4XA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@babel/helper-globals@7.28.0': + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} - '@solana/errors@2.0.0-rc.1': - resolution: {integrity: sha512-ejNvQ2oJ7+bcFAYWj225lyRkHnixuAeb7RQCixm+5mH4n1IA4Qya/9Bmfy5RAAHQzxK43clu3kZmL5eF9VGtYQ==} - hasBin: true - peerDependencies: - typescript: '>=5' + '@babel/helper-module-imports@7.27.1': + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + engines: {node: '>=6.9.0'} - '@solana/errors@2.3.0': - resolution: {integrity: sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==} - engines: {node: '>=20.18.0'} - hasBin: true + '@babel/helper-module-transforms@7.28.3': + resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + engines: {node: '>=6.9.0'} peerDependencies: - typescript: '>=5.3.3' + '@babel/core': ^7.0.0 - '@solana/errors@3.0.3': - resolution: {integrity: sha512-1l84xJlHNva6io62PcYfUamwWlc0eM95nHgCrKX0g0cLoC6D6QHYPCEbEVkR+C5UtP9JDgyQM8MFiv+Ei5tO9Q==} - engines: {node: '>=20.18.0'} - hasBin: true - peerDependencies: - typescript: '>=5.3.3' + '@babel/helper-string-parser@7.27.1': + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + engines: {node: '>=6.9.0'} - '@solana/errors@5.0.0': - resolution: {integrity: sha512-gTuhzO6E+ydfAAzqmqdPcvFyJwAzFKKIrqtnZPpgAuomcPYu+HSo0tuwSM/cTX0djmHt+GoOsf/julph+nvs2w==} - engines: {node: '>=20.18.0'} - hasBin: true - peerDependencies: - typescript: '>=5.3.3' + '@babel/helper-validator-identifier@7.27.1': + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} + engines: {node: '>=6.9.0'} - '@solana/errors@5.1.0': - resolution: {integrity: sha512-JlTyekErWa6Fdcwu1Hrh+jZxjM4YxyorGCFDRVZlmHZFkp5N00DWKcYnSGZrTF8E6ZZEP9pfS2XwM8y7p7HPww==} - engines: {node: '>=20.18.0'} - hasBin: true - peerDependencies: - typescript: '>=5.3.3' + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} - '@solana/errors@6.1.0': - resolution: {integrity: sha512-cqSwcw3Rmn85UR7PyF5nKPdlQsRYBkx7YGRvFaJ6Sal1PM+bfolhL5iT7STQoXxdhXGYwHMPg7kZYxmMdjwnJA==} - engines: {node: '>=20.18.0'} - hasBin: true - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@babel/helper-validator-option@7.27.1': + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + engines: {node: '>=6.9.0'} - '@solana/fast-stable-stringify@2.3.0': - resolution: {integrity: sha512-KfJPrMEieUg6D3hfQACoPy0ukrAV8Kio883llt/8chPEG3FVTX9z/Zuf4O01a15xZmBbmQ7toil2Dp0sxMJSxw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/helpers@7.28.3': + resolution: {integrity: sha512-PTNtvUQihsAsDHMOP5pfobP8C6CM4JWXmP8DrEIt46c3r2bf87Ua1zoqevsMo9g+tWDwgWrFP5EIxuBx5RudAw==} + engines: {node: '>=6.9.0'} - '@solana/fast-stable-stringify@3.0.3': - resolution: {integrity: sha512-ED0pxB6lSEYvg+vOd5hcuQrgzEDnOrURFgp1ZOY+lQhJkQU6xo+P829NcJZQVP1rdU2/YQPAKJKEseyfe9VMIw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/parser@7.28.3': + resolution: {integrity: sha512-7+Ey1mAgYqFAx2h0RuoxcQT5+MlG3GTV0TQrgr7/ZliKsm/MNDxVVutlWaziMq7wJNAz8MTqz55XLpWvva6StA==} + engines: {node: '>=6.0.0'} + hasBin: true - '@solana/fast-stable-stringify@5.0.0': - resolution: {integrity: sha512-sGTbu7a4/olL+8EIOOJ7IZjzqOOpCJcK1UaVJ6015sRgo9vwGf4jg9KtXEYv5LVhLCTYmAb50L4BaIUcBph/Ig==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true - '@solana/fast-stable-stringify@5.1.0': - resolution: {integrity: sha512-ACZo7cH/5EXsBmruw/0gU2/PXL2l4aET0YpL93H6QEaZwEAICFD8cLkj20nBcfLTf4srEiuKtwuSDeONTWIulw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/runtime@7.28.3': + resolution: {integrity: sha512-9uIQ10o0WGdpP6GDhXcdOJPJuDgFtIDtN/9+ArJQ2NAfAmiuhTQdzkaTGR33v43GYS2UrSA0eX2pPPHoFVvpxA==} + engines: {node: '>=6.9.0'} - '@solana/fast-stable-stringify@6.1.0': - resolution: {integrity: sha512-QXUfDFaJCFeARsxJgScWmJ153Tit7Cimk9y0UWWreNBr2Aphi67Nlcj/tr7UABTO0Qaw/0gwrK76zz3m1t3nIw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@babel/template@7.27.2': + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + engines: {node: '>=6.9.0'} - '@solana/functional@2.3.0': - resolution: {integrity: sha512-AgsPh3W3tE+nK3eEw/W9qiSfTGwLYEvl0rWaxHht/lRcuDVwfKRzeSa5G79eioWFFqr+pTtoCr3D3OLkwKz02Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} - '@solana/functional@3.0.3': - resolution: {integrity: sha512-2qX1kKANn8995vOOh5S9AmF4ItGZcfbny0w28Eqy8AFh+GMnSDN4gqpmV2LvxBI9HibXZptGH3RVOMk82h1Mpw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/traverse@7.28.3': + resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} + engines: {node: '>=6.9.0'} - '@solana/functional@5.0.0': - resolution: {integrity: sha512-UNBrpfzBL4dKD2iucjNnrkFbnjz5ZYDu2OvrIBAcCSQsxxgHMamUj1n3EDe6kl1us49YG1r05Ho8QLqNrbkVbw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} - '@solana/functional@5.1.0': - resolution: {integrity: sha512-R6jacWU0Gr+j49lTDp+FSECBolqw2Gq7JlC22rI0JkcxJiiAlp3G80v6zAYq0FkHzxZbjyR6//JYUXSwliem5g==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@babel/types@7.28.2': + resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} + engines: {node: '>=6.9.0'} - '@solana/functional@6.1.0': - resolution: {integrity: sha512-+Sm8ldVxSTHIKaZDvcBu81FPjknXx6OMPlakkKmXjKxPgVLl86ruqMo2yEwoDUHV7DysLrLLcRNn13rfulomRw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} - '@solana/instruction-plans@3.0.3': - resolution: {integrity: sha512-eqoaPtWtmLTTpdvbt4BZF5H6FIlJtXi9H7qLOM1dLYonkOX2Ncezx5NDCZ9tMb2qxVMF4IocYsQnNSnMfjQF1w==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@base-org/account@1.1.1': + resolution: {integrity: sha512-IfVJPrDPhHfqXRDb89472hXkpvJuQQR7FDI9isLPHEqSYt/45whIoBxSPgZ0ssTt379VhQo4+87PWI1DoLSfAQ==} - '@solana/instruction-plans@5.0.0': - resolution: {integrity: sha512-n9oFOMFUPYKEhsXzrXT97QBQ2WvOTar+5SFEj/IOtRuCn4gl2kh0369cjXZpFwUdE3tmKr1zfYFNwbtiNx5pvg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@base-org/account@2.4.0': + resolution: {integrity: sha512-A4Umpi8B9/pqR78D1Yoze4xHyQaujioVRqqO3d6xuDFw9VRtjg6tK3bPlwE0aW+nVH/ntllCpPa2PbI8Rnjcug==} - '@solana/instruction-plans@5.1.0': - resolution: {integrity: sha512-friMgHt0z5jQlCyyTDXfwAMYjCAagI7QYR+hLWB/BmvSuRpai0ddToWbWJoqrNRM312xZ+Oy/qjC3+Ftzi0DLA==} - engines: {node: '>=20.18.0'} + '@blockshake/defly-connect@1.2.1': + resolution: {integrity: sha512-T9wAjPTFdc8iRiDzTqmeBRCIroWLgXmqZHwnpzuchjYZXXqbnj+zge+HS7UaNunpxGVjDUNK1ah7OR6hEqtJoQ==} peerDependencies: - typescript: '>=5.3.3' + algosdk: ^3.0.0 - '@solana/instruction-plans@6.1.0': - resolution: {integrity: sha512-zcsHg544t1zn7LLOVUxOWYlsKn9gvT7R+pL3cTiP2wFNoUN0h9En87H6nVqkZ8LWw23asgW0uM5uJGwfBx2h1Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@coinbase/cdp-sdk@1.39.0': + resolution: {integrity: sha512-3RbeIGVHBlDUxRKSLSnrvpsxo7W4IIqaOHyCscX1rPL/iprL0Nh6AaL/JogC4OkHwquu7SkKWjjNDb+a5wG8gw==} - '@solana/instructions@2.3.0': - resolution: {integrity: sha512-PLMsmaIKu7hEAzyElrk2T7JJx4D+9eRwebhFZpy2PXziNSmFF929eRHKUsKqBFM3cYR1Yy3m6roBZfA+bGE/oQ==} - engines: {node: '>=20.18.0'} + '@coinbase/onchainkit@1.1.2': + resolution: {integrity: sha512-QBH+u7wRYDBax/SNvXGPuLIJ0tAqq85tksUDervGrLRaghEUBZstmg6Qwqw1xMMsW1GNPyk8Wm0xxFqMUh26vg==} peerDependencies: - typescript: '>=5.3.3' + react: ^19 + react-dom: ^19 + viem: ^2.27 + wagmi: ^2.16 - '@solana/instructions@3.0.3': - resolution: {integrity: sha512-4csIi8YUDb5j/J+gDzmYtOvq7ZWLbCxj4t0xKn+fPrBk/FD2pK29KVT3Fu7j4Lh1/ojunQUP9X4NHwUexY3PnA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@coinbase/wallet-sdk@3.9.3': + resolution: {integrity: sha512-N/A2DRIf0Y3PHc1XAMvbBUu4zisna6qAdqABMZwBMNEfWrXpAwx16pZGkYCLGE+Rvv1edbcB2LYDRnACNcmCiw==} - '@solana/instructions@5.0.0': - resolution: {integrity: sha512-12dbrmwERT1o6NTr/Uvrjj/ZsiteSXoT5Gi+dnjIeRNHWg9H+gEFuFzJvTDVKlNg34CZ71xdvbVdbV0V8gKGvg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@coinbase/wallet-sdk@4.3.6': + resolution: {integrity: sha512-4q8BNG1ViL4mSAAvPAtpwlOs1gpC+67eQtgIwNvT3xyeyFFd+guwkc8bcX5rTmQhXpqnhzC4f0obACbP9CqMSA==} - '@solana/instructions@5.1.0': - resolution: {integrity: sha512-fkwpUwwqk5K14T/kZDnCrfeR0kww49HBx+BK8xdSeJx+bt4QTwAHa9YeOkGhGrHEFVEJEUf8FKoxxTzZzJZtKQ==} - engines: {node: '>=20.18.0'} + '@craftamap/esbuild-plugin-html@0.9.0': + resolution: {integrity: sha512-V5LFrcGXQWU1SSzYPwxEFjF8IjeXW0oTKh5c0xyhGuTNoEnjgJRNSX83HnZ5TTAutJfo/MAyWA4Z9/fIwbMhUQ==} + engines: {node: '>=18'} peerDependencies: - typescript: '>=5.3.3' + esbuild: '>=0.15.10' - '@solana/instructions@6.1.0': - resolution: {integrity: sha512-w1LdbJ3yanESckNTYC5KPckgN/25FyGCm07WWrs+dCnnpRNeLiVHIytXCPmArOVAXVkOYidXzhWmqCzqKUjYaA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@cspotcode/source-map-support@0.8.1': + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} - '@solana/keys@2.3.0': - resolution: {integrity: sha512-ZVVdga79pNH+2pVcm6fr2sWz9HTwfopDVhYb0Lh3dh+WBmJjwkabXEIHey2rUES7NjFa/G7sV8lrUn/v8LDCCQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@csstools/color-helpers@5.0.2': + resolution: {integrity: sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==} + engines: {node: '>=18'} - '@solana/keys@3.0.3': - resolution: {integrity: sha512-tp8oK9tMadtSIc4vF4aXXWkPd4oU5XPW8nf28NgrGDWGt25fUHIydKjkf2hPtMt9i1WfRyQZ33B5P3dnsNqcPQ==} - engines: {node: '>=20.18.0'} + '@csstools/css-calc@2.1.4': + resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} + engines: {node: '>=18'} peerDependencies: - typescript: '>=5.3.3' + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 - '@solana/keys@5.0.0': - resolution: {integrity: sha512-kWkR7NslpTttk5i1BhBNCDtVQDkEtgkdsM3Jp9TGPk0GFjBjBwrQStw3vvwLe8itEIvRFGFZU6JHEk8HLS0WLQ==} - engines: {node: '>=20.18.0'} + '@csstools/css-color-parser@3.0.10': + resolution: {integrity: sha512-TiJ5Ajr6WRd1r8HSiwJvZBiJOqtH86aHpUjq5aEKWHiII2Qfjqd/HCWKPOW8EP4vcspXbHnXrwIDlu5savQipg==} + engines: {node: '>=18'} peerDependencies: - typescript: '>=5.3.3' + '@csstools/css-parser-algorithms': ^3.0.5 + '@csstools/css-tokenizer': ^3.0.4 - '@solana/keys@5.1.0': - resolution: {integrity: sha512-ma4zTTuSOmtTCvATHMfUGNTw0Vqah/6XPe1VmLc66ohwXMI3yqatX1FQPXgDZozr15SvLAesfs7/bgl2TRoe9w==} - engines: {node: '>=20.18.0'} + '@csstools/css-parser-algorithms@3.0.5': + resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} + engines: {node: '>=18'} peerDependencies: - typescript: '>=5.3.3' + '@csstools/css-tokenizer': ^3.0.4 - '@solana/keys@6.1.0': - resolution: {integrity: sha512-C/SGCl3VOgBQZ0mLrMxCcJYnMsGpgE8wbx29jqRY+R91m5YhS1f/GfXJPR1lN/h7QGrJ6YDm8eI0Y3AZ7goKHg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@csstools/css-tokenizer@3.0.4': + resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} + engines: {node: '>=18'} - '@solana/kit@2.3.0': - resolution: {integrity: sha512-sb6PgwoW2LjE5oTFu4lhlS/cGt/NB3YrShEyx7JgWFWysfgLdJnhwWThgwy/4HjNsmtMrQGWVls0yVBHcMvlMQ==} - engines: {node: '>=20.18.0'} + '@ecies/ciphers@0.2.4': + resolution: {integrity: sha512-t+iX+Wf5nRKyNzk8dviW3Ikb/280+aEJAnw9YXvCp2tYGPSkMki+NRY+8aNLmVFv3eNtMdvViPNOPxS8SZNP+w==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} peerDependencies: - typescript: '>=5.3.3' + '@noble/ciphers': ^1.0.0 - '@solana/kit@3.0.3': - resolution: {integrity: sha512-CEEhCDmkvztd1zbgADsEQhmj9GyWOOGeW1hZD+gtwbBSF5YN1uofS/pex5MIh/VIqKRj+A2UnYWI1V+9+q/lyQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@emnapi/core@1.4.5': + resolution: {integrity: sha512-XsLw1dEOpkSX/WucdqUhPWP7hDxSvZiY+fsUC14h+FtQ2Ifni4znbBt8punRX+Uj2JG/uDb8nEHVKvrVlvdZ5Q==} - '@solana/kit@5.0.0': - resolution: {integrity: sha512-3ahtzmmMgU+1l2YMhQJSKKm14IdvCycOE/m4XNMu/4icBIptmBgZxrmgRpPHqBilBa+Krp/hBuTg4HWl9IAgWw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} - '@solana/kit@5.1.0': - resolution: {integrity: sha512-oNQRzI0+mGWmXy05psO0J7r9Boy8PF7LH5H0Y9Jxvs10AbG4oSOBtyj20EccsRrr+jkqLw42fqb/4rNuASfvsA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@emnapi/wasi-threads@1.0.4': + resolution: {integrity: sha512-PJR+bOmMOPH8AtcTGAyYNiuJ3/Fcoj2XN/gBEWzDIKh254XO+mM9XoXHk5GNEhodxeMznbg7BlRojVbKN+gC6g==} - '@solana/kit@6.1.0': - resolution: {integrity: sha512-24exn11BPonquufyCkGgypVtmN4JOsdGMsbF3EZ4kFyk7ZNryCn/N8eELr1FCVrHWRXoc0xy/HFaESBULTMf6g==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@es-joy/jsdoccomment@0.50.2': + resolution: {integrity: sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==} + engines: {node: '>=18'} - '@solana/nominal-types@2.3.0': - resolution: {integrity: sha512-uKlMnlP4PWW5UTXlhKM8lcgIaNj8dvd8xO4Y9l+FVvh9RvW2TO0GwUO6JCo7JBzCB0PSqRJdWWaQ8pu1Ti/OkA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/aix-ppc64@0.25.9': + resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] - '@solana/nominal-types@3.0.3': - resolution: {integrity: sha512-aZavCiexeUAoMHRQg4s1AHkH3wscbOb70diyfjhwZVgFz1uUsFez7csPp9tNFkNolnadVb2gky7yBk3IImQJ6A==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] - '@solana/nominal-types@5.0.0': - resolution: {integrity: sha512-Qn7xH4UG2rDAv+wAyheP4jWvX3oQmbZ/woxFZwug7PaRLvyjUswGr38Hil+SjiQyFDo+un1UqWM9N9yusUeeZQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/android-arm64@0.25.9': + resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] - '@solana/nominal-types@5.1.0': - resolution: {integrity: sha512-+4Cm+SpK+D811i9giqv4Up93ZlmUcZfLDHkSH24F4in61+Y2TKA+XKuRtKhNytQMmqCfbvJZ9MHFaIeZw5g+Bg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] - '@solana/nominal-types@6.1.0': - resolution: {integrity: sha512-+skHjN0arNNB9TLsGqA94VCx7euyGURI+qG6wck6E4D7hH6i6DxGiVrtKRghx+smJkkLtTm9BvdVKGoeNQYr7Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/android-arm@0.25.9': + resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] - '@solana/offchain-messages@5.1.0': - resolution: {integrity: sha512-6FUXjiIJprjWa7y/T4E3rUb3HKi3P5zpBweBEwDflEEJ/QlieWUw7xlGAOvZ1eF3Wi+6LfcrdtZOwIkuv6o9Sg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] - '@solana/offchain-messages@6.1.0': - resolution: {integrity: sha512-jrUb7HGUnRA+k44upcqKeevtEdqMxYRSlFdE0JTctZunGlP3GCcTl12tFOpbnFHvBLt8RwS62+nyeES8zzNwXA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/android-x64@0.25.9': + resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] - '@solana/options@2.0.0-rc.1': - resolution: {integrity: sha512-mLUcR9mZ3qfHlmMnREdIFPf9dpMc/Bl66tLSOOWxw4ml5xMT2ohFn7WGqoKcu/UHkT9CrC6+amEdqCNvUqI7AA==} - peerDependencies: - typescript: '>=5' + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] - '@solana/options@2.3.0': - resolution: {integrity: sha512-PPnnZBRCWWoZQ11exPxf//DRzN2C6AoFsDI/u2AsQfYih434/7Kp4XLpfOMT/XESi+gdBMFNNfbES5zg3wAIkw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/darwin-arm64@0.25.9': + resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] - '@solana/options@3.0.3': - resolution: {integrity: sha512-jarsmnQ63RN0JPC5j9sgUat07NrL9PC71XU7pUItd6LOHtu4+wJMio3l5mT0DHVfkfbFLL6iI6+QmXSVhTNF3g==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] - '@solana/options@5.0.0': - resolution: {integrity: sha512-ezHVBFb9FXVSn8LUVRD2tLb6fejU0x8KtGEYyCYh0J0pQuXSITV0IQCjcEopvu/ZxWdXOJyzjvmymnhz90on5A==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/darwin-x64@0.25.9': + resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] - '@solana/options@5.1.0': - resolution: {integrity: sha512-PqgfALd0yhK+QFaYIbRFTV6hBpiy5xwdu07zSw1RLoNvt1sg+MRsRFDk9R8ZdEdiM69PY/cKiClVSjpNzLLcJg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] - '@solana/options@6.1.0': - resolution: {integrity: sha512-/4FtVfR6nkHkMCumyh7/lJ6jMqyES6tKUbOJRa6gJxcIUWeRDu+XrHTHLf3gRNUqDAbFvW8FMIrQm7PdreZgRA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/freebsd-arm64@0.25.9': + resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] - '@solana/plugin-core@6.1.0': - resolution: {integrity: sha512-2nmNCPa6B1QArqpAZHWUkK6K7UXLTrekfcfJm2V//ATEtLpKEBlv0c3mrhOYwNAKP2TpNuvEV33InXWKst9oXQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] - '@solana/plugin-interfaces@6.1.0': - resolution: {integrity: sha512-eWSzfOuwtHUp8vljf5V24Tkz3WxqxiV0vD/BJZBNRZMdYRw3Cw3oeWcvEqHHxGUOie6AjIK8GrKggi8F73ZXbg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/freebsd-x64@0.25.9': + resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] - '@solana/program-client-core@6.1.0': - resolution: {integrity: sha512-5Apka+ulWNfLNLYNR63pLnr5XvkXTQWeaftWED93iTWTZrZv9SyFWcmIsaes6eqGXMQ3RhlebnrWODtKuAA62g==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] - '@solana/programs@2.3.0': - resolution: {integrity: sha512-UXKujV71VCI5uPs+cFdwxybtHZAIZyQkqDiDnmK+DawtOO9mBn4Nimdb/6RjR2CXT78mzO9ZCZ3qfyX+ydcB7w==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-arm64@0.25.9': + resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] - '@solana/programs@3.0.3': - resolution: {integrity: sha512-JZlVE3/AeSNDuH3aEzCZoDu8GTXkMpGXxf93zXLzbxfxhiQ/kHrReN4XE/JWZ/uGWbaFZGR5B3UtdN2QsoZL7w==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] - '@solana/programs@5.0.0': - resolution: {integrity: sha512-BKOfBDrSUCJGZ+qKk2aFLu0nU9/84o6z/VDCJkLjaNNuTv8nOlSYq5flNzo1eyJmnpyW372qNvqqRN3AS23+FQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-arm@0.25.9': + resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] - '@solana/programs@5.1.0': - resolution: {integrity: sha512-zAghXyRGixWNcarShlrnpjMD2115BZTF9JMLIcgkCYDOwjDPFIB/Y0hwDCH87N5uSjzlgkDpxKEL4ILewoZTRQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] - '@solana/programs@6.1.0': - resolution: {integrity: sha512-i4L4gSlIHDsdYRt3/YKVKMIN3UuYSKHRqK9B+AejcIc0y6Y/AXnHqzmpBRXEhvTXz18nt59MLXpVU4wu7ASjJA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/linux-ia32@0.25.9': + resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] - '@solana/promises@2.3.0': - resolution: {integrity: sha512-GjVgutZKXVuojd9rWy1PuLnfcRfqsaCm7InCiZc8bqmJpoghlyluweNc7ml9Y5yQn1P2IOyzh9+p/77vIyNybQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] - '@solana/promises@3.0.3': - resolution: {integrity: sha512-K+UflGBVxj30XQMHTylHHZJdKH5QG3oj5k2s42GrZ/Wbu72oapVJySMBgpK45+p90t8/LEqV6rRPyTXlet9J+Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-loong64@0.25.9': + resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] - '@solana/promises@5.0.0': - resolution: {integrity: sha512-Qmg3UfYfWINEUvBQL3DkPOq34tTg5cfrkPlDtJmi8RVifsPqb6hksbKZGu7ASLZohxIDGmnYQY6oELI7Me+5yw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] - '@solana/promises@5.1.0': - resolution: {integrity: sha512-LU9wwS1PvGc/It610dclfq+JCuUEZSIWjvaF0+sqMP7QCk12Uz7MK2m9TtvLcjTvvKTIrucglRZP6qKroWRqGg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-mips64el@0.25.9': + resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] - '@solana/promises@6.1.0': - resolution: {integrity: sha512-/mUW6peXQiEOaylLpGv4vtkvPzQvSbfhX9j5PNIK/ry4S3SHRQ3j3W/oGy4y3LR5alwo7NcVbubrkh4e4xwcww==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] - '@solana/rpc-api@2.3.0': - resolution: {integrity: sha512-UUdiRfWoyYhJL9PPvFeJr4aJ554ob2jXcpn4vKmRVn9ire0sCbpQKYx6K8eEKHZWXKrDW8IDspgTl0gT/aJWVg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-ppc64@0.25.9': + resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] - '@solana/rpc-api@3.0.3': - resolution: {integrity: sha512-Yym9/Ama62OY69rAZgbOCAy1QlqaWAyb0VlqFuwSaZV1pkFCCFSwWEJEsiN1n8pb2ZP+RtwNvmYixvWizx9yvA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] - '@solana/rpc-api@5.0.0': - resolution: {integrity: sha512-IJbZZnX2B1ldXPok1NhneXTYq9ZvdJbE5Pryr03pZTlPJaWGqDcZuQ14nwR4s6PoUUgdT+p87QlLZqLb8MusoQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-riscv64@0.25.9': + resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] - '@solana/rpc-api@5.1.0': - resolution: {integrity: sha512-eI1tY0i3gmih1C65gFECYbfPRpHEYqFp+9IKjpknZtYpQIe9BqBKSpfYpGiCAbKdN/TMadBNPOzdK15ewhkkvQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] - '@solana/rpc-api@6.1.0': - resolution: {integrity: sha512-+hO5+kZjJHuUNATUQxlJ1+ztXFkgn1j46zRwt3X7kF+VHkW3wsQ7up0JTS+Xsacmkrj1WKfymQweq8JTrsAG8A==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/linux-s390x@0.25.9': + resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] - '@solana/rpc-parsed-types@2.3.0': - resolution: {integrity: sha512-B5pHzyEIbBJf9KHej+zdr5ZNAdSvu7WLU2lOUPh81KHdHQs6dEb310LGxcpCc7HVE8IEdO20AbckewDiAN6OCg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] - '@solana/rpc-parsed-types@3.0.3': - resolution: {integrity: sha512-/koM05IM2fU91kYDQxXil3VBNlOfcP+gXE0js1sdGz8KonGuLsF61CiKB5xt6u1KEXhRyDdXYLjf63JarL4Ozg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-x64@0.25.9': + resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] - '@solana/rpc-parsed-types@5.0.0': - resolution: {integrity: sha512-fU9uqlOYAaBqgk2qCl+ntenBm7wuSFBRbIO/rVjeBPd/qPCvNZU+qFET+ERLK6wbCTSz0MmdHqPn1V8KCMOvZQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] - '@solana/rpc-parsed-types@5.1.0': - resolution: {integrity: sha512-ZJoXHNItALMNa1zmGrNnIh96RBlc9GpIqoaZkdE14mAQ7gWe7Oc0ejYavUeSCmcL0wZcvIFh50AsfVxrHr4+2Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/netbsd-arm64@0.25.9': + resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] - '@solana/rpc-parsed-types@6.1.0': - resolution: {integrity: sha512-YKccynVgWt/gbs0tBYstNw6BSVuOeWdeAldTB2OgH95o2Q04DpO4v97X1MZDysA4SvSZM30Ek5Ni5ss3kskgdw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] - '@solana/rpc-spec-types@2.3.0': - resolution: {integrity: sha512-xQsb65lahjr8Wc9dMtP7xa0ZmDS8dOE2ncYjlvfyw/h4mpdXTUdrSMi6RtFwX33/rGuztQ7Hwaid5xLNSLvsFQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/netbsd-x64@0.25.9': + resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] - '@solana/rpc-spec-types@3.0.3': - resolution: {integrity: sha512-A6Jt8SRRetnN3CeGAvGJxigA9zYRslGgWcSjueAZGvPX+MesFxEUjSWZCfl+FogVFvwkqfkgQZQbPAGZQFJQ6Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] - '@solana/rpc-spec-types@5.0.0': - resolution: {integrity: sha512-B0P/ylXVaCG5oSIV+kB88s2qoW996D8iKhc7RyF0C/AyYvklF6kCwv0N9ZVrWp0ibjlQ8St290WbBHJyo7QZkA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/openbsd-arm64@0.25.9': + resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] - '@solana/rpc-spec-types@5.1.0': - resolution: {integrity: sha512-B8/WyjmHpC34vXtAmTpZyPwRCm7WwoSkmjBcBouaaY1uilJ9+Wp2nptbq2cJyWairOoMSoI7v5kvvnrJuquq4Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] - '@solana/rpc-spec-types@6.1.0': - resolution: {integrity: sha512-tldMv1b6VGcvcRrY5MDWKlsyEKH6K96zE7gAIpKDX2G4T47ZOV+OMA3nh6xQpRgtyCUBsej0t80qmvTBDX/5IQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/openbsd-x64@0.25.9': + resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] - '@solana/rpc-spec@2.3.0': - resolution: {integrity: sha512-fA2LMX4BMixCrNB2n6T83AvjZ3oUQTu7qyPLyt8gHQaoEAXs8k6GZmu6iYcr+FboQCjUmRPgMaABbcr9j2J9Sw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] - '@solana/rpc-spec@3.0.3': - resolution: {integrity: sha512-MZn5/8BebB6MQ4Gstw6zyfWsFAZYAyLzMK+AUf/rSfT8tPmWiJ/mcxnxqOXvFup/l6D67U8pyGpIoFqwCeZqqA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/openharmony-arm64@0.25.9': + resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] - '@solana/rpc-spec@5.0.0': - resolution: {integrity: sha512-1LD2SYEQ5bYhiBumznAPzymtxSX4nYLZd6u+FA0bAxNBVzHDvUUQzVSXHAoWROhlGrCyvtALTs9u0DIDlgZHCA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] - '@solana/rpc-spec@5.1.0': - resolution: {integrity: sha512-y8B6fUWA1EBKXUsNo6b9EiFcQPsaJREPLlcIDbo4b6TucQNwvl7FHfpf1VHJL64SkI/WE69i2WEkiOJYjmLO0A==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/sunos-x64@0.25.9': + resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] - '@solana/rpc-spec@6.1.0': - resolution: {integrity: sha512-RxpkIGizCYhXGUcap7npV2S/rAXZ7P/liozY/ExjMmCxYTDwGIW33kp/uH/JRxuzrL8+f8FqY76VsqqIe+2VZw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] - '@solana/rpc-subscriptions-api@2.3.0': - resolution: {integrity: sha512-9mCjVbum2Hg9KGX3LKsrI5Xs0KX390lS+Z8qB80bxhar6MJPugqIPH8uRgLhCW9GN3JprAfjRNl7our8CPvsPQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/win32-arm64@0.25.9': + resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] - '@solana/rpc-subscriptions-api@3.0.3': - resolution: {integrity: sha512-MGgVK3PUS15qsjuhimpzGZrKD/CTTvS0mAlQ0Jw84zsr1RJVdQJK/F0igu07BVd172eTZL8d90NoAQ3dahW5pA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] - '@solana/rpc-subscriptions-api@5.0.0': - resolution: {integrity: sha512-DGUn3C12swV2FConOlLFN14npIrCtnxehtMLjszMC7g6p/P6WNIz5uAgF7YcIkLBDV8uTeWhM0azmK+V8Qqhvg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/win32-ia32@0.25.9': + resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] - '@solana/rpc-subscriptions-api@5.1.0': - resolution: {integrity: sha512-84e2AsgqAGiVloW3G4RzpHPkInknu3rEuFPut2/69eq3Ab97TiTz2s5kc9gJpprtGM+xbgnIfeuGqr5F+2bXQA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] - '@solana/rpc-subscriptions-api@6.1.0': - resolution: {integrity: sha512-I6J+3VU0dda6EySKbDyd+1urC7RGIRPRp0DcWRVcy68NOLbq0I5C40Dn9O2Zf8iCdK4PbQ7JKdCvZ/bDd45hdg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@esbuild/win32-x64@0.25.9': + resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] - '@solana/rpc-subscriptions-channel-websocket@2.3.0': - resolution: {integrity: sha512-2oL6ceFwejIgeWzbNiUHI2tZZnaOxNTSerszcin7wYQwijxtpVgUHiuItM/Y70DQmH9sKhmikQp+dqeGalaJxw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - ws: ^8.18.0 + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] - '@solana/rpc-subscriptions-channel-websocket@3.0.3': - resolution: {integrity: sha512-zUzUlb8Cwnw+SHlsLrSqyBRtOJKGc+FvSNJo/vWAkLShoV0wUDMPv7VvhTngJx3B/3ANfrOZ4i08i9QfYPAvpQ==} - engines: {node: '>=20.18.0'} + '@eslint-community/eslint-utils@4.7.0': + resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - typescript: '>=5.3.3' - ws: ^8.18.0 + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - '@solana/rpc-subscriptions-channel-websocket@5.0.0': - resolution: {integrity: sha512-vsYXyjVX/kExfpr91zfMKTmWKKFCM+dkhXQDAz5aEE7kAF3KSZDiOGeYvN8Rc85lbIt9QK6BLAT+NBMv4/N9Qg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - ws: ^8.18.0 + '@eslint-community/regexpp@4.12.1': + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@solana/rpc-subscriptions-channel-websocket@5.1.0': - resolution: {integrity: sha512-FzAEmHzXtlckNn7T/1dzDS7r5HmekYPstrtZKjDcVxuGMVBUkZTnb69t7EJvKNuKw1wYZEUd0EEegtC2K/9dZA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' - ws: ^8.18.0 - peerDependenciesMeta: - ws: - optional: true + '@eslint/config-array@0.21.0': + resolution: {integrity: sha512-ENIdc4iLu0d93HeYirvKmrzshzofPw6VkZRKQGe9Nv46ZnWUzcF1xV01dcvEg/1wXUR61OmmlSfyeyO7EvjLxQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@solana/rpc-subscriptions-channel-websocket@6.1.0': - resolution: {integrity: sha512-vsx9b+uyCr9L3giao/BTiBFA8DxV5+gDNFq0t5uL21uQ17JXzBektwzHuHoth9IjkvXV/h+IhwXfuLE9Qm4GQg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@eslint/config-helpers@0.3.1': + resolution: {integrity: sha512-xR93k9WhrDYpXHORXpxVL5oHj3Era7wo6k/Wd8/IsQNnZUTzkGS29lyn3nAT05v6ltUuTFVCCYDEGfy2Or/sPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.15.2': + resolution: {integrity: sha512-78Md3/Rrxh83gCxoUc0EiciuOHsIITzLy53m3d9UyiW8y9Dj2D29FeETqyKA+BRK76tnTp6RXWb3pCay8Oyomg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@solana/rpc-subscriptions-spec@2.3.0': - resolution: {integrity: sha512-rdmVcl4PvNKQeA2l8DorIeALCgJEMSu7U8AXJS1PICeb2lQuMeaR+6cs/iowjvIB0lMVjYN2sFf6Q3dJPu6wWg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@eslint/eslintrc@3.3.1': + resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@solana/rpc-subscriptions-spec@3.0.3': - resolution: {integrity: sha512-9KpQ32OBJWS85mn6q3gkM0AjQe1LKYlMU7gpJRrla/lvXxNLhI95tz5K6StctpUreVmRWTVkNamHE69uUQyY8A==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@eslint/js@9.33.0': + resolution: {integrity: sha512-5K1/mKhWaMfreBGJTwval43JJmkip0RmM+3+IuqupeSKNC/Th2Kc7ucaq5ovTSra/OOKB9c58CGSz3QMVbWt0A==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@solana/rpc-subscriptions-spec@5.0.0': - resolution: {integrity: sha512-erRLvZMncwnciJP6I1SlAk0CyRGIgt83PyHWOVCRXENP9Q5dZbZ9pm4lar2yIp8EjIMnodGHsQWIlKc1hlCQlQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@eslint/object-schema@2.1.6': + resolution: {integrity: sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@solana/rpc-subscriptions-spec@5.1.0': - resolution: {integrity: sha512-ORfjKtainnYisql6z4YsXByVwY8/rWsedVWn5oe/V7Og9LyetTM7hwJ8FbUdRDZwyLlUrI0cEE1aG+3ma/8tPw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@eslint/plugin-kit@0.3.5': + resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@solana/rpc-subscriptions-spec@6.1.0': - resolution: {integrity: sha512-P06jhqzHpZGaLeJmIQkpDeMDD1xUp53ARpmXMsduMC+U5ZKQt29CLo+JrR18boNtls6WfttjVMEbzF25/4UPVA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@ethereumjs/common@3.2.0': + resolution: {integrity: sha512-pksvzI0VyLgmuEF2FA/JR/4/y6hcPq8OUail3/AvycBaW1d5VSauOZzqGvJ3RTmR4MU35lWE8KseKOsEhrFRBA==} - '@solana/rpc-subscriptions@2.3.0': - resolution: {integrity: sha512-Uyr10nZKGVzvCOqwCZgwYrzuoDyUdwtgQRefh13pXIrdo4wYjVmoLykH49Omt6abwStB0a4UL5gX9V4mFdDJZg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethereumjs/rlp@4.0.1': + resolution: {integrity: sha512-tqsQiBQDQdmPWE1xkkBq4rlSW5QZpLOUJ5RJh2/9fug+q9tnUhuZoVLk7s0scUIKTOzEtR72DFBXI4WiZcMpvw==} + engines: {node: '>=14'} + hasBin: true - '@solana/rpc-subscriptions@3.0.3': - resolution: {integrity: sha512-LRvz6NaqvtsYFd32KwZ+rwYQ9XCs+DWjV8BvBLsJpt9/NWSuHf/7Sy/vvP6qtKxut692H/TMvHnC4iulg0WmiQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethereumjs/tx@4.2.0': + resolution: {integrity: sha512-1nc6VO4jtFd172BbSnTnDQVr9IYBFl1y4xPzZdtkrkKIncBCkdbgfdRV+MiTkJYAtTxvV12GRZLqBFT1PNK6Yw==} + engines: {node: '>=14'} - '@solana/rpc-subscriptions@5.0.0': - resolution: {integrity: sha512-cziOSzom/bwFZXViR9J+MxDsdLMcfvrXGw5Icng7dYODFKuVqfsDrQoG8uekJc4fREnbPEM2U+u9YnYSYbFbww==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethereumjs/util@8.1.0': + resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} + engines: {node: '>=14'} - '@solana/rpc-subscriptions@5.1.0': - resolution: {integrity: sha512-u/mafVzBbdqvYDD7x/98T5/5xk4Bl2C/90TaHiKx7FmutVC/H4QsritPTY0v9JG1dOVWbgIfUgfZ0C0DPkiYnA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/abi@5.8.0': + resolution: {integrity: sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==} - '@solana/rpc-subscriptions@6.1.0': - resolution: {integrity: sha512-sqwj+cQinWcZ7M/9+cudKxMPTkTQyGP73980vPCWM7vCpPkp2qzgrEie4DdgDGo+NMwIjeFgu2kdUuLHI3GD/g==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@ethersproject/abstract-provider@5.8.0': + resolution: {integrity: sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==} - '@solana/rpc-transformers@2.3.0': - resolution: {integrity: sha512-UuHYK3XEpo9nMXdjyGKkPCOr7WsZsxs7zLYDO1A5ELH3P3JoehvrDegYRAGzBS2VKsfApZ86ZpJToP0K3PhmMA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/abstract-signer@5.8.0': + resolution: {integrity: sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==} - '@solana/rpc-transformers@3.0.3': - resolution: {integrity: sha512-lzdaZM/dG3s19Tsk4mkJA5JBoS1eX9DnD7z62gkDwrwJDkDBzkAJT9aLcsYFfTmwTfIp6uU2UPgGYc97i1wezw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/address@5.8.0': + resolution: {integrity: sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==} - '@solana/rpc-transformers@5.0.0': - resolution: {integrity: sha512-EMHhSgfF6/T4FfHbLaBP08SIj1ZAjxJr6WPNZMHLV7Cup8UfiB9TNV+bPQkum7JbVQNhUKzkKEEmyYqPfQoV9w==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/base64@5.8.0': + resolution: {integrity: sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==} - '@solana/rpc-transformers@5.1.0': - resolution: {integrity: sha512-6v93xi/ewGS/xEiSktNQ0bh0Uiv1/q9nR5oiFMn3BiAJRC+FdMRMxCjp6H+/Tua7wdhpClaPKrZYBQHoIp59tw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/bignumber@5.8.0': + resolution: {integrity: sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==} - '@solana/rpc-transformers@6.1.0': - resolution: {integrity: sha512-OsSuuRPmsmS02eR9Zz+4iTsr+21hvEMEex5vwbwN6LAGPFlQ4ohqGkxgZCwmYd+Q5HWpnn9Uuf1MDTLLrKQkig==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@ethersproject/bytes@5.8.0': + resolution: {integrity: sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==} - '@solana/rpc-transport-http@2.3.0': - resolution: {integrity: sha512-HFKydmxGw8nAF5N+S0NLnPBDCe5oMDtI2RAmW8DMqP4U3Zxt2XWhvV1SNkAldT5tF0U1vP+is6fHxyhk4xqEvg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/constants@5.8.0': + resolution: {integrity: sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==} - '@solana/rpc-transport-http@3.0.3': - resolution: {integrity: sha512-bIXFwr2LR5A97Z46dI661MJPbHnPfcShBjFzOS/8Rnr8P4ho3j/9EUtjDrsqoxGJT3SLWj5OlyXAlaDAvVTOUQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/hash@5.8.0': + resolution: {integrity: sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==} - '@solana/rpc-transport-http@5.0.0': - resolution: {integrity: sha512-RoIEvWp7yc7rIRzNkOyjLs2UQF0odIEMWj87dbD4Ir4hwTCGo/TSTfQF/8KDV2etdke3Fa1K+W1NkpG2POqWFg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/keccak256@5.8.0': + resolution: {integrity: sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==} - '@solana/rpc-transport-http@5.1.0': - resolution: {integrity: sha512-XoGX+2n/iXzoGb3Xrltbx8avnzp15vCfCGXuZpQWFL+xUg3P4CGl217XyDGjS5VxuUml+f/30xzWl18RaAIEcw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/logger@5.8.0': + resolution: {integrity: sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==} - '@solana/rpc-transport-http@6.1.0': - resolution: {integrity: sha512-3ebaTYuglLJagaXtjwDPVI7SQeeeFN2fpetpGKsuMAiti4fzYqEkNN8FIo+nXBzqqG/cVc2421xKjXl6sO1k/g==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@ethersproject/networks@5.8.0': + resolution: {integrity: sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==} - '@solana/rpc-types@2.3.0': - resolution: {integrity: sha512-O09YX2hED2QUyGxrMOxQ9GzH1LlEwwZWu69QbL4oYmIf6P5dzEEHcqRY6L1LsDVqc/dzAdEs/E1FaPrcIaIIPw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/properties@5.8.0': + resolution: {integrity: sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==} - '@solana/rpc-types@3.0.3': - resolution: {integrity: sha512-petWQ5xSny9UfmC3Qp2owyhNU0w9SyBww4+v7tSVyXMcCC9v6j/XsqTeimH1S0qQUllnv0/FY83ohFaxofmZ6Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/rlp@5.8.0': + resolution: {integrity: sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==} - '@solana/rpc-types@5.0.0': - resolution: {integrity: sha512-JMbhwnV6nX4ezJv/KmaElOR0r/MZTKzKpaz6cv7FopLNuPrYCBrRCZKuM2XQh6gUbt9Mey08/KBOmOGmzTbL/g==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/signing-key@5.8.0': + resolution: {integrity: sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==} - '@solana/rpc-types@5.1.0': - resolution: {integrity: sha512-Rnpt5BuHQvnULPNXUC/yRqB+7iPbon95CSCeyRvPj5tJ4fx2JibvX3s/UEoud5vC+kRjPi/R0BGJ8XFvd3eDWg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/strings@5.8.0': + resolution: {integrity: sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==} - '@solana/rpc-types@6.1.0': - resolution: {integrity: sha512-lR+Cb3v5Rpl49HsXWASy++TSE1AD86eRKabY+iuWnbBMYVGI4MamAvYwgBiygsCNc30nyO2TFNj9STMeSD/gAg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@ethersproject/transactions@5.8.0': + resolution: {integrity: sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==} - '@solana/rpc@2.3.0': - resolution: {integrity: sha512-ZWN76iNQAOCpYC7yKfb3UNLIMZf603JckLKOOLTHuy9MZnTN8XV6uwvDFhf42XvhglgUjGCEnbUqWtxQ9pa/pQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@ethersproject/web@5.8.0': + resolution: {integrity: sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==} - '@solana/rpc@3.0.3': - resolution: {integrity: sha512-3oukAaLK78GegkKcm6iNmRnO4mFeNz+BMvA8T56oizoBNKiRVEq/6DFzVX/LkmZ+wvD601pAB3uCdrTPcC0YKQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@evanhahn/lottie-web-light@5.8.1': + resolution: {integrity: sha512-U0G1tt3/UEYnyCNNslWPi1dB7X1xQ9aoSip+B3GTKO/Bns8yz/p39vBkRSN9d25nkbHuCsbjky2coQftj5YVKw==} - '@solana/rpc@5.0.0': - resolution: {integrity: sha512-Myx/ZBmMHkgh9Di3tLzc+vd30f+6YC1JXr9+YmIHKEeqN/+iTHkDJU2E/hGRLy8vTOBOU7+2466A+dLnSVuGkg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@farcaster/miniapp-core@0.3.8': + resolution: {integrity: sha512-LaRG1L3lxHqo5pP/E2CX9hNqusR0C8hX3QTV2+hzmQJz6IGvmSpH6Q9ivlLyDfbdqokiMFo5Y3Z1EX1zBHMEQQ==} - '@solana/rpc@5.1.0': - resolution: {integrity: sha512-j+ByLxFCoHWw9TnsGzkAVMFUfBDIUE53nIosJAYEsERpImD2mjwc33uDE6YXLKoaKRoYO4tc7IUzkKY1fQp/CA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@farcaster/miniapp-core@0.4.1': + resolution: {integrity: sha512-20FxHTRToYUKx7CQ8PvIy9OoQ6XjdmF1pRMS7dsj37qdqjVDeEkYoK8yXwnoReZoJRcYwIg8P3i6V8bTWNR5mg==} - '@solana/rpc@6.1.0': - resolution: {integrity: sha512-R3y5PklW9mPy5Y34hsXj40R28zN2N7AGLnHqYJVkXkllwVub/QCNpSdDxAnbbS5EGOYGoUOW8s5LFoXwMSr1LQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@farcaster/miniapp-sdk@0.1.9': + resolution: {integrity: sha512-hn0dlIy0JP2Hx6PgKcn9bjYwyPS/SQgYJ/a0qjzG8ZsDfUdjsMPf3yI/jicBipTml/UUoKcbqXM68fsrsbNMKA==} - '@solana/signers@2.3.0': - resolution: {integrity: sha512-OSv6fGr/MFRx6J+ZChQMRqKNPGGmdjkqarKkRzkwmv7v8quWsIRnJT5EV8tBy3LI4DLO/A8vKiNSPzvm1TdaiQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@farcaster/miniapp-sdk@0.2.1': + resolution: {integrity: sha512-2SnDeOtDdlN1lGQt7UyH2jkrZRQDOkmhcrlzNWazYChyPh9XfV8+9fMS+Lr/E2pEws9Q40Xl9POrCzdpUC19lg==} - '@solana/signers@3.0.3': - resolution: {integrity: sha512-UwCd/uPYTZiwd283JKVyOWLLN5sIgMBqGDyUmNU3vo9hcmXKv5ZGm/9TvwMY2z35sXWuIOcj7etxJ8OoWc/ObQ==} - engines: {node: '>=20.18.0'} + '@farcaster/miniapp-wagmi-connector@1.0.0': + resolution: {integrity: sha512-vMRZbekUUctnAUvBFhNoEsJlujRRdxop94fDy5LrKiRR9ax0wtp8gCvLYO+LpaP2PtGs0HFpRwlHNDJWvBR8bg==} peerDependencies: - typescript: '>=5.3.3' + '@farcaster/miniapp-sdk': ^0.1.0 + '@wagmi/core': ^2.14.1 + viem: ^2.21.55 - '@solana/signers@5.0.0': - resolution: {integrity: sha512-9Hw6HekSEzj5O7UBBFPrxk96W5e8tMI3n7KbW7/QiKBDpuvYw9WtnjOsWUE7LqQoc1P0JjGEsrmxE9raQBLvuQ==} - engines: {node: '>=20.18.0'} + '@farcaster/quick-auth@0.0.6': + resolution: {integrity: sha512-tiZndhpfDtEhaKlkmS5cVDuS+A/tafqZT3y9I44rC69m3beJok6e8dIH2JhxVy3EvOWTyTBnrmNn6GOOh+qK6A==} peerDependencies: - typescript: '>=5.3.3' + typescript: 5.8.3 - '@solana/signers@5.1.0': - resolution: {integrity: sha512-B8xO0SGN1ZWYfJROL+da3id279qNbXbXoqud+AuT5gur51RrS4YhNkTQ6khVbGtAOpPMAhkoZN0jnfCC1r33jQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@fastify/ajv-compiler@4.0.5': + resolution: {integrity: sha512-KoWKW+MhvfTRWL4qrhUwAAZoaChluo0m0vbiJlGMt2GXvL4LVPQEjt8kSpHI3IBq5Rez8fg+XeH3cneztq+C7A==} - '@solana/signers@6.1.0': - resolution: {integrity: sha512-WDPGZJr6jIe2dEChv/2KQBnaga8dqOjd6ceBj/HcDHxnCudo66t7GlyZ9+9jMO40AgOOb7EDE5FDqPMrHMg5Yw==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@fastify/error@4.2.0': + resolution: {integrity: sha512-RSo3sVDXfHskiBZKBPRgnQTtIqpi/7zhJOEmAxCiBcM7d0uwdGdxLlsCaLzGs8v8NnxIRlfG0N51p5yFaOentQ==} - '@solana/spl-token-group@0.0.7': - resolution: {integrity: sha512-V1N/iX7Cr7H0uazWUT2uk27TMqlqedpXHRqqAbVO2gvmJyT0E0ummMEAVQeXZ05ZhQ/xF39DLSdBp90XebWEug==} - engines: {node: '>=16'} - peerDependencies: - '@solana/web3.js': ^1.95.3 + '@fastify/fast-json-stringify-compiler@5.0.3': + resolution: {integrity: sha512-uik7yYHkLr6fxd8hJSZ8c+xF4WafPK+XzneQDPU+D10r5X19GW8lJcom2YijX2+qtFF1ENJlHXKFM9ouXNJYgQ==} - '@solana/spl-token-metadata@0.1.6': - resolution: {integrity: sha512-7sMt1rsm/zQOQcUWllQX9mD2O6KhSAtY1hFR2hfFwgqfFWzSY9E9GDvFVNYUI1F0iQKcm6HmePU9QbKRXTEBiA==} - engines: {node: '>=16'} - peerDependencies: - '@solana/web3.js': ^1.95.3 + '@fastify/forwarded@3.0.1': + resolution: {integrity: sha512-JqDochHFqXs3C3Ml3gOY58zM7OqO9ENqPo0UqAjAjH8L01fRZqwX9iLeX34//kiJubF7r2ZQHtBRU36vONbLlw==} - '@solana/spl-token@0.4.13': - resolution: {integrity: sha512-cite/pYWQZZVvLbg5lsodSovbetK/eA24gaR0eeUeMuBAMNrT8XFCwaygKy0N2WSg3gSyjjNpIeAGBAKZaY/1w==} - engines: {node: '>=16'} - peerDependencies: - '@solana/web3.js': ^1.95.5 + '@fastify/merge-json-schemas@0.2.1': + resolution: {integrity: sha512-OA3KGBCy6KtIvLf8DINC5880o5iBlDX4SxzLQS8HorJAbqluzLRn80UXU0bxZn7UOFhFgpRJDasfwn9nG4FG4A==} - '@solana/subscribable@2.3.0': - resolution: {integrity: sha512-DkgohEDbMkdTWiKAoatY02Njr56WXx9e/dKKfmne8/Ad6/2llUIrax78nCdlvZW9quXMaXPTxZvdQqo9N669Og==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@fastify/proxy-addr@5.1.0': + resolution: {integrity: sha512-INS+6gh91cLUjB+PVHfu1UqcB76Sqtpyp7bnL+FYojhjygvOPA9ctiD/JDKsyD9Xgu4hUhCSJBPig/w7duNajw==} - '@solana/subscribable@3.0.3': - resolution: {integrity: sha512-FJ27LKGHLQ5GGttPvTOLQDLrrOZEgvaJhB7yYaHAhPk25+p+erBaQpjePhfkMyUbL1FQbxn1SUJmS6jUuaPjlQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.3': + resolution: {integrity: sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - '@solana/subscribable@5.0.0': - resolution: {integrity: sha512-C2TydIRRd5XUJ8asbARi67Sj/3DRLubWalnNoafBhDsrb88jsRVylntvwXgBw/+lwJdEPEsUnxvcdgdm+3lFlw==} - engines: {node: '>=20.18.0'} + '@floating-ui/react-dom@2.1.5': + resolution: {integrity: sha512-HDO/1/1oH9fjj4eLgegrlH3dklZpHtUYYFiVwMUwfGvk9jWDRWqkklA2/NFScknrcNSspbV868WjXORvreDX+Q==} peerDependencies: - typescript: '>=5.3.3' + react: '>=16.8.0' + react-dom: '>=16.8.0' - '@solana/subscribable@5.1.0': - resolution: {integrity: sha512-OeW5AJwKzHh18+PIPtghuuPJTmEep2Mhb3Lsrq4alas4fibmMGkr39z1HXxVF6l6e2lu/YGhHIDtuhouWmY7ow==} - engines: {node: '>=20.18.0'} + '@floating-ui/react-dom@2.1.6': + resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} peerDependencies: - typescript: '>=5.3.3' + react: '>=16.8.0' + react-dom: '>=16.8.0' - '@solana/subscribable@6.1.0': - resolution: {integrity: sha512-HiUfkxN7638uxPmY4t0gI4+yqnFLZYJKFaT9EpWIuGrOB1d9n+uOHNs3NU7cVMwWXgfZUbztTCKyCVTbcwesNg==} - engines: {node: '>=20.18.0'} + '@floating-ui/react@0.27.16': + resolution: {integrity: sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==} peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + react: '>=17.0.0' + react-dom: '>=17.0.0' - '@solana/sysvars@2.3.0': - resolution: {integrity: sha512-LvjADZrpZ+CnhlHqfI5cmsRzX9Rpyb1Ox2dMHnbsRNzeKAMhu9w4ZBIaeTdO322zsTr509G1B+k2ABD3whvUBA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - '@solana/sysvars@3.0.3': - resolution: {integrity: sha512-GnHew+QeKCs2f9ow+20swEJMH4mDfJA/QhtPgOPTYQx/z69J4IieYJ7fZenSHnA//lJ45fVdNdmy1trypvPLBQ==} - engines: {node: '>=20.18.0'} + '@gemini-wallet/core@0.2.0': + resolution: {integrity: sha512-vv9aozWnKrrPWQ3vIFcWk7yta4hQW1Ie0fsNNPeXnjAxkbXr2hqMagEptLuMxpEP2W3mnRu05VDNKzcvAuuZDw==} peerDependencies: - typescript: '>=5.3.3' + viem: '>=2.0.0' - '@solana/sysvars@5.0.0': - resolution: {integrity: sha512-F/GEb2rS8mrgDd79lDPyu8za9jGE6cRlS4jHNeKCkvOCJxdKQbX34JIzx4kwzjtvk7O8/yrDHfGdpA8nBg/l4w==} - engines: {node: '>=20.18.0'} + '@gemini-wallet/core@0.3.2': + resolution: {integrity: sha512-Z4aHi3ECFf5oWYWM3F1rW83GJfB9OvhBYPTmb5q+VyK3uvzvS48lwo+jwh2eOoCRWEuT/crpb9Vwp2QaS5JqgQ==} peerDependencies: - typescript: '>=5.3.3' + viem: '>=2.0.0' - '@solana/sysvars@5.1.0': - resolution: {integrity: sha512-FJ9YIsLTAaajnOrYEYn54znstXJsvKndRhyCrlyiAEN1IXHw5HtZHploLF3ZZ78b7YU3uv3tFJMziXFBwPOn4Q==} - engines: {node: '>=20.18.0'} + '@graphql-typed-document-node/core@3.2.0': + resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} peerDependencies: - typescript: '>=5.3.3' + graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 - '@solana/sysvars@6.1.0': - resolution: {integrity: sha512-KwJyBBrAOx0BgkiZqOKAaySDb/0JrUFSBQL9/O1kSKGy9TCRX55Ytr1HxNTcTPppWNpbM6JZVK+yW3Ruey0HRw==} - engines: {node: '>=20.18.0'} + '@grpc/grpc-js@1.12.6': + resolution: {integrity: sha512-JXUj6PI0oqqzTGvKtzOkxtpsyPRNsrmhh41TtIz/zEB6J+AUiZZ0dxWzcMwO9Ns5rmSPuMdghlTbUuqIM48d3Q==} + engines: {node: '>=12.10.0'} + + '@grpc/proto-loader@0.7.15': + resolution: {integrity: sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==} + engines: {node: '>=6'} + hasBin: true + + '@hiero-ledger/cryptography@1.16.0-beta.3': + resolution: {integrity: sha512-7+R/HKGq6LiqUZ1agn52sQS6J3+VXBWvqIMUCIU1EVdbEPQDPoVPJYEd7dDreBCLIcjBRcHVjDc9wbi+ar2rsA==} + engines: {node: '>=12.0.0'} peerDependencies: - typescript: ^5.0.0 + expo-crypto: '*' peerDependenciesMeta: - typescript: + expo-crypto: optional: true - '@solana/transaction-confirmation@2.3.0': - resolution: {integrity: sha512-UiEuiHCfAAZEKdfne/XljFNJbsKAe701UQHKXEInYzIgBjRbvaeYZlBmkkqtxwcasgBTOmEaEKT44J14N9VZDw==} - engines: {node: '>=20.18.0'} + '@hiero-ledger/proto@2.26.0-beta.3': + resolution: {integrity: sha512-2UhTKX2RbL2LC8XcgetFa4iS5d8cELY/8PmFolj750z4CoQu2YOchZTqNTdI431qR9uAx3aBVSf+mx/YBYIUNA==} + engines: {node: '>=10.0.0'} peerDependencies: - typescript: '>=5.3.3' + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + debug: 4.4.1 + protobufjs: 7.5.4 + strip-ansi: 7.1.2 - '@solana/transaction-confirmation@3.0.3': - resolution: {integrity: sha512-dXx0OLtR95LMuARgi2dDQlL1QYmk56DOou5q9wKymmeV3JTvfDExeWXnOgjRBBq/dEfj4ugN1aZuTaS18UirFw==} - engines: {node: '>=20.18.0'} + '@hiero-ledger/sdk@2.80.0': + resolution: {integrity: sha512-9FHNPduWl27eNI2Gns0O6GJTqcEJ11lBTML84A7D8albCErVXaUVsnRrASafH+Xfq1dqK5dwsNHRwu8WtM3zVQ==} + engines: {node: '>=18.0.0'} peerDependencies: - typescript: '>=5.3.3' + bn.js: 5.2.1 - '@solana/transaction-confirmation@5.0.0': - resolution: {integrity: sha512-LpusTopYIuQC8hBCloExkTr4Z5/zdp5f4IIbzD5XFeW3xXPZytS3H1IDMGk4bmLdZi9zQNA4lnNHKra5IncRbw==} - engines: {node: '>=20.18.0'} + '@hono/node-server@1.19.0': + resolution: {integrity: sha512-1k8/8OHf5VIymJEcJyVksFpT+AQ5euY0VA5hUkCnlKpD4mr8FSbvXaHblxeTTEr90OaqWzAkQaqD80qHZQKxBA==} + engines: {node: '>=18.14.1'} peerDependencies: - typescript: '>=5.3.3' + hono: ^4 - '@solana/transaction-confirmation@5.1.0': - resolution: {integrity: sha512-6HnL0uH8tWZXJVuaoeTbCQp/FS11Bsc4GSlq+k0N21GdhTbFuqBhsxlAYWbzPWs9+/kYRGHqqXvBPCReWxT7BA==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@humanfs/core@0.19.1': + resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + engines: {node: '>=18.18.0'} - '@solana/transaction-confirmation@6.1.0': - resolution: {integrity: sha512-akSjcqAMOGPFvKctFDSzhjcRc/45WbEVdVQ9mjgH6OYo7B11WZZZaeGPlzAw5KyuG34Px941xmICkBmNqEH47Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@humanfs/node@0.16.6': + resolution: {integrity: sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==} + engines: {node: '>=18.18.0'} - '@solana/transaction-messages@2.3.0': - resolution: {integrity: sha512-bgqvWuy3MqKS5JdNLH649q+ngiyOu5rGS3DizSnWwYUd76RxZl1kN6CoqHSrrMzFMvis6sck/yPGG3wqrMlAww==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} - '@solana/transaction-messages@3.0.3': - resolution: {integrity: sha512-s+6NWRnBhnnjFWV4x2tzBzoWa6e5LiIxIvJlWwVQBFkc8fMGY04w7jkFh0PM08t/QFKeXBEWkyBDa/TFYdkWug==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@humanwhocodes/retry@0.3.1': + resolution: {integrity: sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==} + engines: {node: '>=18.18'} - '@solana/transaction-messages@5.0.0': - resolution: {integrity: sha512-rJLe1wUGW5DovQFV0gjXHXnriPxTBgZ3TvGWnjCu2OIBU8mcQkQVJ7zzVZY2IAYlmJ6OSF9nvzhSt/ncPbkJPg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} - '@solana/transaction-messages@5.1.0': - resolution: {integrity: sha512-9rNV2YJhd85WIMvnwa/vUY4xUw3ZTU17jP1KDo/fFZWk55a0ov0ATJJPyC5HAR1i6hT1cmJzGH/UHhnD9m/Q3w==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@img/colour@1.0.0': + resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + engines: {node: '>=18'} - '@solana/transaction-messages@6.1.0': - resolution: {integrity: sha512-Dpv54LRVcfFbFEa/uB53LaY/TRfKuPGMKR7Z4F290zBgkj9xkpZkI+WLiJBiSloI7Qo2KZqXj3514BIeZvJLcg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] - '@solana/transactions@2.3.0': - resolution: {integrity: sha512-LnTvdi8QnrQtuEZor5Msje61sDpPstTVwKg4y81tNxDhiyomjuvnSNLAq6QsB9gIxUqbNzPZgOG9IU4I4/Uaug==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] - '@solana/transactions@3.0.3': - resolution: {integrity: sha512-iMX+n9j4ON7H1nKlWEbMqMOpKYC6yVGxKKmWHT1KdLRG7v+03I4DnDeFoI+Zmw56FA+7Bbne8jwwX60Q1vk/MQ==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] - '@solana/transactions@5.0.0': - resolution: {integrity: sha512-4TcsqH7JtgRKGGBIRRGz0n+tXu4h5TPPC49kkV0ygIndQaHW7FOZUYTwQ0epq0A5h9KYi+ClNbzF9xiuDbAD5Q==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] - '@solana/transactions@5.1.0': - resolution: {integrity: sha512-06JwSPtz+38ozNgpysAXS2eTMPQCufIisXB6K88X8J4GF8ziqs4nkq0BpXAXn+MpZTkuMt+JeW2RxP3HKhXe5g==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: '>=5.3.3' + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@solana/transactions@6.1.0': - resolution: {integrity: sha512-1dkiNJcTtlHm4Fvs5VohNVpv7RbvbUYYKV7lYXMPIskoLF1eZp0tVlEqD/cRl91RNz7HEysfHqBAwlcJcRmrRg==} - engines: {node: '>=20.18.0'} - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + libc: [glibc] - '@solana/wallet-standard-features@1.3.0': - resolution: {integrity: sha512-ZhpZtD+4VArf6RPitsVExvgkF+nGghd1rzPjd97GmBximpnt1rsUxMOEyoIEuH3XBxPyNB6Us7ha7RHWQR+abg==} - engines: {node: '>=16'} + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@solana/web3.js@1.98.4': - resolution: {integrity: sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==} + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@spruceid/siwe-parser@2.1.2': - resolution: {integrity: sha512-d/r3S1LwJyMaRAKQ0awmo9whfXeE88Qt00vRj91q5uv5ATtWIQEGJ67Yr5eSZw5zp1/fZCXZYuEckt8lSkereQ==} + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + libc: [glibc] - '@stablelib/base64@1.0.1': - resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + libc: [musl] - '@stablelib/binary@1.0.1': - resolution: {integrity: sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==} + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + libc: [musl] - '@stablelib/int@1.0.1': - resolution: {integrity: sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==} + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@stablelib/random@1.0.2': - resolution: {integrity: sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==} + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + libc: [glibc] - '@stablelib/wipe@1.0.1': - resolution: {integrity: sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==} + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@stellar/js-xdr@3.1.2': - resolution: {integrity: sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==} + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] - '@stellar/stellar-base@14.1.0': - resolution: {integrity: sha512-A8kFli6QGy22SRF45IjgPAJfUNGjnI+R7g4DF5NZYVsD1kGf7B4ITyc4OPclLV9tqNI4/lXxafGEw0JEUbHixw==} - engines: {node: '>=20.0.0'} + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@stellar/stellar-sdk@14.6.1': - resolution: {integrity: sha512-A1rQWDLdUasXkMXnYSuhgep+3ZZzyuXJKdt5/KAIc0gkmSp906HTvUpbT4pu+bVr41tu0+J4Ugz9J4BQAGGytg==} - engines: {node: '>=20.0.0'} - hasBin: true + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [glibc] - '@svgr/babel-plugin-add-jsx-attribute@8.0.0': - resolution: {integrity: sha512-b9MIk7yhdS1pMCZM8VeNfUlSKVRhsHZNMl5O9SfaX0l0t5wjdgu4IDzGB8bpnGBBOjGST3rRFVsaaEtI4W6f7g==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + libc: [musl] - '@svgr/babel-plugin-remove-jsx-attribute@8.0.0': - resolution: {integrity: sha512-BcCkm/STipKvbCl6b7QFrMh/vx00vIP63k2eM66MfHJzPr6O2U0jYEViXkHJWqXqQYjdeA9cuCl5KWmlwjDvbA==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + libc: [musl] - '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0': - resolution: {integrity: sha512-5BcGCBfBxB5+XSDSWnhTThfI9jcO5f0Ai2V24gZpG+wXF14BzwxxdDb4g6trdOux0rhibGs385BeFMSmxtS3uA==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] - '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0': - resolution: {integrity: sha512-KVQ+PtIjb1BuYT3ht8M5KbzWBhdAjjUPdlMtpuw/VjT8coTrItWX6Qafl9+ji831JaJcu6PJNKCV0bp01lBNzQ==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] - '@svgr/babel-plugin-svg-dynamic-title@8.0.0': - resolution: {integrity: sha512-omNiKqwjNmOQJ2v6ge4SErBbkooV2aAWwaPFs2vUY7p7GhVkzRkJ00kILXQvRhA6miHnNpXv7MRnnSjdRjK8og==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] - '@svgr/babel-plugin-svg-em-dimensions@8.0.0': - resolution: {integrity: sha512-mURHYnu6Iw3UBTbhGwE/vsngtCIbHE43xCRK7kCw4t01xyGqb2Pd+WXekRRoFOBIY29ZoOhUCTEweDMdrjfi9g==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] - '@svgr/babel-plugin-transform-react-native-svg@8.1.0': - resolution: {integrity: sha512-Tx8T58CHo+7nwJ+EhUwx3LfdNSG9R2OKfaIXXs5soiy5HtgoAEkDay9LIimLOcG8dJQH1wPZp/cnAv6S9CrR1Q==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} - '@svgr/babel-plugin-transform-svg-component@8.0.0': - resolution: {integrity: sha512-DFx8xa3cZXTdb/k3kfPeaixecQLgKh5NVBMwD0AQxOzcZawK4oo1Jh9LbrcACUivsCA7TLG8eeWgrDXjTMhRmw==} + '@isaacs/ttlcache@1.4.1': + resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} engines: {node: '>=12'} - peerDependencies: - '@babel/core': ^7.0.0-0 - '@svgr/babel-preset@8.1.0': - resolution: {integrity: sha512-7EYDbHE7MxHpv4sxvnVPngw5fuR6pw79SkcrILHJ/iMpuKySNCl5W1qcwPEpU+LgyRXOaAFgH0KhwD18wwg6ug==} - engines: {node: '>=14'} - peerDependencies: - '@babel/core': ^7.0.0-0 + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@svgr/core@8.1.0': - resolution: {integrity: sha512-8QqtOQT5ACVlmsvKOJNEaWmRPmcojMOzCz4Hs2BGG/toAp/K38LcsMRyLp349glq5AzJbCEeimEoxaX6v/fLrA==} - engines: {node: '>=14'} + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@svgr/hast-util-to-babel-ast@8.0.0': - resolution: {integrity: sha512-EbDKwO9GpfWP4jN9sGdYwPBU0kdomaPIL2Eu4YwmgP+sJeXT+L7bMwJUBnhzfH8Q2qMBqZ4fJwpCyYsAN3mt2Q==} - engines: {node: '>=14'} + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - '@svgr/plugin-jsx@8.1.0': - resolution: {integrity: sha512-0xiIyBsLlr8quN+WyuxooNW9RJ0Dpr8uOnH/xrCVO8GLUcwHISwj1AG0k+LFzteTkAA0GbX0kj9q6Dk70PTiPA==} - engines: {node: '>=14'} - peerDependencies: - '@svgr/core': '*' + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - '@svgr/plugin-svgo@8.1.0': - resolution: {integrity: sha512-Ywtl837OGO9pTLIN/onoWLmDQ4zFUycI1g76vuKGEz6evR/ZTJlJuz3G/fIkb6OVBJ2g0o6CGJzaEjfmEo3AHA==} - engines: {node: '>=14'} - peerDependencies: - '@svgr/core': '*' + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} - '@svgr/webpack@8.1.0': - resolution: {integrity: sha512-LnhVjMWyMQV9ZmeEy26maJk+8HTIbd59cH4F2MJ439k9DqejRisfFNGAPvRYlKETuh9LrImlS8aKsBgKjMA8WA==} - engines: {node: '>=14'} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - '@swc/helpers@0.5.17': - resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + '@jridgewell/trace-mapping@0.3.30': + resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} - '@szmarczak/http-timer@4.0.6': - resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} - engines: {node: '>=10'} + '@jridgewell/trace-mapping@0.3.9': + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@tailwindcss/node@4.1.17': - resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} + '@js-sdsl/ordered-map@4.4.2': + resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} - '@tailwindcss/oxide-android-arm64@4.1.17': - resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [android] + '@likecoin/qr-code-styling@1.6.6': + resolution: {integrity: sha512-RbGK/+20bJhFZR70r8MeDvfyz3W7U5zXpykSTYOYxZGyo6wC+Y4QnbUpL+YdAtzT2ZIFeCNOcRs2W2FNrKPoaA==} - '@tailwindcss/oxide-darwin-arm64@4.1.17': - resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] + '@lit-labs/ssr-dom-shim@1.4.0': + resolution: {integrity: sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==} - '@tailwindcss/oxide-darwin-x64@4.1.17': - resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] + '@lit/reactive-element@2.1.1': + resolution: {integrity: sha512-N+dm5PAYdQ8e6UlywyyrgI2t++wFGXfHx+dSJ1oBrg6FAxUj40jId++EaRm80MKX5JnlH1sBsyZ5h0bcZKemCg==} - '@tailwindcss/oxide-freebsd-x64@4.1.17': - resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==} - engines: {node: '>= 10'} - cpu: [x64] - os: [freebsd] + '@metamask/eth-json-rpc-provider@1.0.1': + resolution: {integrity: sha512-whiUMPlAOrVGmX8aKYVPvlKyG4CpQXiNNyt74vE1xb5sPvmx5oA7B/kOi/JdBvhGQq97U1/AVdXEdk2zkP8qyA==} + engines: {node: '>=14.0.0'} - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': - resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==} - engines: {node: '>= 10'} - cpu: [arm] - os: [linux] + '@metamask/json-rpc-engine@7.3.3': + resolution: {integrity: sha512-dwZPq8wx9yV3IX2caLi9q9xZBw2XeIoYqdyihDDDpuHVCEiqadJLwqM3zy+uwf6F1QYQ65A8aOMQg1Uw7LMLNg==} + engines: {node: '>=16.0.0'} - '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': - resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] + '@metamask/json-rpc-engine@8.0.2': + resolution: {integrity: sha512-IoQPmql8q7ABLruW7i4EYVHWUbF74yrp63bRuXV5Zf9BQwcn5H9Ww1eLtROYvI1bUXwOiHZ6qT5CWTrDc/t/AA==} + engines: {node: '>=16.0.0'} - '@tailwindcss/oxide-linux-arm64-musl@4.1.17': - resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] + '@metamask/json-rpc-middleware-stream@7.0.2': + resolution: {integrity: sha512-yUdzsJK04Ev98Ck4D7lmRNQ8FPioXYhEUZOMS01LXW8qTvPGiRVXmVltj2p4wrLkh0vW7u6nv0mNl5xzC5Qmfg==} + engines: {node: '>=16.0.0'} - '@tailwindcss/oxide-linux-x64-gnu@4.1.17': - resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] + '@metamask/object-multiplex@2.1.0': + resolution: {integrity: sha512-4vKIiv0DQxljcXwfpnbsXcfa5glMj5Zg9mqn4xpIWqkv6uJ2ma5/GtUfLFSxhlxnR8asRMv8dDmWya1Tc1sDFA==} + engines: {node: ^16.20 || ^18.16 || >=20} - '@tailwindcss/oxide-linux-x64-musl@4.1.17': - resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] + '@metamask/onboarding@1.0.1': + resolution: {integrity: sha512-FqHhAsCI+Vacx2qa5mAFcWNSrTcVGMNjzxVgaX8ECSny/BJ9/vgXP9V7WF/8vb9DltPeQkxr+Fnfmm6GHfmdTQ==} - '@tailwindcss/oxide-wasm32-wasi@4.1.17': - resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - bundledDependencies: - - '@napi-rs/wasm-runtime' - - '@emnapi/core' - - '@emnapi/runtime' - - '@tybys/wasm-util' - - '@emnapi/wasi-threads' - - tslib + '@metamask/providers@16.1.0': + resolution: {integrity: sha512-znVCvux30+3SaUwcUGaSf+pUckzT5ukPRpcBmy+muBLC0yaWnBcvDqGfcsw6CBIenUdFrVoAFa8B6jsuCY/a+g==} + engines: {node: ^18.18 || >=20} - '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': - resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] + '@metamask/rpc-errors@6.4.0': + resolution: {integrity: sha512-1ugFO1UoirU2esS3juZanS/Fo8C8XYocCuBpfZI5N7ECtoG+zu0wF+uWZASik6CkO6w9n/Iebt4iI4pT0vptpg==} + engines: {node: '>=16.0.0'} - '@tailwindcss/oxide-win32-x64-msvc@4.1.17': - resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] + '@metamask/rpc-errors@7.0.2': + resolution: {integrity: sha512-YYYHsVYd46XwY2QZzpGeU4PSdRhHdxnzkB8piWGvJW2xbikZ3R+epAYEL4q/K8bh9JPTucsUdwRFnACor1aOYw==} + engines: {node: ^18.20 || ^20.17 || >=22} - '@tailwindcss/oxide@4.1.17': - resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==} - engines: {node: '>= 10'} + '@metamask/safe-event-emitter@2.0.0': + resolution: {integrity: sha512-/kSXhY692qiV1MXu6EeOZvg5nECLclxNXcKCxJ3cXQgYuRymRHpdx/t7JXfsK+JLjwA1e1c1/SBrlQYpusC29Q==} - '@tailwindcss/postcss@4.1.17': - resolution: {integrity: sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==} + '@metamask/safe-event-emitter@3.1.2': + resolution: {integrity: sha512-5yb2gMI1BDm0JybZezeoX/3XhPDOtTbcFvpTXM9kxsoZjPZFh4XciqRbpD6N86HYZqWDhEaKUDuOyR0sQHEjMA==} + engines: {node: '>=12.0.0'} - '@tanstack/query-core@5.90.11': - resolution: {integrity: sha512-f9z/nXhCgWDF4lHqgIE30jxLe4sYv15QodfdPDKYAk7nAEjNcndy4dHz3ezhdUaR23BpWa4I2EH4/DZ0//Uf8A==} + '@metamask/sdk-analytics@0.0.5': + resolution: {integrity: sha512-fDah+keS1RjSUlC8GmYXvx6Y26s3Ax1U9hGpWb6GSY5SAdmTSIqp2CvYy6yW0WgLhnYhW+6xERuD0eVqV63QIQ==} + deprecated: No longer maintained, superseded by @metamask/connect-analytics - '@tanstack/react-query@5.90.11': - resolution: {integrity: sha512-3uyzz01D1fkTLXuxF3JfoJoHQMU2fxsfJwE+6N5hHy0dVNoZOvwKP8Z2k7k1KDeD54N20apcJnG75TBAStIrBA==} + '@metamask/sdk-communication-layer@0.32.0': + resolution: {integrity: sha512-dmj/KFjMi1fsdZGIOtbhxdg3amxhKL/A5BqSU4uh/SyDKPub/OT+x5pX8bGjpTL1WPWY/Q0OIlvFyX3VWnT06Q==} peerDependencies: - react: ^18 || ^19 + cross-fetch: ^4.0.0 + eciesjs: '*' + eventemitter2: ^6.4.9 + readable-stream: ^3.6.2 + socket.io-client: ^4.5.1 - '@tootallnate/once@2.0.0': - resolution: {integrity: sha512-XCuKFP5PS55gnMVu3dty8KPatLqUoy/ZYzDzAGCQ8JNFCkLXzmI7vNHCR+XpbZaMWQK/vQubr7PkYq8g470J/A==} - engines: {node: '>= 10'} + '@metamask/sdk-communication-layer@0.33.1': + resolution: {integrity: sha512-0bI9hkysxcfbZ/lk0T2+aKVo1j0ynQVTuB3sJ5ssPWlz+Z3VwveCkP1O7EVu1tsVVCb0YV5WxK9zmURu2FIiaA==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect + peerDependencies: + cross-fetch: ^4.0.0 + eciesjs: '*' + eventemitter2: ^6.4.9 + readable-stream: ^3.6.2 + socket.io-client: ^4.5.1 - '@trysound/sax@0.2.0': - resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} - engines: {node: '>=10.13.0'} + '@metamask/sdk-install-modal-web@0.32.0': + resolution: {integrity: sha512-TFoktj0JgfWnQaL3yFkApqNwcaqJ+dw4xcnrJueMP3aXkSNev2Ido+WVNOg4IIMxnmOrfAC9t0UJ0u/dC9MjOQ==} - '@tybys/wasm-util@0.10.0': - resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} + '@metamask/sdk-install-modal-web@0.32.1': + resolution: {integrity: sha512-MGmAo6qSjf1tuYXhCu2EZLftq+DSt5Z7fsIKr2P+lDgdTPWgLfZB1tJKzNcwKKOdf6q9Qmmxn7lJuI/gq5LrKw==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect + + '@metamask/sdk@0.32.0': + resolution: {integrity: sha512-WmGAlP1oBuD9hk4CsdlG1WJFuPtYJY+dnTHJMeCyohTWD2GgkcLMUUuvu9lO1/NVzuOoSi1OrnjbuY1O/1NZ1g==} + + '@metamask/sdk@0.33.1': + resolution: {integrity: sha512-1mcOQVGr9rSrVcbKPNVzbZ8eCl1K0FATsYH3WJ/MH4WcZDWGECWrXJPNMZoEAkLxWiMe8jOQBumg2pmcDa9zpQ==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + '@metamask/superstruct@3.2.1': + resolution: {integrity: sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g==} + engines: {node: '>=16.0.0'} - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + '@metamask/utils@11.4.2': + resolution: {integrity: sha512-TygCcGmUbhmpxjYMm+mx68kRiJ80jYV54/Aa8gUFBv4cTX7ulX2XZKr8CJoJAw3K3FN5ZvCRmU0IzWZFaonwhA==} + engines: {node: ^18.18 || ^20.14 || >=22} - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + '@metamask/utils@5.0.2': + resolution: {integrity: sha512-yfmE79bRQtnMzarnKfX7AEJBwFTxvTyw3nBQlu/5rmGXrjAeAMltoGxO62TFurxrQAFMNa/fEjIHNvungZp0+g==} + engines: {node: '>=14.0.0'} - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + '@metamask/utils@8.5.0': + resolution: {integrity: sha512-I6bkduevXb72TIM9q2LRO63JSsF9EXduh3sBr9oybNX2hNNpr/j1tEjXrsG0Uabm4MJ1xkGAQEMwifvKZIkyxQ==} + engines: {node: '>=16.0.0'} - '@types/body-parser@1.19.6': - resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} + '@metamask/utils@9.3.0': + resolution: {integrity: sha512-w8CVbdkDrVXFJbfBSlDfafDR6BAkpDmv1bC1UJVCoVny5tW2RKAdn9i68Xf7asYT4TnUhl/hN4zfUiKQq9II4g==} + engines: {node: '>=16.0.0'} - '@types/cacheable-request@6.0.3': - resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} + '@modelcontextprotocol/sdk@1.17.3': + resolution: {integrity: sha512-JPwUKWSsbzx+DLFznf/QZ32Qa+ptfbUlHhRLrBQBAFu9iI1iYvizM4p+zhhRDceSsPutXp4z+R/HPVphlIiclg==} + engines: {node: '>=18'} - '@types/chai@5.2.2': - resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} + '@msgpack/msgpack@3.1.3': + resolution: {integrity: sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==} + engines: {node: '>= 18'} - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@next/env@16.0.10': + resolution: {integrity: sha512-8tuaQkyDVgeONQ1MeT9Mkk8pQmZapMKFh5B+OrFUlG3rVmYTXcXlBetBgTurKXGaIZvkoqRT9JL5K3phXcgang==} - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} + '@next/eslint-plugin-next@16.0.6': + resolution: {integrity: sha512-9INsBF3/4XL0/tON8AGsh0svnTtDMLwv3iREGWnWkewGdOnd790tguzq9rX8xwrVthPyvaBHhw1ww0GZz0jO5Q==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@next/swc-darwin-arm64@16.0.10': + resolution: {integrity: sha512-4XgdKtdVsaflErz+B5XeG0T5PeXKDdruDf3CRpnhN+8UebNa5N2H58+3GDgpn/9GBurrQ1uWW768FfscwYkJRg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] - '@types/express-serve-static-core@4.19.8': - resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==} + '@next/swc-darwin-x64@16.0.10': + resolution: {integrity: sha512-spbEObMvRKkQ3CkYVOME+ocPDFo5UqHb8EMTS78/0mQ+O1nqE8toHJVioZo4TvebATxgA8XMTHHrScPrn68OGw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] - '@types/express-serve-static-core@5.0.7': - resolution: {integrity: sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==} + '@next/swc-linux-arm64-gnu@16.0.10': + resolution: {integrity: sha512-uQtWE3X0iGB8apTIskOMi2w/MKONrPOUCi5yLO+v3O8Mb5c7K4Q5KD1jvTpTF5gJKa3VH/ijKjKUq9O9UhwOYw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@types/express@4.17.25': - resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} + '@next/swc-linux-arm64-musl@16.0.10': + resolution: {integrity: sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] - '@types/express@5.0.3': - resolution: {integrity: sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==} + '@next/swc-linux-x64-gnu@16.0.10': + resolution: {integrity: sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] - '@types/fs-extra@9.0.13': - resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + '@next/swc-linux-x64-musl@16.0.10': + resolution: {integrity: sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] - '@types/http-cache-semantics@4.0.4': - resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} + '@next/swc-win32-arm64-msvc@16.0.10': + resolution: {integrity: sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] - '@types/http-errors@2.0.5': - resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + '@next/swc-win32-x64-msvc@16.0.10': + resolution: {integrity: sha512-E+njfCoFLb01RAFEnGZn6ERoOqhK1Gl3Lfz1Kjnj0Ulfu7oJbuMyvBKNj/bw8XZnenHDASlygTjZICQW+rYW1Q==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + '@noble/ciphers@1.2.0': + resolution: {integrity: sha512-YGdEUzYEd+82jeaVbSKKVp1jFZb8LwaNMIIzHFkihGvYdd/KKAr7KaJHdEdSYGredE3ssSravXIa0Jxg28Sv5w==} + engines: {node: ^14.21.3 || >=16} - '@types/json5@0.0.29': - resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} + '@noble/ciphers@1.2.1': + resolution: {integrity: sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==} + engines: {node: ^14.21.3 || >=16} - '@types/keyv@3.1.4': - resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} + '@noble/ciphers@1.3.0': + resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} + engines: {node: ^14.21.3 || >=16} - '@types/lodash@4.17.20': - resolution: {integrity: sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==} + '@noble/ciphers@2.2.0': + resolution: {integrity: sha512-Z6pjIZ/8IJcCGzb2S/0Px5J81yij85xASuk1teLNeg75bfT07MV3a/O2Mtn1I2se43k3lkVEcFaR10N4cgQcZA==} + engines: {node: '>= 20.19.0'} - '@types/mime@1.3.5': - resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + '@noble/curves@1.4.2': + resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} - '@types/ms@2.1.0': - resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} + '@noble/curves@1.8.0': + resolution: {integrity: sha512-j84kjAbzEnQHaSIhRPUmB3/eVXu2k3dKPl2LOrR8fSOIL+89U+7lV117EWHtq/GHM3ReGHM46iRBdZfpc4HRUQ==} + engines: {node: ^14.21.3 || >=16} - '@types/node-fetch@2.6.13': - resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} + '@noble/curves@1.8.1': + resolution: {integrity: sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==} + engines: {node: ^14.21.3 || >=16} - '@types/node@12.20.55': - resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} + '@noble/curves@1.9.1': + resolution: {integrity: sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==} + engines: {node: ^14.21.3 || >=16} - '@types/node@18.19.123': - resolution: {integrity: sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg==} + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} - '@types/node@20.19.11': - resolution: {integrity: sha512-uug3FEEGv0r+jrecvUUpbY8lLisvIjg6AAic6a2bSP5OEOLeJsDSnvhCDov7ipFFMXS3orMpzlmi0ZcuGkBbow==} + '@noble/curves@2.2.0': + resolution: {integrity: sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==} + engines: {node: '>= 20.19.0'} - '@types/node@22.17.2': - resolution: {integrity: sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w==} + '@noble/ed25519@3.1.0': + resolution: {integrity: sha512-pfcObRY3CtvwfaG9Mt5XqZdKmAQppl37tHUeuBhDUbiwJBCVY4/A4lbMvb1xKhMDx96AqAqZpMWuBX1HulhX4g==} - '@types/node@22.7.5': - resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@noble/hashes@1.4.0': + resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} + engines: {node: '>= 16'} - '@types/node@24.3.0': - resolution: {integrity: sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==} + '@noble/hashes@1.7.0': + resolution: {integrity: sha512-HXydb0DgzTpDPwbVeDGCG1gIu7X6+AuU6Zl6av/E/KG8LMsvPntvq+w17CHRpKBmN6Ybdrt1eP3k4cj8DJa78w==} + engines: {node: ^14.21.3 || >=16} - '@types/plist@3.0.5': - resolution: {integrity: sha512-E6OCaRmAe4WDmWNsL/9RMqdkkzDCY1etutkflWk4c+AcjDU07Pcz1fQwTX0TQz+Pxqn9i4L1TU3UFpjnrcDgxA==} + '@noble/hashes@1.7.1': + resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} + engines: {node: ^14.21.3 || >=16} - '@types/prop-types@15.7.15': - resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} - '@types/qs@6.14.0': - resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} + '@noble/hashes@2.2.0': + resolution: {integrity: sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==} + engines: {node: '>= 20.19.0'} - '@types/range-parser@1.2.7': - resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} - '@types/react-dom@18.3.7': - resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} - peerDependencies: - '@types/react': ^18.0.0 + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} - '@types/react-dom@19.1.7': - resolution: {integrity: sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==} - peerDependencies: - '@types/react': ^19.0.0 + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} - '@types/react-dom@19.2.1': - resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} - peerDependencies: - '@types/react': ^19.2.0 + '@nolyfill/is-core-module@1.0.39': + resolution: {integrity: sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==} + engines: {node: '>=12.4.0'} - '@types/react@18.3.27': - resolution: {integrity: sha512-cisd7gxkzjBKU2GgdYrTdtQx1SORymWyaAFhaxQPK9bYO9ot3Y5OikQRvY0VYQtvwjeQnizCINJAenh/V7MK2w==} + '@paulmillr/qr@0.2.1': + resolution: {integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==} + deprecated: 'The package is now available as "qr": npm install qr' - '@types/react@19.1.10': - resolution: {integrity: sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==} + '@perawallet/connect@1.5.2': + resolution: {integrity: sha512-Lq4nLaQBisZUkBIWirhRn4b9MjrKWvlMxfrU6On5al/14E5mm3dlnwGHhpJ88IGlnGs7JyL625LVMgUK1TOTrg==} + peerDependencies: + algosdk: ^3.5.2 - '@types/react@19.2.1': - resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} + '@pinojs/redact@0.4.0': + resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} - '@types/responselike@1.0.3': - resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} - '@types/retry@0.12.0': - resolution: {integrity: sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==} + '@pkgr/core@0.2.9': + resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} - '@types/retry@0.12.2': - resolution: {integrity: sha512-XISRgDJ2Tc5q4TRqvgJtzsRkFYNJzZrhTdtMoGVBttwzzQJkPnS3WWTFc7kuDRoPtPakl+T+OfdEUjYJj7Jbow==} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} - '@types/send@0.17.5': - resolution: {integrity: sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==} + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} - '@types/serve-static@1.15.8': - resolution: {integrity: sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==} + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} - '@types/triple-beam@1.3.5': - resolution: {integrity: sha512-6WaYesThRMCl19iryMYP7/x2OVgCtbIVflDGFpWnb9irXI3UjYE4AzmYuiUKY1AJstGijoY+MgUszMgRxIYTYw==} + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} - '@types/trusted-types@2.0.7': - resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} - '@types/uuid@10.0.0': - resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==} + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} - '@types/uuid@8.3.4': - resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} - '@types/verror@1.10.11': - resolution: {integrity: sha512-RlDm9K7+o5stv0Co8i8ZRGxDbrTxhJtgjqjFyVh/tXQyl/rYtTKlnTvZ88oSTeYREWurwx20Js4kTuKCsFkUtg==} + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} - '@types/ws@7.4.7': - resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} - '@types/ws@8.18.1': - resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} - '@types/yauzl@2.10.3': - resolution: {integrity: sha512-oJoftv0LSuaDZE3Le4DbKX+KS9G36NzOeSap90UIK0yMA/NhKJhqlSGtNDORNRaIbQfzjXDrQa0ytJ6mNRGz/Q==} + '@radix-ui/primitive@1.1.3': + resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - '@typescript-eslint/eslint-plugin@8.40.0': - resolution: {integrity: sha512-w/EboPlBwnmOBtRbiOvzjD+wdiZdgFeo17lkltrtn7X37vagKKWJABvyfsJXTlHe6XBzugmYgd4A4nW+k8Mixw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-arrow@1.1.7': + resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} peerDependencies: - '@typescript-eslint/parser': ^8.40.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@typescript-eslint/eslint-plugin@8.48.0': - resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-collection@1.1.7': + resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} peerDependencies: - '@typescript-eslint/parser': ^8.48.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@typescript-eslint/parser@8.40.0': - resolution: {integrity: sha512-jCNyAuXx8dr5KJMkecGmZ8KI61KBUhkCob+SD+C+I5+Y1FWI2Y3QmY4/cxMCC5WAsZqoEtEETVhUiUMIGCf6Bw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-compose-refs@1.1.2': + resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@typescript-eslint/parser@8.48.0': - resolution: {integrity: sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-context@1.1.2': + resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@typescript-eslint/project-service@8.40.0': - resolution: {integrity: sha512-/A89vz7Wf5DEXsGVvcGdYKbVM9F7DyFXj52lNYUDS1L9yJfqjW/fIp5PgMuEJL/KeqVTe2QSbXAGUZljDUpArw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-dialog@1.1.15': + resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@typescript-eslint/project-service@8.48.0': - resolution: {integrity: sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-direction@1.1.1': + resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/scope-manager@8.40.0': - resolution: {integrity: sha512-y9ObStCcdCiZKzwqsE8CcpyuVMwRouJbbSrNuThDpv16dFAj429IkM6LNb1dZ2m7hK5fHyzNcErZf7CEeKXR4w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/scope-manager@8.48.0': - resolution: {integrity: sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@typescript-eslint/tsconfig-utils@8.40.0': - resolution: {integrity: sha512-jtMytmUaG9d/9kqSl/W3E3xaWESo4hFDxAIHGVW/WKKtQhesnRIJSAJO6XckluuJ6KDB5woD1EiqknriCtAmcw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-dismissable-layer@1.1.11': + resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@typescript-eslint/tsconfig-utils@8.48.0': - resolution: {integrity: sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-dropdown-menu@2.1.16': + resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@typescript-eslint/type-utils@8.40.0': - resolution: {integrity: sha512-eE60cK4KzAc6ZrzlJnflXdrMqOBaugeukWICO2rB0KNvwdIMaEaYiywwHMzA1qFpTxrLhN9Lp4E/00EgWcD3Ow==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-focus-guards@1.1.3': + resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@typescript-eslint/type-utils@8.48.0': - resolution: {integrity: sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-focus-scope@1.1.7': + resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/types@8.40.0': - resolution: {integrity: sha512-ETdbFlgbAmXHyFPwqUIYrfc12ArvpBhEVgGAxVYSwli26dn8Ko+lIo4Su9vI9ykTZdJn+vJprs/0eZU0YMAEQg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/types@8.48.0': - resolution: {integrity: sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@typescript-eslint/typescript-estree@8.40.0': - resolution: {integrity: sha512-k1z9+GJReVVOkc1WfVKs1vBrR5MIKKbdAjDTPvIK3L8De6KbFfPFt6BKpdkdk7rZS2GtC/m6yI5MYX+UsuvVYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-id@1.1.1': + resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@typescript-eslint/typescript-estree@8.48.0': - resolution: {integrity: sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-menu@2.1.16': + resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@typescript-eslint/utils@8.40.0': - resolution: {integrity: sha512-Cgzi2MXSZyAUOY+BFwGs17s7ad/7L+gKt6Y8rAVVWS+7o6wrjeFN4nVfTpbE25MNcxyJ+iYUXflbs2xR9h4UBg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-popover@1.1.15': + resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@typescript-eslint/utils@8.48.0': - resolution: {integrity: sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@radix-ui/react-popper@1.2.8': + resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/visitor-keys@8.40.0': - resolution: {integrity: sha512-8CZ47QwalyRjsypfwnbI3hKy5gJDPmrkLjkgMxhi0+DZZ2QNx2naS6/hWoVYUHU7LU2zleF68V9miaVZvhFfTA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/visitor-keys@8.48.0': - resolution: {integrity: sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - - '@unrs/resolver-binding-android-arm-eabi@1.11.1': - resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} - cpu: [arm] - os: [android] - - '@unrs/resolver-binding-android-arm64@1.11.1': - resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} - cpu: [arm64] - os: [android] - - '@unrs/resolver-binding-darwin-arm64@1.11.1': - resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} - cpu: [arm64] - os: [darwin] - - '@unrs/resolver-binding-darwin-x64@1.11.1': - resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} - cpu: [x64] - os: [darwin] - - '@unrs/resolver-binding-freebsd-x64@1.11.1': - resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} - cpu: [x64] - os: [freebsd] - - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} - cpu: [arm] - os: [linux] - - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} - cpu: [arm] - os: [linux] - - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} - cpu: [arm64] - os: [linux] - - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} - cpu: [arm64] - os: [linux] - - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} - cpu: [ppc64] - os: [linux] - - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} - cpu: [riscv64] - os: [linux] - - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} - cpu: [riscv64] - os: [linux] - - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} - cpu: [s390x] - os: [linux] - - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} - cpu: [x64] - os: [linux] - - '@unrs/resolver-binding-linux-x64-musl@1.11.1': - resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} - cpu: [x64] - os: [linux] - - '@unrs/resolver-binding-wasm32-wasi@1.11.1': - resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} - cpu: [arm64] - os: [win32] + '@radix-ui/react-portal@1.1.9': + resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} - cpu: [ia32] - os: [win32] + '@radix-ui/react-presence@1.1.5': + resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} - cpu: [x64] - os: [win32] + '@radix-ui/react-primitive@2.1.3': + resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@upstash/redis@1.35.3': - resolution: {integrity: sha512-hSjv66NOuahW3MisRGlSgoszU2uONAY2l5Qo3Sae8OT3/Tng9K+2/cBRuyPBX8egwEGcNNCF9+r0V6grNnhL+w==} + '@radix-ui/react-roving-focus@1.1.11': + resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@vitejs/plugin-react@4.7.0': - resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} - engines: {node: ^14.18.0 || >=16.0.0} + '@radix-ui/react-slot@1.2.3': + resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@vitest/expect@3.2.4': - resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} + '@radix-ui/react-tabs@1.1.13': + resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true - '@vitest/mocker@3.2.4': - resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + '@radix-ui/react-toast@1.2.15': + resolution: {integrity: sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==} peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: - msw: + '@types/react': optional: true - vite: + '@types/react-dom': optional: true - '@vitest/pretty-format@3.2.4': - resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} + '@radix-ui/react-use-callback-ref@1.1.1': + resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@vitest/runner@3.2.4': - resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} + '@radix-ui/react-use-controllable-state@1.2.2': + resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@vitest/snapshot@3.2.4': - resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} + '@radix-ui/react-use-effect-event@0.0.2': + resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@vitest/spy@3.2.4': - resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} + '@radix-ui/react-use-escape-keydown@1.1.1': + resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@vitest/utils@3.2.4': - resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@radix-ui/react-use-layout-effect@1.1.1': + resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@wagmi/connectors@5.9.4': - resolution: {integrity: sha512-k/GSdYS6nuL0zLq5H7XasPmKr3Gnvplq+yQhTfRBu/o5Bh+B3aH3Jfq1lUh+t3z5kQcyKJIXw/bZIZ7lVS7UhA==} + '@radix-ui/react-use-rect@1.1.1': + resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} peerDependencies: - '@wagmi/core': 2.19.0 - typescript: '>=5.0.4' - viem: 2.x + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: - typescript: + '@types/react': optional: true - '@wagmi/connectors@6.2.0': - resolution: {integrity: sha512-2NfkbqhNWdjfibb4abRMrn7u6rPjEGolMfApXss6HCDVt9AW2oVC6k8Q5FouzpJezElxLJSagWz9FW1zaRlanA==} + '@radix-ui/react-use-size@1.1.1': + resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} peerDependencies: - '@wagmi/core': 2.22.1 - typescript: '>=5.0.4' - viem: 2.x + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: - typescript: + '@types/react': optional: true - '@wagmi/core@2.19.0': - resolution: {integrity: sha512-lI57q6refAtNU6xnk/oyOpbEtEiwQ6g4rR+C9FEx8Gn2hZlfoyyksndrl6hIKlMBK+UkkKso3VwR5DI65j/5XQ==} + '@radix-ui/react-visually-hidden@1.2.3': + resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} peerDependencies: - '@tanstack/query-core': '>=5.0.0' - typescript: '>=5.0.4' - viem: 2.x + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: - '@tanstack/query-core': + '@types/react': optional: true - typescript: + '@types/react-dom': optional: true - '@wagmi/core@2.22.1': - resolution: {integrity: sha512-cG/xwQWsBEcKgRTkQVhH29cbpbs/TdcUJVFXCyri3ZknxhMyGv0YEjTcrNpRgt2SaswL1KrvslSNYKKo+5YEAg==} + '@radix-ui/rect@1.1.1': + resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} + + '@react-native/assets-registry@0.85.2': + resolution: {integrity: sha512-kauC/oPaxklU4Y+u9gBfCBJm51qX6WBZq4xx0USCdimtp+G8+554kpygfSWIjoqCJa2o06bWxBEjesiuCv+LzA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/codegen@0.85.2': + resolution: {integrity: sha512-XCginmxh0//++EXVOEJHBVZxHla294FzLCFF6jXwAUjvXVhqyIKyxhABfz+r4OOmaiuWk4Rtd4arqdAzeHeprg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} peerDependencies: - '@tanstack/query-core': '>=5.0.0' - typescript: '>=5.0.4' - viem: 2.x + '@babel/core': '*' + + '@react-native/community-cli-plugin@0.85.2': + resolution: {integrity: sha512-3KLgSg1kHvBpr93zMaQhvfYTgnCw7yZRED+3J4dMcYjfSjtD0Wf8SofU6uBmAw9JaVYvP43lpdwUpI4p0+ABsg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@react-native-community/cli': '*' + '@react-native/metro-config': 0.85.2 peerDependenciesMeta: - '@tanstack/query-core': + '@react-native-community/cli': optional: true - typescript: + '@react-native/metro-config': optional: true - '@wallet-standard/app@1.1.0': - resolution: {integrity: sha512-3CijvrO9utx598kjr45hTbbeeykQrQfKmSnxeWOgU25TOEpvcipD/bYDQWIqUv1Oc6KK4YStokSMu/FBNecGUQ==} - engines: {node: '>=16'} + '@react-native/debugger-frontend@0.85.2': + resolution: {integrity: sha512-j+0b9H5f5hGTLQxHIhJU/b/W6ijuxJF+ZTLHB0se2kzUBNxFKd7DkIc6753qk3CJdiv55vxG3XDgmlpbHxOpmA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - '@wallet-standard/base@1.1.0': - resolution: {integrity: sha512-DJDQhjKmSNVLKWItoKThJS+CsJQjR9AOBOirBVT1F9YpRyC9oYHE+ZnSf8y8bxUphtKqdQMPVQ2mHohYdRvDVQ==} - engines: {node: '>=16'} + '@react-native/debugger-shell@0.85.2': + resolution: {integrity: sha512-r5BkhqPMfg3LmaZS5zadHmBNVH5h4bhSpv4BEPGfK4gat9HABAMzUzybi+2wpgU3SoHxnyKGdExEJvoqVcjeRg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - '@wallet-standard/features@1.1.0': - resolution: {integrity: sha512-hiEivWNztx73s+7iLxsuD1sOJ28xtRix58W7Xnz4XzzA/pF0+aicnWgjOdA10doVDEDZdUuZCIIqG96SFNlDUg==} - engines: {node: '>=16'} + '@react-native/dev-middleware@0.85.2': + resolution: {integrity: sha512-3J+NaDUg+QEfDeLAUzgaWhpaxEg78g+KwbydlDCewh2G6WnHpsty8XooruxNHzyAsqVWywZMrzmbn78Ctc1O9Q==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - '@walletconnect/core@2.21.0': - resolution: {integrity: sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==} - engines: {node: '>=18'} + '@react-native/gradle-plugin@0.85.2': + resolution: {integrity: sha512-YXBOLeAqFrv7XwUeBPTKZeOV1FIxn4AW7UAEitScf3ibC8bu8+6NpJu4HWgbNQHg7vDbbTZVbcOl8EwGxsSq2w==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - '@walletconnect/core@2.21.1': - resolution: {integrity: sha512-Tp4MHJYcdWD846PH//2r+Mu4wz1/ZU/fr9av1UWFiaYQ2t2TPLDiZxjLw54AAEpMqlEHemwCgiRiAmjR1NDdTQ==} - engines: {node: '>=18'} + '@react-native/js-polyfills@0.85.2': + resolution: {integrity: sha512-esGEAmKVM40DV/yVmNljCKZTIeUo7qXqc+Hwffkv3TG+b3E24xyFovHrbP98gGxZr2ZsEyx+2sKLdXF5asY5nw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - '@walletconnect/environment@1.0.1': - resolution: {integrity: sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==} + '@react-native/normalize-colors@0.85.2': + resolution: {integrity: sha512-svuOLtjbFGXDdHsriHXuND5FgHg7XlkOXCbH/8+X4t76YLH6qSTffSIQQrKLDL5mn4EFU+Oh/PNO0/FfpnTOTg==} - '@walletconnect/ethereum-provider@2.21.1': - resolution: {integrity: sha512-SSlIG6QEVxClgl1s0LMk4xr2wg4eT3Zn/Hb81IocyqNSGfXpjtawWxKxiC5/9Z95f1INyBD6MctJbL/R1oBwIw==} + '@react-native/virtualized-lists@0.85.2': + resolution: {integrity: sha512-wmVKpAlcr+UB0L5SpbrV865EdleUP7I5+X+48e1aRsQK8q+wsTRBXeUwWVip/1l+HZwlZFeO8iOILJ16VRu0Cw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@types/react': ^19.2.0 + react: '*' + react-native: 0.85.2 + peerDependenciesMeta: + '@types/react': + optional: true - '@walletconnect/events@1.0.1': - resolution: {integrity: sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==} + '@redis/bloom@5.12.1': + resolution: {integrity: sha512-PUUfv+ms7jgPSBVoo/DN4AkPHj4D5TZSd6SbJX7egzBplkYUcKmHRE8RKia7UtZ8bSQbLguLvxVO+asKtQfZWA==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 - '@walletconnect/heartbeat@1.2.2': - resolution: {integrity: sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==} + '@redis/client@5.12.1': + resolution: {integrity: sha512-7aPGWeqA3uFm43o19umzdl16CEjK/JQGtSXVPevplTaOU3VJA/rseBC1QvYUz9lLDIMBimc4SW/zrW4S89BaCA==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@node-rs/xxhash': ^1.1.0 + '@opentelemetry/api': '>=1 <2' + peerDependenciesMeta: + '@node-rs/xxhash': + optional: true + '@opentelemetry/api': + optional: true - '@walletconnect/jsonrpc-http-connection@1.0.8': - resolution: {integrity: sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==} + '@redis/json@5.12.1': + resolution: {integrity: sha512-eOze75esLve4vfqDel7aMX08CNaiLLQS2fV8mpRN9NxPe1rVR4vQyYiW/OgtGUysF6QOr9ANhfxABKNOJfXdKg==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 - '@walletconnect/jsonrpc-provider@1.0.14': - resolution: {integrity: sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==} + '@redis/search@5.12.1': + resolution: {integrity: sha512-ItlxbxC9cKI6IU1TLWoczwJCRb6TdmkEpWv05UrPawqaAnWGRu3rcIqsc5vN483T2fSociuyV1UkWIL5I4//2w==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 - '@walletconnect/jsonrpc-types@1.0.4': - resolution: {integrity: sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==} + '@redis/time-series@5.12.1': + resolution: {integrity: sha512-c6JL6E3EcZJuNqKFz+KM+l9l5mpcQiKvTwgA3blt5glWJ8hjDk0yeHN3beE/MpqYIQ8UEX44ItQzgkE/gCBELQ==} + engines: {node: '>= 18.19.0'} + peerDependencies: + '@redis/client': ^5.12.1 - '@walletconnect/jsonrpc-utils@1.0.8': - resolution: {integrity: sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==} + '@reown/appkit-common@1.7.8': + resolution: {integrity: sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==} - '@walletconnect/jsonrpc-ws-connection@1.0.16': - resolution: {integrity: sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==} + '@reown/appkit-controllers@1.7.8': + resolution: {integrity: sha512-IdXlJlivrlj6m63VsGLsjtPHHsTWvKGVzWIP1fXZHVqmK+rZCBDjCi9j267Rb9/nYRGHWBtlFQhO8dK35WfeDA==} - '@walletconnect/keyvaluestorage@1.1.1': - resolution: {integrity: sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==} + '@reown/appkit-pay@1.7.8': + resolution: {integrity: sha512-OSGQ+QJkXx0FEEjlpQqIhT8zGJKOoHzVnyy/0QFrl3WrQTjCzg0L6+i91Ad5Iy1zb6V5JjqtfIFpRVRWN4M3pw==} + + '@reown/appkit-polyfills@1.7.8': + resolution: {integrity: sha512-W/kq786dcHHAuJ3IV2prRLEgD/2iOey4ueMHf1sIFjhhCGMynMkhsOhQMUH0tzodPqUgAC494z4bpIDYjwWXaA==} + + '@reown/appkit-scaffold-ui@1.7.8': + resolution: {integrity: sha512-RCeHhAwOrIgcvHwYlNWMcIDibdI91waaoEYBGw71inE0kDB8uZbE7tE6DAXJmDkvl0qPh+DqlC4QbJLF1FVYdQ==} + + '@reown/appkit-ui@1.7.8': + resolution: {integrity: sha512-1hjCKjf6FLMFzrulhl0Y9Vb9Fu4royE+SXCPSWh4VhZhWqlzUFc7kutnZKx8XZFVQH4pbBvY62SpRC93gqoHow==} + + '@reown/appkit-utils@1.7.8': + resolution: {integrity: sha512-8X7UvmE8GiaoitCwNoB86pttHgQtzy4ryHZM9kQpvjQ0ULpiER44t1qpVLXNM4X35O0v18W0Dk60DnYRMH2WRw==} peerDependencies: - '@react-native-async-storage/async-storage': 1.x - peerDependenciesMeta: - '@react-native-async-storage/async-storage': - optional: true + valtio: 1.13.2 - '@walletconnect/logger@2.1.2': - resolution: {integrity: sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==} + '@reown/appkit-wallet@1.7.8': + resolution: {integrity: sha512-kspz32EwHIOT/eg/ZQbFPxgXq0B/olDOj3YMu7gvLEFz4xyOFd/wgzxxAXkp5LbG4Cp++s/elh79rVNmVFdB9A==} - '@walletconnect/relay-api@1.0.11': - resolution: {integrity: sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==} + '@reown/appkit@1.7.8': + resolution: {integrity: sha512-51kTleozhA618T1UvMghkhKfaPcc9JlKwLJ5uV+riHyvSoWPKPRIa5A6M1Wano5puNyW0s3fwywhyqTHSilkaA==} - '@walletconnect/relay-auth@1.1.0': - resolution: {integrity: sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==} + '@rollup/rollup-android-arm-eabi@4.46.4': + resolution: {integrity: sha512-B2wfzCJ+ps/OBzRjeds7DlJumCU3rXMxJJS1vzURyj7+KBHGONm7c9q1TfdBl4vCuNMkDvARn3PBl2wZzuR5mw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.46.4': + resolution: {integrity: sha512-FGJYXvYdn8Bs6lAlBZYT5n+4x0ciEp4cmttsvKAZc/c8/JiPaQK8u0c/86vKX8lA7OY/+37lIQSe0YoAImvBAA==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.46.4': + resolution: {integrity: sha512-/9qwE/BM7ATw/W/OFEMTm3dmywbJyLQb4f4v5nmOjgYxPIGpw7HaxRi6LnD4Pjn/q7k55FGeHe1/OD02w63apA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.46.4': + resolution: {integrity: sha512-QkWfNbeRuzFnv2d0aPlrzcA3Ebq2mE8kX/5Pl7VdRShbPBjSnom7dbT8E3Jmhxo2RL784hyqGvR5KHavCJQciw==} + cpu: [x64] + os: [darwin] - '@walletconnect/safe-json@1.0.2': - resolution: {integrity: sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==} + '@rollup/rollup-freebsd-arm64@4.46.4': + resolution: {integrity: sha512-+ToyOMYnSfV8D+ckxO6NthPln/PDNp1P6INcNypfZ7muLmEvPKXqduUiD8DlJpMMT8LxHcE5W0dK9kXfJke9Zw==} + cpu: [arm64] + os: [freebsd] - '@walletconnect/sign-client@2.21.0': - resolution: {integrity: sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==} + '@rollup/rollup-freebsd-x64@4.46.4': + resolution: {integrity: sha512-cGT6ey/W+sje6zywbLiqmkfkO210FgRz7tepWAzzEVgQU8Hn91JJmQWNqs55IuglG8sJdzk7XfNgmGRtcYlo1w==} + cpu: [x64] + os: [freebsd] - '@walletconnect/sign-client@2.21.1': - resolution: {integrity: sha512-QaXzmPsMnKGV6tc4UcdnQVNOz4zyXgarvdIQibJ4L3EmLat73r5ZVl4c0cCOcoaV7rgM9Wbphgu5E/7jNcd3Zg==} + '@rollup/rollup-linux-arm-gnueabihf@4.46.4': + resolution: {integrity: sha512-9fhTJyOb275w5RofPSl8lpr4jFowd+H4oQKJ9XTYzD1JWgxdZKE8bA6d4npuiMemkecQOcigX01FNZNCYnQBdA==} + cpu: [arm] + os: [linux] + libc: [glibc] - '@walletconnect/time@1.0.2': - resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} + '@rollup/rollup-linux-arm-musleabihf@4.46.4': + resolution: {integrity: sha512-+6kCIM5Zjvz2HwPl/udgVs07tPMIp1VU2Y0c72ezjOvSvEfAIWsUgpcSDvnC7g9NrjYR6X9bZT92mZZ90TfvXw==} + cpu: [arm] + os: [linux] + libc: [musl] - '@walletconnect/types@2.21.0': - resolution: {integrity: sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==} + '@rollup/rollup-linux-arm64-gnu@4.46.4': + resolution: {integrity: sha512-SWuXdnsayCZL4lXoo6jn0yyAj7TTjWE4NwDVt9s7cmu6poMhtiras5c8h6Ih6Y0Zk6Z+8t/mLumvpdSPTWub2Q==} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@walletconnect/types@2.21.1': - resolution: {integrity: sha512-UeefNadqP6IyfwWC1Yi7ux+ljbP2R66PLfDrDm8izmvlPmYlqRerJWJvYO4t0Vvr9wrG4Ko7E0c4M7FaPKT/sQ==} + '@rollup/rollup-linux-arm64-musl@4.46.4': + resolution: {integrity: sha512-vDknMDqtMhrrroa5kyX6tuC0aRZZlQ+ipDfbXd2YGz5HeV2t8HOl/FDAd2ynhs7Ki5VooWiiZcCtxiZ4IjqZwQ==} + cpu: [arm64] + os: [linux] + libc: [musl] - '@walletconnect/universal-provider@2.21.0': - resolution: {integrity: sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==} + '@rollup/rollup-linux-loongarch64-gnu@4.46.4': + resolution: {integrity: sha512-mCBkjRZWhvjtl/x+Bd4fQkWZT8canStKDxGrHlBiTnZmJnWygGcvBylzLVCZXka4dco5ymkWhZlLwKCGFF4ivw==} + cpu: [loong64] + os: [linux] + libc: [glibc] - '@walletconnect/universal-provider@2.21.1': - resolution: {integrity: sha512-Wjx9G8gUHVMnYfxtasC9poGm8QMiPCpXpbbLFT+iPoQskDDly8BwueWnqKs4Mx2SdIAWAwuXeZ5ojk5qQOxJJg==} + '@rollup/rollup-linux-ppc64-gnu@4.46.4': + resolution: {integrity: sha512-YMdz2phOTFF+Z66dQfGf0gmeDSi5DJzY5bpZyeg9CPBkV9QDzJ1yFRlmi/j7WWRf3hYIWrOaJj5jsfwgc8GTHQ==} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@walletconnect/utils@2.21.0': - resolution: {integrity: sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==} + '@rollup/rollup-linux-riscv64-gnu@4.46.4': + resolution: {integrity: sha512-r0WKLSfFAK8ucG024v2yiLSJMedoWvk8yWqfNICX28NHDGeu3F/wBf8KG6mclghx4FsLePxJr/9N8rIj1PtCnw==} + cpu: [riscv64] + os: [linux] + libc: [glibc] - '@walletconnect/utils@2.21.1': - resolution: {integrity: sha512-VPZvTcrNQCkbGOjFRbC24mm/pzbRMUq2DSQoiHlhh0X1U7ZhuIrzVtAoKsrzu6rqjz0EEtGxCr3K1TGRqDG4NA==} + '@rollup/rollup-linux-riscv64-musl@4.46.4': + resolution: {integrity: sha512-IaizpPP2UQU3MNyPH1u0Xxbm73D+4OupL0bjo4Hm0496e2wg3zuvoAIhubkD1NGy9fXILEExPQy87mweujEatA==} + cpu: [riscv64] + os: [linux] + libc: [musl] - '@walletconnect/window-getters@1.0.1': - resolution: {integrity: sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==} + '@rollup/rollup-linux-s390x-gnu@4.46.4': + resolution: {integrity: sha512-aCM29orANR0a8wk896p6UEgIfupReupnmISz6SUwMIwTGaTI8MuKdE0OD2LvEg8ondDyZdMvnaN3bW4nFbATPA==} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@walletconnect/window-metadata@1.0.1': - resolution: {integrity: sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==} + '@rollup/rollup-linux-x64-gnu@4.46.4': + resolution: {integrity: sha512-0Xj1vZE3cbr/wda8d/m+UeuSL+TDpuozzdD4QaSzu/xSOMK0Su5RhIkF7KVHFQsobemUNHPLEcYllL7ZTCP/Cg==} + cpu: [x64] + os: [linux] + libc: [glibc] - '@xmldom/xmldom@0.8.11': - resolution: {integrity: sha512-cQzWCtO6C8TQiYl1ruKNn2U6Ao4o4WBBcbL61yJl84x+j5sOWWFU9X7DpND8XZG3daDppSsigMdfAIl2upQBRw==} - engines: {node: '>=10.0.0'} + '@rollup/rollup-linux-x64-musl@4.46.4': + resolution: {integrity: sha512-kM/orjpolfA5yxsx84kI6bnK47AAZuWxglGKcNmokw2yy9i5eHY5UAjcX45jemTJnfHAWo3/hOoRqEeeTdL5hw==} + cpu: [x64] + os: [linux] + libc: [musl] - abbrev@1.1.1: - resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + '@rollup/rollup-win32-arm64-msvc@4.46.4': + resolution: {integrity: sha512-cNLH4psMEsWKILW0isbpQA2OvjXLbKvnkcJFmqAptPQbtLrobiapBJVj6RoIvg6UXVp5w0wnIfd/Q56cNpF+Ew==} + cpu: [arm64] + os: [win32] - abitype@1.0.6: - resolution: {integrity: sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3 >=3.22.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true + '@rollup/rollup-win32-ia32-msvc@4.46.4': + resolution: {integrity: sha512-OiEa5lRhiANpv4SfwYVgQ3opYWi/QmPDC5ve21m8G9pf6ZO+aX1g2EEF1/IFaM1xPSP7mK0msTRXlPs6mIagkg==} + cpu: [ia32] + os: [win32] - abitype@1.0.8: - resolution: {integrity: sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3 >=3.22.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true + '@rollup/rollup-win32-x64-msvc@4.46.4': + resolution: {integrity: sha512-IKL9mewGZ5UuuX4NQlwOmxPyqielvkAPUS2s1cl6yWjjQvyN3h5JTdVFGD5Jr5xMjRC8setOfGQDVgX8V+dkjg==} + cpu: [x64] + os: [win32] - abitype@1.1.0: - resolution: {integrity: sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true + '@rtsao/scc@1.1.0': + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} - abitype@1.2.3: - resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true + '@safe-global/safe-apps-provider@0.18.6': + resolution: {integrity: sha512-4LhMmjPWlIO8TTDC2AwLk44XKXaK6hfBTWyljDm0HQ6TWlOEijVWNrt2s3OCVMSxlXAcEzYfqyu1daHZooTC2Q==} - abort-controller@3.0.0: - resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} - engines: {node: '>=6.5'} + '@safe-global/safe-apps-sdk@9.1.0': + resolution: {integrity: sha512-N5p/ulfnnA2Pi2M3YeWjULeWbjo7ei22JwU/IXnhoHzKq3pYCN6ynL9mJBOlvDVv892EgLPCWCOwQk/uBT2v0Q==} - abstract-logging@2.0.1: - resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} + '@safe-global/safe-gateway-typescript-sdk@3.23.1': + resolution: {integrity: sha512-6ORQfwtEJYpalCeVO21L4XXGSdbEMfyp2hEv6cP82afKXSwvse6d3sdelgaPWUxHIsFRkWvHDdzh8IyyKHZKxw==} + engines: {node: '>=16'} - accepts@1.3.8: - resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} - engines: {node: '>= 0.6'} + '@scure/base@1.1.9': + resolution: {integrity: sha512-8YKhl8GHiNI/pU2VMaofa2Tor7PJRAjwQLBBuilkJ9L5+13yVbC7JO/wS7piioAvPSwR3JKM1IJ/u4xQzbcXKg==} - accepts@2.0.0: - resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} - engines: {node: '>= 0.6'} + '@scure/base@1.2.6': + resolution: {integrity: sha512-g/nm5FgUa//MCj1gV09zTJTaM6KBAHqLN907YVQqf7zC49+DcO4B1so4ZX07Ef10Twr6nuqYEH9GEggFXA4Fmg==} - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + '@scure/bip32@1.4.0': + resolution: {integrity: sha512-sVUpc0Vq3tXCkDGYVWGIZTRfnvu8LoTDaev7vbwh0omSvVORONr960MQWdKqJDCReIEmTj3PAr73O3aoxz7OPg==} - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} - engines: {node: '>=0.4.0'} - hasBin: true + '@scure/bip32@1.6.2': + resolution: {integrity: sha512-t96EPDMbtGgtb7onKKqxRLfE5g05k7uHnHRM2xdE6BP/ZmxaLtPek4J4KfVn/90IQNrU1IOAqMgiDtUdtbe3nw==} - aes-js@4.0.0-beta.5: - resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} + '@scure/bip32@1.7.0': + resolution: {integrity: sha512-E4FFX/N3f4B80AKWp5dP6ow+flD1LQZo/w8UnLGYZO674jS6YnYeepycOOksv+vLPSpgN35wgKgy+ybfTb2SMw==} - agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} + '@scure/bip39@1.3.0': + resolution: {integrity: sha512-disdg7gHuTDZtY+ZdkmLpPCk7fxZSu3gBiEGuoC1XYxv9cGx3Z6cpTggCgW6odSOOIXCiDjuGejW+aJKCY/pIQ==} - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} + '@scure/bip39@1.5.4': + resolution: {integrity: sha512-TFM4ni0vKvCfBpohoh+/lY05i9gRbSwXWngAsF4CABQxoaOHijxuaZ2R6cStDQ5CHtHO9aGJTr4ksVJASRRyMA==} - agentkeepalive@4.6.0: - resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} - engines: {node: '>= 8.0.0'} + '@scure/bip39@1.6.0': + resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} - aggregate-error@3.1.0: - resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} - engines: {node: '>=8'} + '@signinwithethereum/siwe-parser@4.2.0': + resolution: {integrity: sha512-e3edh8XpZrEjbzVYc0BZ4ySFOa8RKTZOQTafSf1E6ejCB5XcBH93jEpYmjzry1EEocgMNq4KlB3YunsFNCXakQ==} - ajv-formats@3.0.1: - resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + '@signinwithethereum/siwe@4.2.0': + resolution: {integrity: sha512-6W+oyKgMFUZRJI4o9P9mTMzrokkXfu3tq1/CfOJj9QrMqyPqujJqv1xnxUAqDQwWVyCA8TMg0Fxk/+gXrDg2Nw==} peerDependencies: - ajv: ^8.0.0 + ethers: ^5.7.0 || ^6.13.0 + viem: ^2.7.0 peerDependenciesMeta: - ajv: + ethers: + optional: true + viem: optional: true - ajv-keywords@3.5.2: - resolution: {integrity: sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==} - peerDependencies: - ajv: ^6.9.1 - - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-regex@6.2.0: - resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} - engines: {node: '>=12'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} + '@sinclair/typebox@0.27.10': + resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + '@sindresorhus/is@4.6.0': + resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} - ansi-styles@6.2.1: - resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} - engines: {node: '>=12'} - - any-promise@1.3.0: - resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + '@socket.io/component-emitter@3.1.2': + resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + '@solana-program/compute-budget@0.11.0': + resolution: {integrity: sha512-7f1ePqB/eURkTwTOO9TNIdUXZcyrZoX3Uy2hNo7cXMfNhPFWp9AVgIyRNBc2jf15sdUa9gNpW+PfP2iV8AYAaw==} + peerDependencies: + '@solana/kit': ^5.0 - apg-js@4.4.0: - resolution: {integrity: sha512-fefmXFknJmtgtNEXfPwZKYkMFX4Fyeyz+fNF6JWp87biGOPslJbCBVU158zvKRZfHBKnJDy8CMM40oLFGkXT8Q==} + '@solana-program/compute-budget@0.8.0': + resolution: {integrity: sha512-qPKxdxaEsFxebZ4K5RPuy7VQIm/tfJLa1+Nlt3KNA8EYQkz9Xm8htdoEaXVrer9kpgzzp9R3I3Bh6omwCM06tQ==} + peerDependencies: + '@solana/kit': ^2.1.0 - app-builder-bin@5.0.0-alpha.12: - resolution: {integrity: sha512-j87o0j6LqPL3QRr8yid6c+Tt5gC7xNfYo6uQIQkorAC6MpeayVMZrEDzKmJJ/Hlv7EnOQpaRm53k6ktDYZyB6w==} + '@solana-program/system@0.8.1': + resolution: {integrity: sha512-71U9Mzdpw8HQtfgfJSL5xKZbLMRnza2Llsfk7gGnmg2waqK+o8MMH4YNma8xXS1UmOBptXIiNvoZ3p7cmOVktg==} + peerDependencies: + '@solana/kit': ^3.0 - app-builder-lib@26.0.12: - resolution: {integrity: sha512-+/CEPH1fVKf6HowBUs6LcAIoRcjeqgvAeoSE+cl7Y7LndyQ9ViGPYibNk7wmhMHzNgHIuIbw4nWADPO+4mjgWw==} - engines: {node: '>=14.0.0'} + '@solana-program/token-2022@0.4.2': + resolution: {integrity: sha512-zIpR5t4s9qEU3hZKupzIBxJ6nUV5/UVyIT400tu9vT1HMs5JHxaTTsb5GUhYjiiTvNwU0MQavbwc4Dl29L0Xvw==} peerDependencies: - dmg-builder: 26.0.12 - electron-builder-squirrel-windows: 26.0.12 + '@solana/kit': ^2.1.0 + '@solana/sysvars': ^2.1.0 - are-docs-informative@0.0.2: - resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} - engines: {node: '>=14'} + '@solana-program/token-2022@0.6.1': + resolution: {integrity: sha512-Ex02cruDMGfBMvZZCrggVR45vdQQSI/unHVpt/7HPt/IwFYB4eTlXtO8otYZyqV/ce5GqZ8S6uwyRf0zy6fdbA==} + peerDependencies: + '@solana/kit': ^5.0 + '@solana/sysvars': ^5.0 - arg@5.0.2: - resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + '@solana-program/token@0.5.1': + resolution: {integrity: sha512-bJvynW5q9SFuVOZ5vqGVkmaPGA0MCC+m9jgJj1nk5m20I389/ms69ASnhWGoOPNcie7S9OwBX0gTj2fiyWpfag==} + peerDependencies: + '@solana/kit': ^2.1.0 - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + '@solana-program/token@0.6.0': + resolution: {integrity: sha512-omkZh4Tt9rre4wzWHNOhOEHyenXQku3xyc/UrKvShexA/Qlhza67q7uRwmwEDUs4QqoDBidSZPooOmepnA/jig==} + peerDependencies: + '@solana/kit': ^3.0 - aria-hidden@1.2.6: - resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} - engines: {node: '>=10'} + '@solana-program/token@0.9.0': + resolution: {integrity: sha512-vnZxndd4ED4Fc56sw93cWZ2djEeeOFxtaPS8SPf5+a+JZjKA/EnKqzbE1y04FuMhIVrLERQ8uR8H2h72eZzlsA==} + peerDependencies: + '@solana/kit': ^5.0 - aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} - engines: {node: '>= 0.4'} + '@solana/accounts@2.3.0': + resolution: {integrity: sha512-QgQTj404Z6PXNOyzaOpSzjgMOuGwG8vC66jSDB+3zHaRcEPRVRd2sVSrd1U6sHtnV3aiaS6YyDuPQMheg4K2jw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} + '@solana/accounts@3.0.3': + resolution: {integrity: sha512-KqlePrlZaHXfu8YQTCxN204ZuVm9o68CCcUr6l27MG2cuRUtEM1Ta0iR8JFkRUAEfZJC4Cu0ZDjK/v49loXjZQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - array-flatten@1.1.1: - resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} + '@solana/accounts@5.1.0': + resolution: {integrity: sha512-Q1KzykCrl/YjLUH2RXF8vPq65U/ehAV2SHZicPbZ0jvgQUU6X1+Eca+0ilxA9xH8srYn3YTVDyEs/LYdfbY/2A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - array-includes@3.1.9: - resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} - engines: {node: '>= 0.4'} + '@solana/accounts@6.1.0': + resolution: {integrity: sha512-0jhmhSSS71ClLtBQIDrLlhkiNER4M9RIXTl1eJ1yJoFlE608JaKHTjNWsdVKdke7uBD6exdjNZkIVmouQPHMcA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - array-union@2.1.0: - resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} - engines: {node: '>=8'} + '@solana/addresses@2.3.0': + resolution: {integrity: sha512-ypTNkY2ZaRFpHLnHAgaW8a83N0/WoqdFvCqf4CQmnMdFsZSdC7qOwcbd7YzdaQn9dy+P2hybewzB+KP7LutxGA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - array.prototype.findlast@1.2.5: - resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} - engines: {node: '>= 0.4'} + '@solana/addresses@3.0.3': + resolution: {integrity: sha512-AuMwKhJI89ANqiuJ/fawcwxNKkSeHH9CApZd2xelQQLS7X8uxAOovpcmEgiObQuiVP944s9ScGUT62Bdul9qYg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - array.prototype.findlastindex@1.2.6: - resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} - engines: {node: '>= 0.4'} + '@solana/addresses@5.1.0': + resolution: {integrity: sha512-X84qSZLgve9YeYsyxGI49WnfEre53tdFu4x9/4oULBgoj8d0A+P9VGLYzmRJ0YFYKRcZG7U4u3MQpI5uLZ1AsQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - array.prototype.flat@1.3.3: - resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} - engines: {node: '>= 0.4'} + '@solana/addresses@6.1.0': + resolution: {integrity: sha512-QT04Vie4iICaalQQRJFMGj/P56IxXiwFtVuZHu1qjZUNmuGTOvX6G98b27RaGtLzpJ3NIku/6OtKxLUBqAKAyQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - array.prototype.flatmap@1.3.3: - resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} - engines: {node: '>= 0.4'} + '@solana/assertions@2.3.0': + resolution: {integrity: sha512-Ekoet3khNg3XFLN7MIz8W31wPQISpKUGDGTylLptI+JjCDWx3PIa88xjEMqFo02WJ8sBj2NLV64Xg1sBcsHjZQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - array.prototype.tosorted@1.1.4: - resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} - engines: {node: '>= 0.4'} + '@solana/assertions@3.0.3': + resolution: {integrity: sha512-2qspxdbWp2y62dfCIlqeWQr4g+hE8FYSSwcaP6itwMwGRb8393yDGCJfI/znuzJh6m/XVWhMHIgFgsBwnevCmg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - arraybuffer.prototype.slice@1.0.4: - resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} - engines: {node: '>= 0.4'} + '@solana/assertions@5.1.0': + resolution: {integrity: sha512-5But2wyxuvGXMIOnD0jBMQ9yq1QQF2LSK3IbIRSkAkXbD3DS6O2tRvKUHNhogd+BpkPyCGOQHBycezgnxmStlg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - assert-plus@1.0.0: - resolution: {integrity: sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==} - engines: {node: '>=0.8'} + '@solana/assertions@6.1.0': + resolution: {integrity: sha512-pLgxB2xxTk2QfTaWpnRpSMYgaPkKYDQgptRvbwmuDQnOW1Zopg+42MT2UrDGd3UFMML1uOFPxIwKM6m51H0uXw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} + '@solana/buffer-layout@4.0.1': + resolution: {integrity: sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==} + engines: {node: '>=5.10'} - ast-types-flow@0.0.8: - resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} + '@solana/codecs-core@2.3.0': + resolution: {integrity: sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - astral-regex@2.0.0: - resolution: {integrity: sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==} - engines: {node: '>=8'} + '@solana/codecs-core@3.0.3': + resolution: {integrity: sha512-emKykJ3h1DmnDOY29Uv9eJXP8E/FHzvlUBJ6te+5EbKdFjj7vdlKYPfDxOI6iGdXTY+YC/ELtbNBh6QwF2uEDQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - async-exit-hook@2.0.1: - resolution: {integrity: sha512-NW2cX8m1Q7KPA7a5M2ULQeZ2wR5qI5PAbw5L0UOMxdioVk9PMZ0h1TmyZEkPYrCvYjDlFICusOu1dlEKAAeXBw==} - engines: {node: '>=0.12.0'} + '@solana/codecs-core@5.1.0': + resolution: {integrity: sha512-vDwi03mxWeWCS5Il6BCdNdifYdOoHVz97YOmbWGIt45b77Ivu5NUYeSD2+ccl6fSw8eYQ6QaqqKXMjbSfsXv4g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - async-function@1.0.0: - resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} - engines: {node: '>= 0.4'} + '@solana/codecs-core@6.1.0': + resolution: {integrity: sha512-5rNnDOOm2GRFMJbd9imYCPNvGOrQ+TZ53NCkFFWbbB7f+L9KkLeuuAsDMFN1lCziJFlymvN785YtDnMeWj2W+g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - async-mutex@0.2.6: - resolution: {integrity: sha512-Hs4R+4SPgamu6rSGW8C7cV9gaWUKEHykfzCCvIRuaVv636Ju10ZdeUbvb4TBEW0INuq2DHZqXbK4Nd3yG4RaRw==} + '@solana/codecs-data-structures@2.3.0': + resolution: {integrity: sha512-qvU5LE5DqEdYMYgELRHv+HMOx73sSoV1ZZkwIrclwUmwTbTaH8QAJURBj0RhQ/zCne7VuLLOZFFGv6jGigWhSw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - async@3.2.6: - resolution: {integrity: sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==} + '@solana/codecs-data-structures@3.0.3': + resolution: {integrity: sha512-R15cLp8riJvToXziW8lP6AMSwsztGhEnwgyGmll32Mo0Yjq+hduW2/fJrA/TJs6tA/OgTzMQjlxgk009EqZHCw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - asynckit@0.4.0: - resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + '@solana/codecs-data-structures@5.1.0': + resolution: {integrity: sha512-ftAwL/jsurFrk9kFVhkTLdQ8fGZ8I0PcbVH+V1a0dIP2aKDofGePvK0XbwZE/ohizC9gEIZxyBX5IgRKk5PXyg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - at-least-node@1.0.0: - resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} - engines: {node: '>= 4.0.0'} + '@solana/codecs-data-structures@6.1.0': + resolution: {integrity: sha512-1cb9g5hrrucTuGkGxqVVq7dCwSMnn4YqwTe365iKkK8HBpLBmUl8XATf1MUs5UtDun1g9eNWOL72Psr8mIUqTQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - atomic-sleep@1.0.0: - resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} - engines: {node: '>=8.0.0'} + '@solana/codecs-numbers@2.3.0': + resolution: {integrity: sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} + '@solana/codecs-numbers@3.0.3': + resolution: {integrity: sha512-pfXkH9J0glrM8qj6389GAn30+cJOxzXLR2FsPOHCUMXrqLhGjMMZAWhsQkpOQ37SGc/7EiQsT/gmyGC7gxHqJQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - avvio@9.2.0: - resolution: {integrity: sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ==} + '@solana/codecs-numbers@5.1.0': + resolution: {integrity: sha512-Ea5/9yjDNOrDZcI40UGzzi6Aq1JNsmzM4m5pOk6Xb3JRZ0YdKOv/MwuCqb6jRgzZ7SQjHhkfGL43kHLJA++bOw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - axe-core@4.10.3: - resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} - engines: {node: '>=4'} + '@solana/codecs-numbers@6.1.0': + resolution: {integrity: sha512-YPQwwl6LE3igH23ah+d8kgpyE5xFcPbuwhxCDsLWqY/ESrvO/0YQSbsgIXahbhZxN59ZC4uq1LnHhBNbpCSVQg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - axios-mock-adapter@1.22.0: - resolution: {integrity: sha512-dmI0KbkyAhntUR05YY96qg2H6gg0XMl2+qTW0xmYg6Up+BFBAJYRLROMXRdDEL06/Wqwa0TJThAYvFtSFdRCZw==} + '@solana/codecs-strings@2.3.0': + resolution: {integrity: sha512-y5pSBYwzVziXu521hh+VxqUtp0hYGTl1eWGoc1W+8mdvBdC1kTqm/X7aYQw33J42hw03JjryvYOvmGgk3Qz/Ug==} + engines: {node: '>=20.18.0'} peerDependencies: - axios: '>= 0.17.0' + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.3.3' - axios-retry@4.5.0: - resolution: {integrity: sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==} + '@solana/codecs-strings@3.0.3': + resolution: {integrity: sha512-VHBXnnTVtcQ1j+7Vrz+qSYo38no+jiHRdGnhFspRXEHNJbllzwKqgBE7YN3qoIXH+MKxgJUcwO5KHmdzf8Wn2A==} + engines: {node: '>=20.18.0'} peerDependencies: - axios: 0.x || 1.x + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.3.3' - axios@1.13.2: - resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} + '@solana/codecs-strings@5.1.0': + resolution: {integrity: sha512-014xwl5T/3VnGW0gceizF47DUs5EURRtgGmbWIR5+Z32yxgQ6hT9Zl0atZbL268RHbUQ03/J8Ush1StQgy7sfQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.3.3' + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true - axios@1.13.4: - resolution: {integrity: sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==} + '@solana/codecs-strings@6.1.0': + resolution: {integrity: sha512-pRH5uAn4VCFUs2rYiDITyWsRnpvs3Uh/nhSc6OSP/kusghcCcCJcUzHBIjT4x08MVacXmGUlSLe/9qPQO+QK3Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: ^5.0.0 + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true - axobject-query@4.1.0: - resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} - engines: {node: '>= 0.4'} + '@solana/codecs@2.3.0': + resolution: {integrity: sha512-JVqGPkzoeyU262hJGdH64kNLH0M+Oew2CIPOa/9tR3++q2pEd4jU2Rxdfye9sd0Ce3XJrR5AIa8ZfbyQXzjh+g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@solana/codecs@3.0.3': + resolution: {integrity: sha512-GOHwTlIQsCoJx9Ryr6cEf0FHKAQ7pY4aO4xgncAftrv0lveTQ1rPP2inQ1QT0gJllsIa8nwbfXAADs9nNJxQDA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - babel-plugin-polyfill-corejs2@0.4.14: - resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} + '@solana/codecs@5.1.0': + resolution: {integrity: sha512-krSuf/E2Sa/4oASZ/jb/5KGUG58m1/bQdLrKvBnoAFhYj7zZf+8V4UqHGTV5n2NCQfmMyORsg9n2saKjkUzo8w==} + engines: {node: '>=20.18.0'} peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + typescript: '>=5.3.3' - babel-plugin-polyfill-corejs3@0.13.0: - resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} + '@solana/codecs@6.1.0': + resolution: {integrity: sha512-VHBS3t8fyVjE0Nqo6b4TUnzdwdRaVo+B5ufHhPLbbjkEXzz8HB4E/OBjgasn+zWGlfScfQAiBFOsfZjbVWu4XA==} + engines: {node: '>=20.18.0'} peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - babel-plugin-polyfill-regenerator@0.6.5: - resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==} + '@solana/errors@2.3.0': + resolution: {integrity: sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==} + engines: {node: '>=20.18.0'} + hasBin: true peerDependencies: - '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - base-x@3.0.11: - resolution: {integrity: sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==} + typescript: '>=5.3.3' - base-x@4.0.1: - resolution: {integrity: sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==} + '@solana/errors@3.0.3': + resolution: {integrity: sha512-1l84xJlHNva6io62PcYfUamwWlc0eM95nHgCrKX0g0cLoC6D6QHYPCEbEVkR+C5UtP9JDgyQM8MFiv+Ei5tO9Q==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.3.3' - base-x@5.0.1: - resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==} + '@solana/errors@5.1.0': + resolution: {integrity: sha512-JlTyekErWa6Fdcwu1Hrh+jZxjM4YxyorGCFDRVZlmHZFkp5N00DWKcYnSGZrTF8E6ZZEP9pfS2XwM8y7p7HPww==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.3.3' - base32.js@0.1.0: - resolution: {integrity: sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==} - engines: {node: '>=0.12.0'} + '@solana/errors@6.1.0': + resolution: {integrity: sha512-cqSwcw3Rmn85UR7PyF5nKPdlQsRYBkx7YGRvFaJ6Sal1PM+bfolhL5iT7STQoXxdhXGYwHMPg7kZYxmMdjwnJA==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + '@solana/fast-stable-stringify@2.3.0': + resolution: {integrity: sha512-KfJPrMEieUg6D3hfQACoPy0ukrAV8Kio883llt/8chPEG3FVTX9z/Zuf4O01a15xZmBbmQ7toil2Dp0sxMJSxw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - big.js@6.2.2: - resolution: {integrity: sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==} + '@solana/fast-stable-stringify@3.0.3': + resolution: {integrity: sha512-ED0pxB6lSEYvg+vOd5hcuQrgzEDnOrURFgp1ZOY+lQhJkQU6xo+P829NcJZQVP1rdU2/YQPAKJKEseyfe9VMIw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bigint-buffer@1.1.5: - resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} - engines: {node: '>= 10.0.0'} + '@solana/fast-stable-stringify@5.1.0': + resolution: {integrity: sha512-ACZo7cH/5EXsBmruw/0gU2/PXL2l4aET0YpL93H6QEaZwEAICFD8cLkj20nBcfLTf4srEiuKtwuSDeONTWIulw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bignumber.js@9.3.1: - resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + '@solana/fast-stable-stringify@6.1.0': + resolution: {integrity: sha512-QXUfDFaJCFeARsxJgScWmJ153Tit7Cimk9y0UWWreNBr2Aphi67Nlcj/tr7UABTO0Qaw/0gwrK76zz3m1t3nIw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} + '@solana/functional@2.3.0': + resolution: {integrity: sha512-AgsPh3W3tE+nK3eEw/W9qiSfTGwLYEvl0rWaxHht/lRcuDVwfKRzeSa5G79eioWFFqr+pTtoCr3D3OLkwKz02Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + '@solana/functional@3.0.3': + resolution: {integrity: sha512-2qX1kKANn8995vOOh5S9AmF4ItGZcfbny0w28Eqy8AFh+GMnSDN4gqpmV2LvxBI9HibXZptGH3RVOMk82h1Mpw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bip32@4.0.0: - resolution: {integrity: sha512-aOGy88DDlVUhspIXJN+dVEtclhIsfAUppD43V0j40cPTld3pv/0X/MlrZSZ6jowIaQQzFwP8M6rFU2z2mVYjDQ==} - engines: {node: '>=6.0.0'} + '@solana/functional@5.1.0': + resolution: {integrity: sha512-R6jacWU0Gr+j49lTDp+FSECBolqw2Gq7JlC22rI0JkcxJiiAlp3G80v6zAYq0FkHzxZbjyR6//JYUXSwliem5g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bip39@3.1.0: - resolution: {integrity: sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==} + '@solana/functional@6.1.0': + resolution: {integrity: sha512-+Sm8ldVxSTHIKaZDvcBu81FPjknXx6OMPlakkKmXjKxPgVLl86ruqMo2yEwoDUHV7DysLrLLcRNn13rfulomRw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + '@solana/instruction-plans@3.0.3': + resolution: {integrity: sha512-eqoaPtWtmLTTpdvbt4BZF5H6FIlJtXi9H7qLOM1dLYonkOX2Ncezx5NDCZ9tMb2qxVMF4IocYsQnNSnMfjQF1w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bn.js@4.12.2: - resolution: {integrity: sha512-n4DSx829VRTRByMRGdjQ9iqsN0Bh4OolPsFnaZBLcbi8iXcB+kJ9s7EnRt4wILZNV3kPLHkRVfOc/HvhC3ovDw==} + '@solana/instruction-plans@5.1.0': + resolution: {integrity: sha512-friMgHt0z5jQlCyyTDXfwAMYjCAagI7QYR+hLWB/BmvSuRpai0ddToWbWJoqrNRM312xZ+Oy/qjC3+Ftzi0DLA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bn.js@5.2.2: - resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} + '@solana/instruction-plans@6.1.0': + resolution: {integrity: sha512-zcsHg544t1zn7LLOVUxOWYlsKn9gvT7R+pL3cTiP2wFNoUN0h9En87H6nVqkZ8LWw23asgW0uM5uJGwfBx2h1Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - body-parser@1.20.3: - resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + '@solana/instructions@2.3.0': + resolution: {integrity: sha512-PLMsmaIKu7hEAzyElrk2T7JJx4D+9eRwebhFZpy2PXziNSmFF929eRHKUsKqBFM3cYR1Yy3m6roBZfA+bGE/oQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - body-parser@2.2.0: - resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} - engines: {node: '>=18'} + '@solana/instructions@3.0.3': + resolution: {integrity: sha512-4csIi8YUDb5j/J+gDzmYtOvq7ZWLbCxj4t0xKn+fPrBk/FD2pK29KVT3Fu7j4Lh1/ojunQUP9X4NHwUexY3PnA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - boolbase@1.0.0: - resolution: {integrity: sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==} + '@solana/instructions@5.1.0': + resolution: {integrity: sha512-fkwpUwwqk5K14T/kZDnCrfeR0kww49HBx+BK8xdSeJx+bt4QTwAHa9YeOkGhGrHEFVEJEUf8FKoxxTzZzJZtKQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - boolean@3.2.0: - resolution: {integrity: sha512-d0II/GO9uf9lfUHH2BQsjxzRJZBdsjgsBiW4BvhWk/3qoKwQFjIDVN19PfX8F2D/r9PCMTtLWjYVCFrpeYUzsw==} - deprecated: Package no longer supported. Contact Support at https://www.npmjs.com/support for more info. + '@solana/instructions@6.1.0': + resolution: {integrity: sha512-w1LdbJ3yanESckNTYC5KPckgN/25FyGCm07WWrs+dCnnpRNeLiVHIytXCPmArOVAXVkOYidXzhWmqCzqKUjYaA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - borsh@0.7.0: - resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + '@solana/keys@2.3.0': + resolution: {integrity: sha512-ZVVdga79pNH+2pVcm6fr2sWz9HTwfopDVhYb0Lh3dh+WBmJjwkabXEIHey2rUES7NjFa/G7sV8lrUn/v8LDCCQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bowser@2.12.0: - resolution: {integrity: sha512-HcOcTudTeEWgbHh0Y1Tyb6fdeR71m4b/QACf0D4KswGTsNeIJQmg38mRENZPAYPZvGFN3fk3604XbQEPdxXdKg==} + '@solana/keys@3.0.3': + resolution: {integrity: sha512-tp8oK9tMadtSIc4vF4aXXWkPd4oU5XPW8nf28NgrGDWGt25fUHIydKjkf2hPtMt9i1WfRyQZ33B5P3dnsNqcPQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + '@solana/keys@5.1.0': + resolution: {integrity: sha512-ma4zTTuSOmtTCvATHMfUGNTw0Vqah/6XPe1VmLc66ohwXMI3yqatX1FQPXgDZozr15SvLAesfs7/bgl2TRoe9w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + '@solana/keys@6.1.0': + resolution: {integrity: sha512-C/SGCl3VOgBQZ0mLrMxCcJYnMsGpgE8wbx29jqRY+R91m5YhS1f/GfXJPR1lN/h7QGrJ6YDm8eI0Y3AZ7goKHg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} + '@solana/kit@2.3.0': + resolution: {integrity: sha512-sb6PgwoW2LjE5oTFu4lhlS/cGt/NB3YrShEyx7JgWFWysfgLdJnhwWThgwy/4HjNsmtMrQGWVls0yVBHcMvlMQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - brorand@1.1.0: - resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + '@solana/kit@3.0.3': + resolution: {integrity: sha512-CEEhCDmkvztd1zbgADsEQhmj9GyWOOGeW1hZD+gtwbBSF5YN1uofS/pex5MIh/VIqKRj+A2UnYWI1V+9+q/lyQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - browserslist@4.25.3: - resolution: {integrity: sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true + '@solana/kit@5.1.0': + resolution: {integrity: sha512-oNQRzI0+mGWmXy05psO0J7r9Boy8PF7LH5H0Y9Jxvs10AbG4oSOBtyj20EccsRrr+jkqLw42fqb/4rNuASfvsA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bs58@4.0.1: - resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} + '@solana/kit@6.1.0': + resolution: {integrity: sha512-24exn11BPonquufyCkGgypVtmN4JOsdGMsbF3EZ4kFyk7ZNryCn/N8eELr1FCVrHWRXoc0xy/HFaESBULTMf6g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - bs58@5.0.0: - resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} + '@solana/nominal-types@2.3.0': + resolution: {integrity: sha512-uKlMnlP4PWW5UTXlhKM8lcgIaNj8dvd8xO4Y9l+FVvh9RvW2TO0GwUO6JCo7JBzCB0PSqRJdWWaQ8pu1Ti/OkA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bs58@6.0.0: - resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} + '@solana/nominal-types@3.0.3': + resolution: {integrity: sha512-aZavCiexeUAoMHRQg4s1AHkH3wscbOb70diyfjhwZVgFz1uUsFez7csPp9tNFkNolnadVb2gky7yBk3IImQJ6A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bs58check@2.1.2: - resolution: {integrity: sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==} + '@solana/nominal-types@5.1.0': + resolution: {integrity: sha512-+4Cm+SpK+D811i9giqv4Up93ZlmUcZfLDHkSH24F4in61+Y2TKA+XKuRtKhNytQMmqCfbvJZ9MHFaIeZw5g+Bg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - buffer-crc32@0.2.13: - resolution: {integrity: sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==} + '@solana/nominal-types@6.1.0': + resolution: {integrity: sha512-+skHjN0arNNB9TLsGqA94VCx7euyGURI+qG6wck6E4D7hH6i6DxGiVrtKRghx+smJkkLtTm9BvdVKGoeNQYr7Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - buffer-from@1.1.2: - resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + '@solana/offchain-messages@5.1.0': + resolution: {integrity: sha512-6FUXjiIJprjWa7y/T4E3rUb3HKi3P5zpBweBEwDflEEJ/QlieWUw7xlGAOvZ1eF3Wi+6LfcrdtZOwIkuv6o9Sg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - buffer-reverse@1.0.1: - resolution: {integrity: sha512-M87YIUBsZ6N924W57vDwT/aOu8hw7ZgdByz6ijksLjmHJELBASmYTTlNHRgjE+pTsT9oJXGaDSgqqwfdHotDUg==} + '@solana/offchain-messages@6.1.0': + resolution: {integrity: sha512-jrUb7HGUnRA+k44upcqKeevtEdqMxYRSlFdE0JTctZunGlP3GCcTl12tFOpbnFHvBLt8RwS62+nyeES8zzNwXA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + '@solana/options@2.3.0': + resolution: {integrity: sha512-PPnnZBRCWWoZQ11exPxf//DRzN2C6AoFsDI/u2AsQfYih434/7Kp4XLpfOMT/XESi+gdBMFNNfbES5zg3wAIkw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - buffer@6.0.3: - resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} + '@solana/options@3.0.3': + resolution: {integrity: sha512-jarsmnQ63RN0JPC5j9sgUat07NrL9PC71XU7pUItd6LOHtu4+wJMio3l5mT0DHVfkfbFLL6iI6+QmXSVhTNF3g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - bufferutil@4.0.9: - resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==} - engines: {node: '>=6.14.2'} + '@solana/options@5.1.0': + resolution: {integrity: sha512-PqgfALd0yhK+QFaYIbRFTV6hBpiy5xwdu07zSw1RLoNvt1sg+MRsRFDk9R8ZdEdiM69PY/cKiClVSjpNzLLcJg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - builder-util-runtime@9.3.1: - resolution: {integrity: sha512-2/egrNDDnRaxVwK3A+cJq6UOlqOdedGA7JPqCeJjN2Zjk1/QB/6QUi3b714ScIGS7HafFXTyzJEOr5b44I3kvQ==} - engines: {node: '>=12.0.0'} + '@solana/options@6.1.0': + resolution: {integrity: sha512-/4FtVfR6nkHkMCumyh7/lJ6jMqyES6tKUbOJRa6gJxcIUWeRDu+XrHTHLf3gRNUqDAbFvW8FMIrQm7PdreZgRA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - builder-util@26.0.11: - resolution: {integrity: sha512-xNjXfsldUEe153h1DraD0XvDOpqGR0L5eKFkdReB7eFW5HqysDZFfly4rckda6y9dF39N3pkPlOblcfHKGw+uA==} + '@solana/plugin-core@6.1.0': + resolution: {integrity: sha512-2nmNCPa6B1QArqpAZHWUkK6K7UXLTrekfcfJm2V//ATEtLpKEBlv0c3mrhOYwNAKP2TpNuvEV33InXWKst9oXQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - bundle-require@4.2.1: - resolution: {integrity: sha512-7Q/6vkyYAwOmQNRw75x+4yRtZCZJXUDmHHlFdkiV0wgv/reNjtJwpu1jPJ0w2kbEpIM0uoKI3S4/f39dU7AjSA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + '@solana/plugin-interfaces@6.1.0': + resolution: {integrity: sha512-eWSzfOuwtHUp8vljf5V24Tkz3WxqxiV0vD/BJZBNRZMdYRw3Cw3oeWcvEqHHxGUOie6AjIK8GrKggi8F73ZXbg==} + engines: {node: '>=20.18.0'} peerDependencies: - esbuild: '>=0.17' + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - bundle-require@5.1.0: - resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + '@solana/program-client-core@6.1.0': + resolution: {integrity: sha512-5Apka+ulWNfLNLYNR63pLnr5XvkXTQWeaftWED93iTWTZrZv9SyFWcmIsaes6eqGXMQ3RhlebnrWODtKuAA62g==} + engines: {node: '>=20.18.0'} peerDependencies: - esbuild: '>=0.18' + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - bytes@3.1.2: - resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} - engines: {node: '>= 0.8'} + '@solana/programs@2.3.0': + resolution: {integrity: sha512-UXKujV71VCI5uPs+cFdwxybtHZAIZyQkqDiDnmK+DawtOO9mBn4Nimdb/6RjR2CXT78mzO9ZCZ3qfyX+ydcB7w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} + '@solana/programs@3.0.3': + resolution: {integrity: sha512-JZlVE3/AeSNDuH3aEzCZoDu8GTXkMpGXxf93zXLzbxfxhiQ/kHrReN4XE/JWZ/uGWbaFZGR5B3UtdN2QsoZL7w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - cacache@16.1.3: - resolution: {integrity: sha512-/+Emcj9DAXxX4cwlLmRI9c166RuL3w30zp4R7Joiv2cQTtTtA+jeuCAjH3ZlGnYS3tKENSrKhAzVVP9GVyzeYQ==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + '@solana/programs@5.1.0': + resolution: {integrity: sha512-zAghXyRGixWNcarShlrnpjMD2115BZTF9JMLIcgkCYDOwjDPFIB/Y0hwDCH87N5uSjzlgkDpxKEL4ILewoZTRQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - cacheable-lookup@5.0.4: - resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} - engines: {node: '>=10.6.0'} + '@solana/programs@6.1.0': + resolution: {integrity: sha512-i4L4gSlIHDsdYRt3/YKVKMIN3UuYSKHRqK9B+AejcIc0y6Y/AXnHqzmpBRXEhvTXz18nt59MLXpVU4wu7ASjJA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - cacheable-request@7.0.4: - resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} - engines: {node: '>=8'} + '@solana/promises@2.3.0': + resolution: {integrity: sha512-GjVgutZKXVuojd9rWy1PuLnfcRfqsaCm7InCiZc8bqmJpoghlyluweNc7ml9Y5yQn1P2IOyzh9+p/77vIyNybQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} + '@solana/promises@3.0.3': + resolution: {integrity: sha512-K+UflGBVxj30XQMHTylHHZJdKH5QG3oj5k2s42GrZ/Wbu72oapVJySMBgpK45+p90t8/LEqV6rRPyTXlet9J+Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} + '@solana/promises@5.1.0': + resolution: {integrity: sha512-LU9wwS1PvGc/It610dclfq+JCuUEZSIWjvaF0+sqMP7QCk12Uz7MK2m9TtvLcjTvvKTIrucglRZP6qKroWRqGg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} + '@solana/promises@6.1.0': + resolution: {integrity: sha512-/mUW6peXQiEOaylLpGv4vtkvPzQvSbfhX9j5PNIK/ry4S3SHRQ3j3W/oGy4y3LR5alwo7NcVbubrkh4e4xwcww==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} + '@solana/rpc-api@2.3.0': + resolution: {integrity: sha512-UUdiRfWoyYhJL9PPvFeJr4aJ554ob2jXcpn4vKmRVn9ire0sCbpQKYx6K8eEKHZWXKrDW8IDspgTl0gT/aJWVg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - camelcase-css@2.0.1: - resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} - engines: {node: '>= 6'} + '@solana/rpc-api@3.0.3': + resolution: {integrity: sha512-Yym9/Ama62OY69rAZgbOCAy1QlqaWAyb0VlqFuwSaZV1pkFCCFSwWEJEsiN1n8pb2ZP+RtwNvmYixvWizx9yvA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - camelcase@5.3.1: - resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} - engines: {node: '>=6'} + '@solana/rpc-api@5.1.0': + resolution: {integrity: sha512-eI1tY0i3gmih1C65gFECYbfPRpHEYqFp+9IKjpknZtYpQIe9BqBKSpfYpGiCAbKdN/TMadBNPOzdK15ewhkkvQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - camelcase@6.3.0: - resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} - engines: {node: '>=10'} + '@solana/rpc-api@6.1.0': + resolution: {integrity: sha512-+hO5+kZjJHuUNATUQxlJ1+ztXFkgn1j46zRwt3X7kF+VHkW3wsQ7up0JTS+Xsacmkrj1WKfymQweq8JTrsAG8A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - caniuse-lite@1.0.30001735: - resolution: {integrity: sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w==} + '@solana/rpc-parsed-types@2.3.0': + resolution: {integrity: sha512-B5pHzyEIbBJf9KHej+zdr5ZNAdSvu7WLU2lOUPh81KHdHQs6dEb310LGxcpCc7HVE8IEdO20AbckewDiAN6OCg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - canonicalize@2.1.0: - resolution: {integrity: sha512-F705O3xrsUtgt98j7leetNhTWPe+5S72rlL5O4jA1pKqBVQ/dT1O1D6PFxmSXvc0SUOinWS57DKx0I3CHrXJHQ==} - hasBin: true + '@solana/rpc-parsed-types@3.0.3': + resolution: {integrity: sha512-/koM05IM2fU91kYDQxXil3VBNlOfcP+gXE0js1sdGz8KonGuLsF61CiKB5xt6u1KEXhRyDdXYLjf63JarL4Ozg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - chai@5.3.1: - resolution: {integrity: sha512-48af6xm9gQK8rhIcOxWwdGzIervm8BVTin+yRp9HEvU20BtVZ2lBywlIJBzwaDtvo0FvjeL7QdCADoUoqIbV3A==} - engines: {node: '>=18'} + '@solana/rpc-parsed-types@5.1.0': + resolution: {integrity: sha512-ZJoXHNItALMNa1zmGrNnIh96RBlc9GpIqoaZkdE14mAQ7gWe7Oc0ejYavUeSCmcL0wZcvIFh50AsfVxrHr4+2Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} + '@solana/rpc-parsed-types@6.1.0': + resolution: {integrity: sha512-YKccynVgWt/gbs0tBYstNw6BSVuOeWdeAldTB2OgH95o2Q04DpO4v97X1MZDysA4SvSZM30Ek5Ni5ss3kskgdw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - chalk@5.6.2: - resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} - engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + '@solana/rpc-spec-types@2.3.0': + resolution: {integrity: sha512-xQsb65lahjr8Wc9dMtP7xa0ZmDS8dOE2ncYjlvfyw/h4mpdXTUdrSMi6RtFwX33/rGuztQ7Hwaid5xLNSLvsFQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - charenc@0.0.2: - resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} + '@solana/rpc-spec-types@3.0.3': + resolution: {integrity: sha512-A6Jt8SRRetnN3CeGAvGJxigA9zYRslGgWcSjueAZGvPX+MesFxEUjSWZCfl+FogVFvwkqfkgQZQbPAGZQFJQ6Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - check-error@2.1.1: - resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} - engines: {node: '>= 16'} + '@solana/rpc-spec-types@5.1.0': + resolution: {integrity: sha512-B8/WyjmHpC34vXtAmTpZyPwRCm7WwoSkmjBcBouaaY1uilJ9+Wp2nptbq2cJyWairOoMSoI7v5kvvnrJuquq4Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} + '@solana/rpc-spec-types@6.1.0': + resolution: {integrity: sha512-tldMv1b6VGcvcRrY5MDWKlsyEKH6K96zE7gAIpKDX2G4T47ZOV+OMA3nh6xQpRgtyCUBsej0t80qmvTBDX/5IQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} + '@solana/rpc-spec@2.3.0': + resolution: {integrity: sha512-fA2LMX4BMixCrNB2n6T83AvjZ3oUQTu7qyPLyt8gHQaoEAXs8k6GZmu6iYcr+FboQCjUmRPgMaABbcr9j2J9Sw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - chownr@2.0.0: - resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} - engines: {node: '>=10'} + '@solana/rpc-spec@3.0.3': + resolution: {integrity: sha512-MZn5/8BebB6MQ4Gstw6zyfWsFAZYAyLzMK+AUf/rSfT8tPmWiJ/mcxnxqOXvFup/l6D67U8pyGpIoFqwCeZqqA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - chromium-pickle-js@0.2.0: - resolution: {integrity: sha512-1R5Fho+jBq0DDydt+/vHWj5KJNJCKdARKOCwZUen84I5BreWoLqRLANH1U87eJy1tiASPtMnGqJJq0ZsLoRPOw==} + '@solana/rpc-spec@5.1.0': + resolution: {integrity: sha512-y8B6fUWA1EBKXUsNo6b9EiFcQPsaJREPLlcIDbo4b6TucQNwvl7FHfpf1VHJL64SkI/WE69i2WEkiOJYjmLO0A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - ci-info@3.9.0: - resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} - engines: {node: '>=8'} + '@solana/rpc-spec@6.1.0': + resolution: {integrity: sha512-RxpkIGizCYhXGUcap7npV2S/rAXZ7P/liozY/ExjMmCxYTDwGIW33kp/uH/JRxuzrL8+f8FqY76VsqqIe+2VZw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - cipher-base@1.0.6: - resolution: {integrity: sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==} - engines: {node: '>= 0.10'} + '@solana/rpc-subscriptions-api@2.3.0': + resolution: {integrity: sha512-9mCjVbum2Hg9KGX3LKsrI5Xs0KX390lS+Z8qB80bxhar6MJPugqIPH8uRgLhCW9GN3JprAfjRNl7our8CPvsPQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - classnames@2.5.1: - resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} + '@solana/rpc-subscriptions-api@3.0.3': + resolution: {integrity: sha512-MGgVK3PUS15qsjuhimpzGZrKD/CTTvS0mAlQ0Jw84zsr1RJVdQJK/F0igu07BVd172eTZL8d90NoAQ3dahW5pA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - clean-stack@2.2.0: - resolution: {integrity: sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==} - engines: {node: '>=6'} + '@solana/rpc-subscriptions-api@5.1.0': + resolution: {integrity: sha512-84e2AsgqAGiVloW3G4RzpHPkInknu3rEuFPut2/69eq3Ab97TiTz2s5kc9gJpprtGM+xbgnIfeuGqr5F+2bXQA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - cli-cursor@3.1.0: - resolution: {integrity: sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==} - engines: {node: '>=8'} + '@solana/rpc-subscriptions-api@6.1.0': + resolution: {integrity: sha512-I6J+3VU0dda6EySKbDyd+1urC7RGIRPRp0DcWRVcy68NOLbq0I5C40Dn9O2Zf8iCdK4PbQ7JKdCvZ/bDd45hdg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - cli-spinners@2.9.2: - resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} - engines: {node: '>=6'} + '@solana/rpc-subscriptions-channel-websocket@2.3.0': + resolution: {integrity: sha512-2oL6ceFwejIgeWzbNiUHI2tZZnaOxNTSerszcin7wYQwijxtpVgUHiuItM/Y70DQmH9sKhmikQp+dqeGalaJxw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + ws: ^8.18.0 - cli-truncate@2.1.0: - resolution: {integrity: sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==} - engines: {node: '>=8'} + '@solana/rpc-subscriptions-channel-websocket@3.0.3': + resolution: {integrity: sha512-zUzUlb8Cwnw+SHlsLrSqyBRtOJKGc+FvSNJo/vWAkLShoV0wUDMPv7VvhTngJx3B/3ANfrOZ4i08i9QfYPAvpQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + ws: ^8.18.0 - client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} + '@solana/rpc-subscriptions-channel-websocket@5.1.0': + resolution: {integrity: sha512-FzAEmHzXtlckNn7T/1dzDS7r5HmekYPstrtZKjDcVxuGMVBUkZTnb69t7EJvKNuKw1wYZEUd0EEegtC2K/9dZA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + ws: ^8.18.0 + peerDependenciesMeta: + ws: + optional: true - cliui@6.0.0: - resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + '@solana/rpc-subscriptions-channel-websocket@6.1.0': + resolution: {integrity: sha512-vsx9b+uyCr9L3giao/BTiBFA8DxV5+gDNFq0t5uL21uQ17JXzBektwzHuHoth9IjkvXV/h+IhwXfuLE9Qm4GQg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - cliui@8.0.1: - resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} - engines: {node: '>=12'} + '@solana/rpc-subscriptions-spec@2.3.0': + resolution: {integrity: sha512-rdmVcl4PvNKQeA2l8DorIeALCgJEMSu7U8AXJS1PICeb2lQuMeaR+6cs/iowjvIB0lMVjYN2sFf6Q3dJPu6wWg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - clone-response@1.0.3: - resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} + '@solana/rpc-subscriptions-spec@3.0.3': + resolution: {integrity: sha512-9KpQ32OBJWS85mn6q3gkM0AjQe1LKYlMU7gpJRrla/lvXxNLhI95tz5K6StctpUreVmRWTVkNamHE69uUQyY8A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - clone@1.0.4: - resolution: {integrity: sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==} - engines: {node: '>=0.8'} + '@solana/rpc-subscriptions-spec@5.1.0': + resolution: {integrity: sha512-ORfjKtainnYisql6z4YsXByVwY8/rWsedVWn5oe/V7Og9LyetTM7hwJ8FbUdRDZwyLlUrI0cEE1aG+3ma/8tPw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - clsx@1.2.1: - resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} - engines: {node: '>=6'} + '@solana/rpc-subscriptions-spec@6.1.0': + resolution: {integrity: sha512-P06jhqzHpZGaLeJmIQkpDeMDD1xUp53ARpmXMsduMC+U5ZKQt29CLo+JrR18boNtls6WfttjVMEbzF25/4UPVA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} + '@solana/rpc-subscriptions@2.3.0': + resolution: {integrity: sha512-Uyr10nZKGVzvCOqwCZgwYrzuoDyUdwtgQRefh13pXIrdo4wYjVmoLykH49Omt6abwStB0a4UL5gX9V4mFdDJZg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - color-convert@1.9.3: - resolution: {integrity: sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==} + '@solana/rpc-subscriptions@3.0.3': + resolution: {integrity: sha512-LRvz6NaqvtsYFd32KwZ+rwYQ9XCs+DWjV8BvBLsJpt9/NWSuHf/7Sy/vvP6qtKxut692H/TMvHnC4iulg0WmiQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} + '@solana/rpc-subscriptions@5.1.0': + resolution: {integrity: sha512-u/mafVzBbdqvYDD7x/98T5/5xk4Bl2C/90TaHiKx7FmutVC/H4QsritPTY0v9JG1dOVWbgIfUgfZ0C0DPkiYnA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - color-name@1.1.3: - resolution: {integrity: sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==} + '@solana/rpc-subscriptions@6.1.0': + resolution: {integrity: sha512-sqwj+cQinWcZ7M/9+cudKxMPTkTQyGP73980vPCWM7vCpPkp2qzgrEie4DdgDGo+NMwIjeFgu2kdUuLHI3GD/g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + '@solana/rpc-transformers@2.3.0': + resolution: {integrity: sha512-UuHYK3XEpo9nMXdjyGKkPCOr7WsZsxs7zLYDO1A5ELH3P3JoehvrDegYRAGzBS2VKsfApZ86ZpJToP0K3PhmMA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} + '@solana/rpc-transformers@3.0.3': + resolution: {integrity: sha512-lzdaZM/dG3s19Tsk4mkJA5JBoS1eX9DnD7z62gkDwrwJDkDBzkAJT9aLcsYFfTmwTfIp6uU2UPgGYc97i1wezw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - color@3.2.1: - resolution: {integrity: sha512-aBl7dZI9ENN6fUGC7mWpMTPNHmWUSNan9tuWN6ahh5ZLNk9baLJOnSMlrQkHcrfFgz2/RigjUVAjdx36VcemKA==} + '@solana/rpc-transformers@5.1.0': + resolution: {integrity: sha512-6v93xi/ewGS/xEiSktNQ0bh0Uiv1/q9nR5oiFMn3BiAJRC+FdMRMxCjp6H+/Tua7wdhpClaPKrZYBQHoIp59tw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - colorspace@1.1.4: - resolution: {integrity: sha512-BgvKJiuVu1igBUF2kEjRCZXol6wiiGbY5ipL/oVPwm0BL9sIpMIzM8IK7vwuxIIzOXMV3Ey5w+vxhm0rR/TN8w==} + '@solana/rpc-transformers@6.1.0': + resolution: {integrity: sha512-OsSuuRPmsmS02eR9Zz+4iTsr+21hvEMEex5vwbwN6LAGPFlQ4ohqGkxgZCwmYd+Q5HWpnn9Uuf1MDTLLrKQkig==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - combined-stream@1.0.8: - resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} - engines: {node: '>= 0.8'} + '@solana/rpc-transport-http@2.3.0': + resolution: {integrity: sha512-HFKydmxGw8nAF5N+S0NLnPBDCe5oMDtI2RAmW8DMqP4U3Zxt2XWhvV1SNkAldT5tF0U1vP+is6fHxyhk4xqEvg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - comlink@4.4.2: - resolution: {integrity: sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==} + '@solana/rpc-transport-http@3.0.3': + resolution: {integrity: sha512-bIXFwr2LR5A97Z46dI661MJPbHnPfcShBjFzOS/8Rnr8P4ho3j/9EUtjDrsqoxGJT3SLWj5OlyXAlaDAvVTOUQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - commander@12.1.0: - resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} - engines: {node: '>=18'} + '@solana/rpc-transport-http@5.1.0': + resolution: {integrity: sha512-XoGX+2n/iXzoGb3Xrltbx8avnzp15vCfCGXuZpQWFL+xUg3P4CGl217XyDGjS5VxuUml+f/30xzWl18RaAIEcw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - commander@14.0.0: - resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} - engines: {node: '>=20'} + '@solana/rpc-transport-http@6.1.0': + resolution: {integrity: sha512-3ebaTYuglLJagaXtjwDPVI7SQeeeFN2fpetpGKsuMAiti4fzYqEkNN8FIo+nXBzqqG/cVc2421xKjXl6sO1k/g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - commander@14.0.1: - resolution: {integrity: sha512-2JkV3gUZUVrbNA+1sjBOYLsMZ5cEEl8GTFP2a4AVz5hvasAMCQ1D2l2le/cX+pV4N6ZU17zjUahLpIXRrnWL8A==} - engines: {node: '>=20'} + '@solana/rpc-types@2.3.0': + resolution: {integrity: sha512-O09YX2hED2QUyGxrMOxQ9GzH1LlEwwZWu69QbL4oYmIf6P5dzEEHcqRY6L1LsDVqc/dzAdEs/E1FaPrcIaIIPw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - commander@14.0.2: - resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} - engines: {node: '>=20'} + '@solana/rpc-types@3.0.3': + resolution: {integrity: sha512-petWQ5xSny9UfmC3Qp2owyhNU0w9SyBww4+v7tSVyXMcCC9v6j/XsqTeimH1S0qQUllnv0/FY83ohFaxofmZ6Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - commander@14.0.3: - resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} - engines: {node: '>=20'} + '@solana/rpc-types@5.1.0': + resolution: {integrity: sha512-Rnpt5BuHQvnULPNXUC/yRqB+7iPbon95CSCeyRvPj5tJ4fx2JibvX3s/UEoud5vC+kRjPi/R0BGJ8XFvd3eDWg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + '@solana/rpc-types@6.1.0': + resolution: {integrity: sha512-lR+Cb3v5Rpl49HsXWASy++TSE1AD86eRKabY+iuWnbBMYVGI4MamAvYwgBiygsCNc30nyO2TFNj9STMeSD/gAg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - commander@4.1.1: - resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} - engines: {node: '>= 6'} + '@solana/rpc@2.3.0': + resolution: {integrity: sha512-ZWN76iNQAOCpYC7yKfb3UNLIMZf603JckLKOOLTHuy9MZnTN8XV6uwvDFhf42XvhglgUjGCEnbUqWtxQ9pa/pQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - commander@5.1.0: - resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} - engines: {node: '>= 6'} + '@solana/rpc@3.0.3': + resolution: {integrity: sha512-3oukAaLK78GegkKcm6iNmRnO4mFeNz+BMvA8T56oizoBNKiRVEq/6DFzVX/LkmZ+wvD601pAB3uCdrTPcC0YKQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - commander@7.2.0: - resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} - engines: {node: '>= 10'} + '@solana/rpc@5.1.0': + resolution: {integrity: sha512-j+ByLxFCoHWw9TnsGzkAVMFUfBDIUE53nIosJAYEsERpImD2mjwc33uDE6YXLKoaKRoYO4tc7IUzkKY1fQp/CA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - commander@9.5.0: - resolution: {integrity: sha512-KRs7WVDKg86PWiuAqhDrAQnTXZKraVcCc6vFdL14qrZ/DcWwuRo7VoiYXalXO7S5GKpqYiVEwCbgFDfxNHKJBQ==} - engines: {node: ^12.20.0 || >=14} + '@solana/rpc@6.1.0': + resolution: {integrity: sha512-R3y5PklW9mPy5Y34hsXj40R28zN2N7AGLnHqYJVkXkllwVub/QCNpSdDxAnbbS5EGOYGoUOW8s5LFoXwMSr1LQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - comment-parser@1.4.1: - resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} - engines: {node: '>= 12.0.0'} + '@solana/signers@2.3.0': + resolution: {integrity: sha512-OSv6fGr/MFRx6J+ZChQMRqKNPGGmdjkqarKkRzkwmv7v8quWsIRnJT5EV8tBy3LI4DLO/A8vKiNSPzvm1TdaiQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - compare-version@0.1.2: - resolution: {integrity: sha512-pJDh5/4wrEnXX/VWRZvruAGHkzKdr46z11OlTPN+VrATlWWhSKewNCJ1futCO5C7eJB3nPMFZA1LeYtcFboZ2A==} - engines: {node: '>=0.10.0'} + '@solana/signers@3.0.3': + resolution: {integrity: sha512-UwCd/uPYTZiwd283JKVyOWLLN5sIgMBqGDyUmNU3vo9hcmXKv5ZGm/9TvwMY2z35sXWuIOcj7etxJ8OoWc/ObQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + '@solana/signers@5.1.0': + resolution: {integrity: sha512-B8xO0SGN1ZWYfJROL+da3id279qNbXbXoqud+AuT5gur51RrS4YhNkTQ6khVbGtAOpPMAhkoZN0jnfCC1r33jQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - concurrently@8.2.2: - resolution: {integrity: sha512-1dP4gpXFhei8IOtlXRE/T/4H88ElHgTiUzh71YUmtjTEHMSRS2Z/fgOxHSxxusGHogsRfxNq1vyAwxSC+EVyDg==} - engines: {node: ^14.13.0 || >=16.0.0} - hasBin: true + '@solana/signers@6.1.0': + resolution: {integrity: sha512-WDPGZJr6jIe2dEChv/2KQBnaga8dqOjd6ceBj/HcDHxnCudo66t7GlyZ9+9jMO40AgOOb7EDE5FDqPMrHMg5Yw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - concurrently@9.2.0: - resolution: {integrity: sha512-IsB/fiXTupmagMW4MNp2lx2cdSN2FfZq78vF90LBB+zZHArbIQZjQtzXCiXnvTxCZSvXanTqFLWBjw2UkLx1SQ==} - engines: {node: '>=18'} - hasBin: true + '@solana/subscribable@2.3.0': + resolution: {integrity: sha512-DkgohEDbMkdTWiKAoatY02Njr56WXx9e/dKKfmne8/Ad6/2llUIrax78nCdlvZW9quXMaXPTxZvdQqo9N669Og==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - confbox@0.1.8: - resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + '@solana/subscribable@3.0.3': + resolution: {integrity: sha512-FJ27LKGHLQ5GGttPvTOLQDLrrOZEgvaJhB7yYaHAhPk25+p+erBaQpjePhfkMyUbL1FQbxn1SUJmS6jUuaPjlQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - config-file-ts@0.2.8-rc1: - resolution: {integrity: sha512-GtNECbVI82bT4RiDIzBSVuTKoSHufnU7Ce7/42bkWZJZFLjmDF2WBpVsvRkhKCfKBnTBb3qZrBwPpFBU/Myvhg==} + '@solana/subscribable@5.1.0': + resolution: {integrity: sha512-OeW5AJwKzHh18+PIPtghuuPJTmEep2Mhb3Lsrq4alas4fibmMGkr39z1HXxVF6l6e2lu/YGhHIDtuhouWmY7ow==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - consola@3.4.2: - resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} - engines: {node: ^14.18.0 || >=16.10.0} + '@solana/subscribable@6.1.0': + resolution: {integrity: sha512-HiUfkxN7638uxPmY4t0gI4+yqnFLZYJKFaT9EpWIuGrOB1d9n+uOHNs3NU7cVMwWXgfZUbztTCKyCVTbcwesNg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - console-table-printer@2.14.6: - resolution: {integrity: sha512-MCBl5HNVaFuuHW6FGbL/4fB7N/ormCy+tQ+sxTrF6QtSbSNETvPuOVbkJBhzDgYhvjWGrTma4eYJa37ZuoQsPw==} + '@solana/sysvars@2.3.0': + resolution: {integrity: sha512-LvjADZrpZ+CnhlHqfI5cmsRzX9Rpyb1Ox2dMHnbsRNzeKAMhu9w4ZBIaeTdO322zsTr509G1B+k2ABD3whvUBA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - content-disposition@0.5.4: - resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} - engines: {node: '>= 0.6'} + '@solana/sysvars@3.0.3': + resolution: {integrity: sha512-GnHew+QeKCs2f9ow+20swEJMH4mDfJA/QhtPgOPTYQx/z69J4IieYJ7fZenSHnA//lJ45fVdNdmy1trypvPLBQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - content-disposition@1.0.0: - resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} - engines: {node: '>= 0.6'} + '@solana/sysvars@5.1.0': + resolution: {integrity: sha512-FJ9YIsLTAaajnOrYEYn54znstXJsvKndRhyCrlyiAEN1IXHw5HtZHploLF3ZZ78b7YU3uv3tFJMziXFBwPOn4Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - content-type@1.0.5: - resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} - engines: {node: '>= 0.6'} + '@solana/sysvars@6.1.0': + resolution: {integrity: sha512-KwJyBBrAOx0BgkiZqOKAaySDb/0JrUFSBQL9/O1kSKGy9TCRX55Ytr1HxNTcTPppWNpbM6JZVK+yW3Ruey0HRw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + '@solana/transaction-confirmation@2.3.0': + resolution: {integrity: sha512-UiEuiHCfAAZEKdfne/XljFNJbsKAe701UQHKXEInYzIgBjRbvaeYZlBmkkqtxwcasgBTOmEaEKT44J14N9VZDw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - cookie-es@1.2.2: - resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} + '@solana/transaction-confirmation@3.0.3': + resolution: {integrity: sha512-dXx0OLtR95LMuARgi2dDQlL1QYmk56DOou5q9wKymmeV3JTvfDExeWXnOgjRBBq/dEfj4ugN1aZuTaS18UirFw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - cookie-signature@1.0.6: - resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} + '@solana/transaction-confirmation@5.1.0': + resolution: {integrity: sha512-6HnL0uH8tWZXJVuaoeTbCQp/FS11Bsc4GSlq+k0N21GdhTbFuqBhsxlAYWbzPWs9+/kYRGHqqXvBPCReWxT7BA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - cookie-signature@1.2.2: - resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} - engines: {node: '>=6.6.0'} + '@solana/transaction-confirmation@6.1.0': + resolution: {integrity: sha512-akSjcqAMOGPFvKctFDSzhjcRc/45WbEVdVQ9mjgH6OYo7B11WZZZaeGPlzAw5KyuG34Px941xmICkBmNqEH47Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - cookie@0.7.1: - resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} - engines: {node: '>= 0.6'} + '@solana/transaction-messages@2.3.0': + resolution: {integrity: sha512-bgqvWuy3MqKS5JdNLH649q+ngiyOu5rGS3DizSnWwYUd76RxZl1kN6CoqHSrrMzFMvis6sck/yPGG3wqrMlAww==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - cookie@0.7.2: - resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} - engines: {node: '>= 0.6'} + '@solana/transaction-messages@3.0.3': + resolution: {integrity: sha512-s+6NWRnBhnnjFWV4x2tzBzoWa6e5LiIxIvJlWwVQBFkc8fMGY04w7jkFh0PM08t/QFKeXBEWkyBDa/TFYdkWug==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - cookie@1.1.1: - resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} - engines: {node: '>=18'} + '@solana/transaction-messages@5.1.0': + resolution: {integrity: sha512-9rNV2YJhd85WIMvnwa/vUY4xUw3ZTU17jP1KDo/fFZWk55a0ov0ATJJPyC5HAR1i6hT1cmJzGH/UHhnD9m/Q3w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - core-js-compat@3.45.1: - resolution: {integrity: sha512-tqTt5T4PzsMIZ430XGviK4vzYSoeNJ6CXODi6c/voxOT6IZqBht5/EKaSNnYiEjjRYxjVz7DQIsOsY0XNi8PIA==} + '@solana/transaction-messages@6.1.0': + resolution: {integrity: sha512-Dpv54LRVcfFbFEa/uB53LaY/TRfKuPGMKR7Z4F290zBgkj9xkpZkI+WLiJBiSloI7Qo2KZqXj3514BIeZvJLcg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true - core-util-is@1.0.2: - resolution: {integrity: sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==} + '@solana/transactions@2.3.0': + resolution: {integrity: sha512-LnTvdi8QnrQtuEZor5Msje61sDpPstTVwKg4y81tNxDhiyomjuvnSNLAq6QsB9gIxUqbNzPZgOG9IU4I4/Uaug==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - core-util-is@1.0.3: - resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} + '@solana/transactions@3.0.3': + resolution: {integrity: sha512-iMX+n9j4ON7H1nKlWEbMqMOpKYC6yVGxKKmWHT1KdLRG7v+03I4DnDeFoI+Zmw56FA+7Bbne8jwwX60Q1vk/MQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} - engines: {node: '>= 0.10'} + '@solana/transactions@5.1.0': + resolution: {integrity: sha512-06JwSPtz+38ozNgpysAXS2eTMPQCufIisXB6K88X8J4GF8ziqs4nkq0BpXAXn+MpZTkuMt+JeW2RxP3HKhXe5g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' - cosmiconfig@8.3.6: - resolution: {integrity: sha512-kcZ6+W5QzcJ3P1Mt+83OUv/oHFqZHIx8DuxG6eZ5RGMERoLqp4BuGjhHLYGK+Kf5XVkQvqBSmAy/nGWN3qDgEA==} - engines: {node: '>=14'} + '@solana/transactions@6.1.0': + resolution: {integrity: sha512-1dkiNJcTtlHm4Fvs5VohNVpv7RbvbUYYKV7lYXMPIskoLF1eZp0tVlEqD/cRl91RNz7HEysfHqBAwlcJcRmrRg==} + engines: {node: '>=20.18.0'} peerDependencies: - typescript: '>=4.9.5' + typescript: ^5.0.0 peerDependenciesMeta: typescript: optional: true - crc-32@1.2.2: - resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} - engines: {node: '>=0.8'} + '@solana/wallet-standard-features@1.3.0': + resolution: {integrity: sha512-ZhpZtD+4VArf6RPitsVExvgkF+nGghd1rzPjd97GmBximpnt1rsUxMOEyoIEuH3XBxPyNB6Us7ha7RHWQR+abg==} + engines: {node: '>=16'} + + '@solana/web3.js@1.98.4': + resolution: {integrity: sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==} + + '@stellar/js-xdr@3.1.2': + resolution: {integrity: sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==} + + '@stellar/stellar-base@14.1.0': + resolution: {integrity: sha512-A8kFli6QGy22SRF45IjgPAJfUNGjnI+R7g4DF5NZYVsD1kGf7B4ITyc4OPclLV9tqNI4/lXxafGEw0JEUbHixw==} + engines: {node: '>=20.0.0'} + + '@stellar/stellar-sdk@14.6.1': + resolution: {integrity: sha512-A1rQWDLdUasXkMXnYSuhgep+3ZZzyuXJKdt5/KAIc0gkmSp906HTvUpbT4pu+bVr41tu0+J4Ugz9J4BQAGGytg==} + engines: {node: '>=20.0.0'} hasBin: true - crc@3.8.0: - resolution: {integrity: sha512-iX3mfgcTMIq3ZKLIsVFAbv7+Mc10kxabAGQb8HvjA1o3T1PIYprbakQ65d3I+2HGHt6nSKkM9PYjgoJO2KcFBQ==} + '@swc/helpers@0.5.15': + resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - create-hash@1.2.0: - resolution: {integrity: sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==} + '@swc/helpers@0.5.17': + resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} - cross-dirname@0.1.0: - resolution: {integrity: sha512-+R08/oI0nl3vfPcqftZRpytksBXDzOUveBq/NBVx0sUp1axwzPQrKinNx5yd5sxPu8j1wIy8AfnVQ+5eFdha6Q==} + '@szmarczak/http-timer@4.0.6': + resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} + engines: {node: '>=10'} - cross-fetch@3.2.0: - resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} + '@tailwindcss/node@4.1.17': + resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} - cross-fetch@4.1.0: - resolution: {integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==} + '@tailwindcss/oxide-android-arm64@4.1.17': + resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} + '@tailwindcss/oxide-darwin-arm64@4.1.17': + resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] - crossws@0.3.5: - resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} + '@tailwindcss/oxide-darwin-x64@4.1.17': + resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] - crypt@0.0.2: - resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + '@tailwindcss/oxide-freebsd-x64@4.1.17': + resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] - crypto-js@4.2.0: - resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': + resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] - css-select@5.2.2: - resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} + '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': + resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] - css-tree@2.2.1: - resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + '@tailwindcss/oxide-linux-arm64-musl@4.1.17': + resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] - css-tree@2.3.1: - resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} + '@tailwindcss/oxide-linux-x64-gnu@4.1.17': + resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] - css-what@6.2.2: - resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} - engines: {node: '>= 6'} + '@tailwindcss/oxide-linux-x64-musl@4.1.17': + resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true + '@tailwindcss/oxide-wasm32-wasi@4.1.17': + resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib - csso@5.0.5: - resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==} - engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'} + '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': + resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] - cssstyle@4.6.0: - resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} - engines: {node: '>=18'} + '@tailwindcss/oxide-win32-x64-msvc@4.1.17': + resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + '@tailwindcss/oxide@4.1.17': + resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==} + engines: {node: '>= 10'} - damerau-levenshtein@1.0.8: - resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} + '@tailwindcss/postcss@4.1.17': + resolution: {integrity: sha512-+nKl9N9mN5uJ+M7dBOOCzINw94MPstNR/GtIhz1fpZysxL/4a+No64jCBD6CPN+bIHWFx3KWuu8XJRrj/572Dw==} - data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} + '@tanstack/query-core@5.90.11': + resolution: {integrity: sha512-f9z/nXhCgWDF4lHqgIE30jxLe4sYv15QodfdPDKYAk7nAEjNcndy4dHz3ezhdUaR23BpWa4I2EH4/DZ0//Uf8A==} - data-urls@5.0.0: - resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} - engines: {node: '>=18'} + '@tanstack/react-query@5.90.11': + resolution: {integrity: sha512-3uyzz01D1fkTLXuxF3JfoJoHQMU2fxsfJwE+6N5hHy0dVNoZOvwKP8Z2k7k1KDeD54N20apcJnG75TBAStIrBA==} + peerDependencies: + react: ^18 || ^19 - data-view-buffer@1.0.2: - resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} - engines: {node: '>= 0.4'} + '@tanstack/store@0.8.0': + resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} - data-view-byte-length@1.0.2: - resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} - engines: {node: '>= 0.4'} + '@tsconfig/node10@1.0.12': + resolution: {integrity: sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==} - data-view-byte-offset@1.0.1: - resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} - engines: {node: '>= 0.4'} + '@tsconfig/node12@1.0.11': + resolution: {integrity: sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==} - date-fns@2.30.0: - resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} - engines: {node: '>=0.11'} + '@tsconfig/node14@1.0.3': + resolution: {integrity: sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==} - dayjs@1.11.13: - resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + '@tsconfig/node16@1.0.4': + resolution: {integrity: sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==} - debug@2.6.9: - resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + '@txnlab/use-wallet@4.6.0': + resolution: {integrity: sha512-niAookAa8cpkrZsGDwQUaeLTODSd5gxSiUHaiPDiHiF/4oGKx/X/KJOFwAA/8iXOI8CTe60fbwEiKRXNIa1RvQ==} peerDependencies: - supports-color: '*' + '@agoralabs-sh/avm-web-provider': ^1.7.0 + '@blockshake/defly-connect': ^1.2.1 + '@perawallet/connect': ^1.4.1 + '@walletconnect/modal': ^2.7.0 + '@walletconnect/sign-client': ^2.23.4 + '@web3auth/base': ^9.0.0 + '@web3auth/base-provider': ^9.0.0 + '@web3auth/modal': ^9.0.0 + '@web3auth/single-factor-auth': ^9.0.0 + algosdk: ^3.0.0 + lute-connect: ^1.6.3 peerDependenciesMeta: - supports-color: + '@agoralabs-sh/avm-web-provider': optional: true - - debug@3.2.7: - resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: + '@blockshake/defly-connect': optional: true - - debug@4.3.4: - resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: + '@perawallet/connect': optional: true - - debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: + '@walletconnect/modal': optional: true - - debug@4.4.1: - resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: + '@walletconnect/sign-client': + optional: true + '@web3auth/base': + optional: true + '@web3auth/base-provider': + optional: true + '@web3auth/modal': + optional: true + '@web3auth/single-factor-auth': + optional: true + lute-connect: optional: true - decamelize@1.2.0: - resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} - engines: {node: '>=0.10.0'} - - decimal.js@10.6.0: - resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - - decode-uri-component@0.2.2: - resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} - engines: {node: '>=0.10'} + '@tybys/wasm-util@0.10.0': + resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} + '@types/aws-lambda@8.10.161': + resolution: {integrity: sha512-rUYdp+MQwSFocxIOcSsYSF3YYYC/uUpMbCY/mbO21vGqfrEYvNSoPyKYDj6RhXXpPfS0KstW9RwG3qXh9sL7FQ==} - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} + '@types/body-parser@1.19.6': + resolution: {integrity: sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==} - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + '@types/cacheable-request@6.0.3': + resolution: {integrity: sha512-IQ3EbTzGxIigb1I3qPZc1rWJnH0BmSKv5QYTalEwweFvyBDLSAe24zP0le/hyi7ecGfZVlIVAg4BZqb8WBwKqw==} - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} + '@types/chai@5.2.2': + resolution: {integrity: sha512-8kB30R7Hwqf40JPiKhVzodJs2Qc1ZJ5zuT3uzw5Hq/dhNCl3G3l83jfpdI1e20BP348+fV7VIL/+FxaXkqBmWg==} - defaults@1.0.4: - resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - defer-to-connect@2.0.1: - resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} - engines: {node: '>=10'} + '@types/debug@4.1.12': + resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} + '@types/deep-eql@4.0.2': + resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + '@types/express-serve-static-core@4.19.8': + resolution: {integrity: sha512-02S5fmqeoKzVZCHPZid4b8JH2eM5HzQLZWN2FohQEy/0eXTq8VXZfSN6Pcr3F6N9R/vNrj7cpgbhjie6m/1tCA==} - delay@5.0.0: - resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} - engines: {node: '>=10'} + '@types/express-serve-static-core@5.0.7': + resolution: {integrity: sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==} - delayed-stream@1.0.0: - resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} - engines: {node: '>=0.4.0'} + '@types/express@4.17.25': + resolution: {integrity: sha512-dVd04UKsfpINUnK0yBoYHDF3xu7xVH4BuDotC/xGuycx4CgbP48X/KF/586bcObxT0HENHXEU8Nqtu6NR+eKhw==} - depd@2.0.0: - resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} - engines: {node: '>= 0.8'} + '@types/express@5.0.3': + resolution: {integrity: sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==} - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} + '@types/http-cache-semantics@4.0.4': + resolution: {integrity: sha512-1m0bIFVc7eJWyve9S0RnuRgcQqF/Xd5QsUZAZeQFr1Q3/p9JWoQQEqmVy+DPTNpGXwhgIetAoYF8JSc33q29QA==} - derive-valtio@0.1.0: - resolution: {integrity: sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==} - peerDependencies: - valtio: '*' + '@types/http-errors@2.0.5': + resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} - destr@2.0.5: - resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} - destroy@1.2.0: - resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} - engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} - detect-browser@5.3.0: - resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==} + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - detect-node-es@1.1.0: - resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + '@types/json5@0.0.29': + resolution: {integrity: sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==} - detect-node@2.1.0: - resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==} + '@types/keyv@3.1.4': + resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} - didyoumean@1.2.2: - resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} - dijkstrajs@1.0.3: - resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + '@types/ms@2.1.0': + resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - dir-compare@4.2.0: - resolution: {integrity: sha512-2xMCmOoMrdQIPHdsTawECdNPwlVFB9zGcz3kuhmBO6U3oU+UQjsue0i8ayLKpgBcm+hcXPMVSGUN9d+pvJ6+VQ==} + '@types/node-fetch@2.6.13': + resolution: {integrity: sha512-QGpRVpzSaUs30JBSGPjOg4Uveu384erbHBoT1zeONvyCfwQxIkUshLAOqN/k9EjGviPRmWTTe6aH2qySWKTVSw==} - dir-glob@3.0.1: - resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} - engines: {node: '>=8'} + '@types/node@12.20.55': + resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} - dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} + '@types/node@18.19.123': + resolution: {integrity: sha512-K7DIaHnh0mzVxreCR9qwgNxp3MH9dltPNIEddW9MYUlcKAzm+3grKNSTe2vCJHI1FaLpvpL5JGJrz1UZDKYvDg==} - dmg-builder@26.0.12: - resolution: {integrity: sha512-59CAAjAhTaIMCN8y9kD573vDkxbs1uhDcrFLHSgutYdPcGOU35Rf95725snvzEOy4BFB7+eLJ8djCNPmGwG67w==} + '@types/node@22.17.2': + resolution: {integrity: sha512-gL6z5N9Jm9mhY+U2KXZpteb+09zyffliRkZyZOHODGATyC5B1Jt/7TzuuiLkFsSUMLbS1OLmlj/E+/3KF4Q/4w==} - dmg-license@1.0.11: - resolution: {integrity: sha512-ZdzmqwKmECOWJpqefloC5OJy1+WZBBse5+MR88z9g9Zn4VY+WYUkAyojmhzJckH5YbbZGcYIuGAkY5/Ys5OM2Q==} - engines: {node: '>=8'} - os: [darwin] - hasBin: true + '@types/qs@6.14.0': + resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} - doctrine@2.1.0: - resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} - engines: {node: '>=0.10.0'} + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} - doctrine@3.0.0: - resolution: {integrity: sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==} - engines: {node: '>=6.0.0'} + '@types/react-dom@19.1.7': + resolution: {integrity: sha512-i5ZzwYpqjmrKenzkoLM2Ibzt6mAsM7pxB6BCIouEVVmgiqaMj1TjaK7hnA36hbW5aZv20kx7Lw6hWzPWg0Rurw==} + peerDependencies: + '@types/react': ^19.0.0 - dom-serializer@2.0.0: - resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + '@types/react-dom@19.2.1': + resolution: {integrity: sha512-/EEvYBdT3BflCWvTMO7YkYBHVE9Ci6XdqZciZANQgKpaiDRGOLIlRo91jbTNRQjgPFWVaRxcYc0luVNFitz57A==} + peerDependencies: + '@types/react': ^19.2.0 - domelementtype@2.3.0: - resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + '@types/react@19.1.10': + resolution: {integrity: sha512-EhBeSYX0Y6ye8pNebpKrwFJq7BoQ8J5SO6NlvNwwHjSj6adXJViPQrKlsyPw7hLBLvckEMO1yxeGdR82YBBlDg==} - domhandler@5.0.3: - resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} - engines: {node: '>= 4'} + '@types/react@19.2.1': + resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} - domutils@3.2.2: - resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} + '@types/responselike@1.0.3': + resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} - dot-case@3.0.4: - resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + '@types/send@0.17.5': + resolution: {integrity: sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==} - dotenv-expand@11.0.7: - resolution: {integrity: sha512-zIHwmZPRshsCdpMDyVsqGmgyP0yT8GAgXUnkdAoJisxvf33k7yO6OuoKmcTGuXPWSsm8Oh88nZicRLA9Y0rUeA==} - engines: {node: '>=12'} + '@types/serve-static@1.15.8': + resolution: {integrity: sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==} - dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} - engines: {node: '>=12'} + '@types/trusted-types@2.0.7': + resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} + '@types/uuid@8.3.4': + resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} - duplexify@4.1.3: - resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} + '@types/ws@7.4.7': + resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} - eciesjs@0.4.15: - resolution: {integrity: sha512-r6kEJXDKecVOCj2nLMuXK/FCPeurW33+3JRpfXVbjLja3XUYFfD9I/JBreH6sUyzcm3G/YQboBjMla6poKeSdA==} - engines: {bun: '>=1', deno: '>=2', node: '>=16'} + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} - ed2curve@0.3.0: - resolution: {integrity: sha512-8w2fmmq3hv9rCrcI7g9hms2pMunQr1JINfcjwR9tAyZqhtyaMN991lF/ZfHfr5tzZQ8c7y7aBgZbjfbd0fjFwQ==} + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} - ee-first@1.1.1: - resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + '@typescript-eslint/eslint-plugin@8.40.0': + resolution: {integrity: sha512-w/EboPlBwnmOBtRbiOvzjD+wdiZdgFeo17lkltrtn7X37vagKKWJABvyfsJXTlHe6XBzugmYgd4A4nW+k8Mixw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.40.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - ejs@3.1.10: - resolution: {integrity: sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==} - engines: {node: '>=0.10.0'} - hasBin: true + '@typescript-eslint/eslint-plugin@8.48.0': + resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.48.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - electron-builder-squirrel-windows@26.0.12: - resolution: {integrity: sha512-kpwXM7c/ayRUbYVErQbsZ0nQZX4aLHQrPEG9C4h9vuJCXylwFH8a7Jgi2VpKIObzCXO7LKHiCw4KdioFLFOgqA==} + '@typescript-eslint/parser@8.40.0': + resolution: {integrity: sha512-jCNyAuXx8dr5KJMkecGmZ8KI61KBUhkCob+SD+C+I5+Y1FWI2Y3QmY4/cxMCC5WAsZqoEtEETVhUiUMIGCf6Bw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - electron-builder@26.0.12: - resolution: {integrity: sha512-cD1kz5g2sgPTMFHjLxfMjUK5JABq3//J4jPswi93tOPFz6btzXYtK5NrDt717NRbukCUDOrrvmYVOWERlqoiXA==} - engines: {node: '>=14.0.0'} - hasBin: true + '@typescript-eslint/parser@8.48.0': + resolution: {integrity: sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - electron-is-dev@3.0.1: - resolution: {integrity: sha512-8TjjAh8Ec51hUi3o4TaU0mD3GMTOESi866oRNavj9A3IQJ7pmv+MJVmdZBFGw4GFT36X7bkqnuDNYvkQgvyI8Q==} - engines: {node: '>=18'} + '@typescript-eslint/project-service@8.40.0': + resolution: {integrity: sha512-/A89vz7Wf5DEXsGVvcGdYKbVM9F7DyFXj52lNYUDS1L9yJfqjW/fIp5PgMuEJL/KeqVTe2QSbXAGUZljDUpArw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' - electron-publish@26.0.11: - resolution: {integrity: sha512-a8QRH0rAPIWH9WyyS5LbNvW9Ark6qe63/LqDB7vu2JXYpi0Gma5Q60Dh4tmTqhOBQt0xsrzD8qE7C+D7j+B24A==} + '@typescript-eslint/project-service@8.48.0': + resolution: {integrity: sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' - electron-to-chromium@1.5.207: - resolution: {integrity: sha512-mryFrrL/GXDTmAtIVMVf+eIXM09BBPlO5IQ7lUyKmK8d+A4VpRGG+M3ofoVef6qyF8s60rJei8ymlJxjUA8Faw==} + '@typescript-eslint/scope-manager@8.40.0': + resolution: {integrity: sha512-y9ObStCcdCiZKzwqsE8CcpyuVMwRouJbbSrNuThDpv16dFAj429IkM6LNb1dZ2m7hK5fHyzNcErZf7CEeKXR4w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - electron-winstaller@5.4.0: - resolution: {integrity: sha512-bO3y10YikuUwUuDUQRM4KfwNkKhnpVO7IPdbsrejwN9/AABJzzTQ4GeHwyzNSrVO+tEH3/Np255a3sVZpZDjvg==} - engines: {node: '>=8.0.0'} + '@typescript-eslint/scope-manager@8.48.0': + resolution: {integrity: sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - electron@37.3.1: - resolution: {integrity: sha512-7DhktRLqhe6OJh/Bo75bTI0puUYEmIwSzMinocgO63mx3MVjtIn2tYMzLmAleNIlud2htkjpsMG2zT4PiTCloA==} - engines: {node: '>= 12.20.55'} - hasBin: true + '@typescript-eslint/tsconfig-utils@8.40.0': + resolution: {integrity: sha512-jtMytmUaG9d/9kqSl/W3E3xaWESo4hFDxAIHGVW/WKKtQhesnRIJSAJO6XckluuJ6KDB5woD1EiqknriCtAmcw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' - elliptic@6.6.1: - resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + '@typescript-eslint/tsconfig-utils@8.48.0': + resolution: {integrity: sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' - emoji-regex@8.0.0: - resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + '@typescript-eslint/type-utils@8.40.0': + resolution: {integrity: sha512-eE60cK4KzAc6ZrzlJnflXdrMqOBaugeukWICO2rB0KNvwdIMaEaYiywwHMzA1qFpTxrLhN9Lp4E/00EgWcD3Ow==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + '@typescript-eslint/type-utils@8.48.0': + resolution: {integrity: sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - enabled@2.0.0: - resolution: {integrity: sha512-AKrN98kuwOzMIdAizXGI86UFBoo26CL21UM763y1h/GMSJ4/OHU9k2YlsmBpyScFo/wbLzWQJBMCW4+IO3/+OQ==} + '@typescript-eslint/types@8.40.0': + resolution: {integrity: sha512-ETdbFlgbAmXHyFPwqUIYrfc12ArvpBhEVgGAxVYSwli26dn8Ko+lIo4Su9vI9ykTZdJn+vJprs/0eZU0YMAEQg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - encode-utf8@1.0.3: - resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} + '@typescript-eslint/types@8.48.0': + resolution: {integrity: sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - encodeurl@1.0.2: - resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} - engines: {node: '>= 0.8'} + '@typescript-eslint/typescript-estree@8.40.0': + resolution: {integrity: sha512-k1z9+GJReVVOkc1WfVKs1vBrR5MIKKbdAjDTPvIK3L8De6KbFfPFt6BKpdkdk7rZS2GtC/m6yI5MYX+UsuvVYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' - encodeurl@2.0.0: - resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} - engines: {node: '>= 0.8'} + '@typescript-eslint/typescript-estree@8.48.0': + resolution: {integrity: sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.0.0' - encoding@0.1.13: - resolution: {integrity: sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==} + '@typescript-eslint/utils@8.40.0': + resolution: {integrity: sha512-Cgzi2MXSZyAUOY+BFwGs17s7ad/7L+gKt6Y8rAVVWS+7o6wrjeFN4nVfTpbE25MNcxyJ+iYUXflbs2xR9h4UBg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - end-of-stream@1.4.5: - resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} + '@typescript-eslint/utils@8.48.0': + resolution: {integrity: sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - engine.io-client@6.6.3: - resolution: {integrity: sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==} + '@typescript-eslint/visitor-keys@8.40.0': + resolution: {integrity: sha512-8CZ47QwalyRjsypfwnbI3hKy5gJDPmrkLjkgMxhi0+DZZ2QNx2naS6/hWoVYUHU7LU2zleF68V9miaVZvhFfTA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - engine.io-parser@5.2.3: - resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} - engines: {node: '>=10.0.0'} + '@typescript-eslint/visitor-keys@8.48.0': + resolution: {integrity: sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - enhanced-resolve@5.18.3: - resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} - engines: {node: '>=10.13.0'} + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + resolution: {integrity: sha512-ppLRUgHVaGRWUx0R0Ut06Mjo9gBaBkg3v/8AxusGLhsIotbBLuRk51rAzqLC8gq6NyyAojEXglNjzf6R948DNw==} + cpu: [arm] + os: [android] - entities@4.5.0: - resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} - engines: {node: '>=0.12'} + '@unrs/resolver-binding-android-arm64@1.11.1': + resolution: {integrity: sha512-lCxkVtb4wp1v+EoN+HjIG9cIIzPkX5OtM03pQYkG+U5O/wL53LC4QbIeazgiKqluGeVEeBlZahHalCaBvU1a2g==} + cpu: [arm64] + os: [android] - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} + '@unrs/resolver-binding-darwin-arm64@1.11.1': + resolution: {integrity: sha512-gPVA1UjRu1Y/IsB/dQEsp2V1pm44Of6+LWvbLc9SDk1c2KhhDRDBUkQCYVWe6f26uJb3fOK8saWMgtX8IrMk3g==} + cpu: [arm64] + os: [darwin] - env-paths@2.2.1: - resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} - engines: {node: '>=6'} + '@unrs/resolver-binding-darwin-x64@1.11.1': + resolution: {integrity: sha512-cFzP7rWKd3lZaCsDze07QX1SC24lO8mPty9vdP+YVa3MGdVgPmFc59317b2ioXtgCMKGiCLxJ4HQs62oz6GfRQ==} + cpu: [x64] + os: [darwin] - err-code@2.0.3: - resolution: {integrity: sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==} + '@unrs/resolver-binding-freebsd-x64@1.11.1': + resolution: {integrity: sha512-fqtGgak3zX4DCB6PFpsH5+Kmt/8CIi4Bry4rb1ho6Av2QHTREM+47y282Uqiu3ZRF5IQioJQ5qWRV6jduA+iGw==} + cpu: [x64] + os: [freebsd] - error-ex@1.3.2: - resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + resolution: {integrity: sha512-u92mvlcYtp9MRKmP+ZvMmtPN34+/3lMHlyMj7wXJDeXxuM0Vgzz0+PPJNsro1m3IZPYChIkn944wW8TYgGKFHw==} + cpu: [arm] + os: [linux] - es-abstract@1.24.0: - resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} - engines: {node: '>= 0.4'} + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + resolution: {integrity: sha512-cINaoY2z7LVCrfHkIcmvj7osTOtm6VVT16b5oQdS4beibX2SYBwgYLmqhBjA1t51CarSaBuX5YNsWLjsqfW5Cw==} + cpu: [arm] + os: [linux] - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} + cpu: [arm64] + os: [linux] + libc: [glibc] - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} + cpu: [arm64] + os: [linux] + libc: [musl] - es-iterator-helpers@1.2.1: - resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} - engines: {node: '>= 0.4'} + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} + cpu: [ppc64] + os: [linux] + libc: [glibc] - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} + cpu: [riscv64] + os: [linux] + libc: [glibc] - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} + cpu: [riscv64] + os: [linux] + libc: [musl] - es-set-tostringtag@2.1.0: - resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} - engines: {node: '>= 0.4'} + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} + cpu: [s390x] + os: [linux] + libc: [glibc] - es-shim-unscopables@1.1.0: - resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} - engines: {node: '>= 0.4'} + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} + cpu: [x64] + os: [linux] + libc: [glibc] - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} - engines: {node: '>= 0.4'} + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} + cpu: [x64] + os: [linux] + libc: [musl] - es-toolkit@1.33.0: - resolution: {integrity: sha512-X13Q/ZSc+vsO1q600bvNK4bxgXMkHcf//RxCmYDaRY5DAcT+eoXjY5hoAPGMdRnWQjvyLEcyauG3b6hz76LNqg==} + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + resolution: {integrity: sha512-nRcz5Il4ln0kMhfL8S3hLkxI85BXs3o8EYoattsJNdsX4YUU89iOkVn7g0VHSRxFuVMdM4Q1jEpIId1Ihim/Uw==} + cpu: [arm64] + os: [win32] - es6-error@4.1.1: - resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + resolution: {integrity: sha512-DCEI6t5i1NmAZp6pFonpD5m7i6aFrpofcp4LA2i8IIq60Jyo28hamKBxNrZcyOwVOZkgsRp9O2sXWBWP8MnvIQ==} + cpu: [ia32] + os: [win32] - es6-promise@4.2.8: - resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + resolution: {integrity: sha512-lrW200hZdbfRtztbygyaq/6jP6AKE8qQN2KvPcJ+x7wiD038YtnYtZ82IMNJ69GJibV7bwL3y9FgK+5w/pYt6g==} + cpu: [x64] + os: [win32] - es6-promisify@5.0.0: - resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} + '@vitest/expect@3.2.4': + resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - esbuild@0.19.12: - resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} - engines: {node: '>=12'} - hasBin: true + '@vitest/mocker@3.2.4': + resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} + peerDependencies: + msw: ^2.4.9 + vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + peerDependenciesMeta: + msw: + optional: true + vite: + optional: true - esbuild@0.25.9: - resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} - engines: {node: '>=18'} - hasBin: true + '@vitest/pretty-format@3.2.4': + resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} + '@vitest/runner@3.2.4': + resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} - escape-html@1.0.3: - resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + '@vitest/snapshot@3.2.4': + resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} + '@vitest/spy@3.2.4': + resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - eslint-config-next@15.5.7: - resolution: {integrity: sha512-nU/TRGHHeG81NeLW5DeQT5t6BDUqbpsNQTvef1ld/tqHT+/zTx60/TIhKnmPISTTe++DVo+DLxDmk4rnwHaZVw==} - peerDependencies: - eslint: ^7.23.0 || ^8.0.0 || ^9.0.0 - typescript: '>=3.3.1' - peerDependenciesMeta: - typescript: - optional: true + '@vitest/utils@3.2.4': + resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - eslint-config-next@16.0.6: - resolution: {integrity: sha512-nx0Z2S50TlcSQ2RtyULCff5tlKTwqF/ICh3U9s8C/e2aRXAm1Ootdb7BEHGZmejtJSgsFq8PVFdlWy8BHiz2pg==} + '@wagmi/connectors@5.9.4': + resolution: {integrity: sha512-k/GSdYS6nuL0zLq5H7XasPmKr3Gnvplq+yQhTfRBu/o5Bh+B3aH3Jfq1lUh+t3z5kQcyKJIXw/bZIZ7lVS7UhA==} peerDependencies: - eslint: '>=9.0.0' - typescript: '>=3.3.1' + '@wagmi/core': 2.19.0 + typescript: '>=5.0.4' + viem: 2.x peerDependenciesMeta: typescript: optional: true - eslint-config-next@16.0.7: - resolution: {integrity: sha512-WubFGLFHfk2KivkdRGfx6cGSFhaQqhERRfyO8BRx+qiGPGp7WLKcPvYC4mdx1z3VhVRcrfFzczjjTrbJZOpnEQ==} + '@wagmi/connectors@6.2.0': + resolution: {integrity: sha512-2NfkbqhNWdjfibb4abRMrn7u6rPjEGolMfApXss6HCDVt9AW2oVC6k8Q5FouzpJezElxLJSagWz9FW1zaRlanA==} peerDependencies: - eslint: '>=9.0.0' - typescript: '>=3.3.1' + '@wagmi/core': 2.22.1 + typescript: '>=5.0.4' + viem: 2.x peerDependenciesMeta: typescript: optional: true - eslint-config-prettier@10.1.8: - resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - - eslint-import-resolver-node@0.3.9: - resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - - eslint-import-resolver-typescript@3.10.1: - resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} - engines: {node: ^14.18.0 || >=16.0.0} + '@wagmi/core@2.19.0': + resolution: {integrity: sha512-lI57q6refAtNU6xnk/oyOpbEtEiwQ6g4rR+C9FEx8Gn2hZlfoyyksndrl6hIKlMBK+UkkKso3VwR5DI65j/5XQ==} peerDependencies: - eslint: '*' - eslint-plugin-import: '*' - eslint-plugin-import-x: '*' + '@tanstack/query-core': '>=5.0.0' + typescript: '>=5.0.4' + viem: 2.x peerDependenciesMeta: - eslint-plugin-import: + '@tanstack/query-core': optional: true - eslint-plugin-import-x: + typescript: optional: true - eslint-module-utils@2.12.1: - resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} - engines: {node: '>=4'} + '@wagmi/core@2.22.1': + resolution: {integrity: sha512-cG/xwQWsBEcKgRTkQVhH29cbpbs/TdcUJVFXCyri3ZknxhMyGv0YEjTcrNpRgt2SaswL1KrvslSNYKKo+5YEAg==} peerDependencies: - '@typescript-eslint/parser': '*' - eslint: '*' - eslint-import-resolver-node: '*' - eslint-import-resolver-typescript: '*' - eslint-import-resolver-webpack: '*' + '@tanstack/query-core': '>=5.0.0' + typescript: '>=5.0.4' + viem: 2.x peerDependenciesMeta: - '@typescript-eslint/parser': - optional: true - eslint: - optional: true - eslint-import-resolver-node: - optional: true - eslint-import-resolver-typescript: - optional: true - eslint-import-resolver-webpack: + '@tanstack/query-core': optional: true - - eslint-plugin-import@2.32.0: - resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} - engines: {node: '>=4'} - peerDependencies: - '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - peerDependenciesMeta: - '@typescript-eslint/parser': + typescript: optional: true - eslint-plugin-jsdoc@50.8.0: - resolution: {integrity: sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - - eslint-plugin-jsx-a11y@6.10.2: - resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} - engines: {node: '>=4.0'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + '@wallet-standard/app@1.1.0': + resolution: {integrity: sha512-3CijvrO9utx598kjr45hTbbeeykQrQfKmSnxeWOgU25TOEpvcipD/bYDQWIqUv1Oc6KK4YStokSMu/FBNecGUQ==} + engines: {node: '>=16'} - eslint-plugin-prettier@5.5.4: - resolution: {integrity: sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==} - engines: {node: ^14.18.0 || >=16.0.0} - peerDependencies: - '@types/eslint': '>=8.0.0' - eslint: '>=8.0.0' - eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' - prettier: '>=3.0.0' - peerDependenciesMeta: - '@types/eslint': - optional: true - eslint-config-prettier: - optional: true + '@wallet-standard/base@1.1.0': + resolution: {integrity: sha512-DJDQhjKmSNVLKWItoKThJS+CsJQjR9AOBOirBVT1F9YpRyC9oYHE+ZnSf8y8bxUphtKqdQMPVQ2mHohYdRvDVQ==} + engines: {node: '>=16'} - eslint-plugin-react-hooks@5.2.0: - resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} - engines: {node: '>=10'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + '@wallet-standard/features@1.1.0': + resolution: {integrity: sha512-hiEivWNztx73s+7iLxsuD1sOJ28xtRix58W7Xnz4XzzA/pF0+aicnWgjOdA10doVDEDZdUuZCIIqG96SFNlDUg==} + engines: {node: '>=16'} - eslint-plugin-react-hooks@7.0.1: - resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} - engines: {node: '>=18'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 + '@walletconnect/browser-utils@1.8.0': + resolution: {integrity: sha512-Wcqqx+wjxIo9fv6eBUFHPsW1y/bGWWRboni5dfD8PtOmrihrEpOCmvRJe4rfl7xgJW8Ea9UqKEaq0bIRLHlK4A==} - eslint-plugin-react@7.37.5: - resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} - engines: {node: '>=4'} - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + '@walletconnect/client@1.8.0': + resolution: {integrity: sha512-svyBQ14NHx6Cs2j4TpkQaBI/2AF4+LXz64FojTjMtV4VMMhl81jSO1vNeg+yYhQzvjcGH/GpSwixjyCW0xFBOQ==} + deprecated: 'WalletConnect''s v1 SDKs are now deprecated. Please upgrade to a v2 SDK. For details see: https://docs.walletconnect.com/' - eslint-scope@7.2.2: - resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@walletconnect/core@1.8.0': + resolution: {integrity: sha512-aFTHvEEbXcZ8XdWBw6rpQDte41Rxwnuk3SgTD8/iKGSRTni50gI9S3YEzMj05jozSiOBxQci4pJDMVhIUMtarw==} - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@walletconnect/core@2.21.0': + resolution: {integrity: sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==} + engines: {node: '>=18'} - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@walletconnect/core@2.21.1': + resolution: {integrity: sha512-Tp4MHJYcdWD846PH//2r+Mu4wz1/ZU/fr9av1UWFiaYQ2t2TPLDiZxjLw54AAEpMqlEHemwCgiRiAmjR1NDdTQ==} + engines: {node: '>=18'} - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@walletconnect/core@2.23.9': + resolution: {integrity: sha512-ws4WG8LeagUo2ERRo02HryXRcpwIRmCQ3pHLW5gWbVReLXXIpgk6ZAfID3fEGHevIwwnHSGww+nNhNpdXyiq0g==} + engines: {node: '>=18.20.8'} - eslint@8.57.1: - resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. - hasBin: true + '@walletconnect/crypto@1.1.0': + resolution: {integrity: sha512-yZO8BBTQt7BcaemjDgwN56OmSv0OO4QjIpvtfj5OxZfL6IQZQWHOhwC6pJg+BmZPbDlJlWFqFuCZRtiPwRmsoA==} - eslint@9.33.0: - resolution: {integrity: sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true + '@walletconnect/encoding@1.0.2': + resolution: {integrity: sha512-CrwSBrjqJ7rpGQcTL3kU+Ief+Bcuu9PH6JLOb+wM6NITX1GTxR/MfNwnQfhLKK6xpRAyj2/nM04OOH6wS8Imag==} - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@walletconnect/environment@1.0.1': + resolution: {integrity: sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==} - espree@9.6.1: - resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@walletconnect/ethereum-provider@2.21.1': + resolution: {integrity: sha512-SSlIG6QEVxClgl1s0LMk4xr2wg4eT3Zn/Hb81IocyqNSGfXpjtawWxKxiC5/9Z95f1INyBD6MctJbL/R1oBwIw==} - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} - engines: {node: '>=0.10'} + '@walletconnect/events@1.0.1': + resolution: {integrity: sha512-NPTqaoi0oPBVNuLv7qPaJazmGHs5JGyO8eEAk5VGKmJzDR7AHzD4k6ilox5kxk1iwiOnFopBOOMLs86Oa76HpQ==} - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} + '@walletconnect/heartbeat@1.2.2': + resolution: {integrity: sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==} - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} + '@walletconnect/iso-crypto@1.8.0': + resolution: {integrity: sha512-pWy19KCyitpfXb70hA73r9FcvklS+FvO9QUIttp3c2mfW8frxgYeRXfxLRCIQTkaYueRKvdqPjbyhPLam508XQ==} - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} + '@walletconnect/jsonrpc-http-connection@1.0.8': + resolution: {integrity: sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==} - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} + '@walletconnect/jsonrpc-provider@1.0.14': + resolution: {integrity: sha512-rtsNY1XqHvWj0EtITNeuf8PHMvlCLiS3EjQL+WOkxEOA4KPxsohFnBDeyPYiNm4ZvkQdLnece36opYidmtbmow==} - etag@1.8.1: - resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} - engines: {node: '>= 0.6'} + '@walletconnect/jsonrpc-types@1.0.4': + resolution: {integrity: sha512-P6679fG/M+wuWg9TY8mh6xFSdYnFyFjwFelxyISxMDrlbXokorEVXYOxiqEbrU3x1BmBoCAJJ+vtEaEoMlpCBQ==} - eth-block-tracker@7.1.0: - resolution: {integrity: sha512-8YdplnuE1IK4xfqpf4iU7oBxnOYAc35934o083G8ao+8WM8QQtt/mVlAY6yIAdY1eMeLqg4Z//PZjJGmWGPMRg==} - engines: {node: '>=14.0.0'} + '@walletconnect/jsonrpc-utils@1.0.8': + resolution: {integrity: sha512-vdeb03bD8VzJUL6ZtzRYsFMq1eZQcM3EAzT0a3st59dyLfJ0wq+tKMpmGH7HlB7waD858UWgfIcudbPFsbzVdw==} - eth-json-rpc-filters@6.0.1: - resolution: {integrity: sha512-ITJTvqoCw6OVMLs7pI8f4gG92n/St6x80ACtHodeS+IXmO0w+t1T5OOzfSt7KLSMLRkVUoexV7tztLgDxg+iig==} - engines: {node: '>=14.0.0'} + '@walletconnect/jsonrpc-ws-connection@1.0.16': + resolution: {integrity: sha512-G81JmsMqh5nJheE1mPst1W0WfVv0SG3N7JggwLLGnI7iuDZJq8cRJvQwLGKHn5H1WTW7DEPCo00zz5w62AbL3Q==} - eth-query@2.1.2: - resolution: {integrity: sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA==} + '@walletconnect/keyvaluestorage@1.1.1': + resolution: {integrity: sha512-V7ZQq2+mSxAq7MrRqDxanTzu2RcElfK1PfNYiaVnJgJ7Q7G7hTVwF8voIBx92qsRyGHZihrwNPHuZd1aKkd0rA==} + peerDependencies: + '@react-native-async-storage/async-storage': 1.x + peerDependenciesMeta: + '@react-native-async-storage/async-storage': + optional: true - eth-rpc-errors@4.0.3: - resolution: {integrity: sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==} + '@walletconnect/logger@2.1.2': + resolution: {integrity: sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==} - ethereum-cryptography@2.2.1: - resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} + '@walletconnect/logger@3.0.2': + resolution: {integrity: sha512-7wR3wAwJTOmX4gbcUZcFMov8fjftY05+5cO/d4cpDD8wDzJ+cIlKdYOXaXfxHLSYeDazMXIsxMYjHYVDfkx+nA==} - ethers@6.15.0: - resolution: {integrity: sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ==} - engines: {node: '>=14.0.0'} + '@walletconnect/randombytes@1.1.0': + resolution: {integrity: sha512-X+LO/9ClnXX2Q/1+u83qMnohVaxC4qsXByM/gMSwGMrUObxEiqEWS+b9Upg9oNl6mTr85dTCRF8W17KVcKKXQw==} - event-target-shim@5.0.1: - resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} - engines: {node: '>=6'} + '@walletconnect/relay-api@1.0.11': + resolution: {integrity: sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==} - eventemitter2@6.4.9: - resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} + '@walletconnect/relay-auth@1.1.0': + resolution: {integrity: sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==} - eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + '@walletconnect/safe-json@1.0.0': + resolution: {integrity: sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg==} - eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + '@walletconnect/safe-json@1.0.2': + resolution: {integrity: sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==} - events@3.3.0: - resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} - engines: {node: '>=0.8.x'} + '@walletconnect/sign-client@2.21.0': + resolution: {integrity: sha512-z7h+PeLa5Au2R591d/8ZlziE0stJvdzP9jNFzFolf2RG/OiXulgFKum8PrIyXy+Rg2q95U9nRVUF9fWcn78yBA==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' - eventsource-parser@3.0.5: - resolution: {integrity: sha512-bSRG85ZrMdmWtm7qkF9He9TNRzc/Bm99gEJMaQoHJ9E6Kv9QBbsldh2oMj7iXmYNEAVvNgvv5vPorG6W+XtBhQ==} - engines: {node: '>=20.0.0'} + '@walletconnect/sign-client@2.21.1': + resolution: {integrity: sha512-QaXzmPsMnKGV6tc4UcdnQVNOz4zyXgarvdIQibJ4L3EmLat73r5ZVl4c0cCOcoaV7rgM9Wbphgu5E/7jNcd3Zg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' - eventsource@2.0.2: - resolution: {integrity: sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==} - engines: {node: '>=12.0.0'} + '@walletconnect/sign-client@2.23.9': + resolution: {integrity: sha512-Xj+hw4E6mGRyhCdVOT/RMgnG+up/Y3v0ho5PlkVozvXWeVSqHNh9DmjLuU97a7OACoGd/oHBF6g3NVqD7MgCMQ==} - eventsource@3.0.7: - resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} - engines: {node: '>=18.0.0'} + '@walletconnect/socket-transport@1.8.0': + resolution: {integrity: sha512-5DyIyWrzHXTcVp0Vd93zJ5XMW61iDM6bcWT4p8DTRfFsOtW46JquruMhxOLeCOieM4D73kcr3U7WtyR4JUsGuQ==} - execa@5.1.1: - resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} - engines: {node: '>=10'} + '@walletconnect/time@1.0.2': + resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} - expect-type@1.2.2: - resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} - engines: {node: '>=12.0.0'} + '@walletconnect/types@1.8.0': + resolution: {integrity: sha512-Cn+3I0V0vT9ghMuzh1KzZvCkiAxTq+1TR2eSqw5E5AVWfmCtECFkVZBP6uUJZ8YjwLqXheI+rnjqPy7sVM4Fyg==} + deprecated: 'WalletConnect''s v1 SDKs are now deprecated. Please upgrade to a v2 SDK. For details see: https://docs.walletconnect.com/' - exponential-backoff@3.1.2: - resolution: {integrity: sha512-8QxYTVXUkuy7fIIoitQkPwGonB8F3Zj8eEO8Sqg9Zv/bkI7RJAzowee4gr81Hak/dUTpA2Z7VfQgoijjPNlUZA==} + '@walletconnect/types@2.21.0': + resolution: {integrity: sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==} - express-rate-limit@7.5.1: - resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} - engines: {node: '>= 16'} - peerDependencies: - express: '>= 4.11' + '@walletconnect/types@2.21.1': + resolution: {integrity: sha512-UeefNadqP6IyfwWC1Yi7ux+ljbP2R66PLfDrDm8izmvlPmYlqRerJWJvYO4t0Vvr9wrG4Ko7E0c4M7FaPKT/sQ==} - express@4.21.2: - resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} - engines: {node: '>= 0.10.0'} + '@walletconnect/types@2.23.9': + resolution: {integrity: sha512-IUl1PpD/Dig8IE2OZ9XtjbPohEyOZJ73xs92EDUzoIyzRtfm36g2D340pY3iu3AAdLv1yFiaZafB8Hf8RFze8A==} - express@5.1.0: - resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} - engines: {node: '>= 18'} + '@walletconnect/universal-provider@2.21.0': + resolution: {integrity: sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' - extension-port-stream@3.0.0: - resolution: {integrity: sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==} - engines: {node: '>=12.0.0'} + '@walletconnect/universal-provider@2.21.1': + resolution: {integrity: sha512-Wjx9G8gUHVMnYfxtasC9poGm8QMiPCpXpbbLFT+iPoQskDDly8BwueWnqKs4Mx2SdIAWAwuXeZ5ojk5qQOxJJg==} + deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' - extract-zip@2.0.1: - resolution: {integrity: sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==} - engines: {node: '>= 10.17.0'} - hasBin: true + '@walletconnect/utils@1.8.0': + resolution: {integrity: sha512-zExzp8Mj1YiAIBfKNm5u622oNw44WOESzo6hj+Q3apSMIb0Jph9X3GDIdbZmvVZsNPxWDL7uodKgZcCInZv2vA==} - extsprintf@1.4.1: - resolution: {integrity: sha512-Wrk35e8ydCKDj/ArClo1VrPVmN8zph5V4AtHwIuHhvMXsKf73UT3BOD+azBIW+3wOJ4FhEH7zyaJCFvChjYvMA==} - engines: {'0': node >=0.6.0} + '@walletconnect/utils@2.21.0': + resolution: {integrity: sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==} - eyes@0.1.8: - resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} - engines: {node: '> 0.1.90'} + '@walletconnect/utils@2.21.1': + resolution: {integrity: sha512-VPZvTcrNQCkbGOjFRbC24mm/pzbRMUq2DSQoiHlhh0X1U7ZhuIrzVtAoKsrzu6rqjz0EEtGxCr3K1TGRqDG4NA==} - fast-decode-uri-component@1.0.1: - resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} + '@walletconnect/utils@2.23.9': + resolution: {integrity: sha512-C5TltCs8UPypNiteYnKSv8+ZDK2EjVDyXCxN6kA9bkA+j6KGsNIV7l9MUA8WBAvE5Gi5EcBdhD3R9Hpo/1HHqQ==} - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + '@walletconnect/window-getters@1.0.0': + resolution: {integrity: sha512-xB0SQsLaleIYIkSsl43vm8EwETpBzJ2gnzk7e0wMF3ktqiTGS6TFHxcprMl5R44KKh4tCcHCJwolMCaDSwtAaA==} - fast-diff@1.3.0: - resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} + '@walletconnect/window-getters@1.0.1': + resolution: {integrity: sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==} - fast-glob@3.3.1: - resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} - engines: {node: '>=8.6.0'} + '@walletconnect/window-metadata@1.0.0': + resolution: {integrity: sha512-9eFvmJxIKCC3YWOL97SgRkKhlyGXkrHwamfechmqszbypFspaSk+t2jQXAEU7YClHF6Qjw5eYOmy1//zFi9/GA==} - fast-glob@3.3.3: - resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} - engines: {node: '>=8.6.0'} + '@walletconnect/window-metadata@1.0.1': + resolution: {integrity: sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==} - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + '@x402/core@2.11.0': + resolution: {integrity: sha512-aqTfZc/BULrlWnd3I0lsqRQaH4gjJd8CsPcL16XqK2Lx5c6QDm+zCljgUVS1yj9BGJoZeQWTzI5hE+SVFkqMTw==} - fast-json-stringify@6.3.0: - resolution: {integrity: sha512-oRCntNDY/329HJPlmdNLIdogNtt6Vyjb1WuT01Soss3slIdyUp8kAcDU3saQTOquEK8KFVfwIIF7FebxUAu+yA==} + '@x402/evm@2.11.0': + resolution: {integrity: sha512-F8uU1txDZA+wc/sEnmaHAyYvoTi/w39r7K3a44MmQHSxECDTEuB3A0FwbxOxUPLN1eyCxTAFKEiqlGe3bwybKA==} - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + abitype@1.0.6: + resolution: {integrity: sha512-MMSqYh4+C/aVqI2RQaWqbvI4Kxo5cQV40WQ4QFtDnNzCkqChm8MuENhElmynZlO0qUy/ObkEUaXtKqYnx1Kp3A==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3 >=3.22.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true - fast-querystring@1.1.2: - resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} + abitype@1.0.8: + resolution: {integrity: sha512-ZeiI6h3GnW06uYDLx0etQtX/p8E24UaHHBj57RSjK7YBFe7iuVn07EDpOeP451D06sF27VOz9JJPlIKJmXgkEg==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3 >=3.22.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true - fast-redact@3.5.0: - resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} - engines: {node: '>=6'} + abitype@1.2.3: + resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} + peerDependencies: + typescript: '>=5.0.4' + zod: ^3.22.0 || ^4.0.0 + peerDependenciesMeta: + typescript: + optional: true + zod: + optional: true - fast-safe-stringify@2.1.1: - resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} - fast-sha256@1.3.0: - resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} + abstract-logging@2.0.1: + resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} - fast-stable-stringify@1.0.0: - resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} + accepts@1.3.8: + resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} + engines: {node: '>= 0.6'} - fast-uri@3.0.6: - resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} - fastestsmallesttextencoderdecoder@1.0.22: - resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - fastify@5.8.2: - resolution: {integrity: sha512-lZmt3navvZG915IE+f7/TIVamxIwmBd+OMB+O9WBzcpIwOo6F0LTh0sluoMFk5VkrKTvvrwIaoJPkir4Z+jtAg==} + acorn-walk@8.3.5: + resolution: {integrity: sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==} + engines: {node: '>=0.4.0'} - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} - fd-slicer@1.1.0: - resolution: {integrity: sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==} + agentkeepalive@4.6.0: + resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} + engines: {node: '>= 8.0.0'} - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: - picomatch: ^3 || ^4 + ajv: ^8.0.0 peerDependenciesMeta: - picomatch: + ajv: optional: true - feaxios@0.0.23: - resolution: {integrity: sha512-eghR0A21fvbkcQBgZuMfQhrXxJzC0GNUGC9fXhBge33D+mFDTwl0aJ35zoQQn575BhyjQitRc5N4f+L4cP708g==} + ajv@6.12.6: + resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - fecha@4.2.3: - resolution: {integrity: sha512-OP2IUU6HeYKJi3i0z4A19kHMQoLVs4Hc+DPqqxI2h/DPZHTm/vjsfC6P0b4jCMy14XizLBqvndQ+UilD7707Jw==} + ajv@8.17.1: + resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} - fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} + algo-msgpack-with-bigint@2.1.1: + resolution: {integrity: sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==} + engines: {node: '>= 10'} - file-entry-cache@6.0.1: - resolution: {integrity: sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==} - engines: {node: ^10.12.0 || >=12.0.0} + algorand-msgpack@1.1.0: + resolution: {integrity: sha512-08k7pBQnkaUB5p+jL7f1TRaUIlTSDE0cesFu1mD7llLao+1cAhtvvZmGE3OnisTd0xOn118QMw74SRqddqaYvw==} + engines: {node: '>= 14'} - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} + algosdk@3.5.2: + resolution: {integrity: sha512-frhGtZl1JvfrLRKmMvUm880wj4OiWsWo2FhbreNWh7pdFsKuWPj60fV682wt/CYefLI70iwHavPOwGBkTVt0VA==} + engines: {node: '>=18.0.0'} - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + anser@1.4.10: + resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} - filelist@1.0.4: - resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + ansi-regex@6.2.0: + resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} + engines: {node: '>=12'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - filter-obj@1.1.0: - resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} - engines: {node: '>=0.10.0'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} - finalhandler@1.3.1: - resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} - engines: {node: '>= 0.8'} + ansi-styles@6.2.1: + resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} + engines: {node: '>=12'} - finalhandler@2.1.0: - resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} - engines: {node: '>= 0.8'} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} - find-my-way@9.5.0: - resolution: {integrity: sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ==} - engines: {node: '>=20'} + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - find-up@4.1.0: - resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} - engines: {node: '>=8'} + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + apg-js@4.4.0: + resolution: {integrity: sha512-fefmXFknJmtgtNEXfPwZKYkMFX4Fyeyz+fNF6JWp87biGOPslJbCBVU158zvKRZfHBKnJDy8CMM40oLFGkXT8Q==} + + are-docs-informative@0.0.2: + resolution: {integrity: sha512-ixiS0nLNNG5jNQzgZJNoUpBKdo9yTYZMGJ+QgT2jmjR7G7+QHRCc4v6LQ3NgE7EBJq+o0ams3waJwkrlBom8Ig==} + engines: {node: '>=14'} + + arg@4.1.3: + resolution: {integrity: sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} - fix-dts-default-cjs-exports@1.0.1: - resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + aria-query@5.3.2: + resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} + engines: {node: '>= 0.4'} - flat-cache@3.2.0: - resolution: {integrity: sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==} - engines: {node: ^10.12.0 || >=12.0.0} + array-buffer-byte-length@1.0.2: + resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} + engines: {node: '>= 0.4'} - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} + array-flatten@1.1.1: + resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} + engines: {node: '>= 0.4'} - fn.name@1.1.0: - resolution: {integrity: sha512-GRnmB5gPyJpAhTQdSZTSp9uaPSvl09KoYcMQtsB9rQoOmzs9dH6ffeccH+Z+cv6P68Hu5bC6JjRh4Ah/mHSNRw==} + array.prototype.findlast@1.2.5: + resolution: {integrity: sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==} + engines: {node: '>= 0.4'} - follow-redirects@1.15.11: - resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} - engines: {node: '>=4.0'} - peerDependencies: - debug: '*' - peerDependenciesMeta: - debug: - optional: true + array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + array.prototype.flat@1.3.3: + resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} + engines: {node: '>= 0.4'} + + array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + + array.prototype.tosorted@1.1.4: + resolution: {integrity: sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==} + engines: {node: '>= 0.4'} + + arraybuffer.prototype.slice@1.0.4: + resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} - foreground-child@3.3.1: - resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} - engines: {node: '>=14'} - - form-data-encoder@1.7.2: - resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} - form-data@4.0.4: - resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} - engines: {node: '>= 6'} + asn1js@3.0.6: + resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==} + engines: {node: '>=12.0.0'} - formdata-node@4.4.1: - resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} - engines: {node: '>= 12.20'} + assertion-error@2.0.1: + resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} + engines: {node: '>=12'} - formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} + ast-types-flow@0.0.8: + resolution: {integrity: sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==} - forwarded@0.2.0: - resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} - engines: {node: '>= 0.6'} + async-function@1.0.0: + resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} + engines: {node: '>= 0.4'} - fresh@0.5.2: - resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} - engines: {node: '>= 0.6'} + async-mutex@0.2.6: + resolution: {integrity: sha512-Hs4R+4SPgamu6rSGW8C7cV9gaWUKEHykfzCCvIRuaVv636Ju10ZdeUbvb4TBEW0INuq2DHZqXbK4Nd3yG4RaRw==} - fresh@2.0.0: - resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} - engines: {node: '>= 0.8'} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - fs-extra@10.1.0: - resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} - engines: {node: '>=12'} + atomic-sleep@1.0.0: + resolution: {integrity: sha512-kNOjDqAh7px0XWNI+4QbzoiR/nTkHAWNud2uvnJquD1/x5a7EQZMJT0AczqK0Qn67oY/TTQ1LbUKajZpp3I9tQ==} + engines: {node: '>=8.0.0'} - fs-extra@11.3.1: - resolution: {integrity: sha512-eXvGGwZ5CL17ZSwHWd3bbgk7UUpF6IFHtP57NYYakPvHOs8GDgDe5KJI36jIJzDkJ6eJjuzRA8eBQb6SkKue0g==} - engines: {node: '>=14.14'} + available-typed-arrays@1.0.7: + resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} + engines: {node: '>= 0.4'} - fs-extra@7.0.1: - resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} - engines: {node: '>=6 <7 || >=8'} + avvio@9.2.0: + resolution: {integrity: sha512-2t/sy01ArdHHE0vRH5Hsay+RtCZt3dLPji7W7/MMOCEgze5b7SNDC4j5H6FnVgPkI1MTNFGzHdHrVXDDl7QSSQ==} - fs-extra@8.1.0: - resolution: {integrity: sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==} - engines: {node: '>=6 <7 || >=8'} + aws-cdk-lib@2.252.0: + resolution: {integrity: sha512-bRLyTtJxhVgsx2JrL2B/KYYWf+Rg0s68UgQp+VRZK0h5fXeaPqDVEJGPMr7FiOgrmYwEadjfbxsTsZKNAloAvg==} + engines: {node: '>= 20.0.0'} + peerDependencies: + constructs: ^10.5.0 + bundledDependencies: + - '@balena/dockerignore' + - '@aws-cdk/cloud-assembly-api' + - case + - fs-extra + - ignore + - jsonschema + - minimatch + - punycode + - semver + - table + - yaml + - mime-types - fs-extra@9.1.0: - resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} - engines: {node: '>=10'} + aws-cdk@2.1120.0: + resolution: {integrity: sha512-vDVa0IX0FhizARdY/GLSParFglKbdHCIhM8IDmynrAv9w8uLLljzWMeLUOhC1XpMErDZ/npYEihAOjfKxTaMIw==} + engines: {node: '>= 18.0.0'} + hasBin: true - fs-minipass@2.1.0: - resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} - engines: {node: '>= 8'} + axe-core@4.10.3: + resolution: {integrity: sha512-Xm7bpRXnDSX2YE2YFfBk2FnF0ep6tmG7xPh8iHee8MIcrgq762Nkce856dYtJYLkuIoYZvGfTs/PbZhideTcEg==} + engines: {node: '>=4'} - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + axios-retry@4.5.0: + resolution: {integrity: sha512-aR99oXhpEDGo0UuAlYcn2iGRds30k366Zfa05XWScR9QaQD4JYiP3/1Qt1u7YlefUOK+cn0CcwoL1oefavQUlQ==} + peerDependencies: + axios: 0.x || 1.x - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] + axios@1.13.2: + resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + axios@1.13.4: + resolution: {integrity: sha512-1wVkUaAO6WyaYtCkcYCOx12ZgpGf9Zif+qXa4n+oYzK558YryKqiL6UWwd5DqiH3VRW0GYhTZQ/vlgJrCoNQlg==} - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + axobject-query@4.1.0: + resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} engines: {node: '>= 0.4'} - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} + babel-plugin-syntax-hermes-parser@0.33.3: + resolution: {integrity: sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA==} - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - get-caller-file@2.0.5: - resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} - engines: {node: 6.* || 8.* || >= 10.*} + base-x@3.0.11: + resolution: {integrity: sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==} - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} + base-x@5.0.1: + resolution: {integrity: sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==} - get-nonce@1.0.1: - resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} - engines: {node: '>=6'} + base32.js@0.1.0: + resolution: {integrity: sha512-n3TkB02ixgBOhTvANakDb4xaMXnYUVkNoRFJjQflcqMQhyEKxEHdj3E6N8t8sUQ0mjH/3/JxzlXuz3ul/J90pQ==} + engines: {node: '>=0.12.0'} - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - get-stream@5.2.0: - resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} - engines: {node: '>=8'} + big.js@6.2.2: + resolution: {integrity: sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==} - get-stream@6.0.1: - resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} - engines: {node: '>=10'} + bignumber.js@9.1.1: + resolution: {integrity: sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==} - get-symbol-description@1.1.0: - resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} - engines: {node: '>= 0.4'} + bignumber.js@9.3.1: + resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} - get-tsconfig@4.10.1: - resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} + blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} + bn.js@4.11.8: + resolution: {integrity: sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==} - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} + bn.js@4.12.3: + resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} - glob@10.4.5: - resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - hasBin: true + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + bn.js@5.2.2: + resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} - glob@8.1.0: - resolution: {integrity: sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==} - engines: {node: '>=12'} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + body-parser@1.20.3: + resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - global-agent@3.0.0: - resolution: {integrity: sha512-PT6XReJ+D07JvGoxQMkT6qji/jVNfX/h364XHZOWeRzy64sSFr+xJ5OX7LI3b4MPQzdL4H8Y8M0xzPpsVMwA8Q==} - engines: {node: '>=10.0'} + body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} - globals@13.24.0: - resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} - engines: {node: '>=8'} + borsh@0.7.0: + resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} + bowser@2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} - globals@16.4.0: - resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} - engines: {node: '>=18'} + bowser@2.12.0: + resolution: {integrity: sha512-HcOcTudTeEWgbHh0Y1Tyb6fdeR71m4b/QACf0D4KswGTsNeIJQmg38mRENZPAYPZvGFN3fk3604XbQEPdxXdKg==} - globalthis@1.0.4: - resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} - engines: {node: '>= 0.4'} + brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - globby@11.1.0: - resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} - engines: {node: '>=10'} + brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} - goober@2.1.16: - resolution: {integrity: sha512-erjk19y1U33+XAMe1VTvIONHYoSqE4iS7BYUZfHaqeohLmnC0FdxEh7rQU+6MZ4OajItzjZFSRtVANrQwNq6/g==} - peerDependencies: - csstype: ^3.0.10 + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} + browserslist@4.25.3: + resolution: {integrity: sha512-cDGv1kkDI4/0e5yON9yM5G/0A5u8sf5TnmdX5C9qHzI9PPu++sQ9zjm1k9NiOrf3riY4OkK0zSGqfvJyJsgCBQ==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true - got@11.8.6: - resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} - engines: {node: '>=10.19.0'} + bs58@4.0.1: + resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} - graceful-fs@4.2.11: - resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + bs58@6.0.0: + resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} - graphql-request@6.1.0: - resolution: {integrity: sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==} - peerDependencies: - graphql: 14 - 16 + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - graphql@16.11.0: - resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} - engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} + buffer@6.0.3: + resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} - h3@1.15.4: - resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} + bufferutil@4.0.9: + resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==} + engines: {node: '>=6.14.2'} - has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + cacheable-lookup@5.0.4: + resolution: {integrity: sha512-2/kNscPhpcxrOigMZzbiWF7dz8ilhb/nIHU3EyZiXWXpeq/au8qJ8VhdftMkty3n7Gj6HIGalQG8oiBNB3AJgA==} + engines: {node: '>=10.6.0'} - has-proto@1.2.0: - resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + cacheable-request@7.0.4: + resolution: {integrity: sha512-v+p6ongsrp0yTGbJXjgxPow2+DL93DASP4kXCDKb8/bwRtt9OEF3whggkkDkGNzgcWy2XaF4a8nZglC7uElscg==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + call-bind@1.0.8: + resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} engines: {node: '>= 0.4'} - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} - hash-base@3.1.0: - resolution: {integrity: sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==} - engines: {node: '>=4'} + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + caniuse-lite@1.0.30001735: + resolution: {integrity: sha512-EV/laoX7Wq2J9TQlyIXRxTJqIw4sxfXS4OYgudGxBYRuTv0q7AM6yMEpU/Vo1I94thg9U6EZ2NfZx9GJq83u7w==} + + chai@5.3.1: + resolution: {integrity: sha512-48af6xm9gQK8rhIcOxWwdGzIervm8BVTin+yRp9HEvU20BtVZ2lBywlIJBzwaDtvo0FvjeL7QdCADoUoqIbV3A==} + engines: {node: '>=18'} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - hash.js@1.1.7: - resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + charenc@0.0.2: + resolution: {integrity: sha512-yrLQ/yVUFXkzg7EDQsPieE/53+0RlaWTs+wBrvW36cyilJ2SaDWfl4Yj7MtLTXleV9uEKefbAGUPv2/iWSooRA==} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + check-error@2.1.1: + resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} + engines: {node: '>= 16'} - hermes-estree@0.25.1: - resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} - hermes-parser@0.25.1: - resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + chrome-launcher@0.15.2: + resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} + engines: {node: '>=12.13.0'} + hasBin: true - hmac-drbg@1.0.1: - resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + chromium-edge-launcher@0.3.0: + resolution: {integrity: sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==} - hono@4.10.7: - resolution: {integrity: sha512-icXIITfw/07Q88nLSkB9aiUrd8rYzSweK681Kjo/TSggaGbOX4RRyxxm71v+3PC8C/j+4rlxGeoTRxQDkaJkUw==} - engines: {node: '>=16.9.0'} + ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} - hosted-git-info@4.1.0: - resolution: {integrity: sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==} - engines: {node: '>=10'} + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} + client-only@0.0.1: + resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - html-to-text@9.0.5: - resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} - engines: {node: '>=14'} + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} - htmlparser2@8.0.2: - resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} - http-cache-semantics@4.2.0: - resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} + clone-response@1.0.3: + resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} - http-errors@2.0.0: - resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} - engines: {node: '>= 0.8'} + clsx@1.2.1: + resolution: {integrity: sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg==} + engines: {node: '>=6'} - http-proxy-agent@5.0.0: - resolution: {integrity: sha512-n2hY8YdoRE1i7r6M0w9DIw5GgZN0G25P8zLCRQ8rjXtTU3vsNFBI/vWK/UIeE6g5MUUz6avwAPXmL6Fy9D/90w==} - engines: {node: '>= 6'} + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} + cluster-key-slot@1.1.2: + resolution: {integrity: sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==} + engines: {node: '>=0.10.0'} - http2-wrapper@1.0.3: - resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} - engines: {node: '>=10.19.0'} + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} - https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} - human-signals@2.1.0: - resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} - engines: {node: '>=10.17.0'} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} - humanize-ms@1.2.1: - resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} + comlink@4.4.2: + resolution: {integrity: sha512-OxGdvBmJuNKSCMO4NTl1L47VRp6xn2wG4F/2hYzB6tiCb709otOxtEYCSvK80PtjODfXXZu8ds+Nw5kVCjqd2g==} - iconv-corefoundation@1.1.7: - resolution: {integrity: sha512-T10qvkw0zz4wnm560lOEg0PovVqUXuOFhhHAkixw8/sycy7TJt7v/RrkEKEQnAw2viPSJu6iAkErxnzR0g8PpQ==} - engines: {node: ^8.11.2 || >=10} - os: [darwin] + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} - iconv-lite@0.4.24: - resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} - engines: {node: '>=0.10.0'} + commander@14.0.0: + resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} + engines: {node: '>=20'} - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} + commander@14.0.2: + resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} + engines: {node: '>=20'} - idb-keyval@6.2.1: - resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==} + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} - idb-keyval@6.2.2: - resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==} + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} + comment-parser@1.4.1: + resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==} + engines: {node: '>= 12.0.0'} - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} + connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} - infer-owner@1.0.4: - resolution: {integrity: sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==} + constructs@10.6.0: + resolution: {integrity: sha512-TxHOnBO5zMo/G76ykzGF/wMpEHu257TbWiIxP9K0Yv/+t70UzgBQiTqjkAsWOPC6jW91DzJI0+ehQV6xDRNBuQ==} - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + content-disposition@0.5.4: + resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} + engines: {node: '>= 0.6'} - inherits@2.0.4: - resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} - internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} - ip-address@10.0.1: - resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} - engines: {node: '>= 12'} + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - ipaddr.js@1.9.1: - resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} - engines: {node: '>= 0.10'} + cookie-es@1.2.2: + resolution: {integrity: sha512-+W7VmiVINB+ywl1HGXJXmrqkOhpKrIiVZV6tQuV54ZyQC7MMuBt81Vc336GMLoHBq5hV/F9eXgt5Mnx0Rha5Fg==} - ipaddr.js@2.3.0: - resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} - engines: {node: '>= 10'} + cookie-signature@1.0.6: + resolution: {integrity: sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==} - iron-webcrypto@1.2.1: - resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} - is-arguments@1.2.0: - resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} - engines: {node: '>= 0.4'} + cookie@0.7.1: + resolution: {integrity: sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==} + engines: {node: '>= 0.6'} - is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} - is-arrayish@0.2.1: - resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} - is-arrayish@0.3.2: - resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} + core-util-is@1.0.3: + resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} - is-async-function@2.1.1: - resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} - engines: {node: '>= 0.4'} + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} - is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} + crc-32@1.2.2: + resolution: {integrity: sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==} + engines: {node: '>=0.8'} + hasBin: true - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} + create-require@1.1.1: + resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==} - is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} + cross-fetch@3.2.0: + resolution: {integrity: sha512-Q+xVJLoGOeIMXZmbUK4HYk+69cQH6LudR0Vu/pRm2YlU/hDV9CiS0gKUMaWY5f2NeUH9C1nV3bsTlCo0FsTV1Q==} - is-buffer@1.1.6: - resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} + cross-fetch@4.1.0: + resolution: {integrity: sha512-uKm5PU+MHTootlWEY+mZ4vvXoCn4fLQxT9dSc1sXVMSFkINTJVN8cAQROpwcKm8bJ/c7rgZVIBWzH5T78sNZZw==} - is-buffer@2.0.5: - resolution: {integrity: sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==} - engines: {node: '>=4'} + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} - is-bun-module@2.0.0: - resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} + crossws@0.3.5: + resolution: {integrity: sha512-ojKiDvcmByhwa8YYqbQI/hg7MEU0NC03+pSdEq4ZUnZR9xXpwk7E43SMNGkn+JxJGPFtNvQ48+vV2p+P1ml5PA==} - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} + crypt@0.0.2: + resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} - is-ci@3.0.1: - resolution: {integrity: sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==} - hasBin: true + crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} + cssstyle@4.6.0: + resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} + engines: {node: '>=18'} - is-data-view@1.0.2: - resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} - engines: {node: '>= 0.4'} + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} + damerau-levenshtein@1.0.8: + resolution: {integrity: sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==} - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} + data-urls@5.0.0: + resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} + engines: {node: '>=18'} - is-finalizationregistry@1.1.1: - resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + data-view-buffer@1.0.2: + resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} - is-fullwidth-code-point@3.0.0: - resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} - engines: {node: '>=8'} + data-view-byte-length@1.0.2: + resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} + engines: {node: '>= 0.4'} - is-generator-function@1.1.0: - resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + data-view-byte-offset@1.0.1: + resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-interactive@1.0.0: - resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==} - engines: {node: '>=8'} + date-fns@2.30.0: + resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} + engines: {node: '>=0.11'} - is-lambda@1.0.1: - resolution: {integrity: sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==} + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} - is-negative-zero@2.0.3: - resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} - engines: {node: '>= 0.4'} + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true - is-network-error@1.1.0: - resolution: {integrity: sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==} - engines: {node: '>=16'} + debug@3.2.7: + resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true - is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} + debug@4.3.7: + resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true - is-path-inside@3.0.3: - resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} - engines: {node: '>=8'} + debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} - is-promise@4.0.0: - resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + decimal.js@10.6.0: + resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} + decode-uri-component@0.2.2: + resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==} + engines: {node: '>=0.10'} - is-retry-allowed@2.2.0: - resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==} + decompress-response@6.0.0: + resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} engines: {node: '>=10'} - is-retry-allowed@3.0.0: - resolution: {integrity: sha512-9xH0xvoggby+u0uGF7cZXdrutWiBiaFG8ZT4YFPXL8NzkyAwX3AKGLeFQLvzDpM430+nDFBZ1LHkie/8ocL06A==} - engines: {node: '>=12'} - - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} + deep-eql@5.0.2: + resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} + engines: {node: '>=6'} - is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - is-stream@2.0.1: - resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} - engines: {node: '>=8'} + defer-to-connect@2.0.1: + resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==} + engines: {node: '>=10'} - is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} - is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + define-properties@1.2.1: + resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - is-typed-array@1.1.15: - resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} - engines: {node: '>= 0.4'} + defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} - is-unicode-supported@0.1.0: - resolution: {integrity: sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==} + delay@5.0.0: + resolution: {integrity: sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==} engines: {node: '>=10'} - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} - is-weakref@1.1.1: - resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} - engines: {node: '>= 0.4'} + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} - is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} - isarray@1.0.0: - resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} + derive-valtio@0.1.0: + resolution: {integrity: sha512-OCg2UsLbXK7GmmpzMXhYkdO64vhJ1ROUUGaTFyHjVwEdMEcTTRj7W1TxLbSBxdY8QLBPCcp66MTyaSy0RpO17A==} + peerDependencies: + valtio: '*' - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + destr@2.0.5: + resolution: {integrity: sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==} - isbinaryfile@4.0.10: - resolution: {integrity: sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==} - engines: {node: '>= 8.0.0'} + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} - isbinaryfile@5.0.4: - resolution: {integrity: sha512-YKBKVkKhty7s8rxddb40oOkuP0NbaeXrQvLin6QMHL7Ypiy2RW9LwOVrVgZRyOrhQlayMd9t+D8yDy8MKFTSDQ==} - engines: {node: '>= 18.0.0'} + detect-browser@5.2.0: + resolution: {integrity: sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA==} - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + detect-browser@5.3.0: + resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==} - isomorphic-ws@4.0.1: - resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} - peerDependencies: - ws: '*' + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} - isows@1.0.6: - resolution: {integrity: sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==} - peerDependencies: - ws: '*' + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - isows@1.0.7: - resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} - peerDependencies: - ws: '*' + diff@4.0.4: + resolution: {integrity: sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==} + engines: {node: '>=0.3.1'} - iterator.prototype@1.1.5: - resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} - engines: {node: '>= 0.4'} + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} - jackspeak@3.4.3: - resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + doctrine@2.1.0: + resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==} + engines: {node: '>=0.10.0'} - jake@10.9.4: - resolution: {integrity: sha512-wpHYzhxiVQL+IV05BLE2Xn34zW1S223hvjtqk0+gsPrwd/8JNLXJgZZM/iPFsYc1xyphF+6M6EvdE5E9MBGkDA==} - engines: {node: '>=10'} - hasBin: true + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} - jayson@4.2.0: - resolution: {integrity: sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==} - engines: {node: '>=8'} - hasBin: true + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} - jiti@1.21.7: - resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} - hasBin: true + duplexify@4.1.3: + resolution: {integrity: sha512-M3BmBhwJRZsSx38lZyhE53Csddgzl5R7xGJNk7CVddZD6CcmwMCH8J+7AprIrQKH7TonKxaCjcv27Qmf+sQ+oA==} - jiti@2.6.1: - resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} - hasBin: true + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - jose@4.15.9: - resolution: {integrity: sha512-1vUQX+IdDMVPj4k8kOxgUqlcK518yluMuGZwqlr44FS1ppZB/5GWh4rZG89erpOBOJjU/OBsnCVFfapsRz6nEA==} + eciesjs@0.4.15: + resolution: {integrity: sha512-r6kEJXDKecVOCj2nLMuXK/FCPeurW33+3JRpfXVbjLja3XUYFfD9I/JBreH6sUyzcm3G/YQboBjMla6poKeSdA==} + engines: {bun: '>=1', deno: '>=2', node: '>=16'} - jose@5.10.0: - resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} - jose@6.0.12: - resolution: {integrity: sha512-T8xypXs8CpmiIi78k0E+Lk7T2zlK4zDyg+o1CZ4AkOHgDg98ogdP2BeZ61lTFKFyoEwJ9RgAgN+SdM3iPgNonQ==} + electron-to-chromium@1.5.207: + resolution: {integrity: sha512-mryFrrL/GXDTmAtIVMVf+eIXM09BBPlO5IQ7lUyKmK8d+A4VpRGG+M3ofoVef6qyF8s60rJei8ymlJxjUA8Faw==} - joycon@3.1.1: - resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} - engines: {node: '>=10'} + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} - js-base64@3.7.8: - resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - js-tiktoken@1.0.21: - resolution: {integrity: sha512-biOj/6M5qdgx5TKjDnFT1ymSpM5tbd3ylwDtrQvFQSu0Z7bBYko2dF+W/aUkXUPuk6IVpRxk/3Q2sHOzGlS36g==} + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + encode-utf8@1.0.3: + resolution: {integrity: sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==} - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} - js-yaml@4.1.0: - resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} - hasBin: true + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} - jsdoc-type-pratt-parser@4.1.0: - resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} - engines: {node: '>=12.0.0'} + end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - jsdom@26.1.0: - resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==} - engines: {node: '>=18'} - peerDependencies: - canvas: ^3.0.0 - peerDependenciesMeta: - canvas: - optional: true + engine.io-client@6.6.3: + resolution: {integrity: sha512-T0iLjnyNWahNyv/lcjS2y4oE358tVS/SYQNxYXGAJ9/GLgH4VCvOQ/mhTjqU88mLZCQgiG8RIegFHYCdVC+j5w==} + + engine.io-parser@5.2.3: + resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} + engines: {node: '>=10.0.0'} - jsesc@3.0.2: - resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} - engines: {node: '>=6'} - hasBin: true + enhanced-resolve@5.18.3: + resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + engines: {node: '>=10.13.0'} - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true + entities@6.0.1: + resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + engines: {node: '>=0.12'} - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} - json-parse-even-better-errors@2.3.1: - resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + engines: {node: '>= 0.4'} - json-rpc-engine@6.1.0: - resolution: {integrity: sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==} - engines: {node: '>=10.0.0'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} - json-rpc-random-id@1.0.1: - resolution: {integrity: sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA==} + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} - json-schema-ref-resolver@3.0.0: - resolution: {integrity: sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==} + es-iterator-helpers@1.2.1: + resolution: {integrity: sha512-uDn+FE1yrDzyC0pCo961B2IHbdM8y/ACZsKD4dG6WqrjV53BADjwa7D+1aom2rsNVfLyDgU/eigvlJGJ08OQ4w==} + engines: {node: '>= 0.4'} - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + es-module-lexer@1.7.0: + resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - json-schema-traverse@1.0.0: - resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} - json-stringify-safe@5.0.1: - resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} + es-shim-unscopables@1.1.0: + resolution: {integrity: sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==} + engines: {node: '>= 0.4'} - json5@1.0.2: - resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} - hasBin: true + es-to-primitive@1.3.0: + resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + engines: {node: '>= 0.4'} - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true + es-toolkit@1.33.0: + resolution: {integrity: sha512-X13Q/ZSc+vsO1q600bvNK4bxgXMkHcf//RxCmYDaRY5DAcT+eoXjY5hoAPGMdRnWQjvyLEcyauG3b6hz76LNqg==} - jsonfile@4.0.0: - resolution: {integrity: sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==} + es-toolkit@1.44.0: + resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==} - jsonfile@6.2.0: - resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + es6-promise@4.2.8: + resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} - jsx-ast-utils@3.3.5: - resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} - engines: {node: '>=4.0'} + es6-promisify@5.0.0: + resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} - jwt-decode@4.0.0: - resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + esbuild@0.25.9: + resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} engines: {node: '>=18'} + hasBin: true - keccak@3.0.4: - resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} - engines: {node: '>=10.0.0'} + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} - keyvaluestorage-interface@1.0.0: - resolution: {integrity: sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==} + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} - kuler@2.0.0: - resolution: {integrity: sha512-Xq9nH7KlWZmXAtodXDDRE7vs6DU1gTU8zYDHDiWLSip45Egwq3plLHzPn27NgvzL2r1LMPC1vdqh98sQxtqj4A==} + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} - langsmith@0.3.62: - resolution: {integrity: sha512-ApoGLs28cJCxL91l1PDDkjsA4oLrbeNlE1pyTvyopqXq9bNJrP8JPUNWZm/tpU0DzZpvZFctRzru4gNAr/bkxg==} + eslint-config-next@16.0.6: + resolution: {integrity: sha512-nx0Z2S50TlcSQ2RtyULCff5tlKTwqF/ICh3U9s8C/e2aRXAm1Ootdb7BEHGZmejtJSgsFq8PVFdlWy8BHiz2pg==} peerDependencies: - '@opentelemetry/api': '*' - '@opentelemetry/exporter-trace-otlp-proto': '*' - '@opentelemetry/sdk-trace-base': '*' - openai: '*' + eslint: '>=9.0.0' + typescript: '>=3.3.1' peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@opentelemetry/exporter-trace-otlp-proto': - optional: true - '@opentelemetry/sdk-trace-base': - optional: true - openai: + typescript: optional: true - language-subtag-registry@0.3.23: - resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} - - language-tags@1.0.9: - resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} - engines: {node: '>=0.10'} - - lazy-val@1.0.5: - resolution: {integrity: sha512-0/BnGCCfyUMkBpeDgWihanIAF9JmZhHBgUhEqzvf+adhNGLoP6TaiI5oF8oyb3I45P+PcnrqihSf01M0l0G5+Q==} + eslint-import-resolver-node@0.3.9: + resolution: {integrity: sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==} - leac@0.6.0: - resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} + eslint-import-resolver-typescript@3.10.1: + resolution: {integrity: sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + eslint: '*' + eslint-plugin-import: '*' + eslint-plugin-import-x: '*' + peerDependenciesMeta: + eslint-plugin-import: + optional: true + eslint-plugin-import-x: + optional: true - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} + eslint-module-utils@2.12.1: + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: '*' + eslint-import-resolver-node: '*' + eslint-import-resolver-typescript: '*' + eslint-import-resolver-webpack: '*' + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true + eslint: + optional: true + eslint-import-resolver-node: + optional: true + eslint-import-resolver-typescript: + optional: true + eslint-import-resolver-webpack: + optional: true - libphonenumber-js@1.12.13: - resolution: {integrity: sha512-QZXnR/OGiDcBjF4hGk0wwVrPcZvbSSyzlvkjXv5LFfktj7O2VZDrt4Xs8SgR/vOFco+qk1i8J43ikMXZoTrtPw==} + eslint-plugin-import@2.32.0: + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} + engines: {node: '>=4'} + peerDependencies: + '@typescript-eslint/parser': '*' + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 + peerDependenciesMeta: + '@typescript-eslint/parser': + optional: true - light-my-request@6.6.0: - resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} + eslint-plugin-jsdoc@50.8.0: + resolution: {integrity: sha512-UyGb5755LMFWPrZTEqqvTJ3urLz1iqj+bYOHFNag+sw3NvaMWP9K2z+uIn37XfNALmQLQyrBlJ5mkiVPL7ADEg==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^7.0.0 || ^8.0.0 || ^9.0.0 - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [android] + eslint-plugin-jsx-a11y@6.10.2: + resolution: {integrity: sha512-scB3nz4WmG75pV8+3eRUQOHZlNSUhFNq37xnpgRkCCELU3XMvXAxLk1eqWWyE22Ki4Q01Fnsw9BA3cJHDPgn2Q==} + engines: {node: '>=4.0'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [darwin] + eslint-plugin-prettier@5.5.4: + resolution: {integrity: sha512-swNtI95SToIz05YINMA6Ox5R057IMAmWZ26GqPxusAp1TZzj+IdY9tXNWWD3vkF/wEqydCONcwjTFpxybBqZsg==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + '@types/eslint': '>=8.0.0' + eslint: '>=8.0.0' + eslint-config-prettier: '>= 7.0.0 <10.0.0 || >=10.1.0' + prettier: '>=3.0.0' + peerDependenciesMeta: + '@types/eslint': + optional: true + eslint-config-prettier: + optional: true - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [darwin] + eslint-plugin-react-hooks@7.0.1: + resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [freebsd] + eslint-plugin-react@7.37.5: + resolution: {integrity: sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==} + engines: {node: '>=4'} + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} - engines: {node: '>= 12.0.0'} - cpu: [arm] - os: [linux] + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [linux] + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] + eslint@9.33.0: + resolution: {integrity: sha512-TS9bTNIryDzStCpJN93aC5VRSW3uTx9sClUn4B87pwiCaJh220otoI0X8mJKr+VcPtniMdN8GKjlwgWGUv5ZKA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [linux] + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} - engines: {node: '>= 12.0.0'} - cpu: [arm64] - os: [win32] + esquery@1.6.0: + resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + engines: {node: '>=0.10'} - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} - engines: {node: '>= 12.0.0'} - cpu: [x64] - os: [win32] + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} - engines: {node: '>= 12.0.0'} + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} - lilconfig@3.1.3: - resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} - engines: {node: '>=14'} + estree-walker@3.0.3: + resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - lines-and-columns@1.2.4: - resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} - lit-element@4.2.1: - resolution: {integrity: sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==} + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} - lit-html@3.3.1: - resolution: {integrity: sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==} + eth-block-tracker@7.1.0: + resolution: {integrity: sha512-8YdplnuE1IK4xfqpf4iU7oBxnOYAc35934o083G8ao+8WM8QQtt/mVlAY6yIAdY1eMeLqg4Z//PZjJGmWGPMRg==} + engines: {node: '>=14.0.0'} - lit@3.3.0: - resolution: {integrity: sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==} + eth-json-rpc-filters@6.0.1: + resolution: {integrity: sha512-ITJTvqoCw6OVMLs7pI8f4gG92n/St6x80ACtHodeS+IXmO0w+t1T5OOzfSt7KLSMLRkVUoexV7tztLgDxg+iig==} + engines: {node: '>=14.0.0'} - llamaindex@0.10.6: - resolution: {integrity: sha512-5tCygOreATUxUYe7cFNSlsWwNK3glm81ufMPapjMWsTtN1dIdBh3MC0o/DG5wU4iFgx+0mJQsAGOB7ea1I7JUg==} - engines: {node: '>=18.0.0'} + eth-query@2.1.2: + resolution: {integrity: sha512-srES0ZcvwkR/wd5OQBRA1bIJMww1skfGS0s8wlwK3/oNP4+wnds60krvu5R1QbpRQjMmpG5OMIWro5s7gvDPsA==} - load-tsconfig@0.2.5: - resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + eth-rpc-errors@4.0.3: + resolution: {integrity: sha512-Z3ymjopaoft7JDoxZcEb3pwdGh7yiYMhOwm2doUt6ASXlMavpNlK6Cre0+IMl2VSGyEU9rkiperQhp5iRxn5Pg==} - locate-path@5.0.0: - resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} - engines: {node: '>=8'} + ethereum-cryptography@2.2.1: + resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} - lodash.debounce@4.0.8: - resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} + eventemitter2@6.4.9: + resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} - lodash.memoize@4.1.2: - resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} + eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + events@3.3.0: + resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} + engines: {node: '>=0.8.x'} - lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} + eventsource-parser@3.0.5: + resolution: {integrity: sha512-bSRG85ZrMdmWtm7qkF9He9TNRzc/Bm99gEJMaQoHJ9E6Kv9QBbsldh2oMj7iXmYNEAVvNgvv5vPorG6W+XtBhQ==} + engines: {node: '>=20.0.0'} - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + eventsource@2.0.2: + resolution: {integrity: sha512-IzUmBGPR3+oUG9dUeXynyNmf91/3zUSJg1lCktzKw47OXuhco54U3r9B7O4XX+Rb1Itm9OZ2b0RkTs10bICOxA==} + engines: {node: '>=12.0.0'} - log-symbols@4.1.0: - resolution: {integrity: sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==} - engines: {node: '>=10'} + eventsource@3.0.7: + resolution: {integrity: sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA==} + engines: {node: '>=18.0.0'} - logform@2.7.0: - resolution: {integrity: sha512-TFYA4jnP7PVbmlBIfhlSe+WKxs9dklXMTEGcBCIvLhE/Tn3H6Gk1norupVW7m5Cnd4bLcr08AytbyV/xj7f/kQ==} - engines: {node: '>= 12.0.0'} + expect-type@1.2.2: + resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + engines: {node: '>=12.0.0'} - loose-envify@1.4.0: - resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} - hasBin: true + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} - loupe@3.2.0: - resolution: {integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==} + express-rate-limit@7.5.1: + resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + engines: {node: '>= 16'} + peerDependencies: + express: '>= 4.11' - lower-case@2.0.2: - resolution: {integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==} + express@4.21.2: + resolution: {integrity: sha512-28HqgMZAmih1Czt9ny7qr6ek2qddF4FclbMzwhCREB6OFfH+rXAnuNCwo1/wFvrtbgsQDb4kSbX9de9lFbrXnA==} + engines: {node: '>= 0.10.0'} - lowercase-keys@2.0.0: - resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} - engines: {node: '>=8'} + express@5.1.0: + resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + engines: {node: '>= 18'} - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + extension-port-stream@3.0.0: + resolution: {integrity: sha512-an2S5quJMiy5bnZKEf6AkfH/7r8CzHvhchU40gxN+OM6HPhe7Z9T1FUychcf2M9PpPOO0Hf7BAEfJkw2TDIBDw==} + engines: {node: '>=12.0.0'} - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + eyes@0.1.8: + resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} + engines: {node: '> 0.1.90'} - lru-cache@6.0.0: - resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} - engines: {node: '>=10'} + fast-base64-decode@1.0.0: + resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==} - lru-cache@7.18.3: - resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} - engines: {node: '>=12'} + fast-copy@3.0.2: + resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} - magic-bytes.js@1.12.1: - resolution: {integrity: sha512-ThQLOhN86ZkJ7qemtVRGYM+gRgR8GEXNli9H/PMvpnZsE44Xfh3wx9kGJaldg314v85m+bFW6WBMaVHJc/c3zA==} + fast-decode-uri-component@1.0.1: + resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + fast-diff@1.3.0: + resolution: {integrity: sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==} - make-fetch-happen@10.2.1: - resolution: {integrity: sha512-NgOPbRiaQM10DYXvN3/hhGVI2M5MtITFryzBGxHM5p4wnFxsVCbxkrBrDsk+EZ5OB4jEOT7AjDxtdF+KVEFT7w==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + fast-glob@3.3.1: + resolution: {integrity: sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==} + engines: {node: '>=8.6.0'} - matcher@3.0.0: - resolution: {integrity: sha512-OkeDaAZ/bQCxeFAozM55PKcKU0yJMPGifLwV4Qgjitu+5MoAfSQN4lsLJeXZ1b8w0x+/Emda6MZgXS1jvsapng==} - engines: {node: '>=10'} + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - md5.js@1.3.5: - resolution: {integrity: sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==} + fast-json-stringify@6.3.0: + resolution: {integrity: sha512-oRCntNDY/329HJPlmdNLIdogNtt6Vyjb1WuT01Soss3slIdyUp8kAcDU3saQTOquEK8KFVfwIIF7FebxUAu+yA==} - md5@2.3.0: - resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - mdn-data@2.0.28: - resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==} + fast-querystring@1.1.2: + resolution: {integrity: sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==} - mdn-data@2.0.30: - resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} + fast-redact@3.5.0: + resolution: {integrity: sha512-dwsoQlS7h9hMeYUq1W++23NDcBLV4KqONnITDV9DjfS3q1SgDGVrBdvvTLUotWtPSD7asWDV9/CmsZPy8Hf70A==} + engines: {node: '>=6'} - media-typer@0.3.0: - resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} - engines: {node: '>= 0.6'} + fast-safe-stringify@2.1.1: + resolution: {integrity: sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA==} - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} - engines: {node: '>= 0.8'} + fast-stable-stringify@1.0.0: + resolution: {integrity: sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==} - merge-descriptors@1.0.3: - resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} + fast-uri@3.0.6: + resolution: {integrity: sha512-Atfo14OibSv5wAp4VWNsFYE1AchQRTv9cBGWET4pZWHzYshFSS9NQI6I57rdKn9croWVMbYFbLhJ+yJvmZIIHw==} - merge-descriptors@2.0.0: - resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} - engines: {node: '>=18'} + fastestsmallesttextencoderdecoder@1.0.22: + resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} - merge-stream@2.0.0: - resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + fastify@5.8.2: + resolution: {integrity: sha512-lZmt3navvZG915IE+f7/TIVamxIwmBd+OMB+O9WBzcpIwOo6F0LTh0sluoMFk5VkrKTvvrwIaoJPkir4Z+jtAg==} - merge2@1.4.1: - resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} - engines: {node: '>= 8'} + fastq@1.19.1: + resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} - merkletreejs@0.5.2: - resolution: {integrity: sha512-MHqclSWRSQQbYciUMALC3PZmE23NPf5IIYo+Z7qAz5jVcqgCB95L1T9jGcr+FtOj2Pa2/X26uG2Xzxs7FJccUg==} - engines: {node: '>= 7.6.0'} + fb-dotslash@0.5.8: + resolution: {integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==} + engines: {node: '>=20'} + hasBin: true - methods@1.1.2: - resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} - engines: {node: '>= 0.6'} + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} - micro-ftch@0.3.1: - resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} - engines: {node: '>=8.6'} + feaxios@0.0.23: + resolution: {integrity: sha512-eghR0A21fvbkcQBgZuMfQhrXxJzC0GNUGC9fXhBge33D+mFDTwl0aJ35zoQQn575BhyjQitRc5N4f+L4cP708g==} - mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} - mime-db@1.54.0: - resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} - engines: {node: '>= 0.6'} + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} - mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} + filter-obj@1.1.0: + resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} + engines: {node: '>=0.10.0'} - mime-types@3.0.1: - resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} - engines: {node: '>= 0.6'} + finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} - mime@1.6.0: - resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} - engines: {node: '>=4'} - hasBin: true + finalhandler@1.3.1: + resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} + engines: {node: '>= 0.8'} - mime@2.6.0: - resolution: {integrity: sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==} - engines: {node: '>=4.0.0'} - hasBin: true + finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} - mimic-fn@2.1.0: - resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} - engines: {node: '>=6'} + find-my-way@9.5.0: + resolution: {integrity: sha512-VW2RfnmscZO5KgBY5XVyKREMW5nMZcxDy+buTOsL+zIPnBlbKm+00sgzoQzq1EVh4aALZLfKdwv6atBGcjvjrQ==} + engines: {node: '>=20'} - mimic-response@1.0.1: - resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} - engines: {node: '>=4'} + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - minimalistic-assert@1.0.1: - resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} - minimalistic-crypto-utils@1.0.1: - resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} - minimatch@10.0.3: - resolution: {integrity: sha512-IPZ167aShDZZUMdRk66cyQAW3qr0WzbHkPdMYa8bzZhlHhO3jALbKdxcaak7W9FfT2rZNpQuUu4Od7ILEpXSaw==} - engines: {node: 20 || >=22} + flatted@3.3.3: + resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + flow-enums-runtime@0.0.6: + resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} + follow-redirects@1.15.11: + resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} + for-each@0.3.5: + resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} + engines: {node: '>= 0.4'} - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} - minipass-collect@1.0.2: - resolution: {integrity: sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==} - engines: {node: '>= 8'} + forge-light@1.1.4: + resolution: {integrity: sha512-Nr0xdu93LJawgBZVU/tC+A+4pbKqigdY5PRBz8CXNm4e5saAZIqU2Qe9+nVFtVO5TWCHSgvI0LaZZuatgE5J1g==} + engines: {node: '>= 6.13.0'} - minipass-fetch@2.1.2: - resolution: {integrity: sha512-LT49Zi2/WMROHYoqGgdlQIZh8mLPZmOrN2NdJjMXxYe4nkN6FUyuPuOAOedNJDrx0IRGg9+4guZewtp8hE6TxA==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + form-data-encoder@1.7.2: + resolution: {integrity: sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==} - minipass-flush@1.0.5: - resolution: {integrity: sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==} - engines: {node: '>= 8'} + form-data@4.0.4: + resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} + engines: {node: '>= 6'} - minipass-pipeline@1.2.4: - resolution: {integrity: sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==} - engines: {node: '>=8'} + formdata-node@4.4.1: + resolution: {integrity: sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==} + engines: {node: '>= 12.20'} - minipass-sized@1.0.3: - resolution: {integrity: sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==} - engines: {node: '>=8'} + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} - minipass@3.3.6: - resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} - engines: {node: '>=8'} + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} - minipass@5.0.0: - resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} - engines: {node: '>=8'} + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} - engines: {node: '>=16 || 14 >=14.17'} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] - minizlib@2.1.2: - resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} - engines: {node: '>= 8'} + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - mipd@0.0.7: - resolution: {integrity: sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true + function.prototype.name@1.1.8: + resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + engines: {node: '>= 0.4'} - mkdirp@0.5.6: - resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} - hasBin: true + functions-have-names@1.2.3: + resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - mkdirp@1.0.4: - resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} - engines: {node: '>=10'} - hasBin: true + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} - mlly@1.7.4: - resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} - ms@2.0.0: - resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} - ms@2.1.2: - resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} - multiformats@9.9.0: - resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} + get-stream@5.2.0: + resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} + engines: {node: '>=8'} - mustache@4.2.0: - resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} - hasBin: true + get-symbol-description@1.1.0: + resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} + engines: {node: '>= 0.4'} - mz@2.7.0: - resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + get-tsconfig@4.10.1: + resolution: {integrity: sha512-auHyJ4AgMz7vgS8Hp3N6HXSmlMdUyhSUrfBF16w153rxtLIEOE+HGqaBppczZvnHLqQJfiHotCYpNhl0lUROFQ==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} - napi-postinstall@0.3.3: - resolution: {integrity: sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==} - engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me hasBin: true - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} - negotiator@0.6.3: - resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} - engines: {node: '>= 0.6'} + globals@16.4.0: + resolution: {integrity: sha512-ob/2LcVVaVGCYN+r14cnwnoDPUufjiYgSqRhiFD0Q1iI4Odora5RE8Iv1D24hAz5oMophRGkGz+yuvQmmUMnMw==} + engines: {node: '>=18'} - negotiator@0.6.4: - resolution: {integrity: sha512-myRT3DiWPHqho5PrJaIRyaMv2kgYf0mUVgBNOYMuCH5Ki1yEiQaf/ZJuQ62nvpc44wL5WDbTX7yGJi1Neevw8w==} - engines: {node: '>= 0.6'} + globalthis@1.0.4: + resolution: {integrity: sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==} + engines: {node: '>= 0.4'} - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} + globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - next@15.5.9: - resolution: {integrity: sha512-agNLK89seZEtC5zUHwtut0+tNrc0Xw4FT/Dg+B/VLEo9pAcS9rtTKpek3V6kVcVwsB2YlqMaHdfZL4eLEVYuCg==} - engines: {node: ^18.18.0 || ^19.8.0 || >= 20.0.0} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.51.1 - babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - babel-plugin-react-compiler: - optional: true - sass: - optional: true + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} - next@16.0.10: - resolution: {integrity: sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==} - engines: {node: '>=20.9.0'} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.51.1 - babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - babel-plugin-react-compiler: - optional: true - sass: - optional: true + got@11.8.6: + resolution: {integrity: sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g==} + engines: {node: '>=10.19.0'} - no-case@3.0.4: - resolution: {integrity: sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==} + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - node-abi@3.75.0: - resolution: {integrity: sha512-OhYaY5sDsIka7H7AtijtI9jwGYLyl29eQn/W623DiN/MIv5sUqc4g7BIDThX+gb7di9f6xK02nkp8sdfFWZLTg==} - engines: {node: '>=10'} + graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - node-addon-api@1.7.2: - resolution: {integrity: sha512-ibPK3iA+vaY1eEjESkQkM0BbCqFOaZMiXRTtdB0u7b4djtY6JnsjvPdUHVMg6xQt3B8fpTTWHI9A+ADjM9frzg==} + graphql-request@6.1.0: + resolution: {integrity: sha512-p+XPfS4q7aIpKVcgmnZKhMNqhltk20hfXtkaIkTfjjmiKMJ5xrt5c743cL03y/K7y1rg3WrIC49xGiEQ4mxdNw==} + peerDependencies: + graphql: 14 - 16 - node-addon-api@2.0.2: - resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} + graphql@16.11.0: + resolution: {integrity: sha512-mS1lbMsxgQj6hge1XZ6p7GPhbrtFwUFYi3wRzXAC/FmYnyXMTvvI3td3rjmQ2u8ewXueaSvRPWaEcgVVOT9Jnw==} + engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - node-addon-api@5.1.0: - resolution: {integrity: sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==} + h3@1.15.4: + resolution: {integrity: sha512-z5cFQWDffyOe4vQ9xIqNfCZdV4p//vy6fBnr8Q1AWnVZ0teurKMG66rLj++TKwKPUP3u7iMUvrvKaEUiQw2QWQ==} - node-addon-api@8.5.0: - resolution: {integrity: sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==} - engines: {node: ^18 || ^20 || >= 21} + has-bigints@1.1.0: + resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} + engines: {node: '>= 0.4'} - node-api-version@0.2.1: - resolution: {integrity: sha512-2xP/IGGMmmSQpI1+O/k72jF/ykvZ89JeuKX3TLJAYPDVLUalrshrLHkeVcCCZqG/eEa635cr8IBYzgnDvM2O8Q==} + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - deprecated: Use your platform's native DOMException instead + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - node-fetch-native@1.6.7: - resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + has-proto@1.2.0: + resolution: {integrity: sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==} + engines: {node: '>= 0.4'} - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} - node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} - node-gyp-build@4.8.4: - resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} - hasBin: true + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} - node-mock-http@1.0.2: - resolution: {integrity: sha512-zWaamgDUdo9SSLw47we78+zYw/bDr5gH8pH7oRRs8V3KmBtu8GLgGIbV2p/gRPd3LWpEOpjQj7X1FOU3VFMJ8g==} + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} - node-releases@2.0.19: - resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} + hermes-compiler@250829098.0.10: + resolution: {integrity: sha512-TcRlZ0/TlyfJqquRFAWoyElVNnkdYRi/sEp4/Qy8/GYxjg8j2cS9D4MjuaQ+qimkmLN7AmO+44IznRf06mAr0w==} - nopt@6.0.0: - resolution: {integrity: sha512-ZwLpbTgdhuZUnZzjd7nb1ZV+4DoiC6/sfiVKok72ym/4Tlf+DFdlHYmT2JPmcNNWV6Pi3SDf1kT+A4r9RTuT9g==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} - hasBin: true + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} + hermes-estree@0.33.3: + resolution: {integrity: sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==} - normalize-url@6.1.0: - resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} - engines: {node: '>=10'} + hermes-estree@0.35.0: + resolution: {integrity: sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==} - npm-run-path@4.0.1: - resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} - engines: {node: '>=8'} + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - nth-check@2.1.1: - resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + hermes-parser@0.33.3: + resolution: {integrity: sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==} - nwsapi@2.2.21: - resolution: {integrity: sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==} + hermes-parser@0.35.0: + resolution: {integrity: sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==} - obj-multiplex@1.0.0: - resolution: {integrity: sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA==} + hi-base32@0.5.1: + resolution: {integrity: sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==} - object-assign@4.1.1: - resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} - engines: {node: '>=0.10.0'} + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} - object-hash@3.0.0: - resolution: {integrity: sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==} - engines: {node: '>= 6'} + hono@4.10.7: + resolution: {integrity: sha512-icXIITfw/07Q88nLSkB9aiUrd8rYzSweK681Kjo/TSggaGbOX4RRyxxm71v+3PC8C/j+4rlxGeoTRxQDkaJkUw==} + engines: {node: '>=16.9.0'} - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} + html-encoding-sniffer@4.0.0: + resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} + engines: {node: '>=18'} - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} + http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} - object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} - object.entries@1.1.9: - resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} - engines: {node: '>= 0.4'} + http-proxy-agent@7.0.2: + resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} + engines: {node: '>= 14'} - object.fromentries@2.0.8: - resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} - engines: {node: '>= 0.4'} + http2-wrapper@1.0.3: + resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} + engines: {node: '>=10.19.0'} - object.groupby@1.0.3: - resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} - engines: {node: '>= 0.4'} + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} - object.values@1.2.1: - resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} - engines: {node: '>= 0.4'} + humanize-ms@1.2.1: + resolution: {integrity: sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==} - ofetch@1.4.1: - resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} + iconv-lite@0.4.24: + resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} + engines: {node: '>=0.10.0'} - on-exit-leak-free@0.2.0: - resolution: {integrity: sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==} + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} - on-exit-leak-free@2.1.2: - resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} - engines: {node: '>=14.0.0'} + idb-keyval@6.2.1: + resolution: {integrity: sha512-8Sb3veuYCyrZL+VBt9LJfZjLUPWVvqn8tG28VqYNFCo43KHcKuq+b4EiXGeuaLAQWL2YmyDgMp2aSpH9JHsEQg==} - on-finished@2.4.1: - resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} - engines: {node: '>= 0.8'} + idb-keyval@6.2.2: + resolution: {integrity: sha512-yjD9nARJ/jb1g+CvD0tlhUHOrJ9Sy0P8T9MF3YaLlHnSRpwPfpTX0XIvpmw3gAJUmEu3FiICLBDPXVwyEvrleg==} - once@1.4.0: - resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + ieee754@1.2.1: + resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - one-time@1.0.0: - resolution: {integrity: sha512-5DXOiRKwuSEcQ/l0kGCF6Q3jcADFv5tSmRaJck/OqkVFcOzutB134KRSfF0xDrL39MNnqxbHBbUUcjZIhTgb2g==} + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} - onetime@5.1.2: - resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} - engines: {node: '>=6'} + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} - openai@4.104.0: - resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} + image-size@1.2.1: + resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} + engines: {node: '>=16.x'} hasBin: true - peerDependencies: - ws: ^8.18.0 - zod: ^3.23.8 - peerDependenciesMeta: - ws: - optional: true - zod: - optional: true - openai@5.13.1: - resolution: {integrity: sha512-Jty97Apw40znKSlXZL2YDap1U2eN9NfXbqm/Rj1rExeOLEnhwezpKQ+v43kIqojavUgm30SR3iuvGlNEBR+AFg==} - hasBin: true - peerDependencies: - ws: ^8.18.0 - zod: ^3.23.8 - peerDependenciesMeta: - ws: - optional: true - zod: - optional: true + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} - openapi-fetch@0.13.8: - resolution: {integrity: sha512-yJ4QKRyNxE44baQ9mY5+r/kAzZ8yXMemtNAOFwOzRXJscdjSxxzWSNlyBAr+o5JjkUw9Lc3W7OIoca0cY3PYnQ==} + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} - openapi-typescript-helpers@0.0.15: - resolution: {integrity: sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==} + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - opensea-js@7.2.1: - resolution: {integrity: sha512-vy7sz2lRMCANrQs9rhNdUsmFSJBjPq1we3/Aib9/sTNudg9830ZvN7XD5if2LBq71L+85tUsxobSNRLBwoEAAg==} - engines: {node: '>=20.0.0'} + internal-slot@1.1.0: + resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} + engines: {node: '>= 0.4'} - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} - ora@5.4.1: - resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==} - engines: {node: '>=10'} + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} - own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} - engines: {node: '>= 0.4'} + ipaddr.js@2.3.0: + resolution: {integrity: sha512-Zv/pA+ciVFbCSBBjGfaKUya/CcGmUHzTydLMaTwrUUEM2DIEO3iZvueGxmacvmN50fGpGVKeTXpb2LcYQxeVdg==} + engines: {node: '>= 10'} - ox@0.11.1: - resolution: {integrity: sha512-1l1gOLAqg0S0xiN1dH5nkPna8PucrZgrIJOfS49MLNiMevxu07Iz4ZjuJS9N+xifvT+PsZyIptS7WHM8nC+0+A==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true + iron-webcrypto@1.2.1: + resolution: {integrity: sha512-feOM6FaSr6rEABp/eDfVseKyTMDt+KGpeB35SkVn9Tyn0CqvVsY3EwI0v5i8nMHyJnzCIQf7nsy3p41TPkJZhg==} - ox@0.4.4: - resolution: {integrity: sha512-oJPEeCDs9iNiPs6J0rTx+Y0KGeCGyCAA3zo94yZhm8G5WpOxrwUtn2Ie/Y8IyARSqqY/j9JTKA3Fc1xs1DvFnw==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true + is-arguments@1.2.0: + resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} + engines: {node: '>= 0.4'} - ox@0.6.7: - resolution: {integrity: sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true + is-array-buffer@3.0.5: + resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} + engines: {node: '>= 0.4'} - ox@0.6.9: - resolution: {integrity: sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true + is-async-function@2.1.1: + resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} + engines: {node: '>= 0.4'} - ox@0.8.1: - resolution: {integrity: sha512-e+z5epnzV+Zuz91YYujecW8cF01mzmrUtWotJ0oEPym/G82uccs7q0WDHTYL3eiONbTUEvcZrptAKLgTBD3u2A==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true + is-bigint@1.1.0: + resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} + engines: {node: '>= 0.4'} - ox@0.9.17: - resolution: {integrity: sha512-rKAnhzhRU3Xh3hiko+i1ZxywZ55eWQzeS/Q4HRKLx2PqfHOolisZHErSsJVipGlmQKHW5qwOED/GighEw9dbLg==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true + is-boolean-object@1.2.2: + resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} + engines: {node: '>= 0.4'} - ox@0.9.6: - resolution: {integrity: sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true + is-buffer@1.1.6: + resolution: {integrity: sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==} - p-cancelable@2.1.1: - resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} - engines: {node: '>=8'} + is-bun-module@2.0.0: + resolution: {integrity: sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==} - p-finally@1.0.0: - resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} - engines: {node: '>=4'} + is-callable@1.2.7: + resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} + engines: {node: '>= 0.4'} - p-limit@2.3.0: - resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} - engines: {node: '>=6'} + is-core-module@2.16.1: + resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + engines: {node: '>= 0.4'} - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + is-data-view@1.0.2: + resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} + engines: {node: '>= 0.4'} - p-locate@4.1.0: - resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} - engines: {node: '>=8'} + is-date-object@1.1.0: + resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} + engines: {node: '>= 0.4'} - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true - p-map@4.0.0: - resolution: {integrity: sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==} - engines: {node: '>=10'} + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} - p-queue@6.6.2: - resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==} - engines: {node: '>=8'} + is-finalizationregistry@1.1.1: + resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} + engines: {node: '>= 0.4'} - p-retry@4.6.2: - resolution: {integrity: sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==} + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - p-retry@6.2.1: - resolution: {integrity: sha512-hEt02O4hUct5wtwg4H4KcWgDdm+l1bOaEy/hWzd8xtXB9BqxTWBBhb+2ImAtH4Cv4rPjV76xN3Zumqk3k3AhhQ==} - engines: {node: '>=16.17'} + is-generator-function@1.1.0: + resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} + engines: {node: '>= 0.4'} - p-timeout@3.2.0: - resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==} - engines: {node: '>=8'} + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} - p-try@2.2.0: - resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} - engines: {node: '>=6'} + is-map@2.0.3: + resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} + engines: {node: '>= 0.4'} - package-json-from-dist@1.0.1: - resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + is-number-object@1.1.1: + resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} + engines: {node: '>= 0.4'} - parse-imports-exports@0.2.4: - resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} - parse-json@5.2.0: - resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} - engines: {node: '>=8'} + is-potential-custom-element-name@1.0.1: + resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - parse-statements@1.0.11: - resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + is-regex@1.2.1: + resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} + engines: {node: '>= 0.4'} - parseley@0.12.1: - resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} + is-retry-allowed@2.2.0: + resolution: {integrity: sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==} + engines: {node: '>=10'} - parseurl@1.3.3: - resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} - engines: {node: '>= 0.8'} + is-retry-allowed@3.0.0: + resolution: {integrity: sha512-9xH0xvoggby+u0uGF7cZXdrutWiBiaFG8ZT4YFPXL8NzkyAwX3AKGLeFQLvzDpM430+nDFBZ1LHkie/8ocL06A==} + engines: {node: '>=12'} - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} + is-set@2.0.3: + resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} + engines: {node: '>= 0.4'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} + is-shared-array-buffer@1.0.4: + resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} + engines: {node: '>= 0.4'} - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} engines: {node: '>=8'} - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} + is-string@1.1.1: + resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} + engines: {node: '>= 0.4'} - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} + is-symbol@1.1.1: + resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} + engines: {node: '>= 0.4'} - path-to-regexp@0.1.12: - resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} + is-typed-array@1.1.15: + resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} + engines: {node: '>= 0.4'} - path-to-regexp@8.2.0: - resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} - engines: {node: '>=16'} + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} - path-type@4.0.0: - resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} - engines: {node: '>=8'} + is-weakmap@2.0.2: + resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} + engines: {node: '>= 0.4'} - pathe@1.1.2: - resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + is-weakref@1.1.1: + resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} + engines: {node: '>= 0.4'} - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + is-weakset@2.0.4: + resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} + engines: {node: '>= 0.4'} - pathval@2.0.1: - resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} - engines: {node: '>= 14.16'} + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} - pe-library@0.4.1: - resolution: {integrity: sha512-eRWB5LBz7PpDu4PUlwT0PhnQfTQJlDDdPa35urV4Osrm0t0AqQFGn+UIkU3klZvwJ8KPO3VbBFsXquA6p6kqZw==} - engines: {node: '>=12', npm: '>=6'} + isarray@1.0.0: + resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} - peberminta@0.9.0: - resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - pend@1.2.0: - resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + isomorphic-ws@4.0.1: + resolution: {integrity: sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==} + peerDependencies: + ws: '*' - picomatch@2.3.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} - engines: {node: '>=8.6'} + isows@1.0.6: + resolution: {integrity: sha512-lPHCayd40oW98/I0uvgaHKWCSvkzY27LjWLbtzOm64yQ+G3Q5npjjbdppU65iZXkK1Zt+kH9pfegli0AYfwYYw==} + peerDependencies: + ws: '*' - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} + isows@1.0.7: + resolution: {integrity: sha512-I1fSfDCZL5P0v33sVqeTDSpcstAg/N+wF5HS033mogOVIp4B+oHC7oOCsA3axAbBSGTJ8QubbNmnIRN/h8U7hg==} + peerDependencies: + ws: '*' - pify@2.3.0: - resolution: {integrity: sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==} - engines: {node: '>=0.10.0'} + iterator.prototype@1.1.5: + resolution: {integrity: sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==} + engines: {node: '>= 0.4'} - pify@3.0.0: - resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} - engines: {node: '>=4'} + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} - pify@5.0.0: - resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} - engines: {node: '>=10'} + jayson@4.2.0: + resolution: {integrity: sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==} + engines: {node: '>=8'} + hasBin: true - pino-abstract-transport@0.5.0: - resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==} + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - pino-abstract-transport@3.0.0: - resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - pino-std-serializers@4.0.0: - resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==} + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - pino-std-serializers@7.1.0: - resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - pino@10.3.1: - resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} + jiti@2.6.1: + resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - pino@7.11.0: - resolution: {integrity: sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==} - hasBin: true + jose@5.10.0: + resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} - pirates@4.0.7: - resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} - engines: {node: '>= 6'} + jose@6.0.12: + resolution: {integrity: sha512-T8xypXs8CpmiIi78k0E+Lk7T2zlK4zDyg+o1CZ4AkOHgDg98ogdP2BeZ61lTFKFyoEwJ9RgAgN+SdM3iPgNonQ==} - pkce-challenge@5.0.0: - resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} - engines: {node: '>=16.20.0'} + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} - pkg-types@1.3.1: - resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + js-base64@3.7.4: + resolution: {integrity: sha512-wpM/wi20Tl+3ifTyi0RdDckS4YTD4Lf953mBRrpG8547T7hInHNPEj8+ck4gB8VDcGyeAWFK++Wb/fU1BeavKQ==} - plist@3.1.0: - resolution: {integrity: sha512-uysumyrvkUX0rX/dEVqt8gC3sTBzd4zoWfLeS29nb53imdaXVvLINYXTI2GNqzaMuvacNx4uJQ8+b3zXR0pkgQ==} - engines: {node: '>=10.4.0'} + js-base64@3.7.7: + resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} - pngjs@5.0.0: - resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} - engines: {node: '>=10.13.0'} + js-base64@3.7.8: + resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} - pony-cause@2.1.11: - resolution: {integrity: sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==} - engines: {node: '>=12.0.0'} + js-sha256@0.9.0: + resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==} - porto@0.2.35: - resolution: {integrity: sha512-gu9FfjjvvYBgQXUHWTp6n3wkTxVtEcqFotM7i3GEZeoQbvLGbssAicCz6hFZ8+xggrJWwi/RLmbwNra50SMmUQ==} - hasBin: true - peerDependencies: - '@tanstack/react-query': '>=5.59.0' - '@wagmi/core': '>=2.16.3' - expo-auth-session: '>=7.0.8' - expo-crypto: '>=15.0.7' - expo-web-browser: '>=15.0.8' - react: '>=18' - react-native: '>=0.81.4' - typescript: '>=5.4.0' - viem: '>=2.37.0' - wagmi: '>=2.0.0' - peerDependenciesMeta: - '@tanstack/react-query': - optional: true - expo-auth-session: - optional: true - expo-crypto: - optional: true - expo-web-browser: - optional: true - react: - optional: true - react-native: - optional: true - typescript: - optional: true - wagmi: - optional: true + js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} - poseidon-lite@0.2.1: - resolution: {integrity: sha512-xIr+G6HeYfOhCuswdqcFpSX47SPhm0EpisWJ6h7fHlWwaVIvH3dLnejpatrtw6Xc6HaLrpq05y7VRfvDmDGIog==} + js-sha512@0.8.0: + resolution: {integrity: sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==} - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - postcss-import@15.1.0: - resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} - engines: {node: '>=14.0.0'} - peerDependencies: - postcss: ^8.0.0 + js-tokens@9.0.1: + resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - postcss-js@4.0.1: - resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} - engines: {node: ^12 || ^14 || >= 16} - peerDependencies: - postcss: ^8.4.21 + js-yaml@4.1.0: + resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} + hasBin: true - postcss-load-config@4.0.2: - resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} - engines: {node: '>= 14'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true + jsc-safe-url@0.2.4: + resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==} - postcss-load-config@6.0.1: - resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} - engines: {node: '>= 18'} + jsdoc-type-pratt-parser@4.1.0: + resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} + engines: {node: '>=12.0.0'} + + jsdom@26.1.0: + resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==} + engines: {node: '>=18'} peerDependencies: - jiti: '>=1.21.0' - postcss: '>=8.0.9' - tsx: ^4.8.1 - yaml: ^2.4.2 + canvas: ^3.0.0 peerDependenciesMeta: - jiti: - optional: true - postcss: - optional: true - tsx: - optional: true - yaml: + canvas: optional: true - postcss-nested@6.2.0: - resolution: {integrity: sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.2.14 + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true - postcss-selector-parser@6.1.2: - resolution: {integrity: sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==} - engines: {node: '>=4'} + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} - postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} + json-rpc-engine@6.1.0: + resolution: {integrity: sha512-NEdLrtrq1jUZyfjkr9OCz9EzCNhnRyWtt1PAnvnhwy6e8XETS0Dtc+ZNCO2gvuAoKsIn2+vCSowXTYE4CkgnAQ==} + engines: {node: '>=10.0.0'} - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} + json-rpc-random-id@1.0.1: + resolution: {integrity: sha512-RJ9YYNCkhVDBuP4zN5BBtYAzEl03yq/jIIsyif0JY9qyJuQQZNeDK7anAPKKlyEtLSj2s8h6hNh2F8zO5q7ScA==} - postject@1.0.0-alpha.6: - resolution: {integrity: sha512-b9Eb8h2eVqNE8edvKdwqkrY6O7kAwmI8kcnBv1NScolYJbo59XUF0noFq+lxbC1yN20bmC0WBEbDC5H/7ASb0A==} - engines: {node: '>=14.0.0'} - hasBin: true + json-schema-ref-resolver@3.0.0: + resolution: {integrity: sha512-hOrZIVL5jyYFjzk7+y7n5JDzGlU8rfWDuYyHwGa2WA8/pcmMHezp2xsVwxrebD/Q9t8Nc5DboieySDpCp4WG4A==} - preact@10.24.2: - resolution: {integrity: sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==} + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - preact@10.27.1: - resolution: {integrity: sha512-V79raXEWch/rbqoNc7nT9E4ep7lu+mI3+sBmfRD4i1M73R3WLYcCtdI0ibxGVf4eQL8ZIz2nFacqEC+rmnOORQ==} + json-schema-traverse@1.0.0: + resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - prettier-linter-helpers@1.0.0: - resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==} - engines: {node: '>=6.0.0'} + json-stringify-safe@5.0.1: + resolution: {integrity: sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==} - prettier@3.5.2: - resolution: {integrity: sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==} - engines: {node: '>=14'} + json5@1.0.2: + resolution: {integrity: sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==} hasBin: true - prettier@3.6.2: - resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} - engines: {node: '>=14'} + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} hasBin: true - proc-log@2.0.1: - resolution: {integrity: sha512-Kcmo2FhfDTXdcbfDH76N7uBYHINxc/8GW7UAVuVP9I+Va3uHSerrnKV6dLooga/gh7GlgzuCCr/eoldnL1muGw==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + jsx-ast-utils@3.3.5: + resolution: {integrity: sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==} + engines: {node: '>=4.0'} - process-nextick-args@2.0.1: - resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} + jwt-decode@4.0.0: + resolution: {integrity: sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==} + engines: {node: '>=18'} - process-warning@1.0.0: - resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} + keccak@3.0.4: + resolution: {integrity: sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==} + engines: {node: '>=10.0.0'} - process-warning@4.0.1: - resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - process-warning@5.0.0: - resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + keyvaluestorage-interface@1.0.0: + resolution: {integrity: sha512-8t6Q3TclQ4uZynJY9IGr2+SsIGwK9JHcO6ootkHCGA0CrQCRy+VkouYNO2xicET6b9al7QKzpebNow+gkpCL8g==} - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} + language-subtag-registry@0.3.23: + resolution: {integrity: sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==} - promise-inflight@1.0.1: - resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} - peerDependencies: - bluebird: '*' - peerDependenciesMeta: - bluebird: - optional: true + language-tags@1.0.9: + resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} + engines: {node: '>=0.10'} - promise-retry@2.0.1: - resolution: {integrity: sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==} - engines: {node: '>=10'} + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} - prop-types@15.8.1: - resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} - engines: {node: '>= 0.10'} + light-my-request@6.6.0: + resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} - proxy-compare@2.6.0: - resolution: {integrity: sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==} + lighthouse-logger@1.4.2: + resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] - pump@3.0.3: - resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] - qr.js@0.0.0: - resolution: {integrity: sha512-c4iYnWb+k2E+vYpRimHqSu575b1/wKl4XFeJGpFmrJQz5I88v9aY2czh7s0w36srfCM1sXgC/xpoJz5dJfq+OQ==} + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] - qrcode@1.5.3: - resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} - engines: {node: '>=10.13.0'} - hasBin: true + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] - qrcode@1.5.4: - resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} - engines: {node: '>=10.13.0'} - hasBin: true + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] - qs@6.13.0: - resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} - engines: {node: '>=0.6'} + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} - engines: {node: '>=0.6'} + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] - query-string@7.1.3: - resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} - engines: {node: '>=6'} + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] - querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] - queue-microtask@1.2.3: - resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} - quick-format-unescaped@4.0.4: - resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} - quick-lru@5.1.1: - resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + lit-element@4.2.1: + resolution: {integrity: sha512-WGAWRGzirAgyphK2urmYOV72tlvnxw7YfyLDgQ+OZnM9vQQBQnumQ7jUJe6unEzwGU3ahFOjuz1iz1jjrpCPuw==} + + lit-html@3.3.1: + resolution: {integrity: sha512-S9hbyDu/vs1qNrithiNyeyv64c9yqiW9l+DBgI18fL+MTvOtWoFR0FWiyq1TxaYef5wNlpEmzlXoBlZEO+WjoA==} + + lit@3.3.0: + resolution: {integrity: sha512-DGVsqsOIHBww2DqnuZzW7QsuCdahp50ojuDaBPC7jUDRpYoH0z7kHBBYZewRzer75FwtrkmkKk7iOAwSaWdBmw==} + + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - radix-ui@1.4.3: - resolution: {integrity: sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} - radix3@1.1.2: - resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} + lodash.debounce@4.0.8: + resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} + lodash.memoize@4.1.2: + resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} - engines: {node: '>= 0.6'} + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - raw-body@2.5.2: - resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} - engines: {node: '>= 0.8'} + lodash.sortby@4.7.0: + resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - raw-body@3.0.0: - resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} - engines: {node: '>= 0.8'} + lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} - react-dom@18.3.1: - resolution: {integrity: sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==} - peerDependencies: - react: ^18.3.1 + lodash@4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - react-dom@19.1.1: - resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} - peerDependencies: - react: ^19.1.1 + long@5.3.1: + resolution: {integrity: sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==} - react-dom@19.2.1: - resolution: {integrity: sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==} - peerDependencies: - react: ^19.2.1 + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true - react-dom@19.2.3: - resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} - peerDependencies: - react: ^19.2.3 + lottie-web@5.13.0: + resolution: {integrity: sha512-+gfBXl6sxXMPe8tKQm7qzLnUy5DUPJPKIyRHwtpCpyUEYjHYRJC/5gjUvdkuO2c3JllrPtHXH5UJJK8LRYl5yQ==} - react-hot-toast@2.6.0: - resolution: {integrity: sha512-bH+2EBMZ4sdyou/DPrfgIouFpcRLCJ+HoCA32UoAYHn6T3Ur5yfcDCeSr5mwldl6pFOsiocmrXMuoCJ1vV8bWg==} - engines: {node: '>=10'} - peerDependencies: - react: '>=16' - react-dom: '>=16' + loupe@3.2.0: + resolution: {integrity: sha512-2NCfZcT5VGVNX9mSZIxLRkEAegDGBpuQZBy13desuHeVORmBDyAET4TkJr4SjqQy3A8JDofMN6LpkK8Xcm/dlw==} + + lowercase-keys@2.0.0: + resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==} + engines: {node: '>=8'} - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - react-qr-code@2.0.18: - resolution: {integrity: sha512-v1Jqz7urLMhkO6jkgJuBYhnqvXagzceg3qJUWayuCK/c6LTIonpWbwxR1f1APGd4xrW/QcQEovNrAojbUz65Tg==} - peerDependencies: - react: '*' + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - react-refresh@0.17.0: - resolution: {integrity: sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==} - engines: {node: '>=0.10.0'} + lute-connect@1.7.0: + resolution: {integrity: sha512-/eXb2/c/xltKyVEVWchd1QZB6F0fvgXwVIqXDQWeJ9unPo0kMMbtuLkeb1v4Kr1lffxX8uGnb+8kAMYjczUASg==} - react-remove-scroll-bar@2.3.8: - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - react-remove-scroll@2.7.1: - resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + make-error@1.3.6: + resolution: {integrity: sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==} - react-style-singleton@2.2.3: - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} - react@18.3.1: - resolution: {integrity: sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==} - engines: {node: '>=0.10.0'} + marky@1.3.0: + resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} - react@19.1.1: - resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} - engines: {node: '>=0.10.0'} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} - react@19.2.1: - resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==} - engines: {node: '>=0.10.0'} + md5@2.3.0: + resolution: {integrity: sha512-T1GITYmFaKuO91vxyoQMFETst+O71VUPEU3ze5GNzDm0OWdP8v1ziTaAEPUr/3kLsY3Sftgz242A1SetQiDL7g==} - react@19.2.3: - resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} - engines: {node: '>=0.10.0'} + media-typer@0.3.0: + resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} + engines: {node: '>= 0.6'} - read-binary-file-arch@1.0.6: - resolution: {integrity: sha512-BNg9EN3DD3GsDXX7Aa8O4p92sryjkmzYYgmgTAc6CA4uGLEDzFfxOxugu21akOxpcXHiEgsYkC6nPsQvLLLmEg==} - hasBin: true + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} - read-cache@1.0.0: - resolution: {integrity: sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==} + memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} - readable-stream@2.3.8: - resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + merge-descriptors@1.0.3: + resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} - real-require@0.1.0: - resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==} - engines: {node: '>= 12.13.0'} + methods@1.1.2: + resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} + engines: {node: '>= 0.6'} - real-require@0.2.0: - resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} - engines: {node: '>= 12.13.0'} + metro-babel-transformer@0.84.3: + resolution: {integrity: sha512-svAA+yMLpeMiGcz/jKJs4oHpIGEx4nBqNEJ5AGj4CYIg1efvK+A0TjR6tgIuc6tKO5e8JmN/1lglpN2+f3/z/w==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - redaxios@0.5.1: - resolution: {integrity: sha512-FSD2AmfdbkYwl7KDExYQlVvIrFz6Yd83pGfaGjBzM9F6rpq8g652Q4Yq5QD4c+nf4g2AgeElv1y+8ajUPiOYMg==} + metro-cache-key@0.84.3: + resolution: {integrity: sha512-TnSL1Fdvrw+2glTdBSRmA5TL8l/i16ECjsrUdf3E5HncA+sNx8KcwDG8r+3ct1UhfYcusJypzZqTN55FZZcwGg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - reflect-metadata@0.2.2: - resolution: {integrity: sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==} + metro-cache@0.84.3: + resolution: {integrity: sha512-0QElxwLaHqLZf+Xqio8QrjVbuXP/8sJfQBGSPiITlKDVXrVLefuzYVSH9Sj+QL6lrPj2gYZd/iwQh1yZuVKnLA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - reflect.getprototypeof@1.0.10: - resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} - engines: {node: '>= 0.4'} + metro-config@0.84.3: + resolution: {integrity: sha512-JmCzZWOETR+O22q8oPBWyQppx3roU9EbkbGzD8Gf1jukQ4b5T1fTzqqHruu6K4sTiNq5zVQySmKF6bp4kVARew==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - regenerate-unicode-properties@10.2.0: - resolution: {integrity: sha512-DqHn3DwbmmPVzeKj9woBadqmXxLvQoQIwu7nopMc72ztvxVmVk2SBhSnx67zuye5TP+lJsb/TBQsjLKhnDf3MA==} - engines: {node: '>=4'} + metro-core@0.84.3: + resolution: {integrity: sha512-cc0pvAa80ai1nDmqqz0P59a+0ZqCZ/YHU/3jEekZL6spFnYDfX8iDLdn9FR6kX+67rmzKxHNrbrSRFLX2AYocw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - regenerate@1.4.2: - resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + metro-file-map@0.84.3: + resolution: {integrity: sha512-1cL4m4Jv1yRUt9RJExZQLfccscdlMNOcRG6LHLtmJhf3BG9j3MujPVc7CIpKYdFl+KUl+sdjge6oO3+meKCHQA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} + metro-minify-terser@0.84.3: + resolution: {integrity: sha512-3ofrG2OQyJbO9RNhCfOcl8QU7EE2WrSsnN5dFkuZaJO5+4Imujr9bUXmspeNlXRsOVk0F/rVRbEFH98lFSCkBQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - regexpu-core@6.2.0: - resolution: {integrity: sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==} - engines: {node: '>=4'} + metro-resolver@0.84.3: + resolution: {integrity: sha512-pjEzGDtoM8DTHAIPK/9u9ZxszEiuRohYUVImWvgbnB91V4gqYJpQcoEYUugf2NIm1lrX5HNu0OvNqWmPBnGYjA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - regjsgen@0.8.0: - resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} + metro-runtime@0.84.3: + resolution: {integrity: sha512-o7HLRfMyVk9N2dUZ9VjQfB6xxUItL9Pi9WcqxURE7MEKOH6wbGt9/E92YdYLluTOtkzYAEVfdC6h6lcxqA+hMQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - regjsparser@0.12.0: - resolution: {integrity: sha512-cnE+y8bz4NhMjISKbgeVJtqNbtf5QpjZP+Bslo+UqkIt9QPnX9q095eiRRASJG1/tz6dlNr6Z5NsBiWYokp6EQ==} - hasBin: true + metro-source-map@0.84.3: + resolution: {integrity: sha512-jS48CeSzw78M8y6VE0f9uy3lVmfbOS677j2VCxnlmlYmnahcXuC6IhoN9K6LynNvos9517yUadcfgioju38xYQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - remeda@2.30.0: - resolution: {integrity: sha512-TcRpI1ecqnMer3jHhFtMerGvHFCDlCHljUp0/9A4HxHOh5bSY3kP1l8nQDFMnWYJKl3MSarDNY1tb0Bs/bCmvw==} + metro-symbolicate@0.84.3: + resolution: {integrity: sha512-J9Tpo8NCycYrozRvBIUyOwGAu4xkawOsAppmTscFiaegK0WvuDGwIM53GbzVSnytCHjVAF0io5GQxpkrKTuc7g==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true - require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} + metro-transform-plugins@0.84.3: + resolution: {integrity: sha512-8S3baq2XhBaafHEH5Q8sJW6tmzsEJk80qKc3RU/nZV1MsnYq94RdjTUR6AyKjQd6Rfsk1BtBxhtiNnk7mgslCg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} + metro-transform-worker@0.84.3: + resolution: {integrity: sha512-Wjba7PyYktNRsHbPmkx2J2UX32rAzcDXjCu49zPHeF/viJlYJhwRaNePQcHaCRqQ+kmgQT4ThprsnJfDj71ZMA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - require-main-filename@2.0.0: - resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + metro@0.84.3: + resolution: {integrity: sha512-1h3lbVrE6hGf1e/764HfhPGg/bGrWMJDDh7G2rc4gFYZboVuI40BlG/y+UhtbhQDNlO/csMvrcnK0YrTlHUVew==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true - requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} + micro-ftch@0.3.1: + resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} - resedit@1.7.2: - resolution: {integrity: sha512-vHjcY2MlAITJhC0eRD/Vv8Vlgmu9Sd3LX9zZvtGzU5ZImdTN3+d6e/4mnTyV8vEbyf1sgNIrWxhWlrys52OkEA==} - engines: {node: '>=12', npm: '>=6'} + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} - resolve-alpn@1.2.1: - resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} - resolve-from@5.0.0: - resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} - engines: {node: '>=8'} + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} - resolve-pkg-maps@1.0.0: - resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} - engines: {node: '>= 0.4'} + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} hasBin: true - resolve@2.0.0-next.5: - resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} - hasBin: true + mimic-response@1.0.1: + resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==} + engines: {node: '>=4'} - responselike@2.0.1: - resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + mimic-response@3.1.0: + resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} + engines: {node: '>=10'} - restore-cursor@3.1.0: - resolution: {integrity: sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==} - engines: {node: '>=8'} + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} - ret@0.5.0: - resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} - engines: {node: '>=10'} + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} - retry@0.12.0: - resolution: {integrity: sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==} - engines: {node: '>= 4'} + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} - retry@0.13.1: - resolution: {integrity: sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==} - engines: {node: '>= 4'} + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} - reusify@1.1.0: - resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} - engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - rfdc@1.4.1: - resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} - rimraf@2.6.3: - resolution: {integrity: sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true + mipd@0.0.7: + resolution: {integrity: sha512-aAPZPNDQ3uMTdKbuO2YmAw2TxLHO0moa4YKAyETM/DTj5FloZo+a+8tU+iv4GmW+sOxKLSRwcSFuczk+Cpt6fg==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} hasBin: true - ripemd160@2.0.2: - resolution: {integrity: sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==} + mlly@1.7.4: + resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} - roarr@2.15.4: - resolution: {integrity: sha512-CHhPh+UNHD2GTXNYhPWLnU8ONHdI+5DI+4EYIAOaiD63rHeYlZvyh8P+in5999TTSFgUYuKUAjzRI4mdh/p+2A==} - engines: {node: '>=8.0'} + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} - rollup@4.46.4: - resolution: {integrity: sha512-YbxoxvoqNg9zAmw4+vzh1FkGAiZRK+LhnSrbSrSXMdZYsRPDWoshcSd/pldKRO6lWzv/e9TiJAVQyirYIeSIPQ==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} - router@2.2.0: - resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} - engines: {node: '>= 18'} + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - rpc-websockets@9.1.3: - resolution: {integrity: sha512-I+kNjW0udB4Fetr3vvtRuYZJS0PcSPyyvBcH5sDdoV8DFs5E4W2pTr7aiMlKfPxANTClP9RlqCPolj9dd5MsEA==} + multiformats@9.9.0: + resolution: {integrity: sha512-HoMUjhH9T8DDBNT+6xzkrd9ga/XiBI4xLr58LJACwK6G3HTOPeMz4nB4KJs33L2BelrIJa7P0VuNaVF3hMYfjg==} - rrweb-cssom@0.8.0: - resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - run-parallel@1.2.0: - resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true - rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + napi-postinstall@0.3.3: + resolution: {integrity: sha512-uTp172LLXSxuSYHv/kou+f6KW3SMppU9ivthaVTXian9sOt3XM/zHYHpRZiLgQoxeWfYUnslNWQHF1+G71xcow==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true - safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} - engines: {node: '>=0.4'} + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - safe-buffer@5.1.2: - resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} + negotiator@0.6.3: + resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} + engines: {node: '>= 0.6'} - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} - safe-push-apply@1.0.0: - resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} - engines: {node: '>= 0.4'} + next@16.0.10: + resolution: {integrity: sha512-RtWh5PUgI+vxlV3HdR+IfWA1UUHu0+Ram/JBO4vWB54cVPentCD0e+lxyAYEsDTqGGMg7qpjhKh6dc6aW7W/sA==} + engines: {node: '>=20.9.0'} + hasBin: true + peerDependencies: + '@opentelemetry/api': ^1.1.0 + '@playwright/test': ^1.51.1 + babel-plugin-react-compiler: '*' + react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 + sass: ^1.3.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@playwright/test': + optional: true + babel-plugin-react-compiler: + optional: true + sass: + optional: true - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} + node-addon-api@2.0.2: + resolution: {integrity: sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==} - safe-regex2@5.1.0: - resolution: {integrity: sha512-pNHAuBW7TrcleFHsxBr5QMi/Iyp0ENjUKz7GCcX1UO7cMh+NmVK6HxQckNL1tJp1XAJVjG6B8OKIPqodqj9rtw==} - hasBin: true + node-domexception@1.0.0: + resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} + engines: {node: '>=10.5.0'} + deprecated: Use your platform's native DOMException instead - safe-stable-stringify@2.5.0: - resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} - engines: {node: '>=10'} + node-fetch-native@1.6.7: + resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true - sanitize-filename@1.6.3: - resolution: {integrity: sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==} + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true - sax@1.4.1: - resolution: {integrity: sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg==} + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} + node-mock-http@1.0.2: + resolution: {integrity: sha512-zWaamgDUdo9SSLw47we78+zYw/bDr5gH8pH7oRRs8V3KmBtu8GLgGIbV2p/gRPd3LWpEOpjQj7X1FOU3VFMJ8g==} - scheduler@0.23.2: - resolution: {integrity: sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==} + node-releases@2.0.19: + resolution: {integrity: sha512-xxOWJsBKtzAq7DY0J+DTzuz58K8e7sJbdgwkbMWQe8UYB6ekmsQ45q0M/tJDsGaZmbC+l7n57UV8Hl5tHxO9uw==} - scheduler@0.26.0: - resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + normalize-url@6.1.0: + resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==} + engines: {node: '>=10'} - secp256k1@5.0.1: - resolution: {integrity: sha512-lDFs9AAIaWP9UCdtWrotXWWF9t8PWgQDcxqgAnpM9rMqxb3Oaq2J0thzPVSxBwdJgyQtkU/sYtFtbM1RSt/iYA==} - engines: {node: '>=18.0.0'} + nullthrows@1.1.1: + resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} - secure-json-parse@4.1.0: - resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} + nwsapi@2.2.21: + resolution: {integrity: sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==} - selderee@0.11.0: - resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} + ob1@0.84.3: + resolution: {integrity: sha512-J7554Ef8bzmKaDY365Afq6PF+qtdnY/d5PKUQFrsKlZHV/N3OGZewVrvDrQDyX5V5NJjTpcAKtlrFZcDr+HvpQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - semver-compare@1.0.0: - resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} + obj-multiplex@1.0.0: + resolution: {integrity: sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA==} - semver@5.7.2: - resolution: {integrity: sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==} - hasBin: true + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} - semver@7.7.2: - resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} - engines: {node: '>=10'} - hasBin: true + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} - engines: {node: '>=10'} - hasBin: true + object.assign@4.1.7: + resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} + engines: {node: '>= 0.4'} - send@0.19.0: - resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} - engines: {node: '>= 0.8.0'} + object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} - send@1.2.0: - resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} - engines: {node: '>= 18'} + object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} + engines: {node: '>= 0.4'} - serialize-error@7.0.1: - resolution: {integrity: sha512-8I8TjW5KMOKsZQTvoxjuSIa7foAwPWGOts+6o7sgjz41/qMD9VQHEDxi6PBvK2l0MXUmqZyNpUK+T2tQaaElvw==} - engines: {node: '>=10'} + object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} - serve-static@1.16.2: - resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} - engines: {node: '>= 0.8.0'} + object.values@1.2.1: + resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} + engines: {node: '>= 0.4'} - serve-static@2.2.0: - resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} - engines: {node: '>= 18'} + ofetch@1.4.1: + resolution: {integrity: sha512-QZj2DfGplQAr2oj9KzceK9Hwz6Whxazmn85yYeVuS3u9XTMOGMRx0kO95MQ+vLsj/S/NwBDMMLU5hpxvI6Tklw==} - set-blocking@2.0.0: - resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + on-exit-leak-free@0.2.0: + resolution: {integrity: sha512-dqaz3u44QbRXQooZLTUKU41ZrzYrcvLISVgbrzbyCMxpmSLJvZ3ZamIJIZ29P6OhZIkNIQKosdeM6t1LYbA9hg==} - set-cookie-parser@2.7.2: - resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + on-exit-leak-free@2.1.2: + resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} + engines: {node: '>=14.0.0'} - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} + on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} - set-proto@1.0.0: - resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} - engines: {node: '>= 0.4'} + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} - setprototypeof@1.2.0: - resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + open@7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} - sha.js@2.4.12: - resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} - engines: {node: '>= 0.10'} + openai@4.104.0: + resolution: {integrity: sha512-p99EFNsA/yX6UhVO93f5kJsDRLAg+CTA2RBqdHK4RtK8u5IJw32Hyb2dTGKbnnFmnuoBv5r7Z2CURI9sGZpSuA==} hasBin: true + peerDependencies: + ws: ^8.18.0 + zod: ^3.23.8 + peerDependenciesMeta: + ws: + optional: true + zod: + optional: true - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + openapi-fetch@0.13.8: + resolution: {integrity: sha512-yJ4QKRyNxE44baQ9mY5+r/kAzZ8yXMemtNAOFwOzRXJscdjSxxzWSNlyBAr+o5JjkUw9Lc3W7OIoca0cY3PYnQ==} - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + openapi-typescript-helpers@0.0.15: + resolution: {integrity: sha512-opyTPaunsklCBpTK8JGef6mfPhLSnyy5a0IN9vKtx3+4aExf+KxEqYwIy3hqkedXIB97u357uLMJsOnm3GVjsw==} - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} - shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + own-keys@1.0.1: + resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} + ox@0.14.20: + resolution: {integrity: sha512-rby38C3nDn8eQkf29Zgw4hkCZJ64Qqi0zRPWL8ENUQ7JVuoITqrVtwWQgM/He19SCMUEc7hS/Sjw0jIOSLJhOw==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} + ox@0.4.4: + resolution: {integrity: sha512-oJPEeCDs9iNiPs6J0rTx+Y0KGeCGyCAA3zo94yZhm8G5WpOxrwUtn2Ie/Y8IyARSqqY/j9JTKA3Fc1xs1DvFnw==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} + ox@0.6.7: + resolution: {integrity: sha512-17Gk/eFsFRAZ80p5eKqv89a57uXjd3NgIf1CaXojATPBuujVc/fQSVhBeAU9JCRB+k7J50WQAyWTxK19T9GgbA==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} + ox@0.6.9: + resolution: {integrity: sha512-wi5ShvzE4eOcTwQVsIPdFr+8ycyX+5le/96iAJutaZAvCes1J0+RvpEPg5QDPDiaR0XQQAvZVl7AwqQcINuUug==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + ox@0.9.17: + resolution: {integrity: sha512-rKAnhzhRU3Xh3hiko+i1ZxywZ55eWQzeS/Q4HRKLx2PqfHOolisZHErSsJVipGlmQKHW5qwOED/GighEw9dbLg==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true - signal-exit@3.0.7: - resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + ox@0.9.3: + resolution: {integrity: sha512-KzyJP+fPV4uhuuqrTZyok4DC7vFzi7HLUFiUNEmpbyh59htKWkOC98IONC1zgXJPbHAhQgqs6B0Z6StCGhmQvg==} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true - signal-exit@4.1.0: - resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} - engines: {node: '>=14'} + p-cancelable@2.1.1: + resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} + engines: {node: '>=8'} - simple-swizzle@0.2.2: - resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==} + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} - simple-update-notifier@2.0.0: - resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} - simple-wcswidth@1.1.2: - resolution: {integrity: sha512-j7piyCjAeTDSjzTSQ7DokZtMNwNlEAyxqSZeCS+CXH7fJ4jx3FuJ/mTW3mE+6JLs4VJBbcll0Kjn+KXI5t21Iw==} - - siwe@2.3.2: - resolution: {integrity: sha512-aSf+6+Latyttbj5nMu6GF3doMfv2UYj83hhwZgUF20ky6fTS83uVhkQABdIVnEuS8y1bBdk7p6ltb9SmlhTTlA==} - peerDependencies: - ethers: ^5.6.8 || ^6.0.8 - - slash@3.0.0: - resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} - slice-ansi@3.0.0: - resolution: {integrity: sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==} - engines: {node: '>=8'} + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} - smart-buffer@4.2.0: - resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} - engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} - snake-case@3.0.4: - resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - socket.io-client@4.8.1: - resolution: {integrity: sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==} - engines: {node: '>=10.0.0'} + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} - socket.io-parser@4.2.4: - resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} - engines: {node: '>=10.0.0'} + parse-imports-exports@0.2.4: + resolution: {integrity: sha512-4s6vd6dx1AotCx/RCI2m7t7GCh5bDRUtGNvRfHSP2wbBQdMi67pPe7mtzmgwcaQ8VKK/6IB7Glfyu3qdZJPybQ==} - socks-proxy-agent@7.0.0: - resolution: {integrity: sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==} - engines: {node: '>= 10'} + parse-statements@1.0.11: + resolution: {integrity: sha512-HlsyYdMBnbPQ9Jr/VgJ1YF4scnldvJpJxCVx6KgqPL4dxppsWrJHCIIxQXMJrqGnsRkNPATbeMJ8Yxu7JMsYcA==} - socks@2.8.7: - resolution: {integrity: sha512-HLpt+uLy/pxB+bum/9DzAgiKS8CX1EvbWxI4zlmgGCExImLdiad2iCwXT5Z4c9c3Eq8rP2318mPW2c+QbtjK8A==} - engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - sonic-boom@2.8.0: - resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==} + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} - sonic-boom@4.2.1: - resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} - source-map-support@0.5.21: - resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + path-parse@1.0.7: + resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} - source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} - deprecated: The work that was done in this beta branch won't be included in future versions + path-to-regexp@0.1.12: + resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} - spawn-command@0.0.2: - resolution: {integrity: sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==} + path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} - spdx-exceptions@2.5.0: - resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - spdx-expression-parse@4.0.0: - resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} - spdx-license-ids@3.0.22: - resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - split-on-first@1.1.0: - resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} - engines: {node: '>=6'} + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} - split2@4.2.0: - resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} - engines: {node: '>= 10.x'} + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} - sprintf-js@1.1.3: - resolution: {integrity: sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==} + pify@3.0.0: + resolution: {integrity: sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==} + engines: {node: '>=4'} - ssri@9.0.1: - resolution: {integrity: sha512-o57Wcn66jMQvfHG1FlYbWeZWW/dHZhJXjpIcTfXldXEk5nz5lStPo3mK0OJQfGR3RbZUlbISexbljkJzuEj/8Q==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + pify@5.0.0: + resolution: {integrity: sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==} + engines: {node: '>=10'} - stable-hash@0.0.5: - resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} + pino-abstract-transport@0.5.0: + resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==} - stack-trace@0.0.10: - resolution: {integrity: sha512-KGzahc7puUKkzyMt+IqAep+TVNbKP+k2Lmwhub39m1AsTSkaDutx56aDCo+HLDzf/D26BIHTJWNiTG1KAJiQCg==} + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + pino-abstract-transport@3.0.0: + resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} - stat-mode@1.0.0: - resolution: {integrity: sha512-jH9EhtKIjuXZ2cWxmXS8ZP80XyC3iasQxMDV8jzhNJpfDb7VbQLVW4Wvsxz9QZvzV+G4YoSfBUVKDOyxLzi/sg==} - engines: {node: '>= 6'} + pino-pretty@13.0.0: + resolution: {integrity: sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==} + hasBin: true - statuses@2.0.1: - resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} - engines: {node: '>= 0.8'} + pino-std-serializers@4.0.0: + resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==} - statuses@2.0.2: - resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} - engines: {node: '>= 0.8'} + pino-std-serializers@7.1.0: + resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} - std-env@3.9.0: - resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} + pino@10.0.0: + resolution: {integrity: sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA==} + hasBin: true - stop-iteration-iterator@1.1.0: - resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} - engines: {node: '>= 0.4'} + pino@10.1.0: + resolution: {integrity: sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==} + hasBin: true - stream-chain@2.2.5: - resolution: {integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==} + pino@10.3.1: + resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} + hasBin: true - stream-json@1.9.1: - resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==} + pino@7.11.0: + resolution: {integrity: sha512-dMACeu63HtRLmCG8VKdy4cShCPKaYDR4youZqoSWLxl5Gu99HUw8bw75thbPv9Nip+H+QYX8o3ZJbTdVZZ2TVg==} + hasBin: true - stream-shift@1.0.3: - resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} - strict-uri-encode@2.0.0: - resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} - engines: {node: '>=4'} + pkce-challenge@5.0.0: + resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} + engines: {node: '>=16.20.0'} - string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} - string.prototype.includes@2.0.1: - resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} - engines: {node: '>= 0.4'} + pony-cause@2.1.11: + resolution: {integrity: sha512-M7LhCsdNbNgiLYiP4WjsfLUuFmCfnjdF6jKe2R9NKl4WFN+HZPGHJZ9lnLP7f9ZnKe3U9nuWD0szirmj+migUg==} + engines: {node: '>=12.0.0'} - string.prototype.matchall@4.0.12: - resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} - engines: {node: '>= 0.4'} + porto@0.2.35: + resolution: {integrity: sha512-gu9FfjjvvYBgQXUHWTp6n3wkTxVtEcqFotM7i3GEZeoQbvLGbssAicCz6hFZ8+xggrJWwi/RLmbwNra50SMmUQ==} + hasBin: true + peerDependencies: + '@tanstack/react-query': '>=5.59.0' + '@wagmi/core': '>=2.16.3' + expo-auth-session: '>=7.0.8' + expo-crypto: '>=15.0.7' + expo-web-browser: '>=15.0.8' + react: '>=18' + react-native: '>=0.81.4' + typescript: '>=5.4.0' + viem: '>=2.37.0' + wagmi: '>=2.0.0' + peerDependenciesMeta: + '@tanstack/react-query': + optional: true + expo-auth-session: + optional: true + expo-crypto: + optional: true + expo-web-browser: + optional: true + react: + optional: true + react-native: + optional: true + typescript: + optional: true + wagmi: + optional: true - string.prototype.repeat@1.0.0: - resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} + poseidon-lite@0.2.1: + resolution: {integrity: sha512-xIr+G6HeYfOhCuswdqcFpSX47SPhm0EpisWJ6h7fHlWwaVIvH3dLnejpatrtw6Xc6HaLrpq05y7VRfvDmDGIog==} - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + possible-typed-array-names@1.1.0: + resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} - string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} - engines: {node: '>= 0.4'} + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true - string.prototype.trimstart@1.0.8: - resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} - engines: {node: '>= 0.4'} + postcss@8.4.31: + resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} + engines: {node: ^10 || ^12 || >=14} - string_decoder@1.1.1: - resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + preact@10.24.2: + resolution: {integrity: sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==} - strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + preact@10.27.1: + resolution: {integrity: sha512-V79raXEWch/rbqoNc7nT9E4ep7lu+mI3+sBmfRD4i1M73R3WLYcCtdI0ibxGVf4eQL8ZIz2nFacqEC+rmnOORQ==} - strip-ansi@7.1.0: - resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} - engines: {node: '>=12'} + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} - strip-bom@3.0.0: - resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} - engines: {node: '>=4'} + prettier-linter-helpers@1.0.1: + resolution: {integrity: sha512-SxToR7P8Y2lWmv/kTzVLC1t/GDI2WGjMwNhLLE9qtH8Q13C+aEmuRlzDst4Up4s0Wc8sF2M+J57iB3cMLqftfg==} + engines: {node: '>=6.0.0'} - strip-final-newline@2.0.0: - resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} - engines: {node: '>=6'} + prettier@3.5.2: + resolution: {integrity: sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==} + engines: {node: '>=14'} + hasBin: true - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - strip-literal@3.0.0: - resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} + process-nextick-args@2.0.1: + resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} - styled-jsx@5.1.6: - resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true + process-warning@1.0.0: + resolution: {integrity: sha512-du4wfLyj4yCZq1VupnVSZmRsPJsNuxoDQFdCFHLaYiEbFBD7QE0a+I4D7hOxrVnh78QE/YipFAj9lXHiXocV+Q==} - sucrase@3.35.0: - resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} - engines: {node: '>=16 || 14 >=14.17'} - hasBin: true + process-warning@4.0.1: + resolution: {integrity: sha512-3c2LzQ3rY9d0hc1emcsHhfT9Jwz0cChib/QN89oME2R451w5fy3f0afAhERFZAwrbDU43wk12d0ORBpDVME50Q==} - sumchecker@3.0.1: - resolution: {integrity: sha512-MvjXzkz/BOfyVDkG0oFOtBxHX2u3gKbMHIF/dXblZsgD3BWOFLmHovIpZY7BykJdAjcqRCBi1WYBNdEC9yI7vg==} - engines: {node: '>= 8.0'} + process-warning@5.0.0: + resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} - superstruct@1.0.4: - resolution: {integrity: sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==} - engines: {node: '>=14.0.0'} + promise@8.3.0: + resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} - superstruct@2.0.2: - resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} - engines: {node: '>=14.0.0'} + prop-types@15.8.1: + resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + protobufjs@7.5.4: + resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + engines: {node: '>=12.0.0'} - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} + proxy-compare@2.6.0: + resolution: {integrity: sha512-8xuCeM3l8yqdmbPoYeLbrAXCBWu19XEYc5/F28f5qOaoAIMyfmBUkl5axiK+x9olUvRlcekvnm98AP9RDngOIw==} - svg-parser@2.0.4: - resolution: {integrity: sha512-e4hG1hRwoOdRb37cIMSgzNsxyzKfayW6VOflrwvR+/bzrkyxY/31WkbgnQpgtrNp1SdpJvpUAGTa/ZoiPNDuRQ==} + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - svgo@3.3.2: - resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==} - engines: {node: '>=14.0.0'} - hasBin: true + pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} - svix@1.74.1: - resolution: {integrity: sha512-99J8jSsk0viwkoAENVy/zpVoZxwn3kBdUvvpFaWiKjCkkTcqNZdoBqMmariDFceL4Q41ntWfUYxaWD37IAk9Kg==} + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} - synckit@0.11.11: - resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} - engines: {node: ^14.18.0 || >=16.0.0} + pvutils@1.1.5: + resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} + engines: {node: '>=16.0.0'} - tabbable@6.3.0: - resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + qr-code-styling@1.6.0-rc.1: + resolution: {integrity: sha512-ModRIiW6oUnsP18QzrRYZSc/CFKFKIdj7pUs57AEVH20ajlglRpN3HukjHk0UbNMTlKGuaYl7Gt6/O5Gg2NU2Q==} - tailwind-merge@2.6.0: - resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} + qrcode-generator@1.5.2: + resolution: {integrity: sha512-pItrW0Z9HnDBnFmgiNrY1uxRdri32Uh9EjNYLPVC2zZ3ZRIIEqBoDgm4DkvDwNNDHTK7FNkmr8zAa77BYc9xNw==} - tailwind-merge@3.4.0: - resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + qrcode@1.5.3: + resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} + engines: {node: '>=10.13.0'} + hasBin: true - tailwindcss@3.4.17: - resolution: {integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==} - engines: {node: '>=14.0.0'} + qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} + engines: {node: '>=10.13.0'} hasBin: true - tailwindcss@4.1.17: - resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} + qs@6.13.0: + resolution: {integrity: sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==} + engines: {node: '>=0.6'} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + query-string@6.13.5: + resolution: {integrity: sha512-svk3xg9qHR39P3JlHuD7g3nRnyay5mHbrPctEBDUxUkHRifPHXJDhBUycdCC0NBjXoDf44Gb+IsOZL1Uwn8M/Q==} engines: {node: '>=6'} - tar@6.2.1: - resolution: {integrity: sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==} + query-string@7.1.3: + resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} + engines: {node: '>=6'} + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + + quick-format-unescaped@4.0.4: + resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} + + quick-lru@5.1.1: + resolution: {integrity: sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==} engines: {node: '>=10'} - deprecated: Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - temp-file@3.4.0: - resolution: {integrity: sha512-C5tjlC/HCtVUOi3KWVokd4vHVViOmGjtLwIh4MuzPo/nMYTV/p1urt3RnMz2IWXDdKEGJH3k5+KPxtqRsUYGtg==} + radix3@1.1.2: + resolution: {integrity: sha512-b484I/7b8rDEdSDKckSSBA8knMpcdsXudlE/LNL639wFoHKwLbEkQFZHWEYwDC0wa0FKUcCY+GAF73Z7wxNVFA==} - temp@0.9.4: - resolution: {integrity: sha512-yYrrsWnrXMcdsnu/7YMYAofM1ktpL5By7vZhf15CrXijWWrEYZks5AXBudalfSWJLlnen/QUJUB5aoB0kqZUGA==} - engines: {node: '>=6.0.0'} + randombytes@2.1.0: + resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - text-encoding-utf-8@1.0.2: - resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} - text-hex@1.0.0: - resolution: {integrity: sha512-uuVGNWzgJ4yhRaNSiubPY7OjISw4sw4E5Uv0wbjp+OzcbmVU/rsT8ujgcXJhn9ypzsgr5vlzpPqP+MBBKcGvbg==} + raw-body@2.5.2: + resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} + engines: {node: '>= 0.8'} - text-table@0.2.0: - resolution: {integrity: sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==} + raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} - thenify-all@1.6.0: - resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} - engines: {node: '>=0.8'} + react-devtools-core@6.1.5: + resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} - thenify@3.3.1: - resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + react-dom@19.1.1: + resolution: {integrity: sha512-Dlq/5LAZgF0Gaz6yiqZCf6VCcZs1ghAJyrsu84Q/GT0gV+mCxbfmKNoGRKBYMJ8IEdGPqu49YWXD02GCknEDkw==} + peerDependencies: + react: ^19.1.1 - thread-stream@0.15.2: - resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==} + react-dom@19.2.3: + resolution: {integrity: sha512-yELu4WmLPw5Mr/lmeEpox5rw3RETacE++JgHqQzd2dg+YbJuat3jH4ingc+WPZhxaoFzdv9y33G+F7Nl5O0GBg==} + peerDependencies: + react: ^19.2.3 - thread-stream@4.0.0: - resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} - engines: {node: '>=20'} + react-is@16.13.1: + resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - tiny-async-pool@1.3.0: - resolution: {integrity: sha512-01EAw5EDrcVrdgyCLgoSPvqznC0sVxDSVeiOz09FUpjh71G79VCqneOr+xvt7T1r76CF6ZZfPjHorN2+d+3mqA==} + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + react-native-get-random-values@1.11.0: + resolution: {integrity: sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ==} + peerDependencies: + react-native: '>=0.56' - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + react-native@0.85.2: + resolution: {integrity: sha512-GFWEPwLYirfj5X8gMtXOWtqX0cqUEURRHETZfFk37VCa4++izrKvGvv24anvuyulXV87NAhVkfNw93rLg3HByw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + peerDependencies: + '@react-native/jest-preset': 0.85.2 + '@types/react': ^19.1.1 + react: ^19.2.3 + peerDependenciesMeta: + '@react-native/jest-preset': + optional: true + '@types/react': + optional: true - tinyglobby@0.2.14: - resolution: {integrity: sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==} - engines: {node: '>=12.0.0'} + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true - tinypool@1.1.1: - resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} - engines: {node: ^18.0.0 || >=20.0.0} + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - tinyspy@4.0.3: - resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} - engines: {node: '>=14.0.0'} + react@19.1.1: + resolution: {integrity: sha512-w8nqGImo45dmMIfljjMwOGtbmC/mk4CMYhWIicdSflH91J9TyCyczcPFXJzrZ/ZXcgGRFeP6BU0BEJTw6tZdfQ==} + engines: {node: '>=0.10.0'} - tldts-core@6.1.86: - resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} + react@19.2.3: + resolution: {integrity: sha512-Ku/hhYbVjOQnXDZFv2+RibmLFGwFdeeKHFcOTlrt7xplBnya5OGn/hIRDsqDiSUcfORsDC7MPxwork8jBwsIWA==} + engines: {node: '>=0.10.0'} - tldts@6.1.86: - resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} - hasBin: true + readable-stream@2.3.8: + resolution: {integrity: sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==} + + readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} - tmp-promise@3.0.3: - resolution: {integrity: sha512-RwM7MoPojPxsOBYnyd2hy0bxtIlVrihNs9pj5SUvY8Zz1sQcQG2tG1hSr8PDxfgEB8RNKDhqbIlroIarSNDNsQ==} + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} - tmp@0.2.5: - resolution: {integrity: sha512-voyz6MApa1rQGUxT3E+BK7/ROe8itEx7vD8/HEvt4xwXucvQ5G5oeEiHkmHZJuBO21RpOf+YYm9MOivj709jow==} - engines: {node: '>=14.14'} + real-require@0.1.0: + resolution: {integrity: sha512-r/H9MzAWtrv8aSVjPCMFpDMl5q66GqtmmRkRjpHTsp4zBAa+snZyiQNlMONiUmEJcsnaw0wCauJ2GWODr/aFkg==} + engines: {node: '>= 12.13.0'} - to-buffer@1.2.1: - resolution: {integrity: sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==} + real-require@0.2.0: + resolution: {integrity: sha512-57frrGM/OCTLqLOAh0mhVA9VBMHd+9U7Zb2THMGdBUoZVOtGbJzjxsYGDJ3A9AYYCP4hn6y1TVbaOfzWtm5GFg==} + engines: {node: '>= 12.13.0'} + + redis@5.12.1: + resolution: {integrity: sha512-LDsoVvb/CpoV9EN3FXvgvSHNJWuCIzl9MiO3ppOevuGLpSGJhwfQjpEwfFJcQvNSddHADDdZaWx0HnmMxRXG7g==} + engines: {node: '>= 18.19.0'} + + reflect.getprototypeof@1.0.10: + resolution: {integrity: sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==} engines: {node: '>= 0.4'} - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} - toad-cache@3.7.0: - resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} - engines: {node: '>=12'} + regexp.prototype.flags@1.5.4: + resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} + engines: {node: '>= 0.4'} - toidentifier@1.0.1: - resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} - engines: {node: '>=0.6'} + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} - toml@3.0.0: - resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} - tough-cookie@5.1.2: - resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} - engines: {node: '>=16'} + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + resolve-alpn@1.2.1: + resolution: {integrity: sha512-0a1F4l73/ZFZOakJnQ3FvkJ2+gSTQWz/r2KE5OdDY0TxPm5h4GkqkWWfM47T7HsbnOtcJVEF4epCVy6u7Q3K+g==} - tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} - tr46@5.1.1: - resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} - engines: {node: '>=18'} + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} - tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + resolve-pkg-maps@1.0.0: + resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} + + resolve@1.22.10: + resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + engines: {node: '>= 0.4'} + hasBin: true + + resolve@2.0.0-next.5: + resolution: {integrity: sha512-U7WjGVG9sH8tvjW5SmGbQuui75FiyjAX72HX15DwBBwF9dNiQZRQAg9nnPhYy+TUnE0+VcrttuvNI8oSxZcocA==} hasBin: true - tree-sitter@0.22.4: - resolution: {integrity: sha512-usbHZP9/oxNsUY65MQUsduGRqDHQOou1cagUSwjhoSYAmSahjQDAVsh9s+SlZkn8X8+O1FULRGwHu7AFP3kjzg==} + responselike@2.0.1: + resolution: {integrity: sha512-4gl03wn3hj1HP3yzgdI7d3lCkF95F21Pz4BPGvKHinyQzALR5CapwC8yIi0Rh58DEMQ/SguC03wFj2k0M/mHhw==} + + ret@0.5.0: + resolution: {integrity: sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==} + engines: {node: '>=10'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - treeify@1.1.0: - resolution: {integrity: sha512-1m4RA7xVAJrSGrrXGs0L3YTwyvBs2S8PbRHaLZAkFw7JR8oIFwYtysxlBZhYIa7xSyiYJKZ3iGrrk55cGA3i9A==} - engines: {node: '>=0.6'} + rfc4648@1.5.3: + resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==} - triple-beam@1.4.1: - resolution: {integrity: sha512-aZbgViZrg1QNcG+LULa7nhZpJTZSLm/mXnHXnbAbjmN5aSa0y7V+wvv6+4WaBtpISJzThKy+PIPxc1Nq1EJ9mg==} - engines: {node: '>= 14.0.0'} + rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} - truncate-utf8-bytes@1.0.2: - resolution: {integrity: sha512-95Pu1QXQvruGEhv62XCMO3Mm90GscOCClvrIUwCM0PYOXK3kaF3l3sIHxx71ThJfcbM2O5Au6SO3AWCSEfW4mQ==} + rollup@4.46.4: + resolution: {integrity: sha512-YbxoxvoqNg9zAmw4+vzh1FkGAiZRK+LhnSrbSrSXMdZYsRPDWoshcSd/pldKRO6lWzv/e9TiJAVQyirYIeSIPQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true - ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} - ts-case-convert@2.1.0: - resolution: {integrity: sha512-Ye79el/pHYXfoew6kqhMwCoxp4NWjKNcm2kBzpmEMIU9dd9aBmHNNFtZ+WTm0rz1ngyDmfqDXDlyUnBXayiD0w==} + rpc-websockets@9.1.3: + resolution: {integrity: sha512-I+kNjW0udB4Fetr3vvtRuYZJS0PcSPyyvBcH5sDdoV8DFs5E4W2pTr7aiMlKfPxANTClP9RlqCPolj9dd5MsEA==} - ts-interface-checker@0.1.13: - resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + rrweb-cssom@0.8.0: + resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} - tsconfck@3.1.6: - resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} - engines: {node: ^18 || >=20} - hasBin: true - peerDependencies: - typescript: ^5.0.0 - peerDependenciesMeta: - typescript: - optional: true + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} - tsconfig-paths@3.15.0: - resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} + safe-array-concat@1.1.3: + resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + engines: {node: '>=0.4'} - tslib@1.14.1: - resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + safe-buffer@5.1.2: + resolution: {integrity: sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==} - tslib@2.7.0: - resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + safe-push-apply@1.0.0: + resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} + engines: {node: '>= 0.4'} - tsup@7.3.0: - resolution: {integrity: sha512-Ja1eaSRrE+QarmATlNO5fse2aOACYMBX+IZRKy1T+gpyH+jXgRrl5l4nHIQJQ1DoDgEjHDTw8cpE085UdBZuWQ==} - engines: {node: '>=18'} - deprecated: Breaking node 16 - hasBin: true - peerDependencies: - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.5.0' - peerDependenciesMeta: - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true + safe-regex-test@1.1.0: + resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} + engines: {node: '>= 0.4'} - tsup@8.5.0: - resolution: {integrity: sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==} - engines: {node: '>=18'} + safe-regex2@5.1.0: + resolution: {integrity: sha512-pNHAuBW7TrcleFHsxBr5QMi/Iyp0ENjUKz7GCcX1UO7cMh+NmVK6HxQckNL1tJp1XAJVjG6B8OKIPqodqj9rtw==} hasBin: true - peerDependencies: - '@microsoft/api-extractor': ^7.36.0 - '@swc/core': ^1 - postcss: ^8.4.12 - typescript: '>=4.5.0' - peerDependenciesMeta: - '@microsoft/api-extractor': - optional: true - '@swc/core': - optional: true - postcss: - optional: true - typescript: - optional: true - tsx@4.20.4: - resolution: {integrity: sha512-yyxBKfORQ7LuRt/BQKBXrpcq59ZvSW0XxwfjAt3w2/8PmdxaFzijtMhTawprSHhpzeM5BgU2hXHG3lklIERZXg==} - engines: {node: '>=18.0.0'} - hasBin: true + safe-stable-stringify@2.5.0: + resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} + engines: {node: '>=10'} - turbo-darwin-64@2.5.6: - resolution: {integrity: sha512-3C1xEdo4aFwMJAPvtlPqz1Sw/+cddWIOmsalHFMrsqqydcptwBfu26WW2cDm3u93bUzMbBJ8k3zNKFqxJ9ei2A==} - cpu: [x64] - os: [darwin] + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - turbo-darwin-arm64@2.5.6: - resolution: {integrity: sha512-LyiG+rD7JhMfYwLqB6k3LZQtYn8CQQUePbpA8mF/hMLPAekXdJo1g0bUPw8RZLwQXUIU/3BU7tXENvhSGz5DPA==} - cpu: [arm64] - os: [darwin] + saxes@6.0.0: + resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} + engines: {node: '>=v12.22.7'} - turbo-linux-64@2.5.6: - resolution: {integrity: sha512-GOcUTT0xiT/pSnHL4YD6Yr3HreUhU8pUcGqcI2ksIF9b2/r/kRHwGFcsHgpG3+vtZF/kwsP0MV8FTlTObxsYIA==} - cpu: [x64] - os: [linux] + scheduler@0.26.0: + resolution: {integrity: sha512-NlHwttCI/l5gCPR3D1nNXtWABUmBwvZpEQiD4IXSbIDq8BzLIK/7Ir5gTFSGZDUu37K5cMNp0hFtzO38sC7gWA==} - turbo-linux-arm64@2.5.6: - resolution: {integrity: sha512-10Tm15bruJEA3m0V7iZcnQBpObGBcOgUcO+sY7/2vk1bweW34LMhkWi8svjV9iDF68+KJDThnYDlYE/bc7/zzQ==} - cpu: [arm64] - os: [linux] + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - turbo-windows-64@2.5.6: - resolution: {integrity: sha512-FyRsVpgaj76It0ludwZsNN40ytHN+17E4PFJyeliBEbxrGTc5BexlXVpufB7XlAaoaZVxbS6KT8RofLfDRyEPg==} - cpu: [x64] - os: [win32] + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} - turbo-windows-arm64@2.5.6: - resolution: {integrity: sha512-j/tWu8cMeQ7HPpKri6jvKtyXg9K1gRyhdK4tKrrchH8GNHscPX/F71zax58yYtLRWTiK04zNzPcUJuoS0+v/+Q==} - cpu: [arm64] - os: [win32] + secure-json-parse@4.1.0: + resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} - turbo@2.5.6: - resolution: {integrity: sha512-gxToHmi9oTBNB05UjUsrWf0OyN5ZXtD0apOarC1KIx232Vp3WimRNy3810QzeNSgyD5rsaIDXlxlbnOzlouo+w==} + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - tweetnacl@1.0.3: - resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} + semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} + engines: {node: '>=10'} + hasBin: true - twitter-api-v2@1.25.0: - resolution: {integrity: sha512-g3JDd5jwJD+gkEe2Qn3GI5GpasYJjFEauTw70kqiBGu+ectWUgtEKtIaZUGKB50+ApyNhl6v871YCS6un6YEJw==} + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + send@0.19.0: + resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} - type-fest@0.13.1: - resolution: {integrity: sha512-34R7HTnG0XIJcBSn5XhDd7nNFPRcXYRZrBB2O2jdKqYODldSzBAqzsWoZYYvduky73toYS/ESqxPvkDf/F0XMg==} - engines: {node: '>=10'} + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} - type-fest@0.20.2: - resolution: {integrity: sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==} - engines: {node: '>=10'} + serialize-error@2.1.0: + resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} + engines: {node: '>=0.10.0'} - type-fest@3.13.1: - resolution: {integrity: sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==} - engines: {node: '>=14.16'} + serve-static@1.16.2: + resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} + engines: {node: '>= 0.8.0'} - type-fest@4.41.0: - resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} - engines: {node: '>=16'} + serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} - type-is@1.6.18: - resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} - engines: {node: '>= 0.6'} + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} - typed-array-buffer@1.0.3: - resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} engines: {node: '>= 0.4'} - typed-array-byte-length@1.0.3: - resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + set-function-name@2.0.2: + resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} engines: {node: '>= 0.4'} - typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + set-proto@1.0.0: + resolution: {integrity: sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==} engines: {node: '>= 0.4'} - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} - engines: {node: '>= 0.4'} + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - typeforce@1.18.0: - resolution: {integrity: sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==} + sha.js@2.4.12: + resolution: {integrity: sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==} + engines: {node: '>= 0.10'} + hasBin: true - typescript-eslint@8.48.0: - resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - typescript@5.9.2: - resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} - engines: {node: '>=14.17'} - hasBin: true + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} - ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} - uint8arrays@3.1.0: - resolution: {integrity: sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==} + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} - unbox-primitive@1.1.0: - resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} - uncrypto@0.1.3: - resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} - undici-types@5.26.5: - resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - undici-types@7.10.0: - resolution: {integrity: sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==} + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + slow-redact@0.3.2: + resolution: {integrity: sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw==} - undici-types@7.22.0: - resolution: {integrity: sha512-RKZvifiL60xdsIuC80UY0dq8Z7DbJUV8/l2hOVbyZAxBzEeQU4Z58+4ZzJ6WN2Lidi9KzT5EbiGX+PI/UGYuRw==} + socket.io-client@4.8.1: + resolution: {integrity: sha512-hJVXfu3E28NmzGk8o1sHhN3om52tRvwYeidbj7xKy2eIIse5IoKX3USlS6Tqt3BHAtflLIkCQBkzVrEEfWUyYQ==} + engines: {node: '>=10.0.0'} - unicode-canonical-property-names-ecmascript@2.0.1: - resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} - engines: {node: '>=4'} + socket.io-parser@4.2.4: + resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + engines: {node: '>=10.0.0'} + + sonic-boom@2.8.0: + resolution: {integrity: sha512-kuonw1YOYYNOve5iHdSahXPOK49GqwA+LZhI6Wz/l0rP57iKyXXIHaRagOBHAPmGwJC6od2Z9zgvZ5loSgMlVg==} + + sonic-boom@4.2.1: + resolution: {integrity: sha512-w6AxtubXa2wTXAUsZMMWERrsIRAdrK0Sc+FUytWvYAhBJLyuI4llrMIC1DtlNSdI99EI86KZum2MMq3EAZlF9Q==} + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} - unicode-match-property-ecmascript@2.0.0: - resolution: {integrity: sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==} - engines: {node: '>=4'} + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} - unicode-match-property-value-ecmascript@2.2.0: - resolution: {integrity: sha512-4IehN3V/+kkr5YeSSDDQG8QLqO26XpL2XP3GQtqwlT/QYSECAwFztxVHjlbh0+gjJ3XmNLS0zDsbgs9jWKExLg==} - engines: {node: '>=4'} + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} - unicode-property-aliases-ecmascript@2.1.0: - resolution: {integrity: sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==} - engines: {node: '>=4'} + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} - unique-filename@2.0.1: - resolution: {integrity: sha512-ODWHtkkdx3IAR+veKxFV+VBkUMcN+FaqzUUd7IZzt+0zhDZFPFxhlqwPF3YQvMHx1TD0tdgYl+kuPnJ8E6ql7A==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + source-map@0.8.0-beta.0: + resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} + engines: {node: '>= 8'} + deprecated: The work that was done in this beta branch won't be included in future versions - unique-slug@3.0.0: - resolution: {integrity: sha512-8EyMynh679x/0gqE9fT9oilG+qEt+ibFyqjuVTsZn1+CMxH+XLlpvr2UZx4nVcCwTpx81nICr2JQFkM+HPLq4w==} - engines: {node: ^12.13.0 || ^14.15.0 || >=16.0.0} + spark-md5@3.0.2: + resolution: {integrity: sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==} - universalify@0.1.2: - resolution: {integrity: sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==} - engines: {node: '>= 4.0.0'} + spdx-exceptions@2.5.0: + resolution: {integrity: sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==} - universalify@2.0.1: - resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} - engines: {node: '>= 10.0.0'} + spdx-expression-parse@4.0.0: + resolution: {integrity: sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==} - unpipe@1.0.0: - resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} - engines: {node: '>= 0.8'} + spdx-license-ids@3.0.22: + resolution: {integrity: sha512-4PRT4nh1EImPbt2jASOKHX7PB7I+e4IWNLvkKFDxNhJlfjbYlleYQh285Z/3mPTHSAK/AvdMmw5BNNuYH8ShgQ==} - unrs-resolver@1.11.1: - resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + split-on-first@1.1.0: + resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==} + engines: {node: '>=6'} - unstorage@1.16.1: - resolution: {integrity: sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==} - peerDependencies: - '@azure/app-configuration': ^1.8.0 - '@azure/cosmos': ^4.2.0 - '@azure/data-tables': ^13.3.0 - '@azure/identity': ^4.6.0 - '@azure/keyvault-secrets': ^4.9.0 - '@azure/storage-blob': ^12.26.0 - '@capacitor/preferences': ^6.0.3 || ^7.0.0 - '@deno/kv': '>=0.9.0' - '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 - '@planetscale/database': ^1.19.0 - '@upstash/redis': ^1.34.3 - '@vercel/blob': '>=0.27.1' - '@vercel/kv': ^1.0.1 - aws4fetch: ^1.0.20 - db0: '>=0.2.1' - idb-keyval: ^6.2.1 - ioredis: ^5.4.2 - uploadthing: ^7.4.4 - peerDependenciesMeta: - '@azure/app-configuration': - optional: true - '@azure/cosmos': - optional: true - '@azure/data-tables': - optional: true - '@azure/identity': - optional: true - '@azure/keyvault-secrets': - optional: true - '@azure/storage-blob': - optional: true - '@capacitor/preferences': - optional: true - '@deno/kv': - optional: true - '@netlify/blobs': - optional: true - '@planetscale/database': - optional: true - '@upstash/redis': - optional: true - '@vercel/blob': - optional: true - '@vercel/kv': - optional: true - aws4fetch: - optional: true - db0: - optional: true - idb-keyval: - optional: true - ioredis: - optional: true - uploadthing: - optional: true + split2@4.2.0: + resolution: {integrity: sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==} + engines: {node: '>= 10.x'} - update-browserslist-db@1.1.3: - resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' + stable-hash@0.0.5: + resolution: {integrity: sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==} - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - urijs@1.19.11: - resolution: {integrity: sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==} + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} - url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} + stacktrace-parser@0.1.11: + resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} + engines: {node: '>=6'} - use-callback-ref@1.3.3: - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} - use-sidecar@1.1.3: - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} - use-sync-external-store@1.2.0: - resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} - use-sync-external-store@1.4.0: - resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + std-env@3.9.0: + resolution: {integrity: sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==} - use-sync-external-store@1.5.0: - resolution: {integrity: sha512-Rb46I4cGGVBmjamjphe8L/UnvJD+uPPtTkNvX5mZgqdbavhI4EbgIWJiIHXJ8bc/i9EQGPRh4DwEURJ552Do0A==} - peerDependencies: - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} - usehooks-ts@3.1.1: - resolution: {integrity: sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA==} - engines: {node: '>=16.15.0'} - peerDependencies: - react: ^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc + stream-chain@2.2.5: + resolution: {integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==} - utf-8-validate@5.0.10: - resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} - engines: {node: '>=6.14.2'} + stream-json@1.9.1: + resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==} - utf8-byte-length@1.0.5: - resolution: {integrity: sha512-Xn0w3MtiQ6zoz2vFyUVruaCL53O/DwUvkEeOvj+uulMm0BkUGYWmBYVyElqZaSLhY6ZD0ulfU3aBra2aVT4xfA==} + stream-shift@1.0.3: + resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + strict-uri-encode@2.0.0: + resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==} + engines: {node: '>=4'} - util@0.12.5: - resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} - utils-merge@1.0.1: - resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} - engines: {node: '>= 0.4.0'} + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} - uuid@10.0.0: - resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} - hasBin: true + string.prototype.includes@2.0.1: + resolution: {integrity: sha512-o7+c9bW6zpAdJHTtujeePODAhkuicdAryFsfVKwA+wGw89wJ4GTY484WTucM9hLtDEOpOvI+aHnzqnC5lHp4Rg==} + engines: {node: '>= 0.4'} - uuid@11.1.0: - resolution: {integrity: sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A==} - hasBin: true + string.prototype.matchall@4.0.12: + resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + engines: {node: '>= 0.4'} - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true + string.prototype.repeat@1.0.0: + resolution: {integrity: sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==} - uuid@9.0.1: - resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} - hasBin: true + string.prototype.trim@1.2.10: + resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + engines: {node: '>= 0.4'} - valid-url@1.0.9: - resolution: {integrity: sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==} + string.prototype.trimend@1.0.9: + resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + engines: {node: '>= 0.4'} - valtio@1.13.2: - resolution: {integrity: sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=16.8' - react: '>=16.8' - peerDependenciesMeta: - '@types/react': - optional: true - react: - optional: true + string.prototype.trimstart@1.0.8: + resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} + engines: {node: '>= 0.4'} - vary@1.1.2: - resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} - engines: {node: '>= 0.8'} + string_decoder@1.1.1: + resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} - verror@1.10.1: - resolution: {integrity: sha512-veufcmxri4e3XSrT0xwfUR7kguIkaxBeosDg00yDWhk49wdwkSUrvvsm7nc75e1PUyvIeZj6nS8VQRYz2/S4Xg==} - engines: {node: '>=0.6.0'} + string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - viem@2.23.2: - resolution: {integrity: sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} - viem@2.40.3: - resolution: {integrity: sha512-feYfEpbgjRkZYQpwcgxqkWzjxHI5LSDAjcGetHHwDRuX9BRQHUdV8ohrCosCYpdEhus/RknD3/bOd4qLYVPPuA==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true + strip-ansi@7.1.0: + resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} + engines: {node: '>=12'} - viem@2.43.5: - resolution: {integrity: sha512-QuJpuEMEPM3EreN+vX4mVY68Sci0+zDxozYfbh/WfV+SSy/Gthm74PH8XmitXdty1xY54uTCJ+/Gbbd1IiMPSA==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} - vite-node@3.2.4: - resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} - vite-tsconfig-paths@5.1.4: - resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==} - peerDependencies: - vite: '*' - peerDependenciesMeta: - vite: - optional: true + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} - vite@6.3.5: - resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - jiti: '>=1.21.0' - less: '*' - lightningcss: ^1.21.0 - sass: '*' - sass-embedded: '*' - stylus: '*' - sugarss: '*' - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true + strip-literal@3.0.0: + resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} - vite@7.1.3: - resolution: {integrity: sha512-OOUi5zjkDxYrKhTV3V7iKsoS37VUM7v40+HuwEmcrsf11Cdx9y3DIr2Px6liIcZFwt3XSRpQvFpL3WVy7ApkGw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true + styled-jsx@5.1.6: + resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} + engines: {node: '>= 12.0.0'} peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 + '@babel/core': '*' + babel-plugin-macros: '*' + react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: + '@babel/core': optional: true - yaml: + babel-plugin-macros: optional: true - vitest@3.2.4: - resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + sucrase@3.35.0: + resolution: {integrity: sha512-8EbVDiu9iN/nESwxeSxDKe0dunta1GOlHufmSSXxMD2z2/tMZpDMpvXQGsc+ajGo8y2uYUmixaSRUc/QPoQ0GA==} + engines: {node: '>=16 || 14 >=14.17'} hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.4 - '@vitest/ui': 3.2.4 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/debug': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} + superstruct@1.0.4: + resolution: {integrity: sha512-7JpaAoX2NGyoFlI9NBh66BQXGONc+uE+MRS5i2iOBKuS4e+ccgMDjATgZldkah+33DakBxDHiss9kvUcGAO8UQ==} + engines: {node: '>=14.0.0'} - wagmi@2.19.5: - resolution: {integrity: sha512-RQUfKMv6U+EcSNNGiPbdkDtJwtuFxZWLmvDiQmjjBgkuPulUwDJsKhi7gjynzJdsx2yDqhHCXkKsbbfbIsHfcQ==} - peerDependencies: - '@tanstack/react-query': '>=5.0.0' - react: '>=18' - typescript: '>=5.0.4' - viem: 2.x - peerDependenciesMeta: - typescript: - optional: true + superstruct@2.0.2: + resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} + engines: {node: '>=14.0.0'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} - wcwidth@1.0.1: - resolution: {integrity: sha512-XHPEwS0q6TaxcvG85+8EYkbiCux2XtWG2mkc47Ng2A77BQu9+DqIOJldST4HgPkuea7dvKSj5VgX3P1d4rW8Tg==} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} + supports-preserve-symlinks-flag@1.0.0: + resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} + engines: {node: '>= 0.4'} - web-streams-polyfill@4.0.0-beta.3: - resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} - engines: {node: '>= 14'} + symbol-tree@3.2.4: + resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - web-tree-sitter@0.24.7: - resolution: {integrity: sha512-CdC/TqVFbXqR+C51v38hv6wOPatKEUGxa39scAeFSm98wIhZxAYonhRQPSMmfZ2w7JDI0zQDdzdmgtNk06/krQ==} + synckit@0.11.11: + resolution: {integrity: sha512-MeQTA1r0litLUf0Rp/iisCaL8761lKAZHaimlbGK4j0HysC4PLfqygQj9srcs0m2RdtDYnF8UuYyKpbjHYp7Jw==} + engines: {node: ^14.18.0 || >=16.0.0} - webextension-polyfill@0.10.0: - resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==} + tabbable@6.3.0: + resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + tailwind-merge@3.4.0: + resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} - webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} + tailwindcss@4.1.17: + resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} - webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} + terser@5.46.2: + resolution: {integrity: sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==} + engines: {node: '>=10'} + hasBin: true - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} + text-encoding-utf-8@1.0.2: + resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} - whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} - whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + thread-stream@0.15.2: + resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==} - which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} - which-builtin-type@1.2.1: - resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} - engines: {node: '>= 0.4'} + thread-stream@4.0.0: + resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} + engines: {node: '>=20'} - which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} + throat@5.0.0: + resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} - which-module@2.0.1: - resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} - engines: {node: '>= 0.4'} + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.3: + resolution: {integrity: sha512-t2T/WLB2WRgZ9EpE4jgPJ9w+i66UZfDc8wHh0xrwiRNN+UwH98GIJkTeZqX9rg0i0ptwzqW+uYeIF0T4F8LR7A==} + engines: {node: '>=14.0.0'} + + tldts-core@6.1.86: + resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} + + tldts@6.1.86: + resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true - wif@2.0.6: - resolution: {integrity: sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==} + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - winston-transport@4.9.0: - resolution: {integrity: sha512-8drMJ4rkgaPo1Me4zD/3WLfI/zPdA9o2IipKODunnGDcuqbHwjsbB79ylv04LCGGzU0xQ6vTznOMpQGaLhhm6A==} - engines: {node: '>= 12.0.0'} + to-buffer@1.2.1: + resolution: {integrity: sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==} + engines: {node: '>= 0.4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toad-cache@3.7.0: + resolution: {integrity: sha512-/m8M+2BJUpoJdgAHoG+baCwBT+tf2VraSfkBgl0Y00qIWt41DJ8R5B8nsEw0I58YwF5IZH6z24/2TobDKnqSWw==} + engines: {node: '>=12'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + toml@3.0.0: + resolution: {integrity: sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==} + + tough-cookie@5.1.2: + resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} + engines: {node: '>=16'} - winston@3.17.0: - resolution: {integrity: sha512-DLiFIXYC5fMPxaRg832S6F5mJYvePtmO5G9v9IgUFPhXm9/GkXarH/TUrBAVzhTCzAj9anE/+GjrgXp/54nOgw==} - engines: {node: '>= 12.0.0'} + tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} + tr46@1.0.1: + resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - wrap-ansi@6.2.0: - resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} - engines: {node: '>=8'} + tr46@5.1.1: + resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} + engines: {node: '>=18'} - wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' - wrappy@1.0.2: - resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - ws@7.5.10: - resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} - engines: {node: '>=8.3.0'} + ts-node@10.9.2: + resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} + hasBin: true peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ^5.0.2 + '@swc/core': '>=1.2.50' + '@swc/wasm': '>=1.2.50' + '@types/node': '*' + typescript: '>=2.7' peerDependenciesMeta: - bufferutil: + '@swc/core': optional: true - utf-8-validate: + '@swc/wasm': optional: true - ws@8.17.1: - resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} - engines: {node: '>=10.0.0'} + tsconfck@3.1.6: + resolution: {integrity: sha512-ks6Vjr/jEw0P1gmOVwutM3B7fWxoWBL2KRDb1JfqGVawBmO5UsvmWOQFGHBPl5yxYz4eERr19E6L7NMv+Fej4w==} + engines: {node: ^18 || >=20} + hasBin: true peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' + typescript: ^5.0.0 peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: + typescript: optional: true - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true + tsconfig-paths@3.15.0: + resolution: {integrity: sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==} - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} - engines: {node: '>=10.0.0'} + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsup@8.5.0: + resolution: {integrity: sha512-VmBp77lWNQq6PfuMqCHD3xWl22vEoWsKajkF8t+yMBawlUS8JzEI+vOVMeuNZIuMML8qXRizFKi9oD5glKQVcQ==} + engines: {node: '>=18'} + hasBin: true peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' peerDependenciesMeta: - bufferutil: + '@microsoft/api-extractor': optional: true - utf-8-validate: + '@swc/core': optional: true - - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} - engines: {node: '>=10.0.0'} - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: '>=5.0.2' - peerDependenciesMeta: - bufferutil: + postcss: optional: true - utf-8-validate: + typescript: optional: true - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} - - xmlbuilder@15.1.1: - resolution: {integrity: sha512-yMqGBqtXyeN1e3TGYvgNgDVZ3j84W4cwkOXQswghol6APgZWaff9lnbvN7MHYJOiXsvGPXtjTYJEiC9J2wv9Eg==} - engines: {node: '>=8.0'} - - xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} + engines: {node: '>=18.0.0'} + hasBin: true - xmlhttprequest-ssl@2.1.2: - resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} - engines: {node: '>=0.4.0'} + turbo-darwin-64@2.5.6: + resolution: {integrity: sha512-3C1xEdo4aFwMJAPvtlPqz1Sw/+cddWIOmsalHFMrsqqydcptwBfu26WW2cDm3u93bUzMbBJ8k3zNKFqxJ9ei2A==} + cpu: [x64] + os: [darwin] - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} + turbo-darwin-arm64@2.5.6: + resolution: {integrity: sha512-LyiG+rD7JhMfYwLqB6k3LZQtYn8CQQUePbpA8mF/hMLPAekXdJo1g0bUPw8RZLwQXUIU/3BU7tXENvhSGz5DPA==} + cpu: [arm64] + os: [darwin] - y18n@4.0.3: - resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + turbo-linux-64@2.5.6: + resolution: {integrity: sha512-GOcUTT0xiT/pSnHL4YD6Yr3HreUhU8pUcGqcI2ksIF9b2/r/kRHwGFcsHgpG3+vtZF/kwsP0MV8FTlTObxsYIA==} + cpu: [x64] + os: [linux] - y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} + turbo-linux-arm64@2.5.6: + resolution: {integrity: sha512-10Tm15bruJEA3m0V7iZcnQBpObGBcOgUcO+sY7/2vk1bweW34LMhkWi8svjV9iDF68+KJDThnYDlYE/bc7/zzQ==} + cpu: [arm64] + os: [linux] - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + turbo-windows-64@2.5.6: + resolution: {integrity: sha512-FyRsVpgaj76It0ludwZsNN40ytHN+17E4PFJyeliBEbxrGTc5BexlXVpufB7XlAaoaZVxbS6KT8RofLfDRyEPg==} + cpu: [x64] + os: [win32] - yallist@4.0.0: - resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + turbo-windows-arm64@2.5.6: + resolution: {integrity: sha512-j/tWu8cMeQ7HPpKri6jvKtyXg9K1gRyhdK4tKrrchH8GNHscPX/F71zax58yYtLRWTiK04zNzPcUJuoS0+v/+Q==} + cpu: [arm64] + os: [win32] - yaml@2.8.1: - resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} - engines: {node: '>= 14.6'} + turbo@2.5.6: + resolution: {integrity: sha512-gxToHmi9oTBNB05UjUsrWf0OyN5ZXtD0apOarC1KIx232Vp3WimRNy3810QzeNSgyD5rsaIDXlxlbnOzlouo+w==} hasBin: true - yargs-parser@18.1.3: - resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} - engines: {node: '>=6'} + tweetnacl-ts@1.0.3: + resolution: {integrity: sha512-C5I/dWf6xjAXaCDlf84T4HvozU/8ycAlq5WRllF1hAeeq5390tfXD+bNas5bhEV0HMSOx8bsQYpLjPl8wfnEeQ==} - yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} + tweetnacl@1.0.3: + resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} - yargs@15.4.1: - resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} engines: {node: '>=8'} - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} + type-is@1.6.18: + resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} + engines: {node: '>= 0.6'} - yauzl@2.10.0: - resolution: {integrity: sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==} + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} + typed-array-buffer@1.0.3: + resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} + engines: {node: '>= 0.4'} - zod-to-json-schema@3.24.6: - resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} - peerDependencies: - zod: ^3.24.1 + typed-array-byte-length@1.0.3: + resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} + engines: {node: '>= 0.4'} - zod-validation-error@4.0.2: - resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} - engines: {node: '>=18.0.0'} + typed-array-byte-offset@1.0.4: + resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + engines: {node: '>= 0.4'} + + typed-array-length@1.0.7: + resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + engines: {node: '>= 0.4'} + + typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + + typescript-eslint@8.48.0: + resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - zod: ^3.25.0 || ^4.0.0 + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' - zod@3.22.4: - resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} + typescript@5.9.2: + resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} + engines: {node: '>=14.17'} + hasBin: true - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true - zod@4.1.13: - resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} - zustand@5.0.0: - resolution: {integrity: sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==} - engines: {node: '>=12.20.0'} + uint8arrays@3.1.0: + resolution: {integrity: sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==} + + uint8arrays@3.1.1: + resolution: {integrity: sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==} + + unbox-primitive@1.1.0: + resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} + engines: {node: '>= 0.4'} + + uncrypto@0.1.3: + resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} + + undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + undici-types@7.22.0: + resolution: {integrity: sha512-RKZvifiL60xdsIuC80UY0dq8Z7DbJUV8/l2hOVbyZAxBzEeQU4Z58+4ZzJ6WN2Lidi9KzT5EbiGX+PI/UGYuRw==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unrs-resolver@1.11.1: + resolution: {integrity: sha512-bSjt9pjaEBnNiGgc9rUiHGKv5l4/TGzDmYw3RhnkJGtLhbnnA/5qJj7x3dNDCRx/PJxu774LlH8lCOlB4hEfKg==} + + unstorage@1.16.1: + resolution: {integrity: sha512-gdpZ3guLDhz+zWIlYP1UwQ259tG5T5vYRzDaHMkQ1bBY1SQPutvZnrRjTFaWUUpseErJIgAZS51h6NOcZVZiqQ==} peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' + '@azure/app-configuration': ^1.8.0 + '@azure/cosmos': ^4.2.0 + '@azure/data-tables': ^13.3.0 + '@azure/identity': ^4.6.0 + '@azure/keyvault-secrets': ^4.9.0 + '@azure/storage-blob': ^12.26.0 + '@capacitor/preferences': ^6.0.3 || ^7.0.0 + '@deno/kv': '>=0.9.0' + '@netlify/blobs': ^6.5.0 || ^7.0.0 || ^8.1.0 || ^9.0.0 || ^10.0.0 + '@planetscale/database': ^1.19.0 + '@upstash/redis': ^1.34.3 + '@vercel/blob': '>=0.27.1' + '@vercel/kv': ^1.0.1 + aws4fetch: ^1.0.20 + db0: '>=0.2.1' + idb-keyval: ^6.2.1 + ioredis: ^5.4.2 + uploadthing: ^7.4.4 peerDependenciesMeta: - '@types/react': + '@azure/app-configuration': optional: true - immer: + '@azure/cosmos': optional: true - react: + '@azure/data-tables': optional: true - use-sync-external-store: + '@azure/identity': optional: true - - zustand@5.0.3: - resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': + '@azure/keyvault-secrets': optional: true - immer: + '@azure/storage-blob': optional: true - react: + '@capacitor/preferences': optional: true - use-sync-external-store: + '@deno/kv': optional: true - - zustand@5.0.8: - resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': + '@netlify/blobs': optional: true - immer: + '@planetscale/database': optional: true - react: + '@upstash/redis': optional: true - use-sync-external-store: + '@vercel/blob': + optional: true + '@vercel/kv': + optional: true + aws4fetch: + optional: true + db0: + optional: true + idb-keyval: + optional: true + ioredis: + optional: true + uploadthing: optional: true -snapshots: + update-browserslist-db@1.1.3: + resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' - 7zip-bin@5.2.0: {} + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - '@across-protocol/app-sdk@0.2.3(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': - dependencies: - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + urijs@1.19.11: + resolution: {integrity: sha512-HXgFDgDommxn5/bIv0cnQZsPhHDA90NPHD6+c/v21U5+Sx5hoP8+dP9IZXBU1gIfvdRfhG8cel9QNPeionfcCQ==} - '@adraffy/ens-normalize@1.10.1': {} + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@adraffy/ens-normalize@1.11.0': {} + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true - '@alloc/quick-lru@5.2.0': {} + use-sync-external-store@1.2.0: + resolution: {integrity: sha512-eEgnFxGQ1Ife9bzYs6VLi8/4X6CObHMw9Qr9tPY43iKwsPw8xE8+EFsf/2cFZ5S3esXgpWgtSCtLNS41F+sKPA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 - '@alloralabs/allora-sdk@0.1.1': - dependencies: - '@types/node': 22.17.2 - typescript: 5.9.2 + use-sync-external-store@1.4.0: + resolution: {integrity: sha512-9WXSPC5fMv61vaupRkCKCxsPxBocVnwakBEkMIHHpkTTg6icbJtg6jzgtLDm4bl3cSHAca52rYWih0k4K3PfHw==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@ampproject/remapping@2.3.0': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 + usehooks-ts@3.1.1: + resolution: {integrity: sha512-I4diPp9Cq6ieSUH2wu+fDAVQO43xwtulo+fKEidHUwZPnYImbtkTjzIJYcDcJqxgmX31GVqNFURodvcgHcW0pA==} + engines: {node: '>=16.15.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 || ^19.0.0-rc - '@anthropic-ai/sdk@0.39.0(encoding@0.1.13)': - dependencies: - '@types/node': 18.19.123 - '@types/node-fetch': 2.6.13 - abort-controller: 3.0.0 - agentkeepalive: 4.6.0 - form-data-encoder: 1.7.2 - formdata-node: 4.4.1 - node-fetch: 2.7.0(encoding@0.1.13) - transitivePeerDependencies: - - encoding + utf-8-validate@5.0.10: + resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} + engines: {node: '>=6.14.2'} - '@anthropic-ai/sdk@0.58.0': {} + utf8@3.0.0: + resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} - '@aptos-labs/aptos-cli@1.1.1': - dependencies: - commander: 12.1.0 + util-deprecate@1.0.2: + resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - '@aptos-labs/aptos-client@2.1.0(got@11.8.6)': - dependencies: - got: 11.8.6 + util@0.12.5: + resolution: {integrity: sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==} - '@aptos-labs/ts-sdk@5.2.1(got@11.8.6)': - dependencies: - '@aptos-labs/aptos-cli': 1.1.1 - '@aptos-labs/aptos-client': 2.1.0(got@11.8.6) - '@noble/curves': 1.9.7 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - eventemitter3: 5.0.1 - js-base64: 3.7.8 - jwt-decode: 4.0.0 - poseidon-lite: 0.2.1 - transitivePeerDependencies: - - got + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} - '@asamuzakjp/css-color@3.2.0': - dependencies: - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - lru-cache: 10.4.3 + uuid@8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true - '@aws-crypto/sha256-js@5.2.0': - dependencies: - '@aws-crypto/util': 5.2.0 - '@aws-sdk/types': 3.862.0 - tslib: 2.8.1 + uuid@9.0.1: + resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} + hasBin: true - '@aws-crypto/util@5.2.0': - dependencies: - '@aws-sdk/types': 3.862.0 - '@smithy/util-utf8': 2.3.0 - tslib: 2.8.1 + v8-compile-cache-lib@3.0.1: + resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} - '@aws-sdk/types@3.862.0': - dependencies: - '@smithy/types': 4.3.2 - tslib: 2.8.1 + valtio@1.13.2: + resolution: {integrity: sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=16.8' + react: '>=16.8' + peerDependenciesMeta: + '@types/react': + optional: true + react: + optional: true - '@babel/code-frame@7.27.1': - dependencies: - '@babel/helper-validator-identifier': 7.27.1 - js-tokens: 4.0.0 - picocolors: 1.1.1 + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} - '@babel/compat-data@7.28.0': {} + viem@2.23.2: + resolution: {integrity: sha512-NVmW/E0c5crMOtbEAqMF0e3NmvQykFXhLOc/CkLIXOlzHSA6KXVz3CYVmaKqBF8/xtjsjHAGjdJN3Ru1kFJLaA==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true - '@babel/core@7.28.3': - dependencies: - '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) - '@babel/helpers': 7.28.3 - '@babel/parser': 7.28.3 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - convert-source-map: 2.0.0 - debug: 4.4.1 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color + viem@2.48.11: + resolution: {integrity: sha512-+WZ5E0dBS6GtKb+1wEk5DeYRRRW42+pFnXCo67Ydodf42sBwO+hu3wnQy66lc4MKmHz+llPVdbyehYr9oTE2iw==} + peerDependencies: + typescript: '>=5.0.4' + peerDependenciesMeta: + typescript: + optional: true - '@babel/generator@7.28.3': - dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.30 - jsesc: 3.1.0 + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true - '@babel/helper-annotate-as-pure@7.27.3': - dependencies: - '@babel/types': 7.28.2 + vite-tsconfig-paths@5.1.4: + resolution: {integrity: sha512-cYj0LRuLV2c2sMqhqhGpaO3LretdtMn/BVX4cPLanIZuwwrkVl+lK84E/miEXkCHWXuq65rhNN4rXsBcOB3S4w==} + peerDependencies: + vite: '*' + peerDependenciesMeta: + vite: + optional: true - '@babel/helper-compilation-targets@7.27.2': - dependencies: - '@babel/compat-data': 7.28.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.25.3 - lru-cache: 5.1.1 - semver: 6.3.1 + vite@6.3.5: + resolution: {integrity: sha512-cZn6NDFE7wdTpINgs++ZJ4N49W2vRp8LCKrn3Ob1kYNtOo21vfDoaV5GzBfLU4MovSAB8uNRm4jgzVQZ+mBzPQ==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + jiti: '>=1.21.0' + less: '*' + lightningcss: ^1.21.0 + sass: '*' + sass-embedded: '*' + stylus: '*' + sugarss: '*' + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color + vitest@3.2.4: + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true - '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - regexpu-core: 6.2.0 - semver: 6.3.1 + vlq@1.0.1: + resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} - '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - debug: 4.4.1 - lodash.debounce: 4.0.8 - resolve: 1.22.10 - transitivePeerDependencies: - - supports-color + vlq@2.0.4: + resolution: {integrity: sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==} - '@babel/helper-globals@7.28.0': {} + w3c-xmlserializer@5.0.0: + resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} + engines: {node: '>=18'} - '@babel/helper-member-expression-to-functions@7.27.1': - dependencies: - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - transitivePeerDependencies: - - supports-color + wagmi@2.19.5: + resolution: {integrity: sha512-RQUfKMv6U+EcSNNGiPbdkDtJwtuFxZWLmvDiQmjjBgkuPulUwDJsKhi7gjynzJdsx2yDqhHCXkKsbbfbIsHfcQ==} + peerDependencies: + '@tanstack/react-query': '>=5.0.0' + react: '>=18' + typescript: '>=5.0.4' + viem: 2.x + peerDependenciesMeta: + typescript: + optional: true - '@babel/helper-module-imports@7.27.1': - dependencies: - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - transitivePeerDependencies: - - supports-color + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + web-streams-polyfill@4.0.0-beta.3: + resolution: {integrity: sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==} + engines: {node: '>= 14'} - '@babel/helper-optimise-call-expression@7.27.1': - dependencies: - '@babel/types': 7.28.2 + webextension-polyfill@0.10.0: + resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==} - '@babel/helper-plugin-utils@7.27.1': {} + webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + webidl-conversions@4.0.2: + resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-member-expression-to-functions': 7.27.1 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + webidl-conversions@7.0.0: + resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} + engines: {node: '>=12'} - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - dependencies: - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - transitivePeerDependencies: - - supports-color + whatwg-encoding@3.1.1: + resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} + engines: {node: '>=18'} - '@babel/helper-string-parser@7.27.1': {} + whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} - '@babel/helper-validator-identifier@7.27.1': {} + whatwg-mimetype@4.0.0: + resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} + engines: {node: '>=18'} - '@babel/helper-validator-option@7.27.1': {} + whatwg-url@14.2.0: + resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} + engines: {node: '>=18'} - '@babel/helper-wrap-function@7.28.3': - dependencies: - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.3 - '@babel/types': 7.28.2 - transitivePeerDependencies: - - supports-color + whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - '@babel/helpers@7.28.3': - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.2 + whatwg-url@7.1.0: + resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} - '@babel/parser@7.28.3': - dependencies: - '@babel/types': 7.28.2 + which-boxed-primitive@1.1.1: + resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} + engines: {node: '>= 0.4'} - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + which-builtin-type@1.2.1: + resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} + engines: {node: '>= 0.4'} - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + which-collection@1.0.2: + resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} + engines: {node: '>= 0.4'} - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color + which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + engines: {node: '>= 0.4'} - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true - '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + ws@7.5.10: + resolution: {integrity: sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true - '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.3) - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + ws@7.5.3: + resolution: {integrity: sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true - '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color + ws@8.17.1: + resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true - '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true - '@babel/plugin-transform-block-scoping@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + ws@8.18.3: + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true - '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + ws@8.19.0: + resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true - '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + xml-name-validator@5.0.0: + resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} + engines: {node: '>=18'} - '@babel/plugin-transform-classes@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-globals': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + xmlchars@2.2.0: + resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/template': 7.27.2 + xmlhttprequest-ssl@2.1.2: + resolution: {integrity: sha512-TEU+nJVUUnA4CYJFLvK5X9AOeH4KvDvhIfm0vV1GaQRtchnG0hgK5p8hw/xjv8cunWYCsiPCSDzObPyhEwq3KQ==} + engines: {node: '>=0.4.0'} - '@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + xtend@4.0.2: + resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} + engines: {node: '>=0.4'} - '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} - '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + yaml@2.8.1: + resolution: {integrity: sha512-lcYcMxX2PO9XMGvAJkJ3OsNMw+/7FKes7/hgerGUYWIoWu5j/+YQqcZr5JnPZWzOsEBgMbSbiSTn/dv/69Mkpw==} + engines: {node: '>= 14.6'} + hasBin: true - '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} - '@babel/plugin-transform-exponentiation-operator@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + yn@3.1.1: + resolution: {integrity: sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==} + engines: {node: '>=6'} - '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + zod-to-json-schema@3.24.6: + resolution: {integrity: sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg==} + peerDependencies: + zod: ^3.24.1 - '@babel/plugin-transform-logical-assignment-operators@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 - '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + zod@3.22.4: + resolution: {integrity: sha512-iC+8Io04lddc+mVqQ9AZ7OQ2MrUKGN+oIQyq1vemgt46jwCwLfhq7/pwnBnNXXXZb8VTVLKwp9EDkx+ryxIWmg==} - '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + zod@3.25.76: + resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + zod@4.1.13: + resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} - '@babel/plugin-transform-modules-systemjs@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + zustand@5.0.0: + resolution: {integrity: sha512-LE+VcmbartOPM+auOjCCLQOsQ05zUTp8RkgwRzefUk+2jISdMMFnxvyTjA4YNWr5ZGXYbVsEMZosttuxUBkojQ==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true - '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + zustand@5.0.3: + resolution: {integrity: sha512-14fwWQtU3pH4dE0dOpdMiWjddcH+QzKIgk1cl8epwSE7yag43k/AD/m4L6+K7DytAOr9gGBe3/EXj9g7cdostg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + zustand@5.0.8: + resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true - '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 +snapshots: - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@adraffy/ens-normalize@1.11.0': {} - '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.3)': + '@algorandfoundation/algokit-utils@10.0.0-alpha.46': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@algorandfoundation/xhd-wallet-api': 2.0.0-canary.1 + '@noble/curves': 2.2.0 + '@noble/ed25519': 3.1.0 + '@noble/hashes': 2.2.0 + algorand-msgpack: 1.1.0 + buffer: 6.0.3 + dotenv: 16.6.1 + hi-base32: 0.5.1 + json-bigint: 1.0.0 + tweetnacl: 1.0.3 + vlq: 2.0.4 - '@babel/plugin-transform-object-rest-spread@7.28.0(@babel/core@7.28.3)': + '@algorandfoundation/xhd-wallet-api@2.0.0-canary.1': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.3) - '@babel/traverse': 7.28.3 - transitivePeerDependencies: - - supports-color + '@noble/ciphers': 2.2.0 + '@noble/curves': 2.2.0 + '@noble/hashes': 2.2.0 + ajv: 8.17.1 + algo-msgpack-with-bigint: 2.1.1 + bn.js: 5.2.2 - '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color + '@alloc/quick-lru@5.2.0': {} - '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.3)': + '@ampproject/remapping@2.3.0': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 - '@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.28.3)': + '@aptos-labs/aptos-cli@1.1.1': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - transitivePeerDependencies: - - supports-color + commander: 12.1.0 - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.3)': + '@aptos-labs/aptos-client@2.1.0(got@11.8.6)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + got: 11.8.6 - '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.3)': + '@aptos-labs/ts-sdk@5.2.1(got@11.8.6)': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@aptos-labs/aptos-cli': 1.1.1 + '@aptos-labs/aptos-client': 2.1.0(got@11.8.6) + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + eventemitter3: 5.0.1 + js-base64: 3.7.8 + jwt-decode: 4.0.0 + poseidon-lite: 0.2.1 transitivePeerDependencies: - - supports-color + - got - '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.3)': + '@asamuzakjp/css-color@3.2.0': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - transitivePeerDependencies: - - supports-color + '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-color-parser': 3.0.10(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) + '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) + '@csstools/css-tokenizer': 3.0.4 + lru-cache: 10.4.3 - '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@aws-cdk/asset-awscli-v1@2.2.273': {} - '@babel/plugin-transform-react-constant-elements@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@aws-cdk/asset-node-proxy-agent-v6@2.1.1': {} - '@babel/plugin-transform-react-display-name@7.28.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@aws-cdk/cloud-assembly-schema@53.20.0': {} - '@babel/plugin-transform-react-jsx-development@7.27.1(@babel/core@7.28.3)': + '@babel/code-frame@7.27.1': dependencies: - '@babel/core': 7.28.3 - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color + '@babel/helper-validator-identifier': 7.27.1 + js-tokens: 4.0.0 + picocolors: 1.1.1 - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.3)': + '@babel/code-frame@7.29.0': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/compat-data@7.28.0': {} - '@babel/plugin-transform-react-jsx@7.27.1(@babel/core@7.28.3)': + '@babel/core@7.28.3': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.3) + '@ampproject/remapping': 2.3.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.3) + '@babel/helpers': 7.28.3 + '@babel/parser': 7.28.3 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.3 '@babel/types': 7.28.2 + convert-source-map: 2.0.0 + debug: 4.4.1 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-react-pure-annotations@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-regenerator@7.28.3(@babel/core@7.28.3)': + '@babel/generator@7.28.3': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/parser': 7.28.3 + '@babel/types': 7.28.2 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + jsesc: 3.1.0 - '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.3)': + '@babel/generator@7.29.1': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + jsesc: 3.1.0 - '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.3)': + '@babel/helper-compilation-targets@7.27.2': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/compat-data': 7.28.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.3 + lru-cache: 5.1.1 + semver: 6.3.1 - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-globals@7.28.0': {} - '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.3)': + '@babel/helper-module-imports@7.27.1': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.28.3 + '@babel/types': 7.28.2 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-typescript@7.28.0(@babel/core@7.28.3)': + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.3) + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.3 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-string-parser@7.27.1': {} - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier@7.27.1': {} - '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.3) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier@7.28.5': {} - '@babel/preset-env@7.28.3(@babel/core@7.28.3)': - dependencies: - '@babel/compat-data': 7.28.0 - '@babel/core': 7.28.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.3) - '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.3) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-block-scoping': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-transform-classes': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-exponentiation-operator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-logical-assignment-operators': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-systemjs': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-object-rest-spread': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.3) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-regenerator': 7.28.3(@babel/core@7.28.3) - '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.3) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.3) - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.3) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.3) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.3) - core-js-compat: 3.45.1 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color + '@babel/helper-validator-option@7.27.1': {} - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.3)': + '@babel/helpers@7.28.3': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/template': 7.27.2 '@babel/types': 7.28.2 - esutils: 2.0.3 - '@babel/preset-react@7.27.1(@babel/core@7.28.3)': + '@babel/parser@7.28.3': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-transform-react-display-name': 7.28.0(@babel/core@7.28.3) - '@babel/plugin-transform-react-jsx': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-react-jsx-development': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-react-pure-annotations': 7.27.1(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color + '@babel/types': 7.28.2 - '@babel/preset-typescript@7.27.1(@babel/core@7.28.3)': + '@babel/parser@7.29.2': dependencies: - '@babel/core': 7.28.3 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color + '@babel/types': 7.29.0 '@babel/runtime@7.28.3': {} @@ -14784,6 +11075,12 @@ snapshots: '@babel/parser': 7.28.3 '@babel/types': 7.28.2 + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@babel/traverse@7.28.3': dependencies: '@babel/code-frame': 7.27.1 @@ -14796,137 +11093,59 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + '@babel/types@7.28.2': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 - '@base-org/account@1.1.1(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) - preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.3(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - - '@base-org/account@1.1.1(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + '@babel/types@7.29.0': dependencies: - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) - preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.3(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.5.0(react@19.2.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 - '@base-org/account@2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)': + '@base-org/account@1.1.1(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@coinbase/cdp-sdk': 1.39.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@noble/hashes': 1.4.0 clsx: 1.2.1 eventemitter3: 5.0.1 idb-keyval: 6.2.1 ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zustand: 5.0.3(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.4.0(react@19.1.1)) transitivePeerDependencies: - '@types/react' - - bufferutil - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - ws - - zod - - '@base-org/account@2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)': - dependencies: - '@coinbase/cdp-sdk': 1.39.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) - preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.3(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - debug - - encoding - - fastestsmallesttextencoderdecoder - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - ws - - zod - - '@base-org/account@2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)': - dependencies: - '@coinbase/cdp-sdk': 1.39.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.2)(zod@4.1.13) - preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - zustand: 5.0.3(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - debug - - encoding - - fastestsmallesttextencoderdecoder + - bufferutil - immer - react - typescript - use-sync-external-store - utf-8-validate - - ws - zod - '@base-org/account@2.4.0(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)': + '@base-org/account@2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)': dependencies: - '@coinbase/cdp-sdk': 1.39.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@coinbase/cdp-sdk': 1.39.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@noble/hashes': 1.4.0 clsx: 1.2.1 eventemitter3: 5.0.1 idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.2)(zod@4.1.13) + ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - zustand: 5.0.3(@types/react@19.2.1)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.4.0(react@19.1.1)) transitivePeerDependencies: - '@types/react' - bufferutil @@ -14941,121 +11160,57 @@ snapshots: - ws - zod - '@cfworker/json-schema@4.1.1': {} - - '@coinbase/agentkit-langchain@0.3.0(@coinbase/agentkit@0.5.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10))(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76))': + '@base-org/account@2.4.0(@types/react@19.2.1)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)': dependencies: - '@coinbase/agentkit': 0.5.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@langchain/core': 0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - zod: 3.25.76 - transitivePeerDependencies: - - '@opentelemetry/api' - - '@opentelemetry/exporter-trace-otlp-proto' - - '@opentelemetry/sdk-trace-base' - - openai - - '@coinbase/agentkit@0.5.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)': - dependencies: - '@across-protocol/app-sdk': 0.2.3(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@alloralabs/allora-sdk': 0.1.1 - '@coinbase/coinbase-sdk': 0.20.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@jup-ag/api': 6.0.44 - '@privy-io/server-auth': 1.31.1(bufferutil@4.0.9)(encoding@0.1.13)(ethers@6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@solana/spl-token': 0.4.13(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - bs58: 4.0.1 - canonicalize: 2.1.0 - decimal.js: 10.6.0 - ethers: 6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - md5: 2.3.0 - opensea-js: 7.2.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - reflect-metadata: 0.2.2 - twitter-api-v2: 1.25.0 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zod: 3.25.76 + '@coinbase/cdp-sdk': 1.39.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.9.3)(zod@4.1.13) + preact: 10.24.2 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + zustand: 5.0.3(@types/react@19.2.1)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) transitivePeerDependencies: + - '@types/react' - bufferutil - debug - encoding - fastestsmallesttextencoderdecoder - - typescript - - utf-8-validate - - '@coinbase/cdp-api-client@0.0.18': - dependencies: - axios: 1.13.2 - transitivePeerDependencies: - - debug - - '@coinbase/cdp-core@0.0.18(@types/react@19.2.1)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@coinbase/cdp-api-client': 0.0.18 - jose: 6.0.12 - ox: 0.8.1(typescript@5.9.2)(zod@3.25.76) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.8(@types/react@19.2.1)(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - debug - immer - react - typescript - use-sync-external-store - utf-8-validate + - ws - zod - '@coinbase/cdp-hooks@0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.2.1)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(react@18.3.1)': - dependencies: - '@coinbase/cdp-core': 0.0.18(@types/react@19.2.1)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) - react: 18.3.1 - - '@coinbase/cdp-react@0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.2.1)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(@coinbase/cdp-hooks@0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.2.1)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(react@18.3.1))(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@coinbase/cdp-core': 0.0.18(@types/react@19.2.1)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@coinbase/cdp-hooks': 0.0.18(@coinbase/cdp-core@0.0.18(@types/react@19.2.1)(bufferutil@4.0.9)(react@18.3.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@18.3.1))(utf-8-validate@5.0.10)(zod@3.25.76))(react@18.3.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-form': 0.1.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-one-time-password-field': 0.1.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - - react-dom - - '@coinbase/cdp-sdk@1.36.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)': + '@blockshake/defly-connect@1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: - '@solana/spl-token': 0.4.13(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - abitype: 1.0.6(typescript@5.9.2)(zod@3.25.76) - axios: 1.13.2 - axios-retry: 4.5.0(axios@1.13.2) - jose: 6.0.12 - md5: 2.3.0 - uncrypto: 0.1.3 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zod: 3.25.76 + '@likecoin/qr-code-styling': 1.6.6 + '@walletconnect/client': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/types': 1.8.0 + algosdk: 3.5.2 + bowser: 2.11.0 + buffer: 6.0.3 + lottie-web: 5.13.0 transitivePeerDependencies: - bufferutil - - debug - - encoding - - fastestsmallesttextencoderdecoder - - typescript - utf-8-validate - '@coinbase/cdp-sdk@1.39.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@coinbase/cdp-sdk@1.39.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: - '@solana-program/system': 0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token': 0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) + '@solana-program/system': 0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token': 0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) abitype: 1.0.6(typescript@5.9.2)(zod@3.25.76) axios: 1.13.4 axios-retry: 4.5.0(axios@1.13.4) jose: 6.0.12 md5: 2.3.0 uncrypto: 0.1.3 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zod: 3.25.76 transitivePeerDependencies: - bufferutil @@ -15066,19 +11221,19 @@ snapshots: - utf-8-validate - ws - '@coinbase/cdp-sdk@1.39.0(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@coinbase/cdp-sdk@1.39.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: - '@solana-program/system': 0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana-program/token': 0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) - '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - abitype: 1.0.6(typescript@5.9.2)(zod@3.25.76) + '@solana-program/system': 0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana-program/token': 0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + abitype: 1.0.6(typescript@5.9.3)(zod@3.25.76) axios: 1.13.4 axios-retry: 4.5.0(axios@1.13.4) jose: 6.0.12 md5: 2.3.0 uncrypto: 0.1.3 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76) zod: 3.25.76 transitivePeerDependencies: - bufferutil @@ -15089,191 +11244,10 @@ snapshots: - utf-8-validate - ws - '@coinbase/coinbase-sdk@0.20.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@scure/bip32': 1.7.0 - abitype: 1.2.3(typescript@5.9.2)(zod@3.25.76) - axios: 1.13.2 - axios-mock-adapter: 1.22.0(axios@1.13.2) - axios-retry: 4.5.0(axios@1.13.2) - bip32: 4.0.0 - bip39: 3.1.0 - decimal.js: 10.6.0 - dotenv: 16.6.1 - ed2curve: 0.3.0 - ethers: 6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - jose: 5.10.0 - secp256k1: 5.0.1 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - bufferutil - - debug - - typescript - - utf-8-validate - - zod - - '@coinbase/onchainkit@0.38.14(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)': - dependencies: - '@farcaster/frame-sdk': 0.0.60(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@farcaster/frame-wagmi-connector': 0.0.42(@farcaster/frame-sdk@0.0.60(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@tanstack/react-query': 5.90.11(react@19.2.3) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - clsx: 2.1.1 - graphql: 16.11.0 - graphql-request: 6.1.0(encoding@0.1.13)(graphql@16.11.0) - qrcode: 1.5.4 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - tailwind-merge: 2.6.0 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react-native - - supports-color - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - ws - - zod - - '@coinbase/onchainkit@0.38.19(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)': - dependencies: - '@farcaster/frame-sdk': 0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@farcaster/miniapp-wagmi-connector': 1.0.0(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@tanstack/react-query': 5.90.11(react@19.2.1) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - clsx: 2.1.1 - graphql: 16.11.0 - graphql-request: 6.1.0(encoding@0.1.13)(graphql@16.11.0) - qrcode: 1.5.4 - react: 19.2.1 - react-dom: 19.2.1(react@19.2.1) - tailwind-merge: 2.6.0 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@farcaster/miniapp-sdk' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react-native - - supports-color - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - ws - - zod - - '@coinbase/onchainkit@0.38.19(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)': - dependencies: - '@farcaster/frame-sdk': 0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@farcaster/miniapp-wagmi-connector': 1.0.0(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@tanstack/react-query': 5.90.11(react@19.2.3) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - clsx: 2.1.1 - graphql: 16.11.0 - graphql-request: 6.1.0(encoding@0.1.13)(graphql@16.11.0) - qrcode: 1.5.4 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - tailwind-merge: 2.6.0 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@farcaster/miniapp-sdk' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react-native - - supports-color - - typescript - - uploadthing - - use-sync-external-store - - utf-8-validate - - ws - - zod - - '@coinbase/onchainkit@1.1.2(@tanstack/query-core@5.90.11)(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13))(zod@4.1.13)': + '@coinbase/onchainkit@1.1.2(@tanstack/query-core@5.90.11)(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(bufferutil@4.0.9)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13))(zod@4.1.13)': dependencies: - '@farcaster/miniapp-sdk': 0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@farcaster/miniapp-wagmi-connector': 1.0.0(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) + '@farcaster/miniapp-sdk': 0.1.9(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@farcaster/miniapp-wagmi-connector': 1.0.0(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)) '@floating-ui/react': 0.27.16(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) @@ -15281,104 +11255,44 @@ snapshots: '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-toast': 1.2.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@tanstack/react-query': 5.90.11(react@19.2.3) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)) clsx: 2.1.1 graphql: 16.11.0 - graphql-request: 6.1.0(encoding@0.1.13)(graphql@16.11.0) + graphql-request: 6.1.0(graphql@16.11.0) qrcode: 1.5.4 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - tailwind-merge: 3.4.0 - usehooks-ts: 3.1.1(react@19.2.3) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - transitivePeerDependencies: - - '@tanstack/query-core' - - '@types/react' - - '@types/react-dom' - - bufferutil - - encoding - - immer - - typescript - - use-sync-external-store - - utf-8-validate - - zod - - '@coinbase/wallet-sdk@3.9.3': - dependencies: - bn.js: 5.2.2 - buffer: 6.0.3 - clsx: 1.2.1 - eth-block-tracker: 7.1.0 - eth-json-rpc-filters: 6.0.1 - eventemitter3: 5.0.1 - keccak: 3.0.4 - preact: 10.27.1 - sha.js: 2.4.12 - transitivePeerDependencies: - - supports-color - - '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) - preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.3(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.4.0(react@19.1.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - - '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) - preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.3(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + tailwind-merge: 3.4.0 + usehooks-ts: 3.1.1(react@19.2.3) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) transitivePeerDependencies: + - '@tanstack/query-core' - '@types/react' + - '@types/react-dom' - bufferutil + - encoding - immer - - react - typescript - use-sync-external-store - utf-8-validate - zod - '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + '@coinbase/wallet-sdk@3.9.3': dependencies: - '@noble/hashes': 1.4.0 + bn.js: 5.2.2 + buffer: 6.0.3 clsx: 1.2.1 + eth-block-tracker: 7.1.0 + eth-json-rpc-filters: 6.0.1 eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) - preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.3(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) + keccak: 3.0.4 + preact: 10.27.1 + sha.js: 2.4.12 transitivePeerDependencies: - - '@types/react' - - bufferutil - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod + - supports-color - '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@noble/hashes': 1.4.0 clsx: 1.2.1 @@ -15386,28 +11300,8 @@ snapshots: idb-keyval: 6.2.1 ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.3(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.5.0(react@19.2.1)) - transitivePeerDependencies: - - '@types/react' - - bufferutil - - immer - - react - - typescript - - use-sync-external-store - - utf-8-validate - - zod - - '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.1.13)': - dependencies: - '@noble/hashes': 1.4.0 - clsx: 1.2.1 - eventemitter3: 5.0.1 - idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.2)(zod@4.1.13) - preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - zustand: 5.0.3(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.4.0(react@19.1.1)) transitivePeerDependencies: - '@types/react' - bufferutil @@ -15418,15 +11312,15 @@ snapshots: - utf-8-validate - zod - '@coinbase/wallet-sdk@4.3.6(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.1.13)': + '@coinbase/wallet-sdk@4.3.6(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@noble/hashes': 1.4.0 clsx: 1.2.1 eventemitter3: 5.0.1 idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.2)(zod@4.1.13) + ox: 0.6.9(typescript@5.9.3)(zod@4.1.13) preact: 10.24.2 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) zustand: 5.0.3(@types/react@19.2.1)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) transitivePeerDependencies: - '@types/react' @@ -15438,11 +11332,9 @@ snapshots: - utf-8-validate - zod - '@colors/colors@1.6.0': {} - - '@craftamap/esbuild-plugin-html@0.9.0(bufferutil@4.0.9)(esbuild@0.25.9)(utf-8-validate@5.0.10)': + '@craftamap/esbuild-plugin-html@0.9.0(bufferutil@4.0.9)(esbuild@0.27.7)(utf-8-validate@5.0.10)': dependencies: - esbuild: 0.25.9 + esbuild: 0.27.7 jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) lodash: 4.17.21 transitivePeerDependencies: @@ -15451,6 +11343,10 @@ snapshots: - supports-color - utf-8-validate + '@cspotcode/source-map-support@0.8.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + '@csstools/color-helpers@5.0.2': {} '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': @@ -15471,131 +11367,10 @@ snapshots: '@csstools/css-tokenizer@3.0.4': {} - '@dabh/diagnostics@2.0.3': - dependencies: - colorspace: 1.1.4 - enabled: 2.0.0 - kuler: 2.0.0 - - '@develar/schema-utils@2.6.5': - dependencies: - ajv: 6.12.6 - ajv-keywords: 3.5.2(ajv@6.12.6) - '@ecies/ciphers@0.2.4(@noble/ciphers@1.3.0)': dependencies: '@noble/ciphers': 1.3.0 - '@electron/asar@3.2.18': - dependencies: - commander: 5.1.0 - glob: 7.2.3 - minimatch: 3.1.2 - - '@electron/asar@3.4.1': - dependencies: - commander: 5.1.0 - glob: 7.2.3 - minimatch: 3.1.2 - - '@electron/fuses@1.8.0': - dependencies: - chalk: 4.1.2 - fs-extra: 9.1.0 - minimist: 1.2.8 - - '@electron/get@2.0.3': - dependencies: - debug: 4.4.1 - env-paths: 2.2.1 - fs-extra: 8.1.0 - got: 11.8.6 - progress: 2.0.3 - semver: 6.3.1 - sumchecker: 3.0.1 - optionalDependencies: - global-agent: 3.0.0 - transitivePeerDependencies: - - supports-color - - '@electron/node-gyp@https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2': - dependencies: - env-paths: 2.2.1 - exponential-backoff: 3.1.2 - glob: 8.1.0 - graceful-fs: 4.2.11 - make-fetch-happen: 10.2.1 - nopt: 6.0.0 - proc-log: 2.0.1 - semver: 7.7.3 - tar: 6.2.1 - which: 2.0.2 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron/notarize@2.5.0': - dependencies: - debug: 4.4.1 - fs-extra: 9.1.0 - promise-retry: 2.0.1 - transitivePeerDependencies: - - supports-color - - '@electron/osx-sign@1.3.1': - dependencies: - compare-version: 0.1.2 - debug: 4.4.1 - fs-extra: 10.1.0 - isbinaryfile: 4.0.10 - minimist: 1.2.8 - plist: 3.1.0 - transitivePeerDependencies: - - supports-color - - '@electron/rebuild@3.7.0': - dependencies: - '@electron/node-gyp': https://codeload.github.com/electron/node-gyp/tar.gz/06b29aafb7708acef8b3669835c8a7857ebc92d2 - '@malept/cross-spawn-promise': 2.0.0 - chalk: 4.1.2 - debug: 4.4.1 - detect-libc: 2.1.2 - fs-extra: 10.1.0 - got: 11.8.6 - node-abi: 3.75.0 - node-api-version: 0.2.1 - ora: 5.4.1 - read-binary-file-arch: 1.0.6 - semver: 7.7.3 - tar: 6.2.1 - yargs: 17.7.2 - transitivePeerDependencies: - - bluebird - - supports-color - - '@electron/universal@2.0.1': - dependencies: - '@electron/asar': 3.4.1 - '@malept/cross-spawn-promise': 2.0.0 - debug: 4.4.1 - dir-compare: 4.2.0 - fs-extra: 11.3.1 - minimatch: 9.0.5 - plist: 3.1.0 - transitivePeerDependencies: - - supports-color - - '@electron/windows-sign@1.2.2': - dependencies: - cross-dirname: 0.1.0 - debug: 4.4.1 - fs-extra: 11.3.1 - minimist: 1.2.8 - postject: 1.0.0-alpha.6 - transitivePeerDependencies: - - supports-color - optional: true - '@emnapi/core@1.4.5': dependencies: '@emnapi/wasi-threads': 1.0.4 @@ -15620,157 +11395,161 @@ snapshots: esquery: 1.6.0 jsdoc-type-pratt-parser: 4.1.0 - '@esbuild/aix-ppc64@0.19.12': - optional: true - '@esbuild/aix-ppc64@0.25.9': optional: true - '@esbuild/android-arm64@0.19.12': + '@esbuild/aix-ppc64@0.27.7': optional: true '@esbuild/android-arm64@0.25.9': optional: true - '@esbuild/android-arm@0.19.12': + '@esbuild/android-arm64@0.27.7': optional: true '@esbuild/android-arm@0.25.9': optional: true - '@esbuild/android-x64@0.19.12': + '@esbuild/android-arm@0.27.7': optional: true '@esbuild/android-x64@0.25.9': optional: true - '@esbuild/darwin-arm64@0.19.12': + '@esbuild/android-x64@0.27.7': optional: true '@esbuild/darwin-arm64@0.25.9': optional: true - '@esbuild/darwin-x64@0.19.12': + '@esbuild/darwin-arm64@0.27.7': optional: true '@esbuild/darwin-x64@0.25.9': optional: true - '@esbuild/freebsd-arm64@0.19.12': + '@esbuild/darwin-x64@0.27.7': optional: true '@esbuild/freebsd-arm64@0.25.9': optional: true - '@esbuild/freebsd-x64@0.19.12': + '@esbuild/freebsd-arm64@0.27.7': optional: true '@esbuild/freebsd-x64@0.25.9': optional: true - '@esbuild/linux-arm64@0.19.12': + '@esbuild/freebsd-x64@0.27.7': optional: true '@esbuild/linux-arm64@0.25.9': optional: true - '@esbuild/linux-arm@0.19.12': + '@esbuild/linux-arm64@0.27.7': optional: true '@esbuild/linux-arm@0.25.9': optional: true - '@esbuild/linux-ia32@0.19.12': + '@esbuild/linux-arm@0.27.7': optional: true '@esbuild/linux-ia32@0.25.9': optional: true - '@esbuild/linux-loong64@0.19.12': + '@esbuild/linux-ia32@0.27.7': optional: true '@esbuild/linux-loong64@0.25.9': optional: true - '@esbuild/linux-mips64el@0.19.12': + '@esbuild/linux-loong64@0.27.7': optional: true '@esbuild/linux-mips64el@0.25.9': optional: true - '@esbuild/linux-ppc64@0.19.12': + '@esbuild/linux-mips64el@0.27.7': optional: true '@esbuild/linux-ppc64@0.25.9': optional: true - '@esbuild/linux-riscv64@0.19.12': + '@esbuild/linux-ppc64@0.27.7': optional: true '@esbuild/linux-riscv64@0.25.9': optional: true - '@esbuild/linux-s390x@0.19.12': + '@esbuild/linux-riscv64@0.27.7': optional: true '@esbuild/linux-s390x@0.25.9': optional: true - '@esbuild/linux-x64@0.19.12': + '@esbuild/linux-s390x@0.27.7': optional: true '@esbuild/linux-x64@0.25.9': optional: true + '@esbuild/linux-x64@0.27.7': + optional: true + '@esbuild/netbsd-arm64@0.25.9': optional: true - '@esbuild/netbsd-x64@0.19.12': + '@esbuild/netbsd-arm64@0.27.7': optional: true '@esbuild/netbsd-x64@0.25.9': optional: true + '@esbuild/netbsd-x64@0.27.7': + optional: true + '@esbuild/openbsd-arm64@0.25.9': optional: true - '@esbuild/openbsd-x64@0.19.12': + '@esbuild/openbsd-arm64@0.27.7': optional: true '@esbuild/openbsd-x64@0.25.9': optional: true + '@esbuild/openbsd-x64@0.27.7': + optional: true + '@esbuild/openharmony-arm64@0.25.9': optional: true - '@esbuild/sunos-x64@0.19.12': + '@esbuild/openharmony-arm64@0.27.7': optional: true '@esbuild/sunos-x64@0.25.9': optional: true - '@esbuild/win32-arm64@0.19.12': + '@esbuild/sunos-x64@0.27.7': optional: true '@esbuild/win32-arm64@0.25.9': optional: true - '@esbuild/win32-ia32@0.19.12': + '@esbuild/win32-arm64@0.27.7': optional: true '@esbuild/win32-ia32@0.25.9': optional: true - '@esbuild/win32-x64@0.19.12': + '@esbuild/win32-ia32@0.27.7': optional: true '@esbuild/win32-x64@0.25.9': optional: true - '@eslint-community/eslint-utils@4.7.0(eslint@8.57.1)': - dependencies: - eslint: 8.57.1 - eslint-visitor-keys: 3.4.3 + '@esbuild/win32-x64@0.27.7': + optional: true '@eslint-community/eslint-utils@4.7.0(eslint@9.33.0(jiti@2.6.1))': dependencies: @@ -15793,20 +11572,6 @@ snapshots: dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@2.1.4': - dependencies: - ajv: 6.12.6 - debug: 4.4.1 - espree: 9.6.1 - globals: 13.24.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.0 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - '@eslint/eslintrc@3.3.1': dependencies: ajv: 6.12.6 @@ -15821,8 +11586,6 @@ snapshots: transitivePeerDependencies: - supports-color - '@eslint/js@8.57.1': {} - '@eslint/js@9.33.0': {} '@eslint/object-schema@2.1.6': {} @@ -15852,122 +11615,160 @@ snapshots: ethereum-cryptography: 2.2.1 micro-ftch: 0.3.1 - '@farcaster/frame-core@0.1.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)': + '@ethersproject/abi@5.8.0': dependencies: - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - ox: 0.4.4(typescript@5.9.2)(zod@3.25.76) - zod: 3.25.76 - transitivePeerDependencies: - - bufferutil - - encoding - - typescript - - utf-8-validate + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 - '@farcaster/frame-sdk@0.0.60(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@ethersproject/abstract-provider@5.8.0': dependencies: - '@farcaster/frame-core': 0.1.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@farcaster/quick-auth': 0.0.5(typescript@5.9.2) - comlink: 4.4.2 - eventemitter3: 5.0.1 - ox: 0.4.4(typescript@5.9.2)(zod@4.1.13) - transitivePeerDependencies: - - bufferutil - - encoding - - typescript - - utf-8-validate - - zod + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/web': 5.8.0 - '@farcaster/frame-sdk@0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@ethersproject/abstract-signer@5.8.0': dependencies: - '@farcaster/miniapp-sdk': 0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@farcaster/quick-auth': 0.0.6(typescript@5.9.2) - comlink: 4.4.2 - eventemitter3: 5.0.1 - ox: 0.4.4(typescript@5.9.2)(zod@3.25.76) - transitivePeerDependencies: - - bufferutil - - encoding - - typescript - - utf-8-validate - - zod + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 - '@farcaster/frame-sdk@0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@ethersproject/address@5.8.0': dependencies: - '@farcaster/miniapp-sdk': 0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@farcaster/quick-auth': 0.0.6(typescript@5.9.2) - comlink: 4.4.2 - eventemitter3: 5.0.1 - ox: 0.4.4(typescript@5.9.2)(zod@4.1.13) - transitivePeerDependencies: - - bufferutil - - encoding - - typescript - - utf-8-validate - - zod + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/rlp': 5.8.0 - '@farcaster/frame-wagmi-connector@0.0.42(@farcaster/frame-sdk@0.0.60(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': + '@ethersproject/base64@5.8.0': dependencies: - '@farcaster/frame-sdk': 0.0.60(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@ethersproject/bytes': 5.8.0 - '@farcaster/miniapp-core@0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)': + '@ethersproject/bignumber@5.8.0': dependencies: - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - ox: 0.4.4(typescript@5.9.2)(zod@3.25.76) - zod: 3.25.76 - transitivePeerDependencies: - - bufferutil - - encoding - - typescript - - utf-8-validate + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + bn.js: 5.2.2 - '@farcaster/miniapp-core@0.4.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)': + '@ethersproject/bytes@5.8.0': dependencies: - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - ox: 0.4.4(typescript@5.9.2)(zod@3.25.76) - zod: 3.25.76 - transitivePeerDependencies: - - bufferutil - - encoding - - typescript - - utf-8-validate + '@ethersproject/logger': 5.8.0 - '@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@ethersproject/constants@5.8.0': dependencies: - '@farcaster/miniapp-core': 0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@farcaster/quick-auth': 0.0.6(typescript@5.9.2) - comlink: 4.4.2 - eventemitter3: 5.0.1 - ox: 0.4.4(typescript@5.9.2)(zod@3.25.76) + '@ethersproject/bignumber': 5.8.0 + + '@ethersproject/hash@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/keccak256@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + js-sha3: 0.8.0 + + '@ethersproject/logger@5.8.0': {} + + '@ethersproject/networks@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/properties@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/rlp@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/signing-key@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + bn.js: 5.2.2 + elliptic: 6.6.1 + hash.js: 1.1.7 + + '@ethersproject/strings@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/transactions@5.8.0': + dependencies: + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + + '@ethersproject/web@5.8.0': + dependencies: + '@ethersproject/base64': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@evanhahn/lottie-web-light@5.8.1': {} + + '@farcaster/miniapp-core@0.3.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)': + dependencies: + '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + ox: 0.4.4(typescript@5.9.3)(zod@3.25.76) + zod: 3.25.76 transitivePeerDependencies: - bufferutil - encoding - typescript - utf-8-validate - - zod - '@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@farcaster/miniapp-core@0.4.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)': dependencies: - '@farcaster/miniapp-core': 0.3.8(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@farcaster/quick-auth': 0.0.6(typescript@5.9.2) - comlink: 4.4.2 - eventemitter3: 5.0.1 - ox: 0.4.4(typescript@5.9.2)(zod@4.1.13) + '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + ox: 0.4.4(typescript@5.9.3)(zod@3.25.76) + zod: 3.25.76 transitivePeerDependencies: - bufferutil - encoding - typescript - utf-8-validate - - zod - '@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@farcaster/miniapp-core': 0.4.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@farcaster/quick-auth': 0.0.6(typescript@5.9.2) + '@farcaster/miniapp-core': 0.3.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@farcaster/quick-auth': 0.0.6(typescript@5.9.3) comlink: 4.4.2 eventemitter3: 5.0.1 - ox: 0.4.4(typescript@5.9.2)(zod@3.25.76) + ox: 0.4.4(typescript@5.9.3)(zod@4.1.13) transitivePeerDependencies: - bufferutil - encoding @@ -15975,13 +11776,13 @@ snapshots: - utf-8-validate - zod - '@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@farcaster/miniapp-core': 0.4.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@farcaster/quick-auth': 0.0.6(typescript@5.9.2) + '@farcaster/miniapp-core': 0.4.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@farcaster/quick-auth': 0.0.6(typescript@5.9.3) comlink: 4.4.2 eventemitter3: 5.0.1 - ox: 0.4.4(typescript@5.9.2)(zod@4.1.13) + ox: 0.4.4(typescript@5.9.3)(zod@4.1.13) transitivePeerDependencies: - bufferutil - encoding @@ -15989,34 +11790,16 @@ snapshots: - utf-8-validate - zod - '@farcaster/miniapp-wagmi-connector@1.0.0(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': - dependencies: - '@farcaster/miniapp-sdk': 0.1.9(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - - '@farcaster/miniapp-wagmi-connector@1.0.0(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@farcaster/miniapp-wagmi-connector@1.0.0(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))': dependencies: - '@farcaster/miniapp-sdk': 0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@farcaster/miniapp-sdk': 0.1.9(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) - '@farcaster/miniapp-wagmi-connector@1.0.0(@farcaster/miniapp-sdk@0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': - dependencies: - '@farcaster/miniapp-sdk': 0.2.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - - '@farcaster/quick-auth@0.0.5(typescript@5.9.2)': - dependencies: - jose: 5.10.0 - typescript: 5.9.2 - zod: 3.25.76 - - '@farcaster/quick-auth@0.0.6(typescript@5.9.2)': + '@farcaster/quick-auth@0.0.6(typescript@5.9.3)': dependencies: jose: 5.10.0 - typescript: 5.9.2 + typescript: 5.9.3 zod: 3.25.76 '@fastify/ajv-compiler@4.0.5': @@ -16056,12 +11839,6 @@ snapshots: '@floating-ui/core': 1.7.3 '@floating-ui/utils': 0.2.10 - '@floating-ui/react-dom@2.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/dom': 1.7.3 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - '@floating-ui/react-dom@2.1.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@floating-ui/dom': 1.7.3 @@ -16084,70 +11861,109 @@ snapshots: '@floating-ui/utils@0.2.10': {} - '@gar/promisify@1.1.3': {} - - '@gemini-wallet/core@0.2.0(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@gemini-wallet/core@0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: '@metamask/rpc-errors': 7.0.2 eventemitter3: 5.0.1 - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - supports-color - '@gemini-wallet/core@0.3.2(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@gemini-wallet/core@0.3.2(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: '@metamask/rpc-errors': 7.0.2 eventemitter3: 5.0.1 - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - supports-color - '@gemini-wallet/core@0.3.2(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': + '@gemini-wallet/core@0.3.2(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))': dependencies: '@metamask/rpc-errors': 7.0.2 eventemitter3: 5.0.1 - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - supports-color - '@gemini-wallet/core@0.3.2(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@graphql-typed-document-node/core@3.2.0(graphql@16.11.0)': dependencies: - '@metamask/rpc-errors': 7.0.2 - eventemitter3: 5.0.1 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - supports-color + graphql: 16.11.0 - '@gemini-wallet/core@0.3.2(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': + '@grpc/grpc-js@1.12.6': dependencies: - '@metamask/rpc-errors': 7.0.2 - eventemitter3: 5.0.1 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - transitivePeerDependencies: - - supports-color + '@grpc/proto-loader': 0.7.15 + '@js-sdsl/ordered-map': 4.4.2 - '@graphql-typed-document-node/core@3.2.0(graphql@16.11.0)': + '@grpc/proto-loader@0.7.15': dependencies: - graphql: 16.11.0 + lodash.camelcase: 4.3.0 + long: 5.3.1 + protobufjs: 7.5.4 + yargs: 17.7.2 - '@heroicons/react@2.2.0(react@19.2.3)': + '@hiero-ledger/cryptography@1.16.0-beta.3(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))': dependencies: - react: 19.2.3 + '@noble/curves': 1.8.1 + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + asn1js: 3.0.6 + bignumber.js: 9.1.1 + bn.js: 5.2.1 + buffer: 6.0.3 + crypto-js: 4.2.0 + debug: 4.4.1 + forge-light: 1.1.4 + js-base64: 3.7.7 + react-native-get-random-values: 1.11.0(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)) + spark-md5: 3.0.2 + strip-ansi: 7.1.2 + tweetnacl: 1.0.3 + utf8: 3.0.0 + transitivePeerDependencies: + - react-native + - supports-color + + '@hiero-ledger/proto@2.26.0-beta.3(ansi-regex@6.2.2)(ansi-styles@6.2.3)(debug@4.4.1)(protobufjs@7.5.4)(strip-ansi@7.1.2)': + dependencies: + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + debug: 4.4.1 + long: 5.3.1 + protobufjs: 7.5.4 + strip-ansi: 7.1.2 + + '@hiero-ledger/sdk@2.80.0(bn.js@5.2.1)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))': + dependencies: + '@ethersproject/abi': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@grpc/grpc-js': 1.12.6 + '@hiero-ledger/cryptography': 1.16.0-beta.3(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)) + '@hiero-ledger/proto': 2.26.0-beta.3(ansi-regex@6.2.2)(ansi-styles@6.2.3)(debug@4.4.1)(protobufjs@7.5.4)(strip-ansi@7.1.2) + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + bignumber.js: 9.1.1 + bn.js: 5.2.1 + crypto-js: 4.2.0 + debug: 4.4.1 + js-base64: 3.7.4 + long: 5.3.1 + pino: 10.1.0 + pino-pretty: 13.0.0 + protobufjs: 7.5.4 + rfc4648: 1.5.3 + strip-ansi: 7.1.2 + utf8: 3.0.0 + transitivePeerDependencies: + - expo-crypto + - react-native + - supports-color '@hono/node-server@1.19.0(hono@4.10.7)': dependencies: hono: 4.10.7 - '@hpke/chacha20poly1305@1.7.1': - dependencies: - '@hpke/common': 1.8.1 - - '@hpke/common@1.8.1': {} - - '@hpke/core@1.7.4': - dependencies: - '@hpke/common': 1.8.1 - '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.6': @@ -16155,18 +11971,8 @@ snapshots: '@humanfs/core': 0.19.1 '@humanwhocodes/retry': 0.3.1 - '@humanwhocodes/config-array@0.13.0': - dependencies: - '@humanwhocodes/object-schema': 2.0.3 - debug: 4.4.1 - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - '@humanwhocodes/module-importer@1.0.1': {} - '@humanwhocodes/object-schema@2.0.3': {} - '@humanwhocodes/retry@0.3.1': {} '@humanwhocodes/retry@0.4.3': {} @@ -16268,12 +12074,6 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 - '@isaacs/cliui@8.0.2': dependencies: string-width: 5.1.2 @@ -16283,6 +12083,21 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/ttlcache@1.4.1': {} + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.10 + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.17.2 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -16295,6 +12110,11 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.30': @@ -16302,65 +12122,16 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 - '@jup-ag/api@6.0.44': {} - - '@langchain/core@0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76))': - dependencies: - '@cfworker/json-schema': 4.1.1 - ansi-styles: 5.2.0 - camelcase: 6.3.0 - decamelize: 1.2.0 - js-tiktoken: 1.0.21 - langsmith: 0.3.62(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - mustache: 4.2.0 - p-queue: 6.6.2 - p-retry: 4.6.2 - uuid: 10.0.0 - zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) - transitivePeerDependencies: - - '@opentelemetry/api' - - '@opentelemetry/exporter-trace-otlp-proto' - - '@opentelemetry/sdk-trace-base' - - openai - - '@langchain/langgraph-checkpoint@0.0.18(@langchain/core@0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)))': - dependencies: - '@langchain/core': 0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - uuid: 10.0.0 - - '@langchain/langgraph-sdk@0.0.109(@langchain/core@0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@jridgewell/trace-mapping@0.3.9': dependencies: - '@types/json-schema': 7.0.15 - p-queue: 6.6.2 - p-retry: 4.6.2 - uuid: 9.0.1 - optionalDependencies: - '@langchain/core': 0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 - '@langchain/langgraph@0.2.74(@langchain/core@0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3)(zod-to-json-schema@3.24.6(zod@3.25.76))': - dependencies: - '@langchain/core': 0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - '@langchain/langgraph-checkpoint': 0.0.18(@langchain/core@0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76))) - '@langchain/langgraph-sdk': 0.0.109(@langchain/core@0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)))(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - uuid: 10.0.0 - zod: 3.25.76 - optionalDependencies: - zod-to-json-schema: 3.24.6(zod@3.25.76) - transitivePeerDependencies: - - react - - react-dom + '@js-sdsl/ordered-map@4.4.2': {} - '@langchain/openai@0.5.18(@langchain/core@0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)))(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@likecoin/qr-code-styling@1.6.6': dependencies: - '@langchain/core': 0.3.72(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - js-tiktoken: 1.0.21 - openai: 5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - zod: 3.25.76 - transitivePeerDependencies: - - ws + qrcode-generator: 1.5.2 '@lit-labs/ssr-dom-shim@1.4.0': {} @@ -16368,73 +12139,6 @@ snapshots: dependencies: '@lit-labs/ssr-dom-shim': 1.4.0 - '@llamaindex/anthropic@0.3.23(@llamaindex/core@0.6.5)(@llamaindex/env@0.1.30)': - dependencies: - '@anthropic-ai/sdk': 0.58.0 - '@llamaindex/core': 0.6.5 - '@llamaindex/env': 0.1.30 - remeda: 2.30.0 - - '@llamaindex/cloud@4.0.7(@llamaindex/core@0.6.5)(@llamaindex/env@0.1.30)': - dependencies: - '@llamaindex/core': 0.6.5 - '@llamaindex/env': 0.1.30 - p-retry: 6.2.1 - - '@llamaindex/core@0.6.5': - dependencies: - '@llamaindex/env': 0.1.30 - '@types/node': 22.17.2 - magic-bytes.js: 1.12.1 - zod: 3.25.76 - zod-to-json-schema: 3.24.6(zod@3.25.76) - transitivePeerDependencies: - - '@huggingface/transformers' - - gpt-tokenizer - - '@llamaindex/env@0.1.30': - dependencies: - '@aws-crypto/sha256-js': 5.2.0 - js-tiktoken: 1.0.21 - pathe: 1.1.2 - - '@llamaindex/node-parser@2.0.5(@llamaindex/core@0.6.5)(@llamaindex/env@0.1.30)(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)': - dependencies: - '@llamaindex/core': 0.6.5 - '@llamaindex/env': 0.1.30 - html-to-text: 9.0.5 - tree-sitter: 0.22.4 - web-tree-sitter: 0.24.7 - - '@llamaindex/openai@0.3.7(@llamaindex/core@0.6.5)(@llamaindex/env@0.1.30)(encoding@0.1.13)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)': - dependencies: - '@llamaindex/core': 0.6.5 - '@llamaindex/env': 0.1.30 - openai: 4.104.0(encoding@0.1.13)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - transitivePeerDependencies: - - encoding - - ws - - zod - - '@llamaindex/workflow@1.0.3(@llamaindex/core@0.6.5)(@llamaindex/env@0.1.30)(zod@3.25.76)': - dependencies: - '@llamaindex/core': 0.6.5 - '@llamaindex/env': 0.1.30 - zod: 3.25.76 - - '@malept/cross-spawn-promise@2.0.0': - dependencies: - cross-spawn: 7.0.6 - - '@malept/flatpak-bundler@0.4.0': - dependencies: - debug: 4.4.1 - fs-extra: 9.1.0 - lodash: 4.17.21 - tmp-promise: 3.0.3 - transitivePeerDependencies: - - supports-color - '@metamask/eth-json-rpc-provider@1.0.1': dependencies: '@metamask/json-rpc-engine': 7.3.3 @@ -16516,10 +12220,10 @@ snapshots: dependencies: openapi-fetch: 0.13.8 - '@metamask/sdk-communication-layer@0.32.0(cross-fetch@4.1.0(encoding@0.1.13))(eciesjs@0.4.15)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@metamask/sdk-communication-layer@0.32.0(cross-fetch@4.1.0)(eciesjs@0.4.15)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: bufferutil: 4.0.9 - cross-fetch: 4.1.0(encoding@0.1.13) + cross-fetch: 4.1.0 date-fns: 2.30.0 debug: 4.4.1 eciesjs: 0.4.15 @@ -16531,11 +12235,11 @@ snapshots: transitivePeerDependencies: - supports-color - '@metamask/sdk-communication-layer@0.33.1(cross-fetch@4.1.0(encoding@0.1.13))(eciesjs@0.4.15)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@metamask/sdk-communication-layer@0.33.1(cross-fetch@4.1.0)(eciesjs@0.4.15)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@metamask/sdk-analytics': 0.0.5 bufferutil: 4.0.9 - cross-fetch: 4.1.0(encoding@0.1.13) + cross-fetch: 4.1.0 date-fns: 2.30.0 debug: 4.3.4 eciesjs: 0.4.15 @@ -16555,16 +12259,16 @@ snapshots: dependencies: '@paulmillr/qr': 0.2.1 - '@metamask/sdk@0.32.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)': + '@metamask/sdk@0.32.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@babel/runtime': 7.28.3 '@metamask/onboarding': 1.0.1 '@metamask/providers': 16.1.0 - '@metamask/sdk-communication-layer': 0.32.0(cross-fetch@4.1.0(encoding@0.1.13))(eciesjs@0.4.15)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@metamask/sdk-communication-layer': 0.32.0(cross-fetch@4.1.0)(eciesjs@0.4.15)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@metamask/sdk-install-modal-web': 0.32.0 '@paulmillr/qr': 0.2.1 bowser: 2.12.0 - cross-fetch: 4.1.0(encoding@0.1.13) + cross-fetch: 4.1.0 debug: 4.4.1 eciesjs: 0.4.15 eth-rpc-errors: 4.0.3 @@ -16582,17 +12286,17 @@ snapshots: - supports-color - utf-8-validate - '@metamask/sdk@0.33.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10)': + '@metamask/sdk@0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@babel/runtime': 7.28.3 '@metamask/onboarding': 1.0.1 '@metamask/providers': 16.1.0 '@metamask/sdk-analytics': 0.0.5 - '@metamask/sdk-communication-layer': 0.33.1(cross-fetch@4.1.0(encoding@0.1.13))(eciesjs@0.4.15)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@metamask/sdk-communication-layer': 0.33.1(cross-fetch@4.1.0)(eciesjs@0.4.15)(eventemitter2@6.4.9)(readable-stream@3.6.2)(socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@metamask/sdk-install-modal-web': 0.32.1 '@paulmillr/qr': 0.2.1 bowser: 2.12.0 - cross-fetch: 4.1.0(encoding@0.1.13) + cross-fetch: 4.1.0 debug: 4.3.4 eciesjs: 0.4.15 eth-rpc-errors: 4.0.3 @@ -16682,6 +12386,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@msgpack/msgpack@3.1.3': {} + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.4.5 @@ -16689,898 +12395,224 @@ snapshots: '@tybys/wasm-util': 0.10.0 optional: true - '@next/env@15.5.9': {} - '@next/env@16.0.10': {} - '@next/eslint-plugin-next@15.5.7': - dependencies: - fast-glob: 3.3.1 - '@next/eslint-plugin-next@16.0.6': dependencies: fast-glob: 3.3.1 - '@next/eslint-plugin-next@16.0.7': - dependencies: - fast-glob: 3.3.1 - - '@next/swc-darwin-arm64@15.5.7': - optional: true - '@next/swc-darwin-arm64@16.0.10': optional: true - '@next/swc-darwin-x64@15.5.7': - optional: true - '@next/swc-darwin-x64@16.0.10': optional: true - '@next/swc-linux-arm64-gnu@15.5.7': - optional: true - '@next/swc-linux-arm64-gnu@16.0.10': optional: true - '@next/swc-linux-arm64-musl@15.5.7': - optional: true - '@next/swc-linux-arm64-musl@16.0.10': optional: true - '@next/swc-linux-x64-gnu@15.5.7': - optional: true - - '@next/swc-linux-x64-gnu@16.0.10': - optional: true - - '@next/swc-linux-x64-musl@15.5.7': - optional: true - - '@next/swc-linux-x64-musl@16.0.10': - optional: true - - '@next/swc-win32-arm64-msvc@15.5.7': - optional: true - - '@next/swc-win32-arm64-msvc@16.0.10': - optional: true - - '@next/swc-win32-x64-msvc@15.5.7': - optional: true - - '@next/swc-win32-x64-msvc@16.0.10': - optional: true - - '@noble/ciphers@1.2.1': {} - - '@noble/ciphers@1.3.0': {} - - '@noble/curves@1.2.0': - dependencies: - '@noble/hashes': 1.3.2 - - '@noble/curves@1.4.2': - dependencies: - '@noble/hashes': 1.4.0 - - '@noble/curves@1.8.0': - dependencies: - '@noble/hashes': 1.7.0 - - '@noble/curves@1.8.1': - dependencies: - '@noble/hashes': 1.7.1 - - '@noble/curves@1.9.1': - dependencies: - '@noble/hashes': 1.8.0 - - '@noble/curves@1.9.7': - dependencies: - '@noble/hashes': 1.8.0 - - '@noble/hashes@1.3.2': {} - - '@noble/hashes@1.4.0': {} - - '@noble/hashes@1.7.0': {} - - '@noble/hashes@1.7.1': {} - - '@noble/hashes@1.8.0': {} - - '@nodelib/fs.scandir@2.1.5': - dependencies: - '@nodelib/fs.stat': 2.0.5 - run-parallel: 1.2.0 - - '@nodelib/fs.stat@2.0.5': {} - - '@nodelib/fs.walk@1.2.8': - dependencies: - '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 - - '@nolyfill/is-core-module@1.0.39': {} - - '@npmcli/fs@2.1.2': - dependencies: - '@gar/promisify': 1.1.3 - semver: 7.7.3 - - '@npmcli/move-file@2.0.1': - dependencies: - mkdirp: 1.0.4 - rimraf: 3.0.2 - - '@opensea/seaport-js@4.0.5(bufferutil@4.0.9)(utf-8-validate@5.0.10)': - dependencies: - ethers: 6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - merkletreejs: 0.5.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - '@paulmillr/qr@0.2.1': {} - - '@pinojs/redact@0.4.0': {} - - '@pkgjs/parseargs@0.11.0': - optional: true - - '@pkgr/core@0.2.9': {} - - '@privy-io/api-base@1.6.0': - dependencies: - zod: 3.25.76 - - '@privy-io/public-api@2.43.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)': - dependencies: - '@privy-io/api-base': 1.6.0 - bs58: 5.0.0 - libphonenumber-js: 1.12.13 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zod: 3.25.76 - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - '@privy-io/server-auth@1.31.1(bufferutil@4.0.9)(encoding@0.1.13)(ethers@6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': - dependencies: - '@hpke/chacha20poly1305': 1.7.1 - '@hpke/core': 1.7.4 - '@noble/curves': 1.9.7 - '@noble/hashes': 1.8.0 - '@privy-io/public-api': 2.43.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@scure/base': 1.2.6 - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - canonicalize: 2.1.0 - dotenv: 16.6.1 - jose: 4.15.9 - node-fetch-native: 1.6.7 - redaxios: 0.5.1 - svix: 1.74.1 - ts-case-convert: 2.1.0 - type-fest: 3.13.1 - optionalDependencies: - ethers: 6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - bufferutil - - encoding - - typescript - - utf-8-validate - - '@radix-ui/colors@3.0.0': {} - - '@radix-ui/number@1.1.1': {} - - '@radix-ui/primitive@1.1.3': {} - - '@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@next/swc-linux-x64-gnu@16.0.10': + optional: true - '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@next/swc-linux-x64-musl@16.0.10': + optional: true - '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@next/swc-win32-arm64-msvc@16.0.10': + optional: true - '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@next/swc-win32-x64-msvc@16.0.10': + optional: true - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@noble/ciphers@1.2.0': {} - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@noble/ciphers@1.2.1': {} - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.1)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 + '@noble/ciphers@1.3.0': {} - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.1)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.1 + '@noble/ciphers@2.2.0': {} - '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@noble/curves@1.4.2': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@noble/hashes': 1.4.0 - '@radix-ui/react-context@1.1.2(@types/react@19.2.1)(react@18.3.1)': + '@noble/curves@1.8.0': dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 + '@noble/hashes': 1.7.0 - '@radix-ui/react-context@1.1.2(@types/react@19.2.1)(react@19.2.3)': + '@noble/curves@1.8.1': dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.1 + '@noble/hashes': 1.7.1 - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@noble/curves@1.9.1': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@19.2.1)(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@noble/hashes': 1.8.0 - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@noble/curves@1.9.7': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@19.2.3) - aria-hidden: 1.2.6 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-remove-scroll: 2.7.1(@types/react@19.2.1)(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@noble/hashes': 1.8.0 - '@radix-ui/react-direction@1.1.1(@types/react@19.2.1)(react@18.3.1)': + '@noble/curves@2.2.0': dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 + '@noble/hashes': 2.2.0 - '@radix-ui/react-direction@1.1.1(@types/react@19.2.1)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.1 + '@noble/ed25519@3.1.0': {} - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@noble/hashes@1.4.0': {} - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.1)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@noble/hashes@1.7.0': {} - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@noble/hashes@1.7.1': {} - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@noble/hashes@1.8.0': {} - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.1)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 + '@noble/hashes@2.2.0': {} - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.1)(react@19.2.3)': + '@nodelib/fs.scandir@2.1.5': dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.1 + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@nodelib/fs.stat@2.0.5': {} - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@nodelib/fs.walk@1.2.8': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.19.1 - '@radix-ui/react-form@0.1.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@nolyfill/is-core-module@1.0.39': {} - '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@paulmillr/qr@0.2.1': {} - '@radix-ui/react-icons@1.3.2(react@18.3.1)': + '@perawallet/connect@1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: - react: 18.3.1 + '@evanhahn/lottie-web-light': 5.8.1 + '@walletconnect/client': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/types': 1.8.0 + algosdk: 3.5.2 + bowser: 2.11.0 + buffer: 6.0.3 + qr-code-styling: 1.6.0-rc.1 + tweetnacl-ts: 1.0.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate - '@radix-ui/react-id@1.1.1(@types/react@19.2.1)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 + '@pinojs/redact@0.4.0': {} - '@radix-ui/react-id@1.1.1(@types/react@19.2.1)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.1 + '@pkgjs/parseargs@0.11.0': + optional: true - '@radix-ui/react-label@2.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@pkgr/core@0.2.9': {} - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@19.2.1)(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@protobufjs/aspromise@1.1.2': {} - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) - aria-hidden: 1.2.6 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-remove-scroll: 2.7.1(@types/react@19.2.1)(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@protobufjs/base64@1.1.2': {} - '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@protobufjs/codegen@2.0.4': {} - '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@protobufjs/eventemitter@1.1.0': {} - '@radix-ui/react-one-time-password-field@0.1.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@protobufjs/fetch@1.1.0': dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 1.1.0 - '@radix-ui/react-password-toggle-field@0.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@protobufjs/float@1.0.2': {} - '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@19.2.1)(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) + '@protobufjs/inquire@1.1.0': {} + + '@protobufjs/path@1.1.2': {} - '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@protobufjs/pool@1.1.0': {} + + '@protobufjs/utf8@1.1.0': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@19.2.3) - aria-hidden: 1.2.6 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) - react-remove-scroll: 2.7.1(@types/react@19.2.1)(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@floating-ui/react-dom': 2.1.5(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/rect': 1.1.1 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 19.2.1 '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@floating-ui/react-dom': 2.1.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/rect': 1.1.1 + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) optionalDependencies: '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-context@1.1.2(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@19.2.3) + aria-hidden: 1.2.6 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) + react-remove-scroll: 2.7.1(@types/react@19.2.1)(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-progress@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-direction@1.1.1(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react: 19.2.3 optionalDependencies: '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.1)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@19.2.3) '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) @@ -17588,1054 +12620,396 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - aria-hidden: 1.2.6 - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll: 2.7.1(@types/react@19.2.1)(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-separator@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-slot@1.2.3(@types/react@19.2.1)(react@18.3.1)': + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 + react: 19.2.3 optionalDependencies: '@types/react': 19.2.1 - '@radix-ui/react-slot@1.2.3(@types/react@19.2.1)(react@19.2.3)': + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + react-dom: 19.2.3(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-id@1.1.1(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) + react: 19.2.3 optionalDependencies: '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) + aria-hidden: 1.2.6 react: 19.2.3 react-dom: 19.2.3(react@19.2.3) + react-remove-scroll: 2.7.1(@types/react@19.2.1)(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-toolbar@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.1)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.1)(react@19.2.3)': - dependencies: - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.1)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.1)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.1)(react@19.2.3) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.1)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.1)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.1)(react@18.3.1)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.1)(react@19.2.3)': - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) - react: 19.2.3 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.1)(react@18.3.1)': - dependencies: - react: 18.3.1 - use-sync-external-store: 1.5.0(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.1)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.1)(react@19.2.3)': - dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@19.2.3) + aria-hidden: 1.2.6 react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + react-remove-scroll: 2.7.1(@types/react@19.2.1)(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.1)(react@18.3.1)': - dependencies: - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.1)(react@18.3.1)': - dependencies: - '@radix-ui/rect': 1.1.1 - react: 18.3.1 - optionalDependencies: - '@types/react': 19.2.1 - - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.1)(react@19.2.3)': + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: + '@floating-ui/react-dom': 2.1.5(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.1)(react@19.2.3) '@radix-ui/rect': 1.1.1 react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.1)(react@18.3.1)': + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - react: 18.3.1 + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.1)(react@19.2.3)': + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@19.2.3) '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@19.2.3) react: 19.2.3 react-dom: 19.2.3(react@19.2.3) optionalDependencies: '@types/react': 19.2.1 '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@radix-ui/rect@1.1.1': {} - - '@radix-ui/themes@3.2.1(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1)': + '@radix-ui/react-slot@1.2.3(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@radix-ui/colors': 3.0.0 - classnames: 2.5.1 - radix-ui: 1.4.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - react-remove-scroll-bar: 2.3.8(@types/react@19.2.1)(react@18.3.1) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) + react: 19.2.3 optionalDependencies: '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - - '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4)': - dependencies: - big.js: 6.2.2 - dayjs: 1.11.13 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4) - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - zod - - '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - big.js: 6.2.2 - dayjs: 1.11.13 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - zod - - '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': - dependencies: - big.js: 6.2.2 - dayjs: 1.11.13 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - zod - - '@reown/appkit-controllers@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - valtio: 1.13.2(@types/react@19.1.10)(react@19.1.1) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - - '@reown/appkit-controllers@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.1) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - - '@reown/appkit-controllers@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.3) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - '@reown/appkit-controllers@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.3) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@reown/appkit-controllers@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - valtio: 1.13.2(@types/react@19.2.1)(react@19.2.3) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) - '@reown/appkit-pay@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76) - lit: 3.3.0 - valtio: 1.13.2(@types/react@19.1.10)(react@19.1.1) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod + react: 19.2.3 + optionalDependencies: + '@types/react': 19.2.1 - '@reown/appkit-pay@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.1))(zod@3.25.76) - lit: 3.3.0 - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.1) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.1)(react@19.2.3) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) + react: 19.2.3 + optionalDependencies: + '@types/react': 19.2.1 - '@reown/appkit-pay@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13) - lit: 3.3.0 - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.3) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) + react: 19.2.3 + optionalDependencies: + '@types/react': 19.2.1 - '@reown/appkit-pay@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13) - lit: 3.3.0 - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.3) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.3) + react: 19.2.3 + optionalDependencies: + '@types/react': 19.2.1 - '@reown/appkit-pay@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-ui': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-utils': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13) - lit: 3.3.0 - valtio: 1.13.2(@types/react@19.2.1)(react@19.2.3) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod + react: 19.2.3 + optionalDependencies: + '@types/react': 19.2.1 - '@reown/appkit-polyfills@1.7.8': + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.1)(react@19.2.3)': dependencies: - buffer: 6.0.3 + '@radix-ui/rect': 1.1.1 + react: 19.2.3 + optionalDependencies: + '@types/react': 19.2.1 - '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76)': + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.1)(react@19.2.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - lit: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - valtio - - zod + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.3) + react: 19.2.3 + optionalDependencies: + '@types/react': 19.2.1 - '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.1))(zod@3.25.76)': + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.1))(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - lit: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - valtio - - zod + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) + react: 19.2.3 + react-dom: 19.2.3(react@19.2.3) + optionalDependencies: + '@types/react': 19.2.1 + '@types/react-dom': 19.2.1(@types/react@19.2.1) + + '@radix-ui/rect@1.1.1': {} + + '@react-native/assets-registry@0.85.2': {} + + '@react-native/codegen@0.85.2(@babel/core@7.28.3)': + dependencies: + '@babel/core': 7.28.3 + '@babel/parser': 7.29.2 + hermes-parser: 0.33.3 + invariant: 2.2.4 + nullthrows: 1.1.1 + tinyglobby: 0.2.15 + yargs: 17.7.2 - '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13)': + '@react-native/community-cli-plugin@0.85.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - lit: 3.3.0 + '@react-native/dev-middleware': 0.85.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + debug: 4.4.1 + invariant: 2.2.4 + metro: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-config: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-core: 0.84.3 + semver: 7.7.3 transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing + - supports-color - utf-8-validate - - valtio - - zod - '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13)': + '@react-native/debugger-frontend@0.85.2': {} + + '@react-native/debugger-shell@0.85.2': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - lit: 3.3.0 + cross-spawn: 7.0.6 + debug: 4.4.1 + fb-dotslash: 0.5.8 + transitivePeerDependencies: + - supports-color + + '@react-native/dev-middleware@0.85.2(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.85.2 + '@react-native/debugger-shell': 0.85.2 + chrome-launcher: 0.15.2 + chromium-edge-launcher: 0.3.0 + connect: 3.7.0 + debug: 4.4.1 + invariant: 2.2.4 + nullthrows: 1.1.1 + open: 7.4.2 + serve-static: 1.16.2 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing + - supports-color - utf-8-validate - - valtio - - zod - '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13)': + '@react-native/gradle-plugin@0.85.2': {} + + '@react-native/js-polyfills@0.85.2': {} + + '@react-native/normalize-colors@0.85.2': {} + + '@react-native/virtualized-lists@0.85.2(@types/react@19.1.10)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-ui': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-utils': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - lit: 3.3.0 + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.1.1 + react-native: 0.85.2(@babel/core@7.28.3)(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10) + optionalDependencies: + '@types/react': 19.1.10 + optional: true + + '@react-native/virtualized-lists@0.85.2(@types/react@19.2.1)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.2.3 + react-native: 0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10) + optionalDependencies: + '@types/react': 19.2.1 + + '@redis/bloom@5.12.1(@redis/client@5.12.1)': + dependencies: + '@redis/client': 5.12.1 + + '@redis/client@5.12.1': + dependencies: + cluster-key-slot: 1.1.2 + + '@redis/json@5.12.1(@redis/client@5.12.1)': + dependencies: + '@redis/client': 5.12.1 + + '@redis/search@5.12.1(@redis/client@5.12.1)': + dependencies: + '@redis/client': 5.12.1 + + '@redis/time-series@5.12.1(@redis/client@5.12.1)': + dependencies: + '@redis/client': 5.12.1 + + '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4)': + dependencies: + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4) transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - bufferutil - - db0 - - encoding - - ioredis - - react - typescript - - uploadthing - utf-8-validate - - valtio - zod - '@reown/appkit-ui@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - lit: 3.3.0 - qrcode: 1.5.3 + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - bufferutil - - db0 - - encoding - - ioredis - - react - typescript - - uploadthing - utf-8-validate - zod - '@reown/appkit-ui@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - lit: 3.3.0 - qrcode: 1.5.3 + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4) transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - bufferutil - - db0 - - encoding - - ioredis - - react - typescript - - uploadthing - utf-8-validate - zod - '@reown/appkit-ui@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - lit: 3.3.0 - qrcode: 1.5.3 + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - bufferutil - - db0 - - encoding - - ioredis - - react - typescript - - uploadthing - utf-8-validate - zod - '@reown/appkit-ui@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@reown/appkit-controllers@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - lit: 3.3.0 - qrcode: 1.5.3 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 1.13.2(@types/react@19.1.10)(react@19.1.1) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -18663,13 +13037,13 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-ui@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@reown/appkit-controllers@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - lit: 3.3.0 - qrcode: 1.5.3 + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + valtio: 1.13.2(@types/react@19.2.1)(react@19.2.3) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -18697,16 +13071,14 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76)': + '@reown/appkit-pay@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76) + lit: 3.3.0 valtio: 1.13.2(@types/react@19.1.10)(react@19.1.1) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -18734,16 +13106,14 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.1))(zod@3.25.76)': + '@reown/appkit-pay@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.1) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13) + lit: 3.3.0 + valtio: 1.13.2(@types/react@19.2.1)(react@19.2.3) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -18771,16 +13141,18 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-utils@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13)': + '@reown/appkit-polyfills@1.7.8': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-polyfills': 1.7.8 + buffer: 6.0.3 + + '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.3) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + lit: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -18806,18 +13178,17 @@ snapshots: - typescript - uploadthing - utf-8-validate + - valtio - zod - '@reown/appkit-utils@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13)': + '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.3) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + lit: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -18843,18 +13214,16 @@ snapshots: - typescript - uploadthing - utf-8-validate + - valtio - zod - '@reown/appkit-utils@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13)': + '@reown/appkit-ui@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-polyfills': 1.7.8 + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/logger': 2.1.2 - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - valtio: 1.13.2(@types/react@19.2.1)(react@19.2.3) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + lit: 3.3.0 + qrcode: 1.5.3 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -18881,33 +13250,14 @@ snapshots: - uploadthing - utf-8-validate - zod - - '@reown/appkit-wallet@1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4) - '@reown/appkit-polyfills': 1.7.8 - '@walletconnect/logger': 2.1.2 - zod: 3.22.4 - transitivePeerDependencies: - - bufferutil - - typescript - - utf-8-validate - - '@reown/appkit@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-pay': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - bs58: 6.0.0 - valtio: 1.13.2(@types/react@19.1.10)(react@19.1.1) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + + '@reown/appkit-ui@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + lit: 3.3.0 + qrcode: 1.5.3 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -18935,21 +13285,16 @@ snapshots: - utf-8-validate - zod - '@reown/appkit@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-utils@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-pay': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.1))(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.1))(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - bs58: 6.0.0 - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.1) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/logger': 2.1.2 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 1.13.2(@types/react@19.1.10)(react@19.1.1) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -18977,21 +13322,16 @@ snapshots: - utf-8-validate - zod - '@reown/appkit@1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@reown/appkit-utils@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-pay': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/universal-provider': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - bs58: 6.0.0 - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.3) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@walletconnect/logger': 2.1.2 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + valtio: 1.13.2(@types/react@19.2.1)(react@19.2.3) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -19019,21 +13359,43 @@ snapshots: - utf-8-validate - zod - '@reown/appkit@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@reown/appkit-wallet@1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4) + '@reown/appkit-polyfills': 1.7.8 + '@walletconnect/logger': 2.1.2 + zod: 3.22.4 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + + '@reown/appkit-wallet@1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4) + '@reown/appkit-polyfills': 1.7.8 + '@walletconnect/logger': 2.1.2 + zod: 3.22.4 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + + '@reown/appkit@1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-pay': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-pay': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3))(zod@4.1.13) + '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.10)(react@19.1.1))(zod@3.25.76) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.0 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) bs58: 6.0.0 - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.3) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + valtio: 1.13.2(@types/react@19.1.10)(react@19.1.1) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -19061,21 +13423,21 @@ snapshots: - utf-8-validate - zod - '@reown/appkit@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@reown/appkit@1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-controllers': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-pay': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-controllers': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-pay': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) '@reown/appkit-polyfills': 1.7.8 - '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13) - '@reown/appkit-ui': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@reown/appkit-utils': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13) + '@reown/appkit-ui': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-utils': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3))(zod@4.1.13) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@walletconnect/types': 2.21.0 + '@walletconnect/universal-provider': 2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) bs58: 6.0.0 valtio: 1.13.2(@types/react@19.2.1)(react@19.2.3) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -19103,8 +13465,6 @@ snapshots: - utf-8-validate - zod - '@rolldown/pluginutils@1.0.0-beta.27': {} - '@rollup/rollup-android-arm-eabi@4.46.4': optional: true @@ -19167,8 +13527,6 @@ snapshots: '@rtsao/scc@1.1.0': {} - '@rushstack/eslint-patch@1.12.0': {} - '@safe-global/safe-apps-provider@0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) @@ -19179,9 +13537,9 @@ snapshots: - utf-8-validate - zod - '@safe-global/safe-apps-provider@0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@safe-global/safe-apps-provider@0.18.6(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) events: 3.3.0 transitivePeerDependencies: - bufferutil @@ -19192,17 +13550,17 @@ snapshots: '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@safe-global/safe-gateway-typescript-sdk': 3.23.1 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - bufferutil - typescript - utf-8-validate - zod - '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@safe-global/safe-gateway-typescript-sdk': 3.23.1 - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - bufferutil - typescript @@ -19248,37 +13606,23 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 - '@selderee/plugin-htmlparser2@0.11.0': - dependencies: - domhandler: 5.0.3 - selderee: 0.11.0 - - '@sindresorhus/is@4.6.0': {} - - '@smithy/is-array-buffer@2.2.0': + '@signinwithethereum/siwe-parser@4.2.0': dependencies: - tslib: 2.8.1 + '@noble/hashes': 1.8.0 + apg-js: 4.4.0 - '@smithy/types@4.3.2': + '@signinwithethereum/siwe@4.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: - tslib: 2.8.1 + '@signinwithethereum/siwe-parser': 4.2.0 + optionalDependencies: + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@smithy/util-buffer-from@2.2.0': - dependencies: - '@smithy/is-array-buffer': 2.2.0 - tslib: 2.8.1 + '@sinclair/typebox@0.27.10': {} - '@smithy/util-utf8@2.3.0': - dependencies: - '@smithy/util-buffer-from': 2.2.0 - tslib: 2.8.1 + '@sindresorhus/is@4.6.0': {} '@socket.io/component-emitter@3.1.2': {} - '@solana-program/compute-budget@0.11.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': - dependencies: - '@solana/kit': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/compute-budget@0.11.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) @@ -19287,22 +13631,17 @@ snapshots: dependencies: '@solana/kit': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@solana-program/system@0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': - dependencies: - '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/system@0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/token-2022@0.4.2(@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2))': + '@solana-program/system@0.8.1(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: - '@solana/kit': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@solana/sysvars': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) + '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/token-2022@0.6.1(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2))': + '@solana-program/token-2022@0.4.2(@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2))': dependencies: - '@solana/kit': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) '@solana/sysvars': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana-program/token-2022@0.6.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2))': @@ -19314,31 +13653,27 @@ snapshots: dependencies: '@solana/kit': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@solana-program/token@0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': - dependencies: - '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/token@0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/token@0.9.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + '@solana-program/token@0.6.0(@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: - '@solana/kit': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana-program/token@0.9.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: '@solana/kit': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/accounts@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/accounts@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-core': 2.3.0(typescript@5.9.2) - '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 2.3.0(typescript@5.9.2) - '@solana/rpc-spec': 2.3.0(typescript@5.9.2) - '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/rpc-spec': 2.3.0(typescript@5.9.3) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -19354,15 +13689,15 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/accounts@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/accounts@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/rpc-spec': 5.0.0(typescript@5.9.2) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -19378,6 +13713,18 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/accounts@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/accounts@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -19391,6 +13738,19 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/accounts@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-strings': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/rpc-spec': 6.1.0(typescript@5.9.3) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/addresses@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/assertions': 2.3.0(typescript@5.9.2) @@ -19402,6 +13762,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/addresses@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 2.3.0(typescript@5.9.3) + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/nominal-types': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/addresses@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/assertions': 3.0.3(typescript@5.9.2) @@ -19413,14 +13784,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/addresses@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/addresses@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/assertions': 5.0.0(typescript@5.9.2) - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/nominal-types': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/assertions': 3.0.3(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -19435,6 +13806,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/addresses@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 5.1.0(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/addresses@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/assertions': 6.1.0(typescript@5.9.2) @@ -19447,85 +13829,105 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/addresses@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 6.1.0(typescript@5.9.3) + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-strings': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/nominal-types': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/assertions@2.3.0(typescript@5.9.2)': dependencies: '@solana/errors': 2.3.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/assertions@2.3.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/assertions@3.0.3(typescript@5.9.2)': dependencies: '@solana/errors': 3.0.3(typescript@5.9.2) typescript: 5.9.2 - '@solana/assertions@5.0.0(typescript@5.9.2)': + '@solana/assertions@3.0.3(typescript@5.9.3)': dependencies: - '@solana/errors': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 '@solana/assertions@5.1.0(typescript@5.9.2)': dependencies: '@solana/errors': 5.1.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/assertions@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/assertions@6.1.0(typescript@5.9.2)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) optionalDependencies: typescript: 5.9.2 - '@solana/buffer-layout-utils@0.2.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)': + '@solana/assertions@6.1.0(typescript@5.9.3)': dependencies: - '@solana/buffer-layout': 4.0.1 - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - bigint-buffer: 1.1.5 - bignumber.js: 9.3.1 - transitivePeerDependencies: - - bufferutil - - encoding - - typescript - - utf-8-validate + '@solana/errors': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 '@solana/buffer-layout@4.0.1': dependencies: buffer: 6.0.3 - '@solana/codecs-core@2.0.0-rc.1(typescript@5.9.2)': - dependencies: - '@solana/errors': 2.0.0-rc.1(typescript@5.9.2) - typescript: 5.9.2 - '@solana/codecs-core@2.3.0(typescript@5.9.2)': dependencies: '@solana/errors': 2.3.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/codecs-core@2.3.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/codecs-core@3.0.3(typescript@5.9.2)': dependencies: '@solana/errors': 3.0.3(typescript@5.9.2) typescript: 5.9.2 - '@solana/codecs-core@5.0.0(typescript@5.9.2)': + '@solana/codecs-core@3.0.3(typescript@5.9.3)': dependencies: - '@solana/errors': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 '@solana/codecs-core@5.1.0(typescript@5.9.2)': dependencies: '@solana/errors': 5.1.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/codecs-core@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/codecs-core@6.1.0(typescript@5.9.2)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) optionalDependencies: typescript: 5.9.2 - '@solana/codecs-data-structures@2.0.0-rc.1(typescript@5.9.2)': + '@solana/codecs-core@6.1.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.9.2) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.9.2) - '@solana/errors': 2.0.0-rc.1(typescript@5.9.2) - typescript: 5.9.2 + '@solana/errors': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 '@solana/codecs-data-structures@2.3.0(typescript@5.9.2)': dependencies: @@ -19534,6 +13936,13 @@ snapshots: '@solana/errors': 2.3.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/codecs-data-structures@2.3.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/codecs-numbers': 2.3.0(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/codecs-data-structures@3.0.3(typescript@5.9.2)': dependencies: '@solana/codecs-core': 3.0.3(typescript@5.9.2) @@ -19541,12 +13950,12 @@ snapshots: '@solana/errors': 3.0.3(typescript@5.9.2) typescript: 5.9.2 - '@solana/codecs-data-structures@5.0.0(typescript@5.9.2)': + '@solana/codecs-data-structures@3.0.3(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/codecs-numbers': 5.0.0(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 '@solana/codecs-data-structures@5.1.0(typescript@5.9.2)': dependencies: @@ -19555,6 +13964,13 @@ snapshots: '@solana/errors': 5.1.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/codecs-data-structures@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/codecs-data-structures@6.1.0(typescript@5.9.2)': dependencies: '@solana/codecs-core': 6.1.0(typescript@5.9.2) @@ -19563,11 +13979,13 @@ snapshots: optionalDependencies: typescript: 5.9.2 - '@solana/codecs-numbers@2.0.0-rc.1(typescript@5.9.2)': + '@solana/codecs-data-structures@6.1.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.9.2) - '@solana/errors': 2.0.0-rc.1(typescript@5.9.2) - typescript: 5.9.2 + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.1.0(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 '@solana/codecs-numbers@2.3.0(typescript@5.9.2)': dependencies: @@ -19575,17 +13993,23 @@ snapshots: '@solana/errors': 2.3.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/codecs-numbers@2.3.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/codecs-numbers@3.0.3(typescript@5.9.2)': dependencies: '@solana/codecs-core': 3.0.3(typescript@5.9.2) '@solana/errors': 3.0.3(typescript@5.9.2) typescript: 5.9.2 - '@solana/codecs-numbers@5.0.0(typescript@5.9.2)': + '@solana/codecs-numbers@3.0.3(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 '@solana/codecs-numbers@5.1.0(typescript@5.9.2)': dependencies: @@ -19593,6 +14017,12 @@ snapshots: '@solana/errors': 5.1.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/codecs-numbers@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/codecs-numbers@6.1.0(typescript@5.9.2)': dependencies: '@solana/codecs-core': 6.1.0(typescript@5.9.2) @@ -19600,13 +14030,12 @@ snapshots: optionalDependencies: typescript: 5.9.2 - '@solana/codecs-strings@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/codecs-numbers@6.1.0(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.9.2) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.9.2) - '@solana/errors': 2.0.0-rc.1(typescript@5.9.2) - fastestsmallesttextencoderdecoder: 1.0.22 - typescript: 5.9.2 + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 '@solana/codecs-strings@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: @@ -19616,6 +14045,14 @@ snapshots: fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.9.2 + '@solana/codecs-strings@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/codecs-numbers': 2.3.0(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + fastestsmallesttextencoderdecoder: 1.0.22 + typescript: 5.9.3 + '@solana/codecs-strings@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/codecs-core': 3.0.3(typescript@5.9.2) @@ -19624,13 +14061,13 @@ snapshots: fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.9.2 - '@solana/codecs-strings@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/codecs-strings@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/codecs-numbers': 5.0.0(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) fastestsmallesttextencoderdecoder: 1.0.22 - typescript: 5.9.2 + typescript: 5.9.3 '@solana/codecs-strings@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: @@ -19641,6 +14078,15 @@ snapshots: optionalDependencies: fastestsmallesttextencoderdecoder: 1.0.22 + '@solana/codecs-strings@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + optionalDependencies: + fastestsmallesttextencoderdecoder: 1.0.22 + '@solana/codecs-strings@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/codecs-core': 6.1.0(typescript@5.9.2) @@ -19650,25 +14096,23 @@ snapshots: fastestsmallesttextencoderdecoder: 1.0.22 typescript: 5.9.2 - '@solana/codecs@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/codecs-strings@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.9.2) - '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.9.2) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.9.2) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/options': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.1.0(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + optionalDependencies: + fastestsmallesttextencoderdecoder: 1.0.22 + typescript: 5.9.3 - '@solana/codecs@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/codecs@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 2.3.0(typescript@5.9.2) - '@solana/codecs-data-structures': 2.3.0(typescript@5.9.2) - '@solana/codecs-numbers': 2.3.0(typescript@5.9.2) - '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/options': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/codecs-data-structures': 2.3.0(typescript@5.9.3) + '@solana/codecs-numbers': 2.3.0(typescript@5.9.3) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/options': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -19683,14 +14127,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/codecs@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/codecs@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/codecs-data-structures': 5.0.0(typescript@5.9.2) - '@solana/codecs-numbers': 5.0.0(typescript@5.9.2) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/options': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-data-structures': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/options': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -19705,6 +14149,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/codecs@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/options': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/codecs@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/codecs-core': 6.1.0(typescript@5.9.2) @@ -19717,11 +14172,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/errors@2.0.0-rc.1(typescript@5.9.2)': + '@solana/codecs@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - chalk: 5.6.2 - commander: 12.1.0 - typescript: 5.9.2 + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.1.0(typescript@5.9.3) + '@solana/codecs-strings': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/options': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder '@solana/errors@2.3.0(typescript@5.9.2)': dependencies: @@ -19729,17 +14190,23 @@ snapshots: commander: 14.0.3 typescript: 5.9.2 + '@solana/errors@2.3.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 14.0.3 + typescript: 5.9.3 + '@solana/errors@3.0.3(typescript@5.9.2)': dependencies: chalk: 5.6.2 commander: 14.0.0 typescript: 5.9.2 - '@solana/errors@5.0.0(typescript@5.9.2)': + '@solana/errors@3.0.3(typescript@5.9.3)': dependencies: chalk: 5.6.2 - commander: 14.0.1 - typescript: 5.9.2 + commander: 14.0.0 + typescript: 5.9.3 '@solana/errors@5.1.0(typescript@5.9.2)': dependencies: @@ -19747,6 +14214,12 @@ snapshots: commander: 14.0.2 typescript: 5.9.2 + '@solana/errors@5.1.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 14.0.2 + typescript: 5.9.3 + '@solana/errors@6.1.0(typescript@5.9.2)': dependencies: chalk: 5.6.2 @@ -19754,46 +14227,77 @@ snapshots: optionalDependencies: typescript: 5.9.2 + '@solana/errors@6.1.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 14.0.3 + optionalDependencies: + typescript: 5.9.3 + '@solana/fast-stable-stringify@2.3.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/fast-stable-stringify@2.3.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/fast-stable-stringify@3.0.3(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@solana/fast-stable-stringify@5.0.0(typescript@5.9.2)': + '@solana/fast-stable-stringify@3.0.3(typescript@5.9.3)': dependencies: - typescript: 5.9.2 + typescript: 5.9.3 '@solana/fast-stable-stringify@5.1.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/fast-stable-stringify@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/fast-stable-stringify@6.1.0(typescript@5.9.2)': optionalDependencies: typescript: 5.9.2 + '@solana/fast-stable-stringify@6.1.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + '@solana/functional@2.3.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/functional@2.3.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/functional@3.0.3(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@solana/functional@5.0.0(typescript@5.9.2)': + '@solana/functional@3.0.3(typescript@5.9.3)': dependencies: - typescript: 5.9.2 + typescript: 5.9.3 '@solana/functional@5.1.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/functional@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/functional@6.1.0(typescript@5.9.2)': optionalDependencies: typescript: 5.9.2 + '@solana/functional@6.1.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + '@solana/instruction-plans@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/errors': 3.0.3(typescript@5.9.2) @@ -19805,14 +14309,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/instruction-plans@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/instruction-plans@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/instructions': 5.0.0(typescript@5.9.2) - '@solana/promises': 5.0.0(typescript@5.9.2) - '@solana/transaction-messages': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/instructions': 3.0.3(typescript@5.9.3) + '@solana/promises': 3.0.3(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -19828,6 +14332,18 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/instruction-plans@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/instructions': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 5.1.0(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/instruction-plans@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) @@ -19841,23 +14357,42 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/instruction-plans@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/instructions': 6.1.0(typescript@5.9.3) + '@solana/keys': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 6.1.0(typescript@5.9.3) + '@solana/transaction-messages': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/instructions@2.3.0(typescript@5.9.2)': dependencies: '@solana/codecs-core': 2.3.0(typescript@5.9.2) '@solana/errors': 2.3.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/instructions@2.3.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/instructions@3.0.3(typescript@5.9.2)': dependencies: '@solana/codecs-core': 3.0.3(typescript@5.9.2) '@solana/errors': 3.0.3(typescript@5.9.2) typescript: 5.9.2 - '@solana/instructions@5.0.0(typescript@5.9.2)': + '@solana/instructions@3.0.3(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 '@solana/instructions@5.1.0(typescript@5.9.2)': dependencies: @@ -19865,6 +14400,12 @@ snapshots: '@solana/errors': 5.1.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/instructions@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/instructions@6.1.0(typescript@5.9.2)': dependencies: '@solana/codecs-core': 6.1.0(typescript@5.9.2) @@ -19872,6 +14413,13 @@ snapshots: optionalDependencies: typescript: 5.9.2 + '@solana/instructions@6.1.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + '@solana/keys@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/assertions': 2.3.0(typescript@5.9.2) @@ -19883,6 +14431,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/keys@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 2.3.0(typescript@5.9.3) + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/nominal-types': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/keys@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/assertions': 3.0.3(typescript@5.9.2) @@ -19894,14 +14453,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/keys@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/keys@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/assertions': 5.0.0(typescript@5.9.2) - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/nominal-types': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/assertions': 3.0.3(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -19916,6 +14475,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/keys@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 5.1.0(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/keys@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/assertions': 6.1.0(typescript@5.9.2) @@ -19923,60 +14493,46 @@ snapshots: '@solana/codecs-strings': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/errors': 6.1.0(typescript@5.9.2) '@solana/nominal-types': 6.1.0(typescript@5.9.2) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - '@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/accounts': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 2.3.0(typescript@5.9.2) - '@solana/functional': 2.3.0(typescript@5.9.2) - '@solana/instructions': 2.3.0(typescript@5.9.2) - '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/programs': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-parsed-types': 2.3.0(typescript@5.9.2) - '@solana/rpc-spec-types': 2.3.0(typescript@5.9.2) - '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/signers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/sysvars': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-confirmation': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - ws - - '@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/accounts': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 3.0.3(typescript@5.9.2) - '@solana/functional': 3.0.3(typescript@5.9.2) - '@solana/instruction-plans': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/instructions': 3.0.3(typescript@5.9.2) - '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/programs': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-parsed-types': 3.0.3(typescript@5.9.2) - '@solana/rpc-spec-types': 3.0.3(typescript@5.9.2) - '@solana/rpc-subscriptions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/signers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/sysvars': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-confirmation': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) + optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: - fastestsmallesttextencoderdecoder + + '@solana/keys@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/assertions': 6.1.0(typescript@5.9.3) + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-strings': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/nominal-types': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/kit@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/accounts': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/functional': 2.3.0(typescript@5.9.3) + '@solana/instructions': 2.3.0(typescript@5.9.3) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/programs': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 2.3.0(typescript@5.9.3) + '@solana/rpc-spec-types': 2.3.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/sysvars': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-confirmation': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder - ws '@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': @@ -20005,28 +14561,28 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/accounts': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/functional': 5.0.0(typescript@5.9.2) - '@solana/instruction-plans': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/instructions': 5.0.0(typescript@5.9.2) - '@solana/keys': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/programs': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-parsed-types': 5.0.0(typescript@5.9.2) - '@solana/rpc-spec-types': 5.0.0(typescript@5.9.2) - '@solana/rpc-subscriptions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/signers': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/sysvars': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-confirmation': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/transaction-messages': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/kit@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/accounts': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/instruction-plans': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/instructions': 3.0.3(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/programs': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-subscriptions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/sysvars': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-confirmation': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - ws @@ -20058,6 +14614,33 @@ snapshots: - fastestsmallesttextencoderdecoder - ws + '@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/accounts': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/instruction-plans': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/instructions': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/offchain-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/programs': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/sysvars': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-confirmation': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)': dependencies: '@solana/accounts': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20091,26 +14674,71 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate + '@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)': + dependencies: + '@solana/accounts': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/functional': 6.1.0(typescript@5.9.3) + '@solana/instruction-plans': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/instructions': 6.1.0(typescript@5.9.3) + '@solana/keys': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/offchain-messages': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/plugin-core': 6.1.0(typescript@5.9.3) + '@solana/plugin-interfaces': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/program-client-core': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/programs': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-api': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 6.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/sysvars': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-confirmation': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/transaction-messages': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + '@solana/nominal-types@2.3.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/nominal-types@2.3.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/nominal-types@3.0.3(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@solana/nominal-types@5.0.0(typescript@5.9.2)': + '@solana/nominal-types@3.0.3(typescript@5.9.3)': dependencies: - typescript: 5.9.2 + typescript: 5.9.3 '@solana/nominal-types@5.1.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/nominal-types@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/nominal-types@6.1.0(typescript@5.9.2)': optionalDependencies: typescript: 5.9.2 + '@solana/nominal-types@6.1.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + '@solana/offchain-messages@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20125,6 +14753,20 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/offchain-messages@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/offchain-messages@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20140,25 +14782,29 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/options@2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/offchain-messages@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 2.0.0-rc.1(typescript@5.9.2) - '@solana/codecs-data-structures': 2.0.0-rc.1(typescript@5.9.2) - '@solana/codecs-numbers': 2.0.0-rc.1(typescript@5.9.2) - '@solana/codecs-strings': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 2.0.0-rc.1(typescript@5.9.2) - typescript: 5.9.2 + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.1.0(typescript@5.9.3) + '@solana/codecs-strings': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/keys': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/options@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/options@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 2.3.0(typescript@5.9.2) - '@solana/codecs-data-structures': 2.3.0(typescript@5.9.2) - '@solana/codecs-numbers': 2.3.0(typescript@5.9.2) - '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 2.3.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/codecs-data-structures': 2.3.0(typescript@5.9.3) + '@solana/codecs-numbers': 2.3.0(typescript@5.9.3) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -20173,14 +14819,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/options@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/options@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/codecs-data-structures': 5.0.0(typescript@5.9.2) - '@solana/codecs-numbers': 5.0.0(typescript@5.9.2) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-data-structures': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -20195,6 +14841,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/options@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/options@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/codecs-core': 6.1.0(typescript@5.9.2) @@ -20207,10 +14864,26 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/options@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.1.0(typescript@5.9.3) + '@solana/codecs-strings': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/plugin-core@6.1.0(typescript@5.9.2)': optionalDependencies: typescript: 5.9.2 + '@solana/plugin-core@6.1.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + '@solana/plugin-interfaces@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20225,6 +14898,20 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/plugin-interfaces@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/instruction-plans': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keys': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-spec': 6.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.1.0(typescript@5.9.3) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/program-client-core@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/accounts': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20241,11 +14928,27 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/programs@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/program-client-core@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 2.3.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/accounts': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/instruction-plans': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/instructions': 6.1.0(typescript@5.9.3) + '@solana/plugin-interfaces': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-api': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/signers': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -20257,11 +14960,11 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/programs@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/programs@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -20273,6 +14976,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/programs@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/programs@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20282,26 +14993,47 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/programs@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/promises@2.3.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/promises@2.3.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/promises@3.0.3(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@solana/promises@5.0.0(typescript@5.9.2)': + '@solana/promises@3.0.3(typescript@5.9.3)': dependencies: - typescript: 5.9.2 + typescript: 5.9.3 '@solana/promises@5.1.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/promises@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/promises@6.1.0(typescript@5.9.2)': optionalDependencies: typescript: 5.9.2 + '@solana/promises@6.1.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + '@solana/rpc-api@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20319,6 +15051,23 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-api@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 2.3.0(typescript@5.9.3) + '@solana/rpc-spec': 2.3.0(typescript@5.9.3) + '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-api@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20336,20 +15085,20 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-api@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': - dependencies: - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/keys': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-parsed-types': 5.0.0(typescript@5.9.2) - '@solana/rpc-spec': 5.0.0(typescript@5.9.2) - '@solana/rpc-transformers': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-messages': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/rpc-api@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-transformers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -20370,6 +15119,23 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-api@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-api@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20388,63 +15154,111 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-api@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-strings': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/keys': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-parsed-types': 6.1.0(typescript@5.9.3) + '@solana/rpc-spec': 6.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-parsed-types@2.3.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/rpc-parsed-types@2.3.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/rpc-parsed-types@3.0.3(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@solana/rpc-parsed-types@5.0.0(typescript@5.9.2)': + '@solana/rpc-parsed-types@3.0.3(typescript@5.9.3)': dependencies: - typescript: 5.9.2 + typescript: 5.9.3 '@solana/rpc-parsed-types@5.1.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/rpc-parsed-types@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/rpc-parsed-types@6.1.0(typescript@5.9.2)': optionalDependencies: typescript: 5.9.2 + '@solana/rpc-parsed-types@6.1.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + '@solana/rpc-spec-types@2.3.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/rpc-spec-types@2.3.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/rpc-spec-types@3.0.3(typescript@5.9.2)': dependencies: typescript: 5.9.2 - '@solana/rpc-spec-types@5.0.0(typescript@5.9.2)': + '@solana/rpc-spec-types@3.0.3(typescript@5.9.3)': dependencies: - typescript: 5.9.2 + typescript: 5.9.3 '@solana/rpc-spec-types@5.1.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@solana/rpc-spec-types@5.1.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@solana/rpc-spec-types@6.1.0(typescript@5.9.2)': optionalDependencies: typescript: 5.9.2 + '@solana/rpc-spec-types@6.1.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + '@solana/rpc-spec@2.3.0(typescript@5.9.2)': dependencies: '@solana/errors': 2.3.0(typescript@5.9.2) '@solana/rpc-spec-types': 2.3.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/rpc-spec@2.3.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/rpc-spec-types': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/rpc-spec@3.0.3(typescript@5.9.2)': dependencies: '@solana/errors': 3.0.3(typescript@5.9.2) '@solana/rpc-spec-types': 3.0.3(typescript@5.9.2) typescript: 5.9.2 - '@solana/rpc-spec@5.0.0(typescript@5.9.2)': + '@solana/rpc-spec@3.0.3(typescript@5.9.3)': dependencies: - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/rpc-spec-types': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 '@solana/rpc-spec@5.1.0(typescript@5.9.2)': dependencies: @@ -20452,6 +15266,12 @@ snapshots: '@solana/rpc-spec-types': 5.1.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/rpc-spec@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/rpc-spec@6.1.0(typescript@5.9.2)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) @@ -20459,6 +15279,13 @@ snapshots: optionalDependencies: typescript: 5.9.2 + '@solana/rpc-spec@6.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + '@solana/rpc-subscriptions-api@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20472,6 +15299,19 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-subscriptions-api@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.9.3) + '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-subscriptions-api@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20485,16 +15325,16 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-api@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/rpc-subscriptions-api@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/keys': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions-spec': 5.0.0(typescript@5.9.2) - '@solana/rpc-transformers': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-messages': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-transformers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -20511,6 +15351,19 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-subscriptions-api@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-subscriptions-api@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20525,14 +15378,19 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-channel-websocket@2.3.0(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions-api@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/errors': 2.3.0(typescript@5.9.2) - '@solana/functional': 2.3.0(typescript@5.9.2) - '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.9.2) - '@solana/subscribable': 2.3.0(typescript@5.9.2) - typescript: 5.9.2 - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/keys': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder '@solana/rpc-subscriptions-channel-websocket@2.3.0(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: @@ -20543,14 +15401,14 @@ snapshots: typescript: 5.9.2 ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@solana/rpc-subscriptions-channel-websocket@3.0.3(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions-channel-websocket@2.3.0(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: - '@solana/errors': 3.0.3(typescript@5.9.2) - '@solana/functional': 3.0.3(typescript@5.9.2) - '@solana/rpc-subscriptions-spec': 3.0.3(typescript@5.9.2) - '@solana/subscribable': 3.0.3(typescript@5.9.2) - typescript: 5.9.2 - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/functional': 2.3.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.9.3) + '@solana/subscribable': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@solana/rpc-subscriptions-channel-websocket@3.0.3(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: @@ -20561,13 +15419,13 @@ snapshots: typescript: 5.9.2 ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@solana/rpc-subscriptions-channel-websocket@5.0.0(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions-channel-websocket@3.0.3(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/functional': 5.0.0(typescript@5.9.2) - '@solana/rpc-subscriptions-spec': 5.0.0(typescript@5.9.2) - '@solana/subscribable': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 3.0.3(typescript@5.9.3) + '@solana/subscribable': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@solana/rpc-subscriptions-channel-websocket@5.1.0(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': @@ -20580,6 +15438,16 @@ snapshots: optionalDependencies: ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/rpc-subscriptions-channel-websocket@5.1.0(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 5.1.0(typescript@5.9.3) + '@solana/subscribable': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + optionalDependencies: + ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@solana/rpc-subscriptions-channel-websocket@6.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) @@ -20593,6 +15461,19 @@ snapshots: - bufferutil - utf-8-validate + '@solana/rpc-subscriptions-channel-websocket@6.1.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)': + dependencies: + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/functional': 6.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.1.0(typescript@5.9.3) + '@solana/subscribable': 6.1.0(typescript@5.9.3) + ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@solana/rpc-subscriptions-spec@2.3.0(typescript@5.9.2)': dependencies: '@solana/errors': 2.3.0(typescript@5.9.2) @@ -20601,6 +15482,14 @@ snapshots: '@solana/subscribable': 2.3.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/rpc-subscriptions-spec@2.3.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/promises': 2.3.0(typescript@5.9.3) + '@solana/rpc-spec-types': 2.3.0(typescript@5.9.3) + '@solana/subscribable': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/rpc-subscriptions-spec@3.0.3(typescript@5.9.2)': dependencies: '@solana/errors': 3.0.3(typescript@5.9.2) @@ -20609,13 +15498,13 @@ snapshots: '@solana/subscribable': 3.0.3(typescript@5.9.2) typescript: 5.9.2 - '@solana/rpc-subscriptions-spec@5.0.0(typescript@5.9.2)': + '@solana/rpc-subscriptions-spec@3.0.3(typescript@5.9.3)': dependencies: - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/promises': 5.0.0(typescript@5.9.2) - '@solana/rpc-spec-types': 5.0.0(typescript@5.9.2) - '@solana/subscribable': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/promises': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + '@solana/subscribable': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 '@solana/rpc-subscriptions-spec@5.1.0(typescript@5.9.2)': dependencies: @@ -20625,6 +15514,14 @@ snapshots: '@solana/subscribable': 5.1.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/rpc-subscriptions-spec@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/promises': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + '@solana/subscribable': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/rpc-subscriptions-spec@6.1.0(typescript@5.9.2)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) @@ -20634,23 +15531,14 @@ snapshots: optionalDependencies: typescript: 5.9.2 - '@solana/rpc-subscriptions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions-spec@6.1.0(typescript@5.9.3)': dependencies: - '@solana/errors': 2.3.0(typescript@5.9.2) - '@solana/fast-stable-stringify': 2.3.0(typescript@5.9.2) - '@solana/functional': 2.3.0(typescript@5.9.2) - '@solana/promises': 2.3.0(typescript@5.9.2) - '@solana/rpc-spec-types': 2.3.0(typescript@5.9.2) - '@solana/rpc-subscriptions-api': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions-channel-websocket': 2.3.0(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.9.2) - '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/subscribable': 2.3.0(typescript@5.9.2) - typescript: 5.9.2 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - ws + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/promises': 6.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.1.0(typescript@5.9.3) + '@solana/subscribable': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 '@solana/rpc-subscriptions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: @@ -20670,20 +15558,20 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/rpc-subscriptions@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/errors': 3.0.3(typescript@5.9.2) - '@solana/fast-stable-stringify': 3.0.3(typescript@5.9.2) - '@solana/functional': 3.0.3(typescript@5.9.2) - '@solana/promises': 3.0.3(typescript@5.9.2) - '@solana/rpc-spec-types': 3.0.3(typescript@5.9.2) - '@solana/rpc-subscriptions-api': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions-channel-websocket': 3.0.3(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-subscriptions-spec': 3.0.3(typescript@5.9.2) - '@solana/rpc-transformers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/subscribable': 3.0.3(typescript@5.9.2) - typescript: 5.9.2 + '@solana/rpc-subscriptions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 2.3.0(typescript@5.9.3) + '@solana/functional': 2.3.0(typescript@5.9.3) + '@solana/promises': 2.3.0(typescript@5.9.3) + '@solana/rpc-spec-types': 2.3.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 2.3.0(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.9.3) + '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/subscribable': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - ws @@ -20706,20 +15594,20 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/rpc-subscriptions@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/fast-stable-stringify': 5.0.0(typescript@5.9.2) - '@solana/functional': 5.0.0(typescript@5.9.2) - '@solana/promises': 5.0.0(typescript@5.9.2) - '@solana/rpc-spec-types': 5.0.0(typescript@5.9.2) - '@solana/rpc-subscriptions-api': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions-channel-websocket': 5.0.0(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-subscriptions-spec': 5.0.0(typescript@5.9.2) - '@solana/rpc-transformers': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/subscribable': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/rpc-subscriptions@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/fast-stable-stringify': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/promises': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 3.0.3(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-transformers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/subscribable': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - ws @@ -20742,6 +15630,24 @@ snapshots: - fastestsmallesttextencoderdecoder - ws + '@solana/rpc-subscriptions@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/promises': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 5.1.0(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/subscribable': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/rpc-subscriptions@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) @@ -20762,6 +15668,26 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate + '@solana/rpc-subscriptions@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)': + dependencies: + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 6.1.0(typescript@5.9.3) + '@solana/functional': 6.1.0(typescript@5.9.3) + '@solana/promises': 6.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.1.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 6.1.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/rpc-subscriptions-spec': 6.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/subscribable': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + '@solana/rpc-transformers@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/errors': 2.3.0(typescript@5.9.2) @@ -20773,6 +15699,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-transformers@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/functional': 2.3.0(typescript@5.9.3) + '@solana/nominal-types': 2.3.0(typescript@5.9.3) + '@solana/rpc-spec-types': 2.3.0(typescript@5.9.3) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-transformers@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/errors': 3.0.3(typescript@5.9.2) @@ -20784,14 +15721,14 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-transformers@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/rpc-transformers@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/functional': 5.0.0(typescript@5.9.2) - '@solana/nominal-types': 5.0.0(typescript@5.9.2) - '@solana/rpc-spec-types': 5.0.0(typescript@5.9.2) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -20806,6 +15743,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-transformers@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-transformers@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) @@ -20818,6 +15766,18 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-transformers@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/functional': 6.1.0(typescript@5.9.3) + '@solana/nominal-types': 6.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.1.0(typescript@5.9.3) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-transport-http@2.3.0(typescript@5.9.2)': dependencies: '@solana/errors': 2.3.0(typescript@5.9.2) @@ -20826,6 +15786,14 @@ snapshots: typescript: 5.9.2 undici-types: 7.22.0 + '@solana/rpc-transport-http@2.3.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/rpc-spec': 2.3.0(typescript@5.9.3) + '@solana/rpc-spec-types': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + undici-types: 7.22.0 + '@solana/rpc-transport-http@3.0.3(typescript@5.9.2)': dependencies: '@solana/errors': 3.0.3(typescript@5.9.2) @@ -20834,13 +15802,13 @@ snapshots: typescript: 5.9.2 undici-types: 7.22.0 - '@solana/rpc-transport-http@5.0.0(typescript@5.9.2)': + '@solana/rpc-transport-http@3.0.3(typescript@5.9.3)': dependencies: - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/rpc-spec': 5.0.0(typescript@5.9.2) - '@solana/rpc-spec-types': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 - undici-types: 7.16.0 + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 + undici-types: 7.22.0 '@solana/rpc-transport-http@5.1.0(typescript@5.9.2)': dependencies: @@ -20848,7 +15816,15 @@ snapshots: '@solana/rpc-spec': 5.1.0(typescript@5.9.2) '@solana/rpc-spec-types': 5.1.0(typescript@5.9.2) typescript: 5.9.2 - undici-types: 7.16.0 + undici-types: 7.22.0 + + '@solana/rpc-transport-http@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + undici-types: 7.22.0 '@solana/rpc-transport-http@6.1.0(typescript@5.9.2)': dependencies: @@ -20859,6 +15835,15 @@ snapshots: optionalDependencies: typescript: 5.9.2 + '@solana/rpc-transport-http@6.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/rpc-spec': 6.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.1.0(typescript@5.9.3) + undici-types: 7.22.0 + optionalDependencies: + typescript: 5.9.3 + '@solana/rpc-types@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20871,6 +15856,18 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-types@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/codecs-numbers': 2.3.0(typescript@5.9.3) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/nominal-types': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-types@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20883,15 +15880,15 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-types@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/rpc-types@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/codecs-numbers': 5.0.0(typescript@5.9.2) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/nominal-types': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -20907,6 +15904,18 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-types@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc-types@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -20920,6 +15929,19 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc-types@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.1.0(typescript@5.9.3) + '@solana/codecs-strings': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/nominal-types': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/errors': 2.3.0(typescript@5.9.2) @@ -20935,6 +15957,21 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 2.3.0(typescript@5.9.3) + '@solana/functional': 2.3.0(typescript@5.9.3) + '@solana/rpc-api': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-spec': 2.3.0(typescript@5.9.3) + '@solana/rpc-spec-types': 2.3.0(typescript@5.9.3) + '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-transport-http': 2.3.0(typescript@5.9.3) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/errors': 3.0.3(typescript@5.9.2) @@ -20950,18 +15987,18 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': - dependencies: - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/fast-stable-stringify': 5.0.0(typescript@5.9.2) - '@solana/functional': 5.0.0(typescript@5.9.2) - '@solana/rpc-api': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-spec': 5.0.0(typescript@5.9.2) - '@solana/rpc-spec-types': 5.0.0(typescript@5.9.2) - '@solana/rpc-transformers': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-transport-http': 5.0.0(typescript@5.9.2) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/rpc@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/fast-stable-stringify': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/rpc-api': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-spec': 3.0.3(typescript@5.9.3) + '@solana/rpc-spec-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-transformers': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-transport-http': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -20980,6 +16017,21 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/rpc@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/rpc-api': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-spec': 5.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-transport-http': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/rpc@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) @@ -20996,17 +16048,33 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/signers@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': - dependencies: - '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-core': 2.3.0(typescript@5.9.2) - '@solana/errors': 2.3.0(typescript@5.9.2) - '@solana/instructions': 2.3.0(typescript@5.9.2) - '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/nominal-types': 2.3.0(typescript@5.9.2) - '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/rpc@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 6.1.0(typescript@5.9.3) + '@solana/functional': 6.1.0(typescript@5.9.3) + '@solana/rpc-api': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-spec': 6.1.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.1.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-transport-http': 6.1.0(typescript@5.9.3) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/instructions': 2.3.0(typescript@5.9.3) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 2.3.0(typescript@5.9.3) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -21024,17 +16092,17 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/signers@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/signers@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/instructions': 5.0.0(typescript@5.9.2) - '@solana/keys': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/nominal-types': 5.0.0(typescript@5.9.2) - '@solana/transaction-messages': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/instructions': 3.0.3(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -21053,6 +16121,21 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/signers@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/instructions': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + '@solana/offchain-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/signers@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -21069,70 +16152,71 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/spl-token-group@0.0.7(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': - dependencies: - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - typescript - - '@solana/spl-token-metadata@0.1.6(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': - dependencies: - '@solana/codecs': 2.0.0-rc.1(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - typescript - - '@solana/spl-token@0.4.13(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)': + '@solana/signers@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/buffer-layout': 4.0.1 - '@solana/buffer-layout-utils': 0.2.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@solana/spl-token-group': 0.0.7(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/spl-token-metadata': 0.1.6(@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10))(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/web3.js': 1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10) - buffer: 6.0.3 + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/instructions': 6.1.0(typescript@5.9.3) + '@solana/keys': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 6.1.0(typescript@5.9.3) + '@solana/offchain-messages': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 transitivePeerDependencies: - - bufferutil - - encoding - fastestsmallesttextencoderdecoder - - typescript - - utf-8-validate '@solana/subscribable@2.3.0(typescript@5.9.2)': dependencies: '@solana/errors': 2.3.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/subscribable@2.3.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 2.3.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/subscribable@3.0.3(typescript@5.9.2)': dependencies: '@solana/errors': 3.0.3(typescript@5.9.2) typescript: 5.9.2 - '@solana/subscribable@5.0.0(typescript@5.9.2)': + '@solana/subscribable@3.0.3(typescript@5.9.3)': dependencies: - '@solana/errors': 5.0.0(typescript@5.9.2) - typescript: 5.9.2 + '@solana/errors': 3.0.3(typescript@5.9.3) + typescript: 5.9.3 '@solana/subscribable@5.1.0(typescript@5.9.2)': dependencies: '@solana/errors': 5.1.0(typescript@5.9.2) typescript: 5.9.2 + '@solana/subscribable@5.1.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.1.0(typescript@5.9.3) + typescript: 5.9.3 + '@solana/subscribable@6.1.0(typescript@5.9.2)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) optionalDependencies: typescript: 5.9.2 - '@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/subscribable@6.1.0(typescript@5.9.3)': dependencies: - '@solana/accounts': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 2.3.0(typescript@5.9.2) - '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/errors': 6.1.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/sysvars@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/accounts': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -21146,13 +16230,13 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/sysvars@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': + '@solana/sysvars@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/accounts': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/accounts': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -21166,6 +16250,16 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/sysvars@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/accounts': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/accounts': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -21177,22 +16271,16 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-confirmation@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': dependencies: - '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 2.3.0(typescript@5.9.2) - '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/promises': 2.3.0(typescript@5.9.2) - '@solana/rpc': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/accounts': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - - ws '@solana/transaction-confirmation@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: @@ -21211,19 +16299,19 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/transaction-confirmation@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/transaction-confirmation@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: - '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 3.0.3(typescript@5.9.2) - '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/promises': 3.0.3(typescript@5.9.2) - '@solana/rpc': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 2.3.0(typescript@5.9.3) + '@solana/rpc': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - ws @@ -21245,19 +16333,19 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/transaction-confirmation@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/keys': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/promises': 5.0.0(typescript@5.9.2) - '@solana/rpc': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-messages': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/transaction-confirmation@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 3.0.3(typescript@5.9.3) + '@solana/rpc': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder - ws @@ -21279,6 +16367,23 @@ snapshots: - fastestsmallesttextencoderdecoder - ws + '@solana/transaction-confirmation@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 5.1.0(typescript@5.9.3) + '@solana/rpc': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - ws + '@solana/transaction-confirmation@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -21298,6 +16403,25 @@ snapshots: - fastestsmallesttextencoderdecoder - utf-8-validate + '@solana/transaction-confirmation@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10)': + dependencies: + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-strings': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/keys': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/promises': 6.1.0(typescript@5.9.3) + '@solana/rpc': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/rpc-subscriptions': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)(utf-8-validate@5.0.10) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transactions': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + '@solana/transaction-messages@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -21313,6 +16437,21 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transaction-messages@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/codecs-data-structures': 2.3.0(typescript@5.9.3) + '@solana/codecs-numbers': 2.3.0(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/functional': 2.3.0(typescript@5.9.3) + '@solana/instructions': 2.3.0(typescript@5.9.3) + '@solana/nominal-types': 2.3.0(typescript@5.9.3) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/transaction-messages@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -21328,18 +16467,18 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-messages@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': - dependencies: - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/codecs-data-structures': 5.0.0(typescript@5.9.2) - '@solana/codecs-numbers': 5.0.0(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/functional': 5.0.0(typescript@5.9.2) - '@solana/instructions': 5.0.0(typescript@5.9.2) - '@solana/nominal-types': 5.0.0(typescript@5.9.2) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/transaction-messages@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-data-structures': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/instructions': 3.0.3(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -21358,6 +16497,21 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transaction-messages@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/instructions': 5.1.0(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/transaction-messages@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -21374,6 +16528,22 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transaction-messages@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.1.0(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/functional': 6.1.0(typescript@5.9.3) + '@solana/instructions': 6.1.0(typescript@5.9.3) + '@solana/nominal-types': 6.1.0(typescript@5.9.3) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/transactions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -21392,6 +16562,24 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transactions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 2.3.0(typescript@5.9.3) + '@solana/codecs-data-structures': 2.3.0(typescript@5.9.3) + '@solana/codecs-numbers': 2.3.0(typescript@5.9.3) + '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 2.3.0(typescript@5.9.3) + '@solana/functional': 2.3.0(typescript@5.9.3) + '@solana/instructions': 2.3.0(typescript@5.9.3) + '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 2.3.0(typescript@5.9.3) + '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/transactions@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -21410,21 +16598,21 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transactions@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': - dependencies: - '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-core': 5.0.0(typescript@5.9.2) - '@solana/codecs-data-structures': 5.0.0(typescript@5.9.2) - '@solana/codecs-numbers': 5.0.0(typescript@5.9.2) - '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.0.0(typescript@5.9.2) - '@solana/functional': 5.0.0(typescript@5.9.2) - '@solana/instructions': 5.0.0(typescript@5.9.2) - '@solana/keys': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/nominal-types': 5.0.0(typescript@5.9.2) - '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-messages': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 + '@solana/transactions@3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 3.0.3(typescript@5.9.3) + '@solana/codecs-data-structures': 3.0.3(typescript@5.9.3) + '@solana/codecs-numbers': 3.0.3(typescript@5.9.3) + '@solana/codecs-strings': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 3.0.3(typescript@5.9.3) + '@solana/functional': 3.0.3(typescript@5.9.3) + '@solana/instructions': 3.0.3(typescript@5.9.3) + '@solana/keys': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 3.0.3(typescript@5.9.3) + '@solana/rpc-types': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 3.0.3(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - fastestsmallesttextencoderdecoder @@ -21446,6 +16634,24 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transactions@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 5.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 5.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 5.1.0(typescript@5.9.3) + '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 5.1.0(typescript@5.9.3) + '@solana/functional': 5.1.0(typescript@5.9.3) + '@solana/instructions': 5.1.0(typescript@5.9.3) + '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 5.1.0(typescript@5.9.3) + '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/transactions@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -21465,12 +16671,31 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder + '@solana/transactions@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/codecs-core': 6.1.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.1.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.1.0(typescript@5.9.3) + '@solana/codecs-strings': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/errors': 6.1.0(typescript@5.9.3) + '@solana/functional': 6.1.0(typescript@5.9.3) + '@solana/instructions': 6.1.0(typescript@5.9.3) + '@solana/keys': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/nominal-types': 6.1.0(typescript@5.9.3) + '@solana/rpc-types': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + '@solana/transaction-messages': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + '@solana/wallet-standard-features@1.3.0': dependencies: '@wallet-standard/base': 1.1.0 '@wallet-standard/features': 1.1.0 - '@solana/web3.js@1.98.4(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)': + '@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)': dependencies: '@babel/runtime': 7.28.3 '@noble/curves': 1.9.7 @@ -21484,7 +16709,7 @@ snapshots: buffer: 6.0.3 fast-stable-stringify: 1.0.0 jayson: 4.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - node-fetch: 2.7.0(encoding@0.1.13) + node-fetch: 2.7.0 rpc-websockets: 9.1.3 superstruct: 2.0.2 transitivePeerDependencies: @@ -21493,27 +16718,28 @@ snapshots: - typescript - utf-8-validate - '@spruceid/siwe-parser@2.1.2': + '@solana/web3.js@1.98.4(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)': dependencies: + '@babel/runtime': 7.28.3 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 - apg-js: 4.4.0 - uri-js: 4.4.1 - valid-url: 1.0.9 - - '@stablelib/base64@1.0.1': {} - - '@stablelib/binary@1.0.1': - dependencies: - '@stablelib/int': 1.0.1 - - '@stablelib/int@1.0.1': {} - - '@stablelib/random@1.0.2': - dependencies: - '@stablelib/binary': 1.0.1 - '@stablelib/wipe': 1.0.1 - - '@stablelib/wipe@1.0.1': {} + '@solana/buffer-layout': 4.0.1 + '@solana/codecs-numbers': 2.3.0(typescript@5.9.3) + agentkeepalive: 4.6.0 + bn.js: 5.2.2 + borsh: 0.7.0 + bs58: 4.0.1 + buffer: 6.0.3 + fast-stable-stringify: 1.0.0 + jayson: 4.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + node-fetch: 2.7.0 + rpc-websockets: 9.1.3 + superstruct: 2.0.2 + transitivePeerDependencies: + - bufferutil + - encoding + - typescript + - utf-8-validate '@stellar/js-xdr@3.1.2': {} @@ -21540,99 +16766,6 @@ snapshots: transitivePeerDependencies: - debug - '@svgr/babel-plugin-add-jsx-attribute@8.0.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - - '@svgr/babel-plugin-remove-jsx-attribute@8.0.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - - '@svgr/babel-plugin-remove-jsx-empty-expression@8.0.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - - '@svgr/babel-plugin-replace-jsx-attribute-value@8.0.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - - '@svgr/babel-plugin-svg-dynamic-title@8.0.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - - '@svgr/babel-plugin-svg-em-dimensions@8.0.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - - '@svgr/babel-plugin-transform-react-native-svg@8.1.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - - '@svgr/babel-plugin-transform-svg-component@8.0.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - - '@svgr/babel-preset@8.1.0(@babel/core@7.28.3)': - dependencies: - '@babel/core': 7.28.3 - '@svgr/babel-plugin-add-jsx-attribute': 8.0.0(@babel/core@7.28.3) - '@svgr/babel-plugin-remove-jsx-attribute': 8.0.0(@babel/core@7.28.3) - '@svgr/babel-plugin-remove-jsx-empty-expression': 8.0.0(@babel/core@7.28.3) - '@svgr/babel-plugin-replace-jsx-attribute-value': 8.0.0(@babel/core@7.28.3) - '@svgr/babel-plugin-svg-dynamic-title': 8.0.0(@babel/core@7.28.3) - '@svgr/babel-plugin-svg-em-dimensions': 8.0.0(@babel/core@7.28.3) - '@svgr/babel-plugin-transform-react-native-svg': 8.1.0(@babel/core@7.28.3) - '@svgr/babel-plugin-transform-svg-component': 8.0.0(@babel/core@7.28.3) - - '@svgr/core@8.1.0(typescript@5.9.2)': - dependencies: - '@babel/core': 7.28.3 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.3) - camelcase: 6.3.0 - cosmiconfig: 8.3.6(typescript@5.9.2) - snake-case: 3.0.4 - transitivePeerDependencies: - - supports-color - - typescript - - '@svgr/hast-util-to-babel-ast@8.0.0': - dependencies: - '@babel/types': 7.28.2 - entities: 4.5.0 - - '@svgr/plugin-jsx@8.1.0(@svgr/core@8.1.0(typescript@5.9.2))': - dependencies: - '@babel/core': 7.28.3 - '@svgr/babel-preset': 8.1.0(@babel/core@7.28.3) - '@svgr/core': 8.1.0(typescript@5.9.2) - '@svgr/hast-util-to-babel-ast': 8.0.0 - svg-parser: 2.0.4 - transitivePeerDependencies: - - supports-color - - '@svgr/plugin-svgo@8.1.0(@svgr/core@8.1.0(typescript@5.9.2))(typescript@5.9.2)': - dependencies: - '@svgr/core': 8.1.0(typescript@5.9.2) - cosmiconfig: 8.3.6(typescript@5.9.2) - deepmerge: 4.3.1 - svgo: 3.3.2 - transitivePeerDependencies: - - typescript - - '@svgr/webpack@8.1.0(typescript@5.9.2)': - dependencies: - '@babel/core': 7.28.3 - '@babel/plugin-transform-react-constant-elements': 7.27.1(@babel/core@7.28.3) - '@babel/preset-env': 7.28.3(@babel/core@7.28.3) - '@babel/preset-react': 7.27.1(@babel/core@7.28.3) - '@babel/preset-typescript': 7.27.1(@babel/core@7.28.3) - '@svgr/core': 8.1.0(typescript@5.9.2) - '@svgr/plugin-jsx': 8.1.0(@svgr/core@8.1.0(typescript@5.9.2)) - '@svgr/plugin-svgo': 8.1.0(@svgr/core@8.1.0(typescript@5.9.2))(typescript@5.9.2) - transitivePeerDependencies: - - supports-color - - typescript - '@swc/helpers@0.5.15': dependencies: tslib: 2.8.1 @@ -21721,45 +16854,37 @@ snapshots: '@tanstack/query-core': 5.90.11 react: 19.1.1 - '@tanstack/react-query@5.90.11(react@19.2.1)': - dependencies: - '@tanstack/query-core': 5.90.11 - react: 19.2.1 - '@tanstack/react-query@5.90.11(react@19.2.3)': dependencies: '@tanstack/query-core': 5.90.11 react: 19.2.3 - '@tootallnate/once@2.0.0': {} + '@tanstack/store@0.8.0': {} - '@trysound/sax@0.2.0': {} + '@tsconfig/node10@1.0.12': {} - '@tybys/wasm-util@0.10.0': - dependencies: - tslib: 2.8.1 - optional: true + '@tsconfig/node12@1.0.11': {} - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 + '@tsconfig/node14@1.0.3': {} - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.28.2 + '@tsconfig/node16@1.0.4': {} - '@types/babel__template@7.4.4': + '@txnlab/use-wallet@4.6.0(@blockshake/defly-connect@1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@perawallet/connect@1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@walletconnect/sign-client@2.23.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(algosdk@3.5.2)(lute-connect@1.7.0)': dependencies: - '@babel/parser': 7.28.3 - '@babel/types': 7.28.2 + '@tanstack/store': 0.8.0 + algosdk: 3.5.2 + optionalDependencies: + '@blockshake/defly-connect': 1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@perawallet/connect': 1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/sign-client': 2.23.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + lute-connect: 1.7.0 - '@types/babel__traverse@7.28.0': + '@tybys/wasm-util@0.10.0': dependencies: - '@babel/types': 7.28.2 + tslib: 2.8.1 + optional: true + + '@types/aws-lambda@8.10.161': {} '@types/body-parser@1.19.6': dependencies: @@ -21816,14 +16941,20 @@ snapshots: '@types/express-serve-static-core': 5.0.7 '@types/serve-static': 1.15.8 - '@types/fs-extra@9.0.13': - dependencies: - '@types/node': 22.17.2 - '@types/http-cache-semantics@4.0.4': {} '@types/http-errors@2.0.5': {} + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} @@ -21832,8 +16963,6 @@ snapshots: dependencies: '@types/node': 22.17.2 - '@types/lodash@4.17.20': {} - '@types/mime@1.3.5': {} '@types/ms@2.1.0': {} @@ -21849,38 +16978,14 @@ snapshots: dependencies: undici-types: 5.26.5 - '@types/node@20.19.11': - dependencies: - undici-types: 6.21.0 - '@types/node@22.17.2': dependencies: undici-types: 6.21.0 - '@types/node@22.7.5': - dependencies: - undici-types: 6.19.8 - - '@types/node@24.3.0': - dependencies: - undici-types: 7.10.0 - - '@types/plist@3.0.5': - dependencies: - '@types/node': 22.17.2 - xmlbuilder: 15.1.1 - optional: true - - '@types/prop-types@15.7.15': {} - '@types/qs@6.14.0': {} '@types/range-parser@1.2.7': {} - '@types/react-dom@18.3.7(@types/react@18.3.27)': - dependencies: - '@types/react': 18.3.27 - '@types/react-dom@19.1.7(@types/react@19.1.10)': dependencies: '@types/react': 19.1.10 @@ -21889,11 +16994,6 @@ snapshots: dependencies: '@types/react': 19.2.1 - '@types/react@18.3.27': - dependencies: - '@types/prop-types': 15.7.15 - csstype: 3.2.3 - '@types/react@19.1.10': dependencies: csstype: 3.2.3 @@ -21906,10 +17006,6 @@ snapshots: dependencies: '@types/node': 22.17.2 - '@types/retry@0.12.0': {} - - '@types/retry@0.12.2': {} - '@types/send@0.17.5': dependencies: '@types/mime': 1.3.5 @@ -21921,17 +17017,10 @@ snapshots: '@types/node': 22.17.2 '@types/send': 0.17.5 - '@types/triple-beam@1.3.5': {} - '@types/trusted-types@2.0.7': {} - '@types/uuid@10.0.0': {} - '@types/uuid@8.3.4': {} - '@types/verror@1.10.11': - optional: true - '@types/ws@7.4.7': dependencies: '@types/node': 22.17.2 @@ -21940,37 +17029,55 @@ snapshots: dependencies: '@types/node': 22.17.2 - '@types/yauzl@2.10.3': + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': dependencies: - '@types/node': 22.17.2 - optional: true + '@types/yargs-parser': 21.0.3 '@typescript-eslint/eslint-plugin@8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/scope-manager': 8.40.0 + '@typescript-eslint/type-utils': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/visitor-keys': 8.40.0 + eslint: 9.33.0(jiti@2.6.1) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.2) + typescript: 5.9.2 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/eslint-plugin@8.40.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.40.0 - '@typescript-eslint/type-utils': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/utils': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.40.0 eslint: 9.33.0(jiti@2.6.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.48.0(eslint@8.57.1)(typescript@5.9.2) + '@typescript-eslint/parser': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/type-utils': 8.48.0(eslint@8.57.1)(typescript@5.9.2) - '@typescript-eslint/utils': 8.48.0(eslint@8.57.1)(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/utils': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.48.0 - eslint: 8.57.1 + eslint: 9.33.0(jiti@2.6.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 @@ -21979,20 +17086,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2)': + '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@eslint-community/regexpp': 4.12.1 - '@typescript-eslint/parser': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/type-utils': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/utils': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/type-utils': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.48.0 eslint: 9.33.0(jiti@2.6.1) graphemer: 1.4.0 ignore: 7.0.5 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -22008,27 +17115,39 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2)': + '@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.40.0 + '@typescript-eslint/types': 8.40.0 + '@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.40.0 + debug: 4.4.1 + eslint: 9.33.0(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2)': dependencies: '@typescript-eslint/scope-manager': 8.48.0 '@typescript-eslint/types': 8.48.0 '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.2) '@typescript-eslint/visitor-keys': 8.48.0 debug: 4.4.1 - eslint: 8.57.1 + eslint: 9.33.0(jiti@2.6.1) typescript: 5.9.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2)': + '@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: '@typescript-eslint/scope-manager': 8.48.0 '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.2) + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) '@typescript-eslint/visitor-keys': 8.48.0 debug: 4.4.1 eslint: 9.33.0(jiti@2.6.1) - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -22041,6 +17160,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.40.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.40.0(typescript@5.9.3) + '@typescript-eslint/types': 8.48.0 + debug: 4.4.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/project-service@8.48.0(typescript@5.9.2)': dependencies: '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.2) @@ -22050,6 +17178,15 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/project-service@8.48.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) + '@typescript-eslint/types': 8.48.0 + debug: 4.4.1 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/scope-manager@8.40.0': dependencies: '@typescript-eslint/types': 8.40.0 @@ -22064,10 +17201,18 @@ snapshots: dependencies: typescript: 5.9.2 + '@typescript-eslint/tsconfig-utils@8.40.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@typescript-eslint/tsconfig-utils@8.48.0(typescript@5.9.2)': dependencies: typescript: 5.9.2 + '@typescript-eslint/tsconfig-utils@8.48.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + '@typescript-eslint/type-utils@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2)': dependencies: '@typescript-eslint/types': 8.40.0 @@ -22080,15 +17225,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/type-utils@8.48.0(eslint@8.57.1)(typescript@5.9.2)': + '@typescript-eslint/type-utils@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.48.0(eslint@8.57.1)(typescript@5.9.2) + '@typescript-eslint/types': 8.40.0 + '@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) debug: 4.4.1 - eslint: 8.57.1 - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 + eslint: 9.33.0(jiti@2.6.1) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - supports-color @@ -22104,6 +17249,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@typescript-eslint/type-utils@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.1 + eslint: 9.33.0(jiti@2.6.1) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + '@typescript-eslint/types@8.40.0': {} '@typescript-eslint/types@8.48.0': {} @@ -22124,559 +17281,219 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@8.48.0(typescript@5.9.2)': + '@typescript-eslint/typescript-estree@8.40.0(typescript@5.9.3)': dependencies: - '@typescript-eslint/project-service': 8.48.0(typescript@5.9.2) - '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.2) - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/visitor-keys': 8.48.0 + '@typescript-eslint/project-service': 8.40.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.40.0(typescript@5.9.3) + '@typescript-eslint/types': 8.40.0 + '@typescript-eslint/visitor-keys': 8.40.0 debug: 4.4.1 + fast-glob: 3.3.3 + is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.7.3 - tinyglobby: 0.2.15 - ts-api-utils: 2.1.0(typescript@5.9.2) - typescript: 5.9.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2)': - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.40.0 - '@typescript-eslint/types': 8.40.0 - '@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.2) - eslint: 9.33.0(jiti@2.6.1) - typescript: 5.9.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.48.0(eslint@8.57.1)(typescript@5.9.2)': - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) - '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.2) - eslint: 8.57.1 - typescript: 5.9.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2)': - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.2) - eslint: 9.33.0(jiti@2.6.1) - typescript: 5.9.2 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.40.0': - dependencies: - '@typescript-eslint/types': 8.40.0 - eslint-visitor-keys: 4.2.1 - - '@typescript-eslint/visitor-keys@8.48.0': - dependencies: - '@typescript-eslint/types': 8.48.0 - eslint-visitor-keys: 4.2.1 - - '@ungap/structured-clone@1.3.0': {} - - '@unrs/resolver-binding-android-arm-eabi@1.11.1': - optional: true - - '@unrs/resolver-binding-android-arm64@1.11.1': - optional: true - - '@unrs/resolver-binding-darwin-arm64@1.11.1': - optional: true - - '@unrs/resolver-binding-darwin-x64@1.11.1': - optional: true - - '@unrs/resolver-binding-freebsd-x64@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-arm64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-x64-gnu@1.11.1': - optional: true - - '@unrs/resolver-binding-linux-x64-musl@1.11.1': - optional: true - - '@unrs/resolver-binding-wasm32-wasi@1.11.1': - dependencies: - '@napi-rs/wasm-runtime': 0.2.12 - optional: true - - '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': - optional: true - - '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': - optional: true - - '@unrs/resolver-binding-win32-x64-msvc@1.11.1': - optional: true - - '@upstash/redis@1.35.3': - dependencies: - uncrypto: 0.1.3 - - '@vitejs/plugin-react@4.7.0(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1))': - dependencies: - '@babel/core': 7.28.3 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.3) - '@rolldown/pluginutils': 1.0.0-beta.27 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - transitivePeerDependencies: - - supports-color - - '@vitejs/plugin-react@4.7.0(vite@7.1.3(@types/node@24.3.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1))': - dependencies: - '@babel/core': 7.28.3 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.3) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.3) - '@rolldown/pluginutils': 1.0.0-beta.27 - '@types/babel__core': 7.20.5 - react-refresh: 0.17.0 - vite: 7.1.3(@types/node@24.3.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - transitivePeerDependencies: - - supports-color - - '@vitest/expect@3.2.4': - dependencies: - '@types/chai': 5.2.2 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.1 - tinyrainbow: 2.0.0 - - '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1))': - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.17 - optionalDependencies: - vite: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - - '@vitest/pretty-format@3.2.4': - dependencies: - tinyrainbow: 2.0.0 - - '@vitest/runner@3.2.4': - dependencies: - '@vitest/utils': 3.2.4 - pathe: 2.0.3 - strip-literal: 3.0.0 - - '@vitest/snapshot@3.2.4': - dependencies: - '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.17 - pathe: 2.0.3 - - '@vitest/spy@3.2.4': - dependencies: - tinyspy: 4.0.3 - - '@vitest/utils@3.2.4': - dependencies: - '@vitest/pretty-format': 3.2.4 - loupe: 3.2.0 - tinyrainbow: 2.0.0 - - '@wagmi/connectors@5.9.4(@types/react@19.1.10)(@upstash/redis@1.35.3)(@wagmi/core@2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': - dependencies: - '@base-org/account': 1.1.1(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@gemini-wallet/core': 0.2.0(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@metamask/sdk': 0.32.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - immer - - ioredis - - react + semver: 7.7.2 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: - supports-color - - uploadthing - - use-sync-external-store - - utf-8-validate - - zod - '@wagmi/connectors@5.9.4(@types/react@19.1.10)(@upstash/redis@1.35.3)(@wagmi/core@2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': + '@typescript-eslint/typescript-estree@8.48.0(typescript@5.9.2)': dependencies: - '@base-org/account': 1.1.1(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@gemini-wallet/core': 0.2.0(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@metamask/sdk': 0.32.0(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - optionalDependencies: + '@typescript-eslint/project-service': 8.48.0(typescript@5.9.2) + '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.2) + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/visitor-keys': 8.48.0 + debug: 4.4.1 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.1.0(typescript@5.9.2) typescript: 5.9.2 transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - immer - - ioredis - - react - supports-color - - uploadthing - - use-sync-external-store - - utf-8-validate - - zod - '@wagmi/connectors@6.2.0(1aee367860625464d156864b651beb8c)': + '@typescript-eslint/typescript-estree@8.48.0(typescript@5.9.3)': dependencies: - '@base-org/account': 2.4.0(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.1.13) - '@gemini-wallet/core': 0.3.2(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - optionalDependencies: - typescript: 5.9.2 + '@typescript-eslint/project-service': 8.48.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/visitor-keys': 8.48.0 + debug: 4.4.1 + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - react-native - supports-color - - uploadthing - - use-sync-external-store - - utf-8-validate - - wagmi - - ws - - zod - '@wagmi/connectors@6.2.0(26b6de6e2b894d3d8ec3de3fd9d7a34e)': + '@typescript-eslint/utils@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2)': dependencies: - '@base-org/account': 2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.1.13) - '@gemini-wallet/core': 0.3.2(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - optionalDependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.40.0 + '@typescript-eslint/types': 8.40.0 + '@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.2) + eslint: 9.33.0(jiti@2.6.1) typescript: 5.9.2 transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - react-native - supports-color - - uploadthing - - use-sync-external-store - - utf-8-validate - - wagmi - - ws - - zod - '@wagmi/connectors@6.2.0(7c0fb5ad6e91c192e500875cd884eb4c)': + '@typescript-eslint/utils@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3)': dependencies: - '@base-org/account': 2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@gemini-wallet/core': 0.3.2(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.1.1))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.1.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - optionalDependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.40.0 + '@typescript-eslint/types': 8.40.0 + '@typescript-eslint/typescript-estree': 8.40.0(typescript@5.9.3) + eslint: 9.33.0(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2)': + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.48.0 + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.2) + eslint: 9.33.0(jiti@2.6.1) typescript: 5.9.2 transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - react-native - supports-color - - uploadthing - - use-sync-external-store - - utf-8-validate - - wagmi - - ws - - zod - '@wagmi/connectors@6.2.0(826cb7847d3729c23c5bbd1840c9486a)': + '@typescript-eslint/utils@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.48.0 + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + eslint: 9.33.0(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.40.0': + dependencies: + '@typescript-eslint/types': 8.40.0 + eslint-visitor-keys: 4.2.1 + + '@typescript-eslint/visitor-keys@8.48.0': + dependencies: + '@typescript-eslint/types': 8.48.0 + eslint-visitor-keys: 4.2.1 + + '@unrs/resolver-binding-android-arm-eabi@1.11.1': + optional: true + + '@unrs/resolver-binding-android-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.11.1': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.11.1': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.11.1': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.11.1': + dependencies: + '@napi-rs/wasm-runtime': 0.2.12 + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.11.1': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.11.1': + optional: true + + '@vitest/expect@3.2.4': dependencies: - '@base-org/account': 2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@gemini-wallet/core': 0.3.2(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - react-native - - supports-color - - uploadthing - - use-sync-external-store - - utf-8-validate - - wagmi - - ws - - zod + '@types/chai': 5.2.2 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.1 + tinyrainbow: 2.0.0 - '@wagmi/connectors@6.2.0(87f53a8d2b85f9075dbb2195dfb00723)': + '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1))': dependencies: - '@base-org/account': 2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.1.13) - '@gemini-wallet/core': 0.3.2(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/react-query' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react - - react-native - - supports-color - - uploadthing - - use-sync-external-store - - utf-8-validate - - wagmi - - ws - - zod + vite: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) + + '@vitest/pretty-format@3.2.4': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.4': + dependencies: + '@vitest/utils': 3.2.4 + pathe: 2.0.3 + strip-literal: 3.0.0 + + '@vitest/snapshot@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@3.2.4': + dependencies: + tinyspy: 4.0.3 + + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.0 + tinyrainbow: 2.0.0 - '@wagmi/connectors@6.2.0(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)': + '@wagmi/connectors@5.9.4(@types/react@19.1.10)(@wagmi/core@2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: - '@base-org/account': 2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.1.13) - '@gemini-wallet/core': 0.3.2(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@base-org/account': 1.1.1(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@gemini-wallet/core': 0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@metamask/sdk': 0.32.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@wagmi/core': 2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -22691,7 +17508,6 @@ snapshots: - '@netlify/blobs' - '@planetscale/database' - '@react-native-async-storage/async-storage' - - '@tanstack/react-query' - '@types/react' - '@upstash/redis' - '@vercel/blob' @@ -22699,37 +17515,29 @@ snapshots: - aws4fetch - bufferutil - db0 - - debug - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - immer - ioredis - react - - react-native - supports-color - uploadthing - use-sync-external-store - utf-8-validate - - wagmi - - ws - zod - '@wagmi/connectors@6.2.0(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)': + '@wagmi/connectors@6.2.0(1c4d5cd8f605c126794a056a26d4bec2)': dependencies: - '@base-org/account': 2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.1.13) - '@gemini-wallet/core': 0.3.2(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@base-org/account': 2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(utf-8-validate@5.0.10)(zod@3.25.76) + '@gemini-wallet/core': 0.3.2(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + porto: 0.2.35(1feacaf19428654ec6ac600c205f8b1e) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -22770,21 +17578,21 @@ snapshots: - ws - zod - '@wagmi/connectors@6.2.0(a7ab704115d4285468feaf0dc0f50159)': + '@wagmi/connectors@6.2.0(534ae91e37efc07526c2008b6d1d5787)': dependencies: - '@base-org/account': 2.4.0(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@gemini-wallet/core': 0.3.2(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(encoding@0.1.13)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@base-org/account': 2.4.0(@types/react@19.2.1)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@4.1.13) + '@gemini-wallet/core': 0.3.2(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)) + '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + porto: 0.2.35(e22920c46066f44d72e0dbd21e289d8b) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -22823,41 +17631,11 @@ snapshots: - ws - zod - '@wagmi/core@2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.9.2) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.0(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)) - optionalDependencies: - '@tanstack/query-core': 5.90.11 - typescript: 5.9.2 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - - '@wagmi/core@2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.9.2) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.0(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.5.0(react@19.2.1)) - optionalDependencies: - '@tanstack/query-core': 5.90.11 - typescript: 5.9.2 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@wagmi/core@2.19.0(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: eventemitter3: 5.0.1 mipd: 0.0.7(typescript@5.9.2) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zustand: 5.0.0(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.4.0(react@19.1.1)) optionalDependencies: '@tanstack/query-core': 5.90.11 @@ -22868,102 +17646,12 @@ snapshots: - react - use-sync-external-store - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.9.2) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.0(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) - optionalDependencies: - '@tanstack/query-core': 5.90.11 - typescript: 5.9.2 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.9.2) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.0(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) - optionalDependencies: - '@tanstack/query-core': 5.90.11 - typescript: 5.9.2 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.9.2) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.0(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.5.0(react@19.2.1)) - optionalDependencies: - '@tanstack/query-core': 5.90.11 - typescript: 5.9.2 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.9.2) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - zustand: 5.0.0(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) - optionalDependencies: - '@tanstack/query-core': 5.90.11 - typescript: 5.9.2 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.9.2) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - zustand: 5.0.0(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) - optionalDependencies: - '@tanstack/query-core': 5.90.11 - typescript: 5.9.2 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': - dependencies: - eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.9.2) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - zustand: 5.0.0(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.5.0(react@19.2.3)) - optionalDependencies: - '@tanstack/query-core': 5.90.11 - typescript: 5.9.2 - transitivePeerDependencies: - - '@types/react' - - immer - - react - - use-sync-external-store - - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': + '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: eventemitter3: 5.0.1 mipd: 0.0.7(typescript@5.9.2) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - zustand: 5.0.0(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.5.0(react@19.2.3)) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.0(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.4.0(react@19.1.1)) optionalDependencies: '@tanstack/query-core': 5.90.11 typescript: 5.9.2 @@ -22973,15 +17661,15 @@ snapshots: - react - use-sync-external-store - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': + '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))': dependencies: eventemitter3: 5.0.1 - mipd: 0.0.7(typescript@5.9.2) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + mipd: 0.0.7(typescript@5.9.3) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) zustand: 5.0.0(@types/react@19.2.1)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) optionalDependencies: '@tanstack/query-core': 5.90.11 - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - '@types/react' - immer @@ -22998,64 +17686,48 @@ snapshots: dependencies: '@wallet-standard/base': 1.1.0 - '@walletconnect/core@2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/browser-utils@1.8.0': dependencies: - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) - '@walletconnect/logger': 2.1.2 - '@walletconnect/relay-api': 1.0.11 - '@walletconnect/relay-auth': 1.1.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/window-getters': 1.0.1 - es-toolkit: 1.33.0 - events: 3.3.0 - uint8arrays: 3.1.0 + '@walletconnect/safe-json': 1.0.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/window-getters': 1.0.0 + '@walletconnect/window-metadata': 1.0.0 + detect-browser: 5.2.0 + + '@walletconnect/client@1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@walletconnect/core': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/iso-crypto': 1.8.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@walletconnect/core@1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@walletconnect/socket-transport': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - utf-8-validate - - zod - '@walletconnect/core@2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/core@2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 2.1.2 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.33.0 events: 3.3.0 @@ -23084,21 +17756,21 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/core@2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 2.1.2 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.33.0 events: 3.3.0 @@ -23127,21 +17799,21 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/core@2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 2.1.2 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.33.0 events: 3.3.0 @@ -23170,21 +17842,21 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/core@2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 2.1.2 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.33.0 events: 3.3.0 @@ -23213,25 +17885,25 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/core@2.23.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) - '@walletconnect/logger': 2.1.2 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.2 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.23.9 + '@walletconnect/utils': 2.23.9(typescript@5.9.2)(zod@3.25.76) '@walletconnect/window-getters': 1.0.1 - es-toolkit: 1.33.0 + es-toolkit: 1.44.0 events: 3.3.0 - uint8arrays: 3.1.0 + uint8arrays: 3.1.1 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -23256,142 +17928,37 @@ snapshots: - utf-8-validate - zod - '@walletconnect/environment@1.0.1': + '@walletconnect/crypto@1.1.0': dependencies: + '@noble/ciphers': 1.2.0 + '@noble/hashes': 1.7.0 + '@walletconnect/encoding': 1.0.2 + '@walletconnect/environment': 1.0.1 + '@walletconnect/randombytes': 1.1.0 tslib: 1.14.1 - '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': - dependencies: - '@reown/appkit': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) - '@walletconnect/sign-client': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/universal-provider': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/utils': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod - - '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/encoding@1.0.2': dependencies: - '@reown/appkit': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) - '@walletconnect/sign-client': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/universal-provider': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/utils': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod + is-typedarray: 1.0.0 + tslib: 1.14.1 + typedarray-to-buffer: 3.1.5 - '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/environment@1.0.1': dependencies: - '@reown/appkit': 1.7.8(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) - '@walletconnect/sign-client': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/universal-provider': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/utils': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - react - - typescript - - uploadthing - - utf-8-validate - - zod + tslib: 1.14.1 - '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) + '@reown/appkit': 1.7.8(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/jsonrpc-http-connection': 1.0.8 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) - '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/universal-provider': 2.21.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/universal-provider': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -23420,18 +17987,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/ethereum-provider@2.21.1(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/ethereum-provider@2.21.1(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@reown/appkit': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) + '@reown/appkit': 1.7.8(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/jsonrpc-http-connection': 1.0.8 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) - '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/universal-provider': 2.21.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.1 + '@walletconnect/universal-provider': 2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -23471,11 +18038,17 @@ snapshots: '@walletconnect/time': 1.0.2 events: 3.3.0 - '@walletconnect/jsonrpc-http-connection@1.0.8(encoding@0.1.13)': + '@walletconnect/iso-crypto@1.8.0': + dependencies: + '@walletconnect/crypto': 1.1.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + + '@walletconnect/jsonrpc-http-connection@1.0.8': dependencies: '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/safe-json': 1.0.2 - cross-fetch: 3.2.0(encoding@0.1.13) + cross-fetch: 3.2.0 events: 3.3.0 transitivePeerDependencies: - encoding @@ -23507,11 +18080,11 @@ snapshots: - bufferutil - utf-8-validate - '@walletconnect/keyvaluestorage@1.1.1(@upstash/redis@1.35.3)': + '@walletconnect/keyvaluestorage@1.1.1': dependencies: '@walletconnect/safe-json': 1.0.2 idb-keyval: 6.2.2 - unstorage: 1.16.1(@upstash/redis@1.35.3)(idb-keyval@6.2.2) + unstorage: 1.16.1(idb-keyval@6.2.2) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -23536,6 +18109,18 @@ snapshots: '@walletconnect/safe-json': 1.0.2 pino: 7.11.0 + '@walletconnect/logger@3.0.2': + dependencies: + '@walletconnect/safe-json': 1.0.2 + pino: 10.0.0 + + '@walletconnect/randombytes@1.1.0': + dependencies: + '@noble/hashes': 1.7.0 + '@walletconnect/encoding': 1.0.2 + '@walletconnect/environment': 1.0.1 + tslib: 1.14.1 + '@walletconnect/relay-api@1.0.11': dependencies: '@walletconnect/jsonrpc-types': 1.0.4 @@ -23548,20 +18133,22 @@ snapshots: '@walletconnect/time': 1.0.2 uint8arrays: 3.1.0 + '@walletconnect/safe-json@1.0.0': {} + '@walletconnect/safe-json@1.0.2': dependencies: tslib: 1.14.1 - '@walletconnect/sign-client@2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/sign-client@2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@walletconnect/core': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/core': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/logger': 2.1.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -23587,16 +18174,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/sign-client@2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@walletconnect/core': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/core': 2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/logger': 2.1.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -23622,16 +18209,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/sign-client@2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@walletconnect/core': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/core': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/logger': 2.1.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -23657,16 +18244,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/sign-client@2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@walletconnect/core': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/core': 2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/logger': 2.1.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -23692,16 +18279,16 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/sign-client@2.23.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@walletconnect/core': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/core': 2.23.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/logger': 2.1.2 + '@walletconnect/logger': 3.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.23.9 + '@walletconnect/utils': 2.23.9(typescript@5.9.2)(zod@3.25.76) events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -23727,51 +18314,27 @@ snapshots: - utf-8-validate - zod - '@walletconnect/sign-client@2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/socket-transport@1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: - '@walletconnect/core': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/logger': 2.1.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - events: 3.3.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + ws: 7.5.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - utf-8-validate - - zod '@walletconnect/time@1.0.2': dependencies: tslib: 1.14.1 - '@walletconnect/types@2.21.0(@upstash/redis@1.35.3)': + '@walletconnect/types@1.8.0': {} + + '@walletconnect/types@2.21.0': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 2.1.2 events: 3.3.0 transitivePeerDependencies: @@ -23794,12 +18357,12 @@ snapshots: - ioredis - uploadthing - '@walletconnect/types@2.21.1(@upstash/redis@1.35.3)': + '@walletconnect/types@2.21.1': dependencies: '@walletconnect/events': 1.0.1 '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 2.1.2 events: 3.3.0 transitivePeerDependencies: @@ -23822,19 +18385,13 @@ snapshots: - ioredis - uploadthing - '@walletconnect/universal-provider@2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/types@2.23.9': dependencies: '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) - '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-types': 1.0.4 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) - '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - es-toolkit: 1.33.0 + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.2 events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -23852,27 +18409,22 @@ snapshots: - '@vercel/blob' - '@vercel/kv' - aws4fetch - - bufferutil - db0 - - encoding - ioredis - - typescript - uploadthing - - utf-8-validate - - zod - '@walletconnect/universal-provider@2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/universal-provider@2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) + '@walletconnect/jsonrpc-http-connection': 1.0.8 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/sign-client': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: @@ -23900,18 +18452,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.0(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/universal-provider@2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) + '@walletconnect/jsonrpc-http-connection': 1.0.8 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/sign-client': 2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.0 + '@walletconnect/utils': 2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: @@ -23939,18 +18491,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/universal-provider@2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) + '@walletconnect/jsonrpc-http-connection': 1.0.8 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: @@ -23978,18 +18530,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/universal-provider@2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) + '@walletconnect/jsonrpc-http-connection': 1.0.8 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.1 + '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: @@ -24017,57 +18569,28 @@ snapshots: - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.1(bufferutil@4.0.9)(encoding@0.1.13)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/utils@1.8.0': dependencies: - '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8(encoding@0.1.13) - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/browser-utils': 1.8.0 + '@walletconnect/encoding': 1.0.2 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) - '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) - '@walletconnect/utils': 2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - es-toolkit: 1.33.0 - events: 3.3.0 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - encoding - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod + '@walletconnect/types': 1.8.0 + bn.js: 4.11.8 + js-sha3: 0.8.0 + query-string: 6.13.5 - '@walletconnect/utils@2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/utils@2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@noble/ciphers': 1.2.1 '@noble/curves': 1.8.1 '@noble/hashes': 1.7.1 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) + '@walletconnect/types': 2.21.0 '@walletconnect/window-getters': 1.0.1 '@walletconnect/window-metadata': 1.0.1 bs58: 6.0.0 @@ -24099,68 +18622,25 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.0(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': - dependencies: - '@noble/ciphers': 1.2.1 - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) - '@walletconnect/relay-api': 1.0.11 - '@walletconnect/relay-auth': 1.1.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) - '@walletconnect/window-getters': 1.0.1 - '@walletconnect/window-metadata': 1.0.1 - bs58: 6.0.0 - detect-browser: 5.3.0 - query-string: 7.1.3 - uint8arrays: 3.1.0 - viem: 2.23.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - ioredis - - typescript - - uploadthing - - utf-8-validate - - zod - - '@walletconnect/utils@2.21.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/utils@2.21.0(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@noble/ciphers': 1.2.1 '@noble/curves': 1.8.1 '@noble/hashes': 1.7.1 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0(@upstash/redis@1.35.3) + '@walletconnect/types': 2.21.0 '@walletconnect/window-getters': 1.0.1 '@walletconnect/window-metadata': 1.0.1 bs58: 6.0.0 detect-browser: 5.3.0 query-string: 7.1.3 uint8arrays: 3.1.0 - viem: 2.23.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -24185,18 +18665,18 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/utils@2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@noble/ciphers': 1.2.1 '@noble/curves': 1.8.1 '@noble/hashes': 1.7.1 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) + '@walletconnect/types': 2.21.1 '@walletconnect/window-getters': 1.0.1 '@walletconnect/window-metadata': 1.0.1 bs58: 6.0.0 @@ -24228,25 +18708,25 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.1(@upstash/redis@1.35.3)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/utils@2.21.1(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@noble/ciphers': 1.2.1 '@noble/curves': 1.8.1 '@noble/hashes': 1.7.1 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) + '@walletconnect/types': 2.21.1 '@walletconnect/window-getters': 1.0.1 '@walletconnect/window-metadata': 1.0.1 bs58: 6.0.0 detect-browser: 5.3.0 query-string: 7.1.3 uint8arrays: 3.1.0 - viem: 2.23.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -24271,25 +18751,27 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + '@walletconnect/utils@2.23.9(typescript@5.9.2)(zod@3.25.76)': dependencies: - '@noble/ciphers': 1.2.1 - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 + '@msgpack/msgpack': 3.1.3 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/keyvaluestorage': 1.1.1(@upstash/redis@1.35.3) + '@walletconnect/keyvaluestorage': 1.1.1 + '@walletconnect/logger': 3.0.2 '@walletconnect/relay-api': 1.0.11 '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1(@upstash/redis@1.35.3) + '@walletconnect/types': 2.23.9 '@walletconnect/window-getters': 1.0.1 '@walletconnect/window-metadata': 1.0.1 - bs58: 6.0.0 + blakejs: 1.2.1 detect-browser: 5.3.0 - query-string: 7.1.3 - uint8arrays: 3.1.0 - viem: 2.23.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + ox: 0.9.3(typescript@5.9.2)(zod@3.25.76) + uint8arrays: 3.1.1 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -24306,50 +18788,59 @@ snapshots: - '@vercel/blob' - '@vercel/kv' - aws4fetch - - bufferutil - db0 - ioredis - typescript - uploadthing - - utf-8-validate - zod + '@walletconnect/window-getters@1.0.0': {} + '@walletconnect/window-getters@1.0.1': dependencies: tslib: 1.14.1 + '@walletconnect/window-metadata@1.0.0': + dependencies: + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata@1.0.1': dependencies: '@walletconnect/window-getters': 1.0.1 tslib: 1.14.1 - '@xmldom/xmldom@0.8.11': {} + '@x402/core@2.11.0': + dependencies: + zod: 3.25.76 - abbrev@1.1.1: {} + '@x402/evm@2.11.0(typescript@5.9.3)': + dependencies: + '@x402/core': 2.11.0 + viem: 2.48.11(typescript@5.9.3)(zod@3.25.76) + zod: 3.25.76 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate abitype@1.0.6(typescript@5.9.2)(zod@3.25.76): optionalDependencies: typescript: 5.9.2 zod: 3.25.76 - abitype@1.0.8(typescript@5.9.2)(zod@3.25.76): + abitype@1.0.6(typescript@5.9.3)(zod@3.25.76): optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 zod: 3.25.76 - abitype@1.0.8(typescript@5.9.2)(zod@4.1.13): - optionalDependencies: - typescript: 5.9.2 - zod: 4.1.13 - - abitype@1.1.0(typescript@5.9.2)(zod@3.25.76): + abitype@1.0.8(typescript@5.9.2)(zod@3.25.76): optionalDependencies: typescript: 5.9.2 zod: 3.25.76 - abitype@1.1.0(typescript@5.9.2)(zod@4.1.13): + abitype@1.0.8(typescript@5.9.3)(zod@4.1.13): optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 zod: 4.1.13 abitype@1.2.3(typescript@5.9.2)(zod@3.22.4): @@ -24367,6 +18858,21 @@ snapshots: typescript: 5.9.2 zod: 4.1.13 + abitype@1.2.3(typescript@5.9.3)(zod@3.22.4): + optionalDependencies: + typescript: 5.9.3 + zod: 3.22.4 + + abitype@1.2.3(typescript@5.9.3)(zod@3.25.76): + optionalDependencies: + typescript: 5.9.3 + zod: 3.25.76 + + abitype@1.2.3(typescript@5.9.3)(zod@4.1.13): + optionalDependencies: + typescript: 5.9.3 + zod: 4.1.13 + abort-controller@3.0.0: dependencies: event-target-shim: 5.0.1 @@ -24387,15 +18893,11 @@ snapshots: dependencies: acorn: 8.15.0 - acorn@8.15.0: {} - - aes-js@4.0.0-beta.5: {} - - agent-base@6.0.2: + acorn-walk@8.3.5: dependencies: - debug: 4.4.1 - transitivePeerDependencies: - - supports-color + acorn: 8.15.0 + + acorn@8.15.0: {} agent-base@7.1.4: {} @@ -24403,19 +18905,10 @@ snapshots: dependencies: humanize-ms: 1.2.1 - aggregate-error@3.1.0: - dependencies: - clean-stack: 2.2.0 - indent-string: 4.0.0 - ajv-formats@3.0.1(ajv@8.17.1): optionalDependencies: ajv: 8.17.1 - ajv-keywords@3.5.2(ajv@6.12.6): - dependencies: - ajv: 6.12.6 - ajv@6.12.6: dependencies: fast-deep-equal: 3.1.3 @@ -24430,10 +18923,29 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + algo-msgpack-with-bigint@2.1.1: {} + + algorand-msgpack@1.1.0: {} + + algosdk@3.5.2: + dependencies: + algorand-msgpack: 1.1.0 + hi-base32: 0.5.1 + js-sha256: 0.9.0 + js-sha3: 0.8.0 + js-sha512: 0.8.0 + json-bigint: 1.0.0 + tweetnacl: 1.0.3 + vlq: 2.0.4 + + anser@1.4.10: {} + ansi-regex@5.0.1: {} ansi-regex@6.2.0: {} + ansi-regex@6.2.2: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 @@ -24442,6 +18954,8 @@ snapshots: ansi-styles@6.2.1: {} + ansi-styles@6.2.3: {} + any-promise@1.3.0: {} anymatch@3.1.3: @@ -24451,52 +18965,9 @@ snapshots: apg-js@4.4.0: {} - app-builder-bin@5.0.0-alpha.12: {} - - app-builder-lib@26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12): - dependencies: - '@develar/schema-utils': 2.6.5 - '@electron/asar': 3.2.18 - '@electron/fuses': 1.8.0 - '@electron/notarize': 2.5.0 - '@electron/osx-sign': 1.3.1 - '@electron/rebuild': 3.7.0 - '@electron/universal': 2.0.1 - '@malept/flatpak-bundler': 0.4.0 - '@types/fs-extra': 9.0.13 - async-exit-hook: 2.0.1 - builder-util: 26.0.11 - builder-util-runtime: 9.3.1 - chromium-pickle-js: 0.2.0 - config-file-ts: 0.2.8-rc1 - debug: 4.4.1 - dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12) - dotenv: 16.6.1 - dotenv-expand: 11.0.7 - ejs: 3.1.10 - electron-builder-squirrel-windows: 26.0.12(dmg-builder@26.0.12) - electron-publish: 26.0.11 - fs-extra: 10.1.0 - hosted-git-info: 4.1.0 - is-ci: 3.0.1 - isbinaryfile: 5.0.4 - js-yaml: 4.1.0 - json5: 2.2.3 - lazy-val: 1.0.5 - minimatch: 10.0.3 - plist: 3.1.0 - resedit: 1.7.2 - semver: 7.7.3 - tar: 6.2.1 - temp-file: 3.4.0 - tiny-async-pool: 1.3.0 - transitivePeerDependencies: - - bluebird - - supports-color - are-docs-informative@0.0.2: {} - arg@5.0.2: {} + arg@4.1.3: {} argparse@2.0.1: {} @@ -24524,8 +18995,6 @@ snapshots: is-string: 1.1.1 math-intrinsics: 1.1.0 - array-union@2.1.0: {} - array.prototype.findlast@1.2.5: dependencies: call-bind: 1.0.8 @@ -24577,30 +19046,26 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 - assert-plus@1.0.0: - optional: true + asap@2.0.6: {} + + asn1js@3.0.6: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 assertion-error@2.0.1: {} ast-types-flow@0.0.8: {} - astral-regex@2.0.0: - optional: true - - async-exit-hook@2.0.1: {} - async-function@1.0.0: {} async-mutex@0.2.6: dependencies: tslib: 2.8.1 - async@3.2.6: {} - asynckit@0.4.0: {} - at-least-node@1.0.0: {} - atomic-sleep@1.0.0: {} available-typed-arrays@1.0.7: @@ -24612,18 +19077,16 @@ snapshots: '@fastify/error': 4.2.0 fastq: 1.19.1 - axe-core@4.10.3: {} - - axios-mock-adapter@1.22.0(axios@1.13.2): + aws-cdk-lib@2.252.0(constructs@10.6.0): dependencies: - axios: 1.13.2 - fast-deep-equal: 3.1.3 - is-buffer: 2.0.5 + '@aws-cdk/asset-awscli-v1': 2.2.273 + '@aws-cdk/asset-node-proxy-agent-v6': 2.1.1 + '@aws-cdk/cloud-assembly-schema': 53.20.0 + constructs: 10.6.0 - axios-retry@4.5.0(axios@1.13.2): - dependencies: - axios: 1.13.2 - is-retry-allowed: 2.2.0 + aws-cdk@2.1120.0: {} + + axe-core@4.10.3: {} axios-retry@4.5.0(axios@1.13.4): dependencies: @@ -24648,29 +19111,9 @@ snapshots: axobject-query@4.1.0: {} - babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.3): + babel-plugin-syntax-hermes-parser@0.33.3: dependencies: - '@babel/compat-data': 7.28.0 - '@babel/core': 7.28.3 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.3) - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.3): - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.3) - core-js-compat: 3.45.1 - transitivePeerDependencies: - - supports-color - - babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.3): - dependencies: - '@babel/core': 7.28.3 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.3) - transitivePeerDependencies: - - supports-color + hermes-parser: 0.33.3 balanced-match@1.0.2: {} @@ -24678,8 +19121,6 @@ snapshots: dependencies: safe-buffer: 5.2.1 - base-x@4.0.1: {} - base-x@5.0.1: {} base32.js@0.1.0: {} @@ -24688,36 +19129,17 @@ snapshots: big.js@6.2.2: {} - bigint-buffer@1.1.5: - dependencies: - bindings: 1.5.0 + bignumber.js@9.1.1: {} bignumber.js@9.3.1: {} - binary-extensions@2.3.0: {} - - bindings@1.5.0: - dependencies: - file-uri-to-path: 1.0.0 - - bip32@4.0.0: - dependencies: - '@noble/hashes': 1.8.0 - '@scure/base': 1.2.6 - typeforce: 1.18.0 - wif: 2.0.6 + blakejs@1.2.1: {} - bip39@3.1.0: - dependencies: - '@noble/hashes': 1.8.0 + bn.js@4.11.8: {} - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 + bn.js@4.12.3: {} - bn.js@4.12.2: {} + bn.js@5.2.1: {} bn.js@5.2.2: {} @@ -24752,17 +19174,14 @@ snapshots: transitivePeerDependencies: - supports-color - boolbase@1.0.0: {} - - boolean@3.2.0: - optional: true - borsh@0.7.0: dependencies: bn.js: 5.2.2 bs58: 4.0.1 text-encoding-utf-8: 1.0.2 + bowser@2.11.0: {} + bowser@2.12.0: {} brace-expansion@1.1.12: @@ -24791,31 +19210,16 @@ snapshots: dependencies: base-x: 3.0.11 - bs58@5.0.0: - dependencies: - base-x: 4.0.1 - bs58@6.0.0: dependencies: base-x: 5.0.1 - bs58check@2.1.2: + bser@2.1.1: dependencies: - bs58: 4.0.1 - create-hash: 1.2.0 - safe-buffer: 5.2.1 - - buffer-crc32@0.2.13: {} + node-int64: 0.4.0 buffer-from@1.1.2: {} - buffer-reverse@1.0.1: {} - - buffer@5.7.1: - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - buffer@6.0.3: dependencies: base64-js: 1.5.1 @@ -24825,40 +19229,6 @@ snapshots: dependencies: node-gyp-build: 4.8.4 - builder-util-runtime@9.3.1: - dependencies: - debug: 4.4.1 - sax: 1.4.1 - transitivePeerDependencies: - - supports-color - - builder-util@26.0.11: - dependencies: - 7zip-bin: 5.2.0 - '@types/debug': 4.1.12 - app-builder-bin: 5.0.0-alpha.12 - builder-util-runtime: 9.3.1 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.1 - fs-extra: 10.1.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - is-ci: 3.0.1 - js-yaml: 4.1.0 - sanitize-filename: 1.6.3 - source-map-support: 0.5.21 - stat-mode: 1.0.0 - temp-file: 3.4.0 - tiny-async-pool: 1.3.0 - transitivePeerDependencies: - - supports-color - - bundle-require@4.2.1(esbuild@0.19.12): - dependencies: - esbuild: 0.19.12 - load-tsconfig: 0.2.5 - bundle-require@5.1.0(esbuild@0.25.9): dependencies: esbuild: 0.25.9 @@ -24868,29 +19238,6 @@ snapshots: cac@6.7.14: {} - cacache@16.1.3: - dependencies: - '@npmcli/fs': 2.1.2 - '@npmcli/move-file': 2.0.1 - chownr: 2.0.0 - fs-minipass: 2.1.0 - glob: 8.1.0 - infer-owner: 1.0.4 - lru-cache: 7.18.3 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - mkdirp: 1.0.4 - p-map: 4.0.0 - promise-inflight: 1.0.1 - rimraf: 3.0.2 - ssri: 9.0.1 - tar: 6.2.1 - unique-filename: 2.0.1 - transitivePeerDependencies: - - bluebird - cacheable-lookup@5.0.4: {} cacheable-request@7.0.4: @@ -24922,16 +19269,12 @@ snapshots: callsites@3.1.0: {} - camelcase-css@2.0.1: {} - camelcase@5.3.1: {} camelcase@6.3.0: {} caniuse-lite@1.0.30001735: {} - canonicalize@2.1.0: {} - chai@5.3.1: dependencies: assertion-error: 2.0.1 @@ -24951,48 +19294,32 @@ snapshots: check-error@2.1.1: {} - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - chokidar@4.0.3: dependencies: readdirp: 4.1.2 - chownr@2.0.0: {} - - chromium-pickle-js@0.2.0: {} - - ci-info@3.9.0: {} - - cipher-base@1.0.6: + chrome-launcher@0.15.2: dependencies: - inherits: 2.0.4 - safe-buffer: 5.2.1 - - classnames@2.5.1: {} - - clean-stack@2.2.0: {} + '@types/node': 22.17.2 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + transitivePeerDependencies: + - supports-color - cli-cursor@3.1.0: + chromium-edge-launcher@0.3.0: dependencies: - restore-cursor: 3.1.0 + '@types/node': 22.17.2 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + mkdirp: 1.0.4 + transitivePeerDependencies: + - supports-color - cli-spinners@2.9.2: {} + ci-info@2.0.0: {} - cli-truncate@2.1.0: - dependencies: - slice-ansi: 3.0.0 - string-width: 4.2.3 - optional: true + ci-info@3.9.0: {} client-only@0.0.1: {} @@ -25012,38 +19339,19 @@ snapshots: dependencies: mimic-response: 1.0.1 - clone@1.0.4: {} - clsx@1.2.1: {} clsx@2.1.1: {} - color-convert@1.9.3: - dependencies: - color-name: 1.1.3 + cluster-key-slot@1.1.2: {} color-convert@2.0.1: dependencies: color-name: 1.1.4 - color-name@1.1.3: {} - color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.2 - - color@3.2.1: - dependencies: - color-convert: 1.9.3 - color-string: 1.9.1 - - colorspace@1.1.4: - dependencies: - color: 3.2.1 - text-hex: 1.0.0 + colorette@2.0.20: {} combined-stream@1.0.8: dependencies: @@ -25055,8 +19363,6 @@ snapshots: commander@14.0.0: {} - commander@14.0.1: {} - commander@14.0.2: {} commander@14.0.3: {} @@ -25065,53 +19371,24 @@ snapshots: commander@4.1.1: {} - commander@5.1.0: {} - - commander@7.2.0: {} - - commander@9.5.0: - optional: true - comment-parser@1.4.1: {} - compare-version@0.1.2: {} - concat-map@0.0.1: {} - concurrently@8.2.2: - dependencies: - chalk: 4.1.2 - date-fns: 2.30.0 - lodash: 4.17.21 - rxjs: 7.8.2 - shell-quote: 1.8.3 - spawn-command: 0.0.2 - supports-color: 8.1.1 - tree-kill: 1.2.2 - yargs: 17.7.2 - - concurrently@9.2.0: - dependencies: - chalk: 4.1.2 - lodash: 4.17.21 - rxjs: 7.8.2 - shell-quote: 1.8.3 - supports-color: 8.1.1 - tree-kill: 1.2.2 - yargs: 17.7.2 - confbox@0.1.8: {} - config-file-ts@0.2.8-rc1: + connect@3.7.0: dependencies: - glob: 10.4.5 - typescript: 5.9.2 + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color consola@3.4.2: {} - console-table-printer@2.14.6: - dependencies: - simple-wcswidth: 1.1.2 + constructs@10.6.0: {} content-disposition@0.5.4: dependencies: @@ -25137,13 +19414,6 @@ snapshots: cookie@1.1.1: {} - core-js-compat@3.45.1: - dependencies: - browserslist: 4.25.3 - - core-util-is@1.0.2: - optional: true - core-util-is@1.0.3: {} cors@2.8.5: @@ -25151,42 +19421,19 @@ snapshots: object-assign: 4.1.1 vary: 1.1.2 - cosmiconfig@8.3.6(typescript@5.9.2): - dependencies: - import-fresh: 3.3.1 - js-yaml: 4.1.0 - parse-json: 5.2.0 - path-type: 4.0.0 - optionalDependencies: - typescript: 5.9.2 - crc-32@1.2.2: {} - crc@3.8.0: - dependencies: - buffer: 5.7.1 - optional: true - - create-hash@1.2.0: - dependencies: - cipher-base: 1.0.6 - inherits: 2.0.4 - md5.js: 1.3.5 - ripemd160: 2.0.2 - sha.js: 2.4.12 - - cross-dirname@0.1.0: - optional: true + create-require@1.1.1: {} - cross-fetch@3.2.0(encoding@0.1.13): + cross-fetch@3.2.0: dependencies: - node-fetch: 2.7.0(encoding@0.1.13) + node-fetch: 2.7.0 transitivePeerDependencies: - encoding - cross-fetch@4.1.0(encoding@0.1.13): + cross-fetch@4.1.0: dependencies: - node-fetch: 2.7.0(encoding@0.1.13) + node-fetch: 2.7.0 transitivePeerDependencies: - encoding @@ -25204,32 +19451,6 @@ snapshots: crypto-js@4.2.0: {} - css-select@5.2.2: - dependencies: - boolbase: 1.0.0 - css-what: 6.2.2 - domhandler: 5.0.3 - domutils: 3.2.2 - nth-check: 2.1.1 - - css-tree@2.2.1: - dependencies: - mdn-data: 2.0.28 - source-map-js: 1.2.1 - - css-tree@2.3.1: - dependencies: - mdn-data: 2.0.30 - source-map-js: 1.2.1 - - css-what@6.2.2: {} - - cssesc@3.0.0: {} - - csso@5.0.5: - dependencies: - css-tree: 2.2.1 - cssstyle@4.6.0: dependencies: '@asamuzakjp/css-color': 3.2.0 @@ -25239,8 +19460,6 @@ snapshots: damerau-levenshtein@1.0.8: {} - data-uri-to-buffer@4.0.1: {} - data-urls@5.0.0: dependencies: whatwg-mimetype: 4.0.0 @@ -25268,6 +19487,8 @@ snapshots: dependencies: '@babel/runtime': 7.28.3 + dateformat@4.6.3: {} + dayjs@1.11.13: {} debug@2.6.9: @@ -25302,13 +19523,7 @@ snapshots: deep-eql@5.0.2: {} - deep-is@0.1.4: {} - - deepmerge@4.3.1: {} - - defaults@1.0.4: - dependencies: - clone: 1.0.4 + deep-is@0.1.4: {} defer-to-connect@2.0.1: {} @@ -25338,14 +19553,6 @@ snapshots: dependencies: valtio: 1.13.2(@types/react@19.1.10)(react@19.1.1) - derive-valtio@0.1.0(valtio@1.13.2(@types/react@19.1.10)(react@19.2.1)): - dependencies: - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.1) - - derive-valtio@0.1.0(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3)): - dependencies: - valtio: 1.13.2(@types/react@19.1.10)(react@19.2.3) - derive-valtio@0.1.0(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3)): dependencies: valtio: 1.13.2(@types/react@19.2.1)(react@19.2.3) @@ -25354,92 +19561,22 @@ snapshots: destroy@1.2.0: {} + detect-browser@5.2.0: {} + detect-browser@5.3.0: {} detect-libc@2.1.2: {} detect-node-es@1.1.0: {} - detect-node@2.1.0: - optional: true - - didyoumean@1.2.2: {} + diff@4.0.4: {} dijkstrajs@1.0.3: {} - dir-compare@4.2.0: - dependencies: - minimatch: 3.1.2 - p-limit: 3.1.0 - - dir-glob@3.0.1: - dependencies: - path-type: 4.0.0 - - dlv@1.1.3: {} - - dmg-builder@26.0.12(electron-builder-squirrel-windows@26.0.12): - dependencies: - app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12) - builder-util: 26.0.11 - builder-util-runtime: 9.3.1 - fs-extra: 10.1.0 - iconv-lite: 0.6.3 - js-yaml: 4.1.0 - optionalDependencies: - dmg-license: 1.0.11 - transitivePeerDependencies: - - bluebird - - electron-builder-squirrel-windows - - supports-color - - dmg-license@1.0.11: - dependencies: - '@types/plist': 3.0.5 - '@types/verror': 1.10.11 - ajv: 6.12.6 - crc: 3.8.0 - iconv-corefoundation: 1.1.7 - plist: 3.1.0 - smart-buffer: 4.2.0 - verror: 1.10.1 - optional: true - doctrine@2.1.0: dependencies: esutils: 2.0.3 - doctrine@3.0.0: - dependencies: - esutils: 2.0.3 - - dom-serializer@2.0.0: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - entities: 4.5.0 - - domelementtype@2.3.0: {} - - domhandler@5.0.3: - dependencies: - domelementtype: 2.3.0 - - domutils@3.2.2: - dependencies: - dom-serializer: 2.0.0 - domelementtype: 2.3.0 - domhandler: 5.0.3 - - dot-case@3.0.4: - dependencies: - no-case: 3.0.4 - tslib: 2.8.1 - - dotenv-expand@11.0.7: - dependencies: - dotenv: 16.6.1 - dotenv@16.6.1: {} dunder-proto@1.0.1: @@ -25464,83 +19601,13 @@ snapshots: '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 - ed2curve@0.3.0: - dependencies: - tweetnacl: 1.0.3 - ee-first@1.1.1: {} - ejs@3.1.10: - dependencies: - jake: 10.9.4 - - electron-builder-squirrel-windows@26.0.12(dmg-builder@26.0.12): - dependencies: - app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12) - builder-util: 26.0.11 - electron-winstaller: 5.4.0 - transitivePeerDependencies: - - bluebird - - dmg-builder - - supports-color - - electron-builder@26.0.12(electron-builder-squirrel-windows@26.0.12): - dependencies: - app-builder-lib: 26.0.12(dmg-builder@26.0.12)(electron-builder-squirrel-windows@26.0.12) - builder-util: 26.0.11 - builder-util-runtime: 9.3.1 - chalk: 4.1.2 - dmg-builder: 26.0.12(electron-builder-squirrel-windows@26.0.12) - fs-extra: 10.1.0 - is-ci: 3.0.1 - lazy-val: 1.0.5 - simple-update-notifier: 2.0.0 - yargs: 17.7.2 - transitivePeerDependencies: - - bluebird - - electron-builder-squirrel-windows - - supports-color - - electron-is-dev@3.0.1: {} - - electron-publish@26.0.11: - dependencies: - '@types/fs-extra': 9.0.13 - builder-util: 26.0.11 - builder-util-runtime: 9.3.1 - chalk: 4.1.2 - form-data: 4.0.4 - fs-extra: 10.1.0 - lazy-val: 1.0.5 - mime: 2.6.0 - transitivePeerDependencies: - - supports-color - electron-to-chromium@1.5.207: {} - electron-winstaller@5.4.0: - dependencies: - '@electron/asar': 3.4.1 - debug: 4.4.1 - fs-extra: 7.0.1 - lodash: 4.17.21 - temp: 0.9.4 - optionalDependencies: - '@electron/windows-sign': 1.2.2 - transitivePeerDependencies: - - supports-color - - electron@37.3.1: - dependencies: - '@electron/get': 2.0.3 - '@types/node': 22.17.2 - extract-zip: 2.0.1 - transitivePeerDependencies: - - supports-color - elliptic@6.6.1: dependencies: - bn.js: 4.12.2 + bn.js: 4.12.3 brorand: 1.1.0 hash.js: 1.1.7 hmac-drbg: 1.0.1 @@ -25552,19 +19619,12 @@ snapshots: emoji-regex@9.2.2: {} - enabled@2.0.0: {} - encode-utf8@1.0.3: {} encodeurl@1.0.2: {} encodeurl@2.0.0: {} - encoding@0.1.13: - dependencies: - iconv-lite: 0.6.3 - optional: true - end-of-stream@1.4.5: dependencies: once: 1.4.0 @@ -25588,17 +19648,11 @@ snapshots: graceful-fs: 4.2.11 tapable: 2.3.0 - entities@4.5.0: {} - entities@6.0.1: {} - env-paths@2.2.1: {} - - err-code@2.0.3: {} - - error-ex@1.3.2: + error-stack-parser@2.1.4: dependencies: - is-arrayish: 0.2.1 + stackframe: 1.3.4 es-abstract@1.24.0: dependencies: @@ -25705,8 +19759,7 @@ snapshots: es-toolkit@1.33.0: {} - es6-error@4.1.1: - optional: true + es-toolkit@1.44.0: {} es6-promise@4.2.8: {} @@ -25714,32 +19767,6 @@ snapshots: dependencies: es6-promise: 4.2.8 - esbuild@0.19.12: - optionalDependencies: - '@esbuild/aix-ppc64': 0.19.12 - '@esbuild/android-arm': 0.19.12 - '@esbuild/android-arm64': 0.19.12 - '@esbuild/android-x64': 0.19.12 - '@esbuild/darwin-arm64': 0.19.12 - '@esbuild/darwin-x64': 0.19.12 - '@esbuild/freebsd-arm64': 0.19.12 - '@esbuild/freebsd-x64': 0.19.12 - '@esbuild/linux-arm': 0.19.12 - '@esbuild/linux-arm64': 0.19.12 - '@esbuild/linux-ia32': 0.19.12 - '@esbuild/linux-loong64': 0.19.12 - '@esbuild/linux-mips64el': 0.19.12 - '@esbuild/linux-ppc64': 0.19.12 - '@esbuild/linux-riscv64': 0.19.12 - '@esbuild/linux-s390x': 0.19.12 - '@esbuild/linux-x64': 0.19.12 - '@esbuild/netbsd-x64': 0.19.12 - '@esbuild/openbsd-x64': 0.19.12 - '@esbuild/sunos-x64': 0.19.12 - '@esbuild/win32-arm64': 0.19.12 - '@esbuild/win32-ia32': 0.19.12 - '@esbuild/win32-x64': 0.19.12 - esbuild@0.25.9: optionalDependencies: '@esbuild/aix-ppc64': 0.25.9 @@ -25769,101 +19796,81 @@ snapshots: '@esbuild/win32-ia32': 0.25.9 '@esbuild/win32-x64': 0.25.9 + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + escalade@3.2.0: {} escape-html@1.0.3: {} escape-string-regexp@4.0.0: {} - eslint-config-next@15.5.7(eslint@8.57.1)(typescript@5.9.2): - dependencies: - '@next/eslint-plugin-next': 15.5.7 - '@rushstack/eslint-patch': 1.12.0 - '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1)(typescript@5.9.2) - '@typescript-eslint/parser': 8.48.0(eslint@8.57.1)(typescript@5.9.2) - eslint: 8.57.1 - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) - eslint-plugin-jsx-a11y: 6.10.2(eslint@8.57.1) - eslint-plugin-react: 7.37.5(eslint@8.57.1) - eslint-plugin-react-hooks: 5.2.0(eslint@8.57.1) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - eslint-import-resolver-webpack - - eslint-plugin-import-x - - supports-color - - eslint-config-next@16.0.6(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2): + eslint-config-next@16.0.6(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 16.0.6 eslint: 9.33.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.33.0(jiti@2.6.1)) globals: 16.4.0 - typescript-eslint: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + typescript-eslint: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-webpack - eslint-plugin-import-x - supports-color - eslint-config-next@16.0.6(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2): + eslint-config-next@16.0.6(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3): dependencies: '@next/eslint-plugin-next': 16.0.6 eslint: 9.33.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-jsx-a11y: 6.10.2(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-react: 7.37.5(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-react-hooks: 7.0.1(eslint@9.33.0(jiti@2.6.1)) - globals: 16.4.0 - typescript-eslint: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - '@typescript-eslint/parser' - - eslint-import-resolver-webpack - - eslint-plugin-import-x - - supports-color - - eslint-config-next@16.0.7(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2): - dependencies: - '@next/eslint-plugin-next': 16.0.7 - eslint: 9.33.0(jiti@2.6.1) - eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.33.0(jiti@2.6.1)) - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-jsx-a11y: 6.10.2(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-react: 7.37.5(eslint@9.33.0(jiti@2.6.1)) eslint-plugin-react-hooks: 7.0.1(eslint@9.33.0(jiti@2.6.1)) globals: 16.4.0 - typescript-eslint: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + typescript-eslint: 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-webpack - eslint-plugin-import-x - supports-color - eslint-config-prettier@10.1.8(eslint@8.57.1): - dependencies: - eslint: 8.57.1 - - eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)): - dependencies: - eslint: 9.33.0(jiti@2.6.1) - optional: true - eslint-import-resolver-node@0.3.9: dependencies: debug: 3.2.7 @@ -25872,70 +19879,64 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1))(eslint@8.57.1): + eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.33.0(jiti@2.6.1)): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.4.1 - eslint: 8.57.1 + eslint: 9.33.0(jiti@2.6.1) get-tsconfig: 4.10.1 is-bun-module: 2.0.0 stable-hash: 0.0.5 tinyglobby: 0.2.15 unrs-resolver: 1.11.1 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.33.0(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.6.1)): dependencies: - '@nolyfill/is-core-module': 1.0.39 - debug: 4.4.1 - eslint: 9.33.0(jiti@2.6.1) - get-tsconfig: 4.10.1 - is-bun-module: 2.0.0 - stable-hash: 0.0.5 - tinyglobby: 0.2.15 - unrs-resolver: 1.11.1 + debug: 3.2.7 optionalDependencies: - eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + '@typescript-eslint/parser': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + eslint: 9.33.0(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: 9.33.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.33.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.48.0(eslint@8.57.1)(typescript@5.9.2) - eslint: 8.57.1 + '@typescript-eslint/parser': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + eslint: 9.33.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1))(eslint@8.57.1) transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)): + eslint-module-utils@2.12.1(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)): dependencies: debug: 3.2.7 optionalDependencies: - '@typescript-eslint/parser': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/parser': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: 9.33.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 eslint-import-resolver-typescript: 3.10.1(eslint-plugin-import@2.32.0)(eslint@9.33.0(jiti@2.6.1)) transitivePeerDependencies: - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -25946,7 +19947,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.33.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0)(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -25964,7 +19965,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@8.57.1): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -25973,9 +19974,9 @@ snapshots: array.prototype.flatmap: 1.3.3 debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.57.1 + eslint: 9.33.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1(eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@8.57.1)(typescript@5.9.2))(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -25987,13 +19988,13 @@ snapshots: string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 8.48.0(eslint@8.57.1)(typescript@5.9.2) + '@typescript-eslint/parser': 8.40.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)): + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1)): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.9 @@ -26004,7 +20005,7 @@ snapshots: doctrine: 2.1.0 eslint: 9.33.0(jiti@2.6.1) eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-node@0.3.9)(eslint@9.33.0(jiti@2.6.1)) hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 @@ -26022,6 +20023,35 @@ snapshots: - eslint-import-resolver-webpack - supports-color + eslint-plugin-import@2.32.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)): + dependencies: + '@rtsao/scc': 1.1.0 + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 + array.prototype.flat: 1.3.3 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 + doctrine: 2.1.0 + eslint: 9.33.0(jiti@2.6.1) + eslint-import-resolver-node: 0.3.9 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.10.1)(eslint@9.33.0(jiti@2.6.1)) + hasown: 2.0.2 + is-core-module: 2.16.1 + is-glob: 4.0.3 + minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 + object.values: 1.2.1 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 + tsconfig-paths: 3.15.0 + optionalDependencies: + '@typescript-eslint/parser': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) + transitivePeerDependencies: + - eslint-import-resolver-typescript + - eslint-import-resolver-webpack + - supports-color + eslint-plugin-jsdoc@50.8.0(eslint@9.33.0(jiti@2.6.1)): dependencies: '@es-joy/jsdoccomment': 0.50.2 @@ -26038,25 +20068,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-jsx-a11y@6.10.2(eslint@8.57.1): - dependencies: - aria-query: 5.3.2 - array-includes: 3.1.9 - array.prototype.flatmap: 1.3.3 - ast-types-flow: 0.0.8 - axe-core: 4.10.3 - axobject-query: 4.1.0 - damerau-levenshtein: 1.0.8 - emoji-regex: 9.2.2 - eslint: 8.57.1 - hasown: 2.0.2 - jsx-ast-utils: 3.3.5 - language-tags: 1.0.9 - minimatch: 3.1.2 - object.fromentries: 2.0.8 - safe-regex-test: 1.1.0 - string.prototype.includes: 2.0.1 - eslint-plugin-jsx-a11y@6.10.2(eslint@9.33.0(jiti@2.6.1)): dependencies: aria-query: 5.3.2 @@ -26076,36 +20087,12 @@ snapshots: safe-regex-test: 1.1.0 string.prototype.includes: 2.0.1 - eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@8.57.1))(eslint@8.57.1)(prettier@3.6.2): - dependencies: - eslint: 8.57.1 - prettier: 3.6.2 - prettier-linter-helpers: 1.0.0 - synckit: 0.11.11 - optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@8.57.1) - - eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2): + eslint-plugin-prettier@5.5.4(eslint@9.33.0(jiti@2.6.1))(prettier@3.5.2): dependencies: eslint: 9.33.0(jiti@2.6.1) prettier: 3.5.2 - prettier-linter-helpers: 1.0.0 - synckit: 0.11.11 - optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@9.33.0(jiti@2.6.1)) - - eslint-plugin-prettier@5.5.4(eslint-config-prettier@10.1.8(eslint@9.33.0(jiti@2.6.1)))(eslint@9.33.0(jiti@2.6.1))(prettier@3.6.2): - dependencies: - eslint: 9.33.0(jiti@2.6.1) - prettier: 3.6.2 - prettier-linter-helpers: 1.0.0 + prettier-linter-helpers: 1.0.1 synckit: 0.11.11 - optionalDependencies: - eslint-config-prettier: 10.1.8(eslint@9.33.0(jiti@2.6.1)) - - eslint-plugin-react-hooks@5.2.0(eslint@8.57.1): - dependencies: - eslint: 8.57.1 eslint-plugin-react-hooks@7.0.1(eslint@9.33.0(jiti@2.6.1)): dependencies: @@ -26118,28 +20105,6 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-plugin-react@7.37.5(eslint@8.57.1): - dependencies: - array-includes: 3.1.9 - array.prototype.findlast: 1.2.5 - array.prototype.flatmap: 1.3.3 - array.prototype.tosorted: 1.1.4 - doctrine: 2.1.0 - es-iterator-helpers: 1.2.1 - eslint: 8.57.1 - estraverse: 5.3.0 - hasown: 2.0.2 - jsx-ast-utils: 3.3.5 - minimatch: 3.1.2 - object.entries: 1.1.9 - object.fromentries: 2.0.8 - object.values: 1.2.1 - prop-types: 15.8.1 - resolve: 2.0.0-next.5 - semver: 6.3.1 - string.prototype.matchall: 4.0.12 - string.prototype.repeat: 1.0.0 - eslint-plugin-react@7.37.5(eslint@9.33.0(jiti@2.6.1)): dependencies: array-includes: 3.1.9 @@ -26162,11 +20127,6 @@ snapshots: string.prototype.matchall: 4.0.12 string.prototype.repeat: 1.0.0 - eslint-scope@7.2.2: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - eslint-scope@8.4.0: dependencies: esrecurse: 4.3.0 @@ -26176,49 +20136,6 @@ snapshots: eslint-visitor-keys@4.2.1: {} - eslint@8.57.1: - dependencies: - '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) - '@eslint-community/regexpp': 4.12.1 - '@eslint/eslintrc': 2.1.4 - '@eslint/js': 8.57.1 - '@humanwhocodes/config-array': 0.13.0 - '@humanwhocodes/module-importer': 1.0.1 - '@nodelib/fs.walk': 1.2.8 - '@ungap/structured-clone': 1.3.0 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.1 - doctrine: 3.0.0 - escape-string-regexp: 4.0.0 - eslint-scope: 7.2.2 - eslint-visitor-keys: 3.4.3 - espree: 9.6.1 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 6.0.1 - find-up: 5.0.0 - glob-parent: 6.0.2 - globals: 13.24.0 - graphemer: 1.4.0 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - is-path-inside: 3.0.3 - js-yaml: 4.1.0 - json-stable-stringify-without-jsonify: 1.0.1 - levn: 0.4.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - strip-ansi: 6.0.1 - text-table: 0.2.0 - transitivePeerDependencies: - - supports-color - eslint@9.33.0(jiti@2.6.1): dependencies: '@eslint-community/eslint-utils': 4.7.0(eslint@9.33.0(jiti@2.6.1)) @@ -26261,17 +20178,11 @@ snapshots: transitivePeerDependencies: - supports-color - espree@10.4.0: - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 4.2.1 - - espree@9.6.1: + espree@10.4.0: dependencies: acorn: 8.15.0 acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 3.4.3 + eslint-visitor-keys: 4.2.1 esquery@1.6.0: dependencies: @@ -26325,25 +20236,10 @@ snapshots: '@scure/bip32': 1.4.0 '@scure/bip39': 1.3.0 - ethers@6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): - dependencies: - '@adraffy/ens-normalize': 1.10.1 - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@types/node': 22.7.5 - aes-js: 4.0.0-beta.5 - tslib: 2.7.0 - ws: 8.17.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - bufferutil - - utf-8-validate - event-target-shim@5.0.1: {} eventemitter2@6.4.9: {} - eventemitter3@4.0.7: {} - eventemitter3@5.0.1: {} events@3.3.0: {} @@ -26356,21 +20252,9 @@ snapshots: dependencies: eventsource-parser: 3.0.5 - execa@5.1.1: - dependencies: - cross-spawn: 7.0.6 - get-stream: 6.0.1 - human-signals: 2.1.0 - is-stream: 2.0.1 - merge-stream: 2.0.0 - npm-run-path: 4.0.1 - onetime: 5.1.2 - signal-exit: 3.0.7 - strip-final-newline: 2.0.0 - expect-type@1.2.2: {} - exponential-backoff@3.1.2: {} + exponential-backoff@3.1.3: {} express-rate-limit@7.5.1(express@5.1.0): dependencies: @@ -26449,20 +20333,11 @@ snapshots: readable-stream: 3.6.2 webextension-polyfill: 0.10.0 - extract-zip@2.0.1: - dependencies: - debug: 4.4.1 - get-stream: 5.2.0 - yauzl: 2.10.0 - optionalDependencies: - '@types/yauzl': 2.10.3 - transitivePeerDependencies: - - supports-color + eyes@0.1.8: {} - extsprintf@1.4.1: - optional: true + fast-base64-decode@1.0.0: {} - eyes@0.1.8: {} + fast-copy@3.0.2: {} fast-decode-uri-component@1.0.1: {} @@ -26507,8 +20382,6 @@ snapshots: fast-safe-stringify@2.1.1: {} - fast-sha256@1.3.0: {} - fast-stable-stringify@1.0.0: {} fast-uri@3.0.6: {} @@ -26537,9 +20410,11 @@ snapshots: dependencies: reusify: 1.1.0 - fd-slicer@1.1.0: + fb-dotslash@0.5.8: {} + + fb-watchman@2.0.2: dependencies: - pend: 1.2.0 + bser: 2.1.1 fdir@6.5.0(picomatch@4.0.3): optionalDependencies: @@ -26549,33 +20424,28 @@ snapshots: dependencies: is-retry-allowed: 3.0.0 - fecha@4.2.3: {} - - fetch-blob@3.2.0: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 - - file-entry-cache@6.0.1: - dependencies: - flat-cache: 3.2.0 - file-entry-cache@8.0.0: dependencies: flat-cache: 4.0.1 - file-uri-to-path@1.0.0: {} - - filelist@1.0.4: - dependencies: - minimatch: 5.1.6 - fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 filter-obj@1.1.0: {} + finalhandler@1.1.2: + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + finalhandler@1.3.1: dependencies: debug: 2.6.9 @@ -26617,16 +20487,10 @@ snapshots: fix-dts-default-cjs-exports@1.0.1: dependencies: - magic-string: 0.30.17 + magic-string: 0.30.21 mlly: 1.7.4 rollup: 4.46.4 - flat-cache@3.2.0: - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - rimraf: 3.0.2 - flat-cache@4.0.1: dependencies: flatted: 3.3.3 @@ -26634,7 +20498,7 @@ snapshots: flatted@3.3.3: {} - fn.name@1.1.0: {} + flow-enums-runtime@0.0.6: {} follow-redirects@1.15.11: {} @@ -26647,6 +20511,8 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + forge-light@1.1.4: {} + form-data-encoder@1.7.2: {} form-data@4.0.4: @@ -26662,53 +20528,12 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 4.0.0-beta.3 - formdata-polyfill@4.0.10: - dependencies: - fetch-blob: 3.2.0 - forwarded@0.2.0: {} fresh@0.5.2: {} fresh@2.0.0: {} - fs-extra@10.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.0 - universalify: 2.0.1 - - fs-extra@11.3.1: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 6.2.0 - universalify: 2.0.1 - - fs-extra@7.0.1: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@8.1.0: - dependencies: - graceful-fs: 4.2.11 - jsonfile: 4.0.0 - universalify: 0.1.2 - - fs-extra@9.1.0: - dependencies: - at-least-node: 1.0.0 - graceful-fs: 4.2.11 - jsonfile: 6.2.0 - universalify: 2.0.1 - - fs-minipass@2.1.0: - dependencies: - minipass: 3.3.6 - - fs.realpath@1.0.0: {} - fsevents@2.3.3: optional: true @@ -26753,8 +20578,6 @@ snapshots: dependencies: pump: 3.0.3 - get-stream@6.0.1: {} - get-symbol-description@1.1.0: dependencies: call-bound: 1.0.4 @@ -26782,37 +20605,6 @@ snapshots: package-json-from-dist: 1.0.1 path-scurry: 1.11.1 - glob@7.2.3: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 - - glob@8.1.0: - dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 5.1.6 - once: 1.4.0 - - global-agent@3.0.0: - dependencies: - boolean: 3.2.0 - es6-error: 4.1.1 - matcher: 3.0.0 - roarr: 2.15.4 - semver: 7.7.3 - serialize-error: 7.0.1 - optional: true - - globals@13.24.0: - dependencies: - type-fest: 0.20.2 - globals@14.0.0: {} globals@16.4.0: {} @@ -26822,21 +20614,8 @@ snapshots: define-properties: 1.2.1 gopd: 1.2.0 - globby@11.1.0: - dependencies: - array-union: 2.1.0 - dir-glob: 3.0.1 - fast-glob: 3.3.3 - ignore: 5.3.2 - merge2: 1.4.1 - slash: 3.0.0 - globrex@0.1.2: {} - goober@2.1.16(csstype@3.2.3): - dependencies: - csstype: 3.2.3 - gopd@1.2.0: {} got@11.8.6: @@ -26857,10 +20636,10 @@ snapshots: graphemer@1.4.0: {} - graphql-request@6.1.0(encoding@0.1.13)(graphql@16.11.0): + graphql-request@6.1.0(graphql@16.11.0): dependencies: '@graphql-typed-document-node/core': 3.2.0(graphql@16.11.0) - cross-fetch: 3.2.0(encoding@0.1.13) + cross-fetch: 3.2.0 graphql: 16.11.0 transitivePeerDependencies: - encoding @@ -26897,12 +20676,6 @@ snapshots: dependencies: has-symbols: 1.1.0 - hash-base@3.1.0: - dependencies: - inherits: 2.0.4 - readable-stream: 3.6.2 - safe-buffer: 5.2.1 - hash.js@1.1.7: dependencies: inherits: 2.0.4 @@ -26912,12 +20685,30 @@ snapshots: dependencies: function-bind: 1.1.2 + help-me@5.0.0: {} + + hermes-compiler@250829098.0.10: {} + hermes-estree@0.25.1: {} + hermes-estree@0.33.3: {} + + hermes-estree@0.35.0: {} + hermes-parser@0.25.1: dependencies: hermes-estree: 0.25.1 + hermes-parser@0.33.3: + dependencies: + hermes-estree: 0.33.3 + + hermes-parser@0.35.0: + dependencies: + hermes-estree: 0.35.0 + + hi-base32@0.5.1: {} + hmac-drbg@1.0.1: dependencies: hash.js: 1.1.7 @@ -26926,29 +20717,10 @@ snapshots: hono@4.10.7: {} - hosted-git-info@4.1.0: - dependencies: - lru-cache: 6.0.0 - html-encoding-sniffer@4.0.0: dependencies: whatwg-encoding: 3.1.1 - html-to-text@9.0.5: - dependencies: - '@selderee/plugin-htmlparser2': 0.11.0 - deepmerge: 4.3.1 - dom-serializer: 2.0.0 - htmlparser2: 8.0.2 - selderee: 0.11.0 - - htmlparser2@8.0.2: - dependencies: - domelementtype: 2.3.0 - domhandler: 5.0.3 - domutils: 3.2.2 - entities: 4.5.0 - http-cache-semantics@4.2.0: {} http-errors@2.0.0: @@ -26959,14 +20731,6 @@ snapshots: statuses: 2.0.1 toidentifier: 1.0.1 - http-proxy-agent@5.0.0: - dependencies: - '@tootallnate/once': 2.0.0 - agent-base: 6.0.2 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - http-proxy-agent@7.0.2: dependencies: agent-base: 7.1.4 @@ -26979,13 +20743,6 @@ snapshots: quick-lru: 5.1.1 resolve-alpn: 1.2.1 - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - https-proxy-agent@7.0.6: dependencies: agent-base: 7.1.4 @@ -26993,18 +20750,10 @@ snapshots: transitivePeerDependencies: - supports-color - human-signals@2.1.0: {} - humanize-ms@1.2.1: dependencies: ms: 2.1.3 - iconv-corefoundation@1.1.7: - dependencies: - cli-truncate: 2.1.0 - node-addon-api: 1.7.2 - optional: true - iconv-lite@0.4.24: dependencies: safer-buffer: 2.1.2 @@ -27023,6 +20772,10 @@ snapshots: ignore@7.0.5: {} + image-size@1.2.1: + dependencies: + queue: 6.0.2 + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -27030,15 +20783,6 @@ snapshots: imurmurhash@0.1.4: {} - indent-string@4.0.0: {} - - infer-owner@1.0.4: {} - - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - inherits@2.0.4: {} internal-slot@1.1.0: @@ -27047,7 +20791,9 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 - ip-address@10.0.1: {} + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 ipaddr.js@1.9.1: {} @@ -27066,10 +20812,6 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 - is-arrayish@0.2.1: {} - - is-arrayish@0.3.2: {} - is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -27082,10 +20824,6 @@ snapshots: dependencies: has-bigints: 1.1.0 - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - is-boolean-object@1.2.2: dependencies: call-bound: 1.0.4 @@ -27093,18 +20831,12 @@ snapshots: is-buffer@1.1.6: {} - is-buffer@2.0.5: {} - is-bun-module@2.0.0: dependencies: semver: 7.7.3 is-callable@1.2.7: {} - is-ci@3.0.1: - dependencies: - ci-info: 3.9.0 - is-core-module@2.16.1: dependencies: hasown: 2.0.2 @@ -27120,6 +20852,8 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-docker@2.2.1: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -27139,16 +20873,10 @@ snapshots: dependencies: is-extglob: 2.1.1 - is-interactive@1.0.0: {} - - is-lambda@1.0.1: {} - is-map@2.0.3: {} is-negative-zero@2.0.3: {} - is-network-error@1.1.0: {} - is-number-object@1.1.1: dependencies: call-bound: 1.0.4 @@ -27156,8 +20884,6 @@ snapshots: is-number@7.0.0: {} - is-path-inside@3.0.3: {} - is-potential-custom-element-name@1.0.1: {} is-promise@4.0.0: {} @@ -27196,7 +20922,7 @@ snapshots: dependencies: which-typed-array: 1.1.19 - is-unicode-supported@0.1.0: {} + is-typedarray@1.0.0: {} is-weakmap@2.0.2: {} @@ -27209,14 +20935,14 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + isarray@1.0.0: {} isarray@2.0.5: {} - isbinaryfile@4.0.10: {} - - isbinaryfile@5.0.4: {} - isexe@2.0.0: {} isomorphic-ws@4.0.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10)): @@ -27227,7 +20953,7 @@ snapshots: dependencies: ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - isows@1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)): + isows@1.0.7(ws@8.18.3): dependencies: ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) @@ -27246,12 +20972,6 @@ snapshots: optionalDependencies: '@pkgjs/parseargs': 0.11.0 - jake@10.9.4: - dependencies: - async: 3.2.6 - filelist: 1.0.4 - picocolors: 1.1.1 - jayson@4.2.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): dependencies: '@types/connect': 3.4.38 @@ -27270,11 +20990,34 @@ snapshots: - bufferutil - utf-8-validate - jiti@1.21.7: {} + jest-get-type@29.6.3: {} - jiti@2.6.1: {} + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.17.2 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-worker@29.7.0: + dependencies: + '@types/node': 22.17.2 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 - jose@4.15.9: {} + jiti@2.6.1: {} jose@5.10.0: {} @@ -27282,11 +21025,17 @@ snapshots: joycon@3.1.1: {} + js-base64@3.7.4: {} + + js-base64@3.7.7: {} + js-base64@3.7.8: {} - js-tiktoken@1.0.21: - dependencies: - base64-js: 1.5.1 + js-sha256@0.9.0: {} + + js-sha3@0.8.0: {} + + js-sha512@0.8.0: {} js-tokens@4.0.0: {} @@ -27296,6 +21045,8 @@ snapshots: dependencies: argparse: 2.0.1 + jsc-safe-url@0.2.4: {} + jsdoc-type-pratt-parser@4.1.0: {} jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): @@ -27325,13 +21076,13 @@ snapshots: - supports-color - utf-8-validate - jsesc@3.0.2: {} - jsesc@3.1.0: {} - json-buffer@3.0.1: {} + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 - json-parse-even-better-errors@2.3.1: {} + json-buffer@3.0.1: {} json-rpc-engine@6.1.0: dependencies: @@ -27358,16 +21109,6 @@ snapshots: json5@2.2.3: {} - jsonfile@4.0.0: - optionalDependencies: - graceful-fs: 4.2.11 - - jsonfile@6.2.0: - dependencies: - universalify: 2.0.1 - optionalDependencies: - graceful-fs: 4.2.11 - jsx-ast-utils@3.3.5: dependencies: array-includes: 3.1.9 @@ -27389,43 +21130,32 @@ snapshots: keyvaluestorage-interface@1.0.0: {} - kuler@2.0.0: {} - - langsmith@0.3.62(openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)): - dependencies: - '@types/uuid': 10.0.0 - chalk: 4.1.2 - console-table-printer: 2.14.6 - p-queue: 6.6.2 - p-retry: 4.6.2 - semver: 7.7.3 - uuid: 10.0.0 - optionalDependencies: - openai: 5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - language-subtag-registry@0.3.23: {} language-tags@1.0.9: dependencies: language-subtag-registry: 0.3.23 - lazy-val@1.0.5: {} - - leac@0.6.0: {} + leven@3.1.0: {} levn@0.4.1: dependencies: prelude-ls: 1.2.1 type-check: 0.4.0 - libphonenumber-js@1.12.13: {} - light-my-request@6.6.0: dependencies: cookie: 1.1.1 process-warning: 4.0.1 set-cookie-parser: 2.7.2 + lighthouse-logger@1.4.2: + dependencies: + debug: 2.6.9 + marky: 1.3.0 + transitivePeerDependencies: + - supports-color + lightningcss-android-arm64@1.30.2: optional: true @@ -27495,28 +21225,6 @@ snapshots: lit-element: 4.2.1 lit-html: 3.3.1 - llamaindex@0.10.6(encoding@0.1.13)(tree-sitter@0.22.4)(web-tree-sitter@0.24.7)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): - dependencies: - '@llamaindex/cloud': 4.0.7(@llamaindex/core@0.6.5)(@llamaindex/env@0.1.30) - '@llamaindex/core': 0.6.5 - '@llamaindex/env': 0.1.30 - '@llamaindex/node-parser': 2.0.5(@llamaindex/core@0.6.5)(@llamaindex/env@0.1.30)(tree-sitter@0.22.4)(web-tree-sitter@0.24.7) - '@llamaindex/openai': 0.3.7(@llamaindex/core@0.6.5)(@llamaindex/env@0.1.30)(encoding@0.1.13)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - '@llamaindex/workflow': 1.0.3(@llamaindex/core@0.6.5)(@llamaindex/env@0.1.30)(zod@3.25.76) - '@types/lodash': 4.17.20 - '@types/node': 22.17.2 - ajv: 8.17.1 - lodash: 4.17.21 - magic-bytes.js: 1.12.1 - transitivePeerDependencies: - - '@huggingface/transformers' - - encoding - - gpt-tokenizer - - tree-sitter - - web-tree-sitter - - ws - - zod - load-tsconfig@0.2.5: {} locate-path@5.0.0: @@ -27527,6 +21235,8 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.camelcase@4.3.0: {} + lodash.debounce@4.0.8: {} lodash.memoize@4.1.2: {} @@ -27535,31 +21245,19 @@ snapshots: lodash.sortby@4.7.0: {} - lodash@4.17.21: {} + lodash.throttle@4.1.1: {} - log-symbols@4.1.0: - dependencies: - chalk: 4.1.2 - is-unicode-supported: 0.1.0 + lodash@4.17.21: {} - logform@2.7.0: - dependencies: - '@colors/colors': 1.6.0 - '@types/triple-beam': 1.3.5 - fecha: 4.2.3 - ms: 2.1.3 - safe-stable-stringify: 2.5.0 - triple-beam: 1.4.1 + long@5.3.1: {} loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 - loupe@3.2.0: {} + lottie-web@5.13.0: {} - lower-case@2.0.2: - dependencies: - tslib: 2.8.1 + loupe@3.2.0: {} lowercase-keys@2.0.0: {} @@ -27569,86 +21267,218 @@ snapshots: dependencies: yallist: 3.1.1 - lru-cache@6.0.0: + lute-connect@1.7.0: {} + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + make-error@1.3.6: {} + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + marky@1.3.0: {} + + math-intrinsics@1.1.0: {} + + md5@2.3.0: dependencies: - yallist: 4.0.0 + charenc: 0.0.2 + crypt: 0.0.2 + is-buffer: 1.1.6 + + media-typer@0.3.0: {} + + media-typer@1.1.0: {} + + memoize-one@5.2.1: {} - lru-cache@7.18.3: {} + merge-descriptors@1.0.3: {} + + merge-descriptors@2.0.0: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} - magic-bytes.js@1.12.1: {} + methods@1.1.2: {} - magic-string@0.30.17: + metro-babel-transformer@0.84.3: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@babel/core': 7.28.3 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.35.0 + metro-cache-key: 0.84.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color - magic-string@0.30.21: + metro-cache-key@0.84.3: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + flow-enums-runtime: 0.0.6 - make-fetch-happen@10.2.1: + metro-cache@0.84.3: dependencies: - agentkeepalive: 4.6.0 - cacache: 16.1.3 - http-cache-semantics: 4.2.0 - http-proxy-agent: 5.0.0 - https-proxy-agent: 5.0.1 - is-lambda: 1.0.1 - lru-cache: 7.18.3 - minipass: 3.3.6 - minipass-collect: 1.0.2 - minipass-fetch: 2.1.2 - minipass-flush: 1.0.5 - minipass-pipeline: 1.2.4 - negotiator: 0.6.4 - promise-retry: 2.0.1 - socks-proxy-agent: 7.0.0 - ssri: 9.0.1 - transitivePeerDependencies: - - bluebird + exponential-backoff: 3.1.3 + flow-enums-runtime: 0.0.6 + https-proxy-agent: 7.0.6 + metro-core: 0.84.3 + transitivePeerDependencies: - supports-color - matcher@3.0.0: + metro-config@0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): dependencies: - escape-string-regexp: 4.0.0 - optional: true - - math-intrinsics@1.1.0: {} + connect: 3.7.0 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-cache: 0.84.3 + metro-core: 0.84.3 + metro-runtime: 0.84.3 + yaml: 2.8.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate - md5.js@1.3.5: + metro-core@0.84.3: dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 - safe-buffer: 5.2.1 + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.84.3 - md5@2.3.0: + metro-file-map@0.84.3: dependencies: - charenc: 0.0.2 - crypt: 0.0.2 - is-buffer: 1.1.6 - - mdn-data@2.0.28: {} - - mdn-data@2.0.30: {} + debug: 4.4.1 + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + nullthrows: 1.1.1 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color - media-typer@0.3.0: {} + metro-minify-terser@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + terser: 5.46.2 - media-typer@1.1.0: {} + metro-resolver@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 - merge-descriptors@1.0.3: {} + metro-runtime@0.84.3: + dependencies: + '@babel/runtime': 7.28.3 + flow-enums-runtime: 0.0.6 - merge-descriptors@2.0.0: {} + metro-source-map@0.84.3: + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.84.3 + nullthrows: 1.1.1 + ob1: 0.84.3 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color - merge-stream@2.0.0: {} + metro-symbolicate@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.84.3 + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color - merge2@1.4.1: {} + metro-transform-plugins@0.84.3: + dependencies: + '@babel/core': 7.28.3 + '@babel/generator': 7.29.1 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color - merkletreejs@0.5.2: + metro-transform-worker@0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): dependencies: - buffer-reverse: 1.0.1 - crypto-js: 4.2.0 - treeify: 1.1.0 + '@babel/core': 7.28.3 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + metro: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-babel-transformer: 0.84.3 + metro-cache: 0.84.3 + metro-cache-key: 0.84.3 + metro-minify-terser: 0.84.3 + metro-source-map: 0.84.3 + metro-transform-plugins: 0.84.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate - methods@1.1.2: {} + metro@0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/core': 7.28.3 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + accepts: 2.0.0 + chalk: 4.1.2 + ci-info: 2.0.0 + connect: 3.7.0 + debug: 4.4.1 + error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + hermes-parser: 0.35.0 + image-size: 1.2.1 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.84.3 + metro-cache: 0.84.3 + metro-cache-key: 0.84.3 + metro-config: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-core: 0.84.3 + metro-file-map: 0.84.3 + metro-resolver: 0.84.3 + metro-runtime: 0.84.3 + metro-source-map: 0.84.3 + metro-symbolicate: 0.84.3 + metro-transform-plugins: 0.84.3 + metro-transform-worker: 0.84.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + mime-types: 3.0.1 + nullthrows: 1.1.1 + serialize-error: 2.1.0 + source-map: 0.5.7 + throat: 5.0.0 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate micro-ftch@0.3.1: {} @@ -27671,10 +21501,6 @@ snapshots: mime@1.6.0: {} - mime@2.6.0: {} - - mimic-fn@2.1.0: {} - mimic-response@1.0.1: {} mimic-response@3.1.0: {} @@ -27683,68 +21509,25 @@ snapshots: minimalistic-crypto-utils@1.0.1: {} - minimatch@10.0.3: - dependencies: - '@isaacs/brace-expansion': 5.0.0 - minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.2 - minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 minimist@1.2.8: {} - minipass-collect@1.0.2: - dependencies: - minipass: 3.3.6 - - minipass-fetch@2.1.2: - dependencies: - minipass: 3.3.6 - minipass-sized: 1.0.3 - minizlib: 2.1.2 - optionalDependencies: - encoding: 0.1.13 - - minipass-flush@1.0.5: - dependencies: - minipass: 3.3.6 - - minipass-pipeline@1.2.4: - dependencies: - minipass: 3.3.6 - - minipass-sized@1.0.3: - dependencies: - minipass: 3.3.6 - - minipass@3.3.6: - dependencies: - yallist: 4.0.0 - - minipass@5.0.0: {} - minipass@7.1.2: {} - minizlib@2.1.2: - dependencies: - minipass: 3.3.6 - yallist: 4.0.0 - mipd@0.0.7(typescript@5.9.2): optionalDependencies: typescript: 5.9.2 - mkdirp@0.5.6: - dependencies: - minimist: 1.2.8 + mipd@0.0.7(typescript@5.9.3): + optionalDependencies: + typescript: 5.9.3 mkdirp@1.0.4: {} @@ -27763,8 +21546,6 @@ snapshots: multiformats@9.9.0: {} - mustache@4.2.0: {} - mz@2.7.0: dependencies: any-promise: 1.3.0 @@ -27779,33 +21560,8 @@ snapshots: negotiator@0.6.3: {} - negotiator@0.6.4: {} - negotiator@1.0.0: {} - next@15.5.9(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - '@next/env': 15.5.9 - '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001735 - postcss: 8.4.31 - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - styled-jsx: 5.1.6(@babel/core@7.28.3)(react@19.2.3) - optionalDependencies: - '@next/swc-darwin-arm64': 15.5.7 - '@next/swc-darwin-x64': 15.5.7 - '@next/swc-linux-arm64-gnu': 15.5.7 - '@next/swc-linux-arm64-musl': 15.5.7 - '@next/swc-linux-x64-gnu': 15.5.7 - '@next/swc-linux-x64-musl': 15.5.7 - '@next/swc-win32-arm64-msvc': 15.5.7 - '@next/swc-win32-x64-msvc': 15.5.7 - sharp: 0.34.5 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - next@16.0.10(@babel/core@7.28.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3): dependencies: '@next/env': 16.0.10 @@ -27829,68 +21585,36 @@ snapshots: - '@babel/core' - babel-plugin-macros - no-case@3.0.4: - dependencies: - lower-case: 2.0.2 - tslib: 2.8.1 - - node-abi@3.75.0: - dependencies: - semver: 7.7.3 - - node-addon-api@1.7.2: - optional: true - node-addon-api@2.0.2: {} - node-addon-api@5.1.0: {} - - node-addon-api@8.5.0: {} - - node-api-version@0.2.1: - dependencies: - semver: 7.7.3 - node-domexception@1.0.0: {} node-fetch-native@1.6.7: {} - node-fetch@2.7.0(encoding@0.1.13): + node-fetch@2.7.0: dependencies: whatwg-url: 5.0.0 - optionalDependencies: - encoding: 0.1.13 - - node-fetch@3.3.2: - dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 node-gyp-build@4.8.4: {} + node-int64@0.4.0: {} + node-mock-http@1.0.2: {} node-releases@2.0.19: {} - nopt@6.0.0: - dependencies: - abbrev: 1.1.1 - normalize-path@3.0.0: {} normalize-url@6.1.0: {} - npm-run-path@4.0.1: - dependencies: - path-key: 3.1.1 - - nth-check@2.1.1: - dependencies: - boolbase: 1.0.0 + nullthrows@1.1.1: {} nwsapi@2.2.21: {} + ob1@0.84.3: + dependencies: + flow-enums-runtime: 0.0.6 + obj-multiplex@1.0.0: dependencies: end-of-stream: 1.4.5 @@ -27899,8 +21623,6 @@ snapshots: object-assign@4.1.1: {} - object-hash@3.0.0: {} - object-inspect@1.13.4: {} object-keys@1.1.1: {} @@ -27951,6 +21673,10 @@ snapshots: on-exit-leak-free@2.1.2: {} + on-finished@2.3.0: + dependencies: + ee-first: 1.1.1 + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -27959,30 +21685,12 @@ snapshots: dependencies: wrappy: 1.0.2 - one-time@1.0.0: - dependencies: - fn.name: 1.1.0 - - onetime@5.1.2: - dependencies: - mimic-fn: 2.1.0 - - openai@4.104.0(encoding@0.1.13)(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): + open@7.4.2: dependencies: - '@types/node': 18.19.123 - '@types/node-fetch': 2.6.13 - abort-controller: 3.0.0 - agentkeepalive: 4.6.0 - form-data-encoder: 1.7.2 - formdata-node: 4.4.1 - node-fetch: 2.7.0(encoding@0.1.13) - optionalDependencies: - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) - zod: 3.25.76 - transitivePeerDependencies: - - encoding + is-docker: 2.2.1 + is-wsl: 2.2.0 - openai@4.104.0(encoding@0.1.13)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): + openai@4.104.0(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): dependencies: '@types/node': 18.19.123 '@types/node-fetch': 2.6.13 @@ -27990,32 +21698,19 @@ snapshots: agentkeepalive: 4.6.0 form-data-encoder: 1.7.2 formdata-node: 4.4.1 - node-fetch: 2.7.0(encoding@0.1.13) + node-fetch: 2.7.0 optionalDependencies: ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) zod: 3.25.76 transitivePeerDependencies: - encoding - openai@5.13.1(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): - optionalDependencies: - ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) - zod: 3.25.76 - openapi-fetch@0.13.8: dependencies: openapi-typescript-helpers: 0.0.15 openapi-typescript-helpers@0.0.15: {} - opensea-js@7.2.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): - dependencies: - '@opensea/seaport-js': 4.0.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) - ethers: 6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - bufferutil - - utf-8-validate - optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -28025,25 +21720,13 @@ snapshots: type-check: 0.4.0 word-wrap: 1.2.5 - ora@5.4.1: - dependencies: - bl: 4.1.0 - chalk: 4.1.2 - cli-cursor: 3.1.0 - cli-spinners: 2.9.2 - is-interactive: 1.0.0 - is-unicode-supported: 0.1.0 - log-symbols: 4.1.0 - strip-ansi: 6.0.1 - wcwidth: 1.0.1 - own-keys@1.0.1: dependencies: get-intrinsic: 1.3.0 object-keys: 1.1.1 safe-push-apply: 1.0.0 - ox@0.11.1(typescript@5.9.2)(zod@3.22.4): + ox@0.14.20(typescript@5.9.2)(zod@3.22.4): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/ciphers': 1.3.0 @@ -28058,7 +21741,7 @@ snapshots: transitivePeerDependencies: - zod - ox@0.11.1(typescript@5.9.2)(zod@3.25.76): + ox@0.14.20(typescript@5.9.2)(zod@3.25.76): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/ciphers': 1.3.0 @@ -28073,7 +21756,7 @@ snapshots: transitivePeerDependencies: - zod - ox@0.11.1(typescript@5.9.2)(zod@4.1.13): + ox@0.14.20(typescript@5.9.3)(zod@3.22.4): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/ciphers': 1.3.0 @@ -28081,70 +21764,72 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) + abitype: 1.2.3(typescript@5.9.3)(zod@3.22.4) eventemitter3: 5.0.1 optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - zod - ox@0.4.4(typescript@5.9.2)(zod@3.25.76): + ox@0.14.20(typescript@5.9.3)(zod@3.25.76): dependencies: '@adraffy/ens-normalize': 1.11.0 - '@noble/curves': 1.9.7 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) eventemitter3: 5.0.1 optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - zod - ox@0.4.4(typescript@5.9.2)(zod@4.1.13): + ox@0.14.20(typescript@5.9.3)(zod@4.1.13): dependencies: '@adraffy/ens-normalize': 1.11.0 - '@noble/curves': 1.9.7 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) + abitype: 1.2.3(typescript@5.9.3)(zod@4.1.13) eventemitter3: 5.0.1 optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - zod - ox@0.6.7(typescript@5.9.2)(zod@3.25.76): + ox@0.4.4(typescript@5.9.3)(zod@3.25.76): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) eventemitter3: 5.0.1 optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - zod - ox@0.6.7(typescript@5.9.2)(zod@4.1.13): + ox@0.4.4(typescript@5.9.3)(zod@4.1.13): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) + abitype: 1.2.3(typescript@5.9.3)(zod@4.1.13) eventemitter3: 5.0.1 optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - zod - ox@0.6.9(typescript@5.9.2)(zod@3.25.76): + ox@0.6.7(typescript@5.9.2)(zod@3.25.76): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/curves': 1.9.7 @@ -28158,24 +21843,23 @@ snapshots: transitivePeerDependencies: - zod - ox@0.6.9(typescript@5.9.2)(zod@4.1.13): + ox@0.6.7(typescript@5.9.3)(zod@4.1.13): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) + abitype: 1.2.3(typescript@5.9.3)(zod@4.1.13) eventemitter3: 5.0.1 optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - zod - ox@0.8.1(typescript@5.9.2)(zod@3.25.76): + ox@0.6.9(typescript@5.9.2)(zod@3.25.76): dependencies: '@adraffy/ens-normalize': 1.11.0 - '@noble/ciphers': 1.3.0 '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 @@ -28187,6 +21871,20 @@ snapshots: transitivePeerDependencies: - zod + ox@0.6.9(typescript@5.9.3)(zod@4.1.13): + dependencies: + '@adraffy/ens-normalize': 1.11.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@4.1.13) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - zod + ox@0.9.17(typescript@5.9.2)(zod@4.1.13): dependencies: '@adraffy/ens-normalize': 1.11.0 @@ -28202,7 +21900,7 @@ snapshots: transitivePeerDependencies: - zod - ox@0.9.6(typescript@5.9.2)(zod@3.25.76): + ox@0.9.17(typescript@5.9.3)(zod@4.1.13): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/ciphers': 1.3.0 @@ -28210,14 +21908,14 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.9.3)(zod@4.1.13) eventemitter3: 5.0.1 optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - zod - ox@0.9.6(typescript@5.9.2)(zod@4.1.13): + ox@0.9.3(typescript@5.9.2)(zod@3.25.76): dependencies: '@adraffy/ens-normalize': 1.11.0 '@noble/ciphers': 1.3.0 @@ -28225,7 +21923,7 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) + abitype: 1.2.3(typescript@5.9.2)(zod@3.25.76) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.2 @@ -28234,8 +21932,6 @@ snapshots: p-cancelable@2.1.1: {} - p-finally@1.0.0: {} - p-limit@2.3.0: dependencies: p-try: 2.2.0 @@ -28252,30 +21948,6 @@ snapshots: dependencies: p-limit: 3.1.0 - p-map@4.0.0: - dependencies: - aggregate-error: 3.1.0 - - p-queue@6.6.2: - dependencies: - eventemitter3: 4.0.7 - p-timeout: 3.2.0 - - p-retry@4.6.2: - dependencies: - '@types/retry': 0.12.0 - retry: 0.13.1 - - p-retry@6.2.1: - dependencies: - '@types/retry': 0.12.2 - is-network-error: 1.1.0 - retry: 0.13.1 - - p-timeout@3.2.0: - dependencies: - p-finally: 1.0.0 - p-try@2.2.0: {} package-json-from-dist@1.0.1: {} @@ -28288,30 +21960,16 @@ snapshots: dependencies: parse-statements: 1.0.11 - parse-json@5.2.0: - dependencies: - '@babel/code-frame': 7.27.1 - error-ex: 1.3.2 - json-parse-even-better-errors: 2.3.1 - lines-and-columns: 1.2.4 - parse-statements@1.0.11: {} parse5@7.3.0: dependencies: entities: 6.0.1 - parseley@0.12.1: - dependencies: - leac: 0.6.0 - peberminta: 0.9.0 - parseurl@1.3.3: {} path-exists@4.0.0: {} - path-is-absolute@1.0.1: {} - path-key@3.1.1: {} path-parse@1.0.7: {} @@ -28325,28 +21983,16 @@ snapshots: path-to-regexp@8.2.0: {} - path-type@4.0.0: {} - - pathe@1.1.2: {} - pathe@2.0.3: {} pathval@2.0.1: {} - pe-library@0.4.1: {} - - peberminta@0.9.0: {} - - pend@1.2.0: {} - picocolors@1.1.1: {} picomatch@2.3.1: {} picomatch@4.0.3: {} - pify@2.3.0: {} - pify@3.0.0: {} pify@5.0.0: {} @@ -28356,14 +22002,62 @@ snapshots: duplexify: 4.1.3 split2: 4.2.0 + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + pino-abstract-transport@3.0.0: dependencies: split2: 4.2.0 + pino-pretty@13.0.0: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pump: 3.0.3 + secure-json-parse: 2.7.0 + sonic-boom: 4.2.1 + strip-json-comments: 3.1.1 + pino-std-serializers@4.0.0: {} pino-std-serializers@7.1.0: {} + pino@10.0.0: + dependencies: + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + slow-redact: 0.3.2 + sonic-boom: 4.2.1 + thread-stream: 3.1.0 + + pino@10.1.0: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 3.1.0 + pino@10.3.1: dependencies: '@pinojs/redact': 0.4.0 @@ -28402,171 +22096,47 @@ snapshots: mlly: 1.7.4 pathe: 2.0.3 - plist@3.1.0: - dependencies: - '@xmldom/xmldom': 0.8.11 - base64-js: 1.5.1 - xmlbuilder: 15.1.1 - pngjs@5.0.0: {} pony-cause@2.1.11: {} - porto@0.2.35(@tanstack/react-query@5.90.11(react@19.1.1))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.1.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)): + porto@0.2.35(1feacaf19428654ec6ac600c205f8b1e): dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) hono: 4.10.7 idb-keyval: 6.2.2 mipd: 0.0.7(typescript@5.9.2) ox: 0.9.17(typescript@5.9.2)(zod@4.1.13) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zod: 4.1.13 zustand: 5.0.8(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.4.0(react@19.1.1)) optionalDependencies: '@tanstack/react-query': 5.90.11(react@19.1.1) react: 19.1.1 + react-native: 0.85.2(@babel/core@7.28.3)(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10) typescript: 5.9.2 - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.1.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - transitivePeerDependencies: - - '@types/react' - - immer - - use-sync-external-store - - porto@0.2.35(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)): - dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - hono: 4.10.7 - idb-keyval: 6.2.2 - mipd: 0.0.7(typescript@5.9.2) - ox: 0.9.17(typescript@5.9.2)(zod@4.1.13) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zod: 4.1.13 - zustand: 5.0.8(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) - optionalDependencies: - '@tanstack/react-query': 5.90.11(react@19.2.1) - react: 19.2.1 - typescript: 5.9.2 - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - transitivePeerDependencies: - - '@types/react' - - immer - - use-sync-external-store - - porto@0.2.35(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76)): - dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - hono: 4.10.7 - idb-keyval: 6.2.2 - mipd: 0.0.7(typescript@5.9.2) - ox: 0.9.17(typescript@5.9.2)(zod@4.1.13) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zod: 4.1.13 - zustand: 5.0.8(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) - optionalDependencies: - '@tanstack/react-query': 5.90.11(react@19.2.1) - react: 19.2.1 - typescript: 5.9.2 - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) - transitivePeerDependencies: - - '@types/react' - - immer - - use-sync-external-store - - porto@0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)): - dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - hono: 4.10.7 - idb-keyval: 6.2.2 - mipd: 0.0.7(typescript@5.9.2) - ox: 0.9.17(typescript@5.9.2)(zod@4.1.13) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - zod: 4.1.13 - zustand: 5.0.8(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) - optionalDependencies: - '@tanstack/react-query': 5.90.11(react@19.2.3) - react: 19.2.3 - typescript: 5.9.2 - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - transitivePeerDependencies: - - '@types/react' - - immer - - use-sync-external-store - - porto@0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)): - dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.5.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - hono: 4.10.7 - idb-keyval: 6.2.2 - mipd: 0.0.7(typescript@5.9.2) - ox: 0.9.17(typescript@5.9.2)(zod@4.1.13) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - zod: 4.1.13 - zustand: 5.0.8(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) - optionalDependencies: - '@tanstack/react-query': 5.90.11(react@19.2.3) - react: 19.2.3 - typescript: 5.9.2 - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - transitivePeerDependencies: - - '@types/react' - - immer - - use-sync-external-store - - porto@0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)): - dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - hono: 4.10.7 - idb-keyval: 6.2.2 - mipd: 0.0.7(typescript@5.9.2) - ox: 0.9.17(typescript@5.9.2)(zod@4.1.13) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - zod: 4.1.13 - zustand: 5.0.8(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) - optionalDependencies: - '@tanstack/react-query': 5.90.11(react@19.2.3) - react: 19.2.3 - typescript: 5.9.2 - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - transitivePeerDependencies: - - '@types/react' - - immer - - use-sync-external-store - - porto@0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)): - dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - hono: 4.10.7 - idb-keyval: 6.2.2 - mipd: 0.0.7(typescript@5.9.2) - ox: 0.9.17(typescript@5.9.2)(zod@4.1.13) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - zod: 4.1.13 - zustand: 5.0.8(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) - optionalDependencies: - '@tanstack/react-query': 5.90.11(react@19.2.3) - react: 19.2.3 - typescript: 5.9.2 - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) + wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.1.1))(@types/react@19.1.10)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76) transitivePeerDependencies: - '@types/react' - immer - use-sync-external-store - porto@0.2.35(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13)): + porto@0.2.35(e22920c46066f44d72e0dbd21e289d8b): dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)) hono: 4.10.7 idb-keyval: 6.2.2 - mipd: 0.0.7(typescript@5.9.2) - ox: 0.9.17(typescript@5.9.2)(zod@4.1.13) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + mipd: 0.0.7(typescript@5.9.3) + ox: 0.9.17(typescript@5.9.3)(zod@4.1.13) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) zod: 4.1.13 zustand: 5.0.8(@types/react@19.2.1)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) optionalDependencies: '@tanstack/react-query': 5.90.11(react@19.2.3) react: 19.2.3 - typescript: 5.9.2 - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) + react-native: 0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10) + typescript: 5.9.3 + wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) transitivePeerDependencies: - '@types/react' - immer @@ -28576,46 +22146,15 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-import@15.1.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - read-cache: 1.0.0 - resolve: 1.22.10 - - postcss-js@4.0.1(postcss@8.5.6): - dependencies: - camelcase-css: 2.0.1 - postcss: 8.5.6 - - postcss-load-config@4.0.2(postcss@8.5.6): - dependencies: - lilconfig: 3.1.3 - yaml: 2.8.1 - optionalDependencies: - postcss: 8.5.6 - - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(yaml@2.8.1): + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.1): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.6.1 postcss: 8.5.6 - tsx: 4.20.4 + tsx: 4.21.0 yaml: 2.8.1 - postcss-nested@6.2.0(postcss@8.5.6): - dependencies: - postcss: 8.5.6 - postcss-selector-parser: 6.1.2 - - postcss-selector-parser@6.1.2: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - postcss-value-parser@4.2.0: {} - postcss@8.4.31: dependencies: nanoid: 3.3.11 @@ -28628,26 +22167,23 @@ snapshots: picocolors: 1.1.1 source-map-js: 1.2.1 - postject@1.0.0-alpha.6: - dependencies: - commander: 9.5.0 - optional: true - preact@10.24.2: {} preact@10.27.1: {} prelude-ls@1.2.1: {} - prettier-linter-helpers@1.0.0: + prettier-linter-helpers@1.0.1: dependencies: fast-diff: 1.3.0 prettier@3.5.2: {} - prettier@3.6.2: {} - - proc-log@2.0.1: {} + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 process-nextick-args@2.0.1: {} @@ -28657,14 +22193,9 @@ snapshots: process-warning@5.0.0: {} - progress@2.0.3: {} - - promise-inflight@1.0.1: {} - - promise-retry@2.0.1: + promise@8.3.0: dependencies: - err-code: 2.0.3 - retry: 0.12.0 + asap: 2.0.6 prop-types@15.8.1: dependencies: @@ -28672,6 +22203,21 @@ snapshots: object-assign: 4.1.1 react-is: 16.13.1 + protobufjs@7.5.4: + 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': 22.17.2 + long: 5.3.1 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -28688,7 +22234,17 @@ snapshots: punycode@2.3.1: {} - qr.js@0.0.0: {} + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.5: {} + + qr-code-styling@1.6.0-rc.1: + dependencies: + qrcode-generator: 1.5.2 + + qrcode-generator@1.5.2: {} qrcode@1.5.3: dependencies: @@ -28711,6 +22267,12 @@ snapshots: dependencies: side-channel: 1.1.0 + query-string@6.13.5: + dependencies: + decode-uri-component: 0.2.2 + split-on-first: 1.1.0 + strict-uri-encode: 2.0.0 + query-string@7.1.3: dependencies: decode-uri-component: 0.2.2 @@ -28718,77 +22280,16 @@ snapshots: split-on-first: 1.1.0 strict-uri-encode: 2.0.0 - querystringify@2.2.0: {} - queue-microtask@1.2.3: {} + queue@6.0.2: + dependencies: + inherits: 2.0.4 + quick-format-unescaped@4.0.4: {} quick-lru@5.1.1: {} - radix-ui@1.4.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1): - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-accessible-icon': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-aspect-ratio': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-avatar': 1.1.10(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-form': 0.1.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-menubar': 1.1.16(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-one-time-password-field': 0.1.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-password-toggle-field': 0.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-progress': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-select': 2.2.6(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slider': 1.3.6(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-switch': 1.2.6(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toast': 1.2.15(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-toolbar': 1.1.11(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.1)(react@18.3.1) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.1(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@18.3.1(react@18.3.1))(react@18.3.1) - react: 18.3.1 - react-dom: 18.3.1(react@18.3.1) - optionalDependencies: - '@types/react': 19.2.1 - '@types/react-dom': 19.2.1(@types/react@19.2.1) - radix3@1.1.2: {} randombytes@2.1.0: @@ -28811,68 +22312,131 @@ snapshots: iconv-lite: 0.6.3 unpipe: 1.0.0 - react-dom@18.3.1(react@18.3.1): + react-devtools-core@6.1.5(bufferutil@4.0.9)(utf-8-validate@5.0.10): dependencies: - loose-envify: 1.4.0 - react: 18.3.1 - scheduler: 0.23.2 + shell-quote: 1.8.3 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate react-dom@19.1.1(react@19.1.1): dependencies: react: 19.1.1 scheduler: 0.26.0 - react-dom@19.2.1(react@19.2.1): - dependencies: - react: 19.2.1 - scheduler: 0.27.0 - react-dom@19.2.3(react@19.2.3): dependencies: react: 19.2.3 scheduler: 0.27.0 - react-hot-toast@2.6.0(react-dom@19.2.3(react@19.2.3))(react@19.2.3): - dependencies: - csstype: 3.2.3 - goober: 2.1.16(csstype@3.2.3) - react: 19.2.3 - react-dom: 19.2.3(react@19.2.3) - react-is@16.13.1: {} - react-qr-code@2.0.18(react@18.3.1): - dependencies: - prop-types: 15.8.1 - qr.js: 0.0.0 - react: 18.3.1 + react-is@18.3.1: {} - react-refresh@0.17.0: {} + react-native-get-random-values@1.11.0(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)): + dependencies: + fast-base64-decode: 1.0.0 + react-native: 0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10) - react-remove-scroll-bar@2.3.8(@types/react@19.2.1)(react@18.3.1): + react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10): dependencies: - react: 18.3.1 - react-style-singleton: 2.2.3(@types/react@19.2.1)(react@18.3.1) - tslib: 2.8.1 + '@react-native/assets-registry': 0.85.2 + '@react-native/codegen': 0.85.2(@babel/core@7.28.3) + '@react-native/community-cli-plugin': 0.85.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@react-native/gradle-plugin': 0.85.2 + '@react-native/js-polyfills': 0.85.2 + '@react-native/normalize-colors': 0.85.2 + '@react-native/virtualized-lists': 0.85.2(@types/react@19.1.10)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + babel-plugin-syntax-hermes-parser: 0.33.3 + base64-js: 1.5.1 + commander: 12.1.0 + flow-enums-runtime: 0.0.6 + hermes-compiler: 250829098.0.10 + invariant: 2.2.4 + memoize-one: 5.2.1 + metro-runtime: 0.84.3 + metro-source-map: 0.84.3 + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 + react: 19.1.1 + react-devtools-core: 6.1.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) + react-refresh: 0.14.2 + regenerator-runtime: 0.13.11 + scheduler: 0.27.0 + semver: 7.7.3 + stacktrace-parser: 0.1.11 + tinyglobby: 0.2.15 + whatwg-fetch: 3.6.20 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + yargs: 17.7.2 optionalDependencies: - '@types/react': 19.2.1 + '@types/react': 19.1.10 + transitivePeerDependencies: + - '@babel/core' + - '@react-native-community/cli' + - '@react-native/metro-config' + - bufferutil + - supports-color + - utf-8-validate + optional: true - react-remove-scroll-bar@2.3.8(@types/react@19.2.1)(react@19.2.3): + react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10): dependencies: + '@react-native/assets-registry': 0.85.2 + '@react-native/codegen': 0.85.2(@babel/core@7.28.3) + '@react-native/community-cli-plugin': 0.85.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@react-native/gradle-plugin': 0.85.2 + '@react-native/js-polyfills': 0.85.2 + '@react-native/normalize-colors': 0.85.2 + '@react-native/virtualized-lists': 0.85.2(@types/react@19.2.1)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + babel-plugin-syntax-hermes-parser: 0.33.3 + base64-js: 1.5.1 + commander: 12.1.0 + flow-enums-runtime: 0.0.6 + hermes-compiler: 250829098.0.10 + invariant: 2.2.4 + memoize-one: 5.2.1 + metro-runtime: 0.84.3 + metro-source-map: 0.84.3 + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 react: 19.2.3 - react-style-singleton: 2.2.3(@types/react@19.2.1)(react@19.2.3) - tslib: 2.8.1 + react-devtools-core: 6.1.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) + react-refresh: 0.14.2 + regenerator-runtime: 0.13.11 + scheduler: 0.27.0 + semver: 7.7.3 + stacktrace-parser: 0.1.11 + tinyglobby: 0.2.15 + whatwg-fetch: 3.6.20 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + yargs: 17.7.2 optionalDependencies: '@types/react': 19.2.1 + transitivePeerDependencies: + - '@babel/core' + - '@react-native-community/cli' + - '@react-native/metro-config' + - bufferutil + - supports-color + - utf-8-validate - react-remove-scroll@2.7.1(@types/react@19.2.1)(react@18.3.1): + react-refresh@0.14.2: {} + + react-remove-scroll-bar@2.3.8(@types/react@19.2.1)(react@19.2.3): dependencies: - react: 18.3.1 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.1)(react@18.3.1) - react-style-singleton: 2.2.3(@types/react@19.2.1)(react@18.3.1) + react: 19.2.3 + react-style-singleton: 2.2.3(@types/react@19.2.1)(react@19.2.3) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.1)(react@18.3.1) - use-sidecar: 1.1.3(@types/react@19.2.1)(react@18.3.1) optionalDependencies: '@types/react': 19.2.1 @@ -28887,14 +22451,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 - react-style-singleton@2.2.3(@types/react@19.2.1)(react@18.3.1): - dependencies: - get-nonce: 1.0.1 - react: 18.3.1 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.1 - react-style-singleton@2.2.3(@types/react@19.2.1)(react@19.2.3): dependencies: get-nonce: 1.0.1 @@ -28903,26 +22459,10 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 - react@18.3.1: - dependencies: - loose-envify: 1.4.0 - react@19.1.1: {} - react@19.2.1: {} - react@19.2.3: {} - read-binary-file-arch@1.0.6: - dependencies: - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - - read-cache@1.0.0: - dependencies: - pify: 2.3.0 - readable-stream@2.3.8: dependencies: core-util-is: 1.0.3 @@ -28939,19 +22479,22 @@ snapshots: string_decoder: 1.3.0 util-deprecate: 1.0.2 - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 - readdirp@4.1.2: {} real-require@0.1.0: {} real-require@0.2.0: {} - redaxios@0.5.1: {} - - reflect-metadata@0.2.2: {} + redis@5.12.1: + dependencies: + '@redis/bloom': 5.12.1(@redis/client@5.12.1) + '@redis/client': 5.12.1 + '@redis/json': 5.12.1(@redis/client@5.12.1) + '@redis/search': 5.12.1(@redis/client@5.12.1) + '@redis/time-series': 5.12.1(@redis/client@5.12.1) + transitivePeerDependencies: + - '@node-rs/xxhash' + - '@opentelemetry/api' reflect.getprototypeof@1.0.10: dependencies: @@ -28964,11 +22507,7 @@ snapshots: get-proto: 1.0.1 which-builtin-type: 1.2.1 - regenerate-unicode-properties@10.2.0: - dependencies: - regenerate: 1.4.2 - - regenerate@1.4.2: {} + regenerator-runtime@0.13.11: {} regexp.prototype.flags@1.5.4: dependencies: @@ -28979,37 +22518,12 @@ snapshots: gopd: 1.2.0 set-function-name: 2.0.2 - regexpu-core@6.2.0: - dependencies: - regenerate: 1.4.2 - regenerate-unicode-properties: 10.2.0 - regjsgen: 0.8.0 - regjsparser: 0.12.0 - unicode-match-property-ecmascript: 2.0.0 - unicode-match-property-value-ecmascript: 2.2.0 - - regjsgen@0.8.0: {} - - regjsparser@0.12.0: - dependencies: - jsesc: 3.0.2 - - remeda@2.30.0: - dependencies: - type-fest: 4.41.0 - require-directory@2.1.1: {} require-from-string@2.0.2: {} require-main-filename@2.0.0: {} - requires-port@1.0.0: {} - - resedit@1.7.2: - dependencies: - pe-library: 0.4.1 - resolve-alpn@1.2.1: {} resolve-from@4.0.0: {} @@ -29034,43 +22548,13 @@ snapshots: dependencies: lowercase-keys: 2.0.0 - restore-cursor@3.1.0: - dependencies: - onetime: 5.1.2 - signal-exit: 3.0.7 - - ret@0.5.0: {} - - retry@0.12.0: {} - - retry@0.13.1: {} - - reusify@1.1.0: {} - - rfdc@1.4.1: {} - - rimraf@2.6.3: - dependencies: - glob: 7.2.3 + ret@0.5.0: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 + reusify@1.1.0: {} - ripemd160@2.0.2: - dependencies: - hash-base: 3.1.0 - inherits: 2.0.4 + rfc4648@1.5.3: {} - roarr@2.15.4: - dependencies: - boolean: 3.2.0 - detect-node: 2.1.0 - globalthis: 1.0.4 - json-stringify-safe: 5.0.1 - semver-compare: 1.0.0 - sprintf-js: 1.1.3 - optional: true + rfdc@1.4.1: {} rollup@4.46.4: dependencies: @@ -29127,10 +22611,6 @@ snapshots: dependencies: queue-microtask: 1.2.3 - rxjs@7.8.2: - dependencies: - tslib: 2.8.1 - safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -29162,41 +22642,18 @@ snapshots: safer-buffer@2.1.2: {} - sanitize-filename@1.6.3: - dependencies: - truncate-utf8-bytes: 1.0.2 - - sax@1.4.1: {} - saxes@6.0.0: dependencies: xmlchars: 2.2.0 - scheduler@0.23.2: - dependencies: - loose-envify: 1.4.0 - scheduler@0.26.0: {} scheduler@0.27.0: {} - secp256k1@5.0.1: - dependencies: - elliptic: 6.6.1 - node-addon-api: 5.1.0 - node-gyp-build: 4.8.4 + secure-json-parse@2.7.0: {} secure-json-parse@4.1.0: {} - selderee@0.11.0: - dependencies: - parseley: 0.12.1 - - semver-compare@1.0.0: - optional: true - - semver@5.7.2: {} - semver@6.3.1: {} semver@7.7.2: {} @@ -29237,10 +22694,7 @@ snapshots: transitivePeerDependencies: - supports-color - serialize-error@7.0.1: - dependencies: - type-fest: 0.13.1 - optional: true + serialize-error@2.1.0: {} serve-static@1.16.2: dependencies: @@ -29364,43 +22818,9 @@ snapshots: siginfo@2.0.0: {} - signal-exit@3.0.7: {} - signal-exit@4.1.0: {} - simple-swizzle@0.2.2: - dependencies: - is-arrayish: 0.3.2 - - simple-update-notifier@2.0.0: - dependencies: - semver: 7.7.3 - - simple-wcswidth@1.1.2: {} - - siwe@2.3.2(ethers@6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)): - dependencies: - '@spruceid/siwe-parser': 2.1.2 - '@stablelib/random': 1.0.2 - ethers: 6.15.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - uri-js: 4.4.1 - valid-url: 1.0.9 - - slash@3.0.0: {} - - slice-ansi@3.0.0: - dependencies: - ansi-styles: 4.3.0 - astral-regex: 2.0.0 - is-fullwidth-code-point: 3.0.0 - optional: true - - smart-buffer@4.2.0: {} - - snake-case@3.0.4: - dependencies: - dot-case: 3.0.4 - tslib: 2.8.1 + slow-redact@0.3.2: {} socket.io-client@4.8.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): dependencies: @@ -29420,19 +22840,6 @@ snapshots: transitivePeerDependencies: - supports-color - socks-proxy-agent@7.0.0: - dependencies: - agent-base: 6.0.2 - debug: 4.4.1 - socks: 2.8.7 - transitivePeerDependencies: - - supports-color - - socks@2.8.7: - dependencies: - ip-address: 10.0.1 - smart-buffer: 4.2.0 - sonic-boom@2.8.0: dependencies: atomic-sleep: 1.0.0 @@ -29448,13 +22855,15 @@ snapshots: buffer-from: 1.1.2 source-map: 0.6.1 + source-map@0.5.7: {} + source-map@0.6.1: {} source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 - spawn-command@0.0.2: {} + spark-md5@3.0.2: {} spdx-exceptions@2.5.0: {} @@ -29469,20 +22878,17 @@ snapshots: split2@4.2.0: {} - sprintf-js@1.1.3: - optional: true - - ssri@9.0.1: - dependencies: - minipass: 3.3.6 - stable-hash@0.0.5: {} - stack-trace@0.0.10: {} - stackback@0.0.2: {} - stat-mode@1.0.0: {} + stackframe@1.3.4: {} + + stacktrace-parser@0.1.11: + dependencies: + type-fest: 0.7.1 + + statuses@1.5.0: {} statuses@2.0.1: {} @@ -29583,9 +22989,11 @@ snapshots: dependencies: ansi-regex: 6.2.0 - strip-bom@3.0.0: {} + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 - strip-final-newline@2.0.0: {} + strip-bom@3.0.0: {} strip-json-comments@3.1.1: {} @@ -29610,12 +23018,6 @@ snapshots: pirates: 4.0.7 ts-interface-checker: 0.1.13 - sumchecker@3.0.1: - dependencies: - debug: 4.4.1 - transitivePeerDependencies: - - supports-color - superstruct@1.0.4: {} superstruct@2.0.2: {} @@ -29630,27 +23032,6 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - svg-parser@2.0.4: {} - - svgo@3.3.2: - dependencies: - '@trysound/sax': 0.2.0 - commander: 7.2.0 - css-select: 5.2.2 - css-tree: 2.3.1 - css-what: 6.2.2 - csso: 5.0.5 - picocolors: 1.1.1 - - svix@1.74.1: - dependencies: - '@stablelib/base64': 1.0.1 - '@types/node': 22.17.2 - es6-promise: 4.2.8 - fast-sha256: 1.3.0 - url-parse: 1.5.10 - uuid: 10.0.0 - symbol-tree@3.2.4: {} synckit@0.11.11: @@ -29659,66 +23040,21 @@ snapshots: tabbable@6.3.0: {} - tailwind-merge@2.6.0: {} - tailwind-merge@3.4.0: {} - tailwindcss@3.4.17: - dependencies: - '@alloc/quick-lru': 5.2.0 - arg: 5.0.2 - chokidar: 3.6.0 - didyoumean: 1.2.2 - dlv: 1.1.3 - fast-glob: 3.3.3 - glob-parent: 6.0.2 - is-glob: 4.0.3 - jiti: 1.21.7 - lilconfig: 3.1.3 - micromatch: 4.0.8 - normalize-path: 3.0.0 - object-hash: 3.0.0 - picocolors: 1.1.1 - postcss: 8.5.6 - postcss-import: 15.1.0(postcss@8.5.6) - postcss-js: 4.0.1(postcss@8.5.6) - postcss-load-config: 4.0.2(postcss@8.5.6) - postcss-nested: 6.2.0(postcss@8.5.6) - postcss-selector-parser: 6.1.2 - resolve: 1.22.10 - sucrase: 3.35.0 - transitivePeerDependencies: - - ts-node - tailwindcss@4.1.17: {} tapable@2.3.0: {} - tar@6.2.1: + terser@5.46.2: dependencies: - chownr: 2.0.0 - fs-minipass: 2.1.0 - minipass: 5.0.0 - minizlib: 2.1.2 - mkdirp: 1.0.4 - yallist: 4.0.0 - - temp-file@3.4.0: - dependencies: - async-exit-hook: 2.0.1 - fs-extra: 10.1.0 - - temp@0.9.4: - dependencies: - mkdirp: 0.5.6 - rimraf: 2.6.3 + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 text-encoding-utf-8@1.0.2: {} - text-hex@1.0.0: {} - - text-table@0.2.0: {} - thenify-all@1.6.0: dependencies: thenify: 3.3.1 @@ -29731,23 +23067,20 @@ snapshots: dependencies: real-require: 0.1.0 - thread-stream@4.0.0: + thread-stream@3.1.0: dependencies: real-require: 0.2.0 - tiny-async-pool@1.3.0: + thread-stream@4.0.0: dependencies: - semver: 5.7.2 + real-require: 0.2.0 + + throat@5.0.0: {} tinybench@2.9.0: {} tinyexec@0.3.2: {} - tinyglobby@0.2.14: - dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) @@ -29765,11 +23098,7 @@ snapshots: dependencies: tldts-core: 6.1.86 - tmp-promise@3.0.3: - dependencies: - tmp: 0.2.5 - - tmp@0.2.5: {} + tmpl@1.0.5: {} to-buffer@1.2.1: dependencies: @@ -29803,27 +23132,34 @@ snapshots: tree-kill@1.2.2: {} - tree-sitter@0.22.4: - dependencies: - node-addon-api: 8.5.0 - node-gyp-build: 4.8.4 - - treeify@1.1.0: {} - - triple-beam@1.4.1: {} - - truncate-utf8-bytes@1.0.2: - dependencies: - utf8-byte-length: 1.0.5 - ts-api-utils@2.1.0(typescript@5.9.2): dependencies: typescript: 5.9.2 - ts-case-convert@2.1.0: {} + ts-api-utils@2.1.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 ts-interface-checker@0.1.13: {} + ts-node@10.9.2(@types/node@22.17.2)(typescript@5.9.3): + dependencies: + '@cspotcode/source-map-support': 0.8.1 + '@tsconfig/node10': 1.0.12 + '@tsconfig/node12': 1.0.11 + '@tsconfig/node14': 1.0.3 + '@tsconfig/node16': 1.0.4 + '@types/node': 22.17.2 + acorn: 8.15.0 + acorn-walk: 8.3.5 + arg: 4.1.3 + create-require: 1.1.1 + diff: 4.0.4 + make-error: 1.3.6 + typescript: 5.9.3 + v8-compile-cache-lib: 3.0.1 + yn: 3.1.1 + tsconfck@3.1.6(typescript@5.9.2): optionalDependencies: typescript: 5.9.2 @@ -29837,34 +23173,37 @@ snapshots: tslib@1.14.1: {} - tslib@2.7.0: {} - tslib@2.8.1: {} - tsup@7.3.0(postcss@8.5.6)(typescript@5.9.2): + tsup@8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1): dependencies: - bundle-require: 4.2.1(esbuild@0.19.12) + bundle-require: 5.1.0(esbuild@0.25.9) cac: 6.7.14 - chokidar: 3.6.0 + chokidar: 4.0.3 + consola: 3.4.2 debug: 4.4.1 - esbuild: 0.19.12 - execa: 5.1.1 - globby: 11.1.0 + esbuild: 0.25.9 + fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 - postcss-load-config: 4.0.2(postcss@8.5.6) + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.1) resolve-from: 5.0.0 rollup: 4.46.4 source-map: 0.8.0-beta.0 sucrase: 3.35.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 tree-kill: 1.2.2 optionalDependencies: postcss: 8.5.6 typescript: 5.9.2 transitivePeerDependencies: + - jiti - supports-color - - ts-node + - tsx + - yaml - tsup@8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(typescript@5.9.2)(yaml@2.8.1): + tsup@8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.3)(yaml@2.8.1): dependencies: bundle-require: 5.1.0(esbuild@0.25.9) cac: 6.7.14 @@ -29875,26 +23214,26 @@ snapshots: fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.4)(yaml@2.8.1) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.1) resolve-from: 5.0.0 rollup: 4.46.4 source-map: 0.8.0-beta.0 sucrase: 3.35.0 tinyexec: 0.3.2 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 tree-kill: 1.2.2 optionalDependencies: postcss: 8.5.6 - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - jiti - supports-color - tsx - yaml - tsx@4.20.4: + tsx@4.21.0: dependencies: - esbuild: 0.25.9 + esbuild: 0.27.7 get-tsconfig: 4.10.1 optionalDependencies: fsevents: 2.3.3 @@ -29926,22 +23265,17 @@ snapshots: turbo-windows-64: 2.5.6 turbo-windows-arm64: 2.5.6 - tweetnacl@1.0.3: {} + tweetnacl-ts@1.0.3: + dependencies: + tslib: 1.14.1 - twitter-api-v2@1.25.0: {} + tweetnacl@1.0.3: {} type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - type-fest@0.13.1: - optional: true - - type-fest@0.20.2: {} - - type-fest@3.13.1: {} - - type-fest@4.41.0: {} + type-fest@0.7.1: {} type-is@1.6.18: dependencies: @@ -29987,27 +23321,35 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 - typeforce@1.18.0: {} + typedarray-to-buffer@3.1.5: + dependencies: + is-typedarray: 1.0.0 - typescript-eslint@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2): + typescript-eslint@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/parser': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.2) - '@typescript-eslint/utils': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3))(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.0(eslint@9.33.0(jiti@2.6.1))(typescript@5.9.3) eslint: 9.33.0(jiti@2.6.1) - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - supports-color typescript@5.9.2: {} + typescript@5.9.3: {} + ufo@1.6.1: {} uint8arrays@3.1.0: dependencies: multiformats: 9.9.0 + uint8arrays@3.1.1: + dependencies: + multiformats: 9.9.0 + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -30019,39 +23361,10 @@ snapshots: undici-types@5.26.5: {} - undici-types@6.19.8: {} - undici-types@6.21.0: {} - undici-types@7.10.0: {} - - undici-types@7.16.0: {} - undici-types@7.22.0: {} - unicode-canonical-property-names-ecmascript@2.0.1: {} - - unicode-match-property-ecmascript@2.0.0: - dependencies: - unicode-canonical-property-names-ecmascript: 2.0.1 - unicode-property-aliases-ecmascript: 2.1.0 - - unicode-match-property-value-ecmascript@2.2.0: {} - - unicode-property-aliases-ecmascript@2.1.0: {} - - unique-filename@2.0.1: - dependencies: - unique-slug: 3.0.0 - - unique-slug@3.0.0: - dependencies: - imurmurhash: 0.1.4 - - universalify@0.1.2: {} - - universalify@2.0.1: {} - unpipe@1.0.0: {} unrs-resolver@1.11.1: @@ -30078,7 +23391,7 @@ snapshots: '@unrs/resolver-binding-win32-ia32-msvc': 1.11.1 '@unrs/resolver-binding-win32-x64-msvc': 1.11.1 - unstorage@1.16.1(@upstash/redis@1.35.3)(idb-keyval@6.2.2): + unstorage@1.16.1(idb-keyval@6.2.2): dependencies: anymatch: 3.1.3 chokidar: 4.0.3 @@ -30089,7 +23402,6 @@ snapshots: ofetch: 1.4.1 ufo: 1.6.1 optionalDependencies: - '@upstash/redis': 1.35.3 idb-keyval: 6.2.2 update-browserslist-db@1.1.3(browserslist@4.25.3): @@ -30104,18 +23416,6 @@ snapshots: urijs@1.19.11: {} - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - - use-callback-ref@1.3.3(@types/react@19.2.1)(react@18.3.1): - dependencies: - react: 18.3.1 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.1 - use-callback-ref@1.3.3(@types/react@19.2.1)(react@19.2.3): dependencies: react: 19.2.3 @@ -30123,14 +23423,6 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 - use-sidecar@1.1.3(@types/react@19.2.1)(react@18.3.1): - dependencies: - detect-node-es: 1.1.0 - react: 18.3.1 - tslib: 2.8.1 - optionalDependencies: - '@types/react': 19.2.1 - use-sidecar@1.1.3(@types/react@19.2.1)(react@19.2.3): dependencies: detect-node-es: 1.1.0 @@ -30143,10 +23435,6 @@ snapshots: dependencies: react: 19.1.1 - use-sync-external-store@1.2.0(react@19.2.1): - dependencies: - react: 19.2.1 - use-sync-external-store@1.2.0(react@19.2.3): dependencies: react: 19.2.3 @@ -30155,33 +23443,10 @@ snapshots: dependencies: react: 19.1.1 - use-sync-external-store@1.4.0(react@19.2.1): - dependencies: - react: 19.2.1 - use-sync-external-store@1.4.0(react@19.2.3): dependencies: react: 19.2.3 - use-sync-external-store@1.5.0(react@18.3.1): - dependencies: - react: 18.3.1 - - use-sync-external-store@1.5.0(react@19.1.1): - dependencies: - react: 19.1.1 - optional: true - - use-sync-external-store@1.5.0(react@19.2.1): - dependencies: - react: 19.2.1 - optional: true - - use-sync-external-store@1.5.0(react@19.2.3): - dependencies: - react: 19.2.3 - optional: true - usehooks-ts@3.1.1(react@19.2.3): dependencies: lodash.debounce: 4.0.8 @@ -30191,7 +23456,7 @@ snapshots: dependencies: node-gyp-build: 4.8.4 - utf8-byte-length@1.0.5: {} + utf8@3.0.0: {} util-deprecate@1.0.2: {} @@ -30205,15 +23470,11 @@ snapshots: utils-merge@1.0.1: {} - uuid@10.0.0: {} - - uuid@11.1.0: {} - uuid@8.3.2: {} uuid@9.0.1: {} - valid-url@1.0.9: {} + v8-compile-cache-lib@3.0.1: {} valtio@1.13.2(@types/react@19.1.10)(react@19.1.1): dependencies: @@ -30224,24 +23485,6 @@ snapshots: '@types/react': 19.1.10 react: 19.1.1 - valtio@1.13.2(@types/react@19.1.10)(react@19.2.1): - dependencies: - derive-valtio: 0.1.0(valtio@1.13.2(@types/react@19.1.10)(react@19.2.1)) - proxy-compare: 2.6.0 - use-sync-external-store: 1.2.0(react@19.2.1) - optionalDependencies: - '@types/react': 19.1.10 - react: 19.2.1 - - valtio@1.13.2(@types/react@19.1.10)(react@19.2.3): - dependencies: - derive-valtio: 0.1.0(valtio@1.13.2(@types/react@19.1.10)(react@19.2.3)) - proxy-compare: 2.6.0 - use-sync-external-store: 1.2.0(react@19.2.3) - optionalDependencies: - '@types/react': 19.1.10 - react: 19.2.3 - valtio@1.13.2(@types/react@19.2.1)(react@19.2.3): dependencies: derive-valtio: 0.1.0(valtio@1.13.2(@types/react@19.2.1)(react@19.2.3)) @@ -30253,57 +23496,16 @@ snapshots: vary@1.1.2: {} - verror@1.10.1: - dependencies: - assert-plus: 1.0.0 - core-util-is: 1.0.2 - extsprintf: 1.4.1 - optional: true - viem@2.23.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76): dependencies: '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 - '@scure/bip32': 1.6.2 - '@scure/bip39': 1.5.4 - abitype: 1.0.8(typescript@5.9.2)(zod@3.25.76) - isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.6.7(typescript@5.9.2)(zod@3.25.76) - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - - viem@2.23.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13): - dependencies: - '@noble/curves': 1.8.1 - '@noble/hashes': 1.7.1 - '@scure/bip32': 1.6.2 - '@scure/bip39': 1.5.4 - abitype: 1.0.8(typescript@5.9.2)(zod@4.1.13) - isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.6.7(typescript@5.9.2)(zod@4.1.13) - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - - viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76): - dependencies: - '@noble/curves': 1.9.1 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.9.2)(zod@3.25.76) - isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.9.6(typescript@5.9.2)(zod@3.25.76) - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@noble/hashes': 1.7.1 + '@scure/bip32': 1.6.2 + '@scure/bip39': 1.5.4 + abitype: 1.0.8(typescript@5.9.2)(zod@3.25.76) + isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + ox: 0.6.7(typescript@5.9.2)(zod@3.25.76) + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -30311,32 +23513,32 @@ snapshots: - utf-8-validate - zod - viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13): + viem@2.23.2(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13): dependencies: - '@noble/curves': 1.9.1 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.9.2)(zod@4.1.13) - isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.9.6(typescript@5.9.2)(zod@4.1.13) - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@scure/bip32': 1.6.2 + '@scure/bip39': 1.5.4 + abitype: 1.0.8(typescript@5.9.3)(zod@4.1.13) + isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + ox: 0.6.7(typescript@5.9.3)(zod@4.1.13) + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - bufferutil - utf-8-validate - zod - viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4): + viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 abitype: 1.2.3(typescript@5.9.2)(zod@3.22.4) - isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.11.1(typescript@5.9.2)(zod@3.22.4) + isows: 1.0.7(ws@8.18.3) + ox: 0.14.20(typescript@5.9.2)(zod@3.22.4) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.9.2 @@ -30345,15 +23547,15 @@ snapshots: - utf-8-validate - zod - viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76): + viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 abitype: 1.2.3(typescript@5.9.2)(zod@3.25.76) - isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.11.1(typescript@5.9.2)(zod@3.25.76) + isows: 1.0.7(ws@8.18.3) + ox: 0.14.20(typescript@5.9.2)(zod@3.25.76) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.9.2 @@ -30362,412 +23564,182 @@ snapshots: - utf-8-validate - zod - viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13): + viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.22.4): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) - isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.11.1(typescript@5.9.2)(zod@4.1.13) + abitype: 1.2.3(typescript@5.9.3)(zod@3.22.4) + isows: 1.0.7(ws@8.18.3) + ox: 0.14.20(typescript@5.9.3)(zod@3.22.4) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - bufferutil - - utf-8-validate - - zod - - vite-node@3.2.4(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1): - dependencies: - cac: 6.7.14 - debug: 4.4.1 - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)): - dependencies: - debug: 4.4.1 - globrex: 0.1.2 - tsconfck: 3.1.6(typescript@5.9.2) - optionalDependencies: - vite: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - transitivePeerDependencies: - - supports-color - - typescript - - vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1): - dependencies: - esbuild: 0.25.9 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.46.4 - tinyglobby: 0.2.14 - optionalDependencies: - '@types/node': 22.17.2 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - tsx: 4.20.4 - yaml: 2.8.1 - - vite@7.1.3(@types/node@24.3.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1): - dependencies: - esbuild: 0.25.9 - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.46.4 - tinyglobby: 0.2.14 - optionalDependencies: - '@types/node': 24.3.0 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - tsx: 4.20.4 - yaml: 2.8.1 - - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1): - dependencies: - '@types/chai': 5.2.2 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.1 - debug: 4.4.1 - expect-type: 1.2.2 - magic-string: 0.30.17 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.9.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.14 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - vite-node: 3.2.4(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.4)(yaml@2.8.1) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/debug': 4.1.12 - '@types/node': 22.17.2 - jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - w3c-xmlserializer@5.0.0: - dependencies: - xml-name-validator: 5.0.0 - - wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.1.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): - dependencies: - '@tanstack/react-query': 5.90.11(react@19.1.1) - '@wagmi/connectors': 6.2.0(7c0fb5ad6e91c192e500875cd884eb4c) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - react: 19.1.1 - use-sync-external-store: 1.4.0(react@19.1.1) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react-native - - supports-color - - uploadthing - - utf-8-validate - - ws - - zod - - wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): - dependencies: - '@tanstack/react-query': 5.90.11(react@19.2.1) - '@wagmi/connectors': 6.2.0(826cb7847d3729c23c5bbd1840c9486a) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - react: 19.2.1 - use-sync-external-store: 1.4.0(react@19.2.1) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react-native - - supports-color - - uploadthing - - utf-8-validate - - ws - - zod - - wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): - dependencies: - '@tanstack/react-query': 5.90.11(react@19.2.1) - '@wagmi/connectors': 6.2.0(a7ab704115d4285468feaf0dc0f50159) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - react: 19.2.1 - use-sync-external-store: 1.4.0(react@19.2.1) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react-native - - supports-color - - uploadthing - utf-8-validate - - ws - zod - wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13): + viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@3.25.76): dependencies: - '@tanstack/react-query': 5.90.11(react@19.2.3) - '@wagmi/connectors': 6.2.0(26b6de6e2b894d3d8ec3de3fd9d7a34e) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - react: 19.2.3 - use-sync-external-store: 1.4.0(react@19.2.3) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) - optionalDependencies: - typescript: 5.9.2 - transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) + isows: 1.0.7(ws@8.18.3) + ox: 0.14.20(typescript@5.9.3)(zod@3.25.76) + ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react-native - - supports-color - - uploadthing - utf-8-validate - - ws - zod - wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@upstash/redis@1.35.3)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13): + viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13): dependencies: - '@tanstack/react-query': 5.90.11(react@19.2.3) - '@wagmi/connectors': 6.2.0(87f53a8d2b85f9075dbb2195dfb00723) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - react: 19.2.3 - use-sync-external-store: 1.4.0(react@19.2.3) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@4.1.13) + isows: 1.0.7(ws@8.18.3) + ox: 0.14.20(typescript@5.9.3)(zod@4.1.13) + ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react-native - - supports-color - - uploadthing - utf-8-validate - - ws - zod - wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13): + viem@2.48.11(typescript@5.9.3)(zod@3.25.76): dependencies: - '@tanstack/react-query': 5.90.11(react@19.2.3) - '@wagmi/connectors': 6.2.0(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - react: 19.2.3 - use-sync-external-store: 1.4.0(react@19.2.3) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.3)(zod@3.25.76) + isows: 1.0.7(ws@8.18.3) + ox: 0.14.20(typescript@5.9.3)(zod@3.25.76) + ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - - '@azure/app-configuration' - - '@azure/cosmos' - - '@azure/data-tables' - - '@azure/identity' - - '@azure/keyvault-secrets' - - '@azure/storage-blob' - - '@capacitor/preferences' - - '@deno/kv' - - '@netlify/blobs' - - '@planetscale/database' - - '@react-native-async-storage/async-storage' - - '@tanstack/query-core' - - '@types/react' - - '@upstash/redis' - - '@vercel/blob' - - '@vercel/kv' - - aws4fetch - bufferutil - - db0 - - debug - - encoding - - expo-auth-session - - expo-crypto - - expo-web-browser - - fastestsmallesttextencoderdecoder - - immer - - ioredis - - react-native - - supports-color - - uploadthing - utf-8-validate - - ws - zod - wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13): + vite-node@3.2.4(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1): dependencies: - '@tanstack/react-query': 5.90.11(react@19.2.3) - '@wagmi/connectors': 6.2.0(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.10)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) - react: 19.2.3 - use-sync-external-store: 1.4.0(react@19.2.3) - viem: 2.43.5(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + cac: 6.7.14 + debug: 4.4.1 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)): + dependencies: + debug: 4.4.1 + globrex: 0.1.2 + tsconfck: 3.1.6(typescript@5.9.2) + optionalDependencies: + vite: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + - typescript + + vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1): + dependencies: + esbuild: 0.25.9 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.46.4 + tinyglobby: 0.2.15 + optionalDependencies: + '@types/node': 22.17.2 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + terser: 5.46.2 + tsx: 4.21.0 + yaml: 2.8.1 + + vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.17.2)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1): + dependencies: + '@types/chai': 5.2.2 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.1 + debug: 4.4.1 + expect-type: 1.2.2 + magic-string: 0.30.21 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.15 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 6.3.5(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@22.17.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.2)(tsx@4.21.0)(yaml@2.8.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/debug': 4.1.12 + '@types/node': 22.17.2 + jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vlq@1.0.1: {} + + vlq@2.0.4: {} + + w3c-xmlserializer@5.0.0: + dependencies: + xml-name-validator: 5.0.0 + + wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.1.1))(@types/react@19.1.10)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.1.10)(bufferutil@4.0.9)(react@19.1.1)(utf-8-validate@5.0.10))(react@19.1.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@3.25.76): + dependencies: + '@tanstack/react-query': 5.90.11(react@19.1.1) + '@wagmi/connectors': 6.2.0(1c4d5cd8f605c126794a056a26d4bec2) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.10)(react@19.1.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.1.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + react: 19.1.1 + use-sync-external-store: 1.4.0(react@19.1.1) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -30805,16 +23777,16 @@ snapshots: - ws - zod - wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(encoding@0.1.13)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13): + wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.2.1)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.2(@babel/core@7.28.3)(@types/react@19.2.1)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3)(typescript@5.9.3)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13))(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(zod@4.1.13): dependencies: '@tanstack/react-query': 5.90.11(react@19.2.3) - '@wagmi/connectors': 6.2.0(1aee367860625464d156864b651beb8c) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) + '@wagmi/connectors': 6.2.0(534ae91e37efc07526c2008b6d1d5787) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.2.1)(react@19.2.3)(typescript@5.9.3)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13)) react: 19.2.3 use-sync-external-store: 1.4.0(react@19.2.3) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.3)(utf-8-validate@5.0.10)(zod@4.1.13) optionalDependencies: - typescript: 5.9.2 + typescript: 5.9.3 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -30850,16 +23822,12 @@ snapshots: - ws - zod - wcwidth@1.0.1: + walker@1.0.8: dependencies: - defaults: 1.0.4 - - web-streams-polyfill@3.3.3: {} + makeerror: 1.0.12 web-streams-polyfill@4.0.0-beta.3: {} - web-tree-sitter@0.24.7: {} - webextension-polyfill@0.10.0: {} webidl-conversions@3.0.1: {} @@ -30872,6 +23840,8 @@ snapshots: dependencies: iconv-lite: 0.6.3 + whatwg-fetch@3.6.20: {} + whatwg-mimetype@4.0.0: {} whatwg-url@14.2.0: @@ -30942,30 +23912,6 @@ snapshots: siginfo: 2.0.0 stackback: 0.0.2 - wif@2.0.6: - dependencies: - bs58check: 2.1.2 - - winston-transport@4.9.0: - dependencies: - logform: 2.7.0 - readable-stream: 3.6.2 - triple-beam: 1.4.1 - - winston@3.17.0: - dependencies: - '@colors/colors': 1.6.0 - '@dabh/diagnostics': 2.0.3 - async: 3.2.6 - is-stream: 2.0.1 - logform: 2.7.0 - one-time: 1.0.0 - readable-stream: 3.6.2 - safe-stable-stringify: 2.5.0 - stack-trace: 0.0.10 - triple-beam: 1.4.1 - winston-transport: 4.9.0 - word-wrap@1.2.5: {} wrap-ansi@6.2.0: @@ -30993,6 +23939,11 @@ snapshots: bufferutil: 4.0.9 utf-8-validate: 5.0.10 + ws@7.5.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): + optionalDependencies: + bufferutil: 4.0.9 + utf-8-validate: 5.0.10 + ws@8.17.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.9 @@ -31015,8 +23966,6 @@ snapshots: xml-name-validator@5.0.0: {} - xmlbuilder@15.1.1: {} - xmlchars@2.2.0: {} xmlhttprequest-ssl@2.1.2: {} @@ -31029,8 +23978,6 @@ snapshots: yallist@3.1.1: {} - yallist@4.0.0: {} - yaml@2.8.1: {} yargs-parser@18.1.3: @@ -31064,10 +24011,7 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 - yauzl@2.10.0: - dependencies: - buffer-crc32: 0.2.13 - fd-slicer: 1.1.0 + yn@3.1.1: {} yocto-queue@0.1.0: {} @@ -31091,36 +24035,6 @@ snapshots: react: 19.1.1 use-sync-external-store: 1.4.0(react@19.1.1) - zustand@5.0.0(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)): - optionalDependencies: - '@types/react': 19.1.10 - react: 19.1.1 - use-sync-external-store: 1.5.0(react@19.1.1) - - zustand@5.0.0(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)): - optionalDependencies: - '@types/react': 19.1.10 - react: 19.2.1 - use-sync-external-store: 1.4.0(react@19.2.1) - - zustand@5.0.0(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.5.0(react@19.2.1)): - optionalDependencies: - '@types/react': 19.1.10 - react: 19.2.1 - use-sync-external-store: 1.5.0(react@19.2.1) - - zustand@5.0.0(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)): - optionalDependencies: - '@types/react': 19.1.10 - react: 19.2.3 - use-sync-external-store: 1.4.0(react@19.2.3) - - zustand@5.0.0(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.5.0(react@19.2.3)): - optionalDependencies: - '@types/react': 19.1.10 - react: 19.2.3 - use-sync-external-store: 1.5.0(react@19.2.3) - zustand@5.0.0(@types/react@19.2.1)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)): optionalDependencies: '@types/react': 19.2.1 @@ -31133,30 +24047,6 @@ snapshots: react: 19.1.1 use-sync-external-store: 1.4.0(react@19.1.1) - zustand@5.0.3(@types/react@19.1.10)(react@19.1.1)(use-sync-external-store@1.5.0(react@19.1.1)): - optionalDependencies: - '@types/react': 19.1.10 - react: 19.1.1 - use-sync-external-store: 1.5.0(react@19.1.1) - - zustand@5.0.3(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)): - optionalDependencies: - '@types/react': 19.1.10 - react: 19.2.1 - use-sync-external-store: 1.4.0(react@19.2.1) - - zustand@5.0.3(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.5.0(react@19.2.1)): - optionalDependencies: - '@types/react': 19.1.10 - react: 19.2.1 - use-sync-external-store: 1.5.0(react@19.2.1) - - zustand@5.0.3(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)): - optionalDependencies: - '@types/react': 19.1.10 - react: 19.2.3 - use-sync-external-store: 1.4.0(react@19.2.3) - zustand@5.0.3(@types/react@19.2.1)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)): optionalDependencies: '@types/react': 19.2.1 @@ -31169,24 +24059,6 @@ snapshots: react: 19.1.1 use-sync-external-store: 1.4.0(react@19.1.1) - zustand@5.0.8(@types/react@19.1.10)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)): - optionalDependencies: - '@types/react': 19.1.10 - react: 19.2.1 - use-sync-external-store: 1.4.0(react@19.2.1) - - zustand@5.0.8(@types/react@19.1.10)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)): - optionalDependencies: - '@types/react': 19.1.10 - react: 19.2.3 - use-sync-external-store: 1.4.0(react@19.2.3) - - zustand@5.0.8(@types/react@19.2.1)(react@18.3.1)(use-sync-external-store@1.5.0(react@18.3.1)): - optionalDependencies: - '@types/react': 19.2.1 - react: 18.3.1 - use-sync-external-store: 1.5.0(react@18.3.1) - zustand@5.0.8(@types/react@19.2.1)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)): optionalDependencies: '@types/react': 19.2.1 diff --git a/examples/typescript/pnpm-workspace.yaml b/examples/typescript/pnpm-workspace.yaml index c98a039f40..550e02bcf9 100644 --- a/examples/typescript/pnpm-workspace.yaml +++ b/examples/typescript/pnpm-workspace.yaml @@ -1,19 +1,22 @@ packages: - "clients/*" - "servers/*" + - "servers/*/lambda" + - "servers/*/cdk" - "fullstack/*" - "facilitator/*" - - "legacy/facilitator" - - "legacy/servers/*" - - "legacy/clients/*" - - "legacy/fullstack/*" - - "legacy/dynamic_agent" - - "legacy/agent" - - "legacy/mcp-embedded-wallet" - - "legacy/mpc" - "../../typescript/packages/core" - "../../typescript/packages/extensions" - "../../typescript/packages/mcp" - "../../typescript/packages/http/*" - "../../typescript/packages/mechanisms/*" - - "../../typescript/packages/legacy/*" +minimumReleaseAge: 4320 # Only install package versions that have been published for at least 3 days. +minimumReleaseAgeStrict: true +allowBuilds: + bufferutil: true + esbuild: true + keccak: true + protobufjs: true + sharp: true + unrs-resolver: true + utf-8-validate: true diff --git a/examples/typescript/servers/README.md b/examples/typescript/servers/README.md index 794371a62f..1ea0d84400 100644 --- a/examples/typescript/servers/README.md +++ b/examples/typescript/servers/README.md @@ -7,13 +7,14 @@ This directory contains TypeScript server examples demonstrating how to protect | Directory | Description | | --- | --- | | [`express/`](./express/) | Using `@x402/express` middleware | +| [`self-facilitation/`](./self-facilitation/) | Express middleware with in-process SDK facilitator | | [`hono/`](./hono/) | Using `@x402/hono` middleware | | [`advanced/`](./advanced/) | Advanced patterns: hooks, dynamic pricing, custom tokens | | [`custom/`](./custom/) | Manual implementation using only `@x402/core` | ## Framework Examples -The **express** and **hono** directories showcase the minimal approach to adding x402 paywalls to your API. These use our middleware packages that automatically handle: +The **express**, **self-facilitation**, and **hono** directories showcase the minimal approach to adding x402 paywalls to your API. These use our middleware packages that automatically handle: 1. Checking for payment headers on protected routes 2. Returning 402 with payment requirements if no payment diff --git a/examples/typescript/servers/advanced/.env-local b/examples/typescript/servers/advanced/.env-local index e16c5a2761..32170903de 100644 --- a/examples/typescript/servers/advanced/.env-local +++ b/examples/typescript/servers/advanced/.env-local @@ -1,4 +1,5 @@ EVM_ADDRESS= SVM_ADDRESS= STELLAR_ADDRESS= +HEDERA_ACCOUNT_ID= FACILITATOR_URL= \ No newline at end of file diff --git a/examples/typescript/servers/advanced/README.md b/examples/typescript/servers/advanced/README.md index 17d98b2314..f3c0286d6f 100644 --- a/examples/typescript/servers/advanced/README.md +++ b/examples/typescript/servers/advanced/README.md @@ -58,7 +58,11 @@ and fill required environment variables: - `FACILITATOR_URL` - Facilitator endpoint URL - `EVM_ADDRESS` - Ethereum address to receive payments +- `SVM_ADDRESS` - Solana address to receive payments (optional for `all-networks`) - `STELLAR_ADDRESS` - Stellar public address (starts with `G`) to receive payments +- `HEDERA_ACCOUNT_ID` - Hedera account id to receive payments (optional for `all-networks`; format: `0.0.XXXXX`) + +> **Hedera Testnet:** Get testnet HBAR from the [Hedera Faucet](https://portal.hedera.com/faucet). 2. Install and build all packages from the typescript examples root: diff --git a/examples/typescript/servers/advanced/all_networks.ts b/examples/typescript/servers/advanced/all_networks.ts index 8d7f639642..2af16b01ca 100644 --- a/examples/typescript/servers/advanced/all_networks.ts +++ b/examples/typescript/servers/advanced/all_networks.ts @@ -5,27 +5,34 @@ * optional chain configuration via environment variables. * * New chain support should be added here in alphabetic order by network prefix - * (e.g., "eip155" before "solana" before "stellar"). + * (e.g., "algorand" before "eip155" before "solana" before "stellar"). */ import { config } from "dotenv"; import express from "express"; import { paymentMiddleware, x402ResourceServer } from "@x402/express"; +import { ExactAvmScheme } from "@x402/avm/exact/server"; import { ExactEvmScheme } from "@x402/evm/exact/server"; +import { ExactHederaScheme } from "@x402/hedera/exact/server"; import { ExactSvmScheme } from "@x402/svm/exact/server"; import { ExactStellarScheme } from "@x402/stellar/exact/server"; import { HTTPFacilitatorClient } from "@x402/core/server"; +import type { Network, Price } from "@x402/core/types"; config(); // Configuration - optional per network +const avmAddress = process.env.AVM_ADDRESS as string | undefined; const evmAddress = process.env.EVM_ADDRESS as `0x${string}` | undefined; const svmAddress = process.env.SVM_ADDRESS as string | undefined; const stellarAddress = process.env.STELLAR_ADDRESS as string | undefined; +const hederaAddress = process.env.HEDERA_ACCOUNT_ID as string | undefined; // Validate at least one address is provided -if (!evmAddress && !svmAddress && !stellarAddress) { - console.error("❌ At least one of EVM_ADDRESS, SVM_ADDRESS, or STELLAR_ADDRESS is required"); +if (!avmAddress && !evmAddress && !svmAddress && !stellarAddress && !hederaAddress) { + console.error( + "❌ At least one of AVM_ADDRESS, EVM_ADDRESS, SVM_ADDRESS, STELLAR_ADDRESS, or HEDERA_ACCOUNT_ID is required", + ); process.exit(1); } @@ -36,17 +43,29 @@ if (!facilitatorUrl) { } // Network configuration +const AVM_NETWORK = "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=" as const; // Algorand Testnet const EVM_NETWORK = "eip155:84532" as const; // Base Sepolia +const HEDERA_NETWORK = "hedera:testnet" as const; // Hedera Testnet const SVM_NETWORK = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" as const; // Solana Devnet const STELLAR_NETWORK = "stellar:testnet" as const; // Stellar Testnet +const HEDERA_HBAR_ASSET = "0.0.0" as const; // Native HBAR asset id +const HEDERA_WEATHER_PRICE_TINYBARS = "100000" as const; // 0.001 HBAR // Build accepts array dynamically based on configured addresses const accepts: Array<{ scheme: string; - price: string; - network: `${string}:${string}`; + price: Price; + network: Network; payTo: string; }> = []; +if (avmAddress) { + accepts.push({ + scheme: "exact", + price: "$0.001", + network: AVM_NETWORK, + payTo: avmAddress, + }); +} if (evmAddress) { accepts.push({ scheme: "exact", @@ -71,12 +90,26 @@ if (stellarAddress) { payTo: stellarAddress, }); } +if (hederaAddress) { + accepts.push({ + scheme: "exact", + price: { + amount: HEDERA_WEATHER_PRICE_TINYBARS, + asset: HEDERA_HBAR_ASSET, + }, + network: HEDERA_NETWORK, + payTo: hederaAddress, + }); +} // Create facilitator client const facilitatorClient = new HTTPFacilitatorClient({ url: facilitatorUrl }); // Create x402 resource server and register schemes dynamically const server = new x402ResourceServer(facilitatorClient); +if (avmAddress) { + server.register(AVM_NETWORK, new ExactAvmScheme()); +} if (evmAddress) { server.register(EVM_NETWORK, new ExactEvmScheme()); } @@ -86,6 +119,9 @@ if (svmAddress) { if (stellarAddress) { server.register(STELLAR_NETWORK, new ExactStellarScheme()); } +if (hederaAddress) { + server.register(HEDERA_NETWORK, new ExactHederaScheme()); +} // Create Express app const app = express(); @@ -123,6 +159,9 @@ app.get("/health", (req, res) => { const port = process.env.PORT || 4021; app.listen(port, () => { console.log(`🚀 All Networks Server listening at http://localhost:${port}`); + if (avmAddress) { + console.log(` AVM: ${avmAddress} on ${AVM_NETWORK}`); + } if (evmAddress) { console.log(` EVM: ${evmAddress} on ${EVM_NETWORK}`); } @@ -132,6 +171,9 @@ app.listen(port, () => { if (stellarAddress) { console.log(` Stellar: ${stellarAddress} on ${STELLAR_NETWORK}`); } + if (hederaAddress) { + console.log(` Hedera: ${hederaAddress} on ${HEDERA_NETWORK}`); + } console.log(` Facilitator: ${facilitatorUrl}`); console.log(); }); diff --git a/examples/typescript/servers/advanced/package.json b/examples/typescript/servers/advanced/package.json index a7fa9475ae..04bdd19fed 100644 --- a/examples/typescript/servers/advanced/package.json +++ b/examples/typescript/servers/advanced/package.json @@ -19,15 +19,18 @@ "dependencies": { "dotenv": "^16.4.7", "express": "^4.18.2", + "@x402/avm": "workspace:*", "@x402/core": "workspace:*", "@x402/express": "workspace:*", "@x402/evm": "workspace:*", + "@x402/hedera": "workspace:*", "@x402/svm": "workspace:*", "@x402/stellar": "workspace:*", "@x402/extensions": "workspace:*" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "^5.0.1", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", @@ -36,8 +39,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/servers/batch-settlement/.env-local b/examples/typescript/servers/batch-settlement/.env-local new file mode 100644 index 0000000000..e39e3110de --- /dev/null +++ b/examples/typescript/servers/batch-settlement/.env-local @@ -0,0 +1,10 @@ +EVM_ADDRESS=0x... +FACILITATOR_URL=http://localhost:4022 + +# Recommended: self-managed receiver authorizer key. Channels survive facilitator changes. +# Omit to delegate to the facilitator's advertised authorizer (channels are then bound to +# that facilitator until drained). +EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY= + +STORAGE_DIR= +DEFERRED_WITHDRAW_DELAY_SECONDS=900 diff --git a/examples/typescript/legacy/clients/axios/.prettierignore b/examples/typescript/servers/batch-settlement/.prettierignore similarity index 100% rename from examples/typescript/legacy/clients/axios/.prettierignore rename to examples/typescript/servers/batch-settlement/.prettierignore diff --git a/examples/typescript/legacy/clients/cdp-sdk/.prettierrc b/examples/typescript/servers/batch-settlement/.prettierrc similarity index 100% rename from examples/typescript/legacy/clients/cdp-sdk/.prettierrc rename to examples/typescript/servers/batch-settlement/.prettierrc diff --git a/examples/typescript/servers/batch-settlement/README.md b/examples/typescript/servers/batch-settlement/README.md new file mode 100644 index 0000000000..e7a305b43d --- /dev/null +++ b/examples/typescript/servers/batch-settlement/README.md @@ -0,0 +1,110 @@ +# @x402/express Batch-Settlement Example Server + +Express server that protects a resource with the **batch-settlement** EVM scheme. Each request is paid by an off-chain voucher; the server batches voucher claims and onchain settlements via a `ChannelManager` running in the background. + +The route demonstrates **dynamic pricing**: the client authorizes up to `$0.01` per request, and the handler bills a random fraction of that via `setSettlementOverrides`. + +See the [scheme specification](../../../../specs/schemes/batch-settlement/scheme_batch_settlement_evm.md) and the [scheme README](../../../../typescript/packages/mechanisms/evm/src/batch-settlement/README.md) for protocol details. + +## Receiver Authorizer: Pick One + +Every channel commits to a `receiverAuthorizer` — the address whose EIP-712 signatures authorize `claimWithSignature` and `refundWithSignature`. This server lets you choose between two strategies: + +### 1. Self-managed (recommended) + +Set `EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY` to an EOA you own. The scheme uses it to sign claims/refunds locally; **any facilitator** can relay the resulting transactions. + +```typescript +const receiverAuthorizerSigner = privateKeyToAccount(process.env.EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY); +new BatchSettlementEvmScheme(evmAddress, { receiverAuthorizerSigner }); +``` + +Channels survive facilitator changes — you can switch facilitators (or add backups) without opening new channels. + +### 2. Facilitator-delegated + +Leave `EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY` unset. The scheme adopts the address advertised by the facilitator's `/supported`. + +```typescript +new BatchSettlementEvmScheme(evmAddress, { /* no receiverAuthorizerSigner */ }); +``` + +This is simpler operationally but binds each channel to the current facilitator authorizer. **Switching facilitators (or rotating their authorizer key) requires opening new channels.** Before swapping, claim outstanding vouchers and refund remaining balances on the old channels. + +## Settlement Policy + +Clients can call `initiateWithdraw` directly onchain at any time, **outside the request flow**. After the channel's `withdrawDelay` elapses, `finalizeWithdraw` drains the escrow and any unclaimed vouchers become unclaimable forever. + +This demo uses local-friendly timing: claim every 1 minute, settle every 2 minutes, and refund channels idle for 3 minutes. The default channel `withdrawDelay` is 1 day. + +For production, choose a `withdrawDelay` greater than your claim cadence plus an operational safety margin. A daily claim job pairs well with a `withdrawDelay` longer than one day; settle less frequently when gas savings matter more than receiver cash-flow latency. Idle refunds are usually best on a week-scale cadence unless your product needs faster channel cleanup. + +The `ChannelManager` runs the server-side lifecycle: claim vouchers from stored channels, settle claimed funds to `payTo`, and optionally refund idle channels. `start()` enables each job at the configured interval, while callbacks let you choose channels, gate settlement, and hook logging/metrics: + +```typescript +manager.start({ + claimIntervalSecs: 60, + settleIntervalSecs: 120, + refundIntervalSecs: 180, + maxClaimsPerBatch: 100, + selectClaimChannels: (channels, { now }) => + channels.filter( + channel => + channel.withdrawRequestedAt > 0 || + now - channel.lastRequestTimestamp >= 60_000, + ), + shouldSettle: ({ pendingSettle }) => pendingSettle, + selectRefundChannels: (channels, { now }) => + channels.filter(channel => now - channel.lastRequestTimestamp >= 180_000), + onClaim: result => console.log(`Claimed ${result.vouchers} vouchers`), + onSettle: result => console.log(`Settled ${result.transaction}`), + onRefund: result => console.log(`Refunded ${result.channel}`), + onError: error => console.error("Settlement error:", error), +}); +``` + +In this example, `selectClaimChannels` prioritizes channels with pending withdrawals and channels idle for at least 1 minute, so their vouchers are claimed before a withdrawal can finalize. The same selection callbacks can be reused with one-shot calls such as `claimAndSettle()` and `refundIdleChannels()` from a cron job or external worker. + +## Storage + +By default, channel sessions are in memory. Set `STORAGE_DIR` to persist them on disk for local restarts. + +For serverless deployments or multi-instance servers, configure the scheme with `RedisChannelStorage`; it stores channel sessions in Redis/Valkey so they survive cold starts and update atomically across processes. + +## Prerequisites + +- Node.js v20+, pnpm v10 +- A running [batch-settlement facilitator](../../facilitator/batch-settlement) (or a hosted one) +- An EVM `payTo` address (does **not** need ETH — it only receives funds via `settle`) + +## Setup + +```bash +cp .env-local .env +# fill EVM_ADDRESS, FACILITATOR_URL, optionally EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY + +cd ../../ +pnpm install && pnpm build +cd servers/batch-settlement + +pnpm dev +``` + +The server listens on `http://localhost:4021`. Hit it with the [client example](../../clients/batch-settlement). + +### Cross-SDK local testing + +For local interop, set `FACILITATOR_URL=http://localhost:4022` (same as +`examples/go/servers/batch-settlement/.env.example`). Env keys match the Go +server example; `GET /api/generate` returns the same `usage` fields as the Go +demo for stable assertions across stacks. + +## Environment + +| Variable | Required | Description | +|----------|----------|-------------| +| `EVM_ADDRESS` | yes | `payTo` address (channel receiver) | +| `FACILITATOR_URL` | yes | Batch-settlement facilitator endpoint | +| `EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY` | no | Self-managed authorizer key (omit to delegate to facilitator) | +| `STORAGE_DIR` | no | Persist channel sessions on disk (defaults to in-memory) | +| `DEFERRED_WITHDRAW_DELAY_SECONDS` | no | Channel `withdrawDelay`; defaults to 86,400 (1 day) | diff --git a/examples/typescript/legacy/facilitator/eslint.config.js b/examples/typescript/servers/batch-settlement/eslint.config.js similarity index 100% rename from examples/typescript/legacy/facilitator/eslint.config.js rename to examples/typescript/servers/batch-settlement/eslint.config.js diff --git a/examples/typescript/servers/batch-settlement/index.ts b/examples/typescript/servers/batch-settlement/index.ts new file mode 100644 index 0000000000..5669b60083 --- /dev/null +++ b/examples/typescript/servers/batch-settlement/index.ts @@ -0,0 +1,114 @@ +import { HTTPFacilitatorClient } from "@x402/core/server"; +import { BatchSettlementEvmScheme, FileChannelStorage } from "@x402/evm/batch-settlement/server"; +import { paymentMiddleware, setSettlementOverrides, x402ResourceServer } from "@x402/express"; +import { config } from "dotenv"; +import express from "express"; +import { privateKeyToAccount } from "viem/accounts"; + +config(); + +const NETWORK = "eip155:84532" as const; + +const evmAddress = process.env.EVM_ADDRESS as `0x${string}`; +const receiverAuthorizerPrivateKey = process.env.EVM_RECEIVER_AUTHORIZER_PRIVATE_KEY as + | `0x${string}` + | undefined; +const storageDir = process.env.STORAGE_DIR; +const withdrawDelay = Number(process.env.DEFERRED_WITHDRAW_DELAY_SECONDS ?? "86400"); + +if (!evmAddress || !/^0x[0-9a-fA-F]{40}$/.test(evmAddress)) { + console.error("Missing or invalid EVM_ADDRESS (checksummed 20-byte hex, 0x-prefixed)"); + process.exit(1); +} + +const facilitatorUrl = process.env.FACILITATOR_URL; +if (!facilitatorUrl) { + console.error("Missing required FACILITATOR_URL environment variable"); + process.exit(1); +} + +const receiverAuthorizerSigner = receiverAuthorizerPrivateKey + ? privateKeyToAccount(receiverAuthorizerPrivateKey) + : undefined; + +const facilitatorClient = new HTTPFacilitatorClient({ url: facilitatorUrl }); + +const batchedScheme = new BatchSettlementEvmScheme(evmAddress, { + ...(receiverAuthorizerSigner ? { receiverAuthorizerSigner } : {}), + withdrawDelay, + ...(storageDir ? { storage: new FileChannelStorage({ directory: storageDir }) } : {}), +}); + +const resourceServer = new x402ResourceServer(facilitatorClient).register(NETWORK, batchedScheme); + +const channelManager = batchedScheme.createChannelManager(facilitatorClient, NETWORK); + +channelManager.start({ + claimIntervalSecs: 60, + settleIntervalSecs: 120, + refundIntervalSecs: 180, + maxClaimsPerBatch: 100, + selectRefundChannels: (channels, context) => + channels.filter(channel => { + if (BigInt(channel.balance) === 0n) return false; + if (channel.pendingRequest && channel.pendingRequest.expiresAt > context.now) return false; + return context.now - channel.lastRequestTimestamp >= 180_000; // Refund channels after 3 minutes of inactivity + }), + onClaim: (r: { vouchers: number; transaction: string }) => + console.log(`Claimed ${r.vouchers} vouchers (tx: ${r.transaction})`), + onSettle: (r: { transaction: string }) => + console.log(`Settled to ${evmAddress} (tx: ${r.transaction})`), + onRefund: r => console.log(`Refunded channel ${r.channel} (tx: ${r.transaction})`), + onError: (e: unknown) => console.error("Settlement error:", e), +}); + +process.on("SIGINT", async () => { + console.log("Shutting down — flushing pending claims…"); + await channelManager.stop({ flush: true }); + process.exit(0); +}); + +const app = express(); + +// Authorize up to this amount per request; optional usage-based override below bills actual usage. +const maxPrice = "$0.01"; + +app.use( + paymentMiddleware( + { + "GET /weather": { + accepts: { + scheme: "batch-settlement", + price: maxPrice, + network: NETWORK, + payTo: evmAddress, + }, + description: "Weather data", + mimeType: "application/json", + }, + }, + resourceServer, + ), +); + +app.get("/weather", (req, res) => { + const chargedPercent = 1 + Math.floor(Math.random() * 100); + setSettlementOverrides(res, { amount: `${chargedPercent}%` }); + + res.send({ + report: { + weather: "sunny", + temperature: 70, + }, + }); +}); + +app.listen(4021, () => { + console.log("Batch-settlement server listening at http://localhost:4021"); + console.log(" GET /weather"); + if (receiverAuthorizerSigner) { + console.log(` Receiver authorizer: local signer ${receiverAuthorizerSigner.address}`); + } else { + console.log(" Receiver authorizer: facilitator"); + } +}); diff --git a/examples/typescript/legacy/servers/express/package.json b/examples/typescript/servers/batch-settlement/package.json similarity index 73% rename from examples/typescript/legacy/servers/express/package.json rename to examples/typescript/servers/batch-settlement/package.json index 0e4cd41af8..86d4398ece 100644 --- a/examples/typescript/legacy/servers/express/package.json +++ b/examples/typescript/servers/batch-settlement/package.json @@ -1,5 +1,5 @@ { - "name": "express-server-example", + "name": "@x402/batch-settlement-server-example", "private": true, "type": "module", "scripts": { @@ -10,12 +10,16 @@ "lint:check": "eslint . --ext .ts" }, "dependencies": { + "@x402/core": "workspace:*", + "@x402/evm": "workspace:*", + "@x402/express": "workspace:*", "dotenv": "^16.4.7", "express": "^4.18.2", - "x402-express": "workspace:*" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "^5.0.1", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", @@ -24,8 +28,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/legacy/clients/fetch/tsconfig.json b/examples/typescript/servers/batch-settlement/tsconfig.json similarity index 100% rename from examples/typescript/legacy/clients/fetch/tsconfig.json rename to examples/typescript/servers/batch-settlement/tsconfig.json diff --git a/examples/typescript/servers/bazaar/package.json b/examples/typescript/servers/bazaar/package.json index 7857c989ab..c750bca94a 100644 --- a/examples/typescript/servers/bazaar/package.json +++ b/examples/typescript/servers/bazaar/package.json @@ -20,6 +20,7 @@ }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "^5.0.1", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", @@ -28,8 +29,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/servers/cloudfront-lambda-edge/GETTING-STARTED-CDK.md b/examples/typescript/servers/cloudfront-lambda-edge/GETTING-STARTED-CDK.md new file mode 100644 index 0000000000..e3fe365d5b --- /dev/null +++ b/examples/typescript/servers/cloudfront-lambda-edge/GETTING-STARTED-CDK.md @@ -0,0 +1,267 @@ +# Getting Started (CDK): Monetize Any HTTP App with x402 + CloudFront + Lambda@Edge + +This guide deploys the same architecture as the [Console guide](./GETTING-STARTED-CONSOLE.md) — x402 payment verification at the CloudFront edge — but with a single `cdk deploy` command instead of clicking through the AWS Console. + +**What CDK is:** The AWS Cloud Development Kit lets you describe infrastructure in TypeScript. You write code that defines your Lambda functions, CloudFront distribution, IAM roles, and how they connect — then CDK translates that into AWS resources automatically. The benefits for this workshop: + +- `cdk deploy` replaces all of Parts 2, 3, and 4 from the Console guide (~45 minutes of clicking) +- `cdk destroy` tears everything down cleanly in one command +- IAM trust policies, Lambda versions, and ARN wiring are handled for you +- The stack is repeatable and version-controlled + +--- + +## Prerequisites + +- **AWS account** ([aws.amazon.com](https://aws.amazon.com)) +- **AWS CLI** installed and configured — [install guide](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) + ```bash + brew install awscli # macOS + aws configure # enter your Access Key ID, Secret, region (any), output: json + aws sts get-caller-identity # verify it works + ``` +- **Node.js 20+** and **pnpm** — verify with `node --version` and `pnpm --version` +- **Ethereum wallet address on Base Sepolia** — install [MetaMask](https://metamask.io) and copy your `0x...` address. Base Sepolia is a testnet — no real money required. + +--- + +## Part 1 — Build the Lambda Bundle + +The CDK stack references the built Lambda output, so you need to build it first. + +**1a. Enter the lambda directory** + +```bash +cd examples/typescript/servers/cloudfront-lambda-edge/lambda +``` + +**1b. Configure your wallet address** + +Open `src/config.ts` and replace the placeholder: + +```typescript +export const PAY_TO = '0xYourActualAddressHere'; +``` + +**1c. Install and build** + +```bash +pnpm install +pnpm build +``` + +You should see: +``` +dist/index.js 206.8kb +⚡ Done in 44ms +``` + +The CDK stack reads from `lambda/dist/` — no manual zipping needed, CDK handles packaging. + +--- + +## Part 2 — Bootstrap CDK + +CDK needs a one-time setup in your AWS account to create an S3 bucket and IAM roles it uses internally for deployments. This only runs once per account/region. + +```bash +cd ../cdk +pnpm install +npx cdk bootstrap +``` + +You'll see output like: +``` +✅ Environment aws://123456789012/us-east-1 bootstrapped. +``` + +> If you see an error about credentials, make sure `aws sts get-caller-identity` returns your account info. + +--- + +## Part 3 — Deploy + +```bash +npx cdk deploy +``` + +CDK will show you a summary of what it's about to create and ask for confirmation: + +``` +This deployment will make potentially sensitive changes according to your current security approval level. + +Do you wish to deploy these changes (y/n)? +``` + +Type `y` and press Enter. + +**What CDK is creating for you:** +- IAM execution role with the correct `lambda.amazonaws.com` and `edgelambda.amazonaws.com` trust policy +- `x402-origin-request` Lambda function in us-east-1 (required for Lambda@Edge) +- `x402-origin-response` Lambda function in us-east-1 +- Published Lambda versions with the correct handlers +- CloudFront distribution pointed at `httpbin.org` +- Lambda@Edge associations on the default cache behavior + +> **Non-EU/NA notice:** The stack deploys with `PriceClass.PRICE_CLASS_100`, which limits CloudFront edge locations to North America and Europe. This is the cheapest option and sufficient for testing. If you need global coverage for production, update `cdk/lib/x402-stack.ts` and change it to `cloudfront.PriceClass.PRICE_CLASS_ALL`, then redeploy with `npx cdk deploy`. + +This takes **5–10 minutes** — CloudFront propagates to edge locations worldwide. + +When complete, CDK prints your domain: + +``` +Outputs: +X402CloudFrontStack.DistributionDomain = https://d1234abcde.cloudfront.net +``` + +Copy that URL. + +--- + +## Part 4 — Validate + +Replace `[YOUR_DOMAIN]` with your CloudFront URL in all commands below. + +**Test 1 — No payment → 402** + +```bash +curl -i https://[YOUR_DOMAIN]/api/test +``` + +Expected response: +``` +HTTP/2 402 + +{ + "x402Version": 1, + "error": "Payment required", + "accepts": [{ + "scheme": "exact", + "network": "eip155:84532", + "payTo": "0xYourAddress...", + "price": "$0.001" + }] +} +``` + +x402 is working — the Lambda function rejected the request at the edge before it ever reached httpbin. + +**Test 2 — Unprotected route → 200** + +```bash +curl -i https://[YOUR_DOMAIN]/get +``` + +The path `/get` is not in your `ROUTES` config, so it passes through to httpbin and returns 200. This confirms CloudFront and the origin are connected correctly. + +**Test 3 — Full payment flow** + +Use the [`fetch` client example](../../../../clients/fetch/) to make a paid request: + +```bash +cd ../../../../clients/fetch +cp .env-local .env +``` + +Edit `.env`: +``` +EVM_PRIVATE_KEY=0xYourBaseSepoliaPrivateKey +RESOURCE_SERVER_URL=https://[YOUR_DOMAIN] +ENDPOINT_PATH=/api/test +``` + +Then run: +```bash +pnpm install && pnpm start +``` + +The client automatically detects the `402`, constructs and signs the payment, attaches it as a `PAYMENT-SIGNATURE` header, and retries — returning the 200 response from httpbin. + +> **Never use a mainnet private key here.** Use a throwaway Base Sepolia wallet with test funds only. + +--- + +## Updating the Stack + +If you change `config.ts` (e.g., different pricing or routes), rebuild and redeploy: + +```bash +# In lambda/ +pnpm build + +# In cdk/ +npx cdk deploy +``` + +CDK detects only the changed resources and updates them — it won't recreate the distribution from scratch. + +To preview what will change before deploying: + +```bash +npx cdk diff +``` + +--- + +## Cleanup + +When done, destroy all AWS resources with one command: + +```bash +npx cdk destroy +``` + +CDK will confirm and then delete the CloudFront distribution, Lambda functions, and IAM role. Nothing is left running. + +--- + +## Using Your Own Origin + +Replace `httpbin.org` in `cdk/lib/x402-stack.ts` with your own server: + +```typescript +origin: new origins.HttpOrigin('your-api.example.com', { + protocolPolicy: cloudfront.OriginProtocolPolicy.HTTPS_ONLY, +}), +``` + +Then `npx cdk deploy` to update. Your origin needs no changes — that's the point. + +--- + +## Going to Mainnet + +Update `src/config.ts` in the lambda directory: + +```typescript +export const NETWORK = 'eip155:8453'; // Base mainnet +export const FACILITATOR_URL = 'https://your-mainnet-facilitator-url'; +export const PAY_TO = '0xYourMainnetWalletAddress'; +``` + +Rebuild and redeploy: + +```bash +cd ../lambda && pnpm build +cd ../cdk && npx cdk deploy +``` + +Browse available mainnet facilitators at the [x402 ecosystem](https://www.x402.org/ecosystem?filter=facilitators). + +--- + +## File Structure + +``` +cloudfront-lambda-edge/ +├── lambda/ # Lambda source — edit config.ts here +│ ├── src/config.ts # ← your wallet address, routes, pricing +│ └── dist/ # built output (referenced by CDK) +├── cdk/ # Infrastructure as code +│ ├── bin/app.ts # CDK app entry point +│ ├── lib/x402-stack.ts # Stack definition (all AWS resources) +│ ├── cdk.json # CDK configuration +│ └── package.json +├── GETTING-STARTED-CONSOLE.md # Step-by-step AWS Console guide +└── GETTING-STARTED-CDK.md # This file +``` diff --git a/examples/typescript/servers/cloudfront-lambda-edge/GETTING-STARTED-CONSOLE.md b/examples/typescript/servers/cloudfront-lambda-edge/GETTING-STARTED-CONSOLE.md new file mode 100644 index 0000000000..de432b79c6 --- /dev/null +++ b/examples/typescript/servers/cloudfront-lambda-edge/GETTING-STARTED-CONSOLE.md @@ -0,0 +1,385 @@ +# Getting Started: Monetize Any HTTP App with x402 + CloudFront + Lambda@Edge + +In this workshop, you will deploy a monetization layer that sits at the global edge. By leveraging AWS CloudFront and Lambda@Edge, you can gate any existing HTTP origin with crypto payments — without modifying a single line of your backend code. + +## The Request Lifecycle + +``` +Client Request + → CloudFront (global edge network) + → Lambda@Edge origin-request: verify payment (or return 402) + → Your origin server (unchanged) + → Lambda@Edge origin-response: settle payment (only on success) + → Response +``` + +1. **Client Request** — a request hits the CloudFront global edge network +2. **Verify (Origin Request)** — a Lambda function intercepts the request and verifies the x402 payment header. If missing or invalid, it returns `402 Payment Required` +3. **Origin Process** — if valid, the request proceeds to your origin server +4. **Settle (Origin Response)** — a second Lambda function settles the payment only if the origin returns a success code (status < 400) +5. **Client Response** — the client receives their data + +The "verify then settle" pattern ensures clients are never charged for failed requests. + +--- + +## Prerequisites + +- **AWS account** ([aws.amazon.com](https://aws.amazon.com)) — free tier is sufficient +- **Node.js 20+** and **pnpm** — verify with `node --version` and `pnpm --version` +- **Ethereum wallet address on Base Sepolia** — the quickest option is [MetaMask](https://metamask.io); copy your `0x...` address. Base Sepolia is a testnet — no real money required. + +--- + +## Part 1 — Build the Lambda Bundle + +This step packages the x402 logic into a single zip file ready for AWS deployment. Everything runs locally. + +**1a. Clone the repository** + +```bash +git clone https://github.com/coinbase/x402.git +cd x402/examples/typescript/servers/cloudfront-lambda-edge/lambda +``` + +**1b. Configure your wallet address** + +Open `src/config.ts` and replace the placeholder with your wallet address: + +```typescript +export const PAY_TO = '0xYourActualAddressHere'; +``` + +Leave `FACILITATOR_URL` and `NETWORK` as-is — they point to the public testnet facilitator on Base Sepolia. + +**1c. Install dependencies and build** + +```bash +pnpm install +pnpm build +``` + +You should see: +``` +dist/index.js 206.8kb +⚡ Done in 44ms +``` + +**1d. Zip the bundle** + +```bash +cd dist && zip -r ../function.zip index.js +``` + +You now have `lambda/function.zip` (~40KB). This is the file you will upload to AWS in Part 3. + +--- + +## Part 2 — Create the IAM Role + +Lambda needs an execution role — permission to run on AWS infrastructure and write logs. You create one role and reuse it for both Lambda functions. + +1. In the black search bar at the top of the AWS Console, type **IAM** → click **IAM** +2. In the left sidebar, click **Roles** → click **Create role** +3. On "Select trusted entity": + - Choose **AWS service** + - Under "Use case", select **Lambda** + - Click **Next** +4. On "Add permissions", search for and check **`AWSLambdaBasicExecutionRole`** → click **Next** +5. On "Name, review, and create": + - Role name: `x402-lambda-edge-role` + - Click **Create role** + +**Update the trust policy to support Lambda@Edge** + +By default the role only trusts `lambda.amazonaws.com`. CloudFront also needs `edgelambda.amazonaws.com` to invoke your functions at the edge. + +1. Find `x402-lambda-edge-role` in the Roles list and click it +2. Click the **Trust relationships** tab → **Edit trust policy** +3. Replace the entire contents with: + +```json +{ + "Version": "2012-10-17", + "Statement": [ + { + "Effect": "Allow", + "Principal": { + "Service": [ + "lambda.amazonaws.com", + "edgelambda.amazonaws.com" + ] + }, + "Action": "sts:AssumeRole" + } + ] +} +``` + +4. Click **Update policy** + +--- + +## Part 3 — Create the Lambda Functions + +> **Critical:** Lambda@Edge functions **must** be deployed in **us-east-1 (N. Virginia)**. Before creating anything, check the region selector in the top-right corner of the console. If it shows anything other than N. Virginia, click it and switch now. You can confirm you're in the right place by checking your browser URL — it should contain `us-east-1.console.aws.amazon.com`. + +You will create two functions from the same zip file. They use different handler names to call different exported functions from the bundle. + +--- + +### Function 1: `x402-origin-request` + +**Step 1 — Open Lambda** + +Search bar → **Lambda** → click **Create function** + +**Step 2 — Author from scratch** + +Select **Author from scratch**, then fill in: + +| Field | Value | +|---|---| +| Function name | `x402-origin-request` | +| Runtime | **Node.js 20.x** | +| Architecture | **x86_64** | + +**Step 3 — Set the execution role** + +Still on the Create function page, expand **"Change default execution role"**: +- Select **"Use an existing role"** +- Choose `x402-lambda-edge-role` from the dropdown + +Click **Create function**. + +**Step 4 — Upload the zip** + +On the function detail page, find the **Code source** panel: +1. Click **Upload from** → **.zip file** +2. Click **Upload** → select your `function.zip` → click **Save** + +**Step 5 — Set the handler** + +Still on the **Code** tab, scroll to the very bottom and find the **Runtime settings** panel. Click **Edit**: + +| Field | Value | +|---|---| +| Handler | `index.originRequestHandler` | + +Click **Save**. + +> The handler format is `filename.exportedFunctionName`. Your bundle exports `originRequestHandler` from `index.js`, so the handler is `index.originRequestHandler`. + +**Step 6 — Set the timeout** + +Click the **Configuration** tab → **General configuration** in the left sidebar → **Edit**: + +| Field | Value | +|---|---| +| Timeout | `0 min 30 sec` | +| Memory | `256 MB` | + +Click **Save**. The default timeout is 3 seconds — payment verification calls the facilitator over the network so it needs more headroom. + +**Step 7 — Publish a version** + +Lambda@Edge cannot use `$LATEST` — CloudFront requires a specific published version number in the ARN. + +1. Click **Actions** → **Publish new version** +2. Description: `initial` +3. Click **Publish** + +The page reloads showing **Version: 1**. **Copy the full ARN from the top of the page** — it ends in `:1`: + +``` +arn:aws:lambda:us-east-1:123456789012:function:x402-origin-request:1 +``` + +Save this — you will paste it into CloudFront in Part 4. + +--- + +### Function 2: `x402-origin-response` + +Repeat every step above with these two differences: + +| Field | Value | +|---|---| +| Function name | `x402-origin-response` | +| Handler | `index.originResponseHandler` | + +Everything else is identical — same zip file, same role, same timeout and memory, same publish step. + +Copy its `:1` ARN too. + +--- + +### Why two functions from one zip? + +Both Lambda functions are built into the same `index.js` bundle — they just export different handler functions. The **Handler** field tells Lambda which export to call. Same code, different entry points, different CloudFront event types. + +--- + +## Part 4 — Create the CloudFront Distribution + +For this workshop, you will use `httpbin.org` as a dummy origin — it echoes back whatever hits it, so you can verify the full x402 flow without building any backend. + +### Phase 1: Create the distribution + +1. Search bar → **CloudFront** → click **Create a CloudFront distribution** + +**Origin settings** + +At the top of the form, under "Origin domain", click **Other origin** and enter `httpbin.org` in the Custom origin field: + +| Field | Value | +|---|---| +| Origin type | **Other origin** | +| Custom origin domain | `httpbin.org` | +| Protocol | **HTTPS only** | + +**Default cache behavior** + +| Field | Value | +|---|---| +| Viewer protocol policy | **Redirect HTTP to HTTPS** | +| Allowed HTTP methods | **GET, HEAD, OPTIONS, PUT, POST, PATCH, DELETE** | +| Cache policy | **CachingDisabled** | +| Origin request policy | **AllViewerExceptHostHeader** | +| Response headers policy | **SimpleCORS** | + +> Setting Cache policy to **CachingDisabled** is critical for testing — otherwise CloudFront may serve cached responses and bypass your Lambda functions entirely. + +**WAF** + +When asked about Web Application Firewall, select **Do not enable security protections** for now. + +**Settings** + +| Field | Value | +|---|---| +| Price class | **Use only North America and Europe** | +| Description | `x402 workshop test` | + +Click **Create distribution**. + +CloudFront will show **Status: Deploying** — this takes **5–10 minutes** while AWS propagates your configuration to edge locations worldwide. + +**Copy your domain name** from the distributions list now — it looks like `d1234abcde.cloudfront.net`. + +--- + +### Phase 2: Add Lambda@Edge associations + +The Lambda function associations live on the **Behavior**, not the distribution creation form. Once your distribution status changes to **Enabled**: + +1. Click on your distribution to open its details +2. Click the **Behaviors** tab +3. Check the box next to the **Default (`*`)** behavior +4. Click **Edit** +5. Scroll down to **Function associations** and fill in: + +| Event type | Function type | ARN | Include Body | +|---|---|---|---| +| Origin request | **Lambda@Edge** | `arn:...:x402-origin-request:1` | ✅ Yes | +| Origin response | **Lambda@Edge** | `arn:...:x402-origin-response:1` | — | + +> **Include Body** must be checked for Origin Request — this ensures POST/PUT request bodies are forwarded correctly. + +6. Click **Save changes** + +CloudFront will redeploy for a few more minutes. Wait for Status to return to **Enabled** before testing. + +--- + +## Part 5 — Validate + +Replace `[YOUR_DOMAIN]` with your `d1234abcde.cloudfront.net` domain in all commands below. + +**Test 1 — No payment → 402** + +```bash +curl -i https://[YOUR_DOMAIN].cloudfront.net/api/test +``` + +Expected response: +``` +HTTP/2 402 + +{ + "x402Version": 1, + "error": "Payment required", + "accepts": [{ + "scheme": "exact", + "network": "eip155:84532", + "payTo": "0xYourAddress...", + "price": "$0.001" + }] +} +``` + +x402 is working — the Lambda function rejected the request at the edge before it ever reached httpbin. + +**Test 2 — Unprotected route → 200** + +```bash +curl -i https://[YOUR_DOMAIN].cloudfront.net/get +``` + +The path `/get` is not in your `ROUTES` config, so it passes through to httpbin and returns a 200. This confirms CloudFront and the origin are connected correctly. + +**Test 3 — Full payment flow** + +Use the [`fetch` client example](../../../../clients/fetch/) from this repo to make a paid request: + +```bash +cd ../../../../clients/fetch +cp .env-local .env +``` + +Edit `.env`: +``` +EVM_PRIVATE_KEY=0xYourBaseSepoliaPrivateKey +RESOURCE_SERVER_URL=https://[YOUR_DOMAIN].cloudfront.net +ENDPOINT_PATH=/api/test +``` + +Then run: +```bash +pnpm install && pnpm start +``` + +The client will automatically detect the `402`, construct and sign the payment, attach it as a `PAYMENT-SIGNATURE` header, and retry — returning the 200 response from httpbin. + +> **Never use a mainnet private key here.** Use a throwaway Base Sepolia wallet with test funds only. + +--- + +## Architecture Insights + +**The "aha" moment:** `httpbin.org` is a generic public API with zero knowledge of crypto or payments. By placing it behind CloudFront with x402, you transformed a free endpoint into a monetized asset in under 30 minutes — with no changes to the origin. + +**Why verify then settle?** Charging a client for a failed request (e.g., a 500 error from the origin) is poor practice. The two-Lambda architecture enforces this: `origin-request` verifies and holds the payment, `origin-response` settles it only when the origin returns status < 400. + +**Why Lambda@Edge?** Payment verification happens at the CloudFront edge location closest to the client — not in a central data center. This minimizes latency and means your origin never receives unpaid requests. + +--- + +## Cleanup + +To avoid ongoing AWS charges, delete resources when done: + +1. **CloudFront** → select your distribution → **Disable** → wait ~5 min → **Delete** +2. **Lambda** → delete `x402-origin-request` and `x402-origin-response` (in us-east-1) +3. **IAM** → delete `x402-lambda-edge-role` + +CloudFront's free tier covers 1TB data transfer and 10M requests/month, so workshop usage costs essentially nothing — but leaving a distribution running indefinitely adds up. + +--- + +## Next Steps + +- **Use your own origin** — replace `httpbin.org` with any HTTP server (AWS, GCP, Azure, on-prem, SaaS) +- **Adjust pricing and routes** — edit `src/config.ts`, rebuild, re-upload the zip, and publish a new version +- **Add WAF bot protection** — charge only bot/scraper traffic while keeping humans free (see [Advanced Patterns](./README.md#advanced-patterns)) +- **Go to mainnet** — update `NETWORK` to `eip155:8453` and `FACILITATOR_URL` to a mainnet facilitator from the [x402 ecosystem](https://www.x402.org/ecosystem?filter=facilitators) diff --git a/examples/typescript/servers/cloudfront-lambda-edge/README.md b/examples/typescript/servers/cloudfront-lambda-edge/README.md index 72d4f02c9a..90bab8c4d7 100644 --- a/examples/typescript/servers/cloudfront-lambda-edge/README.md +++ b/examples/typescript/servers/cloudfront-lambda-edge/README.md @@ -23,6 +23,15 @@ flowchart LR ## Getting Started +### New to AWS? Choose your path + +| Guide | Best for | What you'll use | +|---|---|---| +| [Console Guide](./GETTING-STARTED-CONSOLE.md) | Learning the architecture, first-time AWS setup | AWS Console (browser only, no CLI) | +| [CDK Guide](./GETTING-STARTED-CDK.md) | Repeatable deployments, taking this to production | AWS CLI + `cdk deploy` | + +Both guides deploy the same architecture. Start with the Console guide if you want to understand what each AWS resource does. Use the CDK guide if you want a single command to deploy and destroy everything. + ### Already using CloudFront + Lambda@Edge? The example files are ready for you to add your business logic: @@ -70,11 +79,6 @@ See [Lambda@Edge quotas](https://docs.aws.amazon.com/AmazonCloudFront/latest/Dev Copy `lambda/src/` into your project and adapt the build to your tooling. -> **Note**: Replace `workspace:*` dependencies with specific versions: -> ```json -> "@x402/core": "^2.2.0", -> "@x402/evm": "^2.2.0" -> ``` ### 2. Configure Payment Settings diff --git a/examples/typescript/servers/cloudfront-lambda-edge/cdk/bin/app.ts b/examples/typescript/servers/cloudfront-lambda-edge/cdk/bin/app.ts new file mode 100644 index 0000000000..e02a4be20f --- /dev/null +++ b/examples/typescript/servers/cloudfront-lambda-edge/cdk/bin/app.ts @@ -0,0 +1,12 @@ +import * as cdk from 'aws-cdk-lib'; +import { X402Stack } from '../lib/x402-stack'; + +const app = new cdk.App(); + +new X402Stack(app, 'X402CloudFrontStack', { + env: { + account: process.env.CDK_DEFAULT_ACCOUNT, + region: process.env.CDK_DEFAULT_REGION, + }, + description: 'x402 payment gate using CloudFront + Lambda@Edge', +}); diff --git a/examples/typescript/servers/cloudfront-lambda-edge/cdk/cdk.json b/examples/typescript/servers/cloudfront-lambda-edge/cdk/cdk.json new file mode 100644 index 0000000000..0bc1b6f68f --- /dev/null +++ b/examples/typescript/servers/cloudfront-lambda-edge/cdk/cdk.json @@ -0,0 +1,22 @@ +{ + "app": "npx ts-node --prefer-ts-exts bin/app.ts", + "watch": { + "include": ["**"], + "exclude": [ + "README.md", + "cdk*.json", + "**/*.d.ts", + "**/*.js", + "tsconfig.json", + "package*.json", + "yarn.lock", + "node_modules", + "dist" + ] + }, + "context": { + "@aws-cdk/aws-lambda:recognizeLayerVersion": true, + "@aws-cdk/core:checkSecretUsage": true, + "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true + } +} diff --git a/examples/typescript/servers/cloudfront-lambda-edge/cdk/lib/x402-stack.ts b/examples/typescript/servers/cloudfront-lambda-edge/cdk/lib/x402-stack.ts new file mode 100644 index 0000000000..f60a1d44f7 --- /dev/null +++ b/examples/typescript/servers/cloudfront-lambda-edge/cdk/lib/x402-stack.ts @@ -0,0 +1,98 @@ +import * as cdk from 'aws-cdk-lib'; +import * as lambda from 'aws-cdk-lib/aws-lambda'; +import * as cloudfront from 'aws-cdk-lib/aws-cloudfront'; +import * as origins from 'aws-cdk-lib/aws-cloudfront-origins'; +import { Construct } from 'constructs'; +import * as path from 'path'; + +/** + * x402 CloudFront + Lambda@Edge stack. + * + * Deploys two Lambda@Edge functions that add x402 payment verification to any + * HTTP origin — without modifying the origin itself. + * + * Prerequisites: run `pnpm build` in the ../lambda directory before deploying. + */ +export class X402Stack extends cdk.Stack { + constructor(scope: Construct, id: string, props?: cdk.StackProps) { + super(scope, id, props); + + // Lambda bundle built by running `pnpm build` in ../lambda + const lambdaCode = lambda.Code.fromAsset( + path.join(__dirname, '../../lambda/dist'), + ); + + // EdgeFunction automatically deploys to us-east-1 regardless of the stack region, + // which is a hard requirement for Lambda@Edge. + // It also sets the correct IAM trust policy (lambda + edgelambda principals) automatically. + const originRequestFn = new cloudfront.experimental.EdgeFunction( + this, + 'OriginRequest', + { + runtime: lambda.Runtime.NODEJS_20_X, + handler: 'index.originRequestHandler', + code: lambdaCode, + timeout: cdk.Duration.seconds(30), + memorySize: 256, + description: 'x402 payment verification — runs before request reaches origin', + }, + ); + + const originResponseFn = new cloudfront.experimental.EdgeFunction( + this, + 'OriginResponse', + { + runtime: lambda.Runtime.NODEJS_20_X, + handler: 'index.originResponseHandler', + code: lambdaCode, + timeout: cdk.Duration.seconds(30), + memorySize: 256, + description: 'x402 payment settlement — runs only when origin returns success', + }, + ); + + const distribution = new cloudfront.Distribution(this, 'Distribution', { + comment: 'x402 workshop distribution', + // North America and Europe only — cheapest option for testing. + // Change to PriceClass.PRICE_CLASS_ALL for global production use. + priceClass: cloudfront.PriceClass.PRICE_CLASS_100, + defaultBehavior: { + // Replace 'httpbin.org' with your own origin for production use. + origin: new origins.HttpOrigin('httpbin.org', { + protocolPolicy: cloudfront.OriginProtocolPolicy.HTTPS_ONLY, + }), + viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS, + allowedMethods: cloudfront.AllowedMethods.ALLOW_ALL, + // Disable caching for testing so every request hits Lambda@Edge. + // For production, configure a cache policy appropriate to your content. + cachePolicy: cloudfront.CachePolicy.CACHING_DISABLED, + // Pass all client headers (including PAYMENT-SIGNATURE) to Lambda and origin. + originRequestPolicy: + cloudfront.OriginRequestPolicy.ALL_VIEWER_EXCEPT_HOST_HEADER, + responseHeadersPolicy: + cloudfront.ResponseHeadersPolicy.CORS_ALLOW_ALL_ORIGINS, + edgeLambdas: [ + { + functionVersion: originRequestFn.currentVersion, + eventType: cloudfront.LambdaEdgeEventType.ORIGIN_REQUEST, + includeBody: true, + }, + { + functionVersion: originResponseFn.currentVersion, + eventType: cloudfront.LambdaEdgeEventType.ORIGIN_RESPONSE, + }, + ], + }, + }); + + new cdk.CfnOutput(this, 'DistributionDomain', { + value: `https://${distribution.distributionDomainName}`, + description: 'CloudFront domain — use this URL to test your x402 endpoints', + }); + + new cdk.CfnOutput(this, 'DistributionId', { + value: distribution.distributionId, + description: 'CloudFront distribution ID', + }); + } +} diff --git a/examples/typescript/servers/cloudfront-lambda-edge/cdk/package.json b/examples/typescript/servers/cloudfront-lambda-edge/cdk/package.json new file mode 100644 index 0000000000..354cb15973 --- /dev/null +++ b/examples/typescript/servers/cloudfront-lambda-edge/cdk/package.json @@ -0,0 +1,23 @@ +{ + "name": "@x402-examples/cloudfront-lambda-edge-cdk", + "version": "1.0.0", + "private": true, + "description": "CDK stack for x402 CloudFront + Lambda@Edge deployment", + "scripts": { + "build": "tsc", + "synth": "npx cdk synth", + "deploy": "npx cdk deploy", + "destroy": "npx cdk destroy", + "diff": "npx cdk diff" + }, + "dependencies": { + "aws-cdk-lib": "^2.252.0", + "constructs": "^10.6.0" + }, + "devDependencies": { + "aws-cdk": "^2.1120.0", + "ts-node": "^10.9.0", + "@types/node": "^22.13.4", + "typescript": "^5.7.3" + } +} diff --git a/examples/typescript/servers/cloudfront-lambda-edge/cdk/tsconfig.json b/examples/typescript/servers/cloudfront-lambda-edge/cdk/tsconfig.json new file mode 100644 index 0000000000..3b93b1b966 --- /dev/null +++ b/examples/typescript/servers/cloudfront-lambda-edge/cdk/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "commonjs", + "lib": ["ES2020"], + "types": ["node"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "outDir": "dist", + "rootDir": ".", + "declaration": true, + "declarationMap": true, + "sourceMap": true + }, + "include": ["bin/**/*.ts", "lib/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/examples/typescript/servers/cloudfront-lambda-edge/lambda/package.json b/examples/typescript/servers/cloudfront-lambda-edge/lambda/package.json index 1f96c53bc3..688c859cab 100644 --- a/examples/typescript/servers/cloudfront-lambda-edge/lambda/package.json +++ b/examples/typescript/servers/cloudfront-lambda-edge/lambda/package.json @@ -13,12 +13,13 @@ "clean": "rm -rf dist" }, "dependencies": { - "@x402/core": "workspace:*", - "@x402/evm": "workspace:*" + "@x402/core": "^2.11.0", + "@x402/evm": "^2.11.0" }, "devDependencies": { "@types/aws-lambda": "^8.10.159", + "@types/node": "^22.13.4", "esbuild": "^0.27.2", - "typescript": "^5.9.3" + "typescript": "^5.7.3" } -} \ No newline at end of file +} diff --git a/examples/typescript/servers/cloudfront-lambda-edge/lambda/tsconfig.json b/examples/typescript/servers/cloudfront-lambda-edge/lambda/tsconfig.json index 1951778498..5b22e084d9 100644 --- a/examples/typescript/servers/cloudfront-lambda-edge/lambda/tsconfig.json +++ b/examples/typescript/servers/cloudfront-lambda-edge/lambda/tsconfig.json @@ -1,8 +1,10 @@ { "compilerOptions": { "target": "ES2022", - "module": "commonjs", + "module": "ESNext", + "moduleResolution": "bundler", "lib": ["ES2022"], + "types": ["node"], "outDir": "./dist", "rootDir": "./src", "strict": true, diff --git a/examples/typescript/servers/custom/package.json b/examples/typescript/servers/custom/package.json index 245b8bd9a1..14d2be31b3 100644 --- a/examples/typescript/servers/custom/package.json +++ b/examples/typescript/servers/custom/package.json @@ -17,6 +17,7 @@ }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "^5.0.1", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", @@ -25,7 +26,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/servers/express/package.json b/examples/typescript/servers/express/package.json index adcbe1f6a8..adcb1d056b 100644 --- a/examples/typescript/servers/express/package.json +++ b/examples/typescript/servers/express/package.json @@ -13,13 +13,13 @@ "@x402/core": "workspace:*", "@x402/evm": "workspace:*", "@x402/express": "workspace:*", - "@x402/extensions": "workspace:*", "@x402/svm": "workspace:*", "dotenv": "^16.4.7", "express": "^4.18.2" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "^5.0.1", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", @@ -28,8 +28,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/servers/fastify/package.json b/examples/typescript/servers/fastify/package.json index e6474abe6a..f81709c8d4 100644 --- a/examples/typescript/servers/fastify/package.json +++ b/examples/typescript/servers/fastify/package.json @@ -13,13 +13,13 @@ "@x402/core": "workspace:*", "@x402/evm": "workspace:*", "@x402/fastify": "workspace:*", - "@x402/extensions": "workspace:*", "@x402/svm": "workspace:*", "dotenv": "^16.4.7", "fastify": "^5.0.0" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -27,8 +27,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/servers/hono/package.json b/examples/typescript/servers/hono/package.json index 5da3481328..3831a92d61 100644 --- a/examples/typescript/servers/hono/package.json +++ b/examples/typescript/servers/hono/package.json @@ -16,11 +16,11 @@ "@x402/hono": "workspace:*", "@x402/evm": "workspace:*", "@x402/svm": "workspace:*", - "@x402/extensions": "workspace:*", "hono": "^4.7.1" }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "^5.0.1", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", @@ -29,8 +29,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/servers/mcp/package.json b/examples/typescript/servers/mcp/package.json index 7c30df4406..b4e8b6c00b 100644 --- a/examples/typescript/servers/mcp/package.json +++ b/examples/typescript/servers/mcp/package.json @@ -22,8 +22,8 @@ }, "devDependencies": { "@eslint/js": "^9.24.0", - "@types/express": "^5.0.3", "@types/node": "^22.13.4", + "@types/express": "^5.0.3", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -31,7 +31,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.20.4", - "typescript": "^5.9.2" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/servers/offer-receipt/package.json b/examples/typescript/servers/offer-receipt/package.json index 2ecb0909e6..282ac4c0fa 100644 --- a/examples/typescript/servers/offer-receipt/package.json +++ b/examples/typescript/servers/offer-receipt/package.json @@ -12,7 +12,7 @@ "dependencies": { "dotenv": "^16.4.7", "express": "^4.18.2", - "viem": "^2.21.54", + "viem": "^2.48.11", "@x402/core": "workspace:*", "@x402/express": "workspace:*", "@x402/evm": "workspace:*", @@ -21,8 +21,8 @@ }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "^5.0.1", - "@types/node": "^22.0.0", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -30,7 +30,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/servers/payment-identifier/package.json b/examples/typescript/servers/payment-identifier/package.json index 2995fe247a..3e5fd65247 100644 --- a/examples/typescript/servers/payment-identifier/package.json +++ b/examples/typescript/servers/payment-identifier/package.json @@ -19,6 +19,7 @@ }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "^5.0.1", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", @@ -27,8 +28,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/servers/self-facilitation/.env-local b/examples/typescript/servers/self-facilitation/.env-local new file mode 100644 index 0000000000..5ec28413e1 --- /dev/null +++ b/examples/typescript/servers/self-facilitation/.env-local @@ -0,0 +1 @@ +EVM_PRIVATE_KEY= diff --git a/examples/typescript/legacy/clients/cdp-sdk/.prettierignore b/examples/typescript/servers/self-facilitation/.prettierignore similarity index 93% rename from examples/typescript/legacy/clients/cdp-sdk/.prettierignore rename to examples/typescript/servers/self-facilitation/.prettierignore index 5bd240ba90..3049672b5c 100644 --- a/examples/typescript/legacy/clients/cdp-sdk/.prettierignore +++ b/examples/typescript/servers/self-facilitation/.prettierignore @@ -5,4 +5,4 @@ coverage/ .github/ src/client **/**/*.json -*.md \ No newline at end of file +*.md diff --git a/examples/typescript/legacy/clients/chainlink-vrf-nft/.prettierrc b/examples/typescript/servers/self-facilitation/.prettierrc similarity index 100% rename from examples/typescript/legacy/clients/chainlink-vrf-nft/.prettierrc rename to examples/typescript/servers/self-facilitation/.prettierrc diff --git a/examples/typescript/servers/self-facilitation/README.md b/examples/typescript/servers/self-facilitation/README.md new file mode 100644 index 0000000000..065a59520d --- /dev/null +++ b/examples/typescript/servers/self-facilitation/README.md @@ -0,0 +1,62 @@ +# @x402/self-facilitation Example Server + +Express.js server demonstrating the same paywalled route shape as the `express` example, but using an in-process facilitator created with the SDK (`x402Facilitator`) instead of calling an external facilitator URL. + +## What is different from `servers/express` + +- `servers/express` uses `HTTPFacilitatorClient` and `FACILITATOR_URL` +- `servers/self-facilitation` creates an SDK facilitator in the same process and passes it as a `FacilitatorClient` +- The route/payment middleware setup stays essentially the same + +## Prerequisites + +- Node.js v20+ (install via [nvm](https://github.com/nvm-sh/nvm)) +- pnpm v10 (install via [pnpm.io/installation](https://pnpm.io/installation)) +- EVM private key with Base Sepolia ETH for settlement gas + +## Setup + +1. Copy `.env-local` to `.env`: + +```bash +cp .env-local .env +``` + +Then fill required environment variables: + +- `EVM_PRIVATE_KEY` - Ethereum private key used by the embedded facilitator + +2. Install and build all packages from the TypeScript examples root: + +```bash +cd ../../ +pnpm install && pnpm build +cd servers/self-facilitation +``` + +3. Run the server: + +```bash +pnpm dev +``` + +## Testing the server + +You can test with the existing client examples: + +```bash +cd ../clients/fetch +pnpm dev +``` + +or + +```bash +cd ../clients/axios +pnpm dev +``` + +Both clients follow the usual two-step x402 flow: +1. First request gets `402 Payment Required` +2. Client signs and retries with `PAYMENT` headers +3. Server verifies/settles via the embedded facilitator and returns `200` diff --git a/examples/typescript/legacy/servers/advanced/eslint.config.js b/examples/typescript/servers/self-facilitation/eslint.config.js similarity index 98% rename from examples/typescript/legacy/servers/advanced/eslint.config.js rename to examples/typescript/servers/self-facilitation/eslint.config.js index e2fde7b3b8..66acee252c 100644 --- a/examples/typescript/legacy/servers/advanced/eslint.config.js +++ b/examples/typescript/servers/self-facilitation/eslint.config.js @@ -36,6 +36,7 @@ export default [ import: importPlugin, }, rules: { + ...js.configs.recommended.rules, ...ts.configs.recommended.rules, "import/first": "error", "prettier/prettier": "error", diff --git a/examples/typescript/servers/self-facilitation/index.ts b/examples/typescript/servers/self-facilitation/index.ts new file mode 100644 index 0000000000..b2ac8a0b82 --- /dev/null +++ b/examples/typescript/servers/self-facilitation/index.ts @@ -0,0 +1,83 @@ +import { x402Facilitator } from "@x402/core/facilitator"; +import { paymentMiddleware, x402ResourceServer } from "@x402/express"; +import { toFacilitatorEvmSigner } from "@x402/evm"; +import { registerExactEvmScheme } from "@x402/evm/exact/facilitator"; +import { ExactEvmScheme as ExactEvmServerScheme } from "@x402/evm/exact/server"; +import { config } from "dotenv"; +import express from "express"; +import { createWalletClient, http, publicActions } from "viem"; +import { privateKeyToAccount } from "viem/accounts"; +import { baseSepolia } from "viem/chains"; + +config(); + +if (!process.env.EVM_PRIVATE_KEY) { + console.error("Missing required environment variables"); + process.exit(1); +} + +const evmAccount = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`); + +// 1) Build facilitator signer from an on-chain client. +const viemClient = createWalletClient({ + account: evmAccount, + chain: baseSepolia, + transport: http(), +}).extend(publicActions); + +const evmSigner = toFacilitatorEvmSigner({ + address: evmAccount.address, + getCode: viemClient.getCode, + readContract: viemClient.readContract, + verifyTypedData: viemClient.verifyTypedData, + writeContract: viemClient.writeContract, + sendTransaction: viemClient.sendTransaction, + waitForTransactionReceipt: viemClient.waitForTransactionReceipt, +}); + +// 2) Build an in-process facilitator and register supported scheme/network. +const facilitator = new x402Facilitator(); +registerExactEvmScheme(facilitator, { + signer: evmSigner, + networks: "eip155:84532", // Base Sepolia +}); + +// 3) Use standard express middleware wired to the local facilitator. +const app = express(); + +app.use( + paymentMiddleware( + { + "GET /weather": { + accepts: [ + { + scheme: "exact", + price: "$0.001", + network: "eip155:84532", + payTo: evmAccount.address, + }, + ], + description: "Weather data", + mimeType: "application/json", + }, + }, + new x402ResourceServer({ + verify: facilitator.verify.bind(facilitator), + settle: facilitator.settle.bind(facilitator), + getSupported: async () => facilitator.getSupported(), + }).register("eip155:84532", new ExactEvmServerScheme()), + ), +); + +app.get("/weather", (_req, res) => { + res.send({ + report: { + weather: "sunny", + temperature: 70, + }, + }); +}); + +app.listen(4021, () => { + console.log(`Server listening at http://localhost:${4021}`); +}); diff --git a/examples/typescript/legacy/facilitator/package.json b/examples/typescript/servers/self-facilitation/package.json similarity index 70% rename from examples/typescript/legacy/facilitator/package.json rename to examples/typescript/servers/self-facilitation/package.json index ad7e820081..98c68d7873 100644 --- a/examples/typescript/legacy/facilitator/package.json +++ b/examples/typescript/servers/self-facilitation/package.json @@ -1,30 +1,35 @@ { - "name": "facilitator-example", + "name": "@x402/self-facilitation-server-example", "private": true, "type": "module", "scripts": { "dev": "tsx index.ts", - "solana": "tsx solana.ts", "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", "lint": "eslint . --ext .ts --fix", "lint:check": "eslint . --ext .ts" }, "dependencies": { + "@x402/core": "workspace:*", + "@x402/evm": "workspace:*", + "@x402/express": "workspace:*", "dotenv": "^16.4.7", "express": "^4.18.2", - "x402": "workspace:*" + "viem": "^2.48.11" }, "devDependencies": { "@eslint/js": "^9.24.0", - "eslint": "^9.24.0", - "eslint-plugin-jsdoc": "^50.6.9", - "eslint-plugin-prettier": "^5.2.6", + "@types/node": "^22.13.4", + "@types/express": "^5.0.1", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", + "eslint": "^9.24.0", "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsdoc": "^50.6.9", + "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/legacy/facilitator/tsconfig.json b/examples/typescript/servers/self-facilitation/tsconfig.json similarity index 100% rename from examples/typescript/legacy/facilitator/tsconfig.json rename to examples/typescript/servers/self-facilitation/tsconfig.json diff --git a/examples/typescript/servers/sign-in-with-x/package.json b/examples/typescript/servers/sign-in-with-x/package.json index b68d4e6c2a..dd9944b294 100644 --- a/examples/typescript/servers/sign-in-with-x/package.json +++ b/examples/typescript/servers/sign-in-with-x/package.json @@ -20,8 +20,8 @@ }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "5.0.3", - "@types/node": "^22.10.5", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", "eslint": "^9.24.0", @@ -29,7 +29,7 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/examples/typescript/servers/upto/package.json b/examples/typescript/servers/upto/package.json index 8caa658be5..211146c8e7 100644 --- a/examples/typescript/servers/upto/package.json +++ b/examples/typescript/servers/upto/package.json @@ -19,6 +19,7 @@ }, "devDependencies": { "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", "@types/express": "^5.0.1", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", @@ -27,8 +28,8 @@ "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", - "tsup": "^7.2.0", - "tsx": "^4.7.0", - "typescript": "^5.3.0" + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3" } } diff --git a/foundation/x402 Technical Charter March 31, 2026.pdf b/foundation/x402 Technical Charter March 31, 2026.pdf new file mode 100644 index 0000000000..ef05a7ddcd Binary files /dev/null and b/foundation/x402 Technical Charter March 31, 2026.pdf differ diff --git a/go/.changes/unreleased/add-arbitrum-one-and-arbitrum-sepolia-default-stablecoin.yaml b/go/.changes/unreleased/add-arbitrum-one-and-arbitrum-sepolia-default-stablecoin.yaml deleted file mode 100644 index a4abbc4adc..0000000000 --- a/go/.changes/unreleased/add-arbitrum-one-and-arbitrum-sepolia-default-stablecoin.yaml +++ /dev/null @@ -1,2 +0,0 @@ -kind: added -body: Add Arbitrum One (chain ID 42161) and Arbitrum Sepolid (chain ID 421614) support with USDC as the default stablecoin \ No newline at end of file diff --git a/go/.changes/unreleased/added-20260303-121913.yaml b/go/.changes/unreleased/added-20260303-121913.yaml deleted file mode 100644 index 783a23343b..0000000000 --- a/go/.changes/unreleased/added-20260303-121913.yaml +++ /dev/null @@ -1,3 +0,0 @@ -kind: added -body: Add net/http standard library adapter for x402 payment middleware (http/nethttp package) -time: 2026-03-03T12:19:13.785928+09:00 diff --git a/go/.changes/unreleased/added-20260303-144745.yaml b/go/.changes/unreleased/added-20260303-144745.yaml deleted file mode 100644 index 58b54c2218..0000000000 --- a/go/.changes/unreleased/added-20260303-144745.yaml +++ /dev/null @@ -1,3 +0,0 @@ -kind: added -body: Add Echo framework middleware adapter for x402 payment handling in go/http/echo package -time: 2026-03-03T14:47:45.605889+09:00 diff --git a/go/.changes/unreleased/changed-20260330-155601.yaml b/go/.changes/unreleased/changed-20260330-155601.yaml deleted file mode 100644 index f565b5064e..0000000000 --- a/go/.changes/unreleased/changed-20260330-155601.yaml +++ /dev/null @@ -1,3 +0,0 @@ -kind: changed -body: Updated x402UptoPermit2Proxy canonical address to 0x4020A4f3b7b90ccA423B9fabCc0CE57C6C240002, deployed with deterministic bytecode for reproducible cross-chain CREATE2 addresses -time: 2026-03-30T15:56:01.761933-07:00 diff --git a/go/.changes/unreleased/fixed-20260324-164854.yaml b/go/.changes/unreleased/fixed-20260324-164854.yaml deleted file mode 100644 index 5f8d2a2509..0000000000 --- a/go/.changes/unreleased/fixed-20260324-164854.yaml +++ /dev/null @@ -1,3 +0,0 @@ -kind: fixed -body: 'Fix gin streaming content leak and echo panic on flush ' -time: 2026-03-24T16:48:54.420564+09:00 diff --git a/go/.changes/unreleased/mezo-testnet-default-asset.yaml b/go/.changes/unreleased/mezo-testnet-default-asset.yaml deleted file mode 100644 index 78afc2f626..0000000000 --- a/go/.changes/unreleased/mezo-testnet-default-asset.yaml +++ /dev/null @@ -1,2 +0,0 @@ -kind: added -body: Add Mezo Testnet (chain ID 31611) support with mUSD as the default stablecoin diff --git a/go/.changes/unreleased/polygon-support.yaml b/go/.changes/unreleased/polygon-support.yaml deleted file mode 100644 index 6aaaeb62be..0000000000 --- a/go/.changes/unreleased/polygon-support.yaml +++ /dev/null @@ -1,2 +0,0 @@ -kind: added -body: Add Polygon mainnet (chain ID 137) support with USDC as the default stablecoin diff --git a/go/.changes/unreleased/stable-support.yaml b/go/.changes/unreleased/stable-support.yaml deleted file mode 100644 index ea6a24c24c..0000000000 --- a/go/.changes/unreleased/stable-support.yaml +++ /dev/null @@ -1,2 +0,0 @@ -kind: added -body: Add Stable mainnet (chain ID 988) support with USDT0 as the default stablecoin diff --git a/go/.changes/unreleased/stable-testnet-support.yaml b/go/.changes/unreleased/stable-testnet-support.yaml deleted file mode 100644 index b924cd3c12..0000000000 --- a/go/.changes/unreleased/stable-testnet-support.yaml +++ /dev/null @@ -1,2 +0,0 @@ -kind: added -body: Add Stable testnet (chain ID 2201) support with USDT0 as the default stablecoin diff --git a/go/.changes/unreleased/upto-evm-scheme.yaml b/go/.changes/unreleased/upto-evm-scheme.yaml deleted file mode 100644 index fec62091f4..0000000000 --- a/go/.changes/unreleased/upto-evm-scheme.yaml +++ /dev/null @@ -1,3 +0,0 @@ -kind: added -body: Add upto EVM payment scheme with client, facilitator, and server support for permit2-based partial settlement on EVM chains -time: 2026-03-26T00:00:00.000000+00:00 diff --git a/go/.changes/v2.10.0.md b/go/.changes/v2.10.0.md new file mode 100644 index 0000000000..780a6cb897 --- /dev/null +++ b/go/.changes/v2.10.0.md @@ -0,0 +1,3 @@ +## v2.10.0 - 2026-04-27 +### Fixed +- MCP payload extraction failing with no method set \ No newline at end of file diff --git a/go/.changes/v2.11.0.md b/go/.changes/v2.11.0.md new file mode 100644 index 0000000000..5a262e7066 --- /dev/null +++ b/go/.changes/v2.11.0.md @@ -0,0 +1,6 @@ +## v2.11.0 - 2026-05-11 +### Added +- Add Radius Network (chain ID 723487) and Radius Testnet (chain ID 72344) support with SBC as the default stablecoin +- Log the EXTENSION-RESPONSES header from facilitator verify/settle responses; the HTTP facilitator client decodes the header and logs allowlisted fields (status, rejectedReason, reason, code) without attaching data to VerifyResponse or SettleResponse +- Bazaar service metadata fields (`serviceName`, `tags`, `iconUrl`) on `types.ResourceInfo`, plus `isValidServiceName` / `sanitizeTags` / `isValidIconUrl` / `sanitizeResourceServiceMetadata` helpers in `extensions/bazaar` that facilitator extraction now applies with soft-drop semantics. +- Added batch-settlement evm mechanism \ No newline at end of file diff --git a/go/.changes/v2.5.0.md b/go/.changes/v2.5.0.md new file mode 100644 index 0000000000..a325499383 --- /dev/null +++ b/go/.changes/v2.5.0.md @@ -0,0 +1,12 @@ +## v2.5.0 - 2026-03-06 +### Added +- Add route configuration validation during Initialize() to catch scheme/facilitator mismatches at startup +- Added assetTransferMethod and supportsEip2612 flag to defaultAssets +- Added `onProtectedRequest` hook to HTTP resource server +- Add WithBazaar facilitator client decorator for querying /discovery/resources endpoint from bazaar in go +- Added dynamic function for servers to generate custom response for settlement failures defaulting to empty +- Add in-memory SettlementCache to prevent duplicate SVM transaction settlement during on-chain confirmation window +### Changed +- Separated v1 legacy network name resolution from v2 CAIP-2 resolution; v1 code now uses evm/v1 package, shared utils only accept eip155:CHAIN_ID format +- GetSupported retries up to 3 times with exponential backoff on 429 rate limit responses +- Add pluggable PaywallProvider interface for custom paywall HTML generation with PaywallBuilder pattern \ No newline at end of file diff --git a/go/.changes/v2.6.0.md b/go/.changes/v2.6.0.md new file mode 100644 index 0000000000..634dd51328 --- /dev/null +++ b/go/.changes/v2.6.0.md @@ -0,0 +1,8 @@ +## v2.6.0 - 2026-03-17 +### Added +- Added simulation to permit2 verify and (optional) settle +### Changed +- Replaced SendRawApprovalAndSettle with a generic SendTransactions signer method that accepts an array of transaction requests (pre-signed or unsigned intents). Closed fail-open verification paths, aligned Permit2 amount check to exact match, and improved client extension fallback error handling +- Simulate transaction in verify and (optional) settle; Added multicall utility for efficient rpc calls; Fixed undeployed smart wallet handling +### Fixed +- Fixed paywall config injection targeting `` causing SVG parse errors in the browser \ No newline at end of file diff --git a/go/.changes/v2.7.0.md b/go/.changes/v2.7.0.md new file mode 100644 index 0000000000..99879023ce --- /dev/null +++ b/go/.changes/v2.7.0.md @@ -0,0 +1,8 @@ +## v2.7.0 - 2026-03-23 +### Changed +- Changed Bazaar discovery extension to support dynamic route patterns. EnrichDeclaration now +translates [param] route segments to :param-style routeTemplate and populates pathParams with +concrete values from each request. The EnrichExtensions call in go/http/server.go, previously +disabled (commented out) in all prior Go releases, is now active: ALL existing Go routes that +declare extensions will have their extensions enriched at request time. Added RouteTemplate field +to DiscoveryExtension so callers can read it without a type assertion. \ No newline at end of file diff --git a/go/.changes/v2.8.0.md b/go/.changes/v2.8.0.md new file mode 100644 index 0000000000..89fd18824e --- /dev/null +++ b/go/.changes/v2.8.0.md @@ -0,0 +1,15 @@ +## v2.8.0 - 2026-04-02 +### Added +- Add Arbitrum One (chain ID 42161) and Arbitrum Sepolid (chain ID 421614) support with USDC as the default stablecoin +- Add Mezo Testnet (chain ID 31611) support with mUSD as the default stablecoin +- Add Polygon mainnet (chain ID 137) support with USDC as the default stablecoin +- Add Stable mainnet (chain ID 988) support with USDT0 as the default stablecoin +- Add Stable testnet (chain ID 2201) support with USDT0 as the default stablecoin +- Add net/http standard library adapter for x402 payment middleware (http/nethttp package) +- Add Echo framework middleware adapter for x402 payment handling in go/http/echo package +- Add upto EVM payment scheme with client, facilitator, and server support for permit2-based partial settlement on EVM chains +### Changed +- Updated x402UptoPermit2Proxy canonical address to 0x4020A4f3b7b90ccA423B9fabCc0CE57C6C240002, deployed with deterministic bytecode for reproducible cross-chain CREATE2 addresses +- Migrated project from coinbase/x402 to x402-foundation/x402 organization +### Fixed +- Fix gin streaming content leak and echo panic on flush \ No newline at end of file diff --git a/go/.changes/v2.9.0.md b/go/.changes/v2.9.0.md new file mode 100644 index 0000000000..3e9b7a69ab --- /dev/null +++ b/go/.changes/v2.9.0.md @@ -0,0 +1,3 @@ +## v2.9.0 - 2026-04-13 +### Added +- Add optional `extra.memo` support to SVM exact scheme for seller-defined payment references \ No newline at end of file diff --git a/go/.changeset/facilitator-response-errors.md b/go/.changeset/facilitator-response-errors.md index d6a01891c5..2cb285aa30 100644 --- a/go/.changeset/facilitator-response-errors.md +++ b/go/.changeset/facilitator-response-errors.md @@ -1,5 +1,5 @@ --- -'github.com/coinbase/x402/go': patch +'github.com/x402-foundation/x402/go': patch --- Treat malformed facilitator success payloads as facilitator boundary errors in the Go HTTP client instead of surfacing them as verification or settlement failures. diff --git a/go/.changeset/go-erc20-approval-gas-sponsoring.md b/go/.changeset/go-erc20-approval-gas-sponsoring.md index 6352c448d3..41dcb01479 100644 --- a/go/.changeset/go-erc20-approval-gas-sponsoring.md +++ b/go/.changeset/go-erc20-approval-gas-sponsoring.md @@ -1,5 +1,5 @@ --- -'github.com/coinbase/x402/go': minor +'github.com/x402-foundation/x402/go': minor --- Implemented the erc20 approval gas sponsoring extension in the Go SDK, achieving parity with the TypeScript implementation. Enables Permit2 payments for any ERC-20 token, even those without EIP-2612 support. diff --git a/go/CHANGELOG.md b/go/CHANGELOG.md index 6e218768ad..3e57255dbc 100644 --- a/go/CHANGELOG.md +++ b/go/CHANGELOG.md @@ -1,3 +1,34 @@ +## v2.11.0 - 2026-05-11 +### Added +- Add Radius Network (chain ID 723487) and Radius Testnet (chain ID 72344) support with SBC as the default stablecoin +- Log the EXTENSION-RESPONSES header from facilitator verify/settle responses; the HTTP facilitator client decodes the header and logs allowlisted fields (status, rejectedReason, reason, code) without attaching data to VerifyResponse or SettleResponse +- Bazaar service metadata fields (`serviceName`, `tags`, `iconUrl`) on `types.ResourceInfo`, plus `isValidServiceName` / `sanitizeTags` / `isValidIconUrl` / `sanitizeResourceServiceMetadata` helpers in `extensions/bazaar` that facilitator extraction now applies with soft-drop semantics. +- Added batch-settlement evm mechanism + +## v2.10.0 - 2026-04-27 +### Fixed +- MCP payload extraction failing with no method set + +## v2.9.0 - 2026-04-13 +### Added +- Add optional `extra.memo` support to SVM exact scheme for seller-defined payment references + +## v2.8.0 - 2026-04-02 +### Added +- Add Arbitrum One (chain ID 42161) and Arbitrum Sepolid (chain ID 421614) support with USDC as the default stablecoin +- Add Mezo Testnet (chain ID 31611) support with mUSD as the default stablecoin +- Add Polygon mainnet (chain ID 137) support with USDC as the default stablecoin +- Add Stable mainnet (chain ID 988) support with USDT0 as the default stablecoin +- Add Stable testnet (chain ID 2201) support with USDT0 as the default stablecoin +- Add net/http standard library adapter for x402 payment middleware (http/nethttp package) +- Add Echo framework middleware adapter for x402 payment handling in go/http/echo package +- Add upto EVM payment scheme with client, facilitator, and server support for permit2-based partial settlement on EVM chains +### Changed +- Updated x402UptoPermit2Proxy canonical address to 0x4020A4f3b7b90ccA423B9fabCc0CE57C6C240002, deployed with deterministic bytecode for reproducible cross-chain CREATE2 addresses +- Migrated project from coinbase/x402 to x402-foundation/x402 organization +### Fixed +- Fix gin streaming content leak and echo panic on flush + ## v2.7.0 - 2026-03-23 ### Changed - Changed Bazaar discovery extension to support dynamic route patterns. EnrichDeclaration now diff --git a/go/CLIENT.md b/go/CLIENT.md index 90bbfbee00..f79129f0f9 100644 --- a/go/CLIENT.md +++ b/go/CLIENT.md @@ -16,7 +16,7 @@ An **x402 client** is an application that makes HTTP requests to payment-protect ### Installation ```bash -go get github.com/coinbase/x402/go +go get github.com/x402-foundation/x402/go ``` ### Basic HTTP Client @@ -27,10 +27,10 @@ package main import ( "net/http" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) func main() { @@ -62,7 +62,7 @@ func main() { #### EVM Signer ```go -import evmsigners "github.com/coinbase/x402/go/signers/evm" +import evmsigners "github.com/x402-foundation/x402/go/signers/evm" signer, err := evmsigners.NewClientSignerFromPrivateKey("0x1234...") if err != nil { @@ -75,7 +75,7 @@ fmt.Println("Address:", signer.Address()) #### SVM Signer ```go -import svmsigners "github.com/coinbase/x402/go/signers/svm" +import svmsigners "github.com/x402-foundation/x402/go/signers/svm" signer, err := svmsigners.NewClientSignerFromPrivateKey("5J7W...") if err != nil { @@ -540,8 +540,8 @@ Payment payloads are created fresh for each 402 response. They are not cached be ```go import ( "testing" - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/client" + x402 "github.com/x402-foundation/x402/go" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" ) func TestClientRegistration(t *testing.T) { diff --git a/go/CONTRIBUTING.md b/go/CONTRIBUTING.md index 516da7f440..4ccba71d5d 100644 --- a/go/CONTRIBUTING.md +++ b/go/CONTRIBUTING.md @@ -129,8 +129,8 @@ http/your_framework/ package yourframework import ( - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" ) // Middleware creates x402 payment middleware for YourFramework. @@ -272,7 +272,7 @@ This runs both `go fmt` and `goimports`. Use typed errors from `errors.go`: ```go -import x402 "github.com/coinbase/x402/go" +import x402 "github.com/x402-foundation/x402/go" if err != nil { return nil, x402.NewVerificationError("invalid signature", err) @@ -329,13 +329,13 @@ Examples live in `examples/go/`. When adding a new example: When adding a Go example, include a `go.mod` that references the local SDK: ```go -module github.com/coinbase/x402/examples/go/your-example +module github.com/x402-foundation/x402/examples/go/your-example go 1.24 -require github.com/coinbase/x402/go v0.0.0 +require github.com/x402-foundation/x402/go v0.0.0 -replace github.com/coinbase/x402/go => ../../../go +replace github.com/x402-foundation/x402/go => ../../../go ``` ## Documentation diff --git a/go/FACILITATOR.md b/go/FACILITATOR.md index c45409332d..a57ced3399 100644 --- a/go/FACILITATOR.md +++ b/go/FACILITATOR.md @@ -29,7 +29,7 @@ Client → Resource Server → Facilitator → Network ### Installation ```bash -go get github.com/coinbase/x402/go +go get github.com/x402-foundation/x402/go ``` ### Basic Facilitator Server @@ -39,8 +39,8 @@ package main import ( "github.com/gin-gonic/gin" - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" + x402 "github.com/x402-foundation/x402/go" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" ) func main() { @@ -389,7 +389,7 @@ A race condition exists on Solana where the same payment transaction can be subm The SVM mechanism packages include a built-in `SettlementCache` that mitigates this. When registering SVM facilitator schemes, pass a shared cache instance to both V1 and V2 schemes: ```go -import svm "github.com/coinbase/x402/go/mechanisms/svm" +import svm "github.com/x402-foundation/x402/go/mechanisms/svm" cache := svm.NewSettlementCache() v2Scheme := facilitator.NewExactSvmScheme(signer, cache) diff --git a/go/Makefile b/go/Makefile index 73c8c45eb3..74be306a16 100644 --- a/go/Makefile +++ b/go/Makefile @@ -40,10 +40,10 @@ test-integration: @echo "Running integration tests..." @if [ -f .env ]; then \ echo "Loading environment variables from .env..."; \ - export $$(grep -v '^#' .env | xargs) && go test -v -race -tags="integration,mcp" ./test/integration/...; \ + export $$(grep -v '^#' .env | xargs) && go test -v -race -count=1 -tags="integration,mcp" ./test/integration/...; \ else \ echo "No .env file found, running without environment variables..."; \ - go test -v -race -tags="integration,mcp" ./test/integration/...; \ + go test -v -race -count=1 -tags="integration,mcp" ./test/integration/...; \ fi ## test-integration-no-mcp: Run integration tests without MCP tests @@ -51,10 +51,10 @@ test-integration-no-mcp: @echo "Running integration tests (excluding MCP tests)..." @if [ -f .env ]; then \ echo "Loading environment variables from .env..."; \ - export $$(grep -v '^#' .env | xargs) && go test -v -race -tags=integration ./test/integration/...; \ + export $$(grep -v '^#' .env | xargs) && go test -v -race -count=1 -tags=integration ./test/integration/...; \ else \ echo "No .env file found, running without environment variables..."; \ - go test -v -race -tags=integration ./test/integration/...; \ + go test -v -race -count=1 -tags=integration ./test/integration/...; \ fi ## test-e2e: Run end-to-end tests @@ -126,7 +126,7 @@ changelog-merge: $(CHANGIE) docs: @echo "Generating documentation..." @godoc -http=:6060 & - @echo "Documentation server started at http://localhost:6060/pkg/github.com/coinbase/x402/go/" + @echo "Documentation server started at http://localhost:6060/pkg/github.com/x402-foundation/x402/go/" ## example-client: Run client example example-client: diff --git a/go/README.md b/go/README.md index ae89e6907b..cc4991ffe0 100644 --- a/go/README.md +++ b/go/README.md @@ -9,7 +9,7 @@ x402 is a protocol that enables HTTP resources to require cryptocurrency payment ## Installation ```bash -go get github.com/coinbase/x402/go +go get github.com/x402-foundation/x402/go ``` ## What This Package Exports @@ -186,7 +186,7 @@ For payment processing services that verify and settle payments. ## Package Structure ``` -github.com/coinbase/x402/go +github.com/x402-foundation/x402/go │ ├── Core (framework-agnostic) │ ├── client.go - x402.X402Client diff --git a/go/SERVER.md b/go/SERVER.md index f34d3eec01..ba5b37f47e 100644 --- a/go/SERVER.md +++ b/go/SERVER.md @@ -17,7 +17,7 @@ An **x402 server** is an application that protects HTTP resources with payment r ### Installation ```bash -go get github.com/coinbase/x402/go +go get github.com/x402-foundation/x402/go ``` ### Basic Gin Server @@ -27,10 +27,10 @@ package main import ( "github.com/gin-gonic/gin" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" ) func main() { @@ -152,7 +152,7 @@ settleResult := httpServer.ProcessSettlement(ctx, payload, requirements, nil, &x Request: &reqCtx, ResponseBody: responseBody, ResponseHeaders: responseHeaders, -}) +}, nil) ``` ### 4. Facilitator Client @@ -176,7 +176,7 @@ settleResp, err := facilitator.Settle(ctx, payloadBytes, requirementsBytes) ### Gin Middleware ```go -import ginmw "github.com/coinbase/x402/go/http/gin" +import ginmw "github.com/x402-foundation/x402/go/http/gin" r.Use(ginmw.X402Payment(ginmw.Config{ Routes: routes, @@ -322,8 +322,8 @@ Add protocol extensions like Bazaar discovery: ```go import ( - "github.com/coinbase/x402/go/extensions/bazaar" - "github.com/coinbase/x402/go/extensions/types" + "github.com/x402-foundation/x402/go/extensions/bazaar" + "github.com/x402-foundation/x402/go/extensions/types" ) discoveryExt, _ := bazaar.DeclareDiscoveryExtension( @@ -765,12 +765,12 @@ routes := x402http.RoutesConfig{ **V1:** ```go -import "github.com/coinbase/x402/go/middleware/gin" +import "github.com/x402-foundation/x402/go/middleware/gin" ``` **V2:** ```go -import ginmw "github.com/coinbase/x402/go/http/gin" +import ginmw "github.com/x402-foundation/x402/go/http/gin" ``` ## Related Documentation diff --git a/go/client.go b/go/client.go index 96c0cfd8a0..f617273d7e 100644 --- a/go/client.go +++ b/go/client.go @@ -5,7 +5,7 @@ import ( "fmt" "sync" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // x402Client manages payment mechanisms and creates payment payloads @@ -28,6 +28,7 @@ type x402Client struct { beforePaymentCreationHooks []BeforePaymentCreationHook afterPaymentCreationHooks []AfterPaymentCreationHook onPaymentCreationFailureHooks []OnPaymentCreationFailureHook + onPaymentResponseHooks []OnPaymentResponseHook } // ClientOption configures the client @@ -131,6 +132,55 @@ func (c *x402Client) OnPaymentCreationFailure(hook OnPaymentCreationFailureHook) return c } +// OnPaymentResponse registers a hook fired by the transport after each paid +// response. Returning Recovered=true on a corrective 402 instructs the transport +// to retry once with a freshly built payment payload. +func (c *x402Client) OnPaymentResponse(hook OnPaymentResponseHook) *x402Client { + c.mu.Lock() + defer c.mu.Unlock() + c.onPaymentResponseHooks = append(c.onPaymentResponseHooks, hook) + return c +} + +// HandlePaymentResponse dispatches the OnPaymentResponse lifecycle for a paid +// response: invokes the scheme's PaymentResponseHandler (if implemented) followed +// by every user-registered OnPaymentResponseHook. Returns Recovered=true if any +// hook recovered (first wins; subsequent hooks still run for instrumentation). +func (c *x402Client) HandlePaymentResponse( + ctx context.Context, + prCtx PaymentResponseContext, +) (PaymentResponseResult, error) { + c.mu.RLock() + schemes := findSchemesByNetwork(c.schemes, Network(prCtx.Requirements.Network)) + var schemeImpl SchemeNetworkClient + if schemes != nil { + schemeImpl = schemes[prCtx.Requirements.Scheme] + } + userHooks := append([]OnPaymentResponseHook(nil), c.onPaymentResponseHooks...) + c.mu.RUnlock() + + combined := PaymentResponseResult{} + if handler, ok := schemeImpl.(PaymentResponseHandler); ok { + res, err := handler.OnPaymentResponse(ctx, prCtx) + if err != nil { + return PaymentResponseResult{}, fmt.Errorf("scheme OnPaymentResponse: %w", err) + } + if res.Recovered { + combined.Recovered = true + } + } + for _, hook := range userHooks { + res, err := hook(ctx, prCtx) + if err != nil { + return combined, fmt.Errorf("user OnPaymentResponse hook: %w", err) + } + if res.Recovered { + combined.Recovered = true + } + } + return combined, nil +} + // SelectPaymentRequirementsV1 selects a V1 payment requirement func (c *x402Client) SelectPaymentRequirementsV1(requirements []types.PaymentRequirementsV1) (types.PaymentRequirementsV1, error) { c.mu.RLock() diff --git a/go/client_hooks.go b/go/client_hooks.go index cce0effd48..cf0d32ba85 100644 --- a/go/client_hooks.go +++ b/go/client_hooks.go @@ -64,6 +64,15 @@ type AfterPaymentCreationHook func(PaymentCreatedContext) error // will be returned instead of the error type OnPaymentCreationFailureHook func(PaymentCreationFailureContext) (*PaymentCreationFailureHookResult, error) +// OnPaymentResponseHook is called by the transport after each paid response +// (HTTP 200 with PAYMENT-RESPONSE, or corrective HTTP 402 with PAYMENT-REQUIRED). +// Mirrors the TS x402Client.onPaymentResponse user-level hook. +// +// Returning Recovered=true on a corrective 402 instructs the transport to retry +// once with a freshly built payment payload. The first hook to return Recovered +// wins; subsequent hooks still run for instrumentation. +type OnPaymentResponseHook func(context.Context, PaymentResponseContext) (PaymentResponseResult, error) + // ============================================================================ // Client Hook Registration Options // ============================================================================ @@ -88,3 +97,10 @@ func WithOnPaymentCreationFailureHook(hook OnPaymentCreationFailureHook) ClientO c.onPaymentCreationFailureHooks = append(c.onPaymentCreationFailureHooks, hook) } } + +// WithOnPaymentResponseHook registers a hook to execute after each paid response. +func WithOnPaymentResponseHook(hook OnPaymentResponseHook) ClientOption { + return func(c *x402Client) { + c.onPaymentResponseHooks = append(c.onPaymentResponseHooks, hook) + } +} diff --git a/go/client_test.go b/go/client_test.go index f8dd917e6f..4be542abe1 100644 --- a/go/client_test.go +++ b/go/client_test.go @@ -5,7 +5,7 @@ import ( "errors" "testing" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // Mock V1 client for testing diff --git a/go/constants.go b/go/constants.go index 3640ab3085..178b034f01 100644 --- a/go/constants.go +++ b/go/constants.go @@ -3,7 +3,7 @@ package x402 // Version constants const ( // Version is the SDK version - Version = "2.7.0" + Version = "2.11.0" // ProtocolVersion is the current x402 protocol version ProtocolVersion = 2 diff --git a/go/extensions/README.md b/go/extensions/README.md index e1d7b251f7..1d81f74ba8 100644 --- a/go/extensions/README.md +++ b/go/extensions/README.md @@ -24,7 +24,7 @@ The extension helpers facilitate the conversation between: Servers use helpers to attach extension metadata to payment requirements: ```go -import "github.com/coinbase/x402/go/extensions/bazaar" +import "github.com/x402-foundation/x402/go/extensions/bazaar" // Server declares: "This resource supports Bazaar discovery" extension, _ := bazaar.DeclareDiscoveryExtension(...) @@ -72,7 +72,7 @@ PaymentPayload (Client → Server → Facilitator): Recipients (clients, facilitators) can extract extension data: ```go -import "github.com/coinbase/x402/go/extensions/bazaar" +import "github.com/x402-foundation/x402/go/extensions/bazaar" // Facilitator extracts from client payment (in hook context) discovered, _ := bazaar.ExtractDiscoveredResourceFromPaymentPayload( @@ -151,7 +151,7 @@ The **Bazaar** extension is one example of a server-facilitator extension for au **Import Path:** ``` -github.com/coinbase/x402/go/extensions/bazaar +github.com/x402-foundation/x402/go/extensions/bazaar ``` **Purpose:** @@ -160,12 +160,44 @@ github.com/coinbase/x402/go/extensions/bazaar - Enables building API marketplaces and search engines **What it provides:** -- `DeclareDiscoveryExtension()` - Server helper to declare discovery metadata +- `DeclareDiscoveryExtension()` - Server helper to declare discovery metadata for HTTP endpoints +- `DeclareMcpDiscoveryExtension()` - Server helper to declare discovery metadata for MCP tools - `ExtractDiscoveredResourceFromPaymentPayload()` - Facilitator helper to extract discovered resources from client payments - `ExtractDiscoveredResourceFromPaymentRequired()` - Client helper to extract discovered resources from 402 responses - `ValidateDiscoveryExtension()` - Validation helper - JSON Schema types for structure validation +**MCP Tool Example:** + +```go +import ( + "github.com/x402-foundation/x402/go/extensions/bazaar" + mcp402 "github.com/x402-foundation/x402/go/mcp" + "github.com/x402-foundation/x402/go/types" +) + +weatherDiscovery, _ := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "get_weather", + Description: "Get current weather for a city", + Transport: bazaar.TransportSSE, + InputSchema: bazaar.JSONSchema{ + "properties": map[string]interface{}{ + "city": map[string]interface{}{"type": "string", "description": "City name"}, + }, + "required": []string{"city"}, + }, + Example: map[string]interface{}{"city": "San Francisco"}, +}) + +paymentWrapper := mcp402.NewPaymentWrapper(resourceServer, mcp402.PaymentWrapperConfig{ + Accepts: weatherAccepts, + Resource: &types.ResourceInfo{URL: "mcp://tool/get_weather"}, + Extensions: map[string]interface{}{ + bazaar.BAZAAR.Key(): weatherDiscovery, + }, +}) +``` + **What it does NOT dictate:** - How facilitators should catalog the data - What database or storage to use @@ -242,7 +274,7 @@ The `types/` subdirectory contains shared type definitions: **Import Path:** ``` -github.com/coinbase/x402/go/extensions/types +github.com/x402-foundation/x402/go/extensions/types ``` **Exports:** diff --git a/go/extensions/bazaar/bazaar_test.go b/go/extensions/bazaar/bazaar_test.go index 8eb7591269..24e1b948f2 100644 --- a/go/extensions/bazaar/bazaar_test.go +++ b/go/extensions/bazaar/bazaar_test.go @@ -2,14 +2,15 @@ package bazaar_test import ( "encoding/json" + "strings" "testing" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - v1 "github.com/coinbase/x402/go/extensions/v1" - x402http "github.com/coinbase/x402/go/http" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + v1 "github.com/x402-foundation/x402/go/extensions/v1" + x402http "github.com/x402-foundation/x402/go/http" ) func TestBazaarConstant(t *testing.T) { @@ -2150,6 +2151,701 @@ func TestBazaarDynamicRoutes(t *testing.T) { }) } +// ===== MCP Discovery Extension Tests ===== + +func TestDeclareMcpDiscoveryExtension(t *testing.T) { + t.Run("should create a valid MCP extension with full config", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "weather_lookup", + Description: "Look up weather for a city", + Transport: bazaar.TransportStreamableHTTP, + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "city": map[string]interface{}{"type": "string"}, + }, + "required": []string{"city"}, + }, + Example: map[string]interface{}{"city": "San Francisco"}, + Output: &bazaar.OutputConfig{ + Example: map[string]interface{}{"temperature": 72, "unit": "F"}, + }, + }) + + require.NoError(t, err) + assert.NotNil(t, extension.Info) + assert.NotNil(t, extension.Schema) + + mcpInput, ok := extension.Info.Input.(bazaar.McpInput) + require.True(t, ok, "Expected McpInput type") + assert.Equal(t, "mcp", mcpInput.Type) + assert.Equal(t, "weather_lookup", mcpInput.ToolName) + assert.Equal(t, "Look up weather for a city", mcpInput.Description) + assert.Equal(t, bazaar.TransportStreamableHTTP, mcpInput.Transport) + assert.NotNil(t, mcpInput.InputSchema) + assert.NotNil(t, mcpInput.Example) + + assert.NotNil(t, extension.Info.Output) + assert.Equal(t, "json", extension.Info.Output.Type) + }) + + t.Run("should create a valid MCP extension with minimal config", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "simple_tool", + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{}, + }, + }) + + require.NoError(t, err) + + mcpInput, ok := extension.Info.Input.(bazaar.McpInput) + require.True(t, ok) + assert.Equal(t, "mcp", mcpInput.Type) + assert.Equal(t, "simple_tool", mcpInput.ToolName) + assert.Empty(t, mcpInput.Description) + assert.Empty(t, mcpInput.Transport) + assert.Nil(t, mcpInput.Example) + assert.Nil(t, extension.Info.Output) + }) + + t.Run("should return error when toolName is missing", func(t *testing.T) { + _, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + InputSchema: map[string]interface{}{"type": "object"}, + }) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "toolName is required") + }) + + t.Run("should return error when inputSchema is missing", func(t *testing.T) { + _, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "my_tool", + }) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "inputSchema is required") + }) + + t.Run("should return error when toolName is whitespace-only", func(t *testing.T) { + _, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: " ", + InputSchema: map[string]interface{}{"type": "object"}, + }) + + assert.Error(t, err) + assert.Contains(t, err.Error(), "toolName is required") + }) + + t.Run("should support SSE transport", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "sse_tool", + Transport: bazaar.TransportSSE, + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{}, + }, + }) + + require.NoError(t, err) + + mcpInput, ok := extension.Info.Input.(bazaar.McpInput) + require.True(t, ok) + assert.Equal(t, bazaar.TransportSSE, mcpInput.Transport) + }) + + t.Run("should accept an arbitrary transport value without error", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "custom_transport_tool", + Transport: bazaar.McpTransport("custom-protocol"), + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{}, + }, + }) + + // Declaration succeeds since transport is not validated at declaration time + require.NoError(t, err) + + mcpInput, ok := extension.Info.Input.(bazaar.McpInput) + require.True(t, ok) + assert.Equal(t, bazaar.McpTransport("custom-protocol"), mcpInput.Transport) + + // Custom transports should pass both declaration and schema validation + result := bazaar.ValidateDiscoveryExtension(extension) + assert.True(t, result.Valid, "Custom transport should pass schema validation") + }) + + t.Run("should support streamable-http transport", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "streamable_tool", + Transport: bazaar.TransportStreamableHTTP, + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{}, + }, + }) + + require.NoError(t, err) + + mcpInput, ok := extension.Info.Input.(bazaar.McpInput) + require.True(t, ok) + assert.Equal(t, bazaar.TransportStreamableHTTP, mcpInput.Transport) + }) +} + +func TestValidateDiscoveryExtension_MCP(t *testing.T) { + t.Run("should validate a correct MCP extension", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "weather_lookup", + Description: "Look up weather", + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{"city": map[string]interface{}{"type": "string"}}, + }, + }) + require.NoError(t, err) + + result := bazaar.ValidateDiscoveryExtension(extension) + assert.True(t, result.Valid, "MCP extension should be valid: %v", result.Errors) + }) + + t.Run("should validate a minimal MCP extension", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "minimal_tool", + InputSchema: map[string]interface{}{"type": "object"}, + }) + require.NoError(t, err) + + result := bazaar.ValidateDiscoveryExtension(extension) + assert.True(t, result.Valid, "Minimal MCP extension should be valid: %v", result.Errors) + }) + + t.Run("should validate MCP extension with output", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "output_tool", + InputSchema: map[string]interface{}{"type": "object"}, + Output: &bazaar.OutputConfig{ + Example: map[string]interface{}{"result": "ok"}, + }, + }) + require.NoError(t, err) + + result := bazaar.ValidateDiscoveryExtension(extension) + assert.True(t, result.Valid, "MCP extension with output should be valid: %v", result.Errors) + }) + + t.Run("should reject MCP extension with wrong type in info", func(t *testing.T) { + // Manually construct an extension where info.input.type != "mcp" + // but schema requires const: "mcp" + extension := bazaar.DiscoveryExtension{ + Info: bazaar.DiscoveryInfo{ + Input: bazaar.McpInput{ + Type: "http", // wrong type + ToolName: "bad_tool", + InputSchema: map[string]interface{}{"type": "object"}, + }, + }, + Schema: bazaar.JSONSchema{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": map[string]interface{}{ + "input": map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "type": map[string]interface{}{ + "type": "string", + "const": "mcp", + }, + "toolName": map[string]interface{}{ + "type": "string", + }, + "inputSchema": map[string]interface{}{ + "type": "object", + }, + }, + "required": []string{"type", "toolName", "inputSchema"}, + "additionalProperties": false, + }, + }, + "required": []string{"input"}, + }, + } + + result := bazaar.ValidateDiscoveryExtension(extension) + assert.False(t, result.Valid, "Extension with wrong type should fail validation") + }) + + t.Run("should reject MCP extension missing toolName in info", func(t *testing.T) { + // Manually construct an extension where info is missing toolName + extension := bazaar.DiscoveryExtension{ + Info: bazaar.DiscoveryInfo{ + Input: bazaar.McpInput{ + Type: "mcp", + ToolName: "", // missing + InputSchema: map[string]interface{}{"type": "object"}, + }, + }, + Schema: bazaar.JSONSchema{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": map[string]interface{}{ + "input": map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "type": map[string]interface{}{ + "type": "string", + "const": "mcp", + }, + "toolName": map[string]interface{}{ + "type": "string", + "minLength": 1, + }, + "inputSchema": map[string]interface{}{ + "type": "object", + }, + }, + "required": []string{"type", "toolName", "inputSchema"}, + "additionalProperties": false, + }, + }, + "required": []string{"input"}, + }, + } + + result := bazaar.ValidateDiscoveryExtension(extension) + assert.False(t, result.Valid, "Extension with empty toolName should fail validation when schema has minLength") + }) +} + +func TestDiscoveryInfoUnmarshalJSON_MCP(t *testing.T) { + t.Run("should unmarshal MCP discovery info correctly", func(t *testing.T) { + // Create an MCP extension, marshal to JSON, unmarshal back + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "round_trip_tool", + Description: "Tests JSON round-trip", + Transport: bazaar.TransportStreamableHTTP, + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "query": map[string]interface{}{"type": "string"}, + }, + }, + Example: map[string]interface{}{"query": "test"}, + }) + require.NoError(t, err) + + // Marshal to JSON + jsonBytes, err := json.Marshal(extension) + require.NoError(t, err) + + // Unmarshal back + var roundTripped bazaar.DiscoveryExtension + err = json.Unmarshal(jsonBytes, &roundTripped) + require.NoError(t, err) + + // Should preserve McpInput type + mcpInput, ok := roundTripped.Info.Input.(bazaar.McpInput) + require.True(t, ok, "Expected McpInput after round-trip, got %T", roundTripped.Info.Input) + assert.Equal(t, "mcp", mcpInput.Type) + assert.Equal(t, "round_trip_tool", mcpInput.ToolName) + assert.Equal(t, "Tests JSON round-trip", mcpInput.Description) + assert.Equal(t, bazaar.TransportStreamableHTTP, mcpInput.Transport) + }) + + t.Run("should distinguish MCP from HTTP in mixed JSON", func(t *testing.T) { + // HTTP extension + httpExtension, err := bazaar.DeclareDiscoveryExtension( + bazaar.MethodGET, + map[string]interface{}{"q": "test"}, + bazaar.JSONSchema{"properties": map[string]interface{}{"q": map[string]interface{}{"type": "string"}}}, + "", + nil, + ) + require.NoError(t, err) + + // MCP extension + mcpExtension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "mcp_tool", + InputSchema: map[string]interface{}{"type": "object"}, + }) + require.NoError(t, err) + + // Marshal both + httpJSON, _ := json.Marshal(httpExtension) + mcpJSON, _ := json.Marshal(mcpExtension) + + // Unmarshal both + var httpResult bazaar.DiscoveryExtension + var mcpResult bazaar.DiscoveryExtension + require.NoError(t, json.Unmarshal(httpJSON, &httpResult)) + require.NoError(t, json.Unmarshal(mcpJSON, &mcpResult)) + + _, isQuery := httpResult.Info.Input.(bazaar.QueryInput) + assert.True(t, isQuery, "HTTP extension should unmarshal to QueryInput") + + _, isMcp := mcpResult.Info.Input.(bazaar.McpInput) + assert.True(t, isMcp, "MCP extension should unmarshal to McpInput") + }) +} + +func TestExtractDiscoveredResourceFromPaymentPayload_MCP(t *testing.T) { + t.Run("should extract MCP info from v2 PaymentPayload", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "search_tool", + Description: "Search the database", + Transport: bazaar.TransportStreamableHTTP, + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "query": map[string]interface{}{"type": "string"}, + }, + "required": []string{"query"}, + }, + }) + require.NoError(t, err) + + requirements := x402.PaymentRequirements{ + Scheme: "exact", + Network: "eip155:8453", + } + + paymentPayload := x402.PaymentPayload{ + X402Version: 2, + Accepted: requirements, + Payload: map[string]interface{}{}, + Resource: &x402.ResourceInfo{ + URL: "https://api.example.com/mcp", + }, + Extensions: map[string]interface{}{ + bazaar.BAZAAR.Key(): extension, + }, + } + + payloadBytes, _ := json.Marshal(paymentPayload) + requirementsBytes, _ := json.Marshal(requirements) + + info, err := bazaar.ExtractDiscoveredResourceFromPaymentPayload(payloadBytes, requirementsBytes, true) + require.NoError(t, err) + require.NotNil(t, info) + + assert.Equal(t, "https://api.example.com/mcp", info.ResourceURL) + assert.Equal(t, 2, info.X402Version) + assert.Equal(t, "search_tool", info.ToolName) + assert.Empty(t, info.Method, "MCP resources should have empty Method") + + mcpInput, ok := info.DiscoveryInfo.Input.(bazaar.McpInput) + require.True(t, ok) + assert.Equal(t, "mcp", mcpInput.Type) + assert.Equal(t, "search_tool", mcpInput.ToolName) + }) + + t.Run("should extract MCP resource when method is empty", func(t *testing.T) { + extension := map[string]interface{}{ + "info": map[string]interface{}{ + "input": map[string]interface{}{ + "type": "mcp", + "method": "", + "toolName": "search_tool", + "inputSchema": map[string]interface{}{"type": "object"}, + }, + }, + "schema": map[string]interface{}{}, + } + + requirements := x402.PaymentRequirements{ + Scheme: "exact", + Network: "eip155:8453", + } + + paymentPayload := x402.PaymentPayload{ + X402Version: 2, + Accepted: requirements, + Payload: map[string]interface{}{}, + Resource: &x402.ResourceInfo{ + URL: "https://api.example.com/mcp", + }, + Extensions: map[string]interface{}{ + bazaar.BAZAAR.Key(): extension, + }, + } + + payloadBytes, _ := json.Marshal(paymentPayload) + requirementsBytes, _ := json.Marshal(requirements) + + info, err := bazaar.ExtractDiscoveredResourceFromPaymentPayload(payloadBytes, requirementsBytes, false) + require.NoError(t, err) + require.NotNil(t, info) + assert.Equal(t, "search_tool", info.ToolName) + assert.Empty(t, info.Method) + }) + + t.Run("should recover MCP fields when deserialized as query input", func(t *testing.T) { + // Missing input.type causes default QueryInput decoding in DiscoveryInfo.UnmarshalJSON. + // The extractor should recover MCP fields from raw payload input. + extension := map[string]interface{}{ + "info": map[string]interface{}{ + "input": map[string]interface{}{ + "toolName": "query_fallback_tool", + "transport": "sse", + "inputSchema": map[string]interface{}{"type": "object"}, + }, + }, + "schema": map[string]interface{}{}, + } + + requirements := x402.PaymentRequirements{ + Scheme: "exact", + Network: "eip155:8453", + } + + paymentPayload := x402.PaymentPayload{ + X402Version: 2, + Accepted: requirements, + Payload: map[string]interface{}{}, + Resource: &x402.ResourceInfo{ + URL: "https://api.example.com/mcp", + }, + Extensions: map[string]interface{}{ + bazaar.BAZAAR.Key(): extension, + }, + } + + payloadBytes, _ := json.Marshal(paymentPayload) + requirementsBytes, _ := json.Marshal(requirements) + + info, err := bazaar.ExtractDiscoveredResourceFromPaymentPayload(payloadBytes, requirementsBytes, false) + require.NoError(t, err) + require.NotNil(t, info) + assert.Equal(t, "query_fallback_tool", info.ToolName) + assert.Empty(t, info.Method) + + mcpInput, ok := info.DiscoveryInfo.Input.(bazaar.McpInput) + require.True(t, ok) + assert.Equal(t, "query_fallback_tool", mcpInput.ToolName) + assert.Equal(t, bazaar.TransportSSE, mcpInput.Transport) + }) +} + +func TestExtractDiscoveredResourceFromPaymentRequired_MCP(t *testing.T) { + t.Run("should extract MCP info from v2 PaymentRequired", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "lookup_tool", + Description: "Lookup data", + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "id": map[string]interface{}{"type": "string"}, + }, + }, + }) + require.NoError(t, err) + + paymentRequired := x402.PaymentRequired{ + X402Version: 2, + Resource: &x402.ResourceInfo{ + URL: "https://api.example.com/mcp", + Description: "MCP endpoint", + MimeType: "application/json", + }, + Accepts: []x402.PaymentRequirements{ + {Scheme: "exact", Network: "eip155:8453"}, + }, + Extensions: map[string]interface{}{ + "bazaar": extension, + }, + } + + paymentRequiredBytes, _ := json.Marshal(paymentRequired) + + info, err := bazaar.ExtractDiscoveredResourceFromPaymentRequired(paymentRequiredBytes, true) + require.NoError(t, err) + require.NotNil(t, info) + + assert.Equal(t, "https://api.example.com/mcp", info.ResourceURL) + assert.Equal(t, 2, info.X402Version) + assert.Equal(t, "lookup_tool", info.ToolName) + assert.Empty(t, info.Method) + + mcpInput, ok := info.DiscoveryInfo.Input.(bazaar.McpInput) + require.True(t, ok) + assert.Equal(t, "mcp", mcpInput.Type) + assert.Equal(t, "lookup_tool", mcpInput.ToolName) + }) + + t.Run("should extract MCP info from payment required when method is empty", func(t *testing.T) { + extension := map[string]interface{}{ + "info": map[string]interface{}{ + "input": map[string]interface{}{ + "type": "mcp", + "method": "", + "toolName": "lookup_tool", + "inputSchema": map[string]interface{}{"type": "object"}, + }, + }, + "schema": map[string]interface{}{}, + } + + paymentRequired := x402.PaymentRequired{ + X402Version: 2, + Resource: &x402.ResourceInfo{ + URL: "https://api.example.com/mcp", + }, + Accepts: []x402.PaymentRequirements{ + {Scheme: "exact", Network: "eip155:8453"}, + }, + Extensions: map[string]interface{}{ + bazaar.BAZAAR.Key(): extension, + }, + } + + paymentRequiredBytes, _ := json.Marshal(paymentRequired) + info, err := bazaar.ExtractDiscoveredResourceFromPaymentRequired(paymentRequiredBytes, false) + require.NoError(t, err) + require.NotNil(t, info) + assert.Equal(t, "lookup_tool", info.ToolName) + assert.Empty(t, info.Method) + }) + + t.Run("should recover MCP fields in payment required when deserialized as query input", func(t *testing.T) { + extension := map[string]interface{}{ + "info": map[string]interface{}{ + "input": map[string]interface{}{ + "toolName": "query_fallback_lookup_tool", + "transport": "streamable-http", + "inputSchema": map[string]interface{}{"type": "object"}, + }, + }, + "schema": map[string]interface{}{}, + } + + paymentRequired := x402.PaymentRequired{ + X402Version: 2, + Resource: &x402.ResourceInfo{ + URL: "https://api.example.com/mcp", + }, + Accepts: []x402.PaymentRequirements{ + {Scheme: "exact", Network: "eip155:8453"}, + }, + Extensions: map[string]interface{}{ + bazaar.BAZAAR.Key(): extension, + }, + } + + paymentRequiredBytes, _ := json.Marshal(paymentRequired) + info, err := bazaar.ExtractDiscoveredResourceFromPaymentRequired(paymentRequiredBytes, false) + require.NoError(t, err) + require.NotNil(t, info) + assert.Equal(t, "query_fallback_lookup_tool", info.ToolName) + assert.Empty(t, info.Method) + + mcpInput, ok := info.DiscoveryInfo.Input.(bazaar.McpInput) + require.True(t, ok) + assert.Equal(t, "query_fallback_lookup_tool", mcpInput.ToolName) + assert.Equal(t, bazaar.TransportStreamableHTTP, mcpInput.Transport) + }) +} + +func TestBazaarResourceServerExtension_MCP(t *testing.T) { + t.Run("should pass MCP extension through unchanged", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "passthrough_tool", + Description: "Should not be modified by EnrichDeclaration", + Transport: bazaar.TransportStreamableHTTP, + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{"x": map[string]interface{}{"type": "number"}}, + }, + }) + require.NoError(t, err) + + httpContext := x402http.HTTPRequestContext{ + Method: "POST", + Path: "/mcp/tool", + RoutePattern: "/mcp/tool", + Adapter: &mockHTTPAdapterForBazaar{path: "/mcp/tool"}, + } + + enriched := bazaar.BazaarResourceServerExtension.EnrichDeclaration(extension, httpContext) + + // Should be returned unchanged (same object) + enrichedExt, ok := enriched.(bazaar.DiscoveryExtension) + require.True(t, ok) + + mcpInput, ok := enrichedExt.Info.Input.(bazaar.McpInput) + require.True(t, ok) + assert.Equal(t, "passthrough_tool", mcpInput.ToolName) + assert.Equal(t, "Should not be modified by EnrichDeclaration", mcpInput.Description) + assert.Empty(t, enrichedExt.RouteTemplate, "MCP should not get a routeTemplate") + }) + + t.Run("should pass MCP extension through even with dynamic route context", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "dynamic_context_tool", + InputSchema: map[string]interface{}{"type": "object"}, + }) + require.NoError(t, err) + + // Even with a dynamic route pattern, MCP should be unchanged + httpContext := x402http.HTTPRequestContext{ + Method: "POST", + Path: "/mcp/tools/123", + RoutePattern: "/mcp/tools/[toolId]", + Adapter: &mockHTTPAdapterForBazaar{path: "/mcp/tools/123"}, + } + + enriched := bazaar.BazaarResourceServerExtension.EnrichDeclaration(extension, httpContext) + + enrichedExt, ok := enriched.(bazaar.DiscoveryExtension) + require.True(t, ok) + + _, isMcp := enrichedExt.Info.Input.(bazaar.McpInput) + assert.True(t, isMcp, "Should still be McpInput after enrichment") + assert.Empty(t, enrichedExt.RouteTemplate, "MCP should not get a routeTemplate even with dynamic route") + }) +} + +func TestExtractDiscoveryInfoFromExtension_MCP(t *testing.T) { + t.Run("should extract info from MCP extension with validation", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "extract_tool", + Description: "For extraction test", + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "param": map[string]interface{}{"type": "string"}, + }, + }, + }) + require.NoError(t, err) + + info, err := bazaar.ExtractDiscoveryInfoFromExtension(extension, true) + require.NoError(t, err) + require.NotNil(t, info) + + mcpInput, ok := info.Input.(bazaar.McpInput) + require.True(t, ok) + assert.Equal(t, "extract_tool", mcpInput.ToolName) + }) + + t.Run("should extract info from MCP extension without validation", func(t *testing.T) { + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "novalidate_tool", + InputSchema: map[string]interface{}{"type": "object"}, + }) + require.NoError(t, err) + + info, err := bazaar.ExtractDiscoveryInfoFromExtension(extension, false) + require.NoError(t, err) + require.NotNil(t, info) + + mcpInput, ok := info.Input.(bazaar.McpInput) + require.True(t, ok) + assert.Equal(t, "novalidate_tool", mcpInput.ToolName) + }) +} + // TestDynamicRoutesCatalogConsolidation verifies that two requests to the same // parameterized route produce the same canonical ResourceURL, so a catalog keyed by ResourceURL // contains exactly one entry regardless of how many distinct concrete parameter values arrive. @@ -2193,3 +2889,82 @@ func TestDynamicRoutesCatalogConsolidation(t *testing.T) { assert.Equal(t, discovered1.ResourceURL, discovered2.ResourceURL, "requests to the same parameterized route should consolidate to one catalog entry") } + +func TestExtractDiscoveredResource_ServiceMetadata(t *testing.T) { + declared, _ := bazaar.DeclareDiscoveryExtension( + bazaar.MethodGET, + map[string]interface{}{"city": "NYC"}, + bazaar.JSONSchema{ + "properties": map[string]interface{}{ + "city": map[string]interface{}{"type": "string"}, + }, + }, + "", + nil, + ) + + build := func(resource *x402.ResourceInfo) []byte { + payload := x402.PaymentPayload{ + X402Version: 2, + Accepted: x402.PaymentRequirements{Scheme: "exact", Network: "eip155:8453"}, + Payload: map[string]interface{}{}, + Resource: resource, + Extensions: map[string]interface{}{bazaar.BAZAAR.Key(): declared}, + } + b, _ := json.Marshal(payload) + return b + } + + t.Run("surfaces sanitized serviceName / tags / iconUrl from PaymentPayload", func(t *testing.T) { + bytes := build(&x402.ResourceInfo{ + URL: "https://api.example.com/weather", + Description: "Weather API", + MimeType: "application/json", + ServiceName: "Example Weather", + Tags: []string{"weather", "forecast"}, + IconUrl: "https://api.example.com/icon.png", + }) + discovered, err := bazaar.ExtractDiscoveredResourceFromPaymentPayload(bytes, nil, false) + require.NoError(t, err) + require.NotNil(t, discovered) + assert.Equal(t, "Example Weather", discovered.ServiceName) + assert.Equal(t, []string{"weather", "forecast"}, discovered.Tags) + assert.Equal(t, "https://api.example.com/icon.png", discovered.IconUrl) + }) + + t.Run("soft-drops invalid metadata fields independently from PaymentPayload", func(t *testing.T) { + bytes := build(&x402.ResourceInfo{ + URL: "https://api.example.com/weather", + ServiceName: strings.Repeat("a", 33), + Tags: []string{"weather", "", "forecast"}, + IconUrl: "http://localhost/icon.png", + }) + discovered, err := bazaar.ExtractDiscoveredResourceFromPaymentPayload(bytes, nil, false) + require.NoError(t, err) + require.NotNil(t, discovered) + assert.Equal(t, "", discovered.ServiceName) + assert.Equal(t, []string{"weather", "forecast"}, discovered.Tags) + assert.Equal(t, "", discovered.IconUrl) + }) + + t.Run("surfaces sanitized metadata from PaymentRequired", func(t *testing.T) { + paymentRequired := x402.PaymentRequired{ + X402Version: 2, + Resource: &x402.ResourceInfo{ + URL: "https://api.example.com/weather", + ServiceName: "Example Weather", + Tags: []string{"weather"}, + IconUrl: "https://api.example.com/icon.png", + }, + Accepts: []x402.PaymentRequirements{{Scheme: "exact", Network: "eip155:8453"}}, + Extensions: map[string]interface{}{bazaar.BAZAAR.Key(): declared}, + } + b, _ := json.Marshal(paymentRequired) + discovered, err := bazaar.ExtractDiscoveredResourceFromPaymentRequired(b, false) + require.NoError(t, err) + require.NotNil(t, discovered) + assert.Equal(t, "Example Weather", discovered.ServiceName) + assert.Equal(t, []string{"weather"}, discovered.Tags) + assert.Equal(t, "https://api.example.com/icon.png", discovered.IconUrl) + }) +} diff --git a/go/extensions/bazaar/doc.go b/go/extensions/bazaar/doc.go index c9bf50290e..73dbb686ff 100644 --- a/go/extensions/bazaar/doc.go +++ b/go/extensions/bazaar/doc.go @@ -2,7 +2,8 @@ Package bazaar provides the Bazaar Discovery Extension for x402 v2 and v1. Enables facilitators to automatically catalog and index x402-enabled resources -by following the server's provided discovery instructions. +by following the server's provided discovery instructions. Supports both HTTP +endpoints and MCP (Model Context Protocol) tools. # V2 Usage @@ -10,9 +11,9 @@ The v2 extension follows a pattern where: - `info`: Contains the actual discovery data (the values) - `schema`: JSON Schema that validates the structure of `info` -# For Resource Servers (V2) +# For HTTP Resource Servers (V2) - import "github.com/coinbase/x402/go/extensions/bazaar" + import "github.com/x402-foundation/x402/go/extensions/bazaar" // Declare a GET endpoint extension, err := bazaar.DeclareDiscoveryExtension( @@ -34,13 +35,72 @@ The v2 extension follows a pattern where: Resource: x402.Resource{...}, Accepts: []x402.PaymentRequirements{...}, Extensions: map[string]interface{}{ - bazaar.BAZAAR: extension, + bazaar.BAZAAR.Key(): extension, }, } +# For MCP Tool Servers (V2) + + import "github.com/x402-foundation/x402/go/extensions/bazaar" + + // Declare an MCP tool + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "weather_lookup", + Description: "Look up weather for a city", + Transport: bazaar.TransportStreamableHTTP, + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "city": map[string]interface{}{"type": "string"}, + }, + "required": []string{"city"}, + }, + Example: map[string]interface{}{"city": "San Francisco"}, + }) + + // Include in PaymentRequired response + paymentRequired := x402.PaymentRequired{ + X402Version: 2, + Resource: x402.Resource{...}, + Accepts: []x402.PaymentRequirements{...}, + Extensions: map[string]interface{}{ + bazaar.BAZAAR.Key(): extension, + }, + } + +# For MCP Tool Servers (V2) + + import ( + "github.com/x402-foundation/x402/go/extensions/bazaar" + mcp402 "github.com/x402-foundation/x402/go/mcp" + "github.com/x402-foundation/x402/go/types" + ) + + // Declare an MCP tool for Bazaar discovery + extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "get_weather", + Description: "Get current weather for a city", + Transport: bazaar.TransportSSE, + InputSchema: bazaar.JSONSchema{ + "properties": map[string]interface{}{ + "city": map[string]interface{}{"type": "string"}, + }, + "required": []string{"city"}, + }, + }) + + // Pass in MCP payment wrapper config + paymentWrapper := mcp402.NewPaymentWrapper(resourceServer, mcp402.PaymentWrapperConfig{ + Accepts: accepts, + Resource: &types.ResourceInfo{URL: "mcp://tool/get_weather"}, + Extensions: map[string]interface{}{ + bazaar.BAZAAR.Key(): extension, + }, + }) + # For Facilitators (V2 and V1) - import "github.com/coinbase/x402/go/extensions/bazaar" + import "github.com/x402-foundation/x402/go/extensions/bazaar" // Extract from client's PaymentPayload (facilitator hook context) // V2: Extensions are in PaymentPayload.Extensions (client copied from PaymentRequired) @@ -57,7 +117,7 @@ The v2 extension follows a pattern where: # For Clients (Processing 402 Responses) - import "github.com/coinbase/x402/go/extensions/bazaar" + import "github.com/x402-foundation/x402/go/extensions/bazaar" // Extract from server's 402 PaymentRequired response // V2: Checks PaymentRequired.Extensions, falls back to Accepts[0] @@ -76,7 +136,7 @@ The v2 extension follows a pattern where: V1 discovery information is stored in the `outputSchema` field of PaymentRequirements. Both extraction functions automatically handle v1 format. - import v1 "github.com/coinbase/x402/go/extensions/bazaar/v1" + import v1 "github.com/x402-foundation/x402/go/extensions/v1" // Direct v1 extraction (for advanced use cases) infoV1, err := v1.ExtractDiscoveryInfoV1(paymentRequirementsV1) diff --git a/go/extensions/bazaar/facilitator.go b/go/extensions/bazaar/facilitator.go index ef54483a27..2c10ec3c5d 100644 --- a/go/extensions/bazaar/facilitator.go +++ b/go/extensions/bazaar/facilitator.go @@ -3,15 +3,18 @@ package bazaar import ( "encoding/json" "fmt" + "net" "net/url" "regexp" "strings" + "unicode" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/types" - v1 "github.com/coinbase/x402/go/extensions/v1" - x402types "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/types" + v1 "github.com/x402-foundation/x402/go/extensions/v1" + x402types "github.com/x402-foundation/x402/go/types" "github.com/xeipuuv/gojsonschema" + "golang.org/x/net/idna" ) // ValidationResult represents the result of validating a discovery extension @@ -91,11 +94,16 @@ func ValidateDiscoveryExtension(extension types.DiscoveryExtension) ValidationRe type DiscoveredResource struct { ResourceURL string Method string + ToolName string X402Version int DiscoveryInfo *types.DiscoveryInfo Description string MimeType string RouteTemplate string + // Sanitized service metadata. See SanitizeResourceServiceMetadata for rules. + ServiceName string + Tags []string + IconUrl string } // ExtractDiscoveredResourceFromPaymentPayload extracts a discovered resource from a client's payment payload and requirements. @@ -146,6 +154,8 @@ func ExtractDiscoveredResourceFromPaymentPayload( var description string var mimeType string var routeTemplate string + var rawInput map[string]interface{} + var serviceMetadata SanitizedResourceServiceMetadata version := versionCheck.X402Version switch version { @@ -161,6 +171,7 @@ func ExtractDiscoveredResourceFromPaymentPayload( resourceURL = payload.Resource.URL description = payload.Resource.Description mimeType = payload.Resource.MimeType + serviceMetadata = SanitizeResourceServiceMetadata(payload.Resource) } // Extract discovery info from extensions @@ -173,6 +184,11 @@ func ExtractDiscoveredResourceFromPaymentPayload( if v, ok := m["routeTemplate"]; ok { rawTemplate, _ = v.(string) } + if infoMap, ok := m["info"].(map[string]interface{}); ok { + if inputMap, ok := infoMap["input"].(map[string]interface{}); ok { + rawInput = inputMap + } + } } if isValidRouteTemplate(rawTemplate) { routeTemplate = rawTemplate @@ -224,17 +240,12 @@ func ExtractDiscoveredResourceFromPaymentPayload( return nil, nil } - // Extract method from discovery info - method := "UNKNOWN" - switch input := discoveryInfo.Input.(type) { - case types.QueryInput: - method = string(input.Method) - case types.BodyInput: - method = string(input.Method) - } + // Extract method or toolName from discovery info. + // For MCP, recover toolName from raw input if upstream deserialization produced QueryInput. + method, toolName := extractMethodAndToolName(discoveryInfo, rawInput) - if method == "UNKNOWN" { - return nil, fmt.Errorf("failed to extract method from discovery info") + if method == "" && toolName == "" { + return nil, fmt.Errorf("failed to extract method/toolName from discovery info") } normalizedURL := normalizeResourceURL(resourceURL, routeTemplate) @@ -244,9 +255,13 @@ func ExtractDiscoveredResourceFromPaymentPayload( Description: description, MimeType: mimeType, Method: method, + ToolName: toolName, X402Version: version, DiscoveryInfo: discoveryInfo, RouteTemplate: routeTemplate, + ServiceName: serviceMetadata.ServiceName, + Tags: serviceMetadata.Tags, + IconUrl: serviceMetadata.IconUrl, }, nil } @@ -288,6 +303,251 @@ func isValidRouteTemplate(s string) bool { return true } +// Maximum lengths for resource service metadata fields. Spec: see +// specs/extensions/bazaar.md "Service Metadata on `resource`". +const ( + maxServiceNameLen = 32 + maxTagLen = 32 + maxTags = 5 + maxIconURLLen = 2048 +) + +// matches a bare IPv4 dotted-quad. IPv6 literals are detected via net.ParseIP. +var ipv4Regex = regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`) + +// SSRF defense: any all-digit hostname is suspect because no legitimate DNS name +// is purely numeric. Catches decimal-encoded IPs (http://2130706433/ → 127.0.0.1) +// and short-form IPs (http://0/ → 0.0.0.0, treated as loopback on Linux). +var allDigitsRegex = regexp.MustCompile(`^\d+$`) + +// SSRF defense: hex-encoded IPs (http://0x7f000001/ → 127.0.0.1) — same family +// of bypasses as the decimal form above. +var hexLiteralRegex = regexp.MustCompile(`(?i)^0x[0-9a-f]+$`) + +// Printable ASCII range (U+0020–U+007E). serviceName and tags are constrained +// to this range so that String.length (UTF-16 code units) in TS, len() (code +// points) in Python, and len() (UTF-8 bytes) here all agree on the character +// count. Same convention as paymentidentifier.id. +var printableASCIIRegex = regexp.MustCompile(`^[\x20-\x7e]+$`) + +// Loopback hostnames that must be rejected for SSRF defense. Includes the +// common /etc/hosts aliases on Linux/macOS (`localhost.localdomain`, +// `ip6-localhost`, `ip6-loopback`) — without these, a hostile provider could +// route the facilitator's image fetcher to its own loopback interface. +var loopbackHostnames = map[string]struct{}{ + "localhost": {}, + "localhost.localdomain": {}, + "ip6-localhost": {}, + "ip6-loopback": {}, +} + +// hasControlChar reports whether s contains any ASCII control character +// (C0 range U+0000–U+001F or DEL U+007F). Used by isValidIconUrl on the raw +// URL byte string before parsing. +func hasControlChar(s string) bool { + for i := 0; i < len(s); i++ { + c := s[i] + if c <= 0x1f || c == 0x7f { + return true + } + } + return false +} + +// containsControlChar reports whether s contains any Unicode control character +// (Unicode category Cc). Defense-in-depth: the printable-ASCII regex used by +// isValidServiceName / sanitizeTags already rejects every control character, +// but this explicit check documents intent and would survive any future +// relaxation of the ASCII restriction. +func containsControlChar(s string) bool { + for _, r := range s { + if unicode.IsControl(r) { + return true + } + } + return false +} + +// isValidServiceName checks whether a serviceName value is structurally valid +// for the bazaar resource.serviceName field. Non-empty string of printable +// ASCII (U+0020–U+007E), length ≤ 32. +// +// The ASCII restriction matches the paymentidentifier.id convention and keeps +// len() semantics identical across TS / Python / Go. +// +// Mirrors isValidServiceName (TypeScript) and _is_valid_service_name (Python). +// All three implementations must stay in sync. +func isValidServiceName(s string) bool { + if s == "" { + return false + } + if len(s) > maxServiceNameLen { + return false + } + if containsControlChar(s) { + return false + } + if !printableASCIIRegex.MatchString(s) { + return false + } + return true +} + +// sanitizeTags sanitizes a tags array. Drops entries that are not non-empty +// printable-ASCII strings of at most 32 characters, then truncates to the +// first 5 valid entries. Returns nil when nothing survives so the field can +// be omitted from the catalog. +// +// The ASCII restriction matches the paymentidentifier.id convention and keeps +// len() semantics identical across TS / Python / Go. +// +// Mirrors sanitizeTags (TypeScript) and _sanitize_tags (Python). +// All three implementations must stay in sync. +func sanitizeTags(tags []string) []string { + if len(tags) == 0 { + return nil + } + out := make([]string, 0, maxTags) + // Case-insensitive dedup: keeps the first occurrence's casing. + // Prevents catalog noise like ["Weather", "weather", "WEATHER"]. + seen := make(map[string]struct{}, maxTags) + for _, t := range tags { + if t == "" || len(t) > maxTagLen { + continue + } + if containsControlChar(t) { + continue + } + if !printableASCIIRegex.MatchString(t) { + continue + } + key := strings.ToLower(t) + if _, dup := seen[key]; dup { + continue + } + seen[key] = struct{}{} + out = append(out, t) + if len(out) == maxTags { + break + } + } + if len(out) == 0 { + return nil + } + return out +} + +// isValidIconUrl checks whether an iconUrl value is structurally safe for the +// bazaar resource.iconUrl field. +// +// Rules (see specs/extensions/bazaar.md "Service Metadata on `resource`"): +// - String of length ≤ 2048 +// - No ASCII control characters +// - Parses as an absolute http:// or https:// URL +// - No userinfo (user@host) +// - Host is IDN-normalized (UTS #46 via idna.Lookup.ToASCII) before checks, +// so confusable full-width / Unicode forms (e.g. "localhost") +// collapse to their ASCII canonical and get caught by the loopback check +// - Host is not an IP literal (v4 or v6), not in the loopback set +// (localhost, localhost.localdomain, ip6-localhost, ip6-loopback) +// - Host is not a decimal IP encoding (e.g. 2130706433 → 127.0.0.1) or +// hex literal (e.g. 0x7f000001) — common SSRF bypass forms +// +// Percent-decoding is applied to the hostname before IDN normalization, and +// IDN normalization runs before the IP / loopback checks (parallel to the +// routeTemplate decoder). +// +// Mirrors isValidIconUrl (TypeScript) and _is_valid_icon_url (Python). +// All three implementations must stay in sync. +func isValidIconUrl(s string) bool { + if s == "" || len(s) > maxIconURLLen { + return false + } + if hasControlChar(s) { + return false + } + parsed, err := url.Parse(s) + if err != nil { + return false + } + if parsed.Scheme != "http" && parsed.Scheme != "https" { + return false + } + if parsed.User != nil { + return false + } + host := parsed.Hostname() + if host == "" { + return false + } + decoded, err := url.PathUnescape(host) + if err != nil { + return false + } + // IDN/full-width normalization: e.g. "localhost" (full-width Latin) + // → "localhost". Without this the loopback alias check would miss + // confusable Unicode hostnames. idna.Lookup is the strict profile; it + // rejects malformed IDN as well as normalizing. + asciiHost, err := idna.Lookup.ToASCII(decoded) + if err != nil { + return false + } + host = strings.ToLower(asciiHost) + if host == "" { + return false + } + if _, isLoopback := loopbackHostnames[host]; isLoopback { + return false + } + if ipv4Regex.MatchString(host) { + return false + } + if net.ParseIP(host) != nil { + // Catches IPv6 literals (url.URL.Hostname() strips the brackets). + return false + } + if strings.Contains(host, ":") { + // Defensive: any colon-bearing host after IPv6 bracket-stripping. + return false + } + if allDigitsRegex.MatchString(host) { + return false + } + if hexLiteralRegex.MatchString(host) { + return false + } + return true +} + +// SanitizedResourceServiceMetadata holds the surviving service metadata fields +// after applying the soft-drop validation rules. Mirrors the +// `SanitizedResourceServiceMetadata` type in TypeScript and the +// `SanitizedResourceServiceMetadata` dataclass in Python. +type SanitizedResourceServiceMetadata struct { + ServiceName string + Tags []string + IconUrl string +} + +// SanitizeResourceServiceMetadata applies the bazaar service-metadata +// validation rules to a resource and returns only the fields that survive. +// Missing or invalid fields are dropped silently (soft-drop semantics — see +// spec). +func SanitizeResourceServiceMetadata(r *x402types.ResourceInfo) SanitizedResourceServiceMetadata { + if r == nil { + return SanitizedResourceServiceMetadata{} + } + out := SanitizedResourceServiceMetadata{} + if isValidServiceName(r.ServiceName) { + out.ServiceName = r.ServiceName + } + out.Tags = sanitizeTags(r.Tags) + if isValidIconUrl(r.IconUrl) { + out.IconUrl = r.IconUrl + } + return out +} + // stripQueryParams removes query parameters and fragments from a URL for cataloging func stripQueryParams(rawURL string) string { parsed, err := url.Parse(rawURL) @@ -364,6 +624,8 @@ func ExtractDiscoveredResourceFromPaymentRequired( var description string var mimeType string var routeTemplate string + var rawInput map[string]interface{} + var serviceMetadata SanitizedResourceServiceMetadata version := versionCheck.X402Version switch version { @@ -379,6 +641,7 @@ func ExtractDiscoveredResourceFromPaymentRequired( resourceURL = paymentRequired.Resource.URL description = paymentRequired.Resource.Description mimeType = paymentRequired.Resource.MimeType + serviceMetadata = SanitizeResourceServiceMetadata(paymentRequired.Resource) } // First check PaymentRequired.extensions for bazaar extension @@ -391,6 +654,11 @@ func ExtractDiscoveredResourceFromPaymentRequired( if v, ok := m["routeTemplate"]; ok { rawTemplate, _ = v.(string) } + if infoMap, ok := m["info"].(map[string]interface{}); ok { + if inputMap, ok := infoMap["input"].(map[string]interface{}); ok { + rawInput = inputMap + } + } } if isValidRouteTemplate(rawTemplate) { routeTemplate = rawTemplate @@ -448,17 +716,12 @@ func ExtractDiscoveredResourceFromPaymentRequired( return nil, nil } - // Extract method from discovery info - method := "UNKNOWN" - switch input := discoveryInfo.Input.(type) { - case types.QueryInput: - method = string(input.Method) - case types.BodyInput: - method = string(input.Method) - } + // Extract method or toolName from discovery info. + // For MCP, recover toolName from raw input if upstream deserialization produced QueryInput. + method, toolName := extractMethodAndToolName(discoveryInfo, rawInput) - if method == "UNKNOWN" { - return nil, fmt.Errorf("failed to extract method from discovery info") + if method == "" && toolName == "" { + return nil, fmt.Errorf("failed to extract method/toolName from discovery info") } normalizedURL := normalizeResourceURL(resourceURL, routeTemplate) @@ -468,12 +731,101 @@ func ExtractDiscoveredResourceFromPaymentRequired( Description: description, MimeType: mimeType, Method: method, + ToolName: toolName, X402Version: version, DiscoveryInfo: discoveryInfo, RouteTemplate: routeTemplate, + ServiceName: serviceMetadata.ServiceName, + Tags: serviceMetadata.Tags, + IconUrl: serviceMetadata.IconUrl, }, nil } +func extractMethodAndToolName( + discoveryInfo *types.DiscoveryInfo, + rawInput map[string]interface{}, +) (string, string) { + if discoveryInfo == nil { + return "", "" + } + + if rawInputLooksLikeMCP(rawInput) { + mcpInput, ok := discoveryInfo.Input.(types.McpInput) + if !ok { + mcpInput = types.McpInput{} + } + mcpInput = mergeRawMCPInput(rawInput, mcpInput) + discoveryInfo.Input = mcpInput + return "", strings.TrimSpace(mcpInput.ToolName) + } + + switch input := discoveryInfo.Input.(type) { + case types.QueryInput: + return string(input.Method), "" + case types.BodyInput: + return string(input.Method), "" + case types.McpInput: + normalized := mergeRawMCPInput(rawInput, input) + discoveryInfo.Input = normalized + return "", strings.TrimSpace(normalized.ToolName) + default: + return "", "" + } +} + +func rawInputLooksLikeMCP(rawInput map[string]interface{}) bool { + if len(rawInput) == 0 { + return false + } + if strings.EqualFold(rawString(rawInput, "type"), "mcp") { + return true + } + return rawString(rawInput, "toolName") != "" +} + +func mergeRawMCPInput(rawInput map[string]interface{}, input types.McpInput) types.McpInput { + if strings.TrimSpace(input.Type) == "" { + input.Type = "mcp" + } + if strings.TrimSpace(input.ToolName) == "" { + input.ToolName = rawString(rawInput, "toolName") + } + if strings.TrimSpace(string(input.Transport)) == "" { + if transport := rawString(rawInput, "transport"); transport != "" { + input.Transport = types.McpTransport(transport) + } + } + if input.Description == "" { + input.Description = rawString(rawInput, "description") + } + if input.InputSchema == nil { + if schema, ok := rawInput["inputSchema"]; ok { + input.InputSchema = schema + } + } + if input.Example == nil { + if example, ok := rawInput["example"]; ok { + input.Example = example + } + } + return input +} + +func rawString(raw map[string]interface{}, key string) string { + if len(raw) == 0 { + return "" + } + value, ok := raw[key] + if !ok { + return "" + } + s, ok := value.(string) + if !ok { + return "" + } + return strings.TrimSpace(s) +} + // ExtractDiscoveryInfoFromExtension extracts discovery info from a v2 extension directly // // This is a lower-level function for when you already have the extension object. diff --git a/go/extensions/bazaar/facilitator_client.go b/go/extensions/bazaar/facilitator_client.go index 90be3b9ab6..6c8314ec2a 100644 --- a/go/extensions/bazaar/facilitator_client.go +++ b/go/extensions/bazaar/facilitator_client.go @@ -9,7 +9,7 @@ import ( "net/url" "strconv" - x402http "github.com/coinbase/x402/go/http" + x402http "github.com/x402-foundation/x402/go/http" ) // ListDiscoveryResourcesParams contains optional filtering and pagination parameters @@ -18,6 +18,18 @@ type ListDiscoveryResourcesParams struct { // Type filters by protocol type (e.g., "http", "mcp"). Type string + // PayTo filters by payment recipient address. + PayTo string + + // Scheme filters by payment scheme (e.g., "exact"). + Scheme string + + // Network filters by payment network (e.g., "eip155:8453"). + Network string + + // Extensions filters by extension key present on the discovered resource. + Extensions string + // Limit is the number of discovered x402 resources to return per page. Limit int @@ -25,6 +37,33 @@ type ListDiscoveryResourcesParams struct { Offset int } +// SearchDiscoveryResourcesParams contains parameters for searching discovery resources. +type SearchDiscoveryResourcesParams struct { + // Query is the natural-language search query (required). + Query string + + // Type filters by protocol type (e.g., "http", "mcp"). + Type string + + // PayTo filters by payment recipient address. + PayTo string + + // Scheme filters by payment scheme (e.g., "exact"). + Scheme string + + // Network filters by payment network (e.g., "eip155:8453"). + Network string + + // Extensions filters by extension key present on the discovered resource. + Extensions string + + // Limit is an advisory maximum number of results. The server may return fewer or ignore this. + Limit int + + // Cursor is an advisory continuation token from a previous response. The server may ignore this. + Cursor string +} + // DiscoveryResource represents a discovered x402 resource from the bazaar. type DiscoveryResource struct { // Resource is the URL or identifier of the discovered resource. @@ -42,8 +81,8 @@ type DiscoveryResource struct { // LastUpdated is an ISO 8601 timestamp of when the resource was last updated. LastUpdated string `json:"lastUpdated"` - // Metadata contains additional metadata about the resource. - Metadata map[string]any `json:"metadata,omitempty"` + // Extensions contains additional extension payloads for this discovered resource. + Extensions map[string]any `json:"extensions,omitempty"` } // Pagination contains pagination information for a discovery resources response. @@ -70,10 +109,34 @@ type DiscoveryResourcesResponse struct { Pagination Pagination `json:"pagination"` } +// SearchPagination describes pagination details for a paginated search response. +type SearchPagination struct { + // Limit is the number of results in this page. + Limit int `json:"limit"` + + // Cursor is a continuation token for the next page; may be nil. + Cursor *string `json:"cursor"` +} + +// SearchDiscoveryResourcesResponse is the response from searching discovery resources. +type SearchDiscoveryResourcesResponse struct { + // X402Version is the x402 protocol version of this response. + X402Version int `json:"x402Version"` + + // Resources is the list of matching discovered resources. + Resources []DiscoveryResource `json:"resources"` + + // PartialResults indicates additional matches were truncated by facilitator. + PartialResults bool `json:"partialResults,omitempty"` + + // Pagination contains optional pagination details for paginated responses. + Pagination *SearchPagination `json:"pagination,omitempty"` +} + // BazaarFacilitatorClient wraps an HTTPFacilitatorClient with bazaar discovery // query functionality. It preserves all original facilitator client capabilities -// (Verify, Settle, GetSupported) and adds the ability to list discovered x402 -// resources from the facilitator's bazaar. +// (Verify, Settle, GetSupported) and adds the ability to list and search discovered +// x402 resources from the facilitator's bazaar. type BazaarFacilitatorClient struct { *x402http.HTTPFacilitatorClient } @@ -87,6 +150,9 @@ type BazaarFacilitatorClient struct { // Type: "http", // Limit: 20, // }) +// results, err := client.SearchDiscoveryResources(ctx, &bazaar.SearchDiscoveryResourcesParams{ +// Query: "weather APIs", +// }) func WithBazaar(client *x402http.HTTPFacilitatorClient) *BazaarFacilitatorClient { return &BazaarFacilitatorClient{HTTPFacilitatorClient: client} } @@ -120,7 +186,7 @@ func (c *BazaarFacilitatorClient) ListDiscoveryResources( if err != nil { return nil, fmt.Errorf("failed to get auth headers: %w", err) } - for k, v := range authHeaders.Discovery { + for k, v := range authHeaders.Bazaar { req.Header.Set(k, v) } } @@ -152,6 +218,65 @@ func (c *BazaarFacilitatorClient) ListDiscoveryResources( return &result, nil } +// SearchDiscoveryResources queries the facilitator's /discovery/search endpoint +// to search x402 discovery resources from the bazaar using a natural-language query. +// +// Pagination is optional: facilitators may ignore Limit/Cursor in params, or include +// response.pagination when pagination is used. +func (c *BazaarFacilitatorClient) SearchDiscoveryResources( + ctx context.Context, + params *SearchDiscoveryResourcesParams, +) (*SearchDiscoveryResourcesResponse, error) { + if params == nil || params.Query == "" { + return nil, fmt.Errorf("search query is required") + } + + endpoint, err := c.buildSearchURL(params) + if err != nil { + return nil, fmt.Errorf("failed to build search URL: %w", err) + } + + req, err := http.NewRequestWithContext(ctx, "GET", endpoint, nil) + if err != nil { + return nil, fmt.Errorf("failed to create search request: %w", err) + } + + req.Header.Set("Content-Type", "application/json") + + authProvider := c.GetAuthProvider() + if authProvider != nil { + authHeaders, err := authProvider.GetAuthHeaders(ctx) + if err != nil { + return nil, fmt.Errorf("failed to get auth headers: %w", err) + } + for k, v := range authHeaders.Bazaar { + req.Header.Set(k, v) + } + } + + resp, err := c.HTTPClient().Do(req) + if err != nil { + return nil, fmt.Errorf("search request failed: %w", err) + } + defer resp.Body.Close() + + body, err := io.ReadAll(resp.Body) + if err != nil { + return nil, fmt.Errorf("failed to read response body: %w", err) + } + + if resp.StatusCode != http.StatusOK { + return nil, fmt.Errorf("facilitator searchDiscoveryResources failed (%d): %s", resp.StatusCode, string(body)) + } + + var result SearchDiscoveryResourcesResponse + if err := json.Unmarshal(body, &result); err != nil { + return nil, fmt.Errorf("failed to decode search response: %w", err) + } + + return &result, nil +} + // buildDiscoveryURL constructs the full /discovery/resources URL with query parameters. func (c *BazaarFacilitatorClient) buildDiscoveryURL(params *ListDiscoveryResourcesParams) (string, error) { base := c.URL() + "/discovery/resources" @@ -169,6 +294,18 @@ func (c *BazaarFacilitatorClient) buildDiscoveryURL(params *ListDiscoveryResourc if params.Type != "" { q.Set("type", params.Type) } + if params.PayTo != "" { + q.Set("payTo", params.PayTo) + } + if params.Scheme != "" { + q.Set("scheme", params.Scheme) + } + if params.Network != "" { + q.Set("network", params.Network) + } + if params.Extensions != "" { + q.Set("extensions", params.Extensions) + } if params.Limit > 0 { q.Set("limit", strconv.Itoa(params.Limit)) } @@ -179,3 +316,40 @@ func (c *BazaarFacilitatorClient) buildDiscoveryURL(params *ListDiscoveryResourc u.RawQuery = q.Encode() return u.String(), nil } + +// buildSearchURL constructs the full /discovery/search URL with query parameters. +func (c *BazaarFacilitatorClient) buildSearchURL(params *SearchDiscoveryResourcesParams) (string, error) { + base := c.URL() + "/discovery/search" + + u, err := url.Parse(base) + if err != nil { + return "", err + } + + q := u.Query() + q.Set("query", params.Query) + if params.Type != "" { + q.Set("type", params.Type) + } + if params.PayTo != "" { + q.Set("payTo", params.PayTo) + } + if params.Scheme != "" { + q.Set("scheme", params.Scheme) + } + if params.Network != "" { + q.Set("network", params.Network) + } + if params.Extensions != "" { + q.Set("extensions", params.Extensions) + } + if params.Limit > 0 { + q.Set("limit", strconv.Itoa(params.Limit)) + } + if params.Cursor != "" { + q.Set("cursor", params.Cursor) + } + + u.RawQuery = q.Encode() + return u.String(), nil +} diff --git a/go/extensions/bazaar/facilitator_client_test.go b/go/extensions/bazaar/facilitator_client_test.go index c23ec4308b..a77c4e63ed 100644 --- a/go/extensions/bazaar/facilitator_client_test.go +++ b/go/extensions/bazaar/facilitator_client_test.go @@ -7,7 +7,7 @@ import ( "net/http/httptest" "testing" - x402http "github.com/coinbase/x402/go/http" + x402http "github.com/x402-foundation/x402/go/http" ) // testAuthProvider is a test helper that returns fixed auth headers. @@ -56,7 +56,7 @@ func TestListDiscoveryResources_Success(t *testing.T) { X402Version: 2, Accepts: []json.RawMessage{json.RawMessage(`{"scheme":"exact","network":"eip155:1"}`)}, LastUpdated: "2026-03-01T00:00:00Z", - Metadata: map[string]any{"category": "data"}, + Extensions: map[string]any{"bazaar": map[string]any{"category": "data"}}, }, }, Pagination: Pagination{ @@ -109,8 +109,9 @@ func TestListDiscoveryResources_Success(t *testing.T) { if result.Items[0].LastUpdated != "2026-03-01T00:00:00Z" { t.Errorf("Expected lastUpdated 2026-03-01T00:00:00Z, got %s", result.Items[0].LastUpdated) } - if result.Items[0].Metadata["category"] != "data" { - t.Errorf("Expected metadata category=data, got %v", result.Items[0].Metadata["category"]) + bazaarExt, ok := result.Items[0].Extensions["bazaar"].(map[string]any) + if !ok || bazaarExt["category"] != "data" { + t.Errorf("Expected extensions.bazaar.category=data, got %v", result.Items[0].Extensions) } if result.Pagination.Limit != 20 { t.Errorf("Expected pagination limit 20, got %d", result.Pagination.Limit) @@ -129,6 +130,18 @@ func TestListDiscoveryResources_WithParams(t *testing.T) { if query.Get("type") != "http" { t.Errorf("Expected type=http, got %s", query.Get("type")) } + if query.Get("payTo") != "0x1234567890123456789012345678901234567890" { + t.Errorf("Expected payTo filter, got %s", query.Get("payTo")) + } + if query.Get("scheme") != "exact" { + t.Errorf("Expected scheme=exact, got %s", query.Get("scheme")) + } + if query.Get("network") != "eip155:8453" { + t.Errorf("Expected network=eip155:8453, got %s", query.Get("network")) + } + if query.Get("extensions") != "bazaar" { + t.Errorf("Expected extensions=bazaar, got %s", query.Get("extensions")) + } if query.Get("limit") != "10" { t.Errorf("Expected limit=10, got %s", query.Get("limit")) } @@ -150,9 +163,13 @@ func TestListDiscoveryResources_WithParams(t *testing.T) { })) result, err := client.ListDiscoveryResources(ctx, &ListDiscoveryResourcesParams{ - Type: "http", - Limit: 10, - Offset: 5, + Type: "http", + PayTo: "0x1234567890123456789012345678901234567890", + Scheme: "exact", + Network: "eip155:8453", + Extensions: "bazaar", + Limit: 10, + Offset: 5, }) if err != nil { t.Fatalf("Unexpected error: %v", err) @@ -322,7 +339,7 @@ func TestListDiscoveryResources_WithAuthHeaders(t *testing.T) { authProvider := &testAuthProvider{ headers: x402http.AuthHeaders{ - Discovery: map[string]string{ + Bazaar: map[string]string{ "Authorization": "Bearer test-token", "X-Api-Key": "my-key", }, @@ -489,3 +506,230 @@ func TestListDiscoveryResources_ConnectionError(t *testing.T) { t.Fatal("Expected error for connection failure") } } + +func TestSearchDiscoveryResources_Success(t *testing.T) { + ctx := context.Background() + + cursor := "eyJwYWdlIjoyfQ==" + expectedResponse := SearchDiscoveryResourcesResponse{ + X402Version: 2, + Resources: []DiscoveryResource{ + { + Resource: "https://api.example.com/weather", + Type: "http", + X402Version: 2, + Accepts: []json.RawMessage{json.RawMessage(`{"scheme":"exact","network":"eip155:1"}`)}, + LastUpdated: "2026-03-01T00:00:00Z", + }, + }, + Pagination: &SearchPagination{Limit: 10, Cursor: &cursor}, + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/discovery/search" { + t.Errorf("Expected path /discovery/search, got %s", r.URL.Path) + } + if r.Method != "GET" { + t.Errorf("Expected GET method, got %s", r.Method) + } + if r.URL.Query().Get("query") != "weather APIs" { + t.Errorf("Expected query=weather APIs, got %s", r.URL.Query().Get("query")) + } + + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(expectedResponse) + })) + defer server.Close() + + client := WithBazaar(x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ + URL: server.URL, + })) + + result, err := client.SearchDiscoveryResources(ctx, &SearchDiscoveryResourcesParams{ + Query: "weather APIs", + Limit: 10, + }) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if result.X402Version != 2 { + t.Errorf("Expected x402Version 2, got %d", result.X402Version) + } + if len(result.Resources) != 1 { + t.Fatalf("Expected 1 resource, got %d", len(result.Resources)) + } + if result.Resources[0].Resource != "https://api.example.com/weather" { + t.Errorf("Expected resource https://api.example.com/weather, got %s", result.Resources[0].Resource) + } + if result.Pagination == nil { + t.Fatal("Expected pagination to be present") + } + if result.Pagination.Limit != 10 { + t.Errorf("Expected pagination.limit 10, got %d", result.Pagination.Limit) + } + if result.Pagination.Cursor == nil || *result.Pagination.Cursor != cursor { + t.Errorf("Expected pagination.cursor %q, got %v", cursor, result.Pagination.Cursor) + } +} + +func TestSearchDiscoveryResources_NoPagination(t *testing.T) { + ctx := context.Background() + + expectedResponse := SearchDiscoveryResourcesResponse{ + X402Version: 2, + Resources: []DiscoveryResource{}, + } + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(expectedResponse) + })) + defer server.Close() + + client := WithBazaar(x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ + URL: server.URL, + })) + + result, err := client.SearchDiscoveryResources(ctx, &SearchDiscoveryResourcesParams{ + Query: "mcp tools", + }) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if result.Pagination != nil { + t.Errorf("Expected nil pagination, got %v", result.Pagination) + } +} + +func TestSearchDiscoveryResources_WithTypeFilter(t *testing.T) { + ctx := context.Background() + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + query := r.URL.Query() + if query.Get("query") != "financial" { + t.Errorf("Expected query=financial, got %s", query.Get("query")) + } + if query.Get("type") != "http" { + t.Errorf("Expected type=http, got %s", query.Get("type")) + } + if query.Get("payTo") != "0x1234567890123456789012345678901234567890" { + t.Errorf("Expected payTo filter, got %s", query.Get("payTo")) + } + if query.Get("scheme") != "exact" { + t.Errorf("Expected scheme=exact, got %s", query.Get("scheme")) + } + if query.Get("network") != "eip155:8453" { + t.Errorf("Expected network=eip155:8453, got %s", query.Get("network")) + } + if query.Get("extensions") != "bazaar" { + t.Errorf("Expected extensions=bazaar, got %s", query.Get("extensions")) + } + + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(SearchDiscoveryResourcesResponse{ + X402Version: 2, + Resources: []DiscoveryResource{}, + }) + })) + defer server.Close() + + client := WithBazaar(x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ + URL: server.URL, + })) + + _, err := client.SearchDiscoveryResources(ctx, &SearchDiscoveryResourcesParams{ + Query: "financial", + Type: "http", + PayTo: "0x1234567890123456789012345678901234567890", + Scheme: "exact", + Network: "eip155:8453", + Extensions: "bazaar", + }) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } +} + +func TestSearchDiscoveryResources_RequiresQuery(t *testing.T) { + ctx := context.Background() + + client := WithBazaar(x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ + URL: "http://localhost:9999", + })) + + _, err := client.SearchDiscoveryResources(ctx, &SearchDiscoveryResourcesParams{}) + if err == nil { + t.Fatal("Expected error for missing query") + } + + _, err = client.SearchDiscoveryResources(ctx, nil) + if err == nil { + t.Fatal("Expected error for nil params") + } +} + +func TestSearchDiscoveryResources_ErrorResponse(t *testing.T) { + ctx := context.Background() + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + _, _ = w.Write([]byte("internal server error")) + })) + defer server.Close() + + client := WithBazaar(x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ + URL: server.URL, + })) + + _, err := client.SearchDiscoveryResources(ctx, &SearchDiscoveryResourcesParams{ + Query: "test", + }) + if err == nil { + t.Fatal("Expected error for 500 response") + } + + expected := "facilitator searchDiscoveryResources failed (500): internal server error" + if err.Error() != expected { + t.Errorf("Expected error message %q, got %q", expected, err.Error()) + } +} + +func TestSearchDiscoveryResources_WithAuthHeaders(t *testing.T) { + ctx := context.Background() + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + auth := r.Header.Get("Authorization") + if auth != "Bearer test-token" { + t.Errorf("Expected Authorization header 'Bearer test-token', got %q", auth) + } + + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(SearchDiscoveryResourcesResponse{ + X402Version: 2, + Resources: []DiscoveryResource{}, + }) + })) + defer server.Close() + + authProvider := &testAuthProvider{ + headers: x402http.AuthHeaders{ + Bazaar: map[string]string{ + "Authorization": "Bearer test-token", + }, + }, + } + + client := WithBazaar(x402http.NewHTTPFacilitatorClient(&x402http.FacilitatorConfig{ + URL: server.URL, + AuthProvider: authProvider, + })) + + _, err := client.SearchDiscoveryResources(ctx, &SearchDiscoveryResourcesParams{ + Query: "test", + }) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } +} diff --git a/go/extensions/bazaar/facilitator_test.go b/go/extensions/bazaar/facilitator_test.go index d7a8155685..ef15293300 100644 --- a/go/extensions/bazaar/facilitator_test.go +++ b/go/extensions/bazaar/facilitator_test.go @@ -4,9 +4,12 @@ package bazaar // Uses package bazaar (not bazaar_test) to access unexported functions. import ( + "strings" "testing" "github.com/stretchr/testify/assert" + "github.com/x402-foundation/x402/go/extensions/types" + x402types "github.com/x402-foundation/x402/go/types" ) func TestIsValidRouteTemplate(t *testing.T) { @@ -86,6 +89,52 @@ func TestExtractPathParams(t *testing.T) { }) } +func TestRawString(t *testing.T) { + t.Run("returns empty string for nil map", func(t *testing.T) { + assert.Equal(t, "", rawString(nil, "key")) + }) + + t.Run("returns empty string for empty map", func(t *testing.T) { + assert.Equal(t, "", rawString(map[string]interface{}{}, "key")) + }) + + t.Run("returns empty string when key is absent", func(t *testing.T) { + assert.Equal(t, "", rawString(map[string]interface{}{"other": "val"}, "key")) + }) + + t.Run("returns empty string when value is not a string", func(t *testing.T) { + assert.Equal(t, "", rawString(map[string]interface{}{"key": 42}, "key")) + assert.Equal(t, "", rawString(map[string]interface{}{"key": true}, "key")) + assert.Equal(t, "", rawString(map[string]interface{}{"key": nil}, "key")) + }) + + t.Run("returns trimmed string value", func(t *testing.T) { + assert.Equal(t, "mcp", rawString(map[string]interface{}{"type": " mcp "}, "type")) + }) +} + +func TestExtractMethodAndToolName(t *testing.T) { + t.Run("returns empty strings when discoveryInfo is nil", func(t *testing.T) { + method, toolName := extractMethodAndToolName(nil, nil) + assert.Equal(t, "", method) + assert.Equal(t, "", toolName) + }) + + t.Run("extracts toolName from McpInput via type switch when rawInput has no MCP signals", func(t *testing.T) { + // rawInput has no type="mcp" and no toolName, so rawInputLooksLikeMCP returns false. + // discoveryInfo.Input is McpInput so the type switch McpInput case fires. + info := &types.DiscoveryInfo{ + Input: types.McpInput{ + Type: "mcp", + ToolName: "switch_case_tool", + }, + } + method, toolName := extractMethodAndToolName(info, map[string]interface{}{}) + assert.Equal(t, "", method) + assert.Equal(t, "switch_case_tool", toolName) + }) +} + func TestNormalizeResourceURL(t *testing.T) { t.Run("uses routeTemplate as canonical path when present", func(t *testing.T) { result := normalizeResourceURL("https://api.example.com/users/123?foo=bar#frag", "/users/:userId") @@ -106,3 +155,171 @@ func TestNormalizeResourceURL(t *testing.T) { }) } + +func TestIsValidServiceName(t *testing.T) { + t.Run("accepts strings up to 32 chars", func(t *testing.T) { + assert.True(t, isValidServiceName("Example Weather")) + assert.True(t, isValidServiceName("a")) + assert.True(t, isValidServiceName(strings.Repeat("a", 32))) + }) + + t.Run("rejects empty and over-cap strings", func(t *testing.T) { + assert.False(t, isValidServiceName("")) + assert.False(t, isValidServiceName(strings.Repeat("a", 33))) + }) + + t.Run("rejects non-ASCII characters", func(t *testing.T) { + // Multi-byte chars in UTF-8 — would otherwise diverge across SDKs + // (UTF-16 code units in TS, code points in Python, bytes here). + assert.False(t, isValidServiceName("Café Service")) + assert.False(t, isValidServiceName("東京 Weather")) + assert.False(t, isValidServiceName("🚀 Service")) + }) + + t.Run("rejects ASCII control characters", func(t *testing.T) { + assert.False(t, isValidServiceName("Service\x00")) + assert.False(t, isValidServiceName("Line\nBreak")) + assert.False(t, isValidServiceName("Tab\there")) + }) + + t.Run("accepts printable ASCII with spaces and punctuation", func(t *testing.T) { + assert.True(t, isValidServiceName("Example Weather")) + assert.True(t, isValidServiceName("AT&T")) + assert.True(t, isValidServiceName("Coinbase, Inc.")) + assert.True(t, isValidServiceName("Service v2.0!")) + }) +} + +func TestSanitizeTags(t *testing.T) { + t.Run("returns nil for nil and empty input", func(t *testing.T) { + assert.Nil(t, sanitizeTags(nil)) + assert.Nil(t, sanitizeTags([]string{})) + }) + + t.Run("drops empty and over-cap entries", func(t *testing.T) { + got := sanitizeTags([]string{"weather", "", strings.Repeat("a", 33), "forecast"}) + assert.Equal(t, []string{"weather", "forecast"}, got) + }) + + t.Run("truncates to 5 entries", func(t *testing.T) { + got := sanitizeTags([]string{"a", "b", "c", "d", "e", "f", "g"}) + assert.Equal(t, []string{"a", "b", "c", "d", "e"}, got) + }) + + t.Run("returns nil when nothing survives", func(t *testing.T) { + assert.Nil(t, sanitizeTags([]string{"", strings.Repeat("a", 33)})) + }) + + t.Run("drops non-ASCII tags but keeps ASCII siblings", func(t *testing.T) { + got := sanitizeTags([]string{"weather", "café", "東京", "🚀", "forecast"}) + assert.Equal(t, []string{"weather", "forecast"}, got) + }) + + t.Run("dedupes case-insensitively keeping first occurrence", func(t *testing.T) { + got := sanitizeTags([]string{"Weather", "weather", "WEATHER", "forecast"}) + assert.Equal(t, []string{"Weather", "forecast"}, got) + }) +} + +func TestIsValidIconUrl(t *testing.T) { + t.Run("accepts plain http and https urls", func(t *testing.T) { + assert.True(t, isValidIconUrl("https://api.example.com/icon.png")) + assert.True(t, isValidIconUrl("http://api.example.com/icon")) + }) + + t.Run("rejects empty and over-cap strings", func(t *testing.T) { + assert.False(t, isValidIconUrl("")) + assert.False(t, isValidIconUrl("https://example.com/"+strings.Repeat("a", 2048))) + }) + + t.Run("rejects non-http schemes", func(t *testing.T) { + assert.False(t, isValidIconUrl("data:image/png;base64,iVBOR")) + assert.False(t, isValidIconUrl("file:///etc/passwd")) + assert.False(t, isValidIconUrl("javascript:alert(1)")) + assert.False(t, isValidIconUrl("ftp://example.com/icon.png")) + }) + + t.Run("rejects userinfo", func(t *testing.T) { + assert.False(t, isValidIconUrl("https://user@example.com/icon.png")) + assert.False(t, isValidIconUrl("https://user:pass@example.com/icon.png")) + }) + + t.Run("rejects IP literals", func(t *testing.T) { + assert.False(t, isValidIconUrl("http://10.0.0.1/icon.png")) + assert.False(t, isValidIconUrl("http://127.0.0.1/icon.png")) + assert.False(t, isValidIconUrl("http://[::1]/icon.png")) + assert.False(t, isValidIconUrl("http://[2001:db8::1]/icon.png")) + }) + + t.Run("rejects decimal-encoded and short-form IP hosts", func(t *testing.T) { + // 2130706433 == 127.0.0.1; 0 expands to 0.0.0.0 on Linux. + assert.False(t, isValidIconUrl("http://2130706433/icon.png")) + assert.False(t, isValidIconUrl("http://0/icon.png")) + assert.False(t, isValidIconUrl("http://3232235521/icon.png")) + }) + + t.Run("rejects hex-encoded IP hosts", func(t *testing.T) { + // 0x7f000001 == 127.0.0.1. + assert.False(t, isValidIconUrl("http://0x7f000001/icon.png")) + assert.False(t, isValidIconUrl("http://0X7F000001/icon.png")) + }) + + t.Run("rejects localhost", func(t *testing.T) { + assert.False(t, isValidIconUrl("http://localhost/icon.png")) + assert.False(t, isValidIconUrl("http://LOCALHOST/icon.png")) + }) + + t.Run("rejects loopback aliases from /etc/hosts", func(t *testing.T) { + assert.False(t, isValidIconUrl("http://localhost.localdomain/icon.png")) + assert.False(t, isValidIconUrl("http://ip6-localhost/icon.png")) + assert.False(t, isValidIconUrl("http://ip6-loopback/icon.png")) + }) + + t.Run("rejects IDN / full-width localhost confusables", func(t *testing.T) { + // Full-width Latin "localhost" normalizes to "localhost" via UTS #46. + assert.False(t, isValidIconUrl("http://localhost/icon.png")) + }) + + t.Run("rejects control characters", func(t *testing.T) { + assert.False(t, isValidIconUrl("https://example.com/\x00icon.png")) + assert.False(t, isValidIconUrl("https://example.com/icon\n.png")) + assert.False(t, isValidIconUrl("https://example.com/icon\x7f.png")) + }) + + t.Run("rejects relative paths", func(t *testing.T) { + assert.False(t, isValidIconUrl("/icon.png")) + assert.False(t, isValidIconUrl("icon.png")) + }) +} + +func TestSanitizeResourceServiceMetadata(t *testing.T) { + t.Run("preserves all valid fields", func(t *testing.T) { + out := SanitizeResourceServiceMetadata(&x402types.ResourceInfo{ + URL: "https://api.example.com/x", + ServiceName: "Example Weather", + Tags: []string{"weather", "forecast"}, + IconUrl: "https://api.example.com/icon.png", + }) + assert.Equal(t, "Example Weather", out.ServiceName) + assert.Equal(t, []string{"weather", "forecast"}, out.Tags) + assert.Equal(t, "https://api.example.com/icon.png", out.IconUrl) + }) + + t.Run("soft-drops only invalid fields", func(t *testing.T) { + out := SanitizeResourceServiceMetadata(&x402types.ResourceInfo{ + ServiceName: strings.Repeat("a", 33), + Tags: []string{"weather", "forecast"}, + IconUrl: "data:image/png;base64,iVBOR", + }) + assert.Equal(t, "", out.ServiceName) + assert.Equal(t, []string{"weather", "forecast"}, out.Tags) + assert.Equal(t, "", out.IconUrl) + }) + + t.Run("nil input returns empty struct", func(t *testing.T) { + out := SanitizeResourceServiceMetadata(nil) + assert.Equal(t, "", out.ServiceName) + assert.Nil(t, out.Tags) + assert.Equal(t, "", out.IconUrl) + }) +} diff --git a/go/extensions/bazaar/resource_service.go b/go/extensions/bazaar/resource_service.go index f56089c051..a15a3d7ee5 100644 --- a/go/extensions/bazaar/resource_service.go +++ b/go/extensions/bazaar/resource_service.go @@ -2,8 +2,9 @@ package bazaar import ( "fmt" + "strings" - "github.com/coinbase/x402/go/extensions/types" + "github.com/x402-foundation/x402/go/extensions/types" ) // DeclareDiscoveryExtension creates a discovery extension for any HTTP method @@ -97,6 +98,152 @@ func DeclareDiscoveryExtension( return types.DiscoveryExtension{}, fmt.Errorf("unsupported HTTP method: %s", methodStr) } +// DeclareMcpDiscoveryExtension creates a discovery extension for an MCP tool. +// +// This function helps servers declare how their MCP tool should be discovered, +// including the tool name, input schema, and optional transport/description/example. +// +// Args: +// - config: Configuration for the MCP discovery extension +// +// Returns: +// - DiscoveryExtension with both info and schema +// - Error if required fields are missing +// +// Example: +// +// extension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ +// ToolName: "weather_lookup", +// Description: "Look up weather for a city", +// Transport: bazaar.TransportStreamableHTTP, +// InputSchema: map[string]interface{}{ +// "type": "object", +// "properties": map[string]interface{}{ +// "city": map[string]interface{}{"type": "string"}, +// }, +// "required": []string{"city"}, +// }, +// Example: map[string]interface{}{"city": "San Francisco"}, +// }) +func DeclareMcpDiscoveryExtension(config types.DeclareMcpDiscoveryConfig) (types.DiscoveryExtension, error) { + if strings.TrimSpace(config.ToolName) == "" { + return types.DiscoveryExtension{}, fmt.Errorf("toolName is required for MCP discovery extension") + } + if config.InputSchema == nil { + return types.DiscoveryExtension{}, fmt.Errorf("inputSchema is required for MCP discovery extension") + } + + // Build the info + mcpInput := types.McpInput{ + Type: "mcp", + ToolName: config.ToolName, + InputSchema: config.InputSchema, + } + if config.Description != "" { + mcpInput.Description = config.Description + } + if config.Transport != "" { + mcpInput.Transport = config.Transport + } + if config.Example != nil { + mcpInput.Example = config.Example + } + + mcpInfo := types.McpDiscoveryInfo{ + Input: mcpInput, + } + + if config.Output != nil && config.Output.Example != nil { + mcpInfo.Output = &types.OutputInfo{ + Type: "json", + Example: config.Output.Example, + } + } + + // Build the schema + inputSchemaProperties := map[string]interface{}{ + "type": map[string]interface{}{ + "type": "string", + "const": "mcp", + }, + "toolName": map[string]interface{}{ + "type": "string", + }, + "inputSchema": map[string]interface{}{ + "type": "object", + }, + } + inputRequired := []string{"type", "toolName", "inputSchema"} + + if config.Description != "" { + inputSchemaProperties["description"] = map[string]interface{}{ + "type": "string", + } + } + if config.Transport != "" { + transportSchema := map[string]interface{}{ + "type": "string", + } + if config.Transport == TransportStreamableHTTP || config.Transport == TransportSSE { + transportSchema["enum"] = []string{string(config.Transport)} + } + inputSchemaProperties["transport"] = transportSchema + } + if config.Example != nil { + inputSchemaProperties["example"] = map[string]interface{}{ + "type": "object", + } + } + + schemaProperties := map[string]interface{}{ + "input": map[string]interface{}{ + "type": "object", + "properties": inputSchemaProperties, + "required": inputRequired, + "additionalProperties": false, + }, + } + + // Add output schema if provided + if config.Output != nil && config.Output.Example != nil { + outputSchema := map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "type": map[string]interface{}{ + "type": "string", + }, + "example": map[string]interface{}{ + "type": "object", + }, + }, + "required": []string{"type"}, + } + + if config.Output.Schema != nil { + for k, v := range config.Output.Schema { + outputSchema["properties"].(map[string]interface{})["example"].(map[string]interface{})[k] = v + } + } + + schemaProperties["output"] = outputSchema + } + + schema := types.JSONSchema{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": schemaProperties, + "required": []string{"input"}, + } + + return types.DiscoveryExtension{ + Info: types.DiscoveryInfo{ + Input: mcpInfo.Input, + Output: mcpInfo.Output, + }, + Schema: schema, + }, nil +} + // createQueryDiscoveryExtension creates a query discovery extension func createQueryDiscoveryExtension( method types.QueryParamMethods, diff --git a/go/extensions/bazaar/server.go b/go/extensions/bazaar/server.go index 863b808b18..f720ef6d40 100644 --- a/go/extensions/bazaar/server.go +++ b/go/extensions/bazaar/server.go @@ -6,8 +6,8 @@ import ( "strings" "sync" - "github.com/coinbase/x402/go/extensions/types" - "github.com/coinbase/x402/go/http" + "github.com/x402-foundation/x402/go/extensions/types" + "github.com/x402-foundation/x402/go/http" ) // bracketParamRegex matches [paramName] route segments (Next.js style). @@ -140,6 +140,12 @@ func (e *bazaarResourceServerExtension) EnrichDeclaration( return declaration } + // MCP extensions pass through unchanged — they don't need HTTP method narrowing + // or dynamic route extraction. + if _, ok := extension.Info.Input.(types.McpInput); ok { + return declaration + } + method := httpContext.Method if queryInput, ok := extension.Info.Input.(types.QueryInput); ok { diff --git a/go/extensions/bazaar/types.go b/go/extensions/bazaar/types.go index bb14158bca..186d0469bd 100644 --- a/go/extensions/bazaar/types.go +++ b/go/extensions/bazaar/types.go @@ -1,7 +1,7 @@ package bazaar // Re-export types from the shared types package for convenience -import "github.com/coinbase/x402/go/extensions/types" +import "github.com/x402-foundation/x402/go/extensions/types" // Re-export extension identifier var BAZAAR = types.BAZAAR @@ -23,22 +23,33 @@ const ( BodyTypeText = types.BodyTypeText ) +// Re-export MCP transport constants +const ( + TransportStreamableHTTP = types.TransportStreamableHTTP + TransportSSE = types.TransportSSE +) + // Re-export types type ( - QueryParamMethods = types.QueryParamMethods - BodyMethods = types.BodyMethods - BodyType = types.BodyType - QueryDiscoveryInfo = types.QueryDiscoveryInfo - QueryInput = types.QueryInput - BodyDiscoveryInfo = types.BodyDiscoveryInfo - BodyInput = types.BodyInput - OutputInfo = types.OutputInfo - DiscoveryInfo = types.DiscoveryInfo - JSONSchema = types.JSONSchema - QueryDiscoveryExtension = types.QueryDiscoveryExtension - BodyDiscoveryExtension = types.BodyDiscoveryExtension - DiscoveryExtension = types.DiscoveryExtension - OutputConfig = types.OutputConfig + QueryParamMethods = types.QueryParamMethods + BodyMethods = types.BodyMethods + BodyType = types.BodyType + QueryDiscoveryInfo = types.QueryDiscoveryInfo + QueryInput = types.QueryInput + BodyDiscoveryInfo = types.BodyDiscoveryInfo + BodyInput = types.BodyInput + OutputInfo = types.OutputInfo + DiscoveryInfo = types.DiscoveryInfo + JSONSchema = types.JSONSchema + QueryDiscoveryExtension = types.QueryDiscoveryExtension + BodyDiscoveryExtension = types.BodyDiscoveryExtension + DiscoveryExtension = types.DiscoveryExtension + OutputConfig = types.OutputConfig + McpTransport = types.McpTransport + McpInput = types.McpInput + McpDiscoveryInfo = types.McpDiscoveryInfo + McpDiscoveryExtension = types.McpDiscoveryExtension + DeclareMcpDiscoveryConfig = types.DeclareMcpDiscoveryConfig ) // Re-export utility functions diff --git a/go/extensions/eip2612gassponsor/types.go b/go/extensions/eip2612gassponsor/types.go index ed9bc3a513..c8314b360f 100644 --- a/go/extensions/eip2612gassponsor/types.go +++ b/go/extensions/eip2612gassponsor/types.go @@ -5,7 +5,7 @@ // facilitator submits it on-chain via x402Permit2Proxy.settleWithPermit. package eip2612gassponsor -import x402 "github.com/coinbase/x402/go" +import x402 "github.com/x402-foundation/x402/go" // EIP2612GasSponsoring is the extension identifier for the EIP-2612 gas sponsoring extension. var EIP2612GasSponsoring = x402.NewFacilitatorExtension("eip2612GasSponsoring") diff --git a/go/extensions/erc20approvalgassponsor/resolve_signer_test.go b/go/extensions/erc20approvalgassponsor/resolve_signer_test.go index f455a59db5..f7c234ac00 100644 --- a/go/extensions/erc20approvalgassponsor/resolve_signer_test.go +++ b/go/extensions/erc20approvalgassponsor/resolve_signer_test.go @@ -5,7 +5,7 @@ import ( "math/big" "testing" - evm "github.com/coinbase/x402/go/mechanisms/evm" + evm "github.com/x402-foundation/x402/go/mechanisms/evm" ) type mockApprovalSigner struct { diff --git a/go/extensions/erc20approvalgassponsor/types.go b/go/extensions/erc20approvalgassponsor/types.go index a62d049f51..a9aeaa7a95 100644 --- a/go/extensions/erc20approvalgassponsor/types.go +++ b/go/extensions/erc20approvalgassponsor/types.go @@ -9,8 +9,8 @@ package erc20approvalgassponsor import ( "context" - x402 "github.com/coinbase/x402/go" - evm "github.com/coinbase/x402/go/mechanisms/evm" + x402 "github.com/x402-foundation/x402/go" + evm "github.com/x402-foundation/x402/go/mechanisms/evm" ) // ERC20ApprovalGasSponsoring is the extension identifier for the ERC-20 approval gas sponsoring extension. diff --git a/go/extensions/paymentidentifier/facilitator.go b/go/extensions/paymentidentifier/facilitator.go index 0cb33483af..9c036e87ac 100644 --- a/go/extensions/paymentidentifier/facilitator.go +++ b/go/extensions/paymentidentifier/facilitator.go @@ -4,8 +4,8 @@ import ( "encoding/json" "fmt" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) // parseExtension converts an extension interface{} to a PaymentIdentifierExtension. diff --git a/go/extensions/paymentidentifier/paymentidentifier_test.go b/go/extensions/paymentidentifier/paymentidentifier_test.go index f4e6ec1c09..9ad557e1c5 100644 --- a/go/extensions/paymentidentifier/paymentidentifier_test.go +++ b/go/extensions/paymentidentifier/paymentidentifier_test.go @@ -5,11 +5,11 @@ import ( "strings" "testing" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/paymentidentifier" - "github.com/coinbase/x402/go/extensions/types" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/paymentidentifier" + "github.com/x402-foundation/x402/go/extensions/types" ) func TestConstants(t *testing.T) { diff --git a/go/extensions/paymentidentifier/schema.go b/go/extensions/paymentidentifier/schema.go index 607134e953..67dbd37e5f 100644 --- a/go/extensions/paymentidentifier/schema.go +++ b/go/extensions/paymentidentifier/schema.go @@ -1,7 +1,7 @@ package paymentidentifier import ( - "github.com/coinbase/x402/go/extensions/types" + "github.com/x402-foundation/x402/go/extensions/types" ) // PaymentIdentifierSchema returns the JSON Schema for validating payment identifier info. diff --git a/go/extensions/paymentidentifier/types.go b/go/extensions/paymentidentifier/types.go index 32460d6a70..f650140fad 100644 --- a/go/extensions/paymentidentifier/types.go +++ b/go/extensions/paymentidentifier/types.go @@ -1,7 +1,7 @@ package paymentidentifier import ( - "github.com/coinbase/x402/go/extensions/types" + "github.com/x402-foundation/x402/go/extensions/types" ) // Re-export constants and patterns from shared types for convenience diff --git a/go/extensions/types/types.go b/go/extensions/types/types.go index d445732067..2fba53f2bb 100644 --- a/go/extensions/types/types.go +++ b/go/extensions/types/types.go @@ -4,7 +4,7 @@ import ( "encoding/json" "regexp" - x402 "github.com/coinbase/x402/go" + x402 "github.com/x402-foundation/x402/go" ) // BAZAAR is the extension identifier for the Bazaar discovery extension. @@ -92,6 +92,46 @@ type OutputInfo struct { Example interface{} `json:"example,omitempty"` // Example response } +// McpTransport represents the transport protocol for MCP tools +type McpTransport string + +const ( + TransportStreamableHTTP McpTransport = "streamable-http" + TransportSSE McpTransport = "sse" +) + +// McpInput represents input information for MCP tool discovery +type McpInput struct { + Type string `json:"type"` // "mcp" + ToolName string `json:"toolName"` + Description string `json:"description,omitempty"` + Transport McpTransport `json:"transport,omitempty"` + InputSchema interface{} `json:"inputSchema"` + Example interface{} `json:"example,omitempty"` +} + +// McpDiscoveryInfo represents discovery info for MCP tools +type McpDiscoveryInfo struct { + Input McpInput `json:"input"` + Output *OutputInfo `json:"output,omitempty"` +} + +// McpDiscoveryExtension represents a discovery extension for MCP tools +type McpDiscoveryExtension struct { + Info McpDiscoveryInfo `json:"info"` + Schema JSONSchema `json:"schema"` +} + +// DeclareMcpDiscoveryConfig is the configuration for declaring an MCP discovery extension +type DeclareMcpDiscoveryConfig struct { + ToolName string // MCP tool name + Description string // Human-readable description + Transport McpTransport // Transport protocol (streamable-http, sse) + InputSchema interface{} // JSON Schema for the tool's input + Example interface{} // Example input + Output *OutputConfig +} + // DiscoveryInfo is a union type that can be either Query or Body discovery info type DiscoveryInfo struct { Input interface{} `json:"input"` @@ -109,20 +149,28 @@ func (d *DiscoveryInfo) UnmarshalJSON(data []byte) error { return err } - // Try to determine if it's a query or body input by checking for bodyType field - var checkType struct { + // Check the type field first to discriminate between http and mcp inputs + var checkFields struct { + Type string `json:"type"` BodyType *string `json:"bodyType"` } // Intentionally ignore error - we're just probing for field existence - _ = json.Unmarshal(raw.Input, &checkType) + _ = json.Unmarshal(raw.Input, &checkFields) - if checkType.BodyType != nil { + switch { + case checkFields.Type == "mcp": + var mcpInput McpInput + if err := json.Unmarshal(raw.Input, &mcpInput); err != nil { + return err + } + d.Input = mcpInput + case checkFields.BodyType != nil: var bodyInput BodyInput if err := json.Unmarshal(raw.Input, &bodyInput); err != nil { return err } d.Input = bodyInput - } else { + default: var queryInput QueryInput if err := json.Unmarshal(raw.Input, &queryInput); err != nil { return err diff --git a/go/extensions/v1/facilitator.go b/go/extensions/v1/facilitator.go index 185fce7f41..5c9a9a0339 100644 --- a/go/extensions/v1/facilitator.go +++ b/go/extensions/v1/facilitator.go @@ -4,7 +4,7 @@ import ( "encoding/json" "strings" - "github.com/coinbase/x402/go/extensions/types" + "github.com/x402-foundation/x402/go/extensions/types" ) // V1OutputSchema represents the v1 outputSchema structure diff --git a/go/facilitator.go b/go/facilitator.go index fdb5014555..51817be76e 100644 --- a/go/facilitator.go +++ b/go/facilitator.go @@ -6,7 +6,7 @@ import ( "strings" "sync" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // schemeData stores facilitator and its registered networks diff --git a/go/facilitator_hooks_test.go b/go/facilitator_hooks_test.go index 0767a91f52..4c0a9c358b 100644 --- a/go/facilitator_hooks_test.go +++ b/go/facilitator_hooks_test.go @@ -7,7 +7,7 @@ import ( "fmt" "testing" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // Test Facilitator BeforeVerify hook - abort verification diff --git a/go/facilitator_test.go b/go/facilitator_test.go index 16eef3b82c..441d1dfc0a 100644 --- a/go/facilitator_test.go +++ b/go/facilitator_test.go @@ -7,7 +7,7 @@ import ( "fmt" "testing" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // Mock V1 facilitator for testing diff --git a/go/go.mod b/go/go.mod index 7f498071a9..1d7ca88d3e 100644 --- a/go/go.mod +++ b/go/go.mod @@ -1,4 +1,4 @@ -module github.com/coinbase/x402/go +module github.com/x402-foundation/x402/go go 1.24.0 @@ -18,8 +18,8 @@ require ( require github.com/google/uuid v1.6.0 require ( - github.com/google/uuid v1.6.0 github.com/labstack/echo/v4 v4.15.1 + golang.org/x/net v0.48.0 ) require ( @@ -90,7 +90,6 @@ require ( golang.org/x/arch v0.20.0 // indirect golang.org/x/crypto v0.46.0 // indirect golang.org/x/mod v0.30.0 // indirect - golang.org/x/net v0.48.0 // indirect golang.org/x/oauth2 v0.30.0 // indirect golang.org/x/sync v0.19.0 // indirect golang.org/x/sys v0.39.0 // indirect diff --git a/go/http/avm_paywall_template.go b/go/http/avm_paywall_template.go new file mode 100644 index 0000000000..1bf4e7eb1f --- /dev/null +++ b/go/http/avm_paywall_template.go @@ -0,0 +1,5 @@ +// THIS FILE IS AUTO-GENERATED - DO NOT EDIT +package http + +// AVMPaywallTemplate is the pre-built AVM paywall template with inlined CSS and JS +const AVMPaywallTemplate = "\n \n \n Payment Required\n \n
\n \n \n " diff --git a/go/http/client.go b/go/http/client.go index 378c87bd09..eb6302e6ac 100644 --- a/go/http/client.go +++ b/go/http/client.go @@ -10,8 +10,8 @@ import ( "strings" "sync" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) // ============================================================================ @@ -113,26 +113,33 @@ func (c *x402HTTPClient) GetPaymentSettleResponse(headers map[string]string) (*x // HTTP Client Wrapper // ============================================================================ -// WrapHTTPClientWithPayment wraps a standard HTTP client with x402 payment handling -// This allows transparent payment handling for HTTP requests +// WrapHTTPClientWithPayment returns a new *http.Client whose Transport is wrapped +// with x402 payment handling. The input client is NEVER mutated — its Transport, +// Timeout, Jar and CheckRedirect are copied into a fresh *http.Client. Passing +// http.DefaultClient is safe; the returned client is independent and the global +// default remains untouched. func WrapHTTPClientWithPayment(client *http.Client, x402Client *x402HTTPClient) *http.Client { if client == nil { client = http.DefaultClient } - // Wrap the transport with payment handling originalTransport := client.Transport if originalTransport == nil { originalTransport = http.DefaultTransport } - client.Transport = &PaymentRoundTripper{ - Transport: originalTransport, - x402Client: x402Client, - retryCount: &sync.Map{}, + wrapped := &http.Client{ + Transport: &PaymentRoundTripper{ + Transport: originalTransport, + x402Client: x402Client, + retryCount: &sync.Map{}, + }, + CheckRedirect: client.CheckRedirect, + Jar: client.Jar, + Timeout: client.Timeout, } - return client + return wrapped } // PaymentRoundTripper implements http.RoundTripper with x402 payment handling @@ -142,29 +149,34 @@ type PaymentRoundTripper struct { retryCount *sync.Map // Track retry count per request to prevent infinite loops } -// RoundTrip implements http.RoundTripper with V1/V2 version detection +// RoundTrip implements http.RoundTripper with V1/V2 version detection. +// +// V2 flow includes scheme-aware reconciliation: after the payment retry the +// chosen scheme's PaymentResponseHandler (if implemented) and any user-registered +// OnPaymentResponse hooks fire automatically. On a corrective 402 + Recovered=true, +// the transport rebuilds a fresh payload and retries one more time, mirroring the +// TS @x402/fetch wrapper's recovery behavior. User code never has to call +// ProcessSettleResponse manually. func (t *PaymentRoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { // Get or initialize retry count for this request requestID := fmt.Sprintf("%p", req) count, _ := t.retryCount.LoadOrStore(requestID, 0) retries := count.(int) + defer t.retryCount.Delete(requestID) // Prevent infinite retry loops if retries > 1 { - t.retryCount.Delete(requestID) return nil, fmt.Errorf("payment retry limit exceeded") } // Make initial request resp, err := t.Transport.RoundTrip(req) if err != nil { - t.retryCount.Delete(requestID) return nil, err } // If not 402, return as-is if resp.StatusCode != http.StatusPaymentRequired { - t.retryCount.Delete(requestID) return resp, nil } @@ -183,14 +195,12 @@ func (t *PaymentRoundTripper) RoundTrip(req *http.Request) (*http.Response, erro body, err := io.ReadAll(resp.Body) resp.Body.Close() if err != nil { - t.retryCount.Delete(requestID) return nil, fmt.Errorf("failed to read response body: %w", err) } // Detect version from response version, err := detectPaymentRequiredVersion(headers, body) if err != nil { - t.retryCount.Delete(requestID) return nil, fmt.Errorf("failed to detect payment version: %w", err) } @@ -200,90 +210,162 @@ func (t *PaymentRoundTripper) RoundTrip(req *http.Request) (*http.Response, erro ctx = context.Background() } - // Fork based on version - var payloadBytes []byte + // V1: simple build + retry, no hook dispatch (V1 schemes don't expose the hook). if version == 1 { - // V1 flow: body-based PaymentRequired, V1 types - payloadBytes, err = t.handleV1Payment(ctx, body) - if err != nil { - t.retryCount.Delete(requestID) - return nil, err - } - } else { - // V2 flow: header-based PaymentRequired, V2 types - payloadBytes, err = t.handleV2Payment(ctx, headers, body) + payloadBytes, err := t.handleV1Payment(ctx, body) if err != nil { - t.retryCount.Delete(requestID) return nil, err } + return t.sendPaymentRetry(req, ctx, payloadBytes) + } + + // V2: rich build so we can fire OnPaymentResponse with the right payload + requirements. + build, err := t.buildV2Payment(ctx, headers, body) + if err != nil { + return nil, err + } + + newResp, err := t.sendPaymentRetry(req, ctx, build.payloadBytes) + if err != nil { + return nil, err + } + + // Dispatch OnPaymentResponse and, on corrective 402 with Recovered=true, + // retry once more with a freshly built payload (mirrors @x402/fetch recovery). + recovered, err := t.dispatchPaymentResponseHooks(ctx, build, newResp) + if err != nil { + return nil, err + } + if !recovered || newResp.StatusCode != http.StatusPaymentRequired { + return newResp, nil } - // Encode payment header (works for both V1 and V2) + // Recovery succeeded: rebuild payload from refreshed session state and retry. + freshPayload, err := t.x402Client.client.CreatePaymentPayload( + ctx, + build.requirements, + build.paymentRequired.Resource, + build.paymentRequired.Extensions, + ) + if err != nil { + return newResp, nil + } + freshBytes, err := json.Marshal(freshPayload) + if err != nil { + return newResp, nil + } + + // Drain the corrective 402 body so connection can be reused. + _, _ = io.Copy(io.Discard, newResp.Body) + newResp.Body.Close() + + correctiveResp, err := t.sendPaymentRetry(req, ctx, freshBytes) + if err != nil { + return nil, err + } + + // Fire hooks on the corrective response too — but no further recovery, to + // prevent loops. Mirrors @x402/fetch which bounds recovery to one retry. + correctiveBuild := *build + correctiveBuild.paymentPayload = freshPayload + correctiveBuild.payloadBytes = freshBytes + if _, err := t.dispatchPaymentResponseHooks(ctx, &correctiveBuild, correctiveResp); err != nil { + return correctiveResp, nil + } + return correctiveResp, nil +} + +// sendPaymentRetry clones the original request, attaches PAYMENT-SIGNATURE / X-PAYMENT +// headers built from the given payload bytes, replenishes the body, and dispatches. +func (t *PaymentRoundTripper) sendPaymentRetry( + req *http.Request, + ctx context.Context, + payloadBytes []byte, +) (*http.Response, error) { paymentHeaders, err := t.x402Client.EncodePaymentSignatureHeader(payloadBytes) if err != nil { - t.retryCount.Delete(requestID) return nil, fmt.Errorf("failed to encode payment header: %w", err) } - // Create new request with payment header paymentReq := req.Clone(ctx) for k, v := range paymentHeaders { paymentReq.Header.Set(k, v) } - // Replenish body for retry if possible if req.GetBody != nil { body, err := req.GetBody() if err != nil { - t.retryCount.Delete(requestID) return nil, fmt.Errorf("failed to get body for payment retry: %w", err) } paymentReq.Body = body } - // Retry with payment - newResp, err := t.Transport.RoundTrip(paymentReq) - t.retryCount.Delete(requestID) - - return newResp, err + return t.Transport.RoundTrip(paymentReq) } -// handleV1Payment processes V1 PaymentRequired and creates V1 payload -func (t *PaymentRoundTripper) handleV1Payment(ctx context.Context, body []byte) ([]byte, error) { - // Parse V1 PaymentRequired from body - var paymentRequiredV1 types.PaymentRequiredV1 - if err := json.Unmarshal(body, &paymentRequiredV1); err != nil { - return nil, fmt.Errorf("failed to parse V1 payment required: %w", err) +// dispatchPaymentResponseHooks decodes PAYMENT-RESPONSE / PAYMENT-REQUIRED on the +// retry response and fires the scheme + user-registered OnPaymentResponse hooks +// via x402Client.HandlePaymentResponse. Returns whether the hooks signaled recovery. +// +// Header parse errors are non-fatal: hooks simply don't fire when the server +// omits the header. Hook errors propagate so the caller can surface them. +func (t *PaymentRoundTripper) dispatchPaymentResponseHooks( + ctx context.Context, + build *v2PaymentBuild, + resp *http.Response, +) (bool, error) { + prCtx := x402.PaymentResponseContext{ + PaymentPayload: build.paymentPayload, + Requirements: build.requirements, + } + + if settleHeader := resp.Header.Get("PAYMENT-RESPONSE"); settleHeader != "" { + if settle, err := decodePaymentResponseHeader(settleHeader); err == nil { + prCtx.SettleResponse = settle + } + } + if prCtx.SettleResponse == nil && resp.StatusCode == http.StatusPaymentRequired { + if requiredHeader := resp.Header.Get("PAYMENT-REQUIRED"); requiredHeader != "" { + if pr, err := decodePaymentRequiredHeader(requiredHeader); err == nil { + prCtx.PaymentRequired = &pr + } + } } - // Select V1 requirements - selectedV1, err := t.x402Client.client.SelectPaymentRequirementsV1(paymentRequiredV1.Accepts) - if err != nil { - return nil, fmt.Errorf("cannot fulfill V1 payment requirements: %w", err) + if prCtx.SettleResponse == nil && prCtx.PaymentRequired == nil { + return false, nil } - // Create V1 payment payload - payloadV1, err := t.x402Client.client.CreatePaymentPayloadV1(ctx, selectedV1) + result, err := t.x402Client.client.HandlePaymentResponse(ctx, prCtx) if err != nil { - return nil, fmt.Errorf("failed to create V1 payment: %w", err) + return false, err } + return result.Recovered, nil +} - // Marshal to bytes - return json.Marshal(payloadV1) +// v2PaymentBuild captures all the V2 state PaymentRoundTripper needs across the +// payment retry: the parsed PaymentRequired (so corrective recovery can rebuild), +// the chosen requirements (for hook dispatch), the resulting payload, and its +// marshaled bytes (to put in PAYMENT-SIGNATURE). +type v2PaymentBuild struct { + paymentRequired types.PaymentRequired + requirements types.PaymentRequirements + paymentPayload types.PaymentPayload + payloadBytes []byte } -// handleV2Payment processes V2 PaymentRequired and creates V2 payload -func (t *PaymentRoundTripper) handleV2Payment(ctx context.Context, headers map[string]string, body []byte) ([]byte, error) { - // Parse V2 PaymentRequired (from header or body) +func (t *PaymentRoundTripper) buildV2Payment( + ctx context.Context, + headers map[string]string, + body []byte, +) (*v2PaymentBuild, error) { var paymentRequiredV2 types.PaymentRequired - // Normalize headers to uppercase normalizedHeaders := make(map[string]string) for k, v := range headers { normalizedHeaders[strings.ToUpper(k)] = v } - // Try header first (V2 standard) if header, exists := normalizedHeaders["PAYMENT-REQUIRED"]; exists { decoded, err := decodePaymentRequiredHeader(header) if err != nil { @@ -291,7 +373,6 @@ func (t *PaymentRoundTripper) handleV2Payment(ctx context.Context, headers map[s } paymentRequiredV2 = decoded } else if len(body) > 0 { - // Fall back to body (some V2 servers might use body) if err := json.Unmarshal(body, &paymentRequiredV2); err != nil { return nil, fmt.Errorf("failed to parse V2 payment required: %w", err) } @@ -299,16 +380,14 @@ func (t *PaymentRoundTripper) handleV2Payment(ctx context.Context, headers map[s return nil, fmt.Errorf("no V2 payment required information found") } - // Select V2 requirements - selectedV2, err := t.x402Client.client.SelectPaymentRequirements(paymentRequiredV2.Accepts) + selected, err := t.x402Client.client.SelectPaymentRequirements(paymentRequiredV2.Accepts) if err != nil { return nil, fmt.Errorf("cannot fulfill V2 payment requirements: %w", err) } - // Create V2 payment payload - payloadV2, err := t.x402Client.client.CreatePaymentPayload( + payload, err := t.x402Client.client.CreatePaymentPayload( ctx, - selectedV2, + selected, paymentRequiredV2.Resource, paymentRequiredV2.Extensions, ) @@ -316,8 +395,41 @@ func (t *PaymentRoundTripper) handleV2Payment(ctx context.Context, headers map[s return nil, fmt.Errorf("failed to create V2 payment: %w", err) } + bytes, err := json.Marshal(payload) + if err != nil { + return nil, fmt.Errorf("failed to marshal V2 payment: %w", err) + } + + return &v2PaymentBuild{ + paymentRequired: paymentRequiredV2, + requirements: selected, + paymentPayload: payload, + payloadBytes: bytes, + }, nil +} + +// handleV1Payment processes V1 PaymentRequired and creates V1 payload +func (t *PaymentRoundTripper) handleV1Payment(ctx context.Context, body []byte) ([]byte, error) { + // Parse V1 PaymentRequired from body + var paymentRequiredV1 types.PaymentRequiredV1 + if err := json.Unmarshal(body, &paymentRequiredV1); err != nil { + return nil, fmt.Errorf("failed to parse V1 payment required: %w", err) + } + + // Select V1 requirements + selectedV1, err := t.x402Client.client.SelectPaymentRequirementsV1(paymentRequiredV1.Accepts) + if err != nil { + return nil, fmt.Errorf("cannot fulfill V1 payment requirements: %w", err) + } + + // Create V1 payment payload + payloadV1, err := t.x402Client.client.CreatePaymentPayloadV1(ctx, selectedV1) + if err != nil { + return nil, fmt.Errorf("failed to create V1 payment: %w", err) + } + // Marshal to bytes - return json.Marshal(payloadV2) + return json.Marshal(payloadV1) } // detectPaymentRequiredVersion detects protocol version from HTTP response @@ -417,6 +529,7 @@ func decodePaymentRequiredHeader(header string) (x402.PaymentRequired, error) { // encodePaymentResponseHeader encodes a settlement response as base64 func encodePaymentResponseHeader(response x402.SettleResponse) (string, error) { + response = withTypedChannelStateExtra(response) data, err := json.Marshal(response) if err != nil { return "", fmt.Errorf("failed to marshal settle response: %w", err) @@ -424,6 +537,42 @@ func encodePaymentResponseHeader(response x402.SettleResponse) (string, error) { return base64.StdEncoding.EncodeToString(data), nil } +type paymentResponseChannelStateExtra struct { + ChannelId string `json:"channelId,omitempty"` + Balance string `json:"balance,omitempty"` + TotalClaimed string `json:"totalClaimed,omitempty"` + WithdrawRequestedAt interface{} `json:"withdrawRequestedAt,omitempty"` + RefundNonce string `json:"refundNonce,omitempty"` + ChargedCumulativeAmount string `json:"chargedCumulativeAmount,omitempty"` +} + +func withTypedChannelStateExtra(response x402.SettleResponse) x402.SettleResponse { + raw, ok := response.Extra["channelState"].(map[string]interface{}) + if !ok { + return response + } + + extra := make(map[string]interface{}, len(response.Extra)) + for key, value := range response.Extra { + extra[key] = value + } + extra["channelState"] = paymentResponseChannelStateExtra{ + ChannelId: stringField(raw, "channelId"), + Balance: stringField(raw, "balance"), + TotalClaimed: stringField(raw, "totalClaimed"), + WithdrawRequestedAt: raw["withdrawRequestedAt"], + RefundNonce: stringField(raw, "refundNonce"), + ChargedCumulativeAmount: stringField(raw, "chargedCumulativeAmount"), + } + response.Extra = extra + return response +} + +func stringField(data map[string]interface{}, key string) string { + value, _ := data[key].(string) + return value +} + // decodePaymentResponseHeader decodes a base64 payment response header func decodePaymentResponseHeader(header string) (*x402.SettleResponse, error) { data, err := base64.StdEncoding.DecodeString(header) diff --git a/go/http/client_test.go b/go/http/client_test.go index 0e899bfcf7..f7b8460848 100644 --- a/go/http/client_test.go +++ b/go/http/client_test.go @@ -10,8 +10,8 @@ import ( "strings" "testing" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) func TestNewx402HTTPClient(t *testing.T) { @@ -215,6 +215,55 @@ func TestGetPaymentSettleResponse(t *testing.T) { } } +func TestEncodePaymentResponseHeader_ChannelStateOrder(t *testing.T) { + encoded, err := encodePaymentResponseHeader(x402.SettleResponse{ + Success: true, + Payer: "0xpayer", + Transaction: "0xtx", + Network: "eip155:1", + Amount: "1000", + Extra: map[string]interface{}{ + "channelState": map[string]interface{}{ + "balance": "5000", + "channelId": "0xchan", + "chargedCumulativeAmount": "3000", + "refundNonce": "1", + "totalClaimed": "2000", + "withdrawRequestedAt": 0, + }, + "chargedAmount": "1000", + }, + }) + if err != nil { + t.Fatalf("encodePaymentResponseHeader: %v", err) + } + + decoded, err := base64.StdEncoding.DecodeString(encoded) + if err != nil { + t.Fatalf("decode: %v", err) + } + body := string(decoded) + fields := []string{ + `"channelId":"0xchan"`, + `"balance":"5000"`, + `"totalClaimed":"2000"`, + `"withdrawRequestedAt":0`, + `"refundNonce":"1"`, + `"chargedCumulativeAmount":"3000"`, + } + last := -1 + for _, field := range fields { + idx := strings.Index(body, field) + if idx == -1 { + t.Fatalf("missing %s in %s", field, body) + } + if idx <= last { + t.Fatalf("field %s out of order in %s", field, body) + } + last = idx + } +} + func TestPaymentRoundTripper(t *testing.T) { // Create a test server that returns 402 first, then 200 callCount := 0 @@ -392,3 +441,252 @@ func (m *mockSchemeClient) CreatePaymentPayload(ctx context.Context, requirement Payload: map[string]interface{}{"mock": "payload"}, }, nil } + +// hookSchemeClient implements both SchemeNetworkClient and PaymentResponseHandler so we +// can drive the round-tripper's auto-dispatch path end-to-end. +type hookSchemeClient struct { + scheme string + settleCalls int + correctiveCalls int + signalRecover bool + createPayloadCnt int +} + +func (m *hookSchemeClient) Scheme() string { return m.scheme } + +func (m *hookSchemeClient) CreatePaymentPayload(ctx context.Context, requirements types.PaymentRequirements) (types.PaymentPayload, error) { + m.createPayloadCnt++ + return types.PaymentPayload{ + X402Version: 2, + Payload: map[string]interface{}{"voucher": m.createPayloadCnt}, + }, nil +} + +func (m *hookSchemeClient) OnPaymentResponse(ctx context.Context, prCtx x402.PaymentResponseContext) (x402.PaymentResponseResult, error) { + if prCtx.SettleResponse != nil { + m.settleCalls++ + return x402.PaymentResponseResult{}, nil + } + if prCtx.PaymentRequired != nil { + m.correctiveCalls++ + return x402.PaymentResponseResult{Recovered: m.signalRecover}, nil + } + return x402.PaymentResponseResult{}, nil +} + +func paymentRequiredHeader(t *testing.T, accepts []types.PaymentRequirements) string { + t.Helper() + pr := types.PaymentRequired{X402Version: 2, Accepts: accepts} + encoded, err := encodePaymentRequiredHeader(pr) + if err != nil { + t.Fatalf("encodePaymentRequired: %v", err) + } + return encoded +} + +func paymentResponseHeader(t *testing.T, settle x402.SettleResponse) string { + t.Helper() + encoded, err := encodePaymentResponseHeader(settle) + if err != nil { + t.Fatalf("encodePaymentResponse: %v", err) + } + return encoded +} + +// TestPaymentRoundTripper_DispatchesOnPaymentResponseOnSuccess verifies that a +// successful retry (200 + PAYMENT-RESPONSE) auto-fires the scheme's hook. User +// code should not need to call ProcessSettleResponse manually. +func TestPaymentRoundTripper_DispatchesOnPaymentResponseOnSuccess(t *testing.T) { + scheme := &hookSchemeClient{scheme: "test-scheme"} + x402Client := x402.Newx402Client() + x402Client.Register("eip155:1", scheme) + + accepts := []types.PaymentRequirements{{ + Scheme: "test-scheme", + Network: "eip155:1", + Asset: "USDC", + Amount: "100", + PayTo: "0xrecipient", + }} + + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.Header.Get("PAYMENT-SIGNATURE") == "" { + w.Header().Set("PAYMENT-REQUIRED", paymentRequiredHeader(t, accepts)) + w.WriteHeader(http.StatusPaymentRequired) + return + } + w.Header().Set("PAYMENT-RESPONSE", paymentResponseHeader(t, x402.SettleResponse{ + Success: true, + Transaction: "0xtx", + Network: "eip155:1", + Extra: map[string]interface{}{"channelId": "0xabc", "balance": "999"}, + })) + w.WriteHeader(http.StatusOK) + })) + defer server.Close() + + httpClient := WrapHTTPClientWithPayment(&http.Client{}, Newx402HTTPClient(x402Client)) + req, _ := http.NewRequestWithContext(context.Background(), "GET", server.URL, nil) + resp, err := httpClient.Do(req) + if err != nil { + t.Fatalf("Do: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + t.Fatalf("expected 200, got %d", resp.StatusCode) + } + if scheme.settleCalls != 1 { + t.Fatalf("expected OnPaymentResponse(settle) once, got %d", scheme.settleCalls) + } + if scheme.correctiveCalls != 0 { + t.Fatalf("did not expect corrective dispatch, got %d", scheme.correctiveCalls) + } +} + +// TestPaymentRoundTripper_RetriesOnceWhenHookSignalsRecovered verifies the +// corrective-recovery path: scheme returns Recovered=true on a 402 + PAYMENT-REQUIRED, +// transport rebuilds the payload and retries one more time. +func TestPaymentRoundTripper_RetriesOnceWhenHookSignalsRecovered(t *testing.T) { + scheme := &hookSchemeClient{scheme: "test-scheme", signalRecover: true} + x402Client := x402.Newx402Client() + x402Client.Register("eip155:1", scheme) + + accepts := []types.PaymentRequirements{{ + Scheme: "test-scheme", + Network: "eip155:1", + Asset: "USDC", + Amount: "100", + PayTo: "0xrecipient", + }} + + var attempt int + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + attempt++ + paymentSig := r.Header.Get("PAYMENT-SIGNATURE") + switch { + case paymentSig == "": + // Initial 402 — no payment yet. + w.Header().Set("PAYMENT-REQUIRED", paymentRequiredHeader(t, accepts)) + w.WriteHeader(http.StatusPaymentRequired) + case attempt == 2: + // First paid attempt — corrective 402 carrying PAYMENT-REQUIRED. + w.Header().Set("PAYMENT-REQUIRED", paymentRequiredHeader(t, accepts)) + w.WriteHeader(http.StatusPaymentRequired) + default: + // Recovery retry — succeed. + w.Header().Set("PAYMENT-RESPONSE", paymentResponseHeader(t, x402.SettleResponse{ + Success: true, + Transaction: "0xtx", + Network: "eip155:1", + })) + w.WriteHeader(http.StatusOK) + } + })) + defer server.Close() + + httpClient := WrapHTTPClientWithPayment(&http.Client{}, Newx402HTTPClient(x402Client)) + req, _ := http.NewRequestWithContext(context.Background(), "GET", server.URL, nil) + resp, err := httpClient.Do(req) + if err != nil { + t.Fatalf("Do: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusOK { + t.Fatalf("expected final 200, got %d", resp.StatusCode) + } + if scheme.correctiveCalls != 1 { + t.Fatalf("expected one corrective dispatch, got %d", scheme.correctiveCalls) + } + if scheme.settleCalls != 1 { + t.Fatalf("expected one settle dispatch on recovery retry, got %d", scheme.settleCalls) + } + if scheme.createPayloadCnt < 2 { + t.Fatalf("expected payload to be rebuilt at least twice (retry + recovery), got %d", scheme.createPayloadCnt) + } + if attempt != 3 { + t.Fatalf("expected exactly 3 server attempts (initial + retry + recovery), got %d", attempt) + } +} + +// TestPaymentRoundTripper_NoRecoveryWhenHookDeclines ensures that a corrective 402 +// without recovery propagates as-is — no extra retries, no infinite loops. +func TestPaymentRoundTripper_NoRecoveryWhenHookDeclines(t *testing.T) { + scheme := &hookSchemeClient{scheme: "test-scheme", signalRecover: false} + x402Client := x402.Newx402Client() + x402Client.Register("eip155:1", scheme) + + accepts := []types.PaymentRequirements{{ + Scheme: "test-scheme", + Network: "eip155:1", + Asset: "USDC", + Amount: "100", + PayTo: "0xrecipient", + }} + + var attempt int + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + attempt++ + w.Header().Set("PAYMENT-REQUIRED", paymentRequiredHeader(t, accepts)) + w.WriteHeader(http.StatusPaymentRequired) + })) + defer server.Close() + + httpClient := WrapHTTPClientWithPayment(&http.Client{}, Newx402HTTPClient(x402Client)) + req, _ := http.NewRequestWithContext(context.Background(), "GET", server.URL, nil) + resp, err := httpClient.Do(req) + if err != nil { + t.Fatalf("Do: %v", err) + } + defer resp.Body.Close() + + if resp.StatusCode != http.StatusPaymentRequired { + t.Fatalf("expected 402, got %d", resp.StatusCode) + } + if scheme.correctiveCalls != 1 { + t.Fatalf("expected corrective hook fire once, got %d", scheme.correctiveCalls) + } + if attempt != 2 { + t.Fatalf("expected initial + 1 paid retry, got %d attempts", attempt) + } +} + +// TestWrapHTTPClientWithPayment_DoesNotMutateInput is a regression test for +// the bug where WrapHTTPClientWithPayment mutated the input *http.Client's +// Transport in place. When called with http.DefaultClient that mutation would +// turn every subsequent caller of http.DefaultClient — including unrelated +// refund probes that expect a 402 — into a payment-aware client that auto-pays +// and returns 200. The wrapper must produce a NEW client and leave the input +// untouched. +func TestWrapHTTPClientWithPayment_DoesNotMutateInput(t *testing.T) { + originalDefault := http.DefaultClient.Transport + defer func() { http.DefaultClient.Transport = originalDefault }() + + x402Client := Newx402HTTPClient(x402.Newx402Client()) + + wrapped := WrapHTTPClientWithPayment(http.DefaultClient, x402Client) + + if wrapped == http.DefaultClient { + t.Fatal("wrapper returned the same *http.Client as the input — must return a new client") + } + if http.DefaultClient.Transport != originalDefault { + t.Fatal("http.DefaultClient.Transport was mutated by WrapHTTPClientWithPayment") + } + if _, ok := wrapped.Transport.(*PaymentRoundTripper); !ok { + t.Fatalf("returned client should have PaymentRoundTripper transport, got %T", wrapped.Transport) + } + + custom := &http.Client{Timeout: 7 * 1e9} + customOriginal := custom.Transport + wrapped2 := WrapHTTPClientWithPayment(custom, x402Client) + if wrapped2 == custom { + t.Fatal("wrapper must not return the input *http.Client") + } + if custom.Transport != customOriginal { + t.Fatal("input *http.Client.Transport was mutated") + } + if wrapped2.Timeout != custom.Timeout { + t.Fatalf("wrapped client should preserve Timeout %v, got %v", custom.Timeout, wrapped2.Timeout) + } +} diff --git a/go/http/dynamic_test.go b/go/http/dynamic_test.go index bdbbed3216..8757439d1f 100644 --- a/go/http/dynamic_test.go +++ b/go/http/dynamic_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - x402 "github.com/coinbase/x402/go" + x402 "github.com/x402-foundation/x402/go" ) // Note: mockHTTPAdapter and mockSchemeServer are defined in server_test.go diff --git a/go/http/echo/README.md b/go/http/echo/README.md index 21cbe52697..3b105084a2 100644 --- a/go/http/echo/README.md +++ b/go/http/echo/README.md @@ -5,7 +5,7 @@ Echo middleware integration for the x402 Payment Protocol. This package provides ## Installation ```bash -go get github.com/coinbase/x402/go +go get github.com/x402-foundation/x402/go ``` ## Quick Start @@ -14,9 +14,9 @@ go get github.com/coinbase/x402/go package main import ( - x402http "github.com/coinbase/x402/go/http" - echomw "github.com/coinbase/x402/go/http/echo" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" + x402http "github.com/x402-foundation/x402/go/http" + echomw "github.com/x402-foundation/x402/go/http/echo" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" "github.com/labstack/echo/v4" ) @@ -165,8 +165,8 @@ Register schemes for different networks: ```go import ( - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) e.Use(echomw.PaymentMiddlewareFromConfig(routes, @@ -278,10 +278,10 @@ import ( "net/http" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - echomw "github.com/coinbase/x402/go/http/echo" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + echomw "github.com/x402-foundation/x402/go/http/echo" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" "github.com/labstack/echo/v4" ) diff --git a/go/http/echo/builder.go b/go/http/echo/builder.go index 35189f55dd..7d6a48cce1 100644 --- a/go/http/echo/builder.go +++ b/go/http/echo/builder.go @@ -3,9 +3,9 @@ package echo import ( "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" "github.com/labstack/echo/v4" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" ) // Config provides struct-based configuration for x402 payment middleware. diff --git a/go/http/echo/middleware.go b/go/http/echo/middleware.go index 81a5eb501e..cb4dc3a491 100644 --- a/go/http/echo/middleware.go +++ b/go/http/echo/middleware.go @@ -3,15 +3,16 @@ package echo import ( "bytes" "context" + "encoding/json" "fmt" "net/http" "sync" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - x402http "github.com/coinbase/x402/go/http" "github.com/labstack/echo/v4" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + x402http "github.com/x402-foundation/x402/go/http" ) // SetSettlementOverrides sets settlement overrides on the Echo response for partial settlement. @@ -359,8 +360,43 @@ func handlePaymentVerified(c echo.Context, next echo.HandlerFunc, server *x402ht c.Set("x402_requirements", *result.PaymentRequirements) } - // Continue to protected handler - err := next(c) + // SkipHandler directive: bypass downstream handler, settle inline using the + // directive body. Used for refund acknowledgements where there is no resource + // response to return. + var err error + if result.SkipHandler != nil { + contentType := result.SkipHandler.ContentType + if contentType == "" { + contentType = "application/json" + } + bodyBytes, jerr := json.Marshal(result.SkipHandler.Body) + if jerr != nil { + bodyBytes = []byte("{}") + } + capture.Header().Set("Content-Type", contentType) + capture.statusCode = http.StatusOK + _, _ = capture.body.Write(bodyBytes) + } else { + // Continue to protected handler + func() { + defer func() { + if rec := recover(); rec != nil { + if result.CancellationDispatcher != nil { + perr, ok := rec.(error) + if !ok { + perr = fmt.Errorf("%v", rec) + } + result.CancellationDispatcher.Cancel(x402.VerifiedPaymentCancelOptions{ + Reason: x402.CancellationReasonHandlerThrew, + Err: perr, + }) + } + panic(rec) + } + }() + err = next(c) + }() + } // Restore original writer c.Response().Writer = origWriter @@ -368,11 +404,23 @@ func handlePaymentVerified(c echo.Context, next echo.HandlerFunc, server *x402ht // If handler returned error, propagate it if err != nil { + if result.CancellationDispatcher != nil { + result.CancellationDispatcher.Cancel(x402.VerifiedPaymentCancelOptions{ + Reason: x402.CancellationReasonHandlerThrew, + Err: err, + }) + } return err } // Don't settle if response failed if capture.statusCode >= 400 { + if result.CancellationDispatcher != nil { + result.CancellationDispatcher.Cancel(x402.VerifiedPaymentCancelOptions{ + Reason: x402.CancellationReasonHandlerFailed, + ResponseStatus: capture.statusCode, + }) + } // Write captured error response origWriter.WriteHeader(capture.statusCode) _, _ = origWriter.Write(capture.body.Bytes()) @@ -389,6 +437,7 @@ func handlePaymentVerified(c echo.Context, next echo.HandlerFunc, server *x402ht ResponseBody: capture.body.Bytes(), ResponseHeaders: capture.Header(), }, + result.DeclaredExtensions, ) // Check settlement success diff --git a/go/http/echo/middleware_test.go b/go/http/echo/middleware_test.go index 6500357a33..674c5c03b7 100644 --- a/go/http/echo/middleware_test.go +++ b/go/http/echo/middleware_test.go @@ -10,10 +10,10 @@ import ( "testing" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - "github.com/coinbase/x402/go/types" "github.com/labstack/echo/v4" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/types" ) // ============================================================================ diff --git a/go/http/evm_paywall_template.go b/go/http/evm_paywall_template.go index 1f03ef1070..6b7dc82b07 100644 --- a/go/http/evm_paywall_template.go +++ b/go/http/evm_paywall_template.go @@ -2,4 +2,4 @@ package http // EVMPaywallTemplate is the pre-built EVM paywall template with inlined CSS and JS -const EVMPaywallTemplate = "\n \n \n Payment Required\n \n
\n \n \n " +const EVMPaywallTemplate = "\n \n \n Payment Required\n \n
\n \n \n " diff --git a/go/http/facilitator_client.go b/go/http/facilitator_client.go index 1ca017c3cc..b0d5bf675f 100644 --- a/go/http/facilitator_client.go +++ b/go/http/facilitator_client.go @@ -3,15 +3,17 @@ package http import ( "bytes" "context" + "encoding/base64" "encoding/json" "fmt" "io" + "log" "net/http" "strings" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) // ============================================================================ @@ -38,7 +40,7 @@ type AuthHeaders struct { Verify map[string]string Settle map[string]string Supported map[string]string - Discovery map[string]string + Bazaar map[string]string } // FacilitatorConfig configures the HTTP facilitator client @@ -83,19 +85,24 @@ func (e *FacilitatorResponseError) Unwrap() error { } type verifyResponseEnvelope struct { - IsValid *bool `json:"isValid"` - InvalidReason string `json:"invalidReason,omitempty"` - InvalidMessage string `json:"invalidMessage,omitempty"` - Payer string `json:"payer,omitempty"` + IsValid *bool `json:"isValid"` + InvalidReason string `json:"invalidReason,omitempty"` + InvalidMessage string `json:"invalidMessage,omitempty"` + Payer string `json:"payer,omitempty"` + Extensions map[string]interface{} `json:"extensions,omitempty"` + Extra map[string]interface{} `json:"extra,omitempty"` } type settleResponseEnvelope struct { - Success *bool `json:"success"` - ErrorReason string `json:"errorReason,omitempty"` - ErrorMessage string `json:"errorMessage,omitempty"` - Payer string `json:"payer,omitempty"` - Transaction *string `json:"transaction"` - Network *x402.Network `json:"network"` + Success *bool `json:"success"` + ErrorReason string `json:"errorReason,omitempty"` + ErrorMessage string `json:"errorMessage,omitempty"` + Payer string `json:"payer,omitempty"` + Transaction *string `json:"transaction"` + Network *x402.Network `json:"network"` + Amount string `json:"amount,omitempty"` + Extensions map[string]interface{} `json:"extensions,omitempty"` + Extra map[string]interface{} `json:"extra,omitempty"` } type supportedKindEnvelope struct { @@ -146,6 +153,8 @@ func parseVerifySuccessResponse(body []byte) (*x402.VerifyResponse, error) { InvalidReason: response.InvalidReason, InvalidMessage: response.InvalidMessage, Payer: response.Payer, + Extensions: response.Extensions, + Extra: response.Extra, }, nil } @@ -165,9 +174,46 @@ func parseSettleSuccessResponse(body []byte) (*x402.SettleResponse, error) { Payer: response.Payer, Transaction: *response.Transaction, Network: *response.Network, + Amount: response.Amount, + Extensions: response.Extensions, + Extra: response.Extra, }, nil } +var extensionResponseLogFieldAllowlist = []string{"status", "rejectedReason", "reason", "code"} + +// logExtensionResponsesHeader reads the EXTENSION-RESPONSES header from an HTTP response +// and logs allowlisted fields. Silently ignores malformed headers. +func logExtensionResponsesHeader(resp *http.Response) { + header := resp.Header.Get("EXTENSION-RESPONSES") + if header == "" { + return + } + decoded, err := base64.StdEncoding.DecodeString(header) + if err != nil { + return + } + var headerExtensions map[string]interface{} + if err := json.Unmarshal(decoded, &headerExtensions); err != nil { + return + } + sanitized := make(map[string]map[string]interface{}, len(headerExtensions)) + for extensionKey, payload := range headerExtensions { + filtered := make(map[string]interface{}) + if payloadMap, ok := payload.(map[string]interface{}); ok { + for _, fieldKey := range extensionResponseLogFieldAllowlist { + if value, exists := payloadMap[fieldKey]; exists { + filtered[fieldKey] = value + } + } + } + sanitized[extensionKey] = filtered + } + if extJSON, err := json.Marshal(sanitized); err == nil { + log.Printf("[x402] extension responses: %s", extJSON) + } +} + func parseSupportedSuccessResponse(body []byte) (x402.SupportedResponse, error) { var response supportedResponseEnvelope if err := json.Unmarshal(body, &response); err != nil { @@ -419,7 +465,12 @@ func (c *HTTPFacilitatorClient) verifyHTTP(ctx context.Context, version int, pay return nil, fmt.Errorf("facilitator verify failed (%d): %s", resp.StatusCode, string(responseBody)) } - return parseVerifySuccessResponse(responseBody) + result, err := parseVerifySuccessResponse(responseBody) + if err != nil { + return nil, err + } + logExtensionResponsesHeader(resp) + return result, nil } func (c *HTTPFacilitatorClient) settleHTTP(ctx context.Context, version int, payloadBytes, requirementsBytes []byte) (*x402.SettleResponse, error) { @@ -496,5 +547,10 @@ func (c *HTTPFacilitatorClient) settleHTTP(ctx context.Context, version int, pay return nil, fmt.Errorf("facilitator settle failed (%d): %s", resp.StatusCode, string(responseBody)) } - return parseSettleSuccessResponse(responseBody) + result, err := parseSettleSuccessResponse(responseBody) + if err != nil { + return nil, err + } + logExtensionResponsesHeader(resp) + return result, nil } diff --git a/go/http/facilitator_client_test.go b/go/http/facilitator_client_test.go index 2cb610ba69..be7c5065a2 100644 --- a/go/http/facilitator_client_test.go +++ b/go/http/facilitator_client_test.go @@ -12,7 +12,7 @@ import ( "testing" "time" - x402 "github.com/coinbase/x402/go" + x402 "github.com/x402-foundation/x402/go" ) // Test helper functions diff --git a/go/http/gin/README.md b/go/http/gin/README.md index bdde156947..a320d9356b 100644 --- a/go/http/gin/README.md +++ b/go/http/gin/README.md @@ -5,7 +5,7 @@ Gin middleware integration for the x402 Payment Protocol. This package provides ## Installation ```bash -go get github.com/coinbase/x402/go +go get github.com/x402-foundation/x402/go ``` ## Quick Start @@ -16,10 +16,10 @@ package main import ( "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" "github.com/gin-gonic/gin" ) @@ -154,8 +154,8 @@ Register schemes for different networks: ```go import ( - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - svm "github.com/coinbase/x402/go/mechanisms/svm/exact/server" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + svm "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) r.Use(ginmw.PaymentMiddlewareFromConfig(routes, @@ -238,10 +238,10 @@ import ( "log" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - ginmw "github.com/coinbase/x402/go/http/gin" - evm "github.com/coinbase/x402/go/mechanisms/evm/exact/server" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + evm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" "github.com/gin-gonic/gin" ) diff --git a/go/http/gin/builder.go b/go/http/gin/builder.go index 7619d2f48b..0f2a542ef6 100644 --- a/go/http/gin/builder.go +++ b/go/http/gin/builder.go @@ -3,9 +3,9 @@ package gin import ( "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" "github.com/gin-gonic/gin" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" ) // Config provides struct-based configuration for x402 payment middleware. diff --git a/go/http/gin/middleware.go b/go/http/gin/middleware.go index 05feaae1bc..993618de0d 100644 --- a/go/http/gin/middleware.go +++ b/go/http/gin/middleware.go @@ -3,15 +3,16 @@ package gin import ( "bytes" "context" + "encoding/json" "fmt" "net/http" "sync" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - x402http "github.com/coinbase/x402/go/http" "github.com/gin-gonic/gin" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + x402http "github.com/x402-foundation/x402/go/http" ) // SetSettlementOverrides sets settlement overrides on the Gin response for partial settlement. @@ -360,11 +361,55 @@ func handlePaymentVerified(c *gin.Context, server *x402http.HTTPServer, ctx cont c.Set("x402_requirements", *result.PaymentRequirements) } - // Continue to protected handler - c.Next() + // SkipHandler directive: bypass downstream handler, settle inline using the + // directive body. Used for refund acknowledgements where there is no resource + // response to return. + skipHandler := result.SkipHandler != nil + if skipHandler { + contentType := result.SkipHandler.ContentType + if contentType == "" { + contentType = "application/json" + } + bodyBytes, err := json.Marshal(result.SkipHandler.Body) + if err != nil { + bodyBytes = []byte("{}") + } + writer.Header().Set("Content-Type", contentType) + writer.statusCode = http.StatusOK + _, _ = writer.body.Write(bodyBytes) + // Prevent gin from invoking the protected route handler. Settlement still + // runs below using the canned body in the writer. + c.Abort() + } else { + // Continue to protected handler + func() { + defer func() { + if rec := recover(); rec != nil { + if result.CancellationDispatcher != nil { + err, ok := rec.(error) + if !ok { + err = fmt.Errorf("%v", rec) + } + result.CancellationDispatcher.Cancel(x402.VerifiedPaymentCancelOptions{ + Reason: x402.CancellationReasonHandlerThrew, + Err: err, + }) + } + panic(rec) + } + }() + c.Next() + }() + } - // Check if aborted - if c.IsAborted() { + // Check if aborted by the handler (SkipHandler is an intentional bypass, not a failure). + if !skipHandler && c.IsAborted() { + if result.CancellationDispatcher != nil { + result.CancellationDispatcher.Cancel(x402.VerifiedPaymentCancelOptions{ + Reason: x402.CancellationReasonHandlerFailed, + ResponseStatus: writer.statusCode, + }) + } return } @@ -373,6 +418,12 @@ func handlePaymentVerified(c *gin.Context, server *x402http.HTTPServer, ctx cont // Don't settle if response failed if writer.statusCode >= 400 { + if result.CancellationDispatcher != nil { + result.CancellationDispatcher.Cancel(x402.VerifiedPaymentCancelOptions{ + Reason: x402.CancellationReasonHandlerFailed, + ResponseStatus: writer.statusCode, + }) + } // Write captured response c.Writer.WriteHeader(writer.statusCode) _, _ = c.Writer.Write(writer.body.Bytes()) @@ -389,6 +440,7 @@ func handlePaymentVerified(c *gin.Context, server *x402http.HTTPServer, ctx cont ResponseBody: writer.body.Bytes(), ResponseHeaders: writer.Header(), }, + result.DeclaredExtensions, ) // Check settlement success diff --git a/go/http/gin/middleware_test.go b/go/http/gin/middleware_test.go index 0e2efd045f..ae66119737 100644 --- a/go/http/gin/middleware_test.go +++ b/go/http/gin/middleware_test.go @@ -13,10 +13,10 @@ import ( "testing" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - "github.com/coinbase/x402/go/types" "github.com/gin-gonic/gin" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/types" ) // ============================================================================ diff --git a/go/http/http.go b/go/http/http.go index 9902426ebf..66a06c6a7f 100644 --- a/go/http/http.go +++ b/go/http/http.go @@ -7,7 +7,7 @@ import ( "io" "net/http" - x402 "github.com/coinbase/x402/go" + x402 "github.com/x402-foundation/x402/go" ) // ============================================================================ diff --git a/go/http/nethttp/builder.go b/go/http/nethttp/builder.go index 416c552bfa..fb680470b9 100644 --- a/go/http/nethttp/builder.go +++ b/go/http/nethttp/builder.go @@ -4,8 +4,8 @@ import ( "net/http" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" ) // Config provides struct-based configuration for x402 payment middleware. diff --git a/go/http/nethttp/context.go b/go/http/nethttp/context.go index b9fdd14951..bc0d16c92b 100644 --- a/go/http/nethttp/context.go +++ b/go/http/nethttp/context.go @@ -3,7 +3,7 @@ package nethttp import ( "context" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // contextKey is a private type for context keys defined in this package. diff --git a/go/http/nethttp/middleware.go b/go/http/nethttp/middleware.go index 6ce5588f6f..c77fc55560 100644 --- a/go/http/nethttp/middleware.go +++ b/go/http/nethttp/middleware.go @@ -9,9 +9,9 @@ import ( "sync" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - x402http "github.com/coinbase/x402/go/http" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + x402http "github.com/x402-foundation/x402/go/http" ) // SetSettlementOverrides sets settlement overrides on the response for partial settlement. @@ -289,11 +289,51 @@ func handlePaymentVerified(w http.ResponseWriter, r *http.Request, next http.Han r = r.WithContext(context.WithValue(r.Context(), requirementsContextKey, result.PaymentRequirements)) //nolint:contextcheck // context is derived from r.Context() } - // Call downstream handler with captured writer - next.ServeHTTP(capture, r) + // SkipHandler directive: bypass downstream handler, settle inline using the + // directive body. Used for refund acknowledgements where there is no resource + // response to return. + if result.SkipHandler != nil { + contentType := result.SkipHandler.ContentType + if contentType == "" { + contentType = "application/json" + } + bodyBytes, err := json.Marshal(result.SkipHandler.Body) + if err != nil { + bodyBytes = []byte("{}") + } + capture.Header().Set("Content-Type", contentType) + capture.statusCode = http.StatusOK + capture.written = true + _, _ = capture.body.Write(bodyBytes) + } else { + func() { + defer func() { + if rec := recover(); rec != nil { + if result.CancellationDispatcher != nil { + err, ok := rec.(error) + if !ok { + err = fmt.Errorf("%v", rec) + } + result.CancellationDispatcher.Cancel(x402.VerifiedPaymentCancelOptions{ + Reason: x402.CancellationReasonHandlerThrew, + Err: err, + }) + } + panic(rec) + } + }() + next.ServeHTTP(capture, r) + }() + } // Don't settle if response failed if capture.statusCode >= 400 { + if result.CancellationDispatcher != nil { + result.CancellationDispatcher.Cancel(x402.VerifiedPaymentCancelOptions{ + Reason: x402.CancellationReasonHandlerFailed, + ResponseStatus: capture.statusCode, + }) + } w.WriteHeader(capture.statusCode) _, _ = w.Write(capture.body.Bytes()) return @@ -309,6 +349,7 @@ func handlePaymentVerified(w http.ResponseWriter, r *http.Request, next http.Han ResponseBody: capture.body.Bytes(), ResponseHeaders: capture.Header(), }, + result.DeclaredExtensions, ) if !settleResult.Success { diff --git a/go/http/nethttp/middleware_test.go b/go/http/nethttp/middleware_test.go index 0d4f6928f7..9c4d98666f 100644 --- a/go/http/nethttp/middleware_test.go +++ b/go/http/nethttp/middleware_test.go @@ -10,9 +10,9 @@ import ( "testing" "time" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/types" ) // ============================================================================ diff --git a/go/http/paywall.go b/go/http/paywall.go index a6191f7f4c..1e5a6549a4 100644 --- a/go/http/paywall.go +++ b/go/http/paywall.go @@ -3,7 +3,7 @@ package http import ( "strings" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // ============================================================================ diff --git a/go/http/paywall_test.go b/go/http/paywall_test.go index ae1684bdd5..ceefd937af 100644 --- a/go/http/paywall_test.go +++ b/go/http/paywall_test.go @@ -4,7 +4,7 @@ import ( "strings" "testing" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // mockPaywallProvider is a test PaywallProvider that returns configurable HTML. diff --git a/go/http/server.go b/go/http/server.go index d66ae11b88..5632ce8772 100644 --- a/go/http/server.go +++ b/go/http/server.go @@ -4,6 +4,7 @@ import ( "context" "encoding/base64" "encoding/json" + "errors" "fmt" "html" "log" @@ -13,9 +14,9 @@ import ( "strconv" "strings" - x402 "github.com/coinbase/x402/go" - exttypes "github.com/coinbase/x402/go/extensions/types" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + exttypes "github.com/x402-foundation/x402/go/extensions/types" + "github.com/x402-foundation/x402/go/types" ) // Pre-compiled regex patterns to avoid recompilation on every call. @@ -180,6 +181,18 @@ type HTTPProcessResult struct { Response *HTTPResponseInstructions PaymentPayload *types.PaymentPayload // V2 only PaymentRequirements *types.PaymentRequirements // V2 only + // DeclaredExtensions is the route's enriched extension declaration map. + // Carried through verify → settle so per-extension hooks gate on declared + // keys both in the verify and settle phases. Mirrors TS + // `paymentRequiredResponse.extensions` flowing into both calls. + DeclaredExtensions map[string]interface{} + // SkipHandler is set when an AfterVerifyHook signals that the resource handler + // should be bypassed and settlement performed inline. + SkipHandler *x402.SkipHandlerDirective + // CancellationDispatcher fires onVerifiedPaymentCanceled hooks if the resource + // handler errors or returns a non-2xx status before settlement runs. Set when + // Type is ResultPaymentVerified. + CancellationDispatcher *x402.PaymentCancellationDispatcher } // Result type constants @@ -601,17 +614,26 @@ func (s *x402HTTPResourceServer) ProcessHTTPRequest(ctx context.Context, reqCtx } } - // Verify payment (type-safe) - _, verifyErr := s.VerifyPayment(ctx, *typedPayload, *matchingReqs) + // Verify payment (type-safe). Pass `extensions` so per-extension hooks + // (registered via ResourceServerExtensionHookProvider) gate on declared + // extension keys. + verifyResp, verifyErr := s.VerifyPaymentWithExtensions(ctx, *typedPayload, *matchingReqs, extensions) if verifyErr != nil { err = verifyErr + // Prefer InvalidReason (the protocol error code) over the free-form + // message so enrichers can match on a stable identifier. errorMsg := err.Error() + var ve *x402.VerifyError + if errors.As(verifyErr, &ve) && ve.InvalidReason != "" { + errorMsg = ve.InvalidReason + } - paymentRequired := s.CreatePaymentRequiredResponse( + paymentRequired := s.CreatePaymentRequiredResponseWithPayload( requirements, resourceInfo, errorMsg, extensions, + typedPayload, ) response, err := s.createHTTPResponseV2(paymentRequired, false, paywallConfig, "", nil) @@ -632,11 +654,21 @@ func (s *x402HTTPResourceServer) ProcessHTTPRequest(ctx context.Context, reqCtx } // Payment verified - return HTTPProcessResult{ + result := HTTPProcessResult{ Type: ResultPaymentVerified, PaymentPayload: typedPayload, PaymentRequirements: matchingReqs, + DeclaredExtensions: extensions, + } + if verifyResp != nil { + result.SkipHandler = verifyResp.SkipHandler } + // Skip-handler runs inline; only attach a cancellation dispatcher when there + // is a downstream resource handler whose outcome can fail. + if result.SkipHandler == nil { + result.CancellationDispatcher = s.CreatePaymentCancellationDispatcherWithExtensions(ctx, *typedPayload, *matchingReqs, extensions) + } + return result } // RequiresPayment checks if a request requires payment based on route configuration @@ -667,7 +699,17 @@ func MarshalSettlementOverrides(overrides *x402.SettlementOverrides) string { // the settlement-overrides header from the transport context's ResponseHeaders // (set by the route handler via SetSettlementOverrides). The header is deleted // from ResponseHeaders to prevent it from being sent to the client. -func (s *x402HTTPResourceServer) ProcessSettlement(ctx context.Context, payload types.PaymentPayload, requirements types.PaymentRequirements, overrides *x402.SettlementOverrides, transportContext *HTTPTransportContext) *ProcessSettleResult { +// +// declaredExtensions is forwarded to SettlePaymentWithExtensions so per-extension +// settle hooks fire only when their key is declared on the route. +func (s *x402HTTPResourceServer) ProcessSettlement( + ctx context.Context, + payload types.PaymentPayload, + requirements types.PaymentRequirements, + overrides *x402.SettlementOverrides, + transportContext *HTTPTransportContext, + declaredExtensions map[string]interface{}, +) *ProcessSettleResult { resolved := overrides if resolved == nil && transportContext != nil && transportContext.ResponseHeaders != nil { if val := transportContext.ResponseHeaders.Get(SettlementOverridesHeader); val != "" { @@ -679,7 +721,7 @@ func (s *x402HTTPResourceServer) ProcessSettlement(ctx context.Context, payload } } - settleResult, err := s.SettlePayment(ctx, payload, requirements, resolved) + settleResult, err := s.SettlePaymentWithExtensions(ctx, payload, requirements, resolved, declaredExtensions) if err != nil { return s.buildSettlementFailureResult(err.Error(), x402.Network(requirements.Network), "", nil) } @@ -720,6 +762,7 @@ func (s *x402HTTPResourceServer) buildSettlementFailureResult(errorReason string if settleResult != nil { failureResponse.Network = settleResult.Network failureResponse.Payer = settleResult.Payer + failureResponse.ErrorMessage = settleResult.ErrorMessage } headers, err := s.createSettlementHeaders(&failureResponse) diff --git a/go/http/server_extensions_test.go b/go/http/server_extensions_test.go index 48c1e76545..50aa353d93 100644 --- a/go/http/server_extensions_test.go +++ b/go/http/server_extensions_test.go @@ -7,12 +7,12 @@ import ( "context" "testing" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/bazaar" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/extensions/paymentidentifier" - gohttp "github.com/coinbase/x402/go/http" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/paymentidentifier" + gohttp "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/types" ) // extTestHTTPAdapter is a minimal HTTPAdapter for use in this external test package. diff --git a/go/http/server_test.go b/go/http/server_test.go index 23a26e8015..97f15269b6 100644 --- a/go/http/server_test.go +++ b/go/http/server_test.go @@ -9,8 +9,8 @@ import ( "strings" "testing" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) // Mock HTTP adapter for testing @@ -467,7 +467,7 @@ func TestProcessSettlement(t *testing.T) { } // Test settlement processing - result := server.ProcessSettlement(ctx, payload, requirements, nil, nil) + result := server.ProcessSettlement(ctx, payload, requirements, nil, nil, nil) if !result.Success { t.Fatalf("Unexpected failure: %v", result.ErrorReason) } @@ -513,7 +513,7 @@ func TestProcessSettlement_Failure(t *testing.T) { Payload: map[string]interface{}{}, } - result := server.ProcessSettlement(ctx, payload, requirements, nil, nil) + result := server.ProcessSettlement(ctx, payload, requirements, nil, nil, nil) if result.Success { t.Fatal("Expected settlement failure") } @@ -571,7 +571,7 @@ func TestProcessSettlement_OverridesFromTransportContext(t *testing.T) { ResponseHeaders: h, } - result := server.ProcessSettlement(ctx, payload, requirements, nil, tc) + result := server.ProcessSettlement(ctx, payload, requirements, nil, tc, nil) if !result.Success { t.Fatalf("unexpected failure: %v", result.ErrorReason) } @@ -594,7 +594,7 @@ func TestProcessSettlement_OverridesFromTransportContext(t *testing.T) { } explicit := &x402.SettlementOverrides{Amount: "200"} - result := server.ProcessSettlement(ctx, payload, requirements, explicit, tc) + result := server.ProcessSettlement(ctx, payload, requirements, explicit, tc, nil) if !result.Success { t.Fatalf("unexpected failure: %v", result.ErrorReason) } @@ -616,7 +616,7 @@ func TestProcessSettlement_OverridesFromTransportContext(t *testing.T) { ResponseHeaders: h, } - result := server.ProcessSettlement(ctx, payload, requirements, nil, tc) + result := server.ProcessSettlement(ctx, payload, requirements, nil, tc, nil) if !result.Success { t.Fatalf("unexpected failure: %v", result.ErrorReason) } @@ -638,7 +638,7 @@ func TestProcessSettlement_OverridesFromTransportContext(t *testing.T) { ResponseHeaders: h, } - server.ProcessSettlement(ctx, payload, requirements, nil, tc) + server.ProcessSettlement(ctx, payload, requirements, nil, tc, nil) if tc.ResponseHeaders.Get(SettlementOverridesHeader) != "" { t.Error("expected settlement-overrides header to be deleted from transport context") @@ -649,7 +649,7 @@ func TestProcessSettlement_OverridesFromTransportContext(t *testing.T) { }) t.Run("nil transport context is safe", func(t *testing.T) { - result := server.ProcessSettlement(ctx, payload, requirements, nil, nil) + result := server.ProcessSettlement(ctx, payload, requirements, nil, nil, nil) if !result.Success { t.Fatalf("unexpected failure: %v", result.ErrorReason) } @@ -660,7 +660,7 @@ func TestProcessSettlement_OverridesFromTransportContext(t *testing.T) { Request: &HTTPRequestContext{Path: "/test", Method: "GET"}, ResponseHeaders: nil, } - result := server.ProcessSettlement(ctx, payload, requirements, nil, tc) + result := server.ProcessSettlement(ctx, payload, requirements, nil, tc, nil) if !result.Success { t.Fatalf("unexpected failure: %v", result.ErrorReason) } @@ -674,7 +674,7 @@ func TestProcessSettlement_OverridesFromTransportContext(t *testing.T) { ResponseHeaders: h, } - result := server.ProcessSettlement(ctx, payload, requirements, nil, tc) + result := server.ProcessSettlement(ctx, payload, requirements, nil, tc, nil) if !result.Success { t.Fatalf("unexpected failure: %v", result.ErrorReason) } @@ -697,7 +697,7 @@ func TestProcessSettlement_OverridesFromTransportContext(t *testing.T) { ResponseHeaders: h, } - result := server.ProcessSettlement(ctx, payload, requirements, nil, tc) + result := server.ProcessSettlement(ctx, payload, requirements, nil, tc, nil) if !result.Success { t.Fatalf("unexpected failure: %v", result.ErrorReason) } @@ -1123,6 +1123,99 @@ func (m *mockSchemeServer) EnhancePaymentRequirements(ctx context.Context, base return base, nil } +// mockEnricherSchemeServer extends mockSchemeServer with PaymentRequiredEnricher +// to exercise the verify-failure → enrichment wire-up in ProcessHTTPRequest. +type mockEnricherSchemeServer struct { + mockSchemeServer + calls int + lastErrorReason string + lastPayloadSeen bool +} + +func (m *mockEnricherSchemeServer) EnrichPaymentRequiredResponse(ctx x402.PaymentRequiredContext) { + m.calls++ + m.lastErrorReason = ctx.Error + m.lastPayloadSeen = ctx.PaymentPayload != nil + for i := range ctx.Requirements { + if ctx.Requirements[i].Extra == nil { + ctx.Requirements[i].Extra = map[string]interface{}{} + } + ctx.Requirements[i].Extra["EnrichedBy"] = "mock-enricher" + } +} + +func TestProcessHTTPRequest_VerifyFailureRunsEnricherWithPayload(t *testing.T) { + ctx := context.Background() + + routes := RoutesConfig{ + "POST /api": { + Accepts: PaymentOptions{ + {Scheme: "exact", PayTo: "0xtest", Price: "$1.00", Network: "eip155:1"}, + }, + }, + } + + enricher := &mockEnricherSchemeServer{mockSchemeServer: mockSchemeServer{scheme: "exact"}} + mockClient := &mockFacilitatorClient{ + verify: func(_ context.Context, _ []byte, _ []byte) (*x402.VerifyResponse, error) { + return nil, x402.NewVerifyError("custom_failure_reason", "0xpayer", "human-readable detail") + }, + supported: func(_ context.Context) (x402.SupportedResponse, error) { + return x402.SupportedResponse{ + Kinds: []x402.SupportedKind{{X402Version: 2, Scheme: "exact", Network: "eip155:1"}}, + Signers: map[string][]string{}, + }, nil + }, + } + + server := Newx402HTTPResourceServer( + routes, + x402.WithFacilitatorClient(mockClient), + x402.WithSchemeServer("eip155:1", enricher), + ) + _ = server.Initialize(ctx) + + pp := x402.PaymentPayload{ + X402Version: 2, + Payload: map[string]interface{}{"sig": "test"}, + Accepted: x402.PaymentRequirements{ + Scheme: "exact", Network: "eip155:1", Asset: "USDC", + Amount: "1000000", PayTo: "0xtest", MaxTimeoutSeconds: 300, + }, + } + encoded := base64.StdEncoding.EncodeToString(mustMarshal(t, pp)) + + adapter := &mockHTTPAdapter{ + method: "POST", + path: "/api", + url: "http://example.com/api", + headers: map[string]string{"PAYMENT-SIGNATURE": encoded}, + } + result := server.ProcessHTTPRequest(ctx, HTTPRequestContext{Adapter: adapter, Path: "/api", Method: "POST"}, nil) + + if result.Type != ResultPaymentError { + t.Fatalf("expected ResultPaymentError, got %v", result.Type) + } + if enricher.calls != 1 { + t.Fatalf("expected 1 enricher call, got %d", enricher.calls) + } + if enricher.lastErrorReason != "custom_failure_reason" { + t.Fatalf("expected InvalidReason as error, got %q", enricher.lastErrorReason) + } + if !enricher.lastPayloadSeen { + t.Fatal("expected enricher to receive non-nil PaymentPayload") + } +} + +func mustMarshal(t *testing.T, v interface{}) []byte { + t.Helper() + b, err := json.Marshal(v) + if err != nil { + t.Fatalf("marshal: %v", err) + } + return b +} + // Mock facilitator client type mockFacilitatorClient struct { verify func(ctx context.Context, payloadBytes []byte, requirementsBytes []byte) (*x402.VerifyResponse, error) diff --git a/go/http/svm_paywall_template.go b/go/http/svm_paywall_template.go index 1ca1b8e095..d57f41e870 100644 --- a/go/http/svm_paywall_template.go +++ b/go/http/svm_paywall_template.go @@ -2,4 +2,4 @@ package http // SVMPaywallTemplate is the pre-built SVM paywall template with inlined CSS and JS -const SVMPaywallTemplate = "\n \n \n Payment Required\n \n
\n \n \n " +const SVMPaywallTemplate = "\n \n \n Payment Required\n \n
\n \n \n " diff --git a/go/interfaces.go b/go/interfaces.go index b0668d5a2f..789713ec81 100644 --- a/go/interfaces.go +++ b/go/interfaces.go @@ -3,7 +3,7 @@ package x402 import ( "context" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // MoneyParser is a function that converts a decimal amount to an AssetAmount @@ -98,6 +98,41 @@ type ExtensionAwareClient interface { CreatePaymentPayloadWithExtensions(ctx context.Context, requirements types.PaymentRequirements, extensions map[string]interface{}) (types.PaymentPayload, error) } +// PaymentResponseContext is passed to PaymentResponseHandler implementations after +// the transport receives the response to a paid request. Exactly one of SettleResponse +// or PaymentRequired is populated: +// +// - SettleResponse: the request succeeded (HTTP 200) and the server returned a +// PAYMENT-RESPONSE header carrying the settle outcome. +// - PaymentRequired: the request was rejected (HTTP 402) with a corrective +// PAYMENT-REQUIRED header (e.g. cumulative_amount_mismatch). +// +// Mirrors the TS PaymentResponseContext shape consumed by SchemeClientHooks.onPaymentResponse. +type PaymentResponseContext struct { + PaymentPayload types.PaymentPayload + Requirements types.PaymentRequirements + SettleResponse *SettleResponse + PaymentRequired *types.PaymentRequired +} + +// PaymentResponseResult is returned by PaymentResponseHandler.OnPaymentResponse. +// When Recovered is true, the transport may attempt one additional retry with a +// freshly built payment payload. Used to handle corrective 402 responses where +// the scheme has resynced its session state. +type PaymentResponseResult struct { + Recovered bool +} + +// PaymentResponseHandler is an optional interface that SchemeNetworkClient +// implementations satisfy to reconcile local state after a paid response. +// The transport (PaymentRoundTripper) invokes this hook automatically — user +// code does not need to call ProcessSettleResponse manually. +// +// Mirrors the TS schemeHooks.onPaymentResponse field on SchemeClientHooks. +type PaymentResponseHandler interface { + OnPaymentResponse(ctx context.Context, prCtx PaymentResponseContext) (PaymentResponseResult, error) +} + // ClientExtension can enrich payment payloads on the client side. // Client extensions are invoked after the scheme creates the base payload // but before it is returned. This allows mechanism-specific logic (e.g., EVM EIP-2612 @@ -172,6 +207,24 @@ type AssetDecimalsProvider interface { GetAssetDecimals(asset string, network Network) int } +// PaymentRequiredContext is passed to PaymentRequiredEnricher.EnrichPaymentRequiredResponse. +// PaymentPayload is non-nil only on the verify-failure branch. +type PaymentRequiredContext struct { + Requirements []types.PaymentRequirements + PaymentPayload *types.PaymentPayload + ResourceInfo *types.ResourceInfo + Error string + PaymentRequiredResponse *types.PaymentRequired +} + +// PaymentRequiredEnricher is an optional interface for SchemeNetworkServer +// implementations that want to add per-scheme corrective state to the 402 +// response. Invoked once per matching scheme during PaymentRequired construction; +// implementations may mutate ctx.Requirements entries in place. +type PaymentRequiredEnricher interface { + EnrichPaymentRequiredResponse(ctx PaymentRequiredContext) +} + // SchemeNetworkFacilitator is implemented by facilitator-side payment mechanisms (V2) type SchemeNetworkFacilitator interface { Scheme() string diff --git a/go/legacy/README.md b/go/legacy/README.md index 851fd5f2e9..453ef9e132 100644 --- a/go/legacy/README.md +++ b/go/legacy/README.md @@ -1,9 +1,13 @@ # Go x402 +> **Deprecated (v1)** +> This Go module (`go/legacy`) implements x402 **v1**. It is **deprecated** and will only receive **security patches**. Please migrate to **v2**, see the [Migration guide: v1 to v2](https://docs.x402.org/guides/migration-v1-to-v2). +> Legacy examples are available at git tag `archive/legacy-v1-examples`. + ## Installation ```bash -go get github.com/coinbase/x402/go +go get github.com/x402-foundation/x402/go ``` ## Usage @@ -16,7 +20,7 @@ package main import ( "math/big" - x402gin "github.com/coinbase/x402/go/pkg/gin" + x402gin "github.com/x402-foundation/x402/go/pkg/gin" "github.com/gin-gonic/gin" ) diff --git a/go/legacy/bin/proxy_demo.go b/go/legacy/bin/proxy_demo.go index 9f3d51dfe9..9bd8883925 100644 --- a/go/legacy/bin/proxy_demo.go +++ b/go/legacy/bin/proxy_demo.go @@ -8,9 +8,9 @@ import ( "net/url" "os" - x402gin "github.com/coinbase/x402/go/pkg/gin" - "github.com/coinbase/x402/go/pkg/types" "github.com/gin-gonic/gin" + x402gin "github.com/x402-foundation/x402/go/pkg/gin" + "github.com/x402-foundation/x402/go/pkg/types" ) func main() { diff --git a/go/legacy/examples/mainnet/mainnet.go b/go/legacy/examples/mainnet/mainnet.go index 6040e01807..58cf33b9bf 100644 --- a/go/legacy/examples/mainnet/mainnet.go +++ b/go/legacy/examples/mainnet/mainnet.go @@ -5,10 +5,10 @@ import ( "math/big" "os" - "github.com/coinbase/x402/go/pkg/coinbasefacilitator" - x402gin "github.com/coinbase/x402/go/pkg/gin" "github.com/gin-gonic/gin" "github.com/joho/godotenv" + "github.com/x402-foundation/x402/go/pkg/coinbasefacilitator" + x402gin "github.com/x402-foundation/x402/go/pkg/gin" ) func main() { diff --git a/go/legacy/examples/server/resource.go b/go/legacy/examples/server/resource.go index aa5306dea6..b3a2043504 100644 --- a/go/legacy/examples/server/resource.go +++ b/go/legacy/examples/server/resource.go @@ -3,9 +3,9 @@ package main import ( "math/big" - x402gin "github.com/coinbase/x402/go/pkg/gin" - "github.com/coinbase/x402/go/pkg/types" "github.com/gin-gonic/gin" + x402gin "github.com/x402-foundation/x402/go/pkg/gin" + "github.com/x402-foundation/x402/go/pkg/types" ) func main() { diff --git a/go/legacy/go.mod b/go/legacy/go.mod index e0545f2575..17b7a898d7 100644 --- a/go/legacy/go.mod +++ b/go/legacy/go.mod @@ -1,4 +1,4 @@ -module github.com/coinbase/x402/go +module github.com/x402-foundation/x402/go go 1.23.3 diff --git a/go/legacy/pkg/coinbasefacilitator/cdp.go b/go/legacy/pkg/coinbasefacilitator/cdp.go index 0d246e35bd..b57bbc42dd 100644 --- a/go/legacy/pkg/coinbasefacilitator/cdp.go +++ b/go/legacy/pkg/coinbasefacilitator/cdp.go @@ -6,7 +6,7 @@ import ( "strings" "github.com/coinbase/cdp-sdk/go/auth" - "github.com/coinbase/x402/go/pkg/types" + "github.com/x402-foundation/x402/go/pkg/types" ) // SDKVersion represents the current version of the SDK diff --git a/go/legacy/pkg/coinbasefacilitator/facilitator.go b/go/legacy/pkg/coinbasefacilitator/facilitator.go index db8ffecd35..e9ce56c61c 100644 --- a/go/legacy/pkg/coinbasefacilitator/facilitator.go +++ b/go/legacy/pkg/coinbasefacilitator/facilitator.go @@ -4,7 +4,7 @@ import ( "fmt" "os" - "github.com/coinbase/x402/go/pkg/types" + "github.com/x402-foundation/x402/go/pkg/types" ) const ( diff --git a/go/legacy/pkg/facilitatorclient/facilitatorclient.go b/go/legacy/pkg/facilitatorclient/facilitatorclient.go index cc47b48c90..d12d3096a9 100644 --- a/go/legacy/pkg/facilitatorclient/facilitatorclient.go +++ b/go/legacy/pkg/facilitatorclient/facilitatorclient.go @@ -7,7 +7,7 @@ import ( "io" "net/http" - "github.com/coinbase/x402/go/pkg/types" + "github.com/x402-foundation/x402/go/pkg/types" ) // DefaultFacilitatorURL is the default URL for the x402 facilitator service diff --git a/go/legacy/pkg/facilitatorclient/facilitatorclient_test.go b/go/legacy/pkg/facilitatorclient/facilitatorclient_test.go index 6173aa49ce..003ca4d3bb 100644 --- a/go/legacy/pkg/facilitatorclient/facilitatorclient_test.go +++ b/go/legacy/pkg/facilitatorclient/facilitatorclient_test.go @@ -9,8 +9,8 @@ import ( "testing" "time" - "github.com/coinbase/x402/go/pkg/facilitatorclient" - "github.com/coinbase/x402/go/pkg/types" + "github.com/x402-foundation/x402/go/pkg/facilitatorclient" + "github.com/x402-foundation/x402/go/pkg/types" ) func TestVerify(t *testing.T) { diff --git a/go/legacy/pkg/gin/middleware.go b/go/legacy/pkg/gin/middleware.go index af978ecdd1..2fb65f8a81 100644 --- a/go/legacy/pkg/gin/middleware.go +++ b/go/legacy/pkg/gin/middleware.go @@ -9,8 +9,8 @@ import ( "github.com/gin-gonic/gin" - "github.com/coinbase/x402/go/pkg/facilitatorclient" - "github.com/coinbase/x402/go/pkg/types" + "github.com/x402-foundation/x402/go/pkg/facilitatorclient" + "github.com/x402-foundation/x402/go/pkg/types" ) const x402Version = 1 diff --git a/go/legacy/pkg/gin/middleware_test.go b/go/legacy/pkg/gin/middleware_test.go index d7aadd636e..4a62e3454e 100644 --- a/go/legacy/pkg/gin/middleware_test.go +++ b/go/legacy/pkg/gin/middleware_test.go @@ -11,8 +11,8 @@ import ( "github.com/gin-gonic/gin" "github.com/stretchr/testify/assert" - x402gin "github.com/coinbase/x402/go/pkg/gin" - "github.com/coinbase/x402/go/pkg/types" + x402gin "github.com/x402-foundation/x402/go/pkg/gin" + "github.com/x402-foundation/x402/go/pkg/types" ) // TestServerConfig configures how the test facilitator server responds. diff --git a/go/mcp/CHANGELOG.md b/go/mcp/CHANGELOG.md index 311da68e6b..695bf15252 100644 --- a/go/mcp/CHANGELOG.md +++ b/go/mcp/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -All notable changes to the `github.com/coinbase/x402/go/mcp` package will be documented in this file. +All notable changes to the `github.com/x402-foundation/x402/go/mcp` package will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). diff --git a/go/mcp/README.md b/go/mcp/README.md index b08617fde9..dfdcff3dc3 100644 --- a/go/mcp/README.md +++ b/go/mcp/README.md @@ -5,7 +5,7 @@ MCP (Model Context Protocol) integration for the x402 payment protocol. This pac ## Installation ```bash -go get github.com/coinbase/x402/go/mcp +go get github.com/x402-foundation/x402/go/mcp ``` ## Quick Start @@ -17,7 +17,7 @@ package main import ( "context" - "github.com/coinbase/x402/go/mcp" + "github.com/x402-foundation/x402/go/mcp" mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp" ) @@ -55,7 +55,7 @@ import ( "context" "fmt" "log" - "github.com/coinbase/x402/go/mcp" + "github.com/x402-foundation/x402/go/mcp" mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp" ) diff --git a/go/mcp/client.go b/go/mcp/client.go index 3ad09dbbcb..97ef2968bb 100644 --- a/go/mcp/client.go +++ b/go/mcp/client.go @@ -5,9 +5,9 @@ import ( "encoding/json" "fmt" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) // MCPCaller is the interface for making MCP tool calls. diff --git a/go/mcp/client_test.go b/go/mcp/client_test.go index 5b6e1267b9..e62a842947 100644 --- a/go/mcp/client_test.go +++ b/go/mcp/client_test.go @@ -7,9 +7,9 @@ import ( "fmt" "testing" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) // mockMCPCaller implements MCPCaller for testing. diff --git a/go/mcp/doc.go b/go/mcp/doc.go index 02686c968f..001117ed46 100644 --- a/go/mcp/doc.go +++ b/go/mcp/doc.go @@ -8,7 +8,7 @@ // // import ( // "context" -// "github.com/coinbase/x402/go/mcp" +// "github.com/x402-foundation/x402/go/mcp" // mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp" // ) // @@ -30,8 +30,8 @@ // // import ( // "context" -// x402 "github.com/coinbase/x402/go" -// "github.com/coinbase/x402/go/mcp" +// x402 "github.com/x402-foundation/x402/go" +// "github.com/x402-foundation/x402/go/mcp" // ) // // // Create resource server @@ -63,7 +63,7 @@ // // This package re-exports commonly used types from the x402 core package for convenience: // -// import "github.com/coinbase/x402/go/mcp" +// import "github.com/x402-foundation/x402/go/mcp" // // // Re-exported types available: // // - x402.X402Client (via x402 package) diff --git a/go/mcp/integration_test.go b/go/mcp/integration_test.go new file mode 100644 index 0000000000..64e3a87169 --- /dev/null +++ b/go/mcp/integration_test.go @@ -0,0 +1,317 @@ +package mcp + +import ( + "context" + "encoding/json" + "errors" + "fmt" + "testing" + + "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" +) + +// integrationMCPCaller bridges client → server in-process for integration tests. +// It routes CallTool calls through the server's registered tool handlers. +type integrationMCPCaller struct { + handlers map[string]ToolHandler +} + +func (m *integrationMCPCaller) CallTool(ctx context.Context, params *mcp.CallToolParams) (*mcp.CallToolResult, error) { + handler, ok := m.handlers[params.Name] + if !ok { + return nil, fmt.Errorf("tool %q not found", params.Name) + } + + argsBytes, _ := json.Marshal(params.Arguments) + + req := &mcp.CallToolRequest{ + Params: &mcp.CallToolParamsRaw{ + Name: params.Name, + Arguments: argsBytes, + Meta: params.Meta, + }, + } + return handler(ctx, req) +} + +// setupIntegrationServer creates a resource server with mock facilitator and scheme, +// initializes it, and returns the server along with the mock facilitator for assertions. +func setupIntegrationServer(t *testing.T, facilitator *mockFacilitatorClient) *x402.X402ResourceServer { + t.Helper() + if facilitator == nil { + facilitator = &mockFacilitatorClient{} + } + schemeServer := &mockSchemeNetworkServer{scheme: "cash"} + + server := x402.Newx402ResourceServer( + x402.WithFacilitatorClient(facilitator), + x402.WithSchemeServer("x402:cash", schemeServer), + ) + if err := server.Initialize(context.Background()); err != nil { + t.Fatalf("Failed to initialize server: %v", err) + } + return server +} + +var integrationAccepts = []types.PaymentRequirements{ + { + Scheme: "cash", + Network: "x402:cash", + Amount: "1000", + PayTo: "test-recipient", + }, +} + +// TestIntegration_FreeToolWithoutPayment verifies that free (unwrapped) tools +// can be called without any payment interaction. +func TestIntegration_FreeToolWithoutPayment(t *testing.T) { + caller := &integrationMCPCaller{ + handlers: map[string]ToolHandler{ + "ping": func(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) { + return &mcp.CallToolResult{ + Content: []mcp.Content{&mcp.TextContent{Text: "pong"}}, + }, nil + }, + }, + } + + paymentClient := x402.Newx402Client() + client := NewX402MCPClient(caller, paymentClient, Options{}) + + result, err := client.CallTool(context.Background(), "ping", map[string]interface{}{}) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + if result.PaymentMade { + t.Error("Expected no payment for free tool") + } + if result.IsError { + t.Error("Expected success result") + } + if len(result.Content) == 0 || result.Content[0].Text != "pong" { + t.Errorf("Expected content 'pong', got %v", result.Content) + } +} + +// TestIntegration_PaidToolAutoPayment verifies the full paid tool flow: +// first call returns 402, client auto-pays, second call succeeds with settlement. +func TestIntegration_PaidToolAutoPayment(t *testing.T) { + facilitator := &mockFacilitatorClient{} + resourceServer := setupIntegrationServer(t, facilitator) + + wrapper := NewPaymentWrapper(resourceServer, PaymentWrapperConfig{ + Accepts: integrationAccepts, + Resource: &ResourceInfo{ + URL: "mcp://tool/get_weather", + Description: "Get weather", + MimeType: "application/json", + }, + }) + + weatherHandler := wrapper.Wrap(func(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) { + return &mcp.CallToolResult{ + Content: []mcp.Content{&mcp.TextContent{Text: `{"city":"SF","weather":"sunny"}`}}, + }, nil + }) + + caller := &integrationMCPCaller{ + handlers: map[string]ToolHandler{ + "get_weather": weatherHandler, + }, + } + + paymentClient := x402.Newx402Client() + schemeClient := &mockSchemeNetworkClient{scheme: "cash"} + paymentClient.Register("x402:cash", schemeClient) + + client := NewX402MCPClient(caller, paymentClient, Options{ + AutoPayment: BoolPtr(true), + }) + + result, err := client.CallTool(context.Background(), "get_weather", map[string]interface{}{"city": "SF"}) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if !result.PaymentMade { + t.Error("Expected PaymentMade to be true") + } + if result.IsError { + t.Error("Expected success result") + } + if result.PaymentResponse == nil { + t.Fatal("Expected PaymentResponse to be set") + } + if result.PaymentResponse.Transaction != "tx123" { + t.Errorf("Expected transaction 'tx123', got '%s'", result.PaymentResponse.Transaction) + } + if len(result.Content) == 0 { + t.Fatal("Expected content") + } + + var weather map[string]interface{} + if err := json.Unmarshal([]byte(result.Content[0].Text), &weather); err != nil { + t.Fatalf("Failed to parse weather content: %v", err) + } + if weather["city"] != "SF" { + t.Errorf("Expected city 'SF', got '%v'", weather["city"]) + } +} + +// TestIntegration_ApprovalHookCalledBeforePayment verifies that OnPaymentRequested +// is called and can approve payment before it proceeds. +func TestIntegration_ApprovalHookCalledBeforePayment(t *testing.T) { + facilitator := &mockFacilitatorClient{} + resourceServer := setupIntegrationServer(t, facilitator) + + wrapper := NewPaymentWrapper(resourceServer, PaymentWrapperConfig{ + Accepts: integrationAccepts, + }) + + weatherHandler := wrapper.Wrap(func(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) { + return &mcp.CallToolResult{ + Content: []mcp.Content{&mcp.TextContent{Text: `{"weather":"sunny"}`}}, + }, nil + }) + + caller := &integrationMCPCaller{ + handlers: map[string]ToolHandler{ + "get_weather": weatherHandler, + }, + } + + paymentClient := x402.Newx402Client() + schemeClient := &mockSchemeNetworkClient{scheme: "cash"} + paymentClient.Register("x402:cash", schemeClient) + + approvalCalled := false + client := NewX402MCPClient(caller, paymentClient, Options{ + AutoPayment: BoolPtr(true), + OnPaymentRequested: func(ctx PaymentRequiredContext) (bool, error) { + approvalCalled = true + if ctx.ToolName != "get_weather" { + t.Errorf("Expected tool name 'get_weather', got '%s'", ctx.ToolName) + } + if len(ctx.PaymentRequired.Accepts) == 0 { + t.Error("Expected payment requirements in hook context") + } + return true, nil + }, + }) + + result, err := client.CallTool(context.Background(), "get_weather", map[string]interface{}{}) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if !approvalCalled { + t.Error("Expected OnPaymentRequested to be called") + } + if !result.PaymentMade { + t.Error("Expected PaymentMade to be true") + } +} + +// TestIntegration_PaymentDeniedViaHook verifies that when OnPaymentRequested +// returns false, payment is denied and the client returns an error. +func TestIntegration_PaymentDeniedViaHook(t *testing.T) { + facilitator := &mockFacilitatorClient{} + resourceServer := setupIntegrationServer(t, facilitator) + + wrapper := NewPaymentWrapper(resourceServer, PaymentWrapperConfig{ + Accepts: integrationAccepts, + }) + + handlerCalled := false + weatherHandler := wrapper.Wrap(func(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) { + handlerCalled = true + return &mcp.CallToolResult{ + Content: []mcp.Content{&mcp.TextContent{Text: `{"weather":"sunny"}`}}, + }, nil + }) + + caller := &integrationMCPCaller{ + handlers: map[string]ToolHandler{ + "get_weather": weatherHandler, + }, + } + + paymentClient := x402.Newx402Client() + schemeClient := &mockSchemeNetworkClient{scheme: "cash"} + paymentClient.Register("x402:cash", schemeClient) + + client := NewX402MCPClient(caller, paymentClient, Options{ + AutoPayment: BoolPtr(true), + OnPaymentRequested: func(ctx PaymentRequiredContext) (bool, error) { + return false, nil // Deny + }, + }) + + _, err := client.CallTool(context.Background(), "get_weather", map[string]interface{}{}) + if err == nil { + t.Fatal("Expected error when payment denied") + } + + var paymentErr *PaymentRequiredError + if !errors.As(err, &paymentErr) { + t.Fatalf("Expected PaymentRequiredError, got %T: %v", err, err) + } + + if handlerCalled { + t.Error("Handler should not be called when payment is denied") + } +} + +// TestIntegration_PaymentVerificationFailure verifies that when the facilitator +// returns isValid: false, the client sees a 402 error after the retry. +func TestIntegration_PaymentVerificationFailure(t *testing.T) { + facilitator := &mockFacilitatorClient{ + verifyFunc: func(ctx context.Context, payloadBytes []byte, requirementsBytes []byte) (*x402.VerifyResponse, error) { + return &x402.VerifyResponse{IsValid: false, InvalidReason: "Insufficient funds"}, nil + }, + } + resourceServer := setupIntegrationServer(t, facilitator) + + wrapper := NewPaymentWrapper(resourceServer, PaymentWrapperConfig{ + Accepts: integrationAccepts, + }) + + handlerCalled := false + weatherHandler := wrapper.Wrap(func(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) { + handlerCalled = true + return &mcp.CallToolResult{ + Content: []mcp.Content{&mcp.TextContent{Text: `{"weather":"sunny"}`}}, + }, nil + }) + + caller := &integrationMCPCaller{ + handlers: map[string]ToolHandler{ + "get_weather": weatherHandler, + }, + } + + paymentClient := x402.Newx402Client() + schemeClient := &mockSchemeNetworkClient{scheme: "cash"} + paymentClient.Register("x402:cash", schemeClient) + + client := NewX402MCPClient(caller, paymentClient, Options{ + AutoPayment: BoolPtr(true), + }) + + result, err := client.CallTool(context.Background(), "get_weather", map[string]interface{}{}) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + // After first 402, client retries with payment. + // Server verifies, fails, returns 402 again. + // Client sees second 402 after already paying, returns the error result. + if !result.IsError { + t.Error("Expected error result due to verification failure") + } + if handlerCalled { + t.Error("Handler should not be called when verification fails") + } +} diff --git a/go/mcp/server.go b/go/mcp/server.go index 9cbfdb543e..5063a20761 100644 --- a/go/mcp/server.go +++ b/go/mcp/server.go @@ -12,9 +12,9 @@ import ( "encoding/json" "fmt" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) // ToolHandler is the function signature for MCP tool handlers. @@ -200,6 +200,7 @@ func (w *PaymentWrapper) paymentRequiredResult(errorMsg string) *mcp.CallToolRes Accepts: w.config.Accepts, Error: errorMsg, Resource: resource, + Extensions: w.config.Extensions, } data, _ := json.Marshal(pr) diff --git a/go/mcp/server_test.go b/go/mcp/server_test.go index 6572f1a45f..0eba7a2ade 100644 --- a/go/mcp/server_test.go +++ b/go/mcp/server_test.go @@ -6,9 +6,9 @@ import ( "fmt" "testing" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) // Mock facilitator client for testing @@ -502,6 +502,129 @@ func TestNewPaymentWrapper_HookErrors_NonFatal(t *testing.T) { } } +func TestNewPaymentWrapper_ExtensionsIncludedIn402(t *testing.T) { + server := x402.Newx402ResourceServer() + + extensions := map[string]interface{}{ + "bazaar": map[string]interface{}{ + "info": map[string]interface{}{ + "input": map[string]interface{}{ + "type": "mcp", + "toolName": "get_weather", + }, + }, + }, + } + + config := PaymentWrapperConfig{ + Accepts: []types.PaymentRequirements{ + {Scheme: "cash", Network: "x402:cash", Amount: "1000", PayTo: "test-recipient"}, + }, + Extensions: extensions, + } + + wrapper := NewPaymentWrapper(server, config) + handler := func(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) { + return &mcp.CallToolResult{}, nil + } + wrapped := wrapper.Wrap(handler) + + ctx := context.Background() + req := makeCallToolRequest(map[string]interface{}{}, mcp.Meta{}) + result, err := wrapped(ctx, req) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if !result.IsError { + t.Error("Expected error result for missing payment") + } + + // Verify structuredContent contains extensions.bazaar + if result.StructuredContent == nil { + t.Fatal("Expected structuredContent to be set") + } + sc, ok := result.StructuredContent.(map[string]interface{}) + if !ok { + t.Fatalf("Expected structuredContent to be a map, got %T", result.StructuredContent) + } + extRaw, ok := sc["extensions"] + if !ok { + t.Fatal("Expected 'extensions' key in structuredContent") + } + extMap, ok := extRaw.(map[string]interface{}) + if !ok { + t.Fatalf("Expected extensions to be a map, got %T", extRaw) + } + bazaarRaw, ok := extMap["bazaar"] + if !ok { + t.Fatal("Expected 'bazaar' key in extensions") + } + bazaarMap, ok := bazaarRaw.(map[string]interface{}) + if !ok { + t.Fatalf("Expected bazaar to be a map, got %T", bazaarRaw) + } + infoRaw, ok := bazaarMap["info"] + if !ok { + t.Fatal("Expected 'info' key in bazaar extension") + } + infoMap, ok := infoRaw.(map[string]interface{}) + if !ok { + t.Fatalf("Expected info to be a map, got %T", infoRaw) + } + inputRaw, ok := infoMap["input"] + if !ok { + t.Fatal("Expected 'input' key in bazaar info") + } + inputMap, ok := inputRaw.(map[string]interface{}) + if !ok { + t.Fatalf("Expected input to be a map, got %T", inputRaw) + } + if inputMap["toolName"] != "get_weather" { + t.Errorf("Expected toolName 'get_weather', got '%v'", inputMap["toolName"]) + } +} + +func TestNewPaymentWrapper_NilExtensionsOmitted(t *testing.T) { + server := x402.Newx402ResourceServer() + + config := PaymentWrapperConfig{ + Accepts: []types.PaymentRequirements{ + {Scheme: "cash", Network: "x402:cash", Amount: "1000", PayTo: "test-recipient"}, + }, + // Extensions not set (nil) + } + + wrapper := NewPaymentWrapper(server, config) + handler := func(ctx context.Context, request *mcp.CallToolRequest) (*mcp.CallToolResult, error) { + return &mcp.CallToolResult{}, nil + } + wrapped := wrapper.Wrap(handler) + + ctx := context.Background() + req := makeCallToolRequest(map[string]interface{}{}, mcp.Meta{}) + result, err := wrapped(ctx, req) + if err != nil { + t.Fatalf("Unexpected error: %v", err) + } + + if !result.IsError { + t.Error("Expected error result for missing payment") + } + + // Verify structuredContent does NOT contain "extensions" key + if result.StructuredContent == nil { + t.Fatal("Expected structuredContent to be set") + } + sc, ok := result.StructuredContent.(map[string]interface{}) + if !ok { + t.Fatalf("Expected structuredContent to be a map, got %T", result.StructuredContent) + } + if _, ok := sc["extensions"]; ok { + t.Error("Expected 'extensions' key to be absent when Extensions is nil") + } +} + func TestNewPaymentWrapper_SettlementFailure(t *testing.T) { mockFacilitator := &mockFacilitatorClient{ settleFunc: func(ctx context.Context, payloadBytes []byte, requirementsBytes []byte) (*x402.SettleResponse, error) { diff --git a/go/mcp/types.go b/go/mcp/types.go index 80e6768b58..df0ff4926b 100644 --- a/go/mcp/types.go +++ b/go/mcp/types.go @@ -1,8 +1,8 @@ package mcp import ( - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) // Protocol constants for MCP x402 payment integration. @@ -99,9 +99,10 @@ type MCPToolCallResult struct { // PaymentWrapperConfig configures payment wrapper behavior type PaymentWrapperConfig struct { - Accepts []types.PaymentRequirements - Resource *ResourceInfo - Hooks *PaymentWrapperHooks + Accepts []types.PaymentRequirements + Resource *ResourceInfo + Hooks *PaymentWrapperHooks + Extensions map[string]interface{} } // ResourceInfo provides resource metadata. Alias for types.ResourceInfo for compatibility. diff --git a/go/mcp/utils.go b/go/mcp/utils.go index 81be1c8c5e..c80378a0f0 100644 --- a/go/mcp/utils.go +++ b/go/mcp/utils.go @@ -5,8 +5,8 @@ import ( "errors" "fmt" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) // ExtractPaymentFromMeta extracts payment payload from MCP request _meta field diff --git a/go/mcp/utils_test.go b/go/mcp/utils_test.go index 65ed43c31e..f8e6abd565 100644 --- a/go/mcp/utils_test.go +++ b/go/mcp/utils_test.go @@ -4,8 +4,8 @@ import ( "encoding/json" "testing" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) func TestExtractPaymentFromMeta(t *testing.T) { diff --git a/go/mechanisms/evm/DEFAULT_ASSET.md b/go/mechanisms/evm/DEFAULT_ASSET.md deleted file mode 100644 index 5313a93c1b..0000000000 --- a/go/mechanisms/evm/DEFAULT_ASSET.md +++ /dev/null @@ -1,98 +0,0 @@ -# Default Assets for EVM Chains - -This document explains how to add a default stablecoin asset for a new EVM chain. - -## Overview - -When a server uses `price: "$0.10"` syntax (USD string pricing), x402 needs to know which stablecoin to use for that chain. The default asset is configured in `constants.go` within the `NetworkConfigs` map. - -## Adding a New Chain - -To add support for a new EVM chain, add an entry to the `NetworkConfigs` map in `constants.go`: - -```go -NetworkConfigs = map[string]NetworkConfig{ - // ... existing chains ... - - // Your New Chain - "eip155:YOUR_CHAIN_ID": { - ChainID: big.NewInt(YOUR_CHAIN_ID), - DefaultAsset: AssetInfo{ - Address: "0xYOUR_STABLECOIN_ADDRESS", - Name: "Token Name", // Must match EIP-712 domain name - Version: "1", // Must match EIP-712 domain version - Decimals: 6, // Token decimals (e.g. 6 for USDC) - // AssetTransferMethod: AssetTransferMethodPermit2, // Uncomment if token doesn't support EIP-3009 - // SupportsEip2612: true, // Set if permit2 token implements EIP-2612 permit() - }, - }, -} -``` - -### Required Fields - -| Field | Description | -|-------|-------------| -| `ChainID` | The chain's numeric ID as `*big.Int` | -| `Address` | Contract address of the stablecoin | -| `Name` | EIP-712 domain name (must match the token's domain separator) | -| `Version` | EIP-712 domain version (must match the token's domain separator) | -| `Decimals` | Token decimal places (typically 6 for USDC) | -| `AssetTransferMethod` | *(Optional)* Transfer method override: set to `AssetTransferMethodPermit2` for tokens that don't support EIP-3009. Omit for EIP-3009 tokens (default behavior). | -| `SupportsEip2612` | *(Optional)* Set to `true` for Permit2 tokens that implement EIP-2612 `permit()`. When true, clients can use gasless EIP-2612 permits for Permit2 approval. When false/absent on a Permit2 token, clients fall back to ERC-20 approval gas sponsoring. Ignored for EIP-3009 tokens. | - -## Asset Transfer Methods - -x402 supports two methods for transferring assets: - -| Method | Use Case | Recommendation | -|--------|----------|----------------| -| **EIP-3009** | Tokens with native `transferWithAuthorization` (e.g., USDC) | **Recommended** (Simplest, truly gasless) | -| **Permit2** | Any ERC-20 token | **Universal Fallback** (Requires one-time approval) | - -### Default Behavior - -If no `AssetTransferMethod` is specified, the system defaults to **EIP-3009**. This maintains backward compatibility with existing deployments. - -## Asset Selection Policy - -The default asset is chosen **per chain** based on the following guidelines: - -1. **Chain-endorsed stablecoin**: If the chain has officially selected or endorsed a stablecoin (e.g., XDAI on Gnosis), that asset should be used. - -2. **No official stance**: If the chain team has not taken a public position on a preferred stablecoin, we encourage the team behind that chain to make the selection and submit a PR. - -3. **Community PRs welcome**: Chain teams and community members may submit PRs to add their chain's default asset, provided: - - The selection aligns with the chain's ecosystem preferences - - The EIP-712 domain parameters are correctly specified - -## Contributing - -To add a new chain's default asset: - -1. Obtain the correct EIP-712 domain `name` and `version` from the token contract -2. Check whether the token supports EIP-3009 (`transferWithAuthorization`): - - If yes: omit `AssetTransferMethod` (EIP-3009 is the default) - - If no: set `AssetTransferMethod: AssetTransferMethodPermit2` -3. For Permit2 tokens, check whether the token supports EIP-2612 (`permit()`): - - If yes: set `SupportsEip2612: true` so clients can use gasless EIP-2612 permits for Permit2 approval - - If no: omit `SupportsEip2612` — clients will fall back to ERC-20 approval gas sponsoring -4. Add the entry to `NetworkConfigs` in `constants.go` -5. Submit a PR with the chain name and rationale for the asset selection - -## Cross-SDK Checklist - -When adding a new chain's default asset, update all three SDKs to maintain parity: - -| SDK | File to edit | What to add | -|-----|-------------|-------------| -| **Go** | `go/mechanisms/evm/constants.go` | Entry in `NetworkConfigs` map | -| **TypeScript** | `typescript/packages/mechanisms/evm/src/exact/server/scheme.ts` | Entry in `stablecoins` map inside `getDefaultAsset()` | -| **Python** | `python/x402/mechanisms/evm/constants.py` | Entry in `NETWORK_CONFIGS` dict | - -All three must use: -- The same CAIP-2 network key (e.g., `eip155:YOUR_CHAIN_ID`) -- The same token contract address -- The same EIP-712 domain `name` and `version` -- The same `decimals` value -- The same asset transfer method (EIP-3009 default, or Permit2 if specified) diff --git a/go/mechanisms/evm/README.md b/go/mechanisms/evm/README.md index 1b0f180e3f..25156092e8 100644 --- a/go/mechanisms/evm/README.md +++ b/go/mechanisms/evm/README.md @@ -18,7 +18,7 @@ The exact scheme is organized by role: **Import Path:** ``` -github.com/coinbase/x402/go/mechanisms/evm/exact/client +github.com/x402-foundation/x402/go/mechanisms/evm/exact/client ``` **Exports:** @@ -31,7 +31,7 @@ github.com/coinbase/x402/go/mechanisms/evm/exact/client **Import Path:** ``` -github.com/coinbase/x402/go/mechanisms/evm/exact/server +github.com/x402-foundation/x402/go/mechanisms/evm/exact/server ``` **Exports:** @@ -43,7 +43,7 @@ github.com/coinbase/x402/go/mechanisms/evm/exact/server **Import Path:** ``` -github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator +github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator ``` **Exports:** @@ -61,14 +61,7 @@ All EVM networks are supported by default. The only consideration is how prices 1. Register a custom money parser in their `ExactEvmScheme` via `RegisterMoneyParser()`, OR 2. Use a chain that has a default asset configuration -Networks with default assets configured: - -- **Base Mainnet**: `eip155:8453` (USDC) -- **Base Sepolia**: `eip155:84532` (USDC) -- **MegaETH Mainnet**: `eip155:4326` (MegaUSD) -- **Monad Mainnet**: `eip155:143` (USDC) - -To add default asset support for additional chains, see [DEFAULT_ASSET.md](./DEFAULT_ASSET.md). +For the current list of chains with default assets configured, see [Default Assets for Dollar-String Pricing](../../../docs/core-concepts/network-and-token-support.mdx#default-assets-for-dollar-string-pricing) in the x402 docs. To add default asset support for a new chain, see [Adding Support for New Networks](../../../docs/core-concepts/network-and-token-support.mdx#adding-support-for-new-networks). ## Scheme Implementation diff --git a/go/mechanisms/evm/batch-settlement/README.md b/go/mechanisms/evm/batch-settlement/README.md new file mode 100644 index 0000000000..5cdf4b89b8 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/README.md @@ -0,0 +1,205 @@ +# Batch-Settlement EVM Scheme (`go/mechanisms/evm/batch-settlement`) + +The **batch-settlement** scheme enables high-throughput, low-cost EVM payments via **stateless unidirectional payment channels**. Clients deposit funds into an onchain escrow once, then sign off-chain **cumulative vouchers** per request. Servers verify vouchers with a fast signature check and claim them onchain in batches at their discretion. + +A single claim transaction can cover many channels at once, and claimed funds are swept to the receiver in a separate `settle` step. The scheme also supports **dynamic pricing**: the client authorizes a max per-request and the server charges only what was actually used. + +See the [scheme specification](https://github.com/x402-foundation/x402/blob/main/specs/schemes/batch-settlement/scheme_batch_settlement_evm.md) for full protocol details. + +## Import Paths + +| Role | Import | +|-------------|------------------------------------------------------------------------------| +| Client | `github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/client` | +| Server | `github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/server` | +| Facilitator | `github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/facilitator` | + +## Client Usage + +Register `BatchSettlementEvmScheme` with an `x402Client`. The client handles deposit, voucher signing, channel-state recovery, and corrective 402 resync transparently. + +```go +import ( + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" +) + +signer, _ := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("EVM_PRIVATE_KEY")) + +scheme := client.NewBatchSettlementEvmScheme(signer, &client.BatchSettlementEvmSchemeOptions{ + DepositMultiplier: 5, +}) + +c := x402.Newx402Client() +c.Register("eip155:*", scheme) +``` + +### Deposit Policy + +Controls how much the client deposits when the channel needs funding: + +| Field | Description | +|---------------------|-------------| +| `DepositMultiplier` | Per-request `amount × multiplier` is deposited (default 5). | +| `DepositStrategy` | Optional callback that overrides the computed amount or returns `Skip: true` to send a voucher-only payload (verify will fail; the caller is opting out of auto top-up). | + +```go +scheme := client.NewBatchSettlementEvmScheme(signer, &client.BatchSettlementEvmSchemeOptions{ + DepositStrategy: func(ctx context.Context, c client.DepositStrategyContext) (client.DepositStrategyResult, error) { + // Cap deposits at 1_000_000 base units. + capped, _ := new(big.Int).SetString("1000000", 10) + proposed, _ := new(big.Int).SetString(c.DepositAmount, 10) + if proposed.Cmp(capped) > 0 { + return client.DepositStrategyResult{Amount: capped.String()}, nil + } + return client.DepositStrategyResult{}, nil // use computed + }, +}) +``` + +### Voucher Signer Delegation + +By default, vouchers are signed by the same key as the payer. For better performance — especially when the payer is a **smart wallet** (EIP-1271) — delegate voucher signing to a dedicated EOA. The scheme commits this address as the channel's `payerAuthorizer`, so the facilitator can verify vouchers via fast ECDSA recovery instead of an onchain `isValidSignature` RPC. + +```go +voucherSigner, _ := evmsigners.NewClientSignerFromPrivateKey(voucherKey) +scheme := client.NewBatchSettlementEvmScheme(signer, &client.BatchSettlementEvmSchemeOptions{ + VoucherSigner: voucherSigner, +}) +``` + +### Cooperative Refund + +Request the server to refund the unclaimed balance on the next request: + +```go +scheme.RequestRefund(channelId) +``` + +The server claims any outstanding vouchers and then executes `refundWithSignature` to return `balance - totalClaimed` to the payer. + +### Persistence + +By default, channel state is stored in memory. For long-lived clients, use `FileClientChannelStorage`: + +```go +import "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + +scheme := client.NewBatchSettlementEvmScheme(signer, &client.BatchSettlementEvmSchemeOptions{ + Storage: client.NewFileClientChannelStorage(batchsettlement.FileChannelStorageOptions{ + Directory: "./channels", + }), +}) +``` + +If state is lost, the client recovers from onchain `channels(channelId)` plus corrective 402s — see the spec's *Recovery After State Loss* section. + +## Server Usage + +Register the scheme with an `x402ResourceServer` and pair it with a `ChannelManager` to handle batched claims, settlements, and refunds. + +```go +import ( + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/server" +) + +scheme := server.NewBatchSettlementEvmScheme(receiverAddress, &server.BatchSettlementEvmSchemeServerConfig{ + ReceiverAuthorizerSigner: receiverAuthorizerSigner, // optional: self-managed authorizer (recommended) + WithdrawDelay: 900, // 15 min – 30 days + Storage: server.NewFileChannelStorage(batchsettlement.FileChannelStorageOptions{ + Directory: "./sessions", + }), +}) + +srv := x402.Newx402ResourceServer().Register("eip155:84532", scheme) + +manager := scheme.CreateChannelManager(facilitatorClient, "eip155:84532") +manager.Start(server.AutoSettlementConfig{ + ClaimIntervalSecs: 60, + SettleIntervalSecs: 300, + RefundIntervalSecs: 3600, + // Refund channels with non-zero balance, no live pending request, and + // idle for at least 1 hour. Inline the predicate so callers can swap in + // their own logic (e.g. balance thresholds, pending-withdrawal flushing). + SelectRefundChannels: func(channels []*server.ChannelSession, ctx server.AutoSettlementContext) ([]*server.ChannelSession, error) { + out := make([]*server.ChannelSession, 0, len(channels)) + for _, c := range channels { + if c.Balance == "" || c.Balance == "0" { + continue + } + if c.PendingRequest != nil && c.PendingRequest.ExpiresAt > ctx.Now { + continue + } + if ctx.Now-c.LastRequestTimestamp < 3600_000 { + continue + } + out = append(out, c) + } + return out, nil + }, +}) + +// On shutdown, drain pending claims: +defer manager.Stop(ctx, &server.StopOptions{Flush: true}) +``` + +### Receiver Authorizer + +The `receiverAuthorizer` signs `ClaimBatch` and `Refund` EIP-712 messages and is committed into the channel's identity at deposit time: + +- **Self-managed** (recommended): pass a `ReceiverAuthorizerSigner` (an EOA you control). Channels survive facilitator changes — any facilitator can relay your signed claims and refunds. +- **Facilitator-delegated**: omit `ReceiverAuthorizerSigner`. The scheme picks up `extra.receiverAuthorizer` advertised by the facilitator's `/supported`. Switching facilitators requires opening **new channels**, so existing channels should be drained first via `ClaimAll()` and `RefundAll()`. + +### Pricing + +Set the route `price` to the per-request maximum. To bill less than the max, use the standard x402 settlement-override mechanism for your HTTP framework — see the framework adapter's documentation. + +## Facilitator Usage + +```go +import ( + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/facilitator" +) + +f := x402.Newx402Facilitator() +f.Register( + []x402.Network{"eip155:84532"}, + facilitator.NewBatchSettlementEvmScheme(evmSigner, authorizerSigner), +) +``` + +The `authorizerSigner` produces the EIP-712 signatures advertised in `/supported.kinds[].extra.receiverAuthorizer`. Servers may delegate to it (see above) or supply their own. The `evmSigner` (the wallet account) submits transactions for `deposit`, `claimWithSignature`, `settle`, and `refundWithSignature` — anyone can submit a valid claim/refund tx, but only the configured signer here will be used by this facilitator. + +## Supported Networks + +| Network | CAIP-2 ID | +|--------------|-----------------| +| Base Mainnet | `eip155:8453` | +| Base Sepolia | `eip155:84532` | + +Requires the x402 batch-settlement contract deployed on the target network. + +## Asset Transfer Methods + +Deposits use one of two onchain transfer methods, controlled by `extra.assetTransferMethod`: + +| Method | Description | +|------------|-------------| +| `eip3009` | `receiveWithAuthorization` — for tokens that support EIP-3009 (e.g. USDC). Default. | +| `permit2` | Universal fallback for any ERC-20 via Uniswap Permit2. | + +Deposits are sponsored by the facilitator (gasless for the client). + +## Examples + +- [Client example](../../../../../examples/go/clients/batch-settlement) +- [Server example](../../../../../examples/go/servers/batch-settlement) +- [Facilitator example](../../../../../examples/go/facilitator/batch-settlement) + +## See Also + +- [Batch-Settlement EVM Scheme Specification](https://github.com/x402-foundation/x402/blob/main/specs/schemes/batch-settlement/scheme_batch_settlement_evm.md) diff --git a/go/mechanisms/evm/batch-settlement/client/eip3009.go b/go/mechanisms/evm/batch-settlement/client/eip3009.go new file mode 100644 index 0000000000..893ee0ac91 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/eip3009.go @@ -0,0 +1,146 @@ +package client + +import ( + "context" + "fmt" + "math/big" + "time" + + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// CreateBatchedEIP3009DepositPayload creates a deposit + voucher payload using ERC-3009. +// Signs ReceiveWithAuthorization for the deposit and a cumulative voucher. +func CreateBatchedEIP3009DepositPayload( + ctx context.Context, + signer evm.ClientEvmSigner, + requirements types.PaymentRequirements, + channelConfig batchsettlement.ChannelConfig, + depositAmount string, + maxClaimableAmount string, + voucherSigner evm.ClientEvmSigner, +) (types.PaymentPayload, error) { + networkStr := string(requirements.Network) + + chainId, err := evm.GetEvmChainId(networkStr) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to get chain ID: %w", err) + } + + // Get asset info for EIP-712 domain + assetInfo, err := evm.GetAssetInfo(networkStr, requirements.Asset) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to get asset info: %w", err) + } + + // Get token domain info + tokenName := assetInfo.Name + tokenVersion := assetInfo.Version + if requirements.Extra != nil { + if name, ok := requirements.Extra["name"].(string); ok { + tokenName = name + } + if ver, ok := requirements.Extra["version"].(string); ok { + tokenVersion = ver + } + } + + deposit, ok := new(big.Int).SetString(depositAmount, 10) + if !ok { + return types.PaymentPayload{}, fmt.Errorf("invalid deposit amount: %s", depositAmount) + } + + // Salt is a random per-deposit value; the actual ERC-3009 nonce is derived + // from (channelId, salt) — the deposit collector reproduces the same hash. + salt, err := evm.CreateNonce() + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to create salt: %w", err) + } + + validAfter, validBefore := evm.CreateValidityWindow(time.Hour) + + // Compute channel ID + channelId, err := batchsettlement.ComputeChannelId(channelConfig, chainId) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to compute channel ID: %w", err) + } + + // Derive the onchain ERC-3009 nonce: keccak256(abi.encode(channelId, salt)). + erc3009Nonce, err := batchsettlement.BuildErc3009DepositNonce(channelId, salt) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to build ERC-3009 nonce: %w", err) + } + nonceBytes, err := evm.HexToBytes(erc3009Nonce) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to parse derived nonce: %w", err) + } + + // Sign ReceiveWithAuthorization + // "to" is the ERC3009DepositCollector, which forwards into the BatchSettlement contract. + erc3009Domain := evm.TypedDataDomain{ + Name: tokenName, + Version: tokenVersion, + ChainID: chainId, + VerifyingContract: requirements.Asset, + } + + erc3009Types := map[string][]evm.TypedDataField{ + "EIP712Domain": { + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "ReceiveWithAuthorization": batchsettlement.ReceiveAuthorizationTypes["ReceiveWithAuthorization"], + } + + erc3009Message := map[string]interface{}{ + "from": signer.Address(), + "to": batchsettlement.ERC3009DepositCollectorAddress, + "value": deposit, + "validAfter": validAfter, + "validBefore": validBefore, + "nonce": nonceBytes, + } + + erc3009Sig, err := signer.SignTypedData(ctx, erc3009Domain, erc3009Types, "ReceiveWithAuthorization", erc3009Message) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to sign ERC-3009 authorization: %w", err) + } + + // Sign voucher (use voucherSigner if provided) + actualVoucherSigner := signer + if voucherSigner != nil { + actualVoucherSigner = voucherSigner + } + + voucher, err := SignVoucher(ctx, actualVoucherSigner, channelId, maxClaimableAmount, networkStr) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to sign voucher: %w", err) + } + + // Build deposit payload + depositPayload := &batchsettlement.BatchSettlementDepositPayload{ + Type: "deposit", + ChannelConfig: channelConfig, + Voucher: *voucher, + Deposit: batchsettlement.BatchSettlementDepositData{ + Amount: depositAmount, + Authorization: batchsettlement.BatchSettlementDepositAuthorization{ + Erc3009Authorization: &batchsettlement.BatchSettlementErc3009Authorization{ + ValidAfter: validAfter.String(), + ValidBefore: validBefore.String(), + Salt: salt, + Signature: evm.BytesToHex(erc3009Sig), + }, + }, + }, + } + + return types.PaymentPayload{ + X402Version: 2, + Payload: depositPayload.ToMap(), + }, nil +} diff --git a/go/mechanisms/evm/batch-settlement/client/extensions.go b/go/mechanisms/evm/batch-settlement/client/extensions.go new file mode 100644 index 0000000000..d7456326b3 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/extensions.go @@ -0,0 +1,291 @@ +package client + +import ( + "context" + "fmt" + "math/big" + "time" + + "github.com/ethereum/go-ethereum/common" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" + exactclient "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + "github.com/x402-foundation/x402/go/types" +) + +// Compile-time assertion: BatchSettlementEvmScheme satisfies the optional +// ExtensionAwareClient interface so x402Client routes payments through the +// extension-aware path when the server's 402 advertises gas-sponsoring keys. +var _ x402.ExtensionAwareClient = (*BatchSettlementEvmScheme)(nil) + +// CreatePaymentPayloadWithExtensions creates a batched payment payload with +// extension awareness when `paymentRequired.extensions` advertises EIP-2612 or +// ERC-20 approval gas sponsoring. +// +// Behavior matches the exact / upto schemes: +// +// 1. Build the base payload (deposit-or-voucher) via the standard +// CreatePaymentPayload flow. +// 2. Skip extension enrichment for non-deposit payloads (vouchers don't +// need a token approve). +// 3. Skip extension enrichment for non-Permit2 deposits (ERC-3009 carries +// its own gas-funded transfer authorization). +// 4. Try EIP-2612 first; on a successful permit signature, attach +// `extensions.eip2612GasSponsoring.info` and return. +// 5. Fall back to ERC-20 approval; on success, attach +// `extensions.erc20ApprovalGasSponsoring.info`. +// 6. If neither extension applies (allowance already sufficient, or token +// does not advertise EIP-712 domain fields), return the base payload. +// +// Implements the optional `x402.ExtensionAwareClient` interface so +// `x402Client.CreatePaymentPayload` calls this path automatically when the +// server's 402 contains extension declarations. +func (c *BatchSettlementEvmScheme) CreatePaymentPayloadWithExtensions( + ctx context.Context, + requirements types.PaymentRequirements, + extensions map[string]interface{}, +) (types.PaymentPayload, error) { + result, err := c.CreatePaymentPayload(ctx, requirements) + if err != nil { + return types.PaymentPayload{}, err + } + + // Vouchers never need a Permit2 approval — the deposit already established + // the channel balance. Voucher payloads have type="voucher" without a + // `deposit` field; bail before attempting extension signing. + if result.Payload != nil { + if typ, _ := result.Payload["type"].(string); typ != "deposit" { + return result, nil + } + } + + // Only Permit2 deposits gas-sponsor through these extensions; ERC-3009 + // deposits authorize the transfer in the same signature. Read + // `assetTransferMethod` from requirements.Extra and fall back to inspecting + // the deposit authorization shape so a missing wire field still routes + // correctly. + isPermit2 := false + if requirements.Extra != nil { + if v, ok := requirements.Extra["assetTransferMethod"].(string); ok && v != "" { + isPermit2 = v == "permit2" + } + } + if !isPermit2 && result.Payload != nil { + if dep, ok := result.Payload["deposit"].(map[string]interface{}); ok { + if auth, ok := dep["authorization"].(map[string]interface{}); ok { + if _, has := auth["permit2Authorization"]; has { + isPermit2 = true + } + } + } + } + if !isPermit2 { + return result, nil + } + + if extData, eipErr := c.trySignEip2612Permit(ctx, requirements, result, extensions); eipErr == nil && extData != nil { + result.Extensions = extData + return result, nil + } + + if extData, erc20Err := c.trySignErc20Approval(ctx, requirements, extensions); erc20Err == nil && extData != nil { + result.Extensions = extData + } + + return result, nil +} + +// trySignEip2612Permit attempts to sign an EIP-2612 permit authorizing Permit2 +// to spend the deposit amount. Returns nil (no error) when the extension is +// not advertised, the token does not expose name/version, the signer cannot +// read on-chain state, or the user already has sufficient Permit2 allowance. +// +// The signed `info.amount` is the BATCH deposit amount (matches what the +// facilitator's `validateBatchEip2612Permit` enforces), not `requirements.Amount` +// (the per-request charge). The deadline is taken from the just-signed Permit2 +// authorization so both signatures share an expiry. +func (c *BatchSettlementEvmScheme) trySignEip2612Permit( + ctx context.Context, + requirements types.PaymentRequirements, + result types.PaymentPayload, + extensions map[string]interface{}, +) (map[string]interface{}, error) { + if extensions == nil { + return nil, nil + } + if _, ok := extensions[eip2612gassponsor.EIP2612GasSponsoring.Key()]; !ok { + return nil, nil + } + + tokenName, _ := requirements.Extra["name"].(string) + tokenVersion, _ := requirements.Extra["version"].(string) + if tokenName == "" || tokenVersion == "" { + // Without explicit name/version on the requirements, the token's + // EIP-712 domain is unknown; skip silently so the request falls + // back to the standard Permit2 path (and 402s with + // `permit2_allowance_required` if the user has no allowance). + return nil, nil + } + + readSigner, ok := c.signer.(evm.ClientEvmSignerWithReadContract) + if !ok { + return nil, nil + } + + chainID, err := evm.GetEvmChainId(string(requirements.Network)) + if err != nil { + return nil, err + } + + tokenAddress := evm.NormalizeAddress(requirements.Asset) + + // Pull `payload.deposit.amount` from the freshly-built batched deposit + // payload. The signed EIP-2612 `info.amount` must equal the BATCH + // deposit (what the facilitator's `validateBatchEip2612Permit` checks), + // not `requirements.Amount` (the per-request charge). + var depositAmount string + if result.Payload != nil { + if dep, ok := result.Payload["deposit"].(map[string]interface{}); ok { + if amt, ok := dep["amount"].(string); ok && amt != "" { + depositAmount = amt + } + } + } + if depositAmount == "" { + return nil, nil + } + + // Allowance short-circuit: if the user has already approved Permit2 for + // at least the deposit amount, no permit is needed. The downstream + // facilitator simulation will succeed without the EIP-2612 segment. + if hasSufficientPermit2Allowance(ctx, readSigner, tokenAddress, c.signer.Address(), depositAmount) { + return nil, nil + } + + // Align EIP-2612 deadline with the just-signed Permit2 authorization + // (`payload.deposit.authorization.permit2Authorization.deadline`) so + // both signatures expire together. Falls back to + // `now + maxTimeoutSeconds` when the field isn't present. + deadline := "" + if result.Payload != nil { + if dep, ok := result.Payload["deposit"].(map[string]interface{}); ok { + if auth, ok := dep["authorization"].(map[string]interface{}); ok { + if permit2, ok := auth["permit2Authorization"].(map[string]interface{}); ok { + if d, ok := permit2["deadline"].(string); ok { + deadline = d + } + } + } + } + } + if deadline == "" { + deadline = fmt.Sprintf("%d", time.Now().Unix()+int64(requirements.MaxTimeoutSeconds)) + } + + info, err := exactclient.SignEip2612Permit( + ctx, + readSigner, + tokenAddress, + tokenName, + tokenVersion, + chainID, + deadline, + depositAmount, + ) + if err != nil { + return nil, err + } + + return map[string]interface{}{ + eip2612gassponsor.EIP2612GasSponsoring.Key(): map[string]interface{}{ + "info": info, + }, + }, nil +} + +// trySignErc20Approval signs an `approve(Permit2, MaxUint256)` transaction for +// tokens that do not support EIP-2612. The signed tx is attached as the +// `erc20ApprovalGasSponsoring` extension; the facilitator broadcasts it via its +// extension signer before calling BatchSettlement.deposit. +func (c *BatchSettlementEvmScheme) trySignErc20Approval( + ctx context.Context, + requirements types.PaymentRequirements, + extensions map[string]interface{}, +) (map[string]interface{}, error) { + if extensions == nil { + return nil, nil + } + if _, ok := extensions[erc20approvalgassponsor.ERC20ApprovalGasSponsoring.Key()]; !ok { + return nil, nil + } + + txSigner, ok := c.signer.(evm.ClientEvmSignerWithTxSigning) + if !ok { + return nil, nil + } + + chainID, err := evm.GetEvmChainId(string(requirements.Network)) + if err != nil { + return nil, err + } + + tokenAddress := evm.NormalizeAddress(requirements.Asset) + + if readSigner, hasRead := c.signer.(evm.ClientEvmSignerWithReadContract); hasRead { + // Approximate the deposit amount with the per-request amount — + // sufficient for the allowance short-circuit since `deposit ≥ + // requirements.Amount` always holds for batched flows. Skip the + // short-circuit when no per-request amount is available. + if requirements.Amount != "" && + hasSufficientPermit2Allowance(ctx, readSigner, tokenAddress, c.signer.Address(), requirements.Amount) { + return nil, nil + } + } + + info, err := exactclient.SignErc20ApprovalTransaction(ctx, txSigner, tokenAddress, chainID) + if err != nil { + return nil, err + } + + return map[string]interface{}{ + erc20approvalgassponsor.ERC20ApprovalGasSponsoring.Key(): map[string]interface{}{ + "info": info, + }, + }, nil +} + +// hasSufficientPermit2Allowance returns true when `owner` has already +// approved at least `requiredAmount` to Permit2 for `tokenAddress`. Returns +// false on any RPC error so we conservatively sign an extension rather than +// silently skipping when the allowance cannot be confirmed. +func hasSufficientPermit2Allowance( + ctx context.Context, + readSigner evm.ClientEvmSignerWithReadContract, + tokenAddress string, + owner string, + requiredAmount string, +) bool { + allowanceResult, err := readSigner.ReadContract( + ctx, + tokenAddress, + evm.ERC20AllowanceABI, + "allowance", + common.HexToAddress(owner), + common.HexToAddress(evm.PERMIT2Address), + ) + if err != nil { + return false + } + allowanceBig, ok := allowanceResult.(*big.Int) + if !ok { + return false + } + required, ok := new(big.Int).SetString(requiredAmount, 10) + if !ok { + return false + } + return allowanceBig.Cmp(required) >= 0 +} diff --git a/go/mechanisms/evm/batch-settlement/client/extensions_test.go b/go/mechanisms/evm/batch-settlement/client/extensions_test.go new file mode 100644 index 0000000000..965f844749 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/extensions_test.go @@ -0,0 +1,303 @@ +package client + +import ( + "context" + "math/big" + "testing" + + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/types" +) + +const ( + extTestNetwork = "eip155:8453" + extTestAsset = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913" // USDC Base + extTestPayTo = "0x3333333333333333333333333333333333333333" + extTestSigner = "0x4444444444444444444444444444444444444444" +) + +// extReadSigner combines mockSigner with read-contract + tx-signing capabilities +// so the extension paths in extensions.go can resolve the signer through the +// `evm.ClientEvmSignerWithReadContract` and `evm.ClientEvmSignerWithTxSigning` +// type assertions. +type extReadSigner struct { + *mockSigner + allowance *big.Int + allowanceErr error + noncesResult *big.Int + noncesErr error + signTxResult []byte + signTxErr error + feesPriority *big.Int + feesMax *big.Int + feesErr error + txCount uint64 + txCountErr error +} + +// ReadContract dispatches based on the function name so we can stub both the +// allowance lookup (for short-circuit checks) and the EIP-2612 nonces() call +// from the same fake signer. +func (r *extReadSigner) ReadContract(_ context.Context, _ string, _ []byte, function string, _ ...interface{}) (interface{}, error) { + switch function { + case "allowance": + if r.allowanceErr != nil { + return nil, r.allowanceErr + } + return r.allowance, nil + case "nonces": + if r.noncesErr != nil { + return nil, r.noncesErr + } + return r.noncesResult, nil + } + return nil, nil +} + +// SignTransaction satisfies ClientEvmSignerWithSignTransaction. The exact +// content doesn't matter — we only assert that the extension info ends up +// attached to the payload, not the binary correctness of the signed tx. +func (r *extReadSigner) SignTransaction(_ context.Context, _ interface{}) ([]byte, error) { + if r.signTxErr != nil { + return nil, r.signTxErr + } + return r.signTxResult, nil +} + +func (r *extReadSigner) GetTransactionCount(_ context.Context, _ string) (uint64, error) { + return r.txCount, r.txCountErr +} + +func (r *extReadSigner) EstimateFeesPerGas(_ context.Context) (*big.Int, *big.Int, error) { + if r.feesErr != nil { + return nil, nil, r.feesErr + } + return r.feesMax, r.feesPriority, nil +} + +func batchedExtSchemeWith(signer evm.ClientEvmSigner) *BatchSettlementEvmScheme { + return NewBatchSettlementEvmScheme(signer, &BatchSettlementEvmSchemeOptions{ + Storage: NewInMemoryClientChannelStorage(), + }) +} + +func extRequirementsPermit2() types.PaymentRequirements { + return types.PaymentRequirements{ + Scheme: "batch-settlement", + Network: extTestNetwork, + Asset: extTestAsset, + Amount: "100", + PayTo: extTestPayTo, + Extra: map[string]interface{}{ + "name": "USDC", + "version": "2", + "assetTransferMethod": "permit2", + "receiverAuthorizer": "0x4444444444444444444444444444444444444444", + }, + MaxTimeoutSeconds: 600, + } +} + +func eip2612OnlyDeclared() map[string]interface{} { + return map[string]interface{}{ + eip2612gassponsor.EIP2612GasSponsoring.Key(): map[string]interface{}{}, + } +} + +func bothExtensionsDeclared() map[string]interface{} { + return map[string]interface{}{ + eip2612gassponsor.EIP2612GasSponsoring.Key(): map[string]interface{}{}, + erc20approvalgassponsor.ERC20ApprovalGasSponsoring.Key(): map[string]interface{}{}, + } +} + +// TestCreatePaymentPayloadWithExtensions_NoExtensionsDeclared confirms that +// when the server's 402 has no extensions, the path is identical to plain +// CreatePaymentPayload — no enrichment, no extra RPC. +func TestCreatePaymentPayloadWithExtensions_NoExtensionsDeclared(t *testing.T) { + signer := &extReadSigner{ + mockSigner: &mockSigner{address: extTestSigner, sig: []byte{0xab}}, + allowance: big.NewInt(0), + } + scheme := batchedExtSchemeWith(signer) + + out, err := scheme.CreatePaymentPayloadWithExtensions( + context.Background(), + extRequirementsPermit2(), + nil, + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if out.Extensions != nil { + t.Fatalf("expected no extensions when none advertised, got %+v", out.Extensions) + } +} + +// TestCreatePaymentPayloadWithExtensions_AllowanceShortCircuit confirms the +// EIP-2612 path is skipped when the user has already approved Permit2 for at +// least the deposit amount. +func TestCreatePaymentPayloadWithExtensions_AllowanceShortCircuit(t *testing.T) { + // Deposit defaults to amount * DefaultDepositMultiplier (5) = 500. + // Allowance of 1e18 is way more than enough → no permit signed. + signer := &extReadSigner{ + mockSigner: &mockSigner{address: extTestSigner, sig: []byte{0xab}}, + allowance: new(big.Int).Exp(big.NewInt(10), big.NewInt(18), nil), + noncesResult: big.NewInt(0), + } + scheme := batchedExtSchemeWith(signer) + + out, err := scheme.CreatePaymentPayloadWithExtensions( + context.Background(), + extRequirementsPermit2(), + eip2612OnlyDeclared(), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if out.Extensions != nil { + t.Fatalf("expected allowance short-circuit (no extensions), got %+v", out.Extensions) + } +} + +// TestCreatePaymentPayloadWithExtensions_Eip2612SignedWhenAllowanceZero +// exercises the happy path: server advertises EIP-2612, user has zero +// allowance, signer can sign typed data → extension is attached with the +// expected DEPOSIT amount (not the per-request requirements.Amount). +func TestCreatePaymentPayloadWithExtensions_Eip2612SignedWhenAllowanceZero(t *testing.T) { + signer := &extReadSigner{ + mockSigner: &mockSigner{address: extTestSigner, sig: make([]byte, 65)}, + allowance: big.NewInt(0), + noncesResult: big.NewInt(0), + } + scheme := batchedExtSchemeWith(signer) + + out, err := scheme.CreatePaymentPayloadWithExtensions( + context.Background(), + extRequirementsPermit2(), + eip2612OnlyDeclared(), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if out.Extensions == nil { + t.Fatal("expected extensions to be attached") + } + raw, ok := out.Extensions[eip2612gassponsor.EIP2612GasSponsoring.Key()] + if !ok { + t.Fatalf("eip2612GasSponsoring missing from extensions: %+v", out.Extensions) + } + wrapper, ok := raw.(map[string]interface{}) + if !ok { + t.Fatalf("extension wrapper has wrong shape: %T", raw) + } + info, ok := wrapper["info"].(*eip2612gassponsor.Info) + if !ok { + t.Fatalf("info has wrong type: %T", wrapper["info"]) + } + // The CRITICAL invariant: amount must equal the DEPOSIT amount, not + // requirements.Amount. The Go facilitator's `validateBatchEip2612Permit` + // rejects mismatches with invalid_batch_settlement_evm_eip2612_amount_mismatch. + wantDeposit := "500" // 100 * DefaultDepositMultiplier (5) + if info.Amount != wantDeposit { + t.Fatalf("info.Amount = %q, want %q (deposit amount, not request amount)", info.Amount, wantDeposit) + } +} + +// TestCreatePaymentPayloadWithExtensions_Eip2612TakesPriorityOverErc20 pins +// priority: when both extensions are advertised, EIP-2612 is tried first; if it +// succeeds, the ERC-20 approval branch is NOT exercised. +func TestCreatePaymentPayloadWithExtensions_Eip2612TakesPriorityOverErc20(t *testing.T) { + signer := &extReadSigner{ + mockSigner: &mockSigner{address: extTestSigner, sig: make([]byte, 65)}, + allowance: big.NewInt(0), + noncesResult: big.NewInt(0), + } + scheme := batchedExtSchemeWith(signer) + + out, err := scheme.CreatePaymentPayloadWithExtensions( + context.Background(), + extRequirementsPermit2(), + bothExtensionsDeclared(), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if _, has := out.Extensions[eip2612gassponsor.EIP2612GasSponsoring.Key()]; !has { + t.Fatal("eip2612GasSponsoring should be attached (priority winner)") + } + if _, has := out.Extensions[erc20approvalgassponsor.ERC20ApprovalGasSponsoring.Key()]; has { + t.Fatal("erc20ApprovalGasSponsoring should NOT be attached when EIP-2612 succeeded") + } +} + +// TestCreatePaymentPayloadWithExtensions_Eip2612SkippedWithoutNameVersion +// confirms that without name/version on requirements.Extra, the token's EIP-712 +// domain is unknown and the client silently skips signing instead of erroring. +// The downstream request will then 402 with permit2_allowance_required (the +// standard Permit2 path's diagnosis). +func TestCreatePaymentPayloadWithExtensions_Eip2612SkippedWithoutNameVersion(t *testing.T) { + signer := &extReadSigner{ + mockSigner: &mockSigner{address: extTestSigner, sig: []byte{0xab}}, + allowance: big.NewInt(0), + } + scheme := batchedExtSchemeWith(signer) + + reqs := extRequirementsPermit2() + delete(reqs.Extra, "name") + delete(reqs.Extra, "version") + + out, err := scheme.CreatePaymentPayloadWithExtensions( + context.Background(), + reqs, + eip2612OnlyDeclared(), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if out.Extensions != nil { + t.Fatalf("expected no extensions without name/version, got %+v", out.Extensions) + } +} + +// TestCreatePaymentPayloadWithExtensions_Eip2612DeadlineFromPermit2 +// verifies the EIP-2612 deadline is taken from the just-signed Permit2 +// authorization (not the fallback `now + maxTimeoutSeconds`). This keeps +// both signatures on the same expiry window. The mockSigner records the +// signed message, so we read the deadline from there. +func TestCreatePaymentPayloadWithExtensions_Eip2612DeadlineFromPermit2(t *testing.T) { + signer := &extReadSigner{ + mockSigner: &mockSigner{address: extTestSigner, sig: make([]byte, 65)}, + allowance: big.NewInt(0), + noncesResult: big.NewInt(0), + } + scheme := batchedExtSchemeWith(signer) + + out, err := scheme.CreatePaymentPayloadWithExtensions( + context.Background(), + extRequirementsPermit2(), + eip2612OnlyDeclared(), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + wrapper := out.Extensions[eip2612gassponsor.EIP2612GasSponsoring.Key()].(map[string]interface{}) + info := wrapper["info"].(*eip2612gassponsor.Info) + // Read the deadline straight off the deposit payload — the alignment + // invariant being tested is that whatever value lands in the Permit2 + // authorization (`payload.deposit.authorization.permit2Authorization.deadline`) + // is reused for the EIP-2612 permit. Inlined here because the helper + // was removed (single-call site) and the path is short. + dep, _ := out.Payload["deposit"].(map[string]interface{}) + auth, _ := dep["authorization"].(map[string]interface{}) + permit2, _ := auth["permit2Authorization"].(map[string]interface{}) + depDeadline, _ := permit2["deadline"].(string) + if depDeadline == "" { + t.Fatal("permit2 deadline missing from deposit payload") + } + if info.Deadline != depDeadline { + t.Fatalf("eip2612 deadline = %q, permit2 deadline = %q — must match", info.Deadline, depDeadline) + } +} diff --git a/go/mechanisms/evm/batch-settlement/client/file_storage.go b/go/mechanisms/evm/batch-settlement/client/file_storage.go new file mode 100644 index 0000000000..64e9bfe2b6 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/file_storage.go @@ -0,0 +1,47 @@ +package client + +import ( + "os" + "path/filepath" + "strings" + + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +// FileClientChannelStorage persists each channel's client context as +// {root}/client/{channelId}.json so sessions survive process restarts. +type FileClientChannelStorage struct { + root string +} + +// NewFileClientChannelStorage returns a file-backed client session storage rooted at opts.Directory. +func NewFileClientChannelStorage(opts batchsettlement.FileChannelStorageOptions) *FileClientChannelStorage { + return &FileClientChannelStorage{root: opts.Directory} +} + +func (s *FileClientChannelStorage) filePath(key string) string { + return filepath.Join(s.root, "client", strings.ToLower(key)+".json") +} + +func (s *FileClientChannelStorage) Get(channelId string) (*BatchSettlementClientContext, error) { + out := &BatchSettlementClientContext{} + ok, err := batchsettlement.ReadJSONFile(s.filePath(channelId), out) + if err != nil { + return nil, err + } + if !ok { + return nil, nil + } + return out, nil +} + +func (s *FileClientChannelStorage) Set(channelId string, ctx *BatchSettlementClientContext) error { + return batchsettlement.WriteJSONAtomic(s.filePath(channelId), ctx) +} + +func (s *FileClientChannelStorage) Delete(channelId string) error { + if err := os.Remove(s.filePath(channelId)); err != nil && !batchsettlement.IsNotExist(err) { + return err + } + return nil +} diff --git a/go/mechanisms/evm/batch-settlement/client/file_storage_test.go b/go/mechanisms/evm/batch-settlement/client/file_storage_test.go new file mode 100644 index 0000000000..3c4b575164 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/file_storage_test.go @@ -0,0 +1,92 @@ +package client + +import ( + "os" + "path/filepath" + "reflect" + "testing" + + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +func newFileStore(t *testing.T) (*FileClientChannelStorage, string) { + t.Helper() + dir := t.TempDir() + return NewFileClientChannelStorage(batchsettlement.FileChannelStorageOptions{Directory: dir}), dir +} + +func TestFileClientStorage_GetMissing(t *testing.T) { + s, _ := newFileStore(t) + got, err := s.Get("missing") + if err != nil { + t.Fatalf("err: %v", err) + } + if got != nil { + t.Fatalf("got %+v", got) + } +} + +func TestFileClientStorage_SetGetRoundTrip(t *testing.T) { + s, _ := newFileStore(t) + in := sampleCtx() + if err := s.Set("ch", in); err != nil { + t.Fatalf("Set: %v", err) + } + got, err := s.Get("ch") + if err != nil { + t.Fatalf("Get: %v", err) + } + if !reflect.DeepEqual(in, got) { + t.Fatalf("mismatch:\nwant %+v\ngot %+v", in, got) + } +} + +func TestFileClientStorage_PathLowercased(t *testing.T) { + s, dir := newFileStore(t) + if err := s.Set("0xABCDEF", sampleCtx()); err != nil { + t.Fatalf("Set: %v", err) + } + expected := filepath.Join(dir, "client", "0xabcdef.json") + if _, err := os.Stat(expected); err != nil { + t.Fatalf("expected file at %s: %v", expected, err) + } +} + +func TestFileClientStorage_GetCaseInsensitiveOnPath(t *testing.T) { + s, _ := newFileStore(t) + _ = s.Set("0xABC", sampleCtx()) + // Get should normalise to the same lowercase path + got, err := s.Get("0xabc") + if err != nil { + t.Fatalf("err: %v", err) + } + if got == nil { + t.Fatal("expected hit on lowercased lookup") + } +} + +func TestFileClientStorage_Delete(t *testing.T) { + s, dir := newFileStore(t) + _ = s.Set("ch", sampleCtx()) + if err := s.Delete("ch"); err != nil { + t.Fatalf("Delete: %v", err) + } + got, _ := s.Get("ch") + if got != nil { + t.Fatalf("post-delete got %+v", got) + } + if err := s.Delete("ch"); err != nil { + t.Fatalf("Delete-missing should not error: %v", err) + } + _ = dir +} + +func TestFileClientStorage_GetMalformed(t *testing.T) { + s, dir := newFileStore(t) + bad := filepath.Join(dir, "client", "ch.json") + _ = os.MkdirAll(filepath.Dir(bad), 0o755) + _ = os.WriteFile(bad, []byte("not json{"), 0o644) + if _, err := s.Get("ch"); err == nil { + t.Fatal("expected error for malformed file") + } +} diff --git a/go/mechanisms/evm/batch-settlement/client/permit2.go b/go/mechanisms/evm/batch-settlement/client/permit2.go new file mode 100644 index 0000000000..a4e7e4c497 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/permit2.go @@ -0,0 +1,142 @@ +package client + +import ( + "context" + "fmt" + "math/big" + "time" + + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// CreateBatchedPermit2DepositPayload builds a deposit + voucher payload that +// funds the channel via the universal Permit2 contract using a channel-bound +// `PermitWitnessTransferFrom` authorization. The witness binds the transfer to +// the derived channelId so the Permit2DepositCollector can verify which +// channel the funds belong to. +func CreateBatchedPermit2DepositPayload( + ctx context.Context, + signer evm.ClientEvmSigner, + requirements types.PaymentRequirements, + channelConfig batchsettlement.ChannelConfig, + depositAmount string, + maxClaimableAmount string, + voucherSigner evm.ClientEvmSigner, +) (types.PaymentPayload, error) { + networkStr := string(requirements.Network) + + chainId, err := evm.GetEvmChainId(networkStr) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to get chain ID: %w", err) + } + + depositBig, ok := new(big.Int).SetString(depositAmount, 10) + if !ok { + return types.PaymentPayload{}, fmt.Errorf("invalid deposit amount: %s", depositAmount) + } + + nonce, err := evm.CreatePermit2Nonce() + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to create permit2 nonce: %w", err) + } + nonceBig, ok := new(big.Int).SetString(nonce, 10) + if !ok { + return types.PaymentPayload{}, fmt.Errorf("invalid permit2 nonce: %s", nonce) + } + + deadline := fmt.Sprintf("%d", time.Now().Unix()+int64(requirements.MaxTimeoutSeconds)) + deadlineBig, ok := new(big.Int).SetString(deadline, 10) + if !ok { + return types.PaymentPayload{}, fmt.Errorf("invalid permit2 deadline: %s", deadline) + } + + channelId, err := batchsettlement.ComputeChannelId(channelConfig, chainId) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to compute channel ID: %w", err) + } + channelIdBytes, err := evm.HexToBytes(channelId) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to parse channel id: %w", err) + } + + tokenAddress := evm.NormalizeAddress(requirements.Asset) + spenderAddress := evm.NormalizeAddress(batchsettlement.Permit2DepositCollectorAddress) + + domain := evm.TypedDataDomain{ + Name: batchsettlement.Permit2DomainName, + ChainID: chainId, + VerifyingContract: batchsettlement.Permit2Address, + } + + // EIP-712 type definitions: include EIP712Domain alongside the witness types + // so the signer can hash the domain separator the same way Permit2 does. + typedDataTypes := map[string][]evm.TypedDataField{ + "EIP712Domain": { + {Name: "name", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "PermitWitnessTransferFrom": batchsettlement.BatchPermit2WitnessTypes["PermitWitnessTransferFrom"], + "TokenPermissions": batchsettlement.BatchPermit2WitnessTypes["TokenPermissions"], + "DepositWitness": batchsettlement.BatchPermit2WitnessTypes["DepositWitness"], + } + + message := map[string]interface{}{ + "permitted": map[string]interface{}{ + "token": tokenAddress, + "amount": depositBig, + }, + "spender": spenderAddress, + "nonce": nonceBig, + "deadline": deadlineBig, + "witness": map[string]interface{}{ + "channelId": channelIdBytes, + }, + } + + signature, err := signer.SignTypedData(ctx, domain, typedDataTypes, "PermitWitnessTransferFrom", message) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to sign permit2 authorization: %w", err) + } + + actualVoucherSigner := signer + if voucherSigner != nil { + actualVoucherSigner = voucherSigner + } + voucher, err := SignVoucher(ctx, actualVoucherSigner, channelId, maxClaimableAmount, networkStr) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to sign voucher: %w", err) + } + + depositPayload := &batchsettlement.BatchSettlementDepositPayload{ + Type: "deposit", + ChannelConfig: channelConfig, + Voucher: *voucher, + Deposit: batchsettlement.BatchSettlementDepositData{ + Amount: depositAmount, + Authorization: batchsettlement.BatchSettlementDepositAuthorization{ + Permit2Authorization: &batchsettlement.BatchSettlementPermit2Authorization{ + From: signer.Address(), + Permitted: batchsettlement.BatchSettlementPermit2TokenPermissions{ + Token: tokenAddress, + Amount: depositAmount, + }, + Spender: spenderAddress, + Nonce: nonce, + Deadline: deadline, + Witness: batchsettlement.BatchSettlementPermit2Witness{ + ChannelId: channelId, + }, + Signature: evm.BytesToHex(signature), + }, + }, + }, + } + + return types.PaymentPayload{ + X402Version: 2, + Payload: depositPayload.ToMap(), + }, nil +} diff --git a/go/mechanisms/evm/batch-settlement/client/refund.go b/go/mechanisms/evm/batch-settlement/client/refund.go new file mode 100644 index 0000000000..fc705ef8ae --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/refund.go @@ -0,0 +1,414 @@ +package client + +import ( + "context" + "encoding/base64" + "encoding/json" + "fmt" + "io" + "math/big" + "net/http" + "regexp" + "strings" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// nonRecoverableRefundErrors are refund-specific server errors that the client +// cannot recover from automatically. Seeing any of these means the user should +// adjust their request (or accept that the channel has nothing left to refund) — +// retrying will not help. Sourced from the canonical constants in +// `batched/errors.go` so a rename there flows through to the client classifier +// without a separate edit. +var nonRecoverableRefundErrors = map[string]struct{}{ + batchsettlement.ErrRefundNoBalance: {}, + batchsettlement.ErrRefundAmountInvalid: {}, + batchsettlement.ErrRefundAmountExceedsBalance: {}, +} + +// RefundOptions configures a cooperative refund call. +type RefundOptions struct { + // Amount is the optional partial refund (token base units, decimal string). + // Omit for a full refund (drains the channel's remaining balance). + Amount string + // HTTPClient is an optional HTTP client (defaults to http.DefaultClient). + HTTPClient *http.Client +} + +// RefundContext is the narrow view of the client scheme that the refund flow needs. +// Defining a structural contract here (rather than depending directly on +// *BatchSettlementEvmScheme) keeps refund.go decoupled and enables alternate implementations +// in tests. +type RefundContext interface { + Storage() ClientChannelStorage + Signer() evm.ClientEvmSigner + VoucherSigner() evm.ClientEvmSigner + BuildChannelConfig(requirements types.PaymentRequirements) (batchsettlement.ChannelConfig, error) + RecoverSession(ctx context.Context, requirements types.PaymentRequirements) (*BatchSettlementClientContext, error) + ProcessCorrectivePaymentRequired(ctx context.Context, errorReason string, accepts []types.PaymentRequirements) (bool, error) +} + +// RefundChannel sends a cooperative refund request to the channel that backs `url`. +// +// Flow: +// 1. Probe the URL with `GET` (no payment) to obtain the route's payment requirements. +// 2. Build the ChannelConfig and resolve the local session (or recover it). +// 3. Sign a zero-charge voucher (maxClaimableAmount = chargedCumulativeAmount) +// with refund=true and the optional refundAmount (partial refund). +// 4. Send the voucher via PAYMENT-SIGNATURE. On a corrective 402, run the +// standard recovery path and retry once. +// 5. Return the parsed SettleResponse from the server. +func RefundChannel(ctx context.Context, scheme RefundContext, url string, options *RefundOptions) (*x402.SettleResponse, error) { + httpClient := http.DefaultClient + var refundAmount string + if options != nil { + if options.HTTPClient != nil { + httpClient = options.HTTPClient + } + var err error + refundAmount, err = normalizeRefundAmount(options.Amount) + if err != nil { + return nil, err + } + } + + requirements, err := probeRefundRequirements(ctx, url, httpClient) + if err != nil { + return nil, err + } + + return executeRefund(ctx, scheme, url, requirements, refundAmount, httpClient) +} + +// UpdateSessionAfterRefund reconciles local session state with the outcome of a +// cooperative refund. Deletes the session when the post-refund balance is zero +// (full refund), otherwise updates balance/chargedCumulativeAmount/totalClaimed +// from the server snapshot (partial refund — channel stays open). +func UpdateSessionAfterRefund(storage ClientChannelStorage, channelKey string, settleExtra map[string]interface{}) error { + parsed, _ := batchsettlement.PaymentResponseExtraFromMap(settleExtra) + + balanceStr := "" + chargedStr := "" + totalClaimedStr := "" + if parsed != nil && parsed.ChannelState != nil { + balanceStr = parsed.ChannelState.Balance + chargedStr = parsed.ChannelState.ChargedCumulativeAmount + totalClaimedStr = parsed.ChannelState.TotalClaimed + } + + var balanceAfter *big.Int + if balanceStr != "" { + if bal, ok := new(big.Int).SetString(balanceStr, 10); ok { + balanceAfter = bal + } + } + + if balanceAfter == nil || balanceAfter.Sign() <= 0 { + return storage.Delete(channelKey) + } + + prev, _ := storage.Get(channelKey) + next := &BatchSettlementClientContext{} + if prev != nil { + *next = *prev + } + next.Balance = balanceAfter.String() + if chargedStr != "" { + next.ChargedCumulativeAmount = chargedStr + } + if totalClaimedStr != "" { + next.TotalClaimed = totalClaimedStr + } + return storage.Set(channelKey, next) +} + +// probeRefundRequirements probes a URL with an unauthenticated GET to retrieve +// batch-settlement payment requirements via the 402 PAYMENT-REQUIRED header. +func probeRefundRequirements(ctx context.Context, url string, httpClient *http.Client) (types.PaymentRequirements, error) { + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return types.PaymentRequirements{}, fmt.Errorf("refund probe: build request: %w", err) + } + resp, err := httpClient.Do(req) + if err != nil { + return types.PaymentRequirements{}, fmt.Errorf("refund probe: %w", err) + } + defer resp.Body.Close() + _, _ = io.Copy(io.Discard, resp.Body) + + if resp.StatusCode != http.StatusPaymentRequired { + return types.PaymentRequirements{}, fmt.Errorf("refund probe expected 402, got %d", resp.StatusCode) + } + + header := resp.Header.Get("PAYMENT-REQUIRED") + if header == "" { + return types.PaymentRequirements{}, fmt.Errorf("refund probe response missing PAYMENT-REQUIRED header") + } + + paymentRequired, err := decodePaymentRequiredHeader(header) + if err != nil { + return types.PaymentRequirements{}, fmt.Errorf("refund probe: decode PAYMENT-REQUIRED: %w", err) + } + + for i := range paymentRequired.Accepts { + if paymentRequired.Accepts[i].Scheme == batchsettlement.SchemeBatched { + req := paymentRequired.Accepts[i] + if req.Extra == nil { + return types.PaymentRequirements{}, fmt.Errorf("refund requires a configured receiverAuthorizer on the receiver") + } + ra, _ := req.Extra["receiverAuthorizer"].(string) + if ra == "" { + return types.PaymentRequirements{}, fmt.Errorf("refund requires a configured receiverAuthorizer on the receiver") + } + return req, nil + } + } + return types.PaymentRequirements{}, fmt.Errorf("no %s payment option at %s", batchsettlement.SchemeBatched, url) +} + +// executeRefund builds and submits the refund voucher, retrying once after a corrective 402. +func executeRefund( + ctx context.Context, + scheme RefundContext, + url string, + requirements types.PaymentRequirements, + refundAmount string, + httpClient *http.Client, +) (*x402.SettleResponse, error) { + const maxAttempts = 2 + + for attempt := 1; attempt <= maxAttempts; attempt++ { + voucherPayload, err := buildRefundVoucherPayload(ctx, scheme, requirements, refundAmount) + if err != nil { + return nil, err + } + + signatureHeader, err := encodePaymentSignatureHeader(voucherPayload, requirements) + if err != nil { + return nil, fmt.Errorf("refund: encode PAYMENT-SIGNATURE: %w", err) + } + + req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + if err != nil { + return nil, fmt.Errorf("refund: build request: %w", err) + } + req.Header.Set("PAYMENT-SIGNATURE", signatureHeader) + + resp, err := httpClient.Do(req) + if err != nil { + return nil, fmt.Errorf("refund: %w", err) + } + + if resp.StatusCode == http.StatusPaymentRequired { + // A 402 may carry either a PAYMENT-RESPONSE (settle aborted with a structured + // SettleResponse) or a PAYMENT-REQUIRED (verify aborted with corrective hints). + // Settle-side aborts for refunds are non-recoverable, so fail fast instead of retrying. + settleHeader := resp.Header.Get("PAYMENT-RESPONSE") + func() { + defer resp.Body.Close() + _, _ = io.Copy(io.Discard, resp.Body) + }() + if settleHeader != "" { + settle, decErr := decodePaymentResponseHeader(settleHeader) + if decErr != nil { + return nil, fmt.Errorf("refund: decode PAYMENT-RESPONSE: %w", decErr) + } + return nil, fmt.Errorf("%s", formatRefundFailure(settle)) + } + + requiredHeader := resp.Header.Get("PAYMENT-REQUIRED") + if requiredHeader == "" { + return nil, fmt.Errorf("refund 402 missing PAYMENT-REQUIRED header") + } + paymentRequired, err := decodePaymentRequiredHeader(requiredHeader) + if err != nil { + return nil, fmt.Errorf("refund: decode corrective PAYMENT-REQUIRED: %w", err) + } + if _, nonRecoverable := nonRecoverableRefundErrors[paymentRequired.Error]; nonRecoverable { + return nil, fmt.Errorf("refund failed: %s", paymentRequired.Error) + } + if attempt >= maxAttempts { + return nil, fmt.Errorf("refund failed: server returned 402 after %d attempt(s)", attempt) + } + recovered, recErr := scheme.ProcessCorrectivePaymentRequired(ctx, paymentRequired.Error, paymentRequired.Accepts) + if recErr != nil || !recovered { + reason := paymentRequired.Error + if reason == "" { + reason = "unknown" + } + return nil, fmt.Errorf("refund failed: %s", reason) + } + continue + } + + settleHeader := resp.Header.Get("PAYMENT-RESPONSE") + _, _ = io.Copy(io.Discard, resp.Body) + _ = resp.Body.Close() + if settleHeader == "" { + return nil, fmt.Errorf("refund response missing PAYMENT-RESPONSE header (status %d)", resp.StatusCode) + } + + settle, err := decodePaymentResponseHeader(settleHeader) + if err != nil { + return nil, fmt.Errorf("refund: decode PAYMENT-RESPONSE: %w", err) + } + + // The caller knows it just initiated a refund, so reconcile directly via + // UpdateSessionAfterRefund (deletes on full drain). The channelId is read + // from the nested `channelState` shape. + if settle != nil && settle.Extra != nil { + if cs, ok := settle.Extra["channelState"].(map[string]interface{}); ok { + if channelId, ok := cs["channelId"].(string); ok && channelId != "" { + _ = UpdateSessionAfterRefund(scheme.Storage(), batchsettlement.NormalizeChannelId(channelId), settle.Extra) + } + } + } + return settle, nil + } + + return nil, fmt.Errorf("refund failed: retry budget exhausted") +} + +// buildRefundVoucherPayload builds the voucher payload (zero-charge maxClaimableAmount) for a refund. +func buildRefundVoucherPayload( + ctx context.Context, + scheme RefundContext, + requirements types.PaymentRequirements, + refundAmount string, +) (*types.PaymentPayload, error) { + config, err := scheme.BuildChannelConfig(requirements) + if err != nil { + return nil, fmt.Errorf("refund: build channel config: %w", err) + } + channelId, err := batchsettlement.ComputeChannelId(config, requirements.Network) + if err != nil { + return nil, fmt.Errorf("refund: compute channel ID: %w", err) + } + channelId = batchsettlement.NormalizeChannelId(channelId) + + storage := scheme.Storage() + session, _ := storage.Get(channelId) + if session == nil { + // Try recovery if the signer supports onchain reads. + if _, ok := scheme.Signer().(evm.ClientEvmSignerWithReadContract); ok { + session, err = scheme.RecoverSession(ctx, requirements) + if err != nil { + return nil, fmt.Errorf("refund: recover session: %w", err) + } + } + } + if session == nil { + return nil, fmt.Errorf("refund requires an existing channel session; deposit first or call from a context with an EVM RPC") + } + + charged := session.ChargedCumulativeAmount + if charged == "" { + charged = "0" + } + + // Skip the network round-trip when our local view of the channel already shows + // it is fully drained (balance <= chargedCumulativeAmount). + if session.Balance != "" { + balance, balOk := new(big.Int).SetString(session.Balance, 10) + chargedBig, chargedOk := new(big.Int).SetString(charged, 10) + if balOk && chargedOk && balance.Cmp(chargedBig) <= 0 { + return nil, fmt.Errorf( + "refund failed: channel has no remaining balance (balance=%s, chargedCumulativeAmount=%s)", + session.Balance, charged, + ) + } + } + + voucherSigner := scheme.VoucherSigner() + if voucherSigner == nil { + voucherSigner = scheme.Signer() + } + + voucher, err := SignVoucher(ctx, voucherSigner, channelId, charged, string(requirements.Network)) + if err != nil { + return nil, fmt.Errorf("refund: sign voucher: %w", err) + } + + refundPayload := &batchsettlement.BatchSettlementRefundPayload{ + Type: "refund", + ChannelConfig: config, + Voucher: *voucher, + Amount: refundAmount, + } + + return &types.PaymentPayload{ + X402Version: 2, + Payload: refundPayload.ToMap(), + }, nil +} + +// formatRefundFailure builds a human-readable error message from a settle +// failure response carried in a refund 402 PAYMENT-RESPONSE header. +func formatRefundFailure(settle *x402.SettleResponse) string { + if settle == nil { + return "Refund failed: unknown_settlement_error" + } + reason := settle.ErrorReason + if reason == "" { + reason = "unknown_settlement_error" + } + if settle.ErrorMessage != "" && settle.ErrorMessage != reason { + return fmt.Sprintf("Refund failed: %s: %s", reason, settle.ErrorMessage) + } + return fmt.Sprintf("Refund failed: %s", reason) +} + +// normalizeRefundAmount validates the optional refundAmount argument. +func normalizeRefundAmount(amount string) (string, error) { + if amount == "" { + return "", nil + } + if !regexp.MustCompile(`^\d+$`).MatchString(amount) || amount == "0" { + return "", fmt.Errorf("invalid refund amount %q: must be a positive integer string", amount) + } + return amount, nil +} + +// encodePaymentSignatureHeader marshals a payment payload + accepted requirements +// into the base64 PAYMENT-SIGNATURE header value. +func encodePaymentSignatureHeader(payload *types.PaymentPayload, accepted types.PaymentRequirements) (string, error) { + envelope := map[string]interface{}{ + "x402Version": payload.X402Version, + "accepted": accepted, + "payload": payload.Payload, + } + bytes, err := json.Marshal(envelope) + if err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(bytes), nil +} + +// decodePaymentRequiredHeader decodes a PAYMENT-REQUIRED header into a PaymentRequired struct. +func decodePaymentRequiredHeader(header string) (*x402.PaymentRequired, error) { + decoded, err := base64.StdEncoding.DecodeString(strings.TrimSpace(header)) + if err != nil { + return nil, err + } + var pr x402.PaymentRequired + if err := json.Unmarshal(decoded, &pr); err != nil { + return nil, err + } + return &pr, nil +} + +// decodePaymentResponseHeader decodes a PAYMENT-RESPONSE header into a SettleResponse. +func decodePaymentResponseHeader(header string) (*x402.SettleResponse, error) { + decoded, err := base64.StdEncoding.DecodeString(strings.TrimSpace(header)) + if err != nil { + return nil, err + } + var settle x402.SettleResponse + if err := json.Unmarshal(decoded, &settle); err != nil { + return nil, err + } + return &settle, nil +} diff --git a/go/mechanisms/evm/batch-settlement/client/refund_test.go b/go/mechanisms/evm/batch-settlement/client/refund_test.go new file mode 100644 index 0000000000..fb8ec1cdb3 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/refund_test.go @@ -0,0 +1,673 @@ +package client + +import ( + "context" + "encoding/base64" + "encoding/json" + "errors" + "net/http" + "net/http/httptest" + "strings" + "testing" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// ---------- normalizeRefundAmount ---------- + +func TestNormalizeRefundAmount(t *testing.T) { + cases := []struct { + in string + want string + wantErr bool + }{ + {"", "", false}, + {"1", "1", false}, + {"1000000", "1000000", false}, + {"0", "", true}, + {"-1", "", true}, + {"1.5", "", true}, + {"abc", "", true}, + {" 10 ", "", true}, + } + for _, tc := range cases { + got, err := normalizeRefundAmount(tc.in) + if (err != nil) != tc.wantErr { + t.Fatalf("normalizeRefundAmount(%q): err=%v wantErr=%v", tc.in, err, tc.wantErr) + } + if !tc.wantErr && got != tc.want { + t.Fatalf("normalizeRefundAmount(%q) = %q, want %q", tc.in, got, tc.want) + } + } +} + +// ---------- encodePaymentSignatureHeader ---------- + +func TestEncodePaymentSignatureHeader_RoundTrip(t *testing.T) { + payload := &types.PaymentPayload{ + X402Version: 2, + Payload: map[string]interface{}{"k": "v"}, + } + accepted := types.PaymentRequirements{Scheme: "batch-settlement", Network: "eip155:8453"} + + out, err := encodePaymentSignatureHeader(payload, accepted) + if err != nil { + t.Fatalf("encode: %v", err) + } + decoded, err := base64.StdEncoding.DecodeString(out) + if err != nil { + t.Fatalf("not base64: %v", err) + } + var envelope map[string]interface{} + if err := json.Unmarshal(decoded, &envelope); err != nil { + t.Fatalf("not json: %v", err) + } + if envelope["x402Version"].(float64) != 2 { + t.Fatalf("version = %v", envelope["x402Version"]) + } + if envelope["payload"].(map[string]interface{})["k"] != "v" { + t.Fatalf("payload not preserved: %v", envelope["payload"]) + } +} + +// ---------- decode helpers ---------- + +func TestDecodePaymentRequiredHeader(t *testing.T) { + pr := x402.PaymentRequired{ + X402Version: 2, + Error: "boom", + Accepts: []types.PaymentRequirements{{Scheme: "batch-settlement"}}, + } + raw, _ := json.Marshal(pr) + encoded := base64.StdEncoding.EncodeToString(raw) + got, err := decodePaymentRequiredHeader(" " + encoded + " ") + if err != nil { + t.Fatalf("err: %v", err) + } + if got.Error != "boom" || len(got.Accepts) != 1 { + t.Fatalf("decoded = %+v", got) + } +} + +func TestDecodePaymentRequiredHeader_BadBase64(t *testing.T) { + if _, err := decodePaymentRequiredHeader("!!!not-base64!!!"); err == nil { + t.Fatal("expected error") + } +} + +func TestDecodePaymentRequiredHeader_BadJSON(t *testing.T) { + garbage := base64.StdEncoding.EncodeToString([]byte("not json{")) + if _, err := decodePaymentRequiredHeader(garbage); err == nil { + t.Fatal("expected error") + } +} + +func TestDecodePaymentResponseHeader(t *testing.T) { + settle := x402.SettleResponse{Success: true, Transaction: "0xabc"} + raw, _ := json.Marshal(settle) + encoded := base64.StdEncoding.EncodeToString(raw) + got, err := decodePaymentResponseHeader(encoded) + if err != nil { + t.Fatalf("err: %v", err) + } + if !got.Success || got.Transaction != "0xabc" { + t.Fatalf("decoded = %+v", got) + } +} + +func TestDecodePaymentResponseHeader_Errors(t *testing.T) { + if _, err := decodePaymentResponseHeader("!!!"); err == nil { + t.Fatal("expected base64 error") + } + bad := base64.StdEncoding.EncodeToString([]byte("not json{")) + if _, err := decodePaymentResponseHeader(bad); err == nil { + t.Fatal("expected json error") + } +} + +// ---------- UpdateSessionAfterRefund ---------- + +func TestUpdateSessionAfterRefund_FullRefundDeletes(t *testing.T) { + storage := NewInMemoryClientChannelStorage() + _ = storage.Set("ch", &BatchSettlementClientContext{Balance: "100"}) + err := UpdateSessionAfterRefund(storage, "ch", map[string]interface{}{"balance": "0"}) + if err != nil { + t.Fatalf("err: %v", err) + } + if got, _ := storage.Get("ch"); got != nil { + t.Fatalf("session not deleted: %+v", got) + } +} + +func TestUpdateSessionAfterRefund_MissingBalanceDeletes(t *testing.T) { + storage := NewInMemoryClientChannelStorage() + _ = storage.Set("ch", &BatchSettlementClientContext{Balance: "100"}) + err := UpdateSessionAfterRefund(storage, "ch", map[string]interface{}{}) + if err != nil { + t.Fatalf("err: %v", err) + } + if got, _ := storage.Get("ch"); got != nil { + t.Fatalf("session not deleted: %+v", got) + } +} + +func TestUpdateSessionAfterRefund_PartialRefundUpdates(t *testing.T) { + storage := NewInMemoryClientChannelStorage() + _ = storage.Set("ch", &BatchSettlementClientContext{ + Balance: "1000", + ChargedCumulativeAmount: "100", + TotalClaimed: "100", + Signature: "0xsig", + }) + err := UpdateSessionAfterRefund(storage, "ch", map[string]interface{}{ + "channelState": map[string]interface{}{ + "balance": "500", + "chargedCumulativeAmount": "200", + "totalClaimed": "150", + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + got, _ := storage.Get("ch") + if got == nil { + t.Fatal("session deleted but should be retained") + } + if got.Balance != "500" || got.ChargedCumulativeAmount != "200" || got.TotalClaimed != "150" { + t.Fatalf("not updated: %+v", got) + } + if got.Signature != "0xsig" { + t.Fatalf("signature lost: %q", got.Signature) + } +} + +func TestUpdateSessionAfterRefund_NoPriorSessionPartial(t *testing.T) { + storage := NewInMemoryClientChannelStorage() + err := UpdateSessionAfterRefund(storage, "ch", map[string]interface{}{ + "channelState": map[string]interface{}{ + "balance": "500", + "chargedCumulativeAmount": "10", + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + got, _ := storage.Get("ch") + if got == nil || got.Balance != "500" { + t.Fatalf("session not seeded: %+v", got) + } +} + +// ---------- probeRefundRequirements (HTTP) ---------- + +func TestProbeRefundRequirements_Non402(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusOK) + })) + defer srv.Close() + if _, err := probeRefundRequirements(context.Background(), srv.URL, http.DefaultClient); err == nil { + t.Fatal("expected error") + } +} + +func TestProbeRefundRequirements_MissingHeader(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusPaymentRequired) + })) + defer srv.Close() + if _, err := probeRefundRequirements(context.Background(), srv.URL, http.DefaultClient); err == nil { + t.Fatal("expected error") + } +} + +func TestProbeRefundRequirements_NoBatchedScheme(t *testing.T) { + pr := x402.PaymentRequired{Accepts: []types.PaymentRequirements{{Scheme: "exact"}}} + raw, _ := json.Marshal(pr) + header := base64.StdEncoding.EncodeToString(raw) + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("PAYMENT-REQUIRED", header) + w.WriteHeader(http.StatusPaymentRequired) + })) + defer srv.Close() + if _, err := probeRefundRequirements(context.Background(), srv.URL, http.DefaultClient); err == nil { + t.Fatal("expected error: no batched scheme") + } +} + +func TestProbeRefundRequirements_MissingReceiverAuthorizer(t *testing.T) { + pr := x402.PaymentRequired{Accepts: []types.PaymentRequirements{{Scheme: batchsettlement.SchemeBatched}}} + raw, _ := json.Marshal(pr) + header := base64.StdEncoding.EncodeToString(raw) + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("PAYMENT-REQUIRED", header) + w.WriteHeader(http.StatusPaymentRequired) + })) + defer srv.Close() + if _, err := probeRefundRequirements(context.Background(), srv.URL, http.DefaultClient); err == nil { + t.Fatal("expected error: missing receiverAuthorizer") + } +} + +func TestProbeRefundRequirements_OK(t *testing.T) { + pr := x402.PaymentRequired{ + Accepts: []types.PaymentRequirements{{ + Scheme: batchsettlement.SchemeBatched, + Extra: map[string]interface{}{"receiverAuthorizer": "0x1"}, + }}, + } + raw, _ := json.Marshal(pr) + header := base64.StdEncoding.EncodeToString(raw) + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("PAYMENT-REQUIRED", header) + w.WriteHeader(http.StatusPaymentRequired) + })) + defer srv.Close() + got, err := probeRefundRequirements(context.Background(), srv.URL, http.DefaultClient) + if err != nil { + t.Fatalf("err: %v", err) + } + if got.Scheme != batchsettlement.SchemeBatched { + t.Fatalf("scheme = %q", got.Scheme) + } +} + +func TestProbeRefundRequirements_BadHeader(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("PAYMENT-REQUIRED", "!!!") + w.WriteHeader(http.StatusPaymentRequired) + })) + defer srv.Close() + if _, err := probeRefundRequirements(context.Background(), srv.URL, http.DefaultClient); err == nil { + t.Fatal("expected decode error") + } +} + +// ---------- buildRefundVoucherPayload via stub RefundContext ---------- + +type fakeRefundContext struct { + storage *InMemoryClientChannelStorage + signer *mockSigner + voucherSigner *mockSigner + config batchsettlement.ChannelConfig + recoverErr error + recovered *BatchSettlementClientContext +} + +func (f *fakeRefundContext) Storage() ClientChannelStorage { return f.storage } +func (f *fakeRefundContext) Signer() evm.ClientEvmSigner { return f.signer } +func (f *fakeRefundContext) VoucherSigner() evm.ClientEvmSigner { + if f.voucherSigner == nil { + return nil + } + return f.voucherSigner +} +func (f *fakeRefundContext) BuildChannelConfig(_ types.PaymentRequirements) (batchsettlement.ChannelConfig, error) { + return f.config, nil +} +func (f *fakeRefundContext) RecoverSession(_ context.Context, _ types.PaymentRequirements) (*BatchSettlementClientContext, error) { + if f.recoverErr != nil { + return nil, f.recoverErr + } + if f.recovered != nil { + _ = f.storage.Set("recovered", f.recovered) + } + return f.recovered, nil +} +func (f *fakeRefundContext) ProcessSettleResponse(_ map[string]interface{}) error { return nil } +func (f *fakeRefundContext) ProcessCorrectivePaymentRequired(_ context.Context, _ string, _ []types.PaymentRequirements) (bool, error) { + return false, nil +} + +func defaultConfig() batchsettlement.ChannelConfig { + return batchsettlement.ChannelConfig{ + Payer: "0x1111111111111111111111111111111111111111", + PayerAuthorizer: "0x2222222222222222222222222222222222222222", + Receiver: "0x3333333333333333333333333333333333333333", + ReceiverAuthorizer: "0x4444444444444444444444444444444444444444", + Token: "0x5555555555555555555555555555555555555555", + WithdrawDelay: 900, + Salt: "0x01", + } +} + +func TestBuildRefundVoucherPayload_NoSession(t *testing.T) { + fctx := &fakeRefundContext{ + storage: NewInMemoryClientChannelStorage(), + signer: &mockSigner{address: "0x1"}, + config: defaultConfig(), + } + _, err := buildRefundVoucherPayload(context.Background(), fctx, types.PaymentRequirements{Network: "eip155:8453"}, "") + if err == nil || !strings.Contains(err.Error(), "existing channel session") { + t.Fatalf("expected missing-session error, got %v", err) + } +} + +func TestBuildRefundVoucherPayload_HasSession(t *testing.T) { + channelId, err := batchsettlement.ComputeChannelId(defaultConfig(), "eip155:8453") + if err != nil { + t.Fatalf("compute: %v", err) + } + storage := NewInMemoryClientChannelStorage() + _ = storage.Set(batchsettlement.NormalizeChannelId(channelId), &BatchSettlementClientContext{ + ChargedCumulativeAmount: "200", + }) + + fctx := &fakeRefundContext{ + storage: storage, + signer: &mockSigner{address: "0x1", sig: []byte{0x99}}, + config: defaultConfig(), + } + payload, err := buildRefundVoucherPayload(context.Background(), fctx, types.PaymentRequirements{Network: "eip155:8453"}, "100") + if err != nil { + t.Fatalf("err: %v", err) + } + body := payload.Payload + if body["type"] != "refund" || body["amount"] != "100" { + t.Fatalf("payload = %+v", body) + } + voucherMap, _ := body["voucher"].(map[string]interface{}) + if voucherMap == nil || voucherMap["maxClaimableAmount"] != "200" { + t.Fatalf("expected charged echoed back as max, got %v", body["voucher"]) + } +} + +func TestBuildRefundVoucherPayload_DefaultsChargedZero(t *testing.T) { + channelId, _ := batchsettlement.ComputeChannelId(defaultConfig(), "eip155:8453") + storage := NewInMemoryClientChannelStorage() + _ = storage.Set(batchsettlement.NormalizeChannelId(channelId), &BatchSettlementClientContext{}) + + fctx := &fakeRefundContext{ + storage: storage, + signer: &mockSigner{address: "0x1", sig: []byte{0x88}}, + config: defaultConfig(), + } + payload, err := buildRefundVoucherPayload(context.Background(), fctx, types.PaymentRequirements{Network: "eip155:8453"}, "") + if err != nil { + t.Fatalf("err: %v", err) + } + voucherMap, _ := payload.Payload["voucher"].(map[string]interface{}) + if voucherMap == nil || voucherMap["maxClaimableAmount"] != "0" { + t.Fatalf("expected voucher.maxClaimableAmount=0, got %v", payload.Payload["voucher"]) + } +} + +func TestBuildRefundVoucherPayload_SignerError(t *testing.T) { + channelId, _ := batchsettlement.ComputeChannelId(defaultConfig(), "eip155:8453") + storage := NewInMemoryClientChannelStorage() + _ = storage.Set(batchsettlement.NormalizeChannelId(channelId), &BatchSettlementClientContext{ChargedCumulativeAmount: "1"}) + + fctx := &fakeRefundContext{ + storage: storage, + signer: &mockSigner{address: "0x1", err: errors.New("kms down")}, + config: defaultConfig(), + } + if _, err := buildRefundVoucherPayload(context.Background(), fctx, types.PaymentRequirements{Network: "eip155:8453"}, ""); err == nil { + t.Fatal("expected signer error") + } +} + +// ---------- RefundChannel end-to-end (light) ---------- + +func TestRefundChannel_BadAmount(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusPaymentRequired) + })) + defer srv.Close() + + fctx := &fakeRefundContext{ + storage: NewInMemoryClientChannelStorage(), + signer: &mockSigner{address: "0x1"}, + config: defaultConfig(), + } + _, err := RefundChannel(context.Background(), fctx, srv.URL, &RefundOptions{Amount: "abc"}) + if err == nil { + t.Fatal("expected amount validation error") + } +} + +func TestRefundChannel_ProbeFailure(t *testing.T) { + // Server returns 500 — probe fails. + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusInternalServerError) + })) + defer srv.Close() + fctx := &fakeRefundContext{ + storage: NewInMemoryClientChannelStorage(), + signer: &mockSigner{address: "0x1"}, + config: defaultConfig(), + } + _, err := RefundChannel(context.Background(), fctx, srv.URL, nil) + if err == nil { + t.Fatal("expected probe error") + } +} + +// ---------- formatRefundFailure ---------- + +func TestFormatRefundFailure_NilSettle(t *testing.T) { + got := formatRefundFailure(nil) + if !strings.Contains(got, "unknown_settlement_error") { + t.Fatalf("got %q", got) + } +} + +func TestFormatRefundFailure_ReasonOnly(t *testing.T) { + got := formatRefundFailure(&x402.SettleResponse{ErrorReason: "boom"}) + if got != "Refund failed: boom" { + t.Fatalf("got %q", got) + } +} + +func TestFormatRefundFailure_ReasonAndMessage(t *testing.T) { + got := formatRefundFailure(&x402.SettleResponse{ErrorReason: "boom", ErrorMessage: "details"}) + if got != "Refund failed: boom: details" { + t.Fatalf("got %q", got) + } +} + +func TestFormatRefundFailure_DropsDuplicateMessage(t *testing.T) { + // When errorMessage == errorReason, don't duplicate. + got := formatRefundFailure(&x402.SettleResponse{ErrorReason: "same", ErrorMessage: "same"}) + if got != "Refund failed: same" { + t.Fatalf("got %q", got) + } +} + +func TestFormatRefundFailure_EmptyDefaults(t *testing.T) { + got := formatRefundFailure(&x402.SettleResponse{}) + if !strings.Contains(got, "unknown_settlement_error") { + t.Fatalf("got %q", got) + } +} + +// ---------- buildRefundVoucherPayload — drained channel short-circuit ---------- + +func TestBuildRefundVoucherPayload_DrainedChannelShortCircuits(t *testing.T) { + channelId, _ := batchsettlement.ComputeChannelId(defaultConfig(), "eip155:8453") + storage := NewInMemoryClientChannelStorage() + _ = storage.Set(batchsettlement.NormalizeChannelId(channelId), &BatchSettlementClientContext{ + Balance: "100", + ChargedCumulativeAmount: "100", // balance <= charged → drained + }) + + fctx := &fakeRefundContext{ + storage: storage, + signer: &mockSigner{address: "0x1", sig: []byte{0x77}}, + config: defaultConfig(), + } + _, err := buildRefundVoucherPayload(context.Background(), fctx, types.PaymentRequirements{Network: "eip155:8453"}, "") + if err == nil || !strings.Contains(err.Error(), "no remaining balance") { + t.Fatalf("expected drained-channel error, got %v", err) + } +} + +func TestBuildRefundVoucherPayload_PartiallyDrainedProceeds(t *testing.T) { + channelId, _ := batchsettlement.ComputeChannelId(defaultConfig(), "eip155:8453") + storage := NewInMemoryClientChannelStorage() + _ = storage.Set(batchsettlement.NormalizeChannelId(channelId), &BatchSettlementClientContext{ + Balance: "1000", + ChargedCumulativeAmount: "100", // 1000 > 100 → has remainder + }) + + fctx := &fakeRefundContext{ + storage: storage, + signer: &mockSigner{address: "0x1", sig: []byte{0x77}}, + config: defaultConfig(), + } + _, err := buildRefundVoucherPayload(context.Background(), fctx, types.PaymentRequirements{Network: "eip155:8453"}, "") + if err != nil { + t.Fatalf("err: %v", err) + } +} + +func TestBuildRefundVoucherPayload_EmptyBalanceBypassesShortCircuit(t *testing.T) { + // session.balance == "" → can't compare → don't short-circuit. + channelId, _ := batchsettlement.ComputeChannelId(defaultConfig(), "eip155:8453") + storage := NewInMemoryClientChannelStorage() + _ = storage.Set(batchsettlement.NormalizeChannelId(channelId), &BatchSettlementClientContext{ + ChargedCumulativeAmount: "100", + }) + + fctx := &fakeRefundContext{ + storage: storage, + signer: &mockSigner{address: "0x1", sig: []byte{0x77}}, + config: defaultConfig(), + } + if _, err := buildRefundVoucherPayload(context.Background(), fctx, types.PaymentRequirements{Network: "eip155:8453"}, ""); err != nil { + t.Fatalf("err: %v", err) + } +} + +// ---------- executeRefund — 402 PAYMENT-RESPONSE handling ---------- + +// fakeRefundContextWithSession is a refund context that pre-seeds a session for the +// channel computed from defaultConfig() so executeRefund can reach the network. +func fakeRefundContextWithSession(charged string) *fakeRefundContext { + channelId, _ := batchsettlement.ComputeChannelId(defaultConfig(), "eip155:8453") + storage := NewInMemoryClientChannelStorage() + _ = storage.Set(batchsettlement.NormalizeChannelId(channelId), &BatchSettlementClientContext{ + Balance: "10000", + ChargedCumulativeAmount: charged, + }) + return &fakeRefundContext{ + storage: storage, + signer: &mockSigner{address: "0x1", sig: []byte{0xaa}}, + config: defaultConfig(), + } +} + +func TestExecuteRefund_402WithPaymentResponseFailsFast(t *testing.T) { + // Settle-side abort: server returns 402 + PAYMENT-RESPONSE → no retry, fail with formatted reason. + settle := x402.SettleResponse{ + Success: false, + ErrorReason: batchsettlement.ErrRefundNoBalance, + ErrorMessage: "Channel drained", + } + settleBytes, _ := json.Marshal(settle) + settleHeader := base64.StdEncoding.EncodeToString(settleBytes) + + calls := 0 + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + calls++ + w.Header().Set("PAYMENT-RESPONSE", settleHeader) + w.WriteHeader(http.StatusPaymentRequired) + })) + defer srv.Close() + + fctx := fakeRefundContextWithSession("100") + _, err := executeRefund(context.Background(), fctx, srv.URL, + types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}, + "", http.DefaultClient) + if err == nil { + t.Fatal("expected error") + } + if !strings.Contains(err.Error(), batchsettlement.ErrRefundNoBalance) { + t.Fatalf("got %v", err) + } + if !strings.Contains(err.Error(), "Channel drained") { + t.Fatalf("expected message in error, got %v", err) + } + if calls != 1 { + t.Fatalf("expected fail-fast (1 call), got %d", calls) + } +} + +func TestExecuteRefund_402WithBadPaymentResponseHeader(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("PAYMENT-RESPONSE", "!!!not-base64!!!") + w.WriteHeader(http.StatusPaymentRequired) + })) + defer srv.Close() + fctx := fakeRefundContextWithSession("100") + _, err := executeRefund(context.Background(), fctx, srv.URL, + types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}, + "", http.DefaultClient) + if err == nil || !strings.Contains(err.Error(), "decode PAYMENT-RESPONSE") { + t.Fatalf("got %v", err) + } +} + +func TestExecuteRefund_NonRecoverableErrorFailsFast(t *testing.T) { + // Verify-side abort with a known non-recoverable error code: don't retry. + pr := x402.PaymentRequired{Error: batchsettlement.ErrRefundAmountInvalid} + prBytes, _ := json.Marshal(pr) + prHeader := base64.StdEncoding.EncodeToString(prBytes) + + calls := 0 + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + calls++ + w.Header().Set("PAYMENT-REQUIRED", prHeader) + w.WriteHeader(http.StatusPaymentRequired) + })) + defer srv.Close() + + fctx := fakeRefundContextWithSession("100") + _, err := executeRefund(context.Background(), fctx, srv.URL, + types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}, + "", http.DefaultClient) + if err == nil || !strings.Contains(err.Error(), batchsettlement.ErrRefundAmountInvalid) { + t.Fatalf("got %v", err) + } + if calls != 1 { + t.Fatalf("expected fail-fast (1 call), got %d", calls) + } +} + +func TestExecuteRefund_RecoverableErrorRetriesAndExhausts(t *testing.T) { + // Recoverable error code (not in non-recoverable set) but recovery returns false → fail with reason. + pr := x402.PaymentRequired{Error: "some_recoverable_thing"} + prBytes, _ := json.Marshal(pr) + prHeader := base64.StdEncoding.EncodeToString(prBytes) + + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.Header().Set("PAYMENT-REQUIRED", prHeader) + w.WriteHeader(http.StatusPaymentRequired) + })) + defer srv.Close() + + fctx := fakeRefundContextWithSession("100") + _, err := executeRefund(context.Background(), fctx, srv.URL, + types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}, + "", http.DefaultClient) + if err == nil || !strings.Contains(err.Error(), "some_recoverable_thing") { + t.Fatalf("got %v", err) + } +} + +func TestExecuteRefund_402MissingHeadersErrors(t *testing.T) { + srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) { + w.WriteHeader(http.StatusPaymentRequired) + })) + defer srv.Close() + + fctx := fakeRefundContextWithSession("100") + _, err := executeRefund(context.Background(), fctx, srv.URL, + types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}, + "", http.DefaultClient) + if err == nil || !strings.Contains(err.Error(), "missing PAYMENT-REQUIRED") { + t.Fatalf("got %v", err) + } +} diff --git a/go/mechanisms/evm/batch-settlement/client/scheme.go b/go/mechanisms/evm/batch-settlement/client/scheme.go new file mode 100644 index 0000000000..08159d5da5 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/scheme.go @@ -0,0 +1,772 @@ +package client + +import ( + "context" + "fmt" + "log" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +const ( + // DefaultDepositMultiplier is the default multiplier for the initial deposit. + // It is applied to the per-request amount. + DefaultDepositMultiplier = 5 + // DefaultWithdrawDelay is the default withdraw delay in seconds (15 min). + DefaultWithdrawDelay = 900 + // DefaultSalt is the default channel salt (zero). + DefaultSalt = "0x0000000000000000000000000000000000000000000000000000000000000000" +) + +// DepositStrategyContext is supplied to a DepositStrategy callback before the +// client signs a deposit authorization. +type DepositStrategyContext struct { + PaymentRequirements types.PaymentRequirements + ChannelConfig batchsettlement.ChannelConfig + ChannelId string + ClientContext *BatchSettlementClientContext + RequestAmount string + MaxClaimableAmount string + CurrentBalance string + MinimumDepositAmount string + DepositAmount string +} + +// DepositStrategyResult is the return value of a DepositStrategy callback. +// +// - Skip=true tells the client to send a voucher-only payload even when the +// channel balance is insufficient. The downstream request will fail at +// verify time; the caller is opting out of auto-top-up. +// - Amount overrides the computed deposit. Must be a positive integer string +// (base units) and at least MinimumDepositAmount, or the call errors. +// - Both empty/zero means "use the SDK-computed amount". +type DepositStrategyResult struct { + Skip bool + Amount string +} + +// DepositStrategy is an optional caller hook for per-request deposit sizing. +type DepositStrategy func(ctx context.Context, c DepositStrategyContext) (DepositStrategyResult, error) + +// BatchSettlementEvmSchemeOptions configures the batched client scheme. +// +// Use `DepositStrategy` for app-specific sizing or skipping. +type BatchSettlementEvmSchemeOptions struct { + // DepositMultiplier is the multiplier applied to the required amount for deposits. + // E.g., 5 means deposit 5× the per-request amount. Defaults to 5. + DepositMultiplier int + // DepositStrategy lets the caller override the computed deposit amount or + // skip the deposit entirely (returning Skip=true sends a voucher-only + // payload that will fail at verify if the channel balance is insufficient). + // Optional. + DepositStrategy DepositStrategy + // Storage is the session persistence backend. Defaults to in-memory. + Storage ClientChannelStorage + // Salt is the channel salt for differentiating identical configs. Defaults to zero. + Salt string + // PayerAuthorizer is the EOA address used for voucher signing (separate from payer). + // Zero address means the payer signs vouchers directly (ERC-1271). + PayerAuthorizer string + // VoucherSigner is an optional separate key for signing vouchers. + VoucherSigner evm.ClientEvmSigner +} + +// BatchSettlementEvmScheme implements SchemeNetworkClient for batched EVM payments. +type BatchSettlementEvmScheme struct { + signer evm.ClientEvmSigner + config BatchSettlementEvmSchemeOptions + storage ClientChannelStorage +} + +// NewBatchSettlementEvmScheme creates a new batched client scheme. +func NewBatchSettlementEvmScheme(signer evm.ClientEvmSigner, config *BatchSettlementEvmSchemeOptions) *BatchSettlementEvmScheme { + cfg := BatchSettlementEvmSchemeOptions{ + DepositMultiplier: DefaultDepositMultiplier, + Salt: DefaultSalt, + } + if config != nil { + if config.DepositMultiplier > 0 { + cfg.DepositMultiplier = config.DepositMultiplier + } + if config.Storage != nil { + cfg.Storage = config.Storage + } + if config.Salt != "" { + cfg.Salt = config.Salt + } + cfg.DepositStrategy = config.DepositStrategy + cfg.PayerAuthorizer = config.PayerAuthorizer + cfg.VoucherSigner = config.VoucherSigner + } + + storage := cfg.Storage + if storage == nil { + storage = NewInMemoryClientChannelStorage() + } + + return &BatchSettlementEvmScheme{ + signer: signer, + config: cfg, + storage: storage, + } +} + +// Scheme returns the scheme identifier. +func (c *BatchSettlementEvmScheme) Scheme() string { + return batchsettlement.SchemeBatched +} + +// CreatePaymentPayload creates a batched payment payload. +// +// The client loads local session state, falls back to onchain recovery when +// storage is empty, then chooses deposit vs voucher from the resulting context. +func (c *BatchSettlementEvmScheme) CreatePaymentPayload( + ctx context.Context, + requirements types.PaymentRequirements, +) (types.PaymentPayload, error) { + channelConfig, err := c.BuildChannelConfig(requirements) + if err != nil { + return types.PaymentPayload{}, err + } + + channelId, err := batchsettlement.ComputeChannelId(channelConfig, requirements.Network) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to compute channel ID: %w", err) + } + channelId = batchsettlement.NormalizeChannelId(channelId) + + session, err := c.storage.Get(channelId) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to get session: %w", err) + } + + // Cold-start recovery: if storage has nothing, try to rebuild from the + // onchain channel record. Best-effort — any error means we proceed as a + // truly fresh deposit. We log the failure so misconfigured signers (e.g. + // no RPC wired) surface immediately instead of silently signing vouchers + // the facilitator will reject as cumulative_below_claimed. + if session == nil { + if _, ok := c.signer.(evm.ClientEvmSignerWithReadContract); ok { + recovered, recErr := c.RecoverSession(ctx, requirements) + if recErr != nil { + log.Printf("[x402 batch-settlement] onchain channel recovery failed: %v "+ + "(proceeding as fresh deposit; this will fail if the channel already has onchain totalClaimed > 0)", recErr) + } else { + session = recovered + } + } + } + + requiredAmount, ok := new(big.Int).SetString(requirements.Amount, 10) + if !ok { + return types.PaymentPayload{}, fmt.Errorf("invalid amount: %s", requirements.Amount) + } + + balance := big.NewInt(0) + baseCumulative := big.NewInt(0) + if session != nil { + if v, ok := new(big.Int).SetString(session.Balance, 10); ok && v != nil { + balance = v + } + if v, ok := new(big.Int).SetString(session.ChargedCumulativeAmount, 10); ok && v != nil { + baseCumulative = v + } + } + + newCumulative := new(big.Int).Add(baseCumulative, requiredAmount) + + needsInitialDeposit := balance.Sign() == 0 + needsTopUp := !needsInitialDeposit && newCumulative.Cmp(balance) > 0 + + if needsInitialDeposit || needsTopUp { + computedDeposit := c.calculateDepositAmount(requiredAmount) + minimumDeposit := new(big.Int).Sub(newCumulative, balance) + if minimumDeposit.Sign() < 0 { + minimumDeposit = big.NewInt(0) + } + strategyCtx := DepositStrategyContext{ + PaymentRequirements: requirements, + ChannelConfig: channelConfig, + ChannelId: channelId, + ClientContext: session, + RequestAmount: requiredAmount.String(), + MaxClaimableAmount: newCumulative.String(), + CurrentBalance: balance.String(), + MinimumDepositAmount: minimumDeposit.String(), + DepositAmount: computedDeposit.String(), + } + resolved, err := c.resolveDepositAmount(ctx, strategyCtx) + if err != nil { + return types.PaymentPayload{}, err + } + if resolved.skip { + return c.createVoucherPayload(ctx, channelId, channelConfig, newCumulative.String(), requirements) + } + return c.createDepositPayload(ctx, channelConfig, resolved.amount, newCumulative.String(), requirements) + } + + return c.createVoucherPayload(ctx, channelId, channelConfig, newCumulative.String(), requirements) +} + +// resolveDepositAmountResult is the internal output of resolveDepositAmount. +type resolveDepositAmountResult struct { + amount string + skip bool +} + +// resolveDepositAmount applies the optional DepositStrategy callback to the +// computed deposit amount. +func (c *BatchSettlementEvmScheme) resolveDepositAmount( + ctx context.Context, + strategyCtx DepositStrategyContext, +) (resolveDepositAmountResult, error) { + if c.config.DepositStrategy == nil { + return resolveDepositAmountResult{amount: strategyCtx.DepositAmount}, nil + } + res, err := c.config.DepositStrategy(ctx, strategyCtx) + if err != nil { + return resolveDepositAmountResult{}, fmt.Errorf("deposit strategy: %w", err) + } + if res.Skip { + return resolveDepositAmountResult{skip: true}, nil + } + if res.Amount == "" { + return resolveDepositAmountResult{amount: strategyCtx.DepositAmount}, nil + } + amount, ok := new(big.Int).SetString(res.Amount, 10) + if !ok || amount.Sign() <= 0 { + return resolveDepositAmountResult{}, fmt.Errorf("depositStrategy must return a positive integer deposit amount, got %q", res.Amount) + } + minimum, _ := new(big.Int).SetString(strategyCtx.MinimumDepositAmount, 10) + if minimum != nil && amount.Cmp(minimum) < 0 { + return resolveDepositAmountResult{}, fmt.Errorf( + "depositStrategy returned %s, below required top-up %s", + amount.String(), minimum.String()) + } + return resolveDepositAmountResult{amount: amount.String()}, nil +} + +// BuildChannelConfig constructs a ChannelConfig from payment requirements and scheme config. +// +// Returns an error when `requirements.Extra["receiverAuthorizer"]` is missing +// or zero — without it the derived channelId would not match the onchain +// channel and the deposit transaction would revert. +func (c *BatchSettlementEvmScheme) BuildChannelConfig(requirements types.PaymentRequirements) (batchsettlement.ChannelConfig, error) { + var receiverAuthorizer string + if requirements.Extra != nil { + if ra, ok := requirements.Extra["receiverAuthorizer"].(string); ok { + receiverAuthorizer = ra + } + } + if receiverAuthorizer == "" || strings.EqualFold(receiverAuthorizer, "0x0000000000000000000000000000000000000000") { + return batchsettlement.ChannelConfig{}, fmt.Errorf("payment requirements must include a non-zero extra.receiverAuthorizer") + } + + withdrawDelay := DefaultWithdrawDelay + if requirements.Extra != nil { + switch v := requirements.Extra["withdrawDelay"].(type) { + case float64: + withdrawDelay = int(v) + case int: + withdrawDelay = v + } + } + + // Authorizer resolution order: + // explicit `PayerAuthorizer` -> `VoucherSigner.Address()` -> `signer.Address()`. + // Falling straight through to the signer when a voucher signer is configured + // would commit the wrong authorizer into the channel and the facilitator + // would later reject vouchers signed by the voucher key. + payerAuthorizer := c.config.PayerAuthorizer + if payerAuthorizer == "" { + if c.config.VoucherSigner != nil { + payerAuthorizer = c.config.VoucherSigner.Address() + } else { + payerAuthorizer = c.signer.Address() + } + } + + return batchsettlement.ChannelConfig{ + Payer: c.signer.Address(), + PayerAuthorizer: payerAuthorizer, + Receiver: requirements.PayTo, + ReceiverAuthorizer: receiverAuthorizer, + Token: requirements.Asset, + WithdrawDelay: withdrawDelay, + Salt: c.config.Salt, + }, nil +} + +// Refund sends a cooperative refund request to the channel that backs `url`. +// On success, the local session is updated (or deleted on full refund) and the +// parsed SettleResponse is returned. +func (c *BatchSettlementEvmScheme) Refund(ctx context.Context, url string, options *RefundOptions) (*x402.SettleResponse, error) { + return RefundChannel(ctx, &refundContextAdapter{scheme: c}, url, options) +} + +// OnPaymentResponse implements x402.PaymentResponseHandler so the transport can +// auto-sync local session state after every paid response. +// +// On a successful settle (HTTP 200 + PAYMENT-RESPONSE), folds the server-tracked +// channel snapshot back into the local session so the next request signs a +// voucher built from the right cumulative base. +// +// On a corrective 402 (PAYMENT-REQUIRED carrying batch_settlement_cumulative_* +// or signature recovery data), runs ProcessCorrectivePaymentRequired and reports +// Recovered=true so the transport retries once with a freshly built payload. +func (c *BatchSettlementEvmScheme) OnPaymentResponse( + ctx context.Context, + prCtx x402.PaymentResponseContext, +) (x402.PaymentResponseResult, error) { + if prCtx.SettleResponse != nil { + if prCtx.SettleResponse.Extra != nil { + if err := c.ProcessSettleResponse(prCtx.SettleResponse.Extra); err != nil { + return x402.PaymentResponseResult{}, fmt.Errorf("process settle response: %w", err) + } + } + return x402.PaymentResponseResult{}, nil + } + + if prCtx.PaymentRequired != nil { + recovered, err := c.ProcessCorrectivePaymentRequired( + ctx, + prCtx.PaymentRequired.Error, + prCtx.PaymentRequired.Accepts, + ) + if err != nil { + return x402.PaymentResponseResult{}, fmt.Errorf("process corrective payment required: %w", err) + } + return x402.PaymentResponseResult{Recovered: recovered}, nil + } + + return x402.PaymentResponseResult{}, nil +} + +// ProcessSettleResponse updates local session state from a settle response. +// It merges present fields into the existing session. +// Refund-specific reconciliation is handled at the refund call site via +// UpdateSessionAfterRefund. +func (c *BatchSettlementEvmScheme) ProcessSettleResponse(settle map[string]interface{}) error { + if settle == nil { + return nil + } + + parsed, _ := batchsettlement.PaymentResponseExtraFromMap(settle) + if parsed == nil || parsed.ChannelState == nil { + return nil + } + cs := parsed.ChannelState + if cs.ChannelId == "" { + return nil + } + channelId := batchsettlement.NormalizeChannelId(cs.ChannelId) + + prev, _ := c.storage.Get(channelId) + next := &BatchSettlementClientContext{} + if prev != nil { + *next = *prev + } + if cs.ChargedCumulativeAmount != "" { + next.ChargedCumulativeAmount = cs.ChargedCumulativeAmount + } + if cs.Balance != "" { + next.Balance = cs.Balance + } + if cs.TotalClaimed != "" { + next.TotalClaimed = cs.TotalClaimed + } + return c.storage.Set(channelId, next) +} + +// HasSession checks if a session exists for the given channel ID. +func (c *BatchSettlementEvmScheme) HasSession(channelId string) bool { + session, _ := c.storage.Get(batchsettlement.NormalizeChannelId(channelId)) + return session != nil +} + +// GetSession returns the session for the given channel ID. +func (c *BatchSettlementEvmScheme) GetSession(channelId string) (*BatchSettlementClientContext, bool) { + session, err := c.storage.Get(batchsettlement.NormalizeChannelId(channelId)) + if err != nil || session == nil { + return nil, false + } + return session, true +} + +// RecoverSession rebuilds a client session from onchain channel state. +// Requires the signer to implement ClientEvmSignerWithReadContract. +// This allows recovery after a cold start or in-memory session loss. +func (c *BatchSettlementEvmScheme) RecoverSession(ctx context.Context, requirements types.PaymentRequirements) (*BatchSettlementClientContext, error) { + readSigner, ok := c.signer.(evm.ClientEvmSignerWithReadContract) + if !ok { + return nil, fmt.Errorf("recoverSession requires ClientEvmSigner with ReadContract capability") + } + + channelConfig, err := c.BuildChannelConfig(requirements) + if err != nil { + return nil, err + } + channelId, err := batchsettlement.ComputeChannelId(channelConfig, requirements.Network) + if err != nil { + return nil, fmt.Errorf("failed to compute channel ID: %w", err) + } + channelId = batchsettlement.NormalizeChannelId(channelId) + + channelIdBytes := common.HexToHash(channelId) + + result, err := readSigner.ReadContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementChannelsABI, + "channels", + channelIdBytes, + ) + if err != nil { + return nil, fmt.Errorf("failed to read channel state: %w", err) + } + + // Parse result: [balance (uint128), totalClaimed (uint128)] + balanceStr := "0" + totalClaimedStr := "0" + if results, ok := result.([]interface{}); ok && len(results) >= 2 { + if bal, ok := results[0].(*big.Int); ok { + balanceStr = bal.String() + } + if tc, ok := results[1].(*big.Int); ok { + totalClaimedStr = tc.String() + } + } + + session := &BatchSettlementClientContext{ + ChargedCumulativeAmount: totalClaimedStr, + Balance: balanceStr, + TotalClaimed: totalClaimedStr, + } + + if err := c.storage.Set(channelId, session); err != nil { + return nil, fmt.Errorf("failed to store recovered session: %w", err) + } + + return session, nil +} + +// ProcessCorrectivePaymentRequired handles a corrective 402 response when the +// client's cumulative base is out of sync. It validates the server-provided +// ChannelState (under accept.Extra) against onchain data and updates the local +// session, falling back to pure onchain recovery if no recovery data is sent. +// Returns true when the session was resynced and the request can be retried. +func (c *BatchSettlementEvmScheme) ProcessCorrectivePaymentRequired( + ctx context.Context, + errorReason string, + accepts []types.PaymentRequirements, +) (bool, error) { + // The corrective recovery handshake arrives under two reasons: + // - batchsettlement.ErrCumulativeAmountMismatch — resource-server-emitted + // (sibling prefix `batch_settlement_*`) + // - batchsettlement.ErrCumulativeBelowClaimed — facilitator-emitted + // (canonical `invalid_batch_settlement_evm_*` form) + // Both signal "your client cumulative is stale; refresh and retry". + if errorReason != batchsettlement.ErrCumulativeAmountMismatch && + errorReason != batchsettlement.ErrCumulativeBelowClaimed { + return false, nil + } + + // Find the batched accept + var accept *types.PaymentRequirements + for i := range accepts { + if accepts[i].Scheme == batchsettlement.SchemeBatched { + accept = &accepts[i] + break + } + } + if accept == nil { + return false, nil + } + + chargedStr, signedStr, sig, ok := readChannelStateFromExtra(accept.Extra) + if !ok { + // No signature-based recovery data — fall back to onchain recovery + return c.recoverFromOnChainState(ctx, *accept) + } + + return c.recoverFromSignature(ctx, *accept, chargedStr, signedStr, sig) +} + +// readChannelStateFromExtra extracts the corrective-402 recovery fields from +// accept.Extra: extra.channelState.chargedCumulativeAmount +// + extra.voucherState.{signedMaxClaimable,signature}. +func readChannelStateFromExtra(ex map[string]interface{}) (charged, signed, sig string, ok bool) { + if ex == nil { + return "", "", "", false + } + cs, isMap := ex["channelState"].(map[string]interface{}) + if !isMap { + return "", "", "", false + } + vs, isMap := ex["voucherState"].(map[string]interface{}) + if !isMap { + return "", "", "", false + } + c, hasC := cs["chargedCumulativeAmount"] + s, hasS := vs["signedMaxClaimable"] + g, hasG := vs["signature"] + if !hasC || !hasS || !hasG { + return "", "", "", false + } + return fmt.Sprintf("%v", c), fmt.Sprintf("%v", s), fmt.Sprintf("%v", g), true +} + +// recoverFromSignature recovers session from a corrective 402 that includes a +// server-provided voucher signature. Verifies the signature was produced by the +// client's own signing key before accepting. +// +// Errors from individual recovery steps are intentionally swallowed (returning +// false), allowing the caller to fall back to alternative recovery or retry. +func (c *BatchSettlementEvmScheme) recoverFromSignature( + ctx context.Context, + accept types.PaymentRequirements, + chargedStr string, + signedStr string, + sig string, +) (bool, error) { + charged, ok := new(big.Int).SetString(chargedStr, 10) + if !ok { + return false, nil //nolint:nilerr // parse failure = unrecoverable + } + signed, ok := new(big.Int).SetString(signedStr, 10) + if !ok { + return false, nil //nolint:nilerr + } + if charged.Cmp(signed) > 0 { + return false, nil + } + + readSigner, ok := c.signer.(evm.ClientEvmSignerWithReadContract) + if !ok { + return false, nil + } + + config, err := c.BuildChannelConfig(accept) + if err != nil { + return false, nil //nolint:nilerr + } + channelId, err := batchsettlement.ComputeChannelId(config, accept.Network) + if err != nil { + return false, nil //nolint:nilerr + } + channelId = batchsettlement.NormalizeChannelId(channelId) + + // Read onchain state to verify + channelIdBytes := common.HexToHash(channelId) + result, err := readSigner.ReadContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementChannelsABI, + "channels", + channelIdBytes, + ) + if err != nil { + return false, nil //nolint:nilerr + } + + var chBalance, chTotalClaimed *big.Int + if results, ok := result.([]interface{}); ok && len(results) >= 2 { + chBalance, _ = results[0].(*big.Int) + chTotalClaimed, _ = results[1].(*big.Int) + } + if chBalance == nil || chTotalClaimed == nil { + return false, nil + } + + // charged must be >= onchain totalClaimed + if charged.Cmp(chTotalClaimed) < 0 { + return false, nil + } + + // Verify the signature was produced by our key + chainId, err := evm.GetEvmChainId(string(accept.Network)) + if err != nil { + return false, nil //nolint:nilerr + } + + sigBytes, err := evm.HexToBytes(sig) + if err != nil { + return false, nil //nolint:nilerr + } + channelIdRawBytes, err := evm.HexToBytes(channelId) + if err != nil { + return false, nil //nolint:nilerr + } + + domain := evm.TypedDataDomain{ + Name: batchsettlement.BatchSettlementDomain.Name, + Version: batchsettlement.BatchSettlementDomain.Version, + ChainID: chainId, + VerifyingContract: batchsettlement.BatchSettlementAddress, + } + + voucherSigner := c.signer + if c.config.VoucherSigner != nil { + voucherSigner = c.config.VoucherSigner + } + + expectedAddr := voucherSigner.Address() + if c.config.PayerAuthorizer != "" { + expectedAddr = c.config.PayerAuthorizer + } + + // Use the facilitator-style verification if the signer supports it + verifiable, isVerifiable := readSigner.(evm.FacilitatorEvmSigner) + if isVerifiable { + valid, verifyErr := verifiable.VerifyTypedData( + ctx, + expectedAddr, + domain, + batchsettlement.VoucherTypes, + "Voucher", + map[string]interface{}{ + "channelId": channelIdRawBytes, + "maxClaimableAmount": signed, + }, + sigBytes, + ) + if verifyErr != nil || !valid { + return false, nil //nolint:nilerr // signature mismatch = not recoverable + } + } + + session := &BatchSettlementClientContext{ + ChargedCumulativeAmount: charged.String(), + SignedMaxClaimable: signed.String(), + Signature: sig, + Balance: chBalance.String(), + TotalClaimed: chTotalClaimed.String(), + } + + if err := c.storage.Set(channelId, session); err != nil { + return false, err + } + + return true, nil +} + +// recoverFromOnChainState recovers session purely from onchain state when no +// server-provided signature is available. The onchain totalClaimed becomes the +// new baseline. +func (c *BatchSettlementEvmScheme) recoverFromOnChainState( + ctx context.Context, + accept types.PaymentRequirements, +) (bool, error) { + _, err := c.RecoverSession(ctx, accept) + if err != nil { + return false, nil //nolint:nilerr // recovery failures are non-fatal + } + return true, nil +} + +func (c *BatchSettlementEvmScheme) createVoucherPayload( + ctx context.Context, + channelId string, + channelConfig batchsettlement.ChannelConfig, + maxClaimableAmount string, + requirements types.PaymentRequirements, +) (types.PaymentPayload, error) { + networkStr := string(requirements.Network) + + actualSigner := c.signer + if c.config.VoucherSigner != nil { + actualSigner = c.config.VoucherSigner + } + + voucher, err := SignVoucher(ctx, actualSigner, channelId, maxClaimableAmount, networkStr) + if err != nil { + return types.PaymentPayload{}, fmt.Errorf("failed to sign voucher: %w", err) + } + + voucherPayload := &batchsettlement.BatchSettlementVoucherPayload{ + Type: "voucher", + ChannelConfig: channelConfig, + Voucher: *voucher, + } + + return types.PaymentPayload{ + X402Version: 2, + Payload: voucherPayload.ToMap(), + }, nil +} + +// createDepositPayload dispatches the deposit transfer mechanism on +// `requirements.Extra["assetTransferMethod"]`, falling back to EIP-3009 when +// the field is omitted or set to the default value. +func (c *BatchSettlementEvmScheme) createDepositPayload( + ctx context.Context, + channelConfig batchsettlement.ChannelConfig, + depositAmount string, + maxClaimableAmount string, + requirements types.PaymentRequirements, +) (types.PaymentPayload, error) { + method := batchsettlement.AssetTransferMethodEip3009 + if requirements.Extra != nil { + if v, ok := requirements.Extra["assetTransferMethod"].(string); ok && v != "" { + method = batchsettlement.AssetTransferMethod(v) + } + } + switch method { + case batchsettlement.AssetTransferMethodEip3009: + return CreateBatchedEIP3009DepositPayload( + ctx, + c.signer, + requirements, + channelConfig, + depositAmount, + maxClaimableAmount, + c.config.VoucherSigner, + ) + case batchsettlement.AssetTransferMethodPermit2: + return CreateBatchedPermit2DepositPayload( + ctx, + c.signer, + requirements, + channelConfig, + depositAmount, + maxClaimableAmount, + c.config.VoucherSigner, + ) + default: + return types.PaymentPayload{}, fmt.Errorf("unsupported batch-settlement assetTransferMethod: %s", method) + } +} + +// refundContextAdapter wires *BatchSettlementEvmScheme into the RefundContext interface. +type refundContextAdapter struct { + scheme *BatchSettlementEvmScheme +} + +func (a *refundContextAdapter) Storage() ClientChannelStorage { return a.scheme.storage } +func (a *refundContextAdapter) Signer() evm.ClientEvmSigner { return a.scheme.signer } +func (a *refundContextAdapter) VoucherSigner() evm.ClientEvmSigner { + return a.scheme.config.VoucherSigner +} +func (a *refundContextAdapter) BuildChannelConfig(requirements types.PaymentRequirements) (batchsettlement.ChannelConfig, error) { + return a.scheme.BuildChannelConfig(requirements) +} +func (a *refundContextAdapter) RecoverSession(ctx context.Context, requirements types.PaymentRequirements) (*BatchSettlementClientContext, error) { + return a.scheme.RecoverSession(ctx, requirements) +} +func (a *refundContextAdapter) ProcessCorrectivePaymentRequired(ctx context.Context, errorReason string, accepts []types.PaymentRequirements) (bool, error) { + return a.scheme.ProcessCorrectivePaymentRequired(ctx, errorReason, accepts) +} + +// calculateDepositAmount returns `requiredAmount * DepositMultiplier`. Callers +// wanting a cap should use a DepositStrategy callback. +func (c *BatchSettlementEvmScheme) calculateDepositAmount(requiredAmount *big.Int) *big.Int { + multiplier := big.NewInt(int64(c.config.DepositMultiplier)) + return new(big.Int).Mul(requiredAmount, multiplier) +} diff --git a/go/mechanisms/evm/batch-settlement/client/scheme_test.go b/go/mechanisms/evm/batch-settlement/client/scheme_test.go new file mode 100644 index 0000000000..abdbc07f34 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/scheme_test.go @@ -0,0 +1,761 @@ +package client + +import ( + "context" + "errors" + "math/big" + "testing" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +const ( + testNetwork = "eip155:8453" + testAsset = "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913" + testPayTo = "0x3333333333333333333333333333333333333333" + testReceiverAuthorizer = "0x4444444444444444444444444444444444444444" +) + +// readSigner extends mockSigner with ReadContract. +type readSigner struct { + *mockSigner + readResult interface{} + readErr error +} + +func (r *readSigner) ReadContract(_ context.Context, _ string, _ []byte, _ string, _ ...interface{}) (interface{}, error) { + return r.readResult, r.readErr +} + +func defaultRequirements() types.PaymentRequirements { + return types.PaymentRequirements{ + Scheme: batchsettlement.SchemeBatched, + Network: testNetwork, + Asset: testAsset, + Amount: "100", + PayTo: testPayTo, + Extra: map[string]interface{}{ + "name": "USDC", + "version": "2", + "receiverAuthorizer": testReceiverAuthorizer, + }, + } +} + +// ---------- NewBatchSettlementEvmScheme defaults ---------- + +func TestNewBatchSettlementEvmScheme_Defaults(t *testing.T) { + signer := &mockSigner{address: "0x1"} + scheme := NewBatchSettlementEvmScheme(signer, nil) + if scheme.config.DepositMultiplier != DefaultDepositMultiplier { + t.Fatalf("multiplier = %d", scheme.config.DepositMultiplier) + } + if scheme.config.Salt != DefaultSalt { + t.Fatalf("salt = %s", scheme.config.Salt) + } + if scheme.config.DepositStrategy != nil { + t.Fatal("DepositStrategy should be nil by default") + } + if scheme.storage == nil { + t.Fatal("storage default missing") + } + if scheme.Scheme() != batchsettlement.SchemeBatched { + t.Fatalf("Scheme() = %s", scheme.Scheme()) + } +} + +func TestNewBatchSettlementEvmScheme_OverridesConfig(t *testing.T) { + signer := &mockSigner{address: "0x1"} + storage := NewInMemoryClientChannelStorage() + cfg := &BatchSettlementEvmSchemeOptions{ + DepositMultiplier: 7, + Storage: storage, + Salt: "0xfeed", + PayerAuthorizer: "0xPA", + VoucherSigner: &mockSigner{address: "0xV"}, + } + scheme := NewBatchSettlementEvmScheme(signer, cfg) + if scheme.config.DepositMultiplier != 7 { + t.Fatalf("multiplier = %d", scheme.config.DepositMultiplier) + } + if scheme.storage != storage { + t.Fatal("storage should be the explicit one") + } + if scheme.config.Salt != "0xfeed" { + t.Fatalf("salt = %s", scheme.config.Salt) + } + if scheme.config.PayerAuthorizer != "0xPA" { + t.Fatalf("payerAuthorizer = %s", scheme.config.PayerAuthorizer) + } + if scheme.config.VoucherSigner == nil { + t.Fatal("voucherSigner missing") + } +} + +// ---------- BuildChannelConfig ---------- + +func TestBuildChannelConfig_DefaultsAndOverrides(t *testing.T) { + signer := &mockSigner{address: "0xSIGNER"} + scheme := NewBatchSettlementEvmScheme(signer, nil) + req := defaultRequirements() + config, err := scheme.BuildChannelConfig(req) + if err != nil { + t.Fatalf("BuildChannelConfig: %v", err) + } + + if config.Payer != "0xSIGNER" || config.PayerAuthorizer != "0xSIGNER" { + t.Fatalf("payer/payerAuthorizer = %s/%s", config.Payer, config.PayerAuthorizer) + } + if config.Receiver != testPayTo || config.ReceiverAuthorizer != testReceiverAuthorizer { + t.Fatalf("receiver/receiverAuthorizer mismatch: %s/%s", config.Receiver, config.ReceiverAuthorizer) + } + if config.Token != testAsset { + t.Fatalf("token = %s", config.Token) + } + if config.WithdrawDelay != DefaultWithdrawDelay { + t.Fatalf("withdrawDelay = %d", config.WithdrawDelay) + } +} + +func TestBuildChannelConfig_ReceiverAuthorizerOverride(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + req := defaultRequirements() + req.Extra["receiverAuthorizer"] = "0x5555555555555555555555555555555555555555" + cfg, err := scheme.BuildChannelConfig(req) + if err != nil { + t.Fatalf("BuildChannelConfig: %v", err) + } + if cfg.ReceiverAuthorizer != "0x5555555555555555555555555555555555555555" { + t.Fatalf("receiverAuthorizer = %s", cfg.ReceiverAuthorizer) + } +} + +func TestBuildChannelConfig_RejectsMissingOrZeroReceiverAuthorizer(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + + req := defaultRequirements() + delete(req.Extra, "receiverAuthorizer") + if _, err := scheme.BuildChannelConfig(req); err == nil { + t.Fatalf("expected error when receiverAuthorizer is missing") + } + + req = defaultRequirements() + req.Extra["receiverAuthorizer"] = "0x0000000000000000000000000000000000000000" + if _, err := scheme.BuildChannelConfig(req); err == nil { + t.Fatalf("expected error when receiverAuthorizer is zero") + } +} + +func TestBuildChannelConfig_WithdrawDelayOverride(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + + for _, v := range []interface{}{float64(1800), int(1800)} { + req := defaultRequirements() + req.Extra["withdrawDelay"] = v + cfg, err := scheme.BuildChannelConfig(req) + if err != nil { + t.Fatalf("%T: %v", v, err) + } + if cfg.WithdrawDelay != 1800 { + t.Fatalf("%T: withdrawDelay = %d", v, cfg.WithdrawDelay) + } + } +} + +func TestBuildChannelConfig_ExplicitPayerAuthorizer(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0xSIG"}, &BatchSettlementEvmSchemeOptions{ + PayerAuthorizer: "0xPA", + }) + cfg, err := scheme.BuildChannelConfig(defaultRequirements()) + if err != nil { + t.Fatalf("BuildChannelConfig: %v", err) + } + if cfg.PayerAuthorizer != "0xPA" { + t.Fatalf("payerAuthorizer = %s", cfg.PayerAuthorizer) + } + if cfg.Payer != "0xSIG" { + t.Fatalf("payer = %s", cfg.Payer) + } +} + +// ---------- calculateDepositAmount ---------- + +func TestCalculateDepositAmount_BasicMultiplier(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + // Default multiplier 5 → 5 * 100 = 500. + got := scheme.calculateDepositAmount(big.NewInt(100)) + if got.Cmp(big.NewInt(500)) != 0 { + t.Fatalf("got %s", got.String()) + } +} + +func TestCalculateDepositAmount_HonorsCustomMultiplier(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, &BatchSettlementEvmSchemeOptions{ + DepositMultiplier: 100, + }) + got := scheme.calculateDepositAmount(big.NewInt(100)) + if got.Cmp(big.NewInt(10_000)) != 0 { + t.Fatalf("got %s", got.String()) + } +} + +// ---------- DepositStrategy ---------- + +func TestDepositStrategy_OverridesAmount(t *testing.T) { + called := false + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, &BatchSettlementEvmSchemeOptions{ + DepositStrategy: func(_ context.Context, c DepositStrategyContext) (DepositStrategyResult, error) { + called = true + // Return a higher deposit than the default. + return DepositStrategyResult{Amount: "999999"}, nil + }, + }) + res, err := scheme.resolveDepositAmount(context.Background(), DepositStrategyContext{ + MinimumDepositAmount: "100", + DepositAmount: "500", + }) + if err != nil || !called { + t.Fatalf("strategy not invoked or err: called=%v err=%v", called, err) + } + if res.amount != "999999" || res.skip { + t.Fatalf("got %+v", res) + } +} + +func TestDepositStrategy_SkipsDeposit(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, &BatchSettlementEvmSchemeOptions{ + DepositStrategy: func(_ context.Context, _ DepositStrategyContext) (DepositStrategyResult, error) { + return DepositStrategyResult{Skip: true}, nil + }, + }) + res, err := scheme.resolveDepositAmount(context.Background(), DepositStrategyContext{ + MinimumDepositAmount: "100", + DepositAmount: "500", + }) + if err != nil || !res.skip { + t.Fatalf("expected skip; got %+v err=%v", res, err) + } +} + +func TestDepositStrategy_RejectsBelowMinimum(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, &BatchSettlementEvmSchemeOptions{ + DepositStrategy: func(_ context.Context, _ DepositStrategyContext) (DepositStrategyResult, error) { + return DepositStrategyResult{Amount: "50"}, nil + }, + }) + _, err := scheme.resolveDepositAmount(context.Background(), DepositStrategyContext{ + MinimumDepositAmount: "100", + DepositAmount: "500", + }) + if err == nil { + t.Fatal("expected error: deposit below minimum") + } +} + +func TestDepositStrategy_DefaultsToComputedAmountWhenStrategyReturnsEmpty(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, &BatchSettlementEvmSchemeOptions{ + DepositStrategy: func(_ context.Context, _ DepositStrategyContext) (DepositStrategyResult, error) { + // Empty Amount with Skip=false → SDK uses computed deposit. + return DepositStrategyResult{}, nil + }, + }) + res, err := scheme.resolveDepositAmount(context.Background(), DepositStrategyContext{ + MinimumDepositAmount: "100", + DepositAmount: "500", + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if res.amount != "500" { + t.Fatalf("expected fallback to 500, got %q", res.amount) + } +} + +// ---------- HasSession / GetSession ---------- + +func TestHasSession_GetSession(t *testing.T) { + storage := NewInMemoryClientChannelStorage() + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, &BatchSettlementEvmSchemeOptions{Storage: storage}) + + if scheme.HasSession("0xMISSING") { + t.Fatal("missing should be false") + } + if _, ok := scheme.GetSession("0xMISSING"); ok { + t.Fatal("missing should not return ok") + } + + _ = storage.Set("0xabc", &BatchSettlementClientContext{Balance: "100"}) + if !scheme.HasSession("0xABC") { + t.Fatal("case-insensitive lookup failed") + } + got, ok := scheme.GetSession("0xABC") + if !ok || got.Balance != "100" { + t.Fatalf("GetSession = %+v ok=%v", got, ok) + } +} + +// ---------- ProcessSettleResponse ---------- + +func TestProcessSettleResponse_NilNoop(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + if err := scheme.ProcessSettleResponse(nil); err != nil { + t.Fatalf("err: %v", err) + } +} + +func TestProcessSettleResponse_StoresSession(t *testing.T) { + storage := NewInMemoryClientChannelStorage() + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, &BatchSettlementEvmSchemeOptions{Storage: storage}) + + err := scheme.ProcessSettleResponse(map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": "0xABC", + "chargedCumulativeAmount": "10", + "balance": "1000", + "totalClaimed": "5", + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + got, _ := storage.Get("0xabc") + if got == nil || got.Balance != "1000" || got.ChargedCumulativeAmount != "10" { + t.Fatalf("session = %+v", got) + } +} + +// ProcessSettleResponse is a pure-merge updater. +// It does NOT delete sessions on zero balance — that responsibility belongs to +// UpdateSessionAfterRefund, called explicitly at the refund call site. +func TestProcessSettleResponse_DoesNotDeleteOnZeroBalance(t *testing.T) { + storage := NewInMemoryClientChannelStorage() + _ = storage.Set("0xabc", &BatchSettlementClientContext{Balance: "100"}) + + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, &BatchSettlementEvmSchemeOptions{Storage: storage}) + err := scheme.ProcessSettleResponse(map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": "0xabc", + "balance": "0", + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + got, _ := storage.Get("0xabc") + if got == nil { + t.Fatal("session unexpectedly deleted by ProcessSettleResponse") + } + if got.Balance != "0" { + t.Fatalf("balance not merged: %+v", got) + } +} + +// ---------- CreatePaymentPayload (deposit + voucher branches) ---------- + +func TestCreatePaymentPayload_FirstRequestDeposit(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1111111111111111111111111111111111111111", sig: []byte{0xaa}}, nil) + payload, err := scheme.CreatePaymentPayload(context.Background(), defaultRequirements()) + if err != nil { + t.Fatalf("err: %v", err) + } + if payload.Payload["type"] != "deposit" { + t.Fatalf("expected deposit, got %v", payload.Payload["type"]) + } +} + +func TestCreatePaymentPayload_VoucherWhenSessionHasFunds(t *testing.T) { + storage := NewInMemoryClientChannelStorage() + signer := &mockSigner{address: "0x1111111111111111111111111111111111111111", sig: []byte{0xab}} + scheme := NewBatchSettlementEvmScheme(signer, &BatchSettlementEvmSchemeOptions{Storage: storage}) + + // Pre-seed session with sufficient funds. + channelConfig, err := scheme.BuildChannelConfig(defaultRequirements()) + if err != nil { + t.Fatalf("BuildChannelConfig: %v", err) + } + channelId, _ := batchsettlement.ComputeChannelId(channelConfig, testNetwork) + channelId = batchsettlement.NormalizeChannelId(channelId) + _ = storage.Set(channelId, &BatchSettlementClientContext{Balance: "1000", ChargedCumulativeAmount: "100"}) + + payload, err := scheme.CreatePaymentPayload(context.Background(), defaultRequirements()) + if err != nil { + t.Fatalf("err: %v", err) + } + if payload.Payload["type"] != "voucher" { + t.Fatalf("expected voucher, got %v", payload.Payload["type"]) + } +} + +func TestCreatePaymentPayload_TopsUpOnInsufficient(t *testing.T) { + storage := NewInMemoryClientChannelStorage() + signer := &mockSigner{address: "0x1111111111111111111111111111111111111111", sig: []byte{0xac}} + scheme := NewBatchSettlementEvmScheme(signer, &BatchSettlementEvmSchemeOptions{Storage: storage}) + + channelConfig, err := scheme.BuildChannelConfig(defaultRequirements()) + if err != nil { + t.Fatalf("BuildChannelConfig: %v", err) + } + channelId, _ := batchsettlement.ComputeChannelId(channelConfig, testNetwork) + channelId = batchsettlement.NormalizeChannelId(channelId) + _ = storage.Set(channelId, &BatchSettlementClientContext{Balance: "50", ChargedCumulativeAmount: "0"}) + + payload, err := scheme.CreatePaymentPayload(context.Background(), defaultRequirements()) + if err != nil { + t.Fatalf("err: %v", err) + } + if payload.Payload["type"] != "deposit" { + t.Fatalf("expected deposit (top-up), got %v", payload.Payload["type"]) + } +} + +// DepositStrategy returning Skip=true causes an insufficient-balance request to +// fall through as a voucher (the request will then fail at verify; the caller +// is opting out of auto top-up). +func TestCreatePaymentPayload_DepositStrategySkipYieldsVoucher(t *testing.T) { + storage := NewInMemoryClientChannelStorage() + signer := &mockSigner{address: "0x1111111111111111111111111111111111111111", sig: []byte{0xad}} + scheme := NewBatchSettlementEvmScheme(signer, &BatchSettlementEvmSchemeOptions{ + Storage: storage, + DepositStrategy: func(_ context.Context, _ DepositStrategyContext) (DepositStrategyResult, error) { + return DepositStrategyResult{Skip: true}, nil + }, + }) + + channelConfig, err := scheme.BuildChannelConfig(defaultRequirements()) + if err != nil { + t.Fatalf("BuildChannelConfig: %v", err) + } + channelId, _ := batchsettlement.ComputeChannelId(channelConfig, testNetwork) + channelId = batchsettlement.NormalizeChannelId(channelId) + _ = storage.Set(channelId, &BatchSettlementClientContext{Balance: "50"}) + + payload, err := scheme.CreatePaymentPayload(context.Background(), defaultRequirements()) + if err != nil { + t.Fatalf("err: %v", err) + } + if payload.Payload["type"] != "voucher" { + t.Fatalf("expected voucher (deposit skipped), got %v", payload.Payload["type"]) + } +} + +func TestCreatePaymentPayload_BadAmount(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + req := defaultRequirements() + req.Amount = "not-a-number" + if _, err := scheme.CreatePaymentPayload(context.Background(), req); err == nil { + t.Fatal("expected error") + } +} + +// ---------- RecoverSession ---------- + +func TestRecoverSession_RequiresReadCapableSigner(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + if _, err := scheme.RecoverSession(context.Background(), defaultRequirements()); err == nil { + t.Fatal("expected error: signer lacks ReadContract") + } +} + +func TestRecoverSession_OK(t *testing.T) { + signer := &readSigner{ + mockSigner: &mockSigner{address: "0x1111111111111111111111111111111111111111"}, + readResult: []interface{}{big.NewInt(900), big.NewInt(100)}, + } + scheme := NewBatchSettlementEvmScheme(signer, nil) + got, err := scheme.RecoverSession(context.Background(), defaultRequirements()) + if err != nil { + t.Fatalf("err: %v", err) + } + if got.Balance != "900" || got.TotalClaimed != "100" || got.ChargedCumulativeAmount != "100" { + t.Fatalf("session = %+v", got) + } +} + +func TestRecoverSession_ReadError(t *testing.T) { + signer := &readSigner{ + mockSigner: &mockSigner{address: "0x1"}, + readErr: errors.New("rpc down"), + } + scheme := NewBatchSettlementEvmScheme(signer, nil) + if _, err := scheme.RecoverSession(context.Background(), defaultRequirements()); err == nil { + t.Fatal("expected RPC error") + } +} + +// ---------- ProcessCorrectivePaymentRequired ---------- + +// readChannelStateFromExtra accepts the corrective split shape: +// extra.channelState + extra.voucherState. +func TestReadChannelStateFromExtra_CanonicalSplitShape(t *testing.T) { + extra := map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": "0xabc", + "chargedCumulativeAmount": "200", + "balance": "1000", + "totalClaimed": "100", + }, + "voucherState": map[string]interface{}{ + "signedMaxClaimable": "300", + "signature": "0xsig", + }, + } + charged, signed, sig, ok := readChannelStateFromExtra(extra) + if !ok || charged != "200" || signed != "300" || sig != "0xsig" { + t.Fatalf("canonical shape: ok=%v charged=%q signed=%q sig=%q", ok, charged, signed, sig) + } +} + +func TestReadChannelStateFromExtra_MissingFieldsReturnsFalse(t *testing.T) { + if _, _, _, ok := readChannelStateFromExtra(nil); ok { + t.Fatal("nil extra should be rejected") + } + // channelState present but voucherState missing — not enough for signature recovery. + extra := map[string]interface{}{ + "channelState": map[string]interface{}{"chargedCumulativeAmount": "200"}, + } + if _, _, _, ok := readChannelStateFromExtra(extra); ok { + t.Fatal("missing voucherState should be rejected") + } + // voucherState present but channelState missing. + extra = map[string]interface{}{ + "voucherState": map[string]interface{}{ + "signedMaxClaimable": "300", + "signature": "0xsig", + }, + } + if _, _, _, ok := readChannelStateFromExtra(extra); ok { + t.Fatal("missing channelState should be rejected") + } +} + +func TestProcessCorrective_UnrelatedReason(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + ok, err := scheme.ProcessCorrectivePaymentRequired(context.Background(), "other_reason", nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if ok { + t.Fatal("unrelated reason should not recover") + } +} + +func TestProcessCorrective_NoBatchedAccept(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + ok, err := scheme.ProcessCorrectivePaymentRequired( + context.Background(), + batchsettlement.ErrCumulativeAmountMismatch, + []types.PaymentRequirements{{Scheme: "exact"}}, + ) + if err != nil || ok { + t.Fatalf("expected (false, nil), got (%v, %v)", ok, err) + } +} + +func TestProcessCorrective_FallsBackToOnChain(t *testing.T) { + signer := &readSigner{ + mockSigner: &mockSigner{address: "0x1111111111111111111111111111111111111111"}, + readResult: []interface{}{big.NewInt(900), big.NewInt(100)}, + } + scheme := NewBatchSettlementEvmScheme(signer, nil) + req := defaultRequirements() + ok, err := scheme.ProcessCorrectivePaymentRequired( + context.Background(), + batchsettlement.ErrCumulativeAmountMismatch, + []types.PaymentRequirements{req}, + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if !ok { + t.Fatal("expected onchain recovery to succeed") + } +} + +func TestProcessCorrective_RecoverFromSignatureBadCharged(t *testing.T) { + signer := &readSigner{ + mockSigner: &mockSigner{address: "0x1"}, + readResult: []interface{}{big.NewInt(900), big.NewInt(100)}, + } + scheme := NewBatchSettlementEvmScheme(signer, nil) + req := defaultRequirements() + // Corrective split shape with bad charged amount. + req.Extra["channelState"] = map[string]interface{}{ + "chargedCumulativeAmount": "not-a-number", + } + req.Extra["voucherState"] = map[string]interface{}{ + "signedMaxClaimable": "100", + "signature": "0xff", + } + ok, err := scheme.ProcessCorrectivePaymentRequired( + context.Background(), + batchsettlement.ErrCumulativeAmountMismatch, + []types.PaymentRequirements{req}, + ) + if err != nil || ok { + t.Fatalf("expected (false, nil), got (%v, %v)", ok, err) + } +} + +func TestProcessCorrective_RecoverFromSignatureChargedBeyondSigned(t *testing.T) { + signer := &readSigner{ + mockSigner: &mockSigner{address: "0x1"}, + readResult: []interface{}{big.NewInt(900), big.NewInt(100)}, + } + scheme := NewBatchSettlementEvmScheme(signer, nil) + req := defaultRequirements() + // Corrective split shape with charged > signed. + req.Extra["channelState"] = map[string]interface{}{ + "chargedCumulativeAmount": "200", + } + req.Extra["voucherState"] = map[string]interface{}{ + "signedMaxClaimable": "100", + "signature": "0xff", + } + ok, _ := scheme.ProcessCorrectivePaymentRequired( + context.Background(), + batchsettlement.ErrCumulativeAmountMismatch, + []types.PaymentRequirements{req}, + ) + if ok { + t.Fatal("charged > signed should refuse") + } +} + +func TestProcessCorrective_RecoverFromSignatureNoReadCapability(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + req := defaultRequirements() + req.Extra["channelState"] = map[string]interface{}{"chargedCumulativeAmount": "10"} + req.Extra["voucherState"] = map[string]interface{}{ + "signedMaxClaimable": "100", + "signature": "0xff", + } + ok, _ := scheme.ProcessCorrectivePaymentRequired( + context.Background(), + batchsettlement.ErrCumulativeAmountMismatch, + []types.PaymentRequirements{req}, + ) + if ok { + t.Fatal("no read capability should not recover") + } +} + +// ---------- OnPaymentResponse (PaymentResponseHandler) ---------- + +func TestOnPaymentResponse_SettleResponseFoldsState(t *testing.T) { + storage := NewInMemoryClientChannelStorage() + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, &BatchSettlementEvmSchemeOptions{Storage: storage}) + + res, err := scheme.OnPaymentResponse(context.Background(), x402.PaymentResponseContext{ + Requirements: defaultRequirements(), + SettleResponse: &x402.SettleResponse{ + Success: true, + Extra: map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": "0xabc", + "chargedCumulativeAmount": "12345", + "balance": "67890", + "totalClaimed": "100", + }, + }, + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if res.Recovered { + t.Fatal("settle response should not signal Recovered") + } + got, _ := storage.Get("0xabc") + if got == nil || got.ChargedCumulativeAmount != "12345" || got.Balance != "67890" { + t.Fatalf("session not folded: %+v", got) + } +} + +func TestOnPaymentResponse_NilExtraIsNoop(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + res, err := scheme.OnPaymentResponse(context.Background(), x402.PaymentResponseContext{ + Requirements: defaultRequirements(), + SettleResponse: &x402.SettleResponse{Success: true}, + }) + if err != nil || res.Recovered { + t.Fatalf("expected no-op, got recovered=%v err=%v", res.Recovered, err) + } +} + +func TestOnPaymentResponse_CorrectiveMismatchSignalsRecovered(t *testing.T) { + signer := &readSigner{ + mockSigner: &mockSigner{address: "0x1"}, + readResult: []interface{}{big.NewInt(900), big.NewInt(50)}, + } + storage := NewInMemoryClientChannelStorage() + scheme := NewBatchSettlementEvmScheme(signer, &BatchSettlementEvmSchemeOptions{Storage: storage}) + + res, err := scheme.OnPaymentResponse(context.Background(), x402.PaymentResponseContext{ + Requirements: defaultRequirements(), + PaymentRequired: &types.PaymentRequired{ + X402Version: 2, + Error: batchsettlement.ErrCumulativeAmountMismatch, + Accepts: []types.PaymentRequirements{defaultRequirements()}, + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if !res.Recovered { + t.Fatal("onchain recovery should set Recovered=true") + } +} + +func TestOnPaymentResponse_CorrectiveUnknownErrorDoesNotRecover(t *testing.T) { + scheme := NewBatchSettlementEvmScheme(&mockSigner{address: "0x1"}, nil) + res, err := scheme.OnPaymentResponse(context.Background(), x402.PaymentResponseContext{ + Requirements: defaultRequirements(), + PaymentRequired: &types.PaymentRequired{ + X402Version: 2, + Error: "some_other_error", + Accepts: []types.PaymentRequirements{defaultRequirements()}, + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if res.Recovered { + t.Fatal("unrelated error should not signal Recovered") + } +} + +// ---------- Refund adapter ---------- + +func TestRefundContextAdapter(t *testing.T) { + signer := &mockSigner{address: "0x1"} + voucherSigner := &mockSigner{address: "0xV"} + storage := NewInMemoryClientChannelStorage() + scheme := NewBatchSettlementEvmScheme(signer, &BatchSettlementEvmSchemeOptions{ + Storage: storage, + VoucherSigner: voucherSigner, + }) + a := &refundContextAdapter{scheme: scheme} + if a.Storage() != storage { + t.Fatal("Storage() mismatch") + } + if a.Signer() != evm.ClientEvmSigner(signer) { + t.Fatal("Signer() mismatch") + } + if a.VoucherSigner() != evm.ClientEvmSigner(voucherSigner) { + t.Fatal("VoucherSigner() mismatch") + } + cfg, err := a.BuildChannelConfig(defaultRequirements()) + if err != nil { + t.Fatalf("BuildChannelConfig: %v", err) + } + if cfg.Payer != signer.Address() { + t.Fatalf("BuildChannelConfig.Payer = %s", cfg.Payer) + } + ok, err := a.ProcessCorrectivePaymentRequired(context.Background(), "x", nil) + if err != nil || ok { + t.Fatalf("got (%v, %v)", ok, err) + } +} diff --git a/go/mechanisms/evm/batch-settlement/client/storage.go b/go/mechanisms/evm/batch-settlement/client/storage.go new file mode 100644 index 0000000000..7df3357155 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/storage.go @@ -0,0 +1,62 @@ +package client + +import ( + "sync" +) + +// BatchSettlementClientContext holds per-channel session state on the client side. +type BatchSettlementClientContext struct { + ChargedCumulativeAmount string `json:"chargedCumulativeAmount"` + Balance string `json:"balance"` + TotalClaimed string `json:"totalClaimed"` + DepositAmount string `json:"depositAmount,omitempty"` + SignedMaxClaimable string `json:"signedMaxClaimable,omitempty"` + Signature string `json:"signature,omitempty"` +} + +// ClientChannelStorage is the interface for persisting client-side channel sessions. +type ClientChannelStorage interface { + Get(channelId string) (*BatchSettlementClientContext, error) + Set(channelId string, ctx *BatchSettlementClientContext) error + Delete(channelId string) error +} + +// InMemoryClientChannelStorage is a volatile in-memory implementation of ClientChannelStorage. +type InMemoryClientChannelStorage struct { + mu sync.RWMutex + sessions map[string]*BatchSettlementClientContext +} + +// NewInMemoryClientChannelStorage creates a new in-memory client session storage. +func NewInMemoryClientChannelStorage() *InMemoryClientChannelStorage { + return &InMemoryClientChannelStorage{ + sessions: make(map[string]*BatchSettlementClientContext), + } +} + +func (s *InMemoryClientChannelStorage) Get(channelId string) (*BatchSettlementClientContext, error) { + s.mu.RLock() + defer s.mu.RUnlock() + ctx, ok := s.sessions[channelId] + if !ok { + return nil, nil + } + // Return a copy + copy := *ctx + return ©, nil +} + +func (s *InMemoryClientChannelStorage) Set(channelId string, ctx *BatchSettlementClientContext) error { + s.mu.Lock() + defer s.mu.Unlock() + copy := *ctx + s.sessions[channelId] = © + return nil +} + +func (s *InMemoryClientChannelStorage) Delete(channelId string) error { + s.mu.Lock() + defer s.mu.Unlock() + delete(s.sessions, channelId) + return nil +} diff --git a/go/mechanisms/evm/batch-settlement/client/storage_test.go b/go/mechanisms/evm/batch-settlement/client/storage_test.go new file mode 100644 index 0000000000..b830bfd051 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/storage_test.go @@ -0,0 +1,98 @@ +package client + +import ( + "reflect" + "sync" + "testing" +) + +func sampleCtx() *BatchSettlementClientContext { + return &BatchSettlementClientContext{ + ChargedCumulativeAmount: "100", + Balance: "900", + TotalClaimed: "50", + DepositAmount: "1000", + SignedMaxClaimable: "500", + Signature: "0xsig", + } +} + +func TestInMemoryClientChannelStorage_GetMissing(t *testing.T) { + s := NewInMemoryClientChannelStorage() + got, err := s.Get("missing") + if err != nil { + t.Fatalf("err: %v", err) + } + if got != nil { + t.Fatalf("expected nil, got %+v", got) + } +} + +func TestInMemoryClientChannelStorage_SetGet(t *testing.T) { + s := NewInMemoryClientChannelStorage() + in := sampleCtx() + if err := s.Set("ch", in); err != nil { + t.Fatalf("Set: %v", err) + } + got, err := s.Get("ch") + if err != nil { + t.Fatalf("Get: %v", err) + } + if !reflect.DeepEqual(in, got) { + t.Fatalf("round-trip mismatch:\nwant %+v\ngot %+v", in, got) + } +} + +func TestInMemoryClientChannelStorage_ReturnsCopy(t *testing.T) { + s := NewInMemoryClientChannelStorage() + in := sampleCtx() + _ = s.Set("ch", in) + + // Mutating the input should not affect stored value. + in.Balance = "0" + got, _ := s.Get("ch") + if got.Balance != "900" { + t.Fatalf("storage shares input pointer: %s", got.Balance) + } + + // Mutating returned value should not affect storage. + got.Balance = "1" + got2, _ := s.Get("ch") + if got2.Balance != "900" { + t.Fatalf("storage shares output pointer: %s", got2.Balance) + } +} + +func TestInMemoryClientChannelStorage_Delete(t *testing.T) { + s := NewInMemoryClientChannelStorage() + _ = s.Set("ch", sampleCtx()) + if err := s.Delete("ch"); err != nil { + t.Fatalf("Delete: %v", err) + } + got, _ := s.Get("ch") + if got != nil { + t.Fatalf("expected nil after delete, got %+v", got) + } + // Deleting missing should not error. + if err := s.Delete("missing"); err != nil { + t.Fatalf("Delete missing: %v", err) + } +} + +func TestInMemoryClientChannelStorage_ConcurrentAccess(t *testing.T) { + s := NewInMemoryClientChannelStorage() + var wg sync.WaitGroup + for i := range 50 { + wg.Add(2) + go func(i int) { + defer wg.Done() + _ = s.Set("ch", sampleCtx()) + _ = i + }(i) + go func() { + defer wg.Done() + _, _ = s.Get("ch") + }() + } + wg.Wait() +} diff --git a/go/mechanisms/evm/batch-settlement/client/voucher.go b/go/mechanisms/evm/batch-settlement/client/voucher.go new file mode 100644 index 0000000000..6ae8330969 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/voucher.go @@ -0,0 +1,63 @@ +package client + +import ( + "context" + "fmt" + "math/big" + + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +// SignVoucher signs a cumulative voucher using EIP-712. +// Voucher(bytes32 channelId, uint128 maxClaimableAmount) +func SignVoucher( + ctx context.Context, + signer evm.ClientEvmSigner, + channelId string, + maxClaimableAmount string, + network string, +) (*batchsettlement.BatchSettlementVoucherFields, error) { + chainId, err := evm.GetEvmChainId(network) + if err != nil { + return nil, fmt.Errorf("failed to get chain ID for %s: %w", network, err) + } + + maxClaimable, ok := new(big.Int).SetString(maxClaimableAmount, 10) + if !ok { + return nil, fmt.Errorf("invalid maxClaimableAmount: %s", maxClaimableAmount) + } + + channelIdBytes, err := evm.HexToBytes(channelId) + if err != nil { + return nil, fmt.Errorf("invalid channelId: %w", err) + } + + domain := batchsettlement.GetBatchSettlementEip712Domain(chainId) + + types := map[string][]evm.TypedDataField{ + "EIP712Domain": { + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "Voucher": batchsettlement.VoucherTypes["Voucher"], + } + + message := map[string]interface{}{ + "channelId": channelIdBytes, + "maxClaimableAmount": maxClaimable, + } + + signature, err := signer.SignTypedData(ctx, domain, types, "Voucher", message) + if err != nil { + return nil, fmt.Errorf("failed to sign voucher: %w", err) + } + + return &batchsettlement.BatchSettlementVoucherFields{ + ChannelId: channelId, + MaxClaimableAmount: maxClaimableAmount, + Signature: evm.BytesToHex(signature), + }, nil +} diff --git a/go/mechanisms/evm/batch-settlement/client/voucher_test.go b/go/mechanisms/evm/batch-settlement/client/voucher_test.go new file mode 100644 index 0000000000..ca74b27929 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/client/voucher_test.go @@ -0,0 +1,87 @@ +package client + +import ( + "context" + "errors" + "math/big" + "testing" + + "github.com/x402-foundation/x402/go/mechanisms/evm" +) + +// mockSigner records the last SignTypedData call and returns a canned signature/error. +type mockSigner struct { + address string + sig []byte + err error + + // Captured by the most recent SignTypedData call + lastDomain evm.TypedDataDomain + lastTypes map[string][]evm.TypedDataField + lastPrimaryType string + lastMessage map[string]interface{} +} + +func (m *mockSigner) Address() string { return m.address } +func (m *mockSigner) SignTypedData(_ context.Context, domain evm.TypedDataDomain, types map[string][]evm.TypedDataField, primaryType string, message map[string]interface{}) ([]byte, error) { + m.lastDomain = domain + m.lastTypes = types + m.lastPrimaryType = primaryType + m.lastMessage = message + return m.sig, m.err +} + +func TestSignVoucher_OK(t *testing.T) { + s := &mockSigner{address: "0xpayer", sig: []byte{0xde, 0xad, 0xbe, 0xef}} + channelId := "0x" + "ab" + v, err := SignVoucher(context.Background(), s, channelId, "1000", "eip155:8453") + if err != nil { + t.Fatalf("err: %v", err) + } + if v.ChannelId != channelId || v.MaxClaimableAmount != "1000" { + t.Fatalf("voucher fields = %+v", v) + } + if v.Signature != "0xdeadbeef" { + t.Fatalf("signature = %q", v.Signature) + } + if s.lastPrimaryType != "Voucher" { + t.Fatalf("primaryType = %q", s.lastPrimaryType) + } + if s.lastDomain.ChainID == nil || s.lastDomain.ChainID.Cmp(big.NewInt(8453)) != 0 { + t.Fatalf("domain.ChainID = %v", s.lastDomain.ChainID) + } + if s.lastDomain.Name != "x402 Batch Settlement" { + t.Fatalf("domain.Name = %q", s.lastDomain.Name) + } + if s.lastMessage["maxClaimableAmount"].(*big.Int).Cmp(big.NewInt(1000)) != 0 { + t.Fatalf("message.maxClaimableAmount = %v", s.lastMessage["maxClaimableAmount"]) + } +} + +func TestSignVoucher_BadNetwork(t *testing.T) { + s := &mockSigner{address: "0x"} + if _, err := SignVoucher(context.Background(), s, "0x01", "100", "not-a-network"); err == nil { + t.Fatal("expected error") + } +} + +func TestSignVoucher_BadMaxClaimableAmount(t *testing.T) { + s := &mockSigner{address: "0x"} + if _, err := SignVoucher(context.Background(), s, "0x01", "not-a-number", "eip155:8453"); err == nil { + t.Fatal("expected error") + } +} + +func TestSignVoucher_BadChannelId(t *testing.T) { + s := &mockSigner{address: "0x"} + if _, err := SignVoucher(context.Background(), s, "not-hex", "100", "eip155:8453"); err == nil { + t.Fatal("expected error") + } +} + +func TestSignVoucher_SignerError(t *testing.T) { + s := &mockSigner{address: "0x", err: errors.New("kms down")} + if _, err := SignVoucher(context.Background(), s, "0x01", "100", "eip155:8453"); err == nil { + t.Fatal("expected signer error") + } +} diff --git a/go/mechanisms/evm/batch-settlement/constants.go b/go/mechanisms/evm/batch-settlement/constants.go new file mode 100644 index 0000000000..5b1614bb49 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/constants.go @@ -0,0 +1,366 @@ +package batchsettlement + +import ( + "github.com/ethereum/go-ethereum/crypto" + + "github.com/x402-foundation/x402/go/mechanisms/evm" +) + +const ( + // SchemeBatched is the scheme identifier for batch settlement. + SchemeBatched = "batch-settlement" + + // BatchSettlementAddress is the deployed x402BatchSettlement contract address (CREATE2, all chains). + BatchSettlementAddress = "0x4020074e9dF2ce1deE5A9C1b5c3f541D02a10003" + + // ERC3009DepositCollectorAddress is the deployed ERC3009DepositCollector contract address. + ERC3009DepositCollectorAddress = "0x4020806089470a89826cB9fB1f4059150b550004" + + // Permit2DepositCollectorAddress is the deployed Permit2DepositCollector contract address. + Permit2DepositCollectorAddress = "0x4020425FAf3B746C082C2f942b4E5159887B0005" + + // MinWithdrawDelay is the minimum withdraw delay in seconds (15 minutes). + MinWithdrawDelay = 900 + + // MaxWithdrawDelay is the maximum withdraw delay in seconds (30 days). + MaxWithdrawDelay = 2_592_000 +) + +// ChannelConfigTypeString is the EIP-712 typed-data primary type string used +// for the onchain channel-id pre-image. +const ChannelConfigTypeString = "ChannelConfig(address payer,address payerAuthorizer,address receiver,address receiverAuthorizer,address token,uint40 withdrawDelay,bytes32 salt)" + +// ChannelConfigTypeHash is keccak256(ChannelConfigTypeString). +var ChannelConfigTypeHash = crypto.Keccak256([]byte(ChannelConfigTypeString)) + +// BatchSettlementDomain is the EIP-712 domain for the batch settlement contract. +// ChainId and VerifyingContract are set per-network at signing time. +var BatchSettlementDomain = evm.TypedDataDomain{ + Name: "x402 Batch Settlement", + Version: "1", +} + +// ChannelConfigTypes defines the EIP-712 types for the channel-config struct, +// used to compute the chain-bound channel id via hashTypedData. +var ChannelConfigTypes = map[string][]evm.TypedDataField{ + "ChannelConfig": { + {Name: "payer", Type: "address"}, + {Name: "payerAuthorizer", Type: "address"}, + {Name: "receiver", Type: "address"}, + {Name: "receiverAuthorizer", Type: "address"}, + {Name: "token", Type: "address"}, + {Name: "withdrawDelay", Type: "uint40"}, + {Name: "salt", Type: "bytes32"}, + }, +} + +// VoucherTypes defines the EIP-712 types for a cumulative voucher. +// Voucher(bytes32 channelId, uint128 maxClaimableAmount) +var VoucherTypes = map[string][]evm.TypedDataField{ + "Voucher": { + {Name: "channelId", Type: "bytes32"}, + {Name: "maxClaimableAmount", Type: "uint128"}, + }, +} + +// RefundTypes defines the EIP-712 types for cooperative refund. +// Refund(bytes32 channelId, uint256 nonce, uint128 amount) +var RefundTypes = map[string][]evm.TypedDataField{ + "Refund": { + {Name: "channelId", Type: "bytes32"}, + {Name: "nonce", Type: "uint256"}, + {Name: "amount", Type: "uint128"}, + }, +} + +// ClaimBatchTypes defines the EIP-712 types for receiver-authorizer claim batches. +var ClaimBatchTypes = map[string][]evm.TypedDataField{ + "ClaimBatch": { + {Name: "claims", Type: "ClaimEntry[]"}, + }, + "ClaimEntry": { + {Name: "channelId", Type: "bytes32"}, + {Name: "maxClaimableAmount", Type: "uint128"}, + {Name: "totalClaimed", Type: "uint128"}, + }, +} + +// ReceiveAuthorizationTypes defines the EIP-712 types for ERC-3009 ReceiveWithAuthorization. +var ReceiveAuthorizationTypes = map[string][]evm.TypedDataField{ + "ReceiveWithAuthorization": { + {Name: "from", Type: "address"}, + {Name: "to", Type: "address"}, + {Name: "value", Type: "uint256"}, + {Name: "validAfter", Type: "uint256"}, + {Name: "validBefore", Type: "uint256"}, + {Name: "nonce", Type: "bytes32"}, + }, +} + +// Permit2Address is the universal Permit2 deployment used across EVM chains. +const Permit2Address = "0x000000000022D473030F116dDEE9F6B43aC78BA3" + +// Permit2DomainName is the EIP-712 domain name used by Permit2 typed data. +const Permit2DomainName = "Permit2" + +// BatchPermit2WitnessTypes defines the EIP-712 types for the channel-bound +// Permit2 PermitWitnessTransferFrom signed by the payer when the deposit uses +// the permit2 transfer method. The witness binds the transfer to a specific +// batch-settlement channel id so the Permit2DepositCollector can route funds +// on the receiver's behalf. +var BatchPermit2WitnessTypes = map[string][]evm.TypedDataField{ + "PermitWitnessTransferFrom": { + {Name: "permitted", Type: "TokenPermissions"}, + {Name: "spender", Type: "address"}, + {Name: "nonce", Type: "uint256"}, + {Name: "deadline", Type: "uint256"}, + {Name: "witness", Type: "DepositWitness"}, + }, + "TokenPermissions": { + {Name: "token", Type: "address"}, + {Name: "amount", Type: "uint256"}, + }, + "DepositWitness": { + {Name: "channelId", Type: "bytes32"}, + }, +} + +// DepositWitnessTypeString is the canonical witness type-string fragment that +// must be appended (without the leading `,`) when computing the Permit2 +// witness type hash. +const DepositWitnessTypeString = "DepositWitness witness)DepositWitness(bytes32 channelId)TokenPermissions(address token,uint256 amount)" + +// ============================================================================ +// ABI Definitions +// ============================================================================ + +// channelConfigComponents is the ABI tuple for ChannelConfig, shared across multiple ABIs. +const channelConfigComponentsJSON = `[ + {"name": "payer", "type": "address"}, + {"name": "payerAuthorizer", "type": "address"}, + {"name": "receiver", "type": "address"}, + {"name": "receiverAuthorizer", "type": "address"}, + {"name": "token", "type": "address"}, + {"name": "withdrawDelay", "type": "uint40"}, + {"name": "salt", "type": "bytes32"} +]` + +// BatchSettlementDepositABI for calling deposit(config, amount, collector, collectorData). +var BatchSettlementDepositABI = []byte(`[ + { + "type": "function", + "name": "deposit", + "inputs": [ + {"name": "config", "type": "tuple", "components": ` + channelConfigComponentsJSON + `}, + {"name": "amount", "type": "uint128"}, + {"name": "collector", "type": "address"}, + {"name": "collectorData", "type": "bytes"} + ], + "outputs": [], + "stateMutability": "nonpayable" + } +]`) + +// BatchSettlementClaimABI for calling claim(voucherClaims[]). +var BatchSettlementClaimABI = []byte(`[ + { + "type": "function", + "name": "claim", + "inputs": [ + { + "name": "voucherClaims", + "type": "tuple[]", + "components": [ + { + "name": "voucher", + "type": "tuple", + "components": [ + {"name": "channel", "type": "tuple", "components": ` + channelConfigComponentsJSON + `}, + {"name": "maxClaimableAmount", "type": "uint128"} + ] + }, + {"name": "signature", "type": "bytes"}, + {"name": "totalClaimed", "type": "uint128"} + ] + } + ], + "outputs": [], + "stateMutability": "nonpayable" + } +]`) + +// BatchSettlementClaimWithSignatureABI for calling claimWithSignature(voucherClaims[], authorizerSignature). +var BatchSettlementClaimWithSignatureABI = []byte(`[ + { + "type": "function", + "name": "claimWithSignature", + "inputs": [ + { + "name": "voucherClaims", + "type": "tuple[]", + "components": [ + { + "name": "voucher", + "type": "tuple", + "components": [ + {"name": "channel", "type": "tuple", "components": ` + channelConfigComponentsJSON + `}, + {"name": "maxClaimableAmount", "type": "uint128"} + ] + }, + {"name": "signature", "type": "bytes"}, + {"name": "totalClaimed", "type": "uint128"} + ] + }, + {"name": "authorizerSignature", "type": "bytes"} + ], + "outputs": [], + "stateMutability": "nonpayable" + } +]`) + +// BatchSettlementSettleABI for calling settle(receiver, token). +var BatchSettlementSettleABI = []byte(`[ + { + "type": "function", + "name": "settle", + "inputs": [ + {"name": "receiver", "type": "address"}, + {"name": "token", "type": "address"} + ], + "outputs": [], + "stateMutability": "nonpayable" + } +]`) + +// BatchSettlementRefundABI for calling refund(config, amount). +var BatchSettlementRefundABI = []byte(`[ + { + "type": "function", + "name": "refund", + "inputs": [ + {"name": "config", "type": "tuple", "components": ` + channelConfigComponentsJSON + `}, + {"name": "amount", "type": "uint128"} + ], + "outputs": [], + "stateMutability": "nonpayable" + } +]`) + +// BatchSettlementRefundWithSignatureABI for calling refundWithSignature(config, amount, nonce, receiverAuthorizerSignature). +var BatchSettlementRefundWithSignatureABI = []byte(`[ + { + "type": "function", + "name": "refundWithSignature", + "inputs": [ + {"name": "config", "type": "tuple", "components": ` + channelConfigComponentsJSON + `}, + {"name": "amount", "type": "uint128"}, + {"name": "nonce", "type": "uint256"}, + {"name": "receiverAuthorizerSignature", "type": "bytes"} + ], + "outputs": [], + "stateMutability": "nonpayable" + } +]`) + +// BatchSettlementMulticallABI for calling multicall(data[]). +var BatchSettlementMulticallABI = []byte(`[ + { + "type": "function", + "name": "multicall", + "inputs": [{"name": "data", "type": "bytes[]"}], + "outputs": [{"name": "results", "type": "bytes[]"}], + "stateMutability": "nonpayable" + } +]`) + +// BatchSettlementChannelsABI for reading channels(channelId) -> (balance, totalClaimed). +var BatchSettlementChannelsABI = []byte(`[ + { + "type": "function", + "name": "channels", + "inputs": [{"name": "channelId", "type": "bytes32"}], + "outputs": [ + {"name": "balance", "type": "uint128"}, + {"name": "totalClaimed", "type": "uint128"} + ], + "stateMutability": "view" + } +]`) + +// BatchSettlementPendingWithdrawalsABI for reading pendingWithdrawals(channelId). +var BatchSettlementPendingWithdrawalsABI = []byte(`[ + { + "type": "function", + "name": "pendingWithdrawals", + "inputs": [{"name": "channelId", "type": "bytes32"}], + "outputs": [ + {"name": "amount", "type": "uint128"}, + {"name": "initiatedAt", "type": "uint40"} + ], + "stateMutability": "view" + } +]`) + +// BatchSettlementRefundNonceABI for reading refundNonce(channelId). +var BatchSettlementRefundNonceABI = []byte(`[ + { + "type": "function", + "name": "refundNonce", + "inputs": [{"name": "channelId", "type": "bytes32"}], + "outputs": [{"name": "", "type": "uint256"}], + "stateMutability": "view" + } +]`) + +// BatchSettlementGetChannelIdABI for calling getChannelId(config). +var BatchSettlementGetChannelIdABI = []byte(`[ + { + "type": "function", + "name": "getChannelId", + "inputs": [{"name": "config", "type": "tuple", "components": ` + channelConfigComponentsJSON + `}], + "outputs": [{"name": "", "type": "bytes32"}], + "stateMutability": "pure" + } +]`) + +// BatchSettlementReceiversABI for reading receivers(receiver, token). +var BatchSettlementReceiversABI = []byte(`[ + { + "type": "function", + "name": "receivers", + "inputs": [ + {"name": "receiver", "type": "address"}, + {"name": "token", "type": "address"} + ], + "outputs": [ + {"name": "totalClaimed", "type": "uint128"}, + {"name": "totalSettled", "type": "uint128"} + ], + "stateMutability": "view" + } +]`) + +// BatchSettlementInitiateWithdrawABI for calling initiateWithdraw(config, amount). +var BatchSettlementInitiateWithdrawABI = []byte(`[ + { + "type": "function", + "name": "initiateWithdraw", + "inputs": [ + {"name": "config", "type": "tuple", "components": ` + channelConfigComponentsJSON + `}, + {"name": "amount", "type": "uint128"} + ], + "outputs": [], + "stateMutability": "nonpayable" + } +]`) + +// BatchSettlementFinalizeWithdrawABI for calling finalizeWithdraw(config). +var BatchSettlementFinalizeWithdrawABI = []byte(`[ + { + "type": "function", + "name": "finalizeWithdraw", + "inputs": [{"name": "config", "type": "tuple", "components": ` + channelConfigComponentsJSON + `}], + "outputs": [], + "stateMutability": "nonpayable" + } +]`) diff --git a/go/mechanisms/evm/batch-settlement/constants_test.go b/go/mechanisms/evm/batch-settlement/constants_test.go new file mode 100644 index 0000000000..9b0de685c1 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/constants_test.go @@ -0,0 +1,107 @@ +package batchsettlement + +import ( + "strings" + "testing" +) + +func TestSchemeIdentifier(t *testing.T) { + if SchemeBatched != "batch-settlement" { + t.Fatalf("SchemeBatched = %q", SchemeBatched) + } +} + +func TestContractAddresses(t *testing.T) { + if !strings.HasPrefix(BatchSettlementAddress, "0x") || len(BatchSettlementAddress) != 42 { + t.Fatalf("BatchSettlementAddress malformed: %q", BatchSettlementAddress) + } + if !strings.HasPrefix(ERC3009DepositCollectorAddress, "0x") || len(ERC3009DepositCollectorAddress) != 42 { + t.Fatalf("ERC3009DepositCollectorAddress malformed: %q", ERC3009DepositCollectorAddress) + } +} + +func TestWithdrawDelayBounds(t *testing.T) { + if MinWithdrawDelay != 900 { + t.Fatalf("MinWithdrawDelay = %d", MinWithdrawDelay) + } + if MaxWithdrawDelay != 2_592_000 { + t.Fatalf("MaxWithdrawDelay = %d", MaxWithdrawDelay) + } + if MinWithdrawDelay >= MaxWithdrawDelay { + t.Fatal("min must be less than max") + } +} + +func TestBatchSettlementDomain(t *testing.T) { + if BatchSettlementDomain.Name != "x402 Batch Settlement" { + t.Fatalf("Name = %q", BatchSettlementDomain.Name) + } + if BatchSettlementDomain.Version != "1" { + t.Fatalf("Version = %q", BatchSettlementDomain.Version) + } +} + +func TestVoucherTypes(t *testing.T) { + v, ok := VoucherTypes["Voucher"] + if !ok || len(v) != 2 { + t.Fatalf("VoucherTypes shape = %+v", v) + } + if v[0].Name != "channelId" || v[0].Type != "bytes32" { + t.Fatalf("Voucher[0] = %+v", v[0]) + } + if v[1].Name != "maxClaimableAmount" || v[1].Type != "uint128" { + t.Fatalf("Voucher[1] = %+v", v[1]) + } +} + +func TestRefundTypes(t *testing.T) { + r, ok := RefundTypes["Refund"] + if !ok || len(r) != 3 { + t.Fatalf("RefundTypes shape = %+v", r) + } +} + +func TestClaimBatchTypes(t *testing.T) { + cb, ok := ClaimBatchTypes["ClaimBatch"] + if !ok || len(cb) != 1 { + t.Fatalf("ClaimBatchTypes shape = %+v", cb) + } + if cb[0].Type != "ClaimEntry[]" { + t.Fatalf("ClaimBatch[0].Type = %q", cb[0].Type) + } + ce, ok := ClaimBatchTypes["ClaimEntry"] + if !ok || len(ce) != 3 { + t.Fatalf("ClaimEntry shape = %+v", ce) + } +} + +func TestReceiveAuthorizationTypes(t *testing.T) { + r, ok := ReceiveAuthorizationTypes["ReceiveWithAuthorization"] + if !ok || len(r) != 6 { + t.Fatalf("ReceiveWithAuthorization shape = %+v", r) + } +} + +// TestErrorCodes pins the canonical wire prefix `invalid_batch_settlement_evm_` +// for every error reason exported from this package. Both facilitator-mirrored +// constants and resource-server abort reasons share the same envelope — +// renaming or dropping the prefix here breaks cdp-facilitator's substring +// classifier and the `x402VerifyInvalidReason` / `x402SettleErrorReason` +// CDP Accounts API enums. +func TestErrorCodes(t *testing.T) { + const wirePrefix = "invalid_batch_settlement_evm_" + for _, code := range []string{ + ErrCumulativeBelowClaimed, + ErrCumulativeAmountMismatch, + ErrChannelBusy, + ErrMissingChannel, + ErrChargeExceedsSignedCumulative, + ErrRefundNoBalance, + ErrRefundAmountInvalid, + ErrRefundAmountExceedsBalance, + } { + if !strings.HasPrefix(code, wirePrefix) { + t.Fatalf("error reason must start with %q, got %q", wirePrefix, code) + } + } +} diff --git a/go/mechanisms/evm/batch-settlement/encoding.go b/go/mechanisms/evm/batch-settlement/encoding.go new file mode 100644 index 0000000000..79132b028b --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/encoding.go @@ -0,0 +1,169 @@ +package batchsettlement + +import ( + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/accounts/abi" + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/crypto" +) + +// erc3009DepositNonceABI is the ABI tuple (bytes32, uint256) used to derive +// the ERC-3009 deposit nonce: keccak256(abi.encode(channelId, salt)). +var erc3009DepositNonceABI abi.Arguments + +// erc3009CollectorDataABI is the ABI tuple (uint256, uint256, uint256, bytes) +// used as collectorData passed to deposit(..., collector, collectorData). +var erc3009CollectorDataABI abi.Arguments + +// permit2CollectorDataABI is the ABI tuple (uint256, uint256, bytes, bytes) +// used as collectorData for Permit2DepositCollector.collect: +// (nonce, deadline, permit2Signature, optionalEip2612PermitData). +var permit2CollectorDataABI abi.Arguments + +// eip2612PermitDataABI is the ABI tuple (uint256, uint256, uint8, bytes32, bytes32) +// for the optional EIP-2612 permit segment consumed by Permit2DepositCollector. +var eip2612PermitDataABI abi.Arguments + +func init() { + bytes32Ty, _ := abi.NewType("bytes32", "", nil) + uint8Ty, _ := abi.NewType("uint8", "", nil) + uint256Ty, _ := abi.NewType("uint256", "", nil) + bytesTy, _ := abi.NewType("bytes", "", nil) + + erc3009DepositNonceABI = abi.Arguments{ + {Type: bytes32Ty}, + {Type: uint256Ty}, + } + + erc3009CollectorDataABI = abi.Arguments{ + {Type: uint256Ty}, // validAfter + {Type: uint256Ty}, // validBefore + {Type: uint256Ty}, // salt + {Type: bytesTy}, // signature + } + + permit2CollectorDataABI = abi.Arguments{ + {Type: uint256Ty}, // nonce + {Type: uint256Ty}, // deadline + {Type: bytesTy}, // permit2Signature + {Type: bytesTy}, // eip2612PermitData (or empty `0x`) + } + + eip2612PermitDataABI = abi.Arguments{ + {Type: uint256Ty}, // value + {Type: uint256Ty}, // deadline + {Type: uint8Ty}, // v + {Type: bytes32Ty}, // r + {Type: bytes32Ty}, // s + } +} + +// BuildErc3009DepositNonce computes the ERC-3009 nonce used by the deposit +// collector: keccak256(abi.encode(channelId, salt)). +func BuildErc3009DepositNonce(channelId string, salt string) (string, error) { + channelIdBytes, err := hexToBytes32(channelId) + if err != nil { + return "", fmt.Errorf("invalid channelId: %w", err) + } + saltBig, ok := new(big.Int).SetString(strings.TrimPrefix(salt, "0x"), 16) + if !ok { + return "", fmt.Errorf("invalid salt: %s", salt) + } + + encoded, err := erc3009DepositNonceABI.Pack(channelIdBytes, saltBig) + if err != nil { + return "", fmt.Errorf("failed to ABI-encode deposit nonce inputs: %w", err) + } + return fmt.Sprintf("0x%x", crypto.Keccak256(encoded)), nil +} + +// BuildErc3009CollectorData ABI-encodes (validAfter, validBefore, salt, signature) +// for ERC3009DepositCollector.collect(). +func BuildErc3009CollectorData(validAfter, validBefore, salt, signature string) ([]byte, error) { + va, ok := new(big.Int).SetString(validAfter, 10) + if !ok { + return nil, fmt.Errorf("invalid validAfter: %s", validAfter) + } + vb, ok := new(big.Int).SetString(validBefore, 10) + if !ok { + return nil, fmt.Errorf("invalid validBefore: %s", validBefore) + } + saltBig, ok := new(big.Int).SetString(strings.TrimPrefix(salt, "0x"), 16) + if !ok { + return nil, fmt.Errorf("invalid salt: %s", salt) + } + sigBytes := common.FromHex(signature) + + encoded, err := erc3009CollectorDataABI.Pack(va, vb, saltBig, sigBytes) + if err != nil { + return nil, fmt.Errorf("failed to ABI-encode collector data: %w", err) + } + return encoded, nil +} + +// Eip2612PermitInput is the optional EIP-2612 permit segment consumed by +// Permit2DepositCollector when the deposit goes through the Permit2 path with +// a paired EIP-2612 approval. +type Eip2612PermitInput struct { + Value string + Deadline string + V uint8 + R string // 32-byte hex (with or without 0x prefix) + S string +} + +// BuildEip2612PermitData ABI-encodes (value, deadline, v, r, s) for the +// optional EIP-2612 permit segment consumed by Permit2DepositCollector. +func BuildEip2612PermitData(input Eip2612PermitInput) ([]byte, error) { + value, ok := new(big.Int).SetString(input.Value, 10) + if !ok { + return nil, fmt.Errorf("invalid permit value: %s", input.Value) + } + deadline, ok := new(big.Int).SetString(input.Deadline, 10) + if !ok { + return nil, fmt.Errorf("invalid permit deadline: %s", input.Deadline) + } + r, err := hexToBytes32(input.R) + if err != nil { + return nil, fmt.Errorf("invalid permit r: %w", err) + } + s, err := hexToBytes32(input.S) + if err != nil { + return nil, fmt.Errorf("invalid permit s: %w", err) + } + + encoded, err := eip2612PermitDataABI.Pack(value, deadline, input.V, r, s) + if err != nil { + return nil, fmt.Errorf("failed to ABI-encode permit data: %w", err) + } + return encoded, nil +} + +// BuildPermit2CollectorData ABI-encodes (nonce, deadline, permit2Signature, +// eip2612PermitData) as the collectorData passed to deposit(..., collector, +// collectorData) when using the Permit2 transfer method. Pass an empty +// `eip2612PermitData` ([]byte{} or `0x`) when no EIP-2612 permit accompanies +// the Permit2 authorization. +func BuildPermit2CollectorData(nonce, deadline, permit2Signature string, eip2612PermitData []byte) ([]byte, error) { + n, ok := new(big.Int).SetString(nonce, 10) + if !ok { + return nil, fmt.Errorf("invalid permit2 nonce: %s", nonce) + } + d, ok := new(big.Int).SetString(deadline, 10) + if !ok { + return nil, fmt.Errorf("invalid permit2 deadline: %s", deadline) + } + sigBytes := common.FromHex(permit2Signature) + if eip2612PermitData == nil { + eip2612PermitData = []byte{} + } + + encoded, err := permit2CollectorDataABI.Pack(n, d, sigBytes, eip2612PermitData) + if err != nil { + return nil, fmt.Errorf("failed to ABI-encode permit2 collector data: %w", err) + } + return encoded, nil +} diff --git a/go/mechanisms/evm/batch-settlement/encoding_test.go b/go/mechanisms/evm/batch-settlement/encoding_test.go new file mode 100644 index 0000000000..ee6a0da9cc --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/encoding_test.go @@ -0,0 +1,208 @@ +package batchsettlement + +import ( + "bytes" + "strings" + "testing" +) + +func TestBuildErc3009DepositNonce_Deterministic(t *testing.T) { + const channelId = "0x1111111111111111111111111111111111111111111111111111111111111111" + const salt = "0x02" + + a, err := BuildErc3009DepositNonce(channelId, salt) + if err != nil { + t.Fatalf("err: %v", err) + } + b, err := BuildErc3009DepositNonce(channelId, salt) + if err != nil { + t.Fatalf("err: %v", err) + } + if a != b { + t.Fatalf("non-deterministic: %s vs %s", a, b) + } + if !strings.HasPrefix(a, "0x") || len(a) != 66 { + t.Fatalf("expected 0x-prefixed 32-byte hex; got %q (len %d)", a, len(a)) + } +} + +func TestBuildErc3009DepositNonce_DifferentInputs(t *testing.T) { + const channelId = "0x" + "11" + a, err := BuildErc3009DepositNonce(channelId, "0x01") + if err != nil { + t.Fatalf("err: %v", err) + } + b, err := BuildErc3009DepositNonce(channelId, "0x02") + if err != nil { + t.Fatalf("err: %v", err) + } + if a == b { + t.Fatalf("different salts produced same hash: %s", a) + } +} + +func TestBuildErc3009DepositNonce_AcceptsShortChannelId(t *testing.T) { + // hexToBytes32 left-pads, so short hex is accepted + if _, err := BuildErc3009DepositNonce("0x01", "0x01"); err != nil { + t.Fatalf("short channelId rejected: %v", err) + } +} + +func TestBuildErc3009DepositNonce_InvalidChannelId(t *testing.T) { + long := "0x" + strings.Repeat("ab", 33) + if _, err := BuildErc3009DepositNonce(long, "0x01"); err == nil { + t.Fatal("expected error for too-long channelId") + } +} + +func TestBuildErc3009DepositNonce_InvalidSalt(t *testing.T) { + if _, err := BuildErc3009DepositNonce("0x01", "not-hex"); err == nil { + t.Fatal("expected error for invalid salt") + } +} + +func TestBuildErc3009CollectorData_Deterministic(t *testing.T) { + a, err := BuildErc3009CollectorData("0", "9999999999", "0x01", "0xdeadbeef") + if err != nil { + t.Fatalf("err: %v", err) + } + b, err := BuildErc3009CollectorData("0", "9999999999", "0x01", "0xdeadbeef") + if err != nil { + t.Fatalf("err: %v", err) + } + if !bytes.Equal(a, b) { + t.Fatal("non-deterministic encoding") + } + if len(a) == 0 { + t.Fatal("empty encoding") + } +} + +func TestBuildErc3009CollectorData_DifferentInputsDiffer(t *testing.T) { + a, _ := BuildErc3009CollectorData("0", "1", "0x01", "0xff") + b, _ := BuildErc3009CollectorData("0", "2", "0x01", "0xff") + if bytes.Equal(a, b) { + t.Fatal("validBefore change did not affect encoding") + } +} + +func TestBuildErc3009CollectorData_InvalidValidAfter(t *testing.T) { + if _, err := BuildErc3009CollectorData("not-a-number", "0", "0x01", "0xff"); err == nil { + t.Fatal("expected error") + } +} + +func TestBuildErc3009CollectorData_InvalidValidBefore(t *testing.T) { + if _, err := BuildErc3009CollectorData("0", "not-a-number", "0x01", "0xff"); err == nil { + t.Fatal("expected error") + } +} + +func TestBuildErc3009CollectorData_InvalidSalt(t *testing.T) { + if _, err := BuildErc3009CollectorData("0", "1", "not-hex", "0xff"); err == nil { + t.Fatal("expected error") + } +} + +// ----- Permit2 collector data ------------------------------------------------ + +func TestBuildPermit2CollectorData_Deterministic(t *testing.T) { + a, err := BuildPermit2CollectorData("100", "9999999999", "0xdeadbeef", nil) + if err != nil { + t.Fatalf("err: %v", err) + } + b, err := BuildPermit2CollectorData("100", "9999999999", "0xdeadbeef", []byte{}) + if err != nil { + t.Fatalf("err: %v", err) + } + if !bytes.Equal(a, b) { + t.Fatalf("nil and empty eip2612PermitData should encode identically") + } + if len(a) == 0 { + t.Fatal("empty encoding") + } +} + +func TestBuildPermit2CollectorData_AcceptsEip2612Segment(t *testing.T) { + permit, err := BuildEip2612PermitData(Eip2612PermitInput{ + Value: "1000000", + Deadline: "9999999999", + V: 27, + R: "0x" + strings.Repeat("11", 32), + S: "0x" + strings.Repeat("22", 32), + }) + if err != nil { + t.Fatalf("permit data: %v", err) + } + with, err := BuildPermit2CollectorData("1", "9999999999", "0xff", permit) + if err != nil { + t.Fatalf("with permit: %v", err) + } + without, err := BuildPermit2CollectorData("1", "9999999999", "0xff", nil) + if err != nil { + t.Fatalf("without permit: %v", err) + } + if bytes.Equal(with, without) { + t.Fatal("eip2612 permit segment did not affect encoding") + } +} + +func TestBuildPermit2CollectorData_InvalidNonce(t *testing.T) { + if _, err := BuildPermit2CollectorData("not-a-number", "1", "0xff", nil); err == nil { + t.Fatal("expected error") + } +} + +func TestBuildPermit2CollectorData_InvalidDeadline(t *testing.T) { + if _, err := BuildPermit2CollectorData("1", "not-a-number", "0xff", nil); err == nil { + t.Fatal("expected error") + } +} + +// ----- EIP-2612 permit segment ---------------------------------------------- + +func TestBuildEip2612PermitData_Deterministic(t *testing.T) { + in := Eip2612PermitInput{ + Value: "1000", + Deadline: "1234567890", + V: 28, + R: "0x" + strings.Repeat("aa", 32), + S: "0x" + strings.Repeat("bb", 32), + } + a, err := BuildEip2612PermitData(in) + if err != nil { + t.Fatalf("err: %v", err) + } + b, err := BuildEip2612PermitData(in) + if err != nil { + t.Fatalf("err: %v", err) + } + if !bytes.Equal(a, b) { + t.Fatal("non-deterministic encoding") + } +} + +func TestBuildEip2612PermitData_InvalidR(t *testing.T) { + // hexToBytes32 only rejects hex strings longer than 32 bytes (64 chars). + if _, err := BuildEip2612PermitData(Eip2612PermitInput{ + Value: "1", + Deadline: "1", + V: 27, + R: "0x" + strings.Repeat("ff", 33), + S: "0x" + strings.Repeat("00", 32), + }); err == nil { + t.Fatal("expected error for over-long r") + } +} + +func TestBuildEip2612PermitData_InvalidValue(t *testing.T) { + if _, err := BuildEip2612PermitData(Eip2612PermitInput{ + Value: "not-a-number", + Deadline: "1", + V: 27, + R: "0x" + strings.Repeat("00", 32), + S: "0x" + strings.Repeat("00", 32), + }); err == nil { + t.Fatal("expected error for non-numeric value") + } +} diff --git a/go/mechanisms/evm/batch-settlement/errors.go b/go/mechanisms/evm/batch-settlement/errors.go new file mode 100644 index 0000000000..03166492c7 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/errors.go @@ -0,0 +1,69 @@ +// Package batched holds shared batch-settlement error constants used across +// client / facilitator / server. All reasons share the +// `invalid_batch_settlement_evm_*` prefix and describe mechanism-level +// failures only — no policy/business semantics. +// +// A small subset is duplicated here (and authoritatively defined in +// `go/mechanisms/evm/batch-settlement/facilitator/errors.go`) so non-facilitator +// callers can reference them without importing facilitator (which would +// cycle: facilitator already imports batched). +package batchsettlement + +const ( + // ── Facilitator-emitted reason shared with the client ───────────────── + + // ErrCumulativeBelowClaimed is the canonical value of + // `facilitator.ErrMaxClaimableTooLow`. Surfaced both by the facilitator + // (as a verify rejection) AND by the resource server's corrective 402 + // recovery handshake — clients accept it as a signal to refresh + // channel state and retry. Defined here so `client/scheme.go` can match + // it without importing the facilitator package. + ErrCumulativeBelowClaimed = "invalid_batch_settlement_evm_cumulative_below_claimed" + + // ── Resource-server-emitted reasons ─────────────────────────────────── + // + // Emitted by the resource server's lifecycle hooks (BeforeVerifyHook / + // BeforeSettleHook / AfterVerifyHook) and surfaced to the client + // through the PAYMENT-REQUIRED 402 `error` field. NOT facilitator + // output. + + // ErrCumulativeAmountMismatch signals a recoverable 402 from the resource + // server when the client's signed cumulative disagrees with the server's + // tracked state. Clients refresh from the corrective ChannelState in + // requirements.extra and retry. + ErrCumulativeAmountMismatch = "invalid_batch_settlement_evm_cumulative_amount_mismatch" + + // ErrChannelBusy signals that another request is currently holding the + // per-channel concurrency lock. Clients should back off briefly and + // retry. Emitted by BeforeSettleHook for both voucher commits and + // refund rewrites when a pending request is in flight. + ErrChannelBusy = "invalid_batch_settlement_evm_channel_busy" + + // ErrMissingChannel signals that the server has no record of the + // channel referenced by the payload. Emitted by BeforeSettleHook for + // voucher and refund payloads when no session exists for the computed + // channelId. + ErrMissingChannel = "invalid_batch_settlement_evm_missing_channel" + + // ErrChargeExceedsSignedCumulative signals that committing this voucher + // would push the server-tracked chargedCumulativeAmount above the + // voucher's signed maxClaimableAmount cap. Emitted by BeforeSettleHook's + // voucher-commit path; clients must re-sign with a larger cap. + ErrChargeExceedsSignedCumulative = "invalid_batch_settlement_evm_charge_exceeds_signed_cumulative" + + // ErrRefundNoBalance signals that a cooperative refund request hit a + // channel with no remaining refundable balance (post-claim). Non- + // recoverable — the client must abandon the refund. Emitted by + // BeforeSettleHook's refund-rewrite path. + ErrRefundNoBalance = "invalid_batch_settlement_evm_refund_no_balance" + + // ErrRefundAmountInvalid signals the client requested a malformed refund + // amount (non-numeric or non-positive). Non-recoverable — the client + // must fix the request before retrying. + ErrRefundAmountInvalid = "invalid_batch_settlement_evm_refund_amount_invalid" + + // ErrRefundAmountExceedsBalance signals the client requested a refund + // larger than the channel's available balance. Non-recoverable; client + // should retry with a smaller amount or omit `amount` for a full refund. + ErrRefundAmountExceedsBalance = "invalid_batch_settlement_evm_refund_amount_exceeds_balance" +) diff --git a/go/mechanisms/evm/batch-settlement/facilitator/claim.go b/go/mechanisms/evm/batch-settlement/facilitator/claim.go new file mode 100644 index 0000000000..75ebf017fe --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/claim.go @@ -0,0 +1,139 @@ +package facilitator + +import ( + "context" + "fmt" + "math/big" + "strings" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// ExecuteClaimWithSignature executes a batch claim with receiverAuthorizer signature. +// If ClaimAuthorizerSignature is absent from the payload, the authorizerSigner +// auto-signs the ClaimBatch digest. +func ExecuteClaimWithSignature( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + payload *batchsettlement.BatchSettlementClaimPayload, + requirements types.PaymentRequirements, + authorizerSigner batchsettlement.AuthorizerSigner, +) (*x402.SettleResponse, error) { + network := x402.Network(requirements.Network) + + if len(payload.Claims) == 0 { + return nil, x402.NewSettleError(ErrInvalidClaimPayload, "", network, "", + "no claims provided") + } + + // Resolve signature — auto-sign if absent + var sigBytes []byte + if payload.ClaimAuthorizerSignature != "" { + var err error + sigBytes, err = evm.HexToBytes(payload.ClaimAuthorizerSignature) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidClaimPayload, "", network, "", + fmt.Sprintf("invalid claim authorizer signature: %s", err)) + } + } else { + // Verify authorizer address matches all claims' receiverAuthorizer + for _, claim := range payload.Claims { + if !strings.EqualFold(claim.Voucher.Channel.ReceiverAuthorizer, authorizerSigner.Address()) { + return nil, x402.NewSettleError(ErrAuthorizerAddressMismatch, "", network, "", + fmt.Sprintf("claim receiverAuthorizer %s does not match authorizerSigner %s", + claim.Voucher.Channel.ReceiverAuthorizer, authorizerSigner.Address())) + } + } + // Auto-sign + var err error + sigBytes, err = authorizerSigner.SignClaimBatch(ctx, payload.Claims, string(network)) + if err != nil { + return nil, x402.NewSettleError(ErrClaimTransactionFailed, "", network, "", + fmt.Sprintf("failed to sign claim batch: %s", err)) + } + } + + claimArgs := buildVoucherClaimArgs(payload.Claims) + + // Simulate the transaction before submitting + if _, simErr := signer.ReadContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementClaimWithSignatureABI, + "claimWithSignature", + claimArgs, + sigBytes, + ); simErr != nil { + return &x402.SettleResponse{ //nolint:nilerr // simulation failure → error encoded in response + Success: false, + ErrorReason: ErrClaimSimulationFailed, + ErrorMessage: simErr.Error(), + Transaction: "", + Network: network, + }, nil + } + + txHash, err := signer.WriteContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementClaimWithSignatureABI, + "claimWithSignature", + claimArgs, + sigBytes, + ) + if err != nil { + return nil, x402.NewSettleError(ErrClaimTransactionFailed, "", network, "", + fmt.Sprintf("claimWithSignature transaction failed: %s", err)) + } + + receipt, err := signer.WaitForTransactionReceipt(ctx, txHash) + if err != nil { + return nil, x402.NewSettleError(ErrWaitForReceipt, txHash, network, "", + fmt.Sprintf("failed waiting for claimWithSignature receipt: %s", err)) + } + if receipt.Status != evm.TxStatusSuccess { + return nil, x402.NewSettleError(ErrTransactionReverted, txHash, network, "", + "claimWithSignature transaction reverted") + } + + return &x402.SettleResponse{ + Success: true, + Transaction: txHash, + Network: network, + }, nil +} + +// buildVoucherClaimArgs builds the Solidity-compatible VoucherClaim[] argument for claim calls. +func buildVoucherClaimArgs(claims []batchsettlement.BatchSettlementVoucherClaim) interface{} { + type VoucherStruct struct { + Channel ContractChannelConfigTuple + MaxClaimableAmount *big.Int + } + type VoucherClaimStruct struct { + Voucher VoucherStruct + Signature []byte + TotalClaimed *big.Int + } + + result := make([]VoucherClaimStruct, len(claims)) + for i, claim := range claims { + maxClaimable, _ := new(big.Int).SetString(claim.Voucher.MaxClaimableAmount, 10) + totalClaimed, _ := new(big.Int).SetString(claim.TotalClaimed, 10) + sigBytes, _ := evm.HexToBytes(claim.Signature) + + channelTuple := ToContractChannelConfig(claim.Voucher.Channel) + + result[i] = VoucherClaimStruct{ + Voucher: VoucherStruct{ + Channel: channelTuple, + MaxClaimableAmount: maxClaimable, + }, + Signature: sigBytes, + TotalClaimed: totalClaimed, + } + } + return result +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/deposit.go b/go/mechanisms/evm/batch-settlement/facilitator/deposit.go new file mode 100644 index 0000000000..0a87b2f10f --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/deposit.go @@ -0,0 +1,666 @@ +package facilitator + +import ( + "context" + "fmt" + "math/big" + "strings" + "time" + + "github.com/ethereum/go-ethereum/common" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// resolveDepositTransferMethod inspects the payload + requirements to pick the +// deposit transport. Defaults to ERC-3009 to preserve historical behavior; +// callers opt into Permit2 by setting `accepts.extra.assetTransferMethod` +// or by sending a Permit2 authorization. +func resolveDepositTransferMethod( + payload *batchsettlement.BatchSettlementDepositPayload, + requirements types.PaymentRequirements, +) batchsettlement.AssetTransferMethod { + if payload.Deposit.Authorization.Permit2Authorization != nil { + return batchsettlement.AssetTransferMethodPermit2 + } + if requirements.Extra != nil { + if v, ok := requirements.Extra["assetTransferMethod"].(string); ok && v != "" { + return batchsettlement.AssetTransferMethod(v) + } + } + return batchsettlement.AssetTransferMethodEip3009 +} + +// VerifyDeposit verifies a batched deposit payload. +// Dispatches on the deposit transfer method (ERC-3009 or Permit2), validates +// the matching authorization, voucher signature, payer balance, and +// maxClaimableAmount, then simulates the onchain deposit to surface revert +// reasons before settle. +// +// `extensions` is the top-level `payment.extensions` envelope and `fctx` is the +// facilitator's registered extension context. Together they enable the EIP-2612 +// and ERC-20 approval gas-sponsoring branches for Permit2 deposits. Both may +// be nil for the standard Permit2 path or for ERC-3009 deposits. +func VerifyDeposit( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + payload *batchsettlement.BatchSettlementDepositPayload, + requirements types.PaymentRequirements, + extensions map[string]interface{}, + fctx *x402.FacilitatorContext, +) (*x402.VerifyResponse, error) { + config := payload.ChannelConfig + channelId := payload.Voucher.ChannelId + + // Validate channel config + if err := ValidateChannelConfig(config, channelId, requirements); err != nil { + return nil, err + } + + // Validate deposit amount + depositAmount, ok := new(big.Int).SetString(payload.Deposit.Amount, 10) + if !ok || depositAmount.Sign() <= 0 { + return nil, x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, + fmt.Sprintf("invalid deposit amount: %s", payload.Deposit.Amount)) + } + + // Get chain ID + chainId, err := signer.GetChainID(ctx) + if err != nil { + return nil, x402.NewVerifyError(ErrChannelStateReadFailed, config.Payer, + fmt.Sprintf("failed to get chain ID: %s", err)) + } + + transferMethod := resolveDepositTransferMethod(payload, requirements) + + // Permit2 branch may consult extensions to choose between standard / + // EIP-2612 / ERC-20 approval execution; resolved once here and reused by + // both the simulation below and the eventual SettleDeposit call. + var permit2Branch *permit2DepositBranch + switch transferMethod { + case batchsettlement.AssetTransferMethodEip3009: + auth := payload.Deposit.Authorization.Erc3009Authorization + if auth == nil { + return nil, x402.NewVerifyError(ErrErc3009AuthorizationRequired, config.Payer, + "erc3009 authorization required for assetTransferMethod=eip3009") + } + if reason, err := verifyErc3009DepositAuthorization( + ctx, signer, config, channelId, depositAmount, auth, chainId, requirements.Extra, + ); err != nil { + return nil, err + } else if reason != "" { + return nil, x402.NewVerifyError(reason, config.Payer, "ERC-3009 authorization invalid") + } + case batchsettlement.AssetTransferMethodPermit2: + auth := payload.Deposit.Authorization.Permit2Authorization + if auth == nil { + return nil, x402.NewVerifyError(ErrPermit2AuthorizationRequired, config.Payer, + "permit2 authorization required for assetTransferMethod=permit2") + } + if reason, err := verifyPermit2DepositAuthorization( + ctx, signer, config, channelId, depositAmount, auth, chainId, + ); err != nil { + return nil, err + } else if reason != "" { + return nil, x402.NewVerifyError(reason, config.Payer, "Permit2 authorization invalid") + } + // Resolve the gas-sponsorship branch (standard / eip2612 / erc20Approval) + // once and reuse it during simulation. Errors here are well-formed + // rejections (e.g. EIP-2612 amount mismatch); internal failures bubble. + branch, reason, branchErr := resolvePermit2DepositBranch( + ctx, auth, payload.Deposit.Amount, + payerAssetView{Payer: config.Payer, Token: config.Token}, + extensions, fctx, string(requirements.Network), + ) + if branchErr != nil { + return nil, x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, + fmt.Sprintf("failed to resolve permit2 deposit branch: %s", branchErr)) + } + if reason != "" { + return nil, x402.NewVerifyError(reason, config.Payer, "Permit2 deposit extension invalid") + } + permit2Branch = branch + default: + return nil, x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, + fmt.Sprintf("unsupported assetTransferMethod: %s", transferMethod)) + } + + // Verify voucher signature + voucherValid, err := VerifyBatchedVoucherTypedData( + ctx, signer, + channelId, + payload.Voucher.MaxClaimableAmount, + config.PayerAuthorizer, + config.Payer, + payload.Voucher.Signature, + chainId, + ) + if err != nil { + return nil, x402.NewVerifyError(ErrVoucherSignatureInvalid, config.Payer, + fmt.Sprintf("voucher signature verification failed: %s", err)) + } + if !voucherValid { + return nil, x402.NewVerifyError(ErrVoucherSignatureInvalid, config.Payer, + "voucher signature is invalid") + } + + // Check payer balance + payerBalance, err := signer.GetBalance(ctx, config.Payer, config.Token) + if err != nil { + return nil, x402.NewVerifyError(ErrChannelStateReadFailed, config.Payer, + fmt.Sprintf("failed to read payer balance: %s", err)) + } + if payerBalance.Cmp(depositAmount) < 0 { + return nil, x402.NewVerifyError(ErrInsufficientBalance, config.Payer, + fmt.Sprintf("payer balance %s is less than deposit amount %s", payerBalance.String(), depositAmount.String())) + } + + // Read existing channel state. + // For brand-new channels the contract returns zero values for all fields; + // ReadChannelState returns those zeros successfully — a nil error with + // Balance=0, TotalClaimed=0 etc. A non-nil error means an actual RPC + // failure, which we surface rather than silently masking. + state, err := ReadChannelState(ctx, signer, channelId) + if err != nil { + return nil, x402.NewVerifyError(ErrChannelStateReadFailed, config.Payer, + fmt.Sprintf("failed to read channel state: %s", err)) + } + + // Validate maxClaimableAmount <= balance + deposit + maxClaimable, ok := new(big.Int).SetString(payload.Voucher.MaxClaimableAmount, 10) + if !ok { + return nil, x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, "invalid maxClaimableAmount") + } + effectiveBalance := new(big.Int).Add(state.Balance, depositAmount) + if maxClaimable.Cmp(effectiveBalance) > 0 { + return nil, x402.NewVerifyError(ErrMaxClaimableExceedsBal, config.Payer, + fmt.Sprintf("maxClaimableAmount %s exceeds effective balance %s", maxClaimable.String(), effectiveBalance.String())) + } + + // Validate maxClaimableAmount > totalClaimed (monotonic increase) + if maxClaimable.Cmp(state.TotalClaimed) < 0 { + return nil, x402.NewVerifyError(ErrMaxClaimableTooLow, config.Payer, + fmt.Sprintf("maxClaimableAmount %s is below totalClaimed %s", maxClaimable.String(), state.TotalClaimed.String())) + } + + // Simulate the deposit transaction to catch onchain errors early. + configTuple := ToContractChannelConfig(config) + collectorAddr, collectorData, err := buildDepositCollectorCall(payload, transferMethod, permit2Branch) + if err != nil { + return nil, x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, + fmt.Sprintf("failed to build collector data for simulation: %s", err)) + } + // ERC-20 approval branch: the user has not yet approved Permit2, so the + // standalone deposit() simulation would always revert with insufficient + // allowance. The execution path is multi-tx (approve+deposit handled by the + // extension signer in `SettleDeposit`); skip the eth_call here. + skipSimulation := permit2Branch != nil && permit2Branch.kind == permit2BranchErc20Approval + if !skipSimulation { + _, simErr := signer.ReadContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementDepositABI, + "deposit", + configTuple, + depositAmount, + collectorAddr, + collectorData, + ) + if simErr != nil { + // Diagnose the most common standard-Permit2-path simulation + // revert: the user hasn't approved Permit2. We probe + // `allowance(payer, Permit2)` and surface the dedicated reason + // when it's below the deposit amount; any other revert (signature + // invalidation, balance, etc.) passes through as the generic + // ErrDepositSimulationFailed. Mirrors exact's + // `CheckPermit2Prerequisites` diagnosis. RPC failures during the + // probe also fall through to the generic reason. + invalidReason := ErrDepositSimulationFailed + if transferMethod == batchsettlement.AssetTransferMethodPermit2 && + (permit2Branch == nil || permit2Branch.kind == permit2BranchStandard) { + if allowanceResult, allowErr := signer.ReadContract( + ctx, + config.Token, + evm.ERC20AllowanceABI, + "allowance", + common.HexToAddress(config.Payer), + common.HexToAddress(evm.PERMIT2Address), + ); allowErr == nil { + if allowance, ok := allowanceResult.(*big.Int); ok && allowance != nil && + allowance.Cmp(depositAmount) < 0 { + invalidReason = ErrPermit2AllowanceRequired + } + } + } + return &x402.VerifyResponse{ //nolint:nilerr // simulation failure → error encoded in response + IsValid: false, + InvalidReason: invalidReason, + Payer: config.Payer, + }, nil + } + } + + // Build response with projected state after deposit + projectedState := &batchsettlement.ChannelState{ + Balance: effectiveBalance, + TotalClaimed: state.TotalClaimed, + WithdrawRequestedAt: state.WithdrawRequestedAt, + RefundNonce: state.RefundNonce, + } + + return &x402.VerifyResponse{ + IsValid: true, + Payer: config.Payer, + Extra: BuildVerifyExtra(channelId, projectedState), + }, nil +} + +// SettleDeposit executes a deposit onchain. +// Calls deposit(config, amount, collector, collectorData) on the BatchSettlement contract. +// +// `extensions` is the top-level `payment.extensions` envelope and `fctx` is the +// facilitator's registered extension context. They activate the ERC-20 approval +// gas-sponsoring branch (which broadcasts a pre-signed approve() before the +// deposit() via `Erc20ApprovalGasSponsoringSigner.SendTransactions`) and the +// EIP-2612 permit segment (encoded into `collectorData`). Both may be nil for +// the standard Permit2 path or for ERC-3009 deposits. +func SettleDeposit( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + payload *batchsettlement.BatchSettlementDepositPayload, + requirements types.PaymentRequirements, + extensions map[string]interface{}, + fctx *x402.FacilitatorContext, +) (*x402.SettleResponse, error) { + config := payload.ChannelConfig + network := x402.Network(requirements.Network) + + depositAmount, ok := new(big.Int).SetString(payload.Deposit.Amount, 10) + if !ok { + return nil, x402.NewSettleError(ErrInvalidDepositPayload, "", network, config.Payer, + fmt.Sprintf("invalid deposit amount: %s", payload.Deposit.Amount)) + } + + // Dispatch on transfer method (ERC-3009 vs Permit2) and build the matching + // collector address + data for the onchain `deposit(config, amount, + // collector, collectorData)` call. For Permit2, also resolve the + // gas-sponsorship branch so settle uses the same execution path verify + // already greenlit. + transferMethod := resolveDepositTransferMethod(payload, requirements) + var permit2Branch *permit2DepositBranch + if transferMethod == batchsettlement.AssetTransferMethodPermit2 { + auth := payload.Deposit.Authorization.Permit2Authorization + if auth == nil { + return nil, x402.NewSettleError(ErrPermit2AuthorizationRequired, "", network, config.Payer, + "permit2 authorization required for assetTransferMethod=permit2") + } + branch, reason, branchErr := resolvePermit2DepositBranch( + ctx, auth, payload.Deposit.Amount, + payerAssetView{Payer: config.Payer, Token: config.Token}, + extensions, fctx, string(requirements.Network), + ) + if branchErr != nil { + return nil, x402.NewSettleError(ErrInvalidDepositPayload, "", network, config.Payer, + fmt.Sprintf("failed to resolve permit2 deposit branch: %s", branchErr)) + } + if reason != "" { + return nil, x402.NewSettleError(reason, "", network, config.Payer, + "Permit2 deposit extension invalid at settle") + } + permit2Branch = branch + } + + collectorAddr, collectorData, err := buildDepositCollectorCall(payload, transferMethod, permit2Branch) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidDepositPayload, "", network, config.Payer, + fmt.Sprintf("failed to build collector data: %s", err)) + } + + // Build channel config tuple for contract call + configTuple := ToContractChannelConfig(config) + + // Branch on extension settlement strategy: + // erc20Approval → broadcast pre-signed approve() then deposit() via the + // facilitator extension signer's SendTransactions. + // else → single deposit() write through the facilitator signer. + var txHash string + if permit2Branch != nil && permit2Branch.kind == permit2BranchErc20Approval { + settleCall := erc20approvalgassponsor.WriteContractCall{ + Address: batchsettlement.BatchSettlementAddress, + ABI: batchsettlement.BatchSettlementDepositABI, + Function: "deposit", + Args: []interface{}{configTuple, depositAmount, collectorAddr, collectorData}, + } + txHashes, sendErr := permit2Branch.extensionSigner.SendTransactions(ctx, []erc20approvalgassponsor.TransactionRequest{ + {Serialized: permit2Branch.erc20Info.SignedTransaction}, + {Call: &settleCall}, + }) + if sendErr != nil { + return nil, x402.NewSettleError(ErrErc20ApprovalBroadcastFailed, "", network, config.Payer, + fmt.Sprintf("erc20 approval + deposit send failed: %s", sendErr)) + } + if len(txHashes) < 2 { + return nil, x402.NewSettleError(ErrDepositTransactionFailed, "", network, config.Payer, + fmt.Sprintf("expected 2 tx hashes from extension signer, got %d", len(txHashes))) + } + // The deposit tx is the second; this is what we wait on and report + // back as the settlement transaction. + txHash = txHashes[1] + } else { + txHash, err = signer.WriteContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementDepositABI, + "deposit", + configTuple, + depositAmount, + collectorAddr, + collectorData, + ) + if err != nil { + return nil, x402.NewSettleError(ErrDepositTransactionFailed, "", network, config.Payer, + fmt.Sprintf("deposit transaction failed: %s", err)) + } + } + + // Wait for receipt + receipt, err := signer.WaitForTransactionReceipt(ctx, txHash) + if err != nil { + return nil, x402.NewSettleError(ErrWaitForReceipt, txHash, network, config.Payer, + fmt.Sprintf("failed waiting for deposit receipt: %s", err)) + } + if receipt.Status != evm.TxStatusSuccess { + return nil, x402.NewSettleError(ErrTransactionReverted, txHash, network, config.Payer, + "deposit transaction reverted") + } + + // Optimistic post-deposit extra (fallback if RPC hasn't caught up to + // the just-confirmed tx). The settle response intentionally omits + // `chargedCumulativeAmount` — that field is added by the resource + // server's `enrichSettlementResponse` hook, and emitting + // it from the facilitator violates the additive-enrichment policy. + priorState, _ := ReadChannelState(ctx, signer, payload.Voucher.ChannelId) + priorBalance := big.NewInt(0) + priorTotalClaimed := big.NewInt(0) + priorWithdrawRequestedAt := 0 + priorRefundNonce := big.NewInt(0) + if priorState != nil { + if priorState.Balance != nil { + priorBalance = priorState.Balance + } + if priorState.TotalClaimed != nil { + priorTotalClaimed = priorState.TotalClaimed + } + priorWithdrawRequestedAt = priorState.WithdrawRequestedAt + if priorState.RefundNonce != nil { + priorRefundNonce = priorState.RefundNonce + } + } + optimisticBalance := new(big.Int).Add(priorBalance, depositAmount) + optimisticState := &batchsettlement.ChannelState{ + Balance: optimisticBalance, + TotalClaimed: priorTotalClaimed, + WithdrawRequestedAt: priorWithdrawRequestedAt, + RefundNonce: priorRefundNonce, + } + + // Poll the RPC until it reflects the just-confirmed deposit, so subsequent + // verify reads are guaranteed to see this balance. + expectedMinBalance := new(big.Int).Set(optimisticBalance) + deadline := time.Now().Add(2 * time.Second) + postState, _ := ReadChannelState(ctx, signer, payload.Voucher.ChannelId) + for postState == nil || postState.Balance == nil || postState.Balance.Cmp(expectedMinBalance) < 0 { + if time.Now().After(deadline) { + break + } + time.Sleep(150 * time.Millisecond) + postState, _ = ReadChannelState(ctx, signer, payload.Voucher.ChannelId) + } + + finalState := optimisticState + if postState != nil && postState.Balance != nil && postState.Balance.Cmp(expectedMinBalance) >= 0 { + finalState = postState + } + + extra := BuildSettleExtra(payload.Voucher.ChannelId, finalState) + + return &x402.SettleResponse{ + Success: true, + Transaction: txHash, + Network: network, + Payer: config.Payer, + Amount: payload.Deposit.Amount, + Extra: extra, + }, nil +} + +// buildDepositCollectorCall returns the onchain `(collector, collectorData)` +// pair needed by the BatchSettlement `deposit` call for the given transfer +// method. For Permit2, a non-nil `branch` provides the resolved +// gas-sponsorship execution path (standard / EIP-2612 / ERC-20 approval) and +// its pre-encoded `collectorData` (with EIP-2612 permit bytes appended where +// applicable). When `branch` is nil for Permit2 (legacy callers), the standard +// path is used. +func buildDepositCollectorCall( + payload *batchsettlement.BatchSettlementDepositPayload, + method batchsettlement.AssetTransferMethod, + branch *permit2DepositBranch, +) (common.Address, []byte, error) { + switch method { + case batchsettlement.AssetTransferMethodEip3009: + auth := payload.Deposit.Authorization.Erc3009Authorization + if auth == nil { + return common.Address{}, nil, fmt.Errorf("no ERC-3009 authorization provided") + } + data, err := batchsettlement.BuildErc3009CollectorData(auth.ValidAfter, auth.ValidBefore, auth.Salt, auth.Signature) + if err != nil { + return common.Address{}, nil, err + } + return common.HexToAddress(batchsettlement.ERC3009DepositCollectorAddress), data, nil + case batchsettlement.AssetTransferMethodPermit2: + auth := payload.Deposit.Authorization.Permit2Authorization + if auth == nil { + return common.Address{}, nil, fmt.Errorf("no Permit2 authorization provided") + } + var data []byte + var err error + if branch != nil { + data = branch.collectorData + } else { + data, err = batchsettlement.BuildPermit2CollectorData(auth.Nonce, auth.Deadline, auth.Signature, nil) + if err != nil { + return common.Address{}, nil, err + } + } + return common.HexToAddress(batchsettlement.Permit2DepositCollectorAddress), data, nil + default: + return common.Address{}, nil, fmt.Errorf("unsupported assetTransferMethod: %s", method) + } +} + +// verifyErc3009DepositAuthorization validates the time window and EIP-712 +// `ReceiveWithAuthorization` signature for an ERC-3009 deposit. +// +// The token's EIP-712 domain (`name` / `version`) is consumed from +// `extra.name` / `extra.version`. Resource servers populate these from cached +// asset metadata when constructing payment requirements (see +// `BatchSettlementEvmScheme.GetExtra` in the server package); a missing or +// blank field is reported as `ErrMissingEip712Domain`. +// +// Returns ("invalidReason", nil) when the authorization is well-formed but +// invalid, ("", err) when an RPC/parse error blocked verification entirely, +// or ("", nil) when the authorization is valid. +func verifyErc3009DepositAuthorization( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + config batchsettlement.ChannelConfig, + channelId string, + depositAmount *big.Int, + auth *batchsettlement.BatchSettlementErc3009Authorization, + chainId *big.Int, + extra map[string]interface{}, +) (string, error) { + validAfter, ok := new(big.Int).SetString(auth.ValidAfter, 10) + if !ok { + return "", x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, "invalid validAfter") + } + validBefore, ok := new(big.Int).SetString(auth.ValidBefore, 10) + if !ok { + return "", x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, "invalid validBefore") + } + if reason := Erc3009AuthorizationTimeInvalidReason(validAfter, validBefore); reason != "" { + return reason, nil + } + + // Token EIP-712 domain — required to recompute the + // `ReceiveWithAuthorization` digest. Read from `requirements.extra` + // (populated by the resource server's GetExtra hook); missing fields are + // reported as a structured ErrMissingEip712Domain rejection. + tokenName, _ := extra["name"].(string) + tokenVersion, _ := extra["version"].(string) + if tokenName == "" || tokenVersion == "" { + return ErrMissingEip712Domain, nil + } + + erc3009Nonce, err := batchsettlement.BuildErc3009DepositNonce(channelId, auth.Salt) + if err != nil { + return "", x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, + fmt.Sprintf("failed to derive ERC-3009 nonce: %s", err)) + } + saltBytes, err := evm.HexToBytes(erc3009Nonce) + if err != nil { + return "", x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, + fmt.Sprintf("invalid erc3009 nonce: %s", err)) + } + sigBytes, err := evm.HexToBytes(auth.Signature) + if err != nil { + return "", x402.NewVerifyError(ErrErc3009SignatureInvalid, config.Payer, + fmt.Sprintf("invalid erc3009 signature: %s", err)) + } + + valid, err := signer.VerifyTypedData( + ctx, + config.Payer, + evm.TypedDataDomain{ + Name: tokenName, + Version: tokenVersion, + ChainID: chainId, + VerifyingContract: config.Token, + }, + batchsettlement.ReceiveAuthorizationTypes, + "ReceiveWithAuthorization", + map[string]interface{}{ + "from": config.Payer, + "to": batchsettlement.ERC3009DepositCollectorAddress, + "value": depositAmount, + "validAfter": validAfter, + "validBefore": validBefore, + "nonce": saltBytes, + }, + sigBytes, + ) + if err != nil { + return "", x402.NewVerifyError(ErrErc3009SignatureInvalid, config.Payer, + fmt.Sprintf("ERC-3009 signature verification failed: %s", err)) + } + if !valid { + return ErrErc3009SignatureInvalid, nil + } + return "", nil +} + +// verifyPermit2DepositAuthorization validates the channel-bound Permit2 +// PermitWitnessTransferFrom signature for a deposit. Verifies that: +// - permitted.token == channelConfig.token +// - witness.channelId == voucher.channelId +// - spender == Permit2DepositCollectorAddress +// - permitted.amount == deposit.amount +// - the EIP-712 signature recovers to channelConfig.payer +// +// Returns ("invalidReason", nil) on a well-formed but rejected authorization. +// Token mismatch, spender mismatch, deadline expiry, amount mismatch, and +// signature failure each map to a dedicated machine-readable error string. +func verifyPermit2DepositAuthorization( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + config batchsettlement.ChannelConfig, + channelId string, + depositAmount *big.Int, + auth *batchsettlement.BatchSettlementPermit2Authorization, + chainId *big.Int, +) (string, error) { + if !strings.EqualFold(auth.Permitted.Token, config.Token) { + return ErrTokenMismatch, nil + } + if !strings.EqualFold(auth.Witness.ChannelId, channelId) { + return ErrChannelIdMismatch, nil + } + if !strings.EqualFold(auth.Spender, batchsettlement.Permit2DepositCollectorAddress) { + return ErrPermit2InvalidSpender, nil + } + if auth.Permitted.Amount != depositAmount.String() { + return ErrPermit2AmountMismatch, nil + } + if !strings.EqualFold(auth.From, config.Payer) { + return ErrInvalidDepositPayload, nil + } + + nonceBig, ok := new(big.Int).SetString(auth.Nonce, 10) + if !ok { + return "", x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, "invalid permit2 nonce") + } + deadlineBig, ok := new(big.Int).SetString(auth.Deadline, 10) + if !ok { + return "", x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, "invalid permit2 deadline") + } + if deadlineBig.Sign() > 0 && deadlineBig.Cmp(big.NewInt(currentTimestamp())) < 0 { + return ErrPermit2DeadlineExpired, nil + } + channelIdBytes, err := evm.HexToBytes(channelId) + if err != nil { + return "", x402.NewVerifyError(ErrInvalidDepositPayload, config.Payer, "invalid channel id") + } + sigBytes, err := evm.HexToBytes(auth.Signature) + if err != nil { + return "", x402.NewVerifyError(ErrPermit2InvalidSignature, config.Payer, + fmt.Sprintf("invalid permit2 signature: %s", err)) + } + + domain := evm.TypedDataDomain{ + Name: batchsettlement.Permit2DomainName, + ChainID: chainId, + VerifyingContract: batchsettlement.Permit2Address, + } + message := map[string]interface{}{ + "permitted": map[string]interface{}{ + "token": evm.NormalizeAddress(auth.Permitted.Token), + "amount": depositAmount, + }, + "spender": evm.NormalizeAddress(auth.Spender), + "nonce": nonceBig, + "deadline": deadlineBig, + "witness": map[string]interface{}{ + "channelId": channelIdBytes, + }, + } + valid, err := signer.VerifyTypedData( + ctx, config.Payer, + domain, + batchsettlement.BatchPermit2WitnessTypes, + "PermitWitnessTransferFrom", + message, + sigBytes, + ) + if err != nil { + return "", x402.NewVerifyError(ErrPermit2InvalidSignature, config.Payer, + fmt.Sprintf("permit2 signature verification failed: %s", err)) + } + if !valid { + return ErrPermit2InvalidSignature, nil + } + return "", nil +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/deposit_eip3009_test.go b/go/mechanisms/evm/batch-settlement/facilitator/deposit_eip3009_test.go new file mode 100644 index 0000000000..f5f40ddd2d --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/deposit_eip3009_test.go @@ -0,0 +1,217 @@ +package facilitator + +import ( + "context" + "errors" + "fmt" + "math/big" + "strings" + "testing" + "time" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +const ( + testErc3009Payer = "0x1111111111111111111111111111111111111111" + testErc3009Token = "0x2222222222222222222222222222222222222222" + testErc3009ChannelId = "0x3333333333333333333333333333333333333333333333333333333333333333" +) + +func goodErc3009Auth() *batchsettlement.BatchSettlementErc3009Authorization { + now := time.Now().Unix() + return &batchsettlement.BatchSettlementErc3009Authorization{ + ValidAfter: fmt.Sprintf("%d", now-60), + ValidBefore: fmt.Sprintf("%d", now+3600), + Salt: "0x" + strings.Repeat("aa", 32), + Signature: "0x" + strings.Repeat("11", 65), + } +} + +func goodErc3009Config() batchsettlement.ChannelConfig { + return batchsettlement.ChannelConfig{ + Payer: testErc3009Payer, + PayerAuthorizer: testErc3009Payer, + Receiver: "0xreceiver000000000000000000000000000000ab", + ReceiverAuthorizer: "0xreceiver000000000000000000000000000000ab", + Token: testErc3009Token, + WithdrawDelay: 900, + Salt: "0x" + strings.Repeat("00", 32), + } +} + +// goodErc3009Extra returns the resource-server-populated `requirements.extra` +// shape the ERC-3009 verifier consumes. +func goodErc3009Extra() map[string]interface{} { + return map[string]interface{}{ + "name": "USD Coin", + "version": "2", + } +} + +// stubErc3009Signer overrides VerifyTypedData on top of fakeFacilitatorSigner +// so individual ERC-3009 verify branches can be exercised without a live RPC. +type stubErc3009Signer struct { + fakeFacilitatorSigner + verifyTypedDataResult bool + verifyTypedDataErr error +} + +func (s *stubErc3009Signer) VerifyTypedData(_ context.Context, _ string, _ evm.TypedDataDomain, _ map[string][]evm.TypedDataField, _ string, _ map[string]interface{}, _ []byte) (bool, error) { + return s.verifyTypedDataResult, s.verifyTypedDataErr +} + +// TestVerifyErc3009_InvalidValidAfter pins the malformed-input branch: a +// non-numeric `validAfter` is rejected before any signer call so the +// downstream RPC path isn't reached. +func TestVerifyErc3009_InvalidValidAfter(t *testing.T) { + auth := goodErc3009Auth() + auth.ValidAfter = "not-a-number" + _, err := verifyErc3009DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodErc3009Config(), testErc3009ChannelId, + big.NewInt(1000), auth, big.NewInt(8453), goodErc3009Extra(), + ) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrInvalidDepositPayload { + t.Fatalf("got %v", err) + } +} + +// TestVerifyErc3009_InvalidValidBefore mirrors the validAfter case above so +// both numeric input fields are guarded by the same invalid-payload reason. +func TestVerifyErc3009_InvalidValidBefore(t *testing.T) { + auth := goodErc3009Auth() + auth.ValidBefore = "not-a-number" + _, err := verifyErc3009DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodErc3009Config(), testErc3009ChannelId, + big.NewInt(1000), auth, big.NewInt(8453), goodErc3009Extra(), + ) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrInvalidDepositPayload { + t.Fatalf("got %v", err) + } +} + +// TestVerifyErc3009_ValidBeforeExpired pins the time-window check: an +// already-expired authorization must surface ErrValidBeforeExpired as a +// well-formed-but-rejected reason (not as an internal error). +func TestVerifyErc3009_ValidBeforeExpired(t *testing.T) { + auth := goodErc3009Auth() + now := time.Now().Unix() + auth.ValidAfter = fmt.Sprintf("%d", now-3600) + auth.ValidBefore = fmt.Sprintf("%d", now-60) + reason, err := verifyErc3009DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodErc3009Config(), testErc3009ChannelId, + big.NewInt(1000), auth, big.NewInt(8453), goodErc3009Extra(), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrValidBeforeExpired { + t.Fatalf("reason = %q, want %q", reason, ErrValidBeforeExpired) + } +} + +// TestVerifyErc3009_ValidAfterInFuture pins the not-yet-valid branch: an +// authorization whose validAfter is in the future must surface +// ErrValidAfterInFuture as a well-formed-but-rejected reason. +func TestVerifyErc3009_ValidAfterInFuture(t *testing.T) { + auth := goodErc3009Auth() + now := time.Now().Unix() + auth.ValidAfter = fmt.Sprintf("%d", now+3600) + auth.ValidBefore = fmt.Sprintf("%d", now+7200) + reason, err := verifyErc3009DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodErc3009Config(), testErc3009ChannelId, + big.NewInt(1000), auth, big.NewInt(8453), goodErc3009Extra(), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrValidAfterInFuture { + t.Fatalf("reason = %q, want %q", reason, ErrValidAfterInFuture) + } +} + +// TestVerifyErc3009_MissingExtraName pins the structured-rejection branch when +// the resource server forgot to populate `requirements.extra.name`. The ERC-3009 +// deposit collector needs the token's EIP-712 domain to recompute the digest, so +// the facilitator must surface ErrMissingEip712Domain instead of a generic +// invalid-payload reason. +func TestVerifyErc3009_MissingExtraName(t *testing.T) { + extra := goodErc3009Extra() + delete(extra, "name") + reason, err := verifyErc3009DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodErc3009Config(), testErc3009ChannelId, + big.NewInt(1000), goodErc3009Auth(), big.NewInt(8453), extra, + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrMissingEip712Domain { + t.Fatalf("reason = %q, want %q", reason, ErrMissingEip712Domain) + } +} + +// TestVerifyErc3009_MissingExtraVersion mirrors the missing-name case for the +// version field — both are required and the facilitator should not assume a +// silent default like "1", which would mask resource-server misconfiguration. +func TestVerifyErc3009_MissingExtraVersion(t *testing.T) { + extra := goodErc3009Extra() + delete(extra, "version") + reason, err := verifyErc3009DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodErc3009Config(), testErc3009ChannelId, + big.NewInt(1000), goodErc3009Auth(), big.NewInt(8453), extra, + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrMissingEip712Domain { + t.Fatalf("reason = %q, want %q", reason, ErrMissingEip712Domain) + } +} + +// TestVerifyErc3009_NilExtra pins the same defensive behavior when the +// extra map itself is nil (e.g. legacy callers / cached requirements without +// metadata). Reading a nil map is well-defined in Go and yields the +// zero-value string, so the missing-domain check still fires. +func TestVerifyErc3009_NilExtra(t *testing.T) { + reason, err := verifyErc3009DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodErc3009Config(), testErc3009ChannelId, + big.NewInt(1000), goodErc3009Auth(), big.NewInt(8453), nil, + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrMissingEip712Domain { + t.Fatalf("reason = %q, want %q", reason, ErrMissingEip712Domain) + } +} + +// TestVerifyErc3009_VerifyTypedDataFalse pins the signature-rejected branch: +// when the signer reports the EIP-712 signature as invalid, the helper must +// surface ErrErc3009SignatureInvalid as a well-formed-but-rejected reason +// (not as an internal error). The valid extra ensures we reach the signer +// instead of short-circuiting on a missing-domain check. +func TestVerifyErc3009_VerifyTypedDataFalse(t *testing.T) { + signer := &stubErc3009Signer{verifyTypedDataResult: false} + reason, err := verifyErc3009DepositAuthorization( + context.Background(), signer, + goodErc3009Config(), testErc3009ChannelId, + big.NewInt(1000), goodErc3009Auth(), big.NewInt(8453), goodErc3009Extra(), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrErc3009SignatureInvalid { + t.Fatalf("reason = %q, want %q", reason, ErrErc3009SignatureInvalid) + } +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/deposit_permit2.go b/go/mechanisms/evm/batch-settlement/facilitator/deposit_permit2.go new file mode 100644 index 0000000000..8d7a53167b --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/deposit_permit2.go @@ -0,0 +1,191 @@ +package facilitator + +import ( + "context" + "strings" + + "github.com/ethereum/go-ethereum/common" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +// permit2DepositBranchKind enumerates the three Permit2 deposit settlement +// strategies. +type permit2DepositBranchKind string + +const ( + permit2BranchStandard permit2DepositBranchKind = "standard" + permit2BranchEip2612 permit2DepositBranchKind = "eip2612" + permit2BranchErc20Approval permit2DepositBranchKind = "erc20Approval" +) + +// permit2DepositBranch captures the resolved gas-sponsorship branch for a +// Permit2 batch-settlement deposit. Verify and settle share the result so +// they encode the same `collectorData` and pick the same execution path. +// +// kind=="standard" → no extension; facilitator submits a single +// +// deposit() tx with empty EIP-2612 segment. +// +// kind=="eip2612" → encoded EIP-2612 permit segment is appended to +// +// `collectorData`; facilitator still submits a single deposit() tx. +// +// kind=="erc20Approval" → facilitator extension signer broadcasts a +// +// pre-signed approve() then deposit() (multi-tx). +type permit2DepositBranch struct { + kind permit2DepositBranchKind + collectorData []byte + erc20Info *erc20approvalgassponsor.Info + extensionSigner erc20approvalgassponsor.Erc20ApprovalGasSponsoringSigner +} + +// resolvePermit2DepositBranch parses the payment payload's `extensions` +// envelope and decides which gas-sponsorship branch to take. +// +// On a well-formed but rejected extension (e.g. payer/asset/amount mismatch) +// returns ("invalidReason", nil); on a successful branch resolution returns +// (branch, "", nil); on an internal error returns (nil, "", err). +func resolvePermit2DepositBranch( + _ context.Context, + auth *batchsettlement.BatchSettlementPermit2Authorization, + depositAmount string, + requirements payerAssetView, + extensions map[string]interface{}, + fctx *x402.FacilitatorContext, + network string, +) (*permit2DepositBranch, string, error) { + tokenAddress := evm.NormalizeAddress(requirements.Token) + payer := requirements.Payer + + // EIP-2612 takes priority over ERC-20 approval because it keeps settlement + // to a single deposit() transaction. + eip2612Info, _ := eip2612gassponsor.ExtractEip2612GasSponsoringInfo(extensions) + if eip2612Info != nil { + // Wrap the shared evm validator with the batch-specific rule that + // `info.amount == deposit.amount`, then translate the shared reason + // strings into the batched error codes. + if sharedReason := evm.ValidateEip2612PermitForPayment(eip2612Info, payer, tokenAddress); sharedReason != "" { + var batchedReason string + switch sharedReason { + case "invalid_eip2612_extension_format": + batchedReason = ErrEip2612InvalidFormat + case "eip2612_from_mismatch": + batchedReason = ErrEip2612OwnerMismatch + case "eip2612_asset_mismatch": + batchedReason = ErrEip2612AssetMismatch + case "eip2612_spender_not_permit2": + batchedReason = ErrEip2612SpenderMismatch + case "eip2612_deadline_expired": + batchedReason = ErrEip2612DeadlineExpired + default: + batchedReason = sharedReason + } + return nil, batchedReason, nil + } + if eip2612Info.Amount != depositAmount { + return nil, ErrEip2612AmountMismatch, nil + } + v, r, s, signatureOK := splitEip2612Signature(eip2612Info.Signature) + if !signatureOK { + return nil, ErrEip2612InvalidSignature, nil + } + eip2612Bytes, encodeErr := batchsettlement.BuildEip2612PermitData(batchsettlement.Eip2612PermitInput{ + Value: eip2612Info.Amount, + Deadline: eip2612Info.Deadline, + V: v, + R: bytes32Hex(r), + S: bytes32Hex(s), + }) + if encodeErr != nil { + return nil, "", encodeErr + } + collectorData, err := batchsettlement.BuildPermit2CollectorData(auth.Nonce, auth.Deadline, auth.Signature, eip2612Bytes) + if err != nil { + return nil, "", err + } + return &permit2DepositBranch{ + kind: permit2BranchEip2612, + collectorData: collectorData, + }, "", nil + } + + erc20Info, _ := erc20approvalgassponsor.ExtractInfo(extensions) + if erc20Info != nil { + if fctx == nil { + return nil, ErrErc20ApprovalUnavailable, nil + } + ext, ok := fctx.GetExtension(erc20approvalgassponsor.ERC20ApprovalGasSponsoring.Key()).(*erc20approvalgassponsor.Erc20ApprovalFacilitatorExtension) + if !ok || ext == nil { + return nil, ErrErc20ApprovalUnavailable, nil + } + extSigner := ext.ResolveSigner(network) + if extSigner == nil { + return nil, ErrErc20ApprovalUnavailable, nil + } + // Validate the signed approve tx against batch-specific + // expectations. Wire format mirrors exact (`approve(Permit2, + // MaxUint256)` signed tx). + switch { + case !erc20approvalgassponsor.ValidateInfo(erc20Info): + return nil, ErrErc20ApprovalInvalidFormat, nil + case !strings.EqualFold(erc20Info.From, payer): + return nil, ErrErc20ApprovalFromMismatch, nil + case !strings.EqualFold(erc20Info.Asset, tokenAddress): + return nil, ErrErc20ApprovalAssetMismatch, nil + case !strings.EqualFold(erc20Info.Spender, evm.PERMIT2Address): + return nil, ErrErc20ApprovalWrongSpender, nil + } + // ERC-20 approval branch: standard Permit2 collectorData (no EIP-2612 + // segment); the approve() tx is broadcast separately by the extension + // signer ahead of the deposit() tx in `SettleDeposit`. + collectorData, err := batchsettlement.BuildPermit2CollectorData(auth.Nonce, auth.Deadline, auth.Signature, nil) + if err != nil { + return nil, "", err + } + return &permit2DepositBranch{ + kind: permit2BranchErc20Approval, + collectorData: collectorData, + erc20Info: erc20Info, + extensionSigner: extSigner, + }, "", nil + } + + // No extension supplied: standard Permit2 path. Caller will simulate against + // the existing on-chain allowance and reject with `permit2_allowance_required` + // if the user hasn't pre-approved Permit2. + collectorData, err := batchsettlement.BuildPermit2CollectorData(auth.Nonce, auth.Deadline, auth.Signature, nil) + if err != nil { + return nil, "", err + } + return &permit2DepositBranch{ + kind: permit2BranchStandard, + collectorData: collectorData, + }, "", nil +} + +// payerAssetView is the narrow projection of the deposit payload + requirements +// that resolvePermit2DepositBranch needs. Defined as a small struct so the +// resolver doesn't need to import the full BatchSettlementDepositPayload / channel +// types — keeps the signature stable and easier to test. +type payerAssetView struct { + Payer string + Token string +} + +func splitEip2612Signature(signature string) (uint8, [32]byte, [32]byte, bool) { + v, r, s, err := evm.SplitEip2612Signature(signature) + return v, r, s, err == nil +} + +// bytes32Hex converts a [32]byte to a 0x-prefixed hex string suitable for +// `BuildEip2612PermitData`'s R/S inputs (which accept either prefixed or +// unprefixed hex). Used twice (R and S) by `resolvePermit2DepositBranch`. +func bytes32Hex(b [32]byte) string { + return common.BytesToHash(b[:]).Hex() +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/deposit_permit2_extensions_test.go b/go/mechanisms/evm/batch-settlement/facilitator/deposit_permit2_extensions_test.go new file mode 100644 index 0000000000..c480fe8d0b --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/deposit_permit2_extensions_test.go @@ -0,0 +1,346 @@ +package facilitator + +import ( + "context" + "testing" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" +) + +// canonicalPayer is a checksummed-address-shaped fixture used across tests. +// Format must match `addressPattern` in the extension validators (40 hex chars +// after 0x), which is why the unit tests above use 0x1111... for the payer. +const ( + extPayer = "0x1111111111111111111111111111111111111111" + extToken = "0x2222222222222222222222222222222222222222" + extOwner = extPayer + extAmount = "1000" + // futureDeadline is a unix timestamp far in the future so the deadline + // validation in evm.ValidateEip2612PermitForPayment passes. + futureDeadline = "9999999999" + // 65-byte hex string formed from 130 hex chars; passes hexPattern. + signature65Bytes = "0x" + // sentinel for clarity + "11111111111111111111111111111111" + + "11111111111111111111111111111111" + + "22222222222222222222222222222222" + + "22222222222222222222222222222222" + + "01" +) + +// extensionsWithEip2612 wraps a fully-populated Info into the envelope shape +// `eip2612gassponsor.ExtractEip2612GasSponsoringInfo` expects. +func extensionsWithEip2612(info *eip2612gassponsor.Info) map[string]interface{} { + return map[string]interface{}{ + eip2612gassponsor.EIP2612GasSponsoring.Key(): map[string]interface{}{ + "info": info, + }, + } +} + +func extensionsWithErc20Approval(info *erc20approvalgassponsor.Info) map[string]interface{} { + return map[string]interface{}{ + erc20approvalgassponsor.ERC20ApprovalGasSponsoring.Key(): map[string]interface{}{ + "info": info, + }, + } +} + +// goodEip2612Info returns a valid EIP-2612 Info matching the deposit amount +// and the canonical Permit2 spender. +func goodEip2612Info() *eip2612gassponsor.Info { + return &eip2612gassponsor.Info{ + From: extOwner, + Asset: extToken, + Spender: evm.PERMIT2Address, + Amount: extAmount, + Nonce: "0", + Deadline: futureDeadline, + Signature: signature65Bytes, + Version: "1", + } +} + +func goodErc20ApprovalInfo() *erc20approvalgassponsor.Info { + return &erc20approvalgassponsor.Info{ + From: extOwner, + Asset: extToken, + Spender: evm.PERMIT2Address, + Amount: extAmount, + // Minimal valid hex; ValidateInfo only checks the format pattern, + // not RLP-decodability. + SignedTransaction: "0x02", + Version: erc20approvalgassponsor.ERC20ApprovalGasSponsoringVersion, + } +} + +func TestResolvePermit2DepositBranch_StandardWhenNoExtensions(t *testing.T) { + auth := goodPermit2Auth() + branch, reason, err := resolvePermit2DepositBranch( + context.Background(), auth, extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + nil, nil, "eip155:84532", + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != "" { + t.Fatalf("reason = %q, want empty", reason) + } + if branch == nil { + t.Fatal("branch is nil") + } + if branch.kind != permit2BranchStandard { + t.Fatalf("kind = %q, want %q", branch.kind, permit2BranchStandard) + } + if len(branch.collectorData) == 0 { + t.Fatal("collectorData should be populated for standard path") + } +} + +// TestResolvePermit2DepositBranch_Eip2612HappyPath confirms a valid EIP-2612 +// extension resolves to the eip2612 branch with non-empty collectorData. The +// collectorData must be larger than the standard path's encoding (which has +// an empty 4th ABI segment) because it now carries the 5-tuple permit blob. +func TestResolvePermit2DepositBranch_Eip2612HappyPath(t *testing.T) { + auth := goodPermit2Auth() + standard, _, _ := resolvePermit2DepositBranch( + context.Background(), auth, extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + nil, nil, "eip155:84532", + ) + branch, reason, err := resolvePermit2DepositBranch( + context.Background(), auth, extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + extensionsWithEip2612(goodEip2612Info()), + nil, "eip155:84532", + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != "" { + t.Fatalf("reason = %q, want empty", reason) + } + if branch.kind != permit2BranchEip2612 { + t.Fatalf("kind = %q, want %q", branch.kind, permit2BranchEip2612) + } + if len(branch.collectorData) <= len(standard.collectorData) { + t.Fatalf("eip2612 collectorData (%d bytes) should be longer than standard (%d bytes) — eip2612 segment must be encoded", + len(branch.collectorData), len(standard.collectorData)) + } +} + +// TestResolvePermit2DepositBranch_Eip2612AmountMismatch is the regression for +// the batch-specific rule that info.Amount must equal the deposit amount. +// This rule is what prevents a payer from gas-sponsoring a smaller permit +// than the channel deposit they are funding. +func TestResolvePermit2DepositBranch_Eip2612AmountMismatch(t *testing.T) { + info := goodEip2612Info() + info.Amount = "999" // != extAmount + branch, reason, err := resolvePermit2DepositBranch( + context.Background(), goodPermit2Auth(), extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + extensionsWithEip2612(info), + nil, "eip155:84532", + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrEip2612AmountMismatch { + t.Fatalf("reason = %q, want %q", reason, ErrEip2612AmountMismatch) + } + if branch != nil { + t.Fatal("branch should be nil on rejection") + } +} + +func TestResolvePermit2DepositBranch_Eip2612OwnerMismatch(t *testing.T) { + info := goodEip2612Info() + info.From = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + _, reason, _ := resolvePermit2DepositBranch( + context.Background(), goodPermit2Auth(), extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + extensionsWithEip2612(info), + nil, "eip155:84532", + ) + if reason != ErrEip2612OwnerMismatch { + t.Fatalf("reason = %q, want %q", reason, ErrEip2612OwnerMismatch) + } +} + +func TestResolvePermit2DepositBranch_Eip2612SpenderMismatch(t *testing.T) { + info := goodEip2612Info() + info.Spender = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + _, reason, _ := resolvePermit2DepositBranch( + context.Background(), goodPermit2Auth(), extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + extensionsWithEip2612(info), + nil, "eip155:84532", + ) + if reason != ErrEip2612SpenderMismatch { + t.Fatalf("reason = %q, want %q", reason, ErrEip2612SpenderMismatch) + } +} + +func TestResolvePermit2DepositBranch_Eip2612DeadlineExpired(t *testing.T) { + info := goodEip2612Info() + info.Deadline = "1" // long expired + _, reason, _ := resolvePermit2DepositBranch( + context.Background(), goodPermit2Auth(), extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + extensionsWithEip2612(info), + nil, "eip155:84532", + ) + if reason != ErrEip2612DeadlineExpired { + t.Fatalf("reason = %q, want %q", reason, ErrEip2612DeadlineExpired) + } +} + +// TestResolvePermit2DepositBranch_Erc20ApprovalRequiresExtensionSigner ensures +// the ERC-20 approval branch refuses to proceed when the host facilitator has +// not registered an `Erc20ApprovalFacilitatorExtension`. Without an extension +// signer there's no way to broadcast the pre-signed approve() before deposit(). +func TestResolvePermit2DepositBranch_Erc20ApprovalRequiresExtensionSigner(t *testing.T) { + _, reason, err := resolvePermit2DepositBranch( + context.Background(), goodPermit2Auth(), extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + extensionsWithErc20Approval(goodErc20ApprovalInfo()), + nil, // no fctx + "eip155:84532", + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrErc20ApprovalUnavailable { + t.Fatalf("reason = %q, want %q", reason, ErrErc20ApprovalUnavailable) + } + + // Empty fctx (no registration) → same outcome. + emptyCtx := x402.NewFacilitatorContext(map[string]x402.FacilitatorExtension{}) + _, reason, _ = resolvePermit2DepositBranch( + context.Background(), goodPermit2Auth(), extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + extensionsWithErc20Approval(goodErc20ApprovalInfo()), + emptyCtx, "eip155:84532", + ) + if reason != ErrErc20ApprovalUnavailable { + t.Fatalf("empty fctx: reason = %q, want %q", reason, ErrErc20ApprovalUnavailable) + } +} + +// TestResolvePermit2DepositBranch_Erc20ApprovalHappyPath verifies the branch +// resolves with a registered extension, populates collectorData (without an +// EIP-2612 segment — that's an exclusive-OR with this branch), and surfaces +// the extension signer for SettleDeposit to use. +func TestResolvePermit2DepositBranch_Erc20ApprovalHappyPath(t *testing.T) { + standard, _, _ := resolvePermit2DepositBranch( + context.Background(), goodPermit2Auth(), extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + nil, nil, "eip155:84532", + ) + + stub := &stubExtensionSigner{fakeFacilitatorSigner: &fakeFacilitatorSigner{}} + ext := &erc20approvalgassponsor.Erc20ApprovalFacilitatorExtension{Signer: stub} + fctx := x402.NewFacilitatorContext(map[string]x402.FacilitatorExtension{ + erc20approvalgassponsor.ERC20ApprovalGasSponsoring.Key(): ext, + }) + + branch, reason, err := resolvePermit2DepositBranch( + context.Background(), goodPermit2Auth(), extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + extensionsWithErc20Approval(goodErc20ApprovalInfo()), + fctx, "eip155:84532", + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != "" { + t.Fatalf("reason = %q, want empty", reason) + } + if branch.kind != permit2BranchErc20Approval { + t.Fatalf("kind = %q, want %q", branch.kind, permit2BranchErc20Approval) + } + if branch.extensionSigner == nil { + t.Fatal("extensionSigner should be propagated for SettleDeposit") + } + if branch.erc20Info == nil { + t.Fatal("erc20Info should be propagated for SettleDeposit") + } + // ERC-20 approval branch reuses the standard collectorData encoding (no + // EIP-2612 segment). Lengths must match exactly. + if len(branch.collectorData) != len(standard.collectorData) { + t.Fatalf("erc20Approval collectorData length %d != standard %d", + len(branch.collectorData), len(standard.collectorData)) + } +} + +func TestResolvePermit2DepositBranch_Erc20ApprovalAssetMismatch(t *testing.T) { + info := goodErc20ApprovalInfo() + info.Asset = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + + stub := &stubExtensionSigner{fakeFacilitatorSigner: &fakeFacilitatorSigner{}} + ext := &erc20approvalgassponsor.Erc20ApprovalFacilitatorExtension{Signer: stub} + fctx := x402.NewFacilitatorContext(map[string]x402.FacilitatorExtension{ + erc20approvalgassponsor.ERC20ApprovalGasSponsoring.Key(): ext, + }) + + _, reason, err := resolvePermit2DepositBranch( + context.Background(), goodPermit2Auth(), extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + extensionsWithErc20Approval(info), + fctx, "eip155:84532", + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrErc20ApprovalAssetMismatch { + t.Fatalf("reason = %q, want %q", reason, ErrErc20ApprovalAssetMismatch) + } +} + +// TestResolvePermit2DepositBranch_Eip2612TakesPriorityOverErc20 ensures that +// when both extensions are advertised and populated by the client, EIP-2612 +// wins because it executes atomically in a single deposit() transaction. +func TestResolvePermit2DepositBranch_Eip2612TakesPriorityOverErc20(t *testing.T) { + stub := &stubExtensionSigner{fakeFacilitatorSigner: &fakeFacilitatorSigner{}} + ext := &erc20approvalgassponsor.Erc20ApprovalFacilitatorExtension{Signer: stub} + fctx := x402.NewFacilitatorContext(map[string]x402.FacilitatorExtension{ + erc20approvalgassponsor.ERC20ApprovalGasSponsoring.Key(): ext, + }) + + exts := map[string]interface{}{ + eip2612gassponsor.EIP2612GasSponsoring.Key(): map[string]interface{}{"info": goodEip2612Info()}, + erc20approvalgassponsor.ERC20ApprovalGasSponsoring.Key(): map[string]interface{}{"info": goodErc20ApprovalInfo()}, + } + + branch, reason, err := resolvePermit2DepositBranch( + context.Background(), goodPermit2Auth(), extAmount, + payerAssetView{Payer: extPayer, Token: extToken}, + exts, fctx, "eip155:84532", + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != "" { + t.Fatalf("reason = %q, want empty", reason) + } + if branch.kind != permit2BranchEip2612 { + t.Fatalf("priority broken: got %q, want %q", branch.kind, permit2BranchEip2612) + } +} + +// stubExtensionSigner is a minimal Erc20ApprovalGasSponsoringSigner used only +// to register an extension for branch-resolution tests. The resolver stores +// the signer reference but does NOT invoke any of its methods — only +// `SettleDeposit` calls into it, and that path is covered by the integration +// test harness. We embed `*fakeFacilitatorSigner` to inherit the no-op +// FacilitatorEvmSigner stubs and only add `SendTransactions`. +type stubExtensionSigner struct { + *fakeFacilitatorSigner +} + +func (s *stubExtensionSigner) SendTransactions(_ context.Context, _ []erc20approvalgassponsor.TransactionRequest) ([]string, error) { + return nil, nil +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/deposit_permit2_test.go b/go/mechanisms/evm/batch-settlement/facilitator/deposit_permit2_test.go new file mode 100644 index 0000000000..6e19db197f --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/deposit_permit2_test.go @@ -0,0 +1,159 @@ +package facilitator + +import ( + "context" + "math/big" + "strings" + "testing" + + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +const ( + testPermit2Payer = "0x1111111111111111111111111111111111111111" + testPermit2Token = "0x2222222222222222222222222222222222222222" + testPermit2ChannelId = "0x3333333333333333333333333333333333333333333333333333333333333333" +) + +func goodPermit2Auth() *batchsettlement.BatchSettlementPermit2Authorization { + return &batchsettlement.BatchSettlementPermit2Authorization{ + From: testPermit2Payer, + Permitted: batchsettlement.BatchSettlementPermit2TokenPermissions{ + Token: testPermit2Token, + Amount: "1000", + }, + Spender: batchsettlement.Permit2DepositCollectorAddress, + Nonce: "1", + Deadline: "9999999999", + Witness: batchsettlement.BatchSettlementPermit2Witness{ChannelId: testPermit2ChannelId}, + Signature: "0x" + strings.Repeat("11", 65), + } +} + +func goodPermit2Config() batchsettlement.ChannelConfig { + return batchsettlement.ChannelConfig{ + Payer: testPermit2Payer, + PayerAuthorizer: testPermit2Payer, + Receiver: "0xreceiver000000000000000000000000000000ab", + ReceiverAuthorizer: "0xreceiver000000000000000000000000000000ab", + Token: testPermit2Token, + WithdrawDelay: 900, + Salt: "0x0000000000000000000000000000000000000000000000000000000000000000", + } +} + +func TestVerifyPermit2_TokenMismatchReason(t *testing.T) { + auth := goodPermit2Auth() + auth.Permitted.Token = "0xdeadbeef00000000000000000000000000000000" + reason, err := verifyPermit2DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodPermit2Config(), testPermit2ChannelId, + big.NewInt(1000), auth, big.NewInt(8453), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrTokenMismatch { + t.Fatalf("reason = %q, want %q", reason, ErrTokenMismatch) + } +} + +func TestVerifyPermit2_ChannelIdMismatchReason(t *testing.T) { + auth := goodPermit2Auth() + auth.Witness.ChannelId = "0x" + strings.Repeat("ab", 32) + reason, err := verifyPermit2DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodPermit2Config(), testPermit2ChannelId, + big.NewInt(1000), auth, big.NewInt(8453), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrChannelIdMismatch { + t.Fatalf("reason = %q, want %q", reason, ErrChannelIdMismatch) + } +} + +func TestVerifyPermit2_SpenderMismatchReason(t *testing.T) { + auth := goodPermit2Auth() + auth.Spender = "0xdeadbeef00000000000000000000000000000000" + reason, err := verifyPermit2DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodPermit2Config(), testPermit2ChannelId, + big.NewInt(1000), auth, big.NewInt(8453), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrPermit2InvalidSpender { + t.Fatalf("reason = %q, want %q", reason, ErrPermit2InvalidSpender) + } +} + +func TestVerifyPermit2_AmountMismatchReason(t *testing.T) { + auth := goodPermit2Auth() + auth.Permitted.Amount = "999" // != deposit amount + reason, err := verifyPermit2DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodPermit2Config(), testPermit2ChannelId, + big.NewInt(1000), auth, big.NewInt(8453), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrPermit2AmountMismatch { + t.Fatalf("reason = %q, want %q", reason, ErrPermit2AmountMismatch) + } +} + +func TestVerifyPermit2_DeadlineExpiredReason(t *testing.T) { + auth := goodPermit2Auth() + auth.Deadline = "1" // far in the past + reason, err := verifyPermit2DepositAuthorization( + context.Background(), &fakeFacilitatorSigner{}, + goodPermit2Config(), testPermit2ChannelId, + big.NewInt(1000), auth, big.NewInt(8453), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrPermit2DeadlineExpired { + t.Fatalf("reason = %q, want %q", reason, ErrPermit2DeadlineExpired) + } +} + +func TestVerifyPermit2_InvalidSignatureReason(t *testing.T) { + signer := &fakeFacilitatorSigner{ + verifyTypedData: func(_ string) (bool, error) { return false, nil }, + } + auth := goodPermit2Auth() + reason, err := verifyPermit2DepositAuthorization( + context.Background(), signer, + goodPermit2Config(), testPermit2ChannelId, + big.NewInt(1000), auth, big.NewInt(8453), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != ErrPermit2InvalidSignature { + t.Fatalf("reason = %q, want %q", reason, ErrPermit2InvalidSignature) + } +} + +func TestVerifyPermit2_ValidAuthorizationReturnsEmpty(t *testing.T) { + signer := &fakeFacilitatorSigner{ + verifyTypedData: func(_ string) (bool, error) { return true, nil }, + } + auth := goodPermit2Auth() + reason, err := verifyPermit2DepositAuthorization( + context.Background(), signer, + goodPermit2Config(), testPermit2ChannelId, + big.NewInt(1000), auth, big.NewInt(8453), + ) + if err != nil { + t.Fatalf("err: %v", err) + } + if reason != "" { + t.Fatalf("reason = %q, want empty", reason) + } +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/errors.go b/go/mechanisms/evm/batch-settlement/facilitator/errors.go new file mode 100644 index 0000000000..3933ce3de6 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/errors.go @@ -0,0 +1,104 @@ +// Package facilitator emits canonical batch-settlement EVM rejection tokens. +// Every facilitator-emitted reason starts with `invalid_batch_settlement_evm_`, +// mirroring the `invalid_exact_evm_*` shape used by the exact EVM facilitator +// (see go/mechanisms/evm/exact/facilitator/errors.go). Exported symbols stay +// `Err…` (Go-idiomatic) — only the string values are part of the wire contract; +// the constants here describe mechanism-level failures only and intentionally +// carry no policy/business semantics. +package facilitator + +import batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + +const ( + // Payload parsing errors + ErrInvalidPayload = "invalid_batch_settlement_evm_payload_type" + ErrInvalidDepositPayload = "invalid_batch_settlement_evm_deposit_payload" + ErrInvalidVoucherPayload = "invalid_batch_settlement_evm_voucher_payload" + ErrInvalidClaimPayload = "invalid_batch_settlement_evm_claim_payload" + ErrInvalidSettlePayload = "invalid_batch_settlement_evm_settle_payload" + ErrInvalidRefundPayload = "invalid_batch_settlement_evm_refund_payload" + ErrInvalidScheme = "invalid_batch_settlement_evm_scheme" + ErrNetworkMismatch = "invalid_batch_settlement_evm_network_mismatch" + + // Channel config validation errors + ErrReceiverMismatch = "invalid_batch_settlement_evm_receiver_mismatch" + ErrReceiverAuthorizerMismatch = "invalid_batch_settlement_evm_receiver_authorizer_mismatch" + ErrTokenMismatch = "invalid_batch_settlement_evm_token_mismatch" + ErrWithdrawDelayOutOfRange = "invalid_batch_settlement_evm_withdraw_delay_out_of_range" + ErrWithdrawDelayMismatch = "invalid_batch_settlement_evm_withdraw_delay_mismatch" + ErrChannelIdMismatch = "invalid_batch_settlement_evm_channel_id_mismatch" + + // ERC-3009 authorization errors + ErrValidBeforeExpired = "invalid_batch_settlement_evm_payload_authorization_valid_before" + ErrValidAfterInFuture = "invalid_batch_settlement_evm_payload_authorization_valid_after" + ErrErc3009SignatureInvalid = "invalid_batch_settlement_evm_receive_authorization_signature" + ErrErc3009AuthorizationRequired = "invalid_batch_settlement_evm_erc3009_authorization_required" + + // ErrMissingEip712Domain signals that the resource server omitted the + // token's EIP-712 domain (`name` / `version`) from + // `paymentRequirements.extra`. The ERC-3009 deposit collector verifies the + // `ReceiveWithAuthorization` signature against the token's EIP-712 domain, + // so the facilitator cannot proceed without these fields. + ErrMissingEip712Domain = "invalid_batch_settlement_evm_missing_eip712_domain" + + // Voucher errors + ErrVoucherSignatureInvalid = "invalid_batch_settlement_evm_voucher_signature" + // ErrMaxClaimableTooLow is aliased from batchsettlement.ErrCumulativeBelowClaimed + // so the corrective-recovery client check (client/scheme.go) and the + // facilitator emitter share a single source of truth and can never drift. + ErrMaxClaimableTooLow = batchsettlement.ErrCumulativeBelowClaimed + ErrMaxClaimableExceedsBal = "invalid_batch_settlement_evm_cumulative_exceeds_balance" + ErrInsufficientBalance = "invalid_batch_settlement_evm_insufficient_balance" + + // Permit2 deposit authorization errors. + ErrPermit2AuthorizationRequired = "invalid_batch_settlement_evm_permit2_authorization_required" + ErrPermit2InvalidSpender = "invalid_batch_settlement_evm_permit2_invalid_spender" + ErrPermit2AmountMismatch = "invalid_batch_settlement_evm_permit2_amount_mismatch" + ErrPermit2DeadlineExpired = "invalid_batch_settlement_evm_permit2_deadline_expired" + ErrPermit2InvalidSignature = "invalid_batch_settlement_evm_permit2_invalid_signature" + ErrPermit2AllowanceRequired = "invalid_batch_settlement_evm_permit2_allowance_required" + + // EIP-2612 permit segment errors (gas-sponsored Permit2 branch). + ErrEip2612AmountMismatch = "invalid_batch_settlement_evm_eip2612_amount_mismatch" + ErrEip2612OwnerMismatch = "invalid_batch_settlement_evm_eip2612_owner_mismatch" + ErrEip2612AssetMismatch = "invalid_batch_settlement_evm_eip2612_asset_mismatch" + ErrEip2612SpenderMismatch = "invalid_batch_settlement_evm_eip2612_spender_mismatch" + ErrEip2612DeadlineExpired = "invalid_batch_settlement_evm_eip2612_deadline_expired" + ErrEip2612InvalidFormat = "invalid_batch_settlement_evm_eip2612_invalid_format" + ErrEip2612InvalidSignature = "invalid_batch_settlement_evm_eip2612_invalid_signature" + + // ERC-20 approval gas-sponsoring errors. The facilitator extension signer + // broadcasts a pre-signed `approve(Permit2, max)` then the deposit() tx; + // these errors surface format/payer/asset mismatches and missing signers. + ErrErc20ApprovalUnavailable = "invalid_batch_settlement_evm_erc20_approval_unavailable" + ErrErc20ApprovalInvalidFormat = "invalid_batch_settlement_evm_erc20_approval_invalid_format" + ErrErc20ApprovalFromMismatch = "invalid_batch_settlement_evm_erc20_approval_from_mismatch" + ErrErc20ApprovalAssetMismatch = "invalid_batch_settlement_evm_erc20_approval_asset_mismatch" + ErrErc20ApprovalWrongSpender = "invalid_batch_settlement_evm_erc20_approval_wrong_spender" + ErrErc20ApprovalBroadcastFailed = "invalid_batch_settlement_evm_erc20_approval_broadcast_failed" + + // Channel state errors + ErrChannelStateReadFailed = "invalid_batch_settlement_evm_channel_state_read_failed" + ErrChannelNotFound = "invalid_batch_settlement_evm_channel_not_found" + ErrRpcReadFailed = "invalid_batch_settlement_evm_rpc_read_failed" + + // Transaction errors + ErrDepositTransactionFailed = "invalid_batch_settlement_evm_deposit_transaction_failed" + ErrClaimTransactionFailed = "invalid_batch_settlement_evm_claim_transaction_failed" + ErrSettleTransactionFailed = "invalid_batch_settlement_evm_settle_transaction_failed" + ErrRefundTransactionFailed = "invalid_batch_settlement_evm_refund_transaction_failed" + ErrTransactionReverted = "invalid_batch_settlement_evm_transaction_reverted" + ErrWaitForReceipt = "invalid_batch_settlement_evm_wait_for_receipt_failed" + + // Simulation errors + ErrDepositSimulationFailed = "invalid_batch_settlement_evm_deposit_simulation_failed" + ErrClaimSimulationFailed = "invalid_batch_settlement_evm_claim_simulation_failed" + ErrSettleSimulationFailed = "invalid_batch_settlement_evm_settle_simulation_failed" + ErrRefundSimulationFailed = "invalid_batch_settlement_evm_refund_simulation_failed" + + // Authorizer errors + ErrAuthorizerAddressMismatch = "invalid_batch_settlement_evm_authorizer_address_mismatch" + + // Settle action errors + ErrUnknownSettleAction = "invalid_batch_settlement_evm_unknown_settle_action" +) diff --git a/go/mechanisms/evm/batch-settlement/facilitator/errors_test.go b/go/mechanisms/evm/batch-settlement/facilitator/errors_test.go new file mode 100644 index 0000000000..c11011bef3 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/errors_test.go @@ -0,0 +1,250 @@ +package facilitator + +import ( + "strings" + "testing" +) + +// TestExportedErrorReasonsAreStable pins the wire format and naming +// invariants for the exported error-reason constants in errors.go. +// +// These tokens are consumed by downstream classifiers (notably +// cdp-facilitator) that map facilitator output 1:1 into the +// `x402VerifyInvalidReason` / `x402SettleErrorReason` CDP Accounts API enums +// (`invalid_batch_settlement_evm_*`). Renaming or silently dropping any +// token breaks the mapping at the wire level, so this test asserts: +// +// 1. every constant is non-empty +// 2. every constant carries the canonical `invalid_batch_settlement_evm_` +// prefix — mirroring the `invalid_exact_evm_*` discipline already in +// `go/mechanisms/evm/exact/facilitator/errors.go` +// 3. no two constants share the same string value (uniqueness, since the +// downstream classifier's identity passthrough would otherwise silently +// collapse two distinct failure causes into one CDP enum) +// +// Add new constants to `errors.go` and also append them here so future +// renames trip this test instead of leaking through to wire consumers. +func TestExportedErrorReasonsAreStable(t *testing.T) { + const wirePrefix = "invalid_batch_settlement_evm_" + + // Inventory of every exported error-reason constant in this package. + // Keep alphabetical-ish order grouped by section to ease review. + cases := map[string]string{ + // Payload parsing errors + "ErrInvalidPayload": ErrInvalidPayload, + "ErrInvalidDepositPayload": ErrInvalidDepositPayload, + "ErrInvalidVoucherPayload": ErrInvalidVoucherPayload, + "ErrInvalidClaimPayload": ErrInvalidClaimPayload, + "ErrInvalidSettlePayload": ErrInvalidSettlePayload, + "ErrInvalidRefundPayload": ErrInvalidRefundPayload, + "ErrInvalidScheme": ErrInvalidScheme, + "ErrNetworkMismatch": ErrNetworkMismatch, + + // Channel config validation errors + "ErrReceiverMismatch": ErrReceiverMismatch, + "ErrReceiverAuthorizerMismatch": ErrReceiverAuthorizerMismatch, + "ErrTokenMismatch": ErrTokenMismatch, + "ErrWithdrawDelayOutOfRange": ErrWithdrawDelayOutOfRange, + "ErrWithdrawDelayMismatch": ErrWithdrawDelayMismatch, + "ErrChannelIdMismatch": ErrChannelIdMismatch, + + // ERC-3009 authorization errors + "ErrValidBeforeExpired": ErrValidBeforeExpired, + "ErrValidAfterInFuture": ErrValidAfterInFuture, + "ErrErc3009SignatureInvalid": ErrErc3009SignatureInvalid, + "ErrErc3009AuthorizationRequired": ErrErc3009AuthorizationRequired, + "ErrMissingEip712Domain": ErrMissingEip712Domain, + + // Voucher errors + "ErrVoucherSignatureInvalid": ErrVoucherSignatureInvalid, + "ErrMaxClaimableTooLow": ErrMaxClaimableTooLow, + "ErrMaxClaimableExceedsBal": ErrMaxClaimableExceedsBal, + "ErrInsufficientBalance": ErrInsufficientBalance, + + // Channel state errors + "ErrChannelStateReadFailed": ErrChannelStateReadFailed, + "ErrChannelNotFound": ErrChannelNotFound, + "ErrRpcReadFailed": ErrRpcReadFailed, + + // Transaction errors + "ErrDepositTransactionFailed": ErrDepositTransactionFailed, + "ErrClaimTransactionFailed": ErrClaimTransactionFailed, + "ErrSettleTransactionFailed": ErrSettleTransactionFailed, + "ErrRefundTransactionFailed": ErrRefundTransactionFailed, + "ErrTransactionReverted": ErrTransactionReverted, + "ErrWaitForReceipt": ErrWaitForReceipt, + + // Simulation errors + "ErrDepositSimulationFailed": ErrDepositSimulationFailed, + "ErrClaimSimulationFailed": ErrClaimSimulationFailed, + "ErrSettleSimulationFailed": ErrSettleSimulationFailed, + "ErrRefundSimulationFailed": ErrRefundSimulationFailed, + + // Authorizer / settle-action errors + "ErrAuthorizerAddressMismatch": ErrAuthorizerAddressMismatch, + "ErrUnknownSettleAction": ErrUnknownSettleAction, + + // Permit2 deposit authorization errors + "ErrPermit2AuthorizationRequired": ErrPermit2AuthorizationRequired, + "ErrPermit2InvalidSpender": ErrPermit2InvalidSpender, + "ErrPermit2AmountMismatch": ErrPermit2AmountMismatch, + "ErrPermit2DeadlineExpired": ErrPermit2DeadlineExpired, + "ErrPermit2InvalidSignature": ErrPermit2InvalidSignature, + "ErrPermit2AllowanceRequired": ErrPermit2AllowanceRequired, + + // EIP-2612 permit segment errors + "ErrEip2612AmountMismatch": ErrEip2612AmountMismatch, + "ErrEip2612OwnerMismatch": ErrEip2612OwnerMismatch, + "ErrEip2612AssetMismatch": ErrEip2612AssetMismatch, + "ErrEip2612SpenderMismatch": ErrEip2612SpenderMismatch, + "ErrEip2612DeadlineExpired": ErrEip2612DeadlineExpired, + "ErrEip2612InvalidFormat": ErrEip2612InvalidFormat, + "ErrEip2612InvalidSignature": ErrEip2612InvalidSignature, + + // ERC-20 approval gas-sponsoring errors + "ErrErc20ApprovalUnavailable": ErrErc20ApprovalUnavailable, + "ErrErc20ApprovalInvalidFormat": ErrErc20ApprovalInvalidFormat, + "ErrErc20ApprovalFromMismatch": ErrErc20ApprovalFromMismatch, + "ErrErc20ApprovalAssetMismatch": ErrErc20ApprovalAssetMismatch, + "ErrErc20ApprovalWrongSpender": ErrErc20ApprovalWrongSpender, + "ErrErc20ApprovalBroadcastFailed": ErrErc20ApprovalBroadcastFailed, + } + + // 1. Non-empty + 2. Prefix + for name, value := range cases { + if value == "" { + t.Errorf("%s is empty", name) + continue + } + if !strings.HasPrefix(value, wirePrefix) { + t.Errorf("%s = %q does not start with wire prefix %q", name, value, wirePrefix) + } + } + + // 3. Uniqueness — surface the duplicate names so the failure points at + // the rename / typo, not just "two constants collided". + bySymbol := make(map[string][]string, len(cases)) + for name, value := range cases { + bySymbol[value] = append(bySymbol[value], name) + } + for value, names := range bySymbol { + if len(names) > 1 { + t.Errorf("duplicate value %q shared by %v — downstream classifiers (cdp-facilitator) match by string contains and would silently collapse these", value, names) + } + } +} + +// TestRequiredCdpFacilitatorContract pins the exact wire values the CDP +// Accounts API enums (`x402VerifyInvalidReason` / `x402SettleErrorReason`) +// expect for the Permit2 / EIP-2612 / ERC-20 approval families. cdp-facilitator +// after this revision does identity passthrough on these tokens, so any drift +// here surfaces as an undefined-enum error at the API boundary. +// +// `_invalid_*` suffixes are preserved verbatim (the leading `invalid_` envelope +// replaces the old `batch_settlement_evm_*` prefix and does NOT swallow inner +// `_invalid_*` segments). Earlier revisions collapsed these and produced +// abbreviated wire strings (e.g. `...permit2_spender`) that CDP had to +// denormalize, so we restored the full +// form here so the SDK can identity-map onto CDP's OpenAPI enum names. +func TestRequiredCdpFacilitatorContract(t *testing.T) { + required := map[string]string{ + // Permit2 + "ErrPermit2AuthorizationRequired": "invalid_batch_settlement_evm_permit2_authorization_required", + "ErrPermit2InvalidSpender": "invalid_batch_settlement_evm_permit2_invalid_spender", + "ErrPermit2AmountMismatch": "invalid_batch_settlement_evm_permit2_amount_mismatch", + "ErrPermit2DeadlineExpired": "invalid_batch_settlement_evm_permit2_deadline_expired", + "ErrPermit2InvalidSignature": "invalid_batch_settlement_evm_permit2_invalid_signature", + "ErrPermit2AllowanceRequired": "invalid_batch_settlement_evm_permit2_allowance_required", + // EIP-2612 + "ErrEip2612AmountMismatch": "invalid_batch_settlement_evm_eip2612_amount_mismatch", + "ErrEip2612OwnerMismatch": "invalid_batch_settlement_evm_eip2612_owner_mismatch", + "ErrEip2612AssetMismatch": "invalid_batch_settlement_evm_eip2612_asset_mismatch", + "ErrEip2612SpenderMismatch": "invalid_batch_settlement_evm_eip2612_spender_mismatch", + "ErrEip2612DeadlineExpired": "invalid_batch_settlement_evm_eip2612_deadline_expired", + "ErrEip2612InvalidFormat": "invalid_batch_settlement_evm_eip2612_invalid_format", + "ErrEip2612InvalidSignature": "invalid_batch_settlement_evm_eip2612_invalid_signature", + // ERC-20 approval (gas-sponsored) + "ErrErc20ApprovalUnavailable": "invalid_batch_settlement_evm_erc20_approval_unavailable", + "ErrErc20ApprovalInvalidFormat": "invalid_batch_settlement_evm_erc20_approval_invalid_format", + "ErrErc20ApprovalFromMismatch": "invalid_batch_settlement_evm_erc20_approval_from_mismatch", + "ErrErc20ApprovalAssetMismatch": "invalid_batch_settlement_evm_erc20_approval_asset_mismatch", + "ErrErc20ApprovalWrongSpender": "invalid_batch_settlement_evm_erc20_approval_wrong_spender", + "ErrErc20ApprovalBroadcastFailed": "invalid_batch_settlement_evm_erc20_approval_broadcast_failed", + } + + // Map each symbol to its actual current value via a sibling table so the + // test fails compilation if a constant is ever deleted. + actual := map[string]string{ + "ErrPermit2AuthorizationRequired": ErrPermit2AuthorizationRequired, + "ErrPermit2InvalidSpender": ErrPermit2InvalidSpender, + "ErrPermit2AmountMismatch": ErrPermit2AmountMismatch, + "ErrPermit2DeadlineExpired": ErrPermit2DeadlineExpired, + "ErrPermit2InvalidSignature": ErrPermit2InvalidSignature, + "ErrPermit2AllowanceRequired": ErrPermit2AllowanceRequired, + "ErrEip2612AmountMismatch": ErrEip2612AmountMismatch, + "ErrEip2612OwnerMismatch": ErrEip2612OwnerMismatch, + "ErrEip2612AssetMismatch": ErrEip2612AssetMismatch, + "ErrEip2612SpenderMismatch": ErrEip2612SpenderMismatch, + "ErrEip2612DeadlineExpired": ErrEip2612DeadlineExpired, + "ErrEip2612InvalidFormat": ErrEip2612InvalidFormat, + "ErrEip2612InvalidSignature": ErrEip2612InvalidSignature, + "ErrErc20ApprovalUnavailable": ErrErc20ApprovalUnavailable, + "ErrErc20ApprovalInvalidFormat": ErrErc20ApprovalInvalidFormat, + "ErrErc20ApprovalFromMismatch": ErrErc20ApprovalFromMismatch, + "ErrErc20ApprovalAssetMismatch": ErrErc20ApprovalAssetMismatch, + "ErrErc20ApprovalWrongSpender": ErrErc20ApprovalWrongSpender, + "ErrErc20ApprovalBroadcastFailed": ErrErc20ApprovalBroadcastFailed, + } + + for name, want := range required { + got, ok := actual[name] + if !ok { + t.Errorf("%s: missing from inventory", name) + continue + } + if got != want { + t.Errorf("%s = %q, want %q (cdp-facilitator wire contract)", name, got, want) + } + } +} + +// TestNoLegacyBatchSettlementEvmPrefix guards against accidental reintroduction +// of the legacy `batch_settlement_evm_*` prefix on any facilitator constant. +// The new canonical form is `invalid_batch_settlement_evm_*`; legacy values +// would be silently translated by cdp-facilitator's deprecation shim during +// the migration window, masking real wire breaks. After the shim is removed +// from cdp-facilitator, any leak would surface as a 500 there. +func TestNoLegacyBatchSettlementEvmPrefix(t *testing.T) { + all := []string{ + ErrInvalidPayload, ErrInvalidDepositPayload, ErrInvalidVoucherPayload, + ErrInvalidClaimPayload, ErrInvalidSettlePayload, ErrInvalidRefundPayload, + ErrInvalidScheme, ErrNetworkMismatch, + ErrReceiverMismatch, ErrReceiverAuthorizerMismatch, ErrTokenMismatch, + ErrWithdrawDelayOutOfRange, ErrWithdrawDelayMismatch, ErrChannelIdMismatch, + ErrValidBeforeExpired, ErrValidAfterInFuture, ErrErc3009SignatureInvalid, + ErrErc3009AuthorizationRequired, ErrMissingEip712Domain, + ErrVoucherSignatureInvalid, ErrMaxClaimableTooLow, ErrMaxClaimableExceedsBal, + ErrInsufficientBalance, + ErrChannelStateReadFailed, ErrChannelNotFound, ErrRpcReadFailed, + ErrDepositTransactionFailed, ErrClaimTransactionFailed, + ErrSettleTransactionFailed, ErrRefundTransactionFailed, + ErrTransactionReverted, ErrWaitForReceipt, + ErrDepositSimulationFailed, ErrClaimSimulationFailed, + ErrSettleSimulationFailed, ErrRefundSimulationFailed, + ErrAuthorizerAddressMismatch, ErrUnknownSettleAction, + ErrPermit2AuthorizationRequired, ErrPermit2InvalidSpender, + ErrPermit2AmountMismatch, ErrPermit2DeadlineExpired, + ErrPermit2InvalidSignature, ErrPermit2AllowanceRequired, + ErrEip2612AmountMismatch, ErrEip2612OwnerMismatch, ErrEip2612AssetMismatch, + ErrEip2612SpenderMismatch, ErrEip2612DeadlineExpired, + ErrEip2612InvalidFormat, ErrEip2612InvalidSignature, + ErrErc20ApprovalUnavailable, ErrErc20ApprovalInvalidFormat, + ErrErc20ApprovalFromMismatch, ErrErc20ApprovalAssetMismatch, + ErrErc20ApprovalWrongSpender, ErrErc20ApprovalBroadcastFailed, + } + for _, v := range all { + if strings.HasPrefix(v, "batch_settlement_evm_") { + t.Errorf("legacy prefix detected: %q — must use `invalid_batch_settlement_evm_*`", v) + } + } +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/exec_test.go b/go/mechanisms/evm/batch-settlement/facilitator/exec_test.go new file mode 100644 index 0000000000..c4de956af2 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/exec_test.go @@ -0,0 +1,618 @@ +package facilitator + +import ( + "context" + "errors" + "math/big" + "testing" + + x402 "github.com/x402-foundation/x402/go" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +const testNetwork = "eip155:8453" + +func reqsFor(network string) types.PaymentRequirements { + return types.PaymentRequirements{ + Scheme: batchsettlement.SchemeBatched, + Network: network, + PayTo: "0x3333333333333333333333333333333333333333", + Asset: "0x5555555555555555555555555555555555555555", + Amount: "100", + Extra: map[string]interface{}{ + "receiverAuthorizer": "0x4444444444444444444444444444444444444444", + }, + } +} + +// ----- ExecuteClaimWithSignature ----- + +func TestExecuteClaimWithSignature_NoClaims(t *testing.T) { + scheme := newScheme() + resp, err := ExecuteClaimWithSignature( + context.Background(), + scheme.signer, + &batchsettlement.BatchSettlementClaimPayload{Claims: nil}, + reqsFor(testNetwork), + scheme.authorizerSigner, + ) + if resp != nil { + t.Fatalf("expected nil resp, got %+v", resp) + } + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrInvalidClaimPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestExecuteClaimWithSignature_BadProvidedSignature(t *testing.T) { + scheme := newScheme() + payload := &batchsettlement.BatchSettlementClaimPayload{ + Claims: []batchsettlement.BatchSettlementVoucherClaim{sampleClaim()}, + ClaimAuthorizerSignature: "not-hex", + } + _, err := ExecuteClaimWithSignature(context.Background(), scheme.signer, payload, reqsFor(testNetwork), scheme.authorizerSigner) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrInvalidClaimPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestExecuteClaimWithSignature_AuthorizerAddressMismatch(t *testing.T) { + scheme := newScheme() + claim := sampleClaim() + claim.Voucher.Channel.ReceiverAuthorizer = "0xfeedfeedfeedfeedfeedfeedfeedfeedfeedfeed" + payload := &batchsettlement.BatchSettlementClaimPayload{Claims: []batchsettlement.BatchSettlementVoucherClaim{claim}} + _, err := ExecuteClaimWithSignature(context.Background(), scheme.signer, payload, reqsFor(testNetwork), scheme.authorizerSigner) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrAuthorizerAddressMismatch { + t.Fatalf("got err = %v", err) + } +} + +func TestExecuteClaimWithSignature_SimulationFailed(t *testing.T) { + scheme := newScheme() + claim := sampleClaim() + claim.Voucher.Channel.ReceiverAuthorizer = "0xauthorizer" + payload := &batchsettlement.BatchSettlementClaimPayload{Claims: []batchsettlement.BatchSettlementVoucherClaim{claim}} + resp, err := ExecuteClaimWithSignature(context.Background(), scheme.signer, payload, reqsFor(testNetwork), scheme.authorizerSigner) + if err != nil { + t.Fatalf("err: %v", err) + } + if resp.Success || resp.ErrorReason != ErrClaimSimulationFailed { + t.Fatalf("got %+v", resp) + } +} + +// ----- ExecuteRefundWithSignature ----- + +func TestExecuteRefundWithSignature_BadAmount(t *testing.T) { + scheme := newScheme() + payload := &batchsettlement.BatchSettlementEnrichedRefundPayload{ + Type: "refund", + ChannelConfig: validConfig(), + Amount: "not-a-number", + RefundNonce: "1", + } + _, err := ExecuteRefundWithSignature(context.Background(), scheme.signer, payload, reqsFor(testNetwork), scheme.authorizerSigner) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrInvalidRefundPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestExecuteRefundWithSignature_BadNonce(t *testing.T) { + scheme := newScheme() + payload := &batchsettlement.BatchSettlementEnrichedRefundPayload{ + Type: "refund", + ChannelConfig: validConfig(), + Amount: "100", + RefundNonce: "not-a-number", + } + _, err := ExecuteRefundWithSignature(context.Background(), scheme.signer, payload, reqsFor(testNetwork), scheme.authorizerSigner) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrInvalidRefundPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestExecuteRefundWithSignature_BadProvidedRefundSig(t *testing.T) { + scheme := newScheme() + payload := &batchsettlement.BatchSettlementEnrichedRefundPayload{ + Type: "refund", + ChannelConfig: validConfig(), + Amount: "100", + RefundNonce: "1", + RefundAuthorizerSignature: "not-hex", + } + _, err := ExecuteRefundWithSignature(context.Background(), scheme.signer, payload, reqsFor(testNetwork), scheme.authorizerSigner) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrInvalidRefundPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestExecuteRefundWithSignature_AuthorizerAddressMismatch(t *testing.T) { + scheme := newScheme() + cfg := validConfig() + cfg.ReceiverAuthorizer = "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + payload := &batchsettlement.BatchSettlementEnrichedRefundPayload{ + Type: "refund", + ChannelConfig: cfg, + Amount: "100", + RefundNonce: "1", + } + _, err := ExecuteRefundWithSignature(context.Background(), scheme.signer, payload, reqsFor(testNetwork), scheme.authorizerSigner) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrAuthorizerAddressMismatch { + t.Fatalf("got err = %v", err) + } +} + +func TestExecuteRefundWithSignature_SimulationFailed_DirectPath(t *testing.T) { + scheme := newScheme() + cfg := validConfig() + cfg.ReceiverAuthorizer = "0xauthorizer" + payload := &batchsettlement.BatchSettlementEnrichedRefundPayload{ + Type: "refund", + ChannelConfig: cfg, + Amount: "100", + RefundNonce: "1", + } + resp, err := ExecuteRefundWithSignature(context.Background(), scheme.signer, payload, reqsFor(testNetwork), scheme.authorizerSigner) + if err != nil { + t.Fatalf("err: %v", err) + } + if resp.Success || resp.ErrorReason != ErrRefundSimulationFailed { + t.Fatalf("got %+v", resp) + } +} + +func TestExecuteRefundWithSignature_BadProvidedClaimSig(t *testing.T) { + scheme := newScheme() + cfg := validConfig() + cfg.ReceiverAuthorizer = "0xauthorizer" + payload := &batchsettlement.BatchSettlementEnrichedRefundPayload{ + Type: "refund", + ChannelConfig: cfg, + Amount: "100", + RefundNonce: "1", + Claims: []batchsettlement.BatchSettlementVoucherClaim{sampleClaim()}, + ClaimAuthorizerSignature: "not-hex", + RefundAuthorizerSignature: "0xdead", + } + _, err := ExecuteRefundWithSignature(context.Background(), scheme.signer, payload, reqsFor(testNetwork), scheme.authorizerSigner) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrInvalidRefundPayload { + t.Fatalf("got err = %v", err) + } +} + +// ----- ExecuteSettle ----- + +func TestExecuteSettle_SimulationFailed(t *testing.T) { + scheme := newScheme() + payload := &batchsettlement.BatchSettlementSettlePayload{ + Type: "settle", + Receiver: "0x3333333333333333333333333333333333333333", + Token: "0x5555555555555555555555555555555555555555", + } + resp, err := ExecuteSettle(context.Background(), scheme.signer, payload, reqsFor(testNetwork)) + if err != nil { + t.Fatalf("err: %v", err) + } + if resp.Success || resp.ErrorReason != ErrSettleSimulationFailed { + t.Fatalf("got %+v", resp) + } +} + +// ----- SettleDeposit ----- + +func TestSettleDeposit_BadAmount(t *testing.T) { + scheme := newScheme() + payload := &batchsettlement.BatchSettlementDepositPayload{ + Type: "deposit", + ChannelConfig: validConfig(), + Deposit: batchsettlement.BatchSettlementDepositData{ + Amount: "not-a-number", + }, + } + _, err := SettleDeposit(context.Background(), scheme.signer, payload, reqsFor(testNetwork), nil, nil) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrInvalidDepositPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestSettleDeposit_MissingAuthorization(t *testing.T) { + // buildERC3009CollectorData returns an error when no auth is present, so + // SettleDeposit short-circuits with ErrInvalidDepositPayload before any RPC. + scheme := newScheme() + payload := &batchsettlement.BatchSettlementDepositPayload{ + Type: "deposit", + ChannelConfig: validConfig(), + Deposit: batchsettlement.BatchSettlementDepositData{ + Amount: "100", + }, + } + _, err := SettleDeposit(context.Background(), scheme.signer, payload, reqsFor(testNetwork), nil, nil) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrInvalidDepositPayload { + t.Fatalf("got err = %v", err) + } +} + +// ----- VerifyDeposit pre-RPC paths ----- + +func TestVerifyDeposit_BadAmount(t *testing.T) { + scheme := newScheme() + cfg := validConfig() + id, _ := batchsettlement.ComputeChannelId(cfg, testNetwork) + payload := &batchsettlement.BatchSettlementDepositPayload{ + Type: "deposit", + ChannelConfig: cfg, + Deposit: batchsettlement.BatchSettlementDepositData{ + Amount: "0", + }, + Voucher: batchsettlement.BatchSettlementVoucherFields{ + ChannelId: id, + MaxClaimableAmount: "100", + Signature: "0xsig", + }, + } + _, err := VerifyDeposit(context.Background(), scheme.signer, payload, reqsFor(testNetwork), nil, nil) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrInvalidDepositPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestVerifyDeposit_BadValidAfter(t *testing.T) { + scheme := newScheme() + cfg := validConfig() + id, _ := batchsettlement.ComputeChannelId(cfg, testNetwork) + payload := &batchsettlement.BatchSettlementDepositPayload{ + Type: "deposit", + ChannelConfig: cfg, + Deposit: batchsettlement.BatchSettlementDepositData{ + Amount: "100", + Authorization: batchsettlement.BatchSettlementDepositAuthorization{ + Erc3009Authorization: &batchsettlement.BatchSettlementErc3009Authorization{ + ValidAfter: "not-a-number", + ValidBefore: "9999999999", + Salt: "0x" + zeros(64), + Signature: "0xdeadbeef", + }, + }, + }, + Voucher: batchsettlement.BatchSettlementVoucherFields{ + ChannelId: id, + MaxClaimableAmount: "100", + Signature: "0xsig", + }, + } + _, err := VerifyDeposit(context.Background(), scheme.signer, payload, reqsFor(testNetwork), nil, nil) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrInvalidDepositPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestVerifyDeposit_BadValidBefore(t *testing.T) { + scheme := newScheme() + cfg := validConfig() + id, _ := batchsettlement.ComputeChannelId(cfg, testNetwork) + payload := &batchsettlement.BatchSettlementDepositPayload{ + Type: "deposit", + ChannelConfig: cfg, + Deposit: batchsettlement.BatchSettlementDepositData{ + Amount: "100", + Authorization: batchsettlement.BatchSettlementDepositAuthorization{ + Erc3009Authorization: &batchsettlement.BatchSettlementErc3009Authorization{ + ValidAfter: "0", + ValidBefore: "not-a-number", + Salt: "0x" + zeros(64), + Signature: "0xdeadbeef", + }, + }, + }, + Voucher: batchsettlement.BatchSettlementVoucherFields{ + ChannelId: id, + MaxClaimableAmount: "100", + Signature: "0xsig", + }, + } + _, err := VerifyDeposit(context.Background(), scheme.signer, payload, reqsFor(testNetwork), nil, nil) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrInvalidDepositPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestVerifyDeposit_ExpiredAuthorization(t *testing.T) { + scheme := newScheme() + cfg := validConfig() + id, _ := batchsettlement.ComputeChannelId(cfg, testNetwork) + payload := &batchsettlement.BatchSettlementDepositPayload{ + Type: "deposit", + ChannelConfig: cfg, + Deposit: batchsettlement.BatchSettlementDepositData{ + Amount: "100", + Authorization: batchsettlement.BatchSettlementDepositAuthorization{ + Erc3009Authorization: &batchsettlement.BatchSettlementErc3009Authorization{ + ValidAfter: "0", + ValidBefore: "1", + Salt: "0x" + zeros(64), + Signature: "0xdeadbeef", + }, + }, + }, + Voucher: batchsettlement.BatchSettlementVoucherFields{ + ChannelId: id, + MaxClaimableAmount: "100", + Signature: "0xsig", + }, + } + _, err := VerifyDeposit(context.Background(), scheme.signer, payload, reqsFor(testNetwork), nil, nil) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrValidBeforeExpired { + t.Fatalf("got err = %v", err) + } +} + +func TestVerifyDeposit_ChannelConfigInvalid(t *testing.T) { + // channelId mismatch fires before any RPC. + scheme := newScheme() + cfg := validConfig() + payload := &batchsettlement.BatchSettlementDepositPayload{ + Type: "deposit", + ChannelConfig: cfg, + Deposit: batchsettlement.BatchSettlementDepositData{ + Amount: "100", + }, + Voucher: batchsettlement.BatchSettlementVoucherFields{ + ChannelId: "0x" + zeros(64), + MaxClaimableAmount: "100", + Signature: "0xsig", + }, + } + _, err := VerifyDeposit(context.Background(), scheme.signer, payload, reqsFor(testNetwork), nil, nil) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrChannelIdMismatch { + t.Fatalf("got err = %v", err) + } +} + +// ----- VerifyVoucher pre-RPC paths ----- + +func TestVerifyVoucher_ChannelConfigInvalid(t *testing.T) { + scheme := newScheme() + cfg := validConfig() + payload := &batchsettlement.BatchSettlementVoucherPayload{ + Type: "voucher", + ChannelConfig: cfg, + Voucher: batchsettlement.BatchSettlementVoucherFields{ + ChannelId: "0x" + zeros(64), + MaxClaimableAmount: "100", + Signature: "0xsig", + }, + } + _, err := VerifyVoucher(context.Background(), scheme.signer, payload, reqsFor(testNetwork), cfg) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrChannelIdMismatch { + t.Fatalf("got err = %v", err) + } +} + +// TestVerifyRefundVoucher_ChannelConfigInvalid ensures VerifyRefundVoucher +// shares the same channel-id validation surface as VerifyVoucher. The refund +// path is otherwise identical aside from the cumulative comparison. +func TestVerifyRefundVoucher_ChannelConfigInvalid(t *testing.T) { + scheme := newScheme() + cfg := validConfig() + payload := &batchsettlement.BatchSettlementRefundPayload{ + Type: "refund", + ChannelConfig: cfg, + Voucher: batchsettlement.BatchSettlementVoucherFields{ + ChannelId: "0x" + zeros(64), + MaxClaimableAmount: "0", + Signature: "0xsig", + }, + } + _, err := VerifyRefundVoucher(context.Background(), scheme.signer, payload, reqsFor(testNetwork), cfg) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrChannelIdMismatch { + t.Fatalf("got err = %v", err) + } +} + +// ----- helpers ----- + +func sampleClaim() batchsettlement.BatchSettlementVoucherClaim { + c := batchsettlement.BatchSettlementVoucherClaim{ + Signature: "0xdeadbeef", + TotalClaimed: "0", + } + c.Voucher.Channel = validConfig() + c.Voucher.MaxClaimableAmount = "100" + return c +} + +func zeros(n int) string { + out := make([]byte, n) + for i := range out { + out[i] = '0' + } + return string(out) +} + +// ----- buildRefundResponse ----- + +// TestBuildRefundResponse pins the refund response shape: +// - top-level: success, tx, network, payer, amount +// - extra.channelState: channelId, balance, totalClaimed, withdrawRequestedAt, refundNonce +// - NO `refund: true` flag at any level; resource hooks use the payload type +// and channelState fields instead +// - NO `chargedCumulativeAmount` (the resource server's +// enrichSettlementResponse hook adds it via additive merge) +func TestBuildRefundResponse(t *testing.T) { + details := refundSettlementDetails{ + amount: "2000", + channelState: batchsettlement.BatchSettlementChannelStateExtra{ + ChannelId: "0xchan", + Balance: "3000", + TotalClaimed: "3000", + WithdrawRequestedAt: 0, + RefundNonce: "1", + }, + } + resp := buildRefundResponse("0xtx", x402.Network(testNetwork), "0xpayer", details) + if !resp.Success || resp.Transaction != "0xtx" || resp.Network != x402.Network(testNetwork) { + t.Fatalf("envelope: %+v", resp) + } + if resp.Payer != "0xpayer" { + t.Fatalf("payer = %q, want 0xpayer", resp.Payer) + } + if resp.Amount != "2000" { + t.Fatalf("amount = %q, want 2000", resp.Amount) + } + if _, hasLegacy := resp.Extra["refund"]; hasLegacy { + t.Fatalf("extra.refund must NOT be emitted; got %+v", resp.Extra) + } + cs, ok := resp.Extra["channelState"].(map[string]interface{}) + if !ok { + t.Fatalf("extra.channelState missing or wrong shape: %+v", resp.Extra) + } + if cs["channelId"] != "0xchan" { + t.Fatalf("channelId = %v", cs["channelId"]) + } + if cs["balance"] != "3000" { + t.Fatalf("balance = %v", cs["balance"]) + } + if cs["totalClaimed"] != "3000" { + t.Fatalf("totalClaimed = %v", cs["totalClaimed"]) + } + if cs["refundNonce"] != "1" { + t.Fatalf("refundNonce = %v", cs["refundNonce"]) + } + if _, hasCharged := cs["chargedCumulativeAmount"]; hasCharged { + t.Fatalf("chargedCumulativeAmount must NOT be emitted by facilitator (server enrichSettlementResponse adds it): %+v", cs) + } +} + +// TestComputeRefundSettlementDetails_AnalyticPathNoClaims covers the common +// case: no pending withdrawal, no claims accompanying the refund. The +// snapshot is computed from preState + payload alone, without a post-state poll. +func TestComputeRefundSettlementDetails_AnalyticPathNoClaims(t *testing.T) { + preState := &batchsettlement.ChannelState{ + Balance: big.NewInt(5000), + TotalClaimed: big.NewInt(0), + WithdrawRequestedAt: 0, + RefundNonce: big.NewInt(0), + } + payload := &batchsettlement.BatchSettlementEnrichedRefundPayload{ + Type: "refund", + Amount: "2000", + RefundNonce: "0", + } + details := computeRefundSettlementDetails( + context.Background(), nil /*signer not consulted*/, payload, "0xchan", preState, big.NewInt(2000), + ) + if details.amount != "2000" { + t.Fatalf("amount = %q, want 2000 (no available cap)", details.amount) + } + if details.channelState.Balance != "3000" { + t.Fatalf("balance = %q, want 3000 (5000 - 2000)", details.channelState.Balance) + } + if details.channelState.TotalClaimed != "0" { + t.Fatalf("totalClaimed = %q, want 0 (no claims)", details.channelState.TotalClaimed) + } + if details.channelState.RefundNonce != "1" { + t.Fatalf("refundNonce = %q, want 1 (preNonce + 1)", details.channelState.RefundNonce) + } + if details.channelState.WithdrawRequestedAt != 0 { + t.Fatalf("withdrawRequestedAt = %d, want 0", details.channelState.WithdrawRequestedAt) + } +} + +// TestComputeRefundSettlementDetails_CapsAtAvailable ensures a requested refund +// above preBalance - postClaimTotalClaimed is capped at the available remainder. +func TestComputeRefundSettlementDetails_CapsAtAvailable(t *testing.T) { + preState := &batchsettlement.ChannelState{ + Balance: big.NewInt(5000), + TotalClaimed: big.NewInt(0), + WithdrawRequestedAt: 0, + RefundNonce: big.NewInt(0), + } + // Claims up to totalClaimed=4000 → available = 5000 - 4000 = 1000. + payload := &batchsettlement.BatchSettlementEnrichedRefundPayload{ + Type: "refund", + Amount: "2000", + RefundNonce: "0", + Claims: []batchsettlement.BatchSettlementVoucherClaim{{ + TotalClaimed: "4000", + }}, + } + details := computeRefundSettlementDetails( + context.Background(), nil, payload, "0xchan", preState, big.NewInt(2000), + ) + if details.amount != "1000" { + t.Fatalf("amount = %q, want 1000 (capped at available)", details.amount) + } + if details.channelState.Balance != "4000" { + t.Fatalf("balance = %q, want 4000 (5000 - 1000)", details.channelState.Balance) + } + if details.channelState.TotalClaimed != "4000" { + t.Fatalf("totalClaimed = %q, want 4000 (advances to last claim)", details.channelState.TotalClaimed) + } +} + +// TestComputeRefundSettlementDetails_NoPreState exercises the RPC-failure +// fallback: missing preState means zero available balance, zero actual refund, +// zero postBalance, and refundNonce advances to 1. Ensures the response never +// panics on a missing chain read. +func TestComputeRefundSettlementDetails_NoPreState(t *testing.T) { + payload := &batchsettlement.BatchSettlementEnrichedRefundPayload{ + Type: "refund", + Amount: "2000", + RefundNonce: "0", + } + details := computeRefundSettlementDetails( + context.Background(), nil, payload, "0xchan", nil, big.NewInt(2000), + ) + if details.amount != "0" { + t.Fatalf("amount = %q, want 0 (no preState → no available)", details.amount) + } + if details.channelState.Balance != "0" { + t.Fatalf("balance = %q, want 0", details.channelState.Balance) + } + if details.channelState.RefundNonce != "1" { + t.Fatalf("refundNonce = %q, want 1", details.channelState.RefundNonce) + } +} + +// ----- encodeXxxCalldata + buildVoucherClaimArgs ----- + +func TestBuildVoucherClaimArgs_Length(t *testing.T) { + claims := []batchsettlement.BatchSettlementVoucherClaim{sampleClaim(), sampleClaim()} + out := buildVoucherClaimArgs(claims) + // The result is a slice of unexported struct values; assert via reflection. + if v, ok := out.([]struct { + Voucher struct { + Channel interface{} + MaxClaimableAmount *big.Int + } + Signature []byte + TotalClaimed *big.Int + }); ok { + if len(v) != 2 { + t.Fatalf("len = %d", len(v)) + } + return + } + // Fallback: just confirm non-nil + if out == nil { + t.Fatal("expected non-nil result") + } +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/refund.go b/go/mechanisms/evm/batch-settlement/facilitator/refund.go new file mode 100644 index 0000000000..795e6eb2dd --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/refund.go @@ -0,0 +1,384 @@ +package facilitator + +import ( + "context" + "fmt" + "math/big" + "strings" + "time" + + "github.com/ethereum/go-ethereum/accounts/abi" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// The post-refund state is only polled when the channel was in +// pending-withdrawal at refund time, since withdraw cancellation makes a simple +// `preBalance - actualRefund` formula inaccurate; otherwise the formula is +// exact and a re-read is unnecessary. +const ( + refundStatePollDeadline = 2 * time.Second + refundStatePollInterval = 150 * time.Millisecond +) + +// ExecuteRefundWithSignature executes a cooperative refund using receiverAuthorizer signature. +// If RefundAuthorizerSignature or ClaimAuthorizerSignature are absent, the +// authorizerSigner auto-signs them. +func ExecuteRefundWithSignature( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + payload *batchsettlement.BatchSettlementEnrichedRefundPayload, + requirements types.PaymentRequirements, + authorizerSigner batchsettlement.AuthorizerSigner, +) (*x402.SettleResponse, error) { + network := x402.Network(requirements.Network) + + refundAmount, ok := new(big.Int).SetString(payload.Amount, 10) + if !ok { + return nil, x402.NewSettleError(ErrInvalidRefundPayload, "", network, "", + fmt.Sprintf("invalid refund amount: %s", payload.Amount)) + } + + nonce, ok := new(big.Int).SetString(payload.RefundNonce, 10) + if !ok { + return nil, x402.NewSettleError(ErrInvalidRefundPayload, "", network, "", + fmt.Sprintf("invalid nonce: %s", payload.RefundNonce)) + } + + // Resolve refund authorizer signature — auto-sign if absent + var refundSig []byte + if payload.RefundAuthorizerSignature != "" { + var err error + refundSig, err = evm.HexToBytes(payload.RefundAuthorizerSignature) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidRefundPayload, "", network, "", + fmt.Sprintf("invalid refund authorizer signature: %s", err)) + } + } else { + // Verify authorizer address matches config's receiverAuthorizer + if !strings.EqualFold(payload.ChannelConfig.ReceiverAuthorizer, authorizerSigner.Address()) { + return nil, x402.NewSettleError(ErrAuthorizerAddressMismatch, "", network, "", + fmt.Sprintf("config receiverAuthorizer %s does not match authorizerSigner %s", + payload.ChannelConfig.ReceiverAuthorizer, authorizerSigner.Address())) + } + channelId, err := batchsettlement.ComputeChannelId(payload.ChannelConfig, string(network)) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidRefundPayload, "", network, "", + fmt.Sprintf("failed to compute channel id: %s", err)) + } + refundSig, err = authorizerSigner.SignRefund(ctx, channelId, payload.Amount, payload.RefundNonce, string(network)) + if err != nil { + return nil, x402.NewSettleError(ErrRefundTransactionFailed, "", network, "", + fmt.Sprintf("failed to sign refund: %s", err)) + } + } + + configTuple := ToContractChannelConfig(payload.ChannelConfig) + + // Compute the canonical channel id once — used for ABI encoding, + // pre/post-state reads, and the response Extra.channelState. + channelId, err := batchsettlement.ComputeChannelId(payload.ChannelConfig, string(network)) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidRefundPayload, "", network, payload.ChannelConfig.Payer, + fmt.Sprintf("failed to compute channel id: %s", err)) + } + + // Read pre-refund onchain state. Errors are non-fatal — without a + // pre-state we still execute the refund and synthesize an extra from + // the payload alone, which the resource server's afterSettle hook can + // still parse. + preState, _ := ReadChannelState(ctx, signer, channelId) + + // Handle claims + refund atomically if claims are present + if len(payload.Claims) > 0 { + // Resolve claim authorizer signature — auto-sign if absent + var claimSig []byte + if payload.ClaimAuthorizerSignature != "" { + var err error + claimSig, err = evm.HexToBytes(payload.ClaimAuthorizerSignature) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidRefundPayload, "", network, "", + fmt.Sprintf("invalid claim authorizer signature: %s", err)) + } + } else { + var err error + claimSig, err = authorizerSigner.SignClaimBatch(ctx, payload.Claims, string(network)) + if err != nil { + return nil, x402.NewSettleError(ErrRefundTransactionFailed, "", network, "", + fmt.Sprintf("failed to sign claim batch for refund: %s", err)) + } + } + + claimArgs := buildVoucherClaimArgs(payload.Claims) + + // ABI-encode both calls for multicall. + claimAbi, err := abi.JSON(strings.NewReader(string(batchsettlement.BatchSettlementClaimWithSignatureABI))) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidRefundPayload, "", network, "", + fmt.Sprintf("failed to load claim ABI: %s", err)) + } + claimCalldata, err := claimAbi.Pack("claimWithSignature", claimArgs, claimSig) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidRefundPayload, "", network, "", + fmt.Sprintf("failed to encode claim calldata: %s", err)) + } + + refundAbi, err := abi.JSON(strings.NewReader(string(batchsettlement.BatchSettlementRefundWithSignatureABI))) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidRefundPayload, "", network, "", + fmt.Sprintf("failed to load refund ABI: %s", err)) + } + refundCalldata, err := refundAbi.Pack("refundWithSignature", configTuple, refundAmount, nonce, refundSig) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidRefundPayload, "", network, "", + fmt.Sprintf("failed to encode refund calldata: %s", err)) + } + + // Simulate via readContract + _, simErr := signer.ReadContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementMulticallABI, + "multicall", + [][]byte{claimCalldata, refundCalldata}, + ) + if simErr != nil { + return &x402.SettleResponse{ //nolint:nilerr // simulation failure → error encoded in response + Success: false, + ErrorReason: ErrRefundSimulationFailed, + ErrorMessage: simErr.Error(), + Transaction: "", + Network: network, + }, nil + } + + txHash, err := signer.WriteContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementMulticallABI, + "multicall", + [][]byte{claimCalldata, refundCalldata}, + ) + if err != nil { + return nil, x402.NewSettleError(ErrRefundTransactionFailed, "", network, "", + fmt.Sprintf("multicall (claim+refund) transaction failed: %s", err)) + } + + receipt, err := signer.WaitForTransactionReceipt(ctx, txHash) + if err != nil { + return nil, x402.NewSettleError(ErrWaitForReceipt, txHash, network, "", + fmt.Sprintf("failed waiting for multicall receipt: %s", err)) + } + if receipt.Status != evm.TxStatusSuccess { + return nil, x402.NewSettleError(ErrTransactionReverted, txHash, network, "", + "multicall (claim+refund) transaction reverted") + } + + details := computeRefundSettlementDetails(ctx, signer, payload, channelId, preState, refundAmount) + return buildRefundResponse(txHash, network, payload.ChannelConfig.Payer, details), nil + } + + // No claims — direct refundWithSignature + + // Simulate + _, simErr := signer.ReadContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementRefundWithSignatureABI, + "refundWithSignature", + configTuple, + refundAmount, + nonce, + refundSig, + ) + if simErr != nil { + return &x402.SettleResponse{ //nolint:nilerr // simulation failure → error encoded in response + Success: false, + ErrorReason: ErrRefundSimulationFailed, + ErrorMessage: simErr.Error(), + Transaction: "", + Network: network, + }, nil + } + + txHash, err := signer.WriteContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementRefundWithSignatureABI, + "refundWithSignature", + configTuple, + refundAmount, + nonce, + refundSig, + ) + if err != nil { + return nil, x402.NewSettleError(ErrRefundTransactionFailed, "", network, "", + fmt.Sprintf("refundWithSignature transaction failed: %s", err)) + } + + receipt, err := signer.WaitForTransactionReceipt(ctx, txHash) + if err != nil { + return nil, x402.NewSettleError(ErrWaitForReceipt, txHash, network, "", + fmt.Sprintf("failed waiting for refundWithSignature receipt: %s", err)) + } + if receipt.Status != evm.TxStatusSuccess { + return nil, x402.NewSettleError(ErrTransactionReverted, txHash, network, "", + "refundWithSignature transaction reverted") + } + + details := computeRefundSettlementDetails(ctx, signer, payload, channelId, preState, refundAmount) + return buildRefundResponse(txHash, network, payload.ChannelConfig.Payer, details), nil +} + +// refundSettlementDetails captures the per-refund response fields the +// facilitator computes from pre/post onchain state and the enriched payload. +type refundSettlementDetails struct { + // amount is the actual refund amount in token base units (decimal string). + // May differ from `payload.amount` when the requested amount exceeds the + // channel's available balance after preceding claims; in that case + // available is used. + amount string + // channelState is the post-refund snapshot. balance reflects + // `preBalance - actualRefund`; totalClaimed reflects the last claim's + // totalClaimed (or preTotalClaimed if no claims); refundNonce is + // `preRefundNonce + 1`; withdrawRequestedAt is 0 because a successful + // `refundWithSignature` clears the pending withdrawal. + channelState batchsettlement.BatchSettlementChannelStateExtra +} + +// computeRefundSettlementDetails builds the response fields after a successful +// refund onchain. When the pre-state shows an active pending withdrawal, the +// facilitator polls for confirmation that the refund nonce advanced before +// computing the snapshot from chain; in the common case the snapshot is +// computed analytically from preState + payload. +func computeRefundSettlementDetails( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + payload *batchsettlement.BatchSettlementEnrichedRefundPayload, + channelId string, + preState *batchsettlement.ChannelState, + requestedAmount *big.Int, +) refundSettlementDetails { + // Default zero values when preState is unavailable; skip pre-balance-based + // capping in that case. + preBalance := big.NewInt(0) + preTotalClaimed := big.NewInt(0) + preRefundNonce := big.NewInt(0) + preWithdrawRequestedAt := 0 + if preState != nil { + if preState.Balance != nil { + preBalance = preState.Balance + } + if preState.TotalClaimed != nil { + preTotalClaimed = preState.TotalClaimed + } + if preState.RefundNonce != nil { + preRefundNonce = preState.RefundNonce + } + preWithdrawRequestedAt = preState.WithdrawRequestedAt + } + + // If the channel was in pending withdrawal, polling the post-state is + // the only way to know the final balance because `refundWithSignature` + // also cancels the withdrawal in a single transaction. On RPC lag (deadline + // elapsed without nonce advancement) we fall through to the analytic path + // below. + if preState != nil && preWithdrawRequestedAt != 0 { + expectedNonce := new(big.Int).Add(preRefundNonce, big.NewInt(1)) + var postState *batchsettlement.ChannelState + deadline := time.Now().Add(refundStatePollDeadline) + for { + s, err := ReadChannelState(ctx, signer, channelId) + if err == nil && s != nil && s.RefundNonce != nil && s.RefundNonce.Cmp(expectedNonce) >= 0 { + postState = s + break + } + if !time.Now().Before(deadline) { + break + } + time.Sleep(refundStatePollInterval) + } + if postState != nil { + actualRefund := big.NewInt(0) + if preBalance.Cmp(postState.Balance) > 0 { + actualRefund = new(big.Int).Sub(preBalance, postState.Balance) + } + return refundSettlementDetails{ + amount: actualRefund.String(), + channelState: batchsettlement.BatchSettlementChannelStateExtra{ + ChannelId: channelId, + Balance: postState.Balance.String(), + TotalClaimed: postState.TotalClaimed.String(), + WithdrawRequestedAt: postState.WithdrawRequestedAt, + RefundNonce: postState.RefundNonce.String(), + }, + } + } + } + + // Analytic path: compute the post-refund snapshot from preState + payload. + // totalClaimed advances to the last claim's totalClaimed (or stays at + // preTotalClaimed if no claims accompany the refund). + postClaimTotalClaimed := new(big.Int).Set(preTotalClaimed) + if n := len(payload.Claims); n > 0 { + if v, ok := new(big.Int).SetString(payload.Claims[n-1].TotalClaimed, 10); ok && v.Cmp(postClaimTotalClaimed) > 0 { + postClaimTotalClaimed = v + } + } + available := new(big.Int).Sub(preBalance, postClaimTotalClaimed) + if available.Sign() < 0 { + available = big.NewInt(0) + } + actualRefund := new(big.Int).Set(requestedAmount) + if actualRefund.Cmp(available) > 0 { + actualRefund = available + } + + postBalance := new(big.Int).Sub(preBalance, actualRefund) + if postBalance.Sign() < 0 { + postBalance = big.NewInt(0) + } + postRefundNonce := new(big.Int).Add(preRefundNonce, big.NewInt(1)) + + return refundSettlementDetails{ + amount: actualRefund.String(), + channelState: batchsettlement.BatchSettlementChannelStateExtra{ + ChannelId: channelId, + Balance: postBalance.String(), + TotalClaimed: postClaimTotalClaimed.String(), + WithdrawRequestedAt: 0, // refundWithSignature clears any pending withdrawal + RefundNonce: postRefundNonce.String(), + }, + } +} + +// buildRefundResponse assembles a SettleResponse for a refund: success + tx + +// payer + amount + extra.channelState. The resource server's +// `enrichSettlementResponse` hook adds `chargedCumulativeAmount` on top via +// additive merge. +func buildRefundResponse( + txHash string, + network x402.Network, + payer string, + details refundSettlementDetails, +) *x402.SettleResponse { + return &x402.SettleResponse{ + Success: true, + Transaction: txHash, + Network: network, + Payer: payer, + Amount: details.amount, + Extra: map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": details.channelState.ChannelId, + "balance": details.channelState.Balance, + "totalClaimed": details.channelState.TotalClaimed, + "withdrawRequestedAt": details.channelState.WithdrawRequestedAt, + "refundNonce": details.channelState.RefundNonce, + }, + }, + } +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/scheme.go b/go/mechanisms/evm/batch-settlement/facilitator/scheme.go new file mode 100644 index 0000000000..4527c5cbe2 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/scheme.go @@ -0,0 +1,153 @@ +package facilitator + +import ( + "context" + "fmt" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// BatchSettlementEvmScheme implements SchemeNetworkFacilitator for batch settlement on EVM. +type BatchSettlementEvmScheme struct { + signer evm.FacilitatorEvmSigner + authorizerSigner batchsettlement.AuthorizerSigner +} + +// NewBatchSettlementEvmScheme creates a new batch settlement facilitator scheme. +// The authorizerSigner is a dedicated key that provides EIP-712 signatures for +// claimWithSignature / refundWithSignature. The facilitator auto-signs when the +// server omits signatures from the payload. +func NewBatchSettlementEvmScheme(signer evm.FacilitatorEvmSigner, authorizerSigner batchsettlement.AuthorizerSigner) *BatchSettlementEvmScheme { + return &BatchSettlementEvmScheme{signer: signer, authorizerSigner: authorizerSigner} +} + +// Scheme returns the scheme identifier. +func (f *BatchSettlementEvmScheme) Scheme() string { + return batchsettlement.SchemeBatched +} + +// CaipFamily returns the CAIP family pattern this facilitator supports. +func (f *BatchSettlementEvmScheme) CaipFamily() string { + return "eip155:*" +} + +// GetExtra returns mechanism-specific extra data for the supported kinds endpoint. +// Exposes the receiverAuthorizer address so server and client can embed it in ChannelConfig. +func (f *BatchSettlementEvmScheme) GetExtra(_ x402.Network) map[string]interface{} { + return map[string]interface{}{ + "receiverAuthorizer": f.authorizerSigner.Address(), + } +} + +// GetSigners returns signer addresses used by this facilitator. +func (f *BatchSettlementEvmScheme) GetSigners(_ x402.Network) []string { + return f.signer.GetAddresses() +} + +// Verify verifies a batched payment payload. +// Routes to deposit or voucher verification based on payload type. +func (f *BatchSettlementEvmScheme) Verify( + ctx context.Context, + payload types.PaymentPayload, + requirements types.PaymentRequirements, + fctx *x402.FacilitatorContext, +) (*x402.VerifyResponse, error) { + // Defensive scheme and network validation. + if payload.Accepted.Scheme != batchsettlement.SchemeBatched || requirements.Scheme != batchsettlement.SchemeBatched { + return &x402.VerifyResponse{IsValid: false, InvalidReason: ErrInvalidScheme}, nil + } + if payload.Accepted.Network != requirements.Network { + return &x402.VerifyResponse{IsValid: false, InvalidReason: ErrNetworkMismatch}, nil + } + + data := payload.Payload + + if batchsettlement.IsDepositPayload(data) { + depositPayload, err := batchsettlement.DepositPayloadFromMap(data) + if err != nil { + return nil, x402.NewVerifyError(ErrInvalidDepositPayload, "", + fmt.Sprintf("failed to parse deposit payload: %s", err)) + } + return VerifyDeposit(ctx, f.signer, depositPayload, requirements, payload.Extensions, fctx) + } + + if batchsettlement.IsVoucherPayload(data) { + voucherPayload, err := batchsettlement.VoucherPayloadFromMap(data) + if err != nil { + return nil, x402.NewVerifyError(ErrInvalidVoucherPayload, "", + fmt.Sprintf("failed to parse voucher payload: %s", err)) + } + return VerifyVoucher(ctx, f.signer, voucherPayload, requirements, voucherPayload.ChannelConfig) + } + + // Cooperative refund: client sends a zero-charge voucher with type="refund". + // Refund and voucher payloads share the same voucher-verification path with + // a refund-aware cumulative check. + if batchsettlement.IsRefundPayload(data) { + refundPayload, err := batchsettlement.RefundPayloadFromMap(data) + if err != nil { + return nil, x402.NewVerifyError(ErrInvalidRefundPayload, "", + fmt.Sprintf("failed to parse refund payload: %s", err)) + } + return VerifyRefundVoucher(ctx, f.signer, refundPayload, requirements, refundPayload.ChannelConfig) + } + + return &x402.VerifyResponse{IsValid: false, InvalidReason: ErrInvalidPayload}, nil +} + +// Settle settles a batched payment onchain. +// Routes based on payload type or settleAction field. +func (f *BatchSettlementEvmScheme) Settle( + ctx context.Context, + payload types.PaymentPayload, + requirements types.PaymentRequirements, + fctx *x402.FacilitatorContext, +) (*x402.SettleResponse, error) { + data := payload.Payload + network := x402.Network(requirements.Network) + + // Check for deposit payload (type="deposit") + if batchsettlement.IsDepositPayload(data) { + depositPayload, err := batchsettlement.DepositPayloadFromMap(data) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidDepositPayload, "", network, "", + fmt.Sprintf("failed to parse deposit payload: %s", err)) + } + return SettleDeposit(ctx, f.signer, depositPayload, requirements, payload.Extensions, fctx) + } + + // Enriched refund settle-action (must be checked BEFORE plain claim, since both + // have type="refund" but enriched also has claims+amount+refundNonce). + if batchsettlement.IsEnrichedRefundPayload(data) { + refundPayload, err := batchsettlement.EnrichedRefundPayloadFromMap(data) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidRefundPayload, "", network, "", + fmt.Sprintf("failed to parse refund payload: %s", err)) + } + return ExecuteRefundWithSignature(ctx, f.signer, refundPayload, requirements, f.authorizerSigner) + } + + if batchsettlement.IsClaimPayload(data) { + claimPayload, err := batchsettlement.ClaimPayloadFromMap(data) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidClaimPayload, "", network, "", + fmt.Sprintf("failed to parse claim payload: %s", err)) + } + return ExecuteClaimWithSignature(ctx, f.signer, claimPayload, requirements, f.authorizerSigner) + } + + if batchsettlement.IsSettlePayload(data) { + settlePayload, err := batchsettlement.SettlePayloadFromMap(data) + if err != nil { + return nil, x402.NewSettleError(ErrInvalidSettlePayload, "", network, "", + fmt.Sprintf("failed to parse settle payload: %s", err)) + } + return ExecuteSettle(ctx, f.signer, settlePayload, requirements) + } + + return nil, x402.NewSettleError(ErrUnknownSettleAction, "", network, "", + "unrecognized batch-settlement settle action or payload type") +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/scheme_test.go b/go/mechanisms/evm/batch-settlement/facilitator/scheme_test.go new file mode 100644 index 0000000000..477ab41af4 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/scheme_test.go @@ -0,0 +1,279 @@ +package facilitator + +import ( + "context" + "errors" + "math/big" + "testing" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// fakeFacilitatorSigner is a no-op FacilitatorEvmSigner used when routing should +// fail before any RPC is required. Methods that depend on RPC return errors. +type fakeFacilitatorSigner struct { + addresses []string + chainId *big.Int + + // Optional overrides for VerifyTypedData and ReadContract. + verifyTypedData func(address string) (bool, error) + verifyCalls int + verifyAddrs []string +} + +func (f *fakeFacilitatorSigner) GetAddresses() []string { return f.addresses } +func (f *fakeFacilitatorSigner) ReadContract(_ context.Context, _ string, _ []byte, _ string, _ ...interface{}) (interface{}, error) { + return nil, errors.New("no rpc") +} +func (f *fakeFacilitatorSigner) VerifyTypedData(_ context.Context, address string, _ evm.TypedDataDomain, _ map[string][]evm.TypedDataField, _ string, _ map[string]interface{}, _ []byte) (bool, error) { + f.verifyCalls++ + f.verifyAddrs = append(f.verifyAddrs, address) + if f.verifyTypedData != nil { + return f.verifyTypedData(address) + } + return false, errors.New("no rpc") +} +func (f *fakeFacilitatorSigner) WriteContract(_ context.Context, _ string, _ []byte, _ string, _ ...interface{}) (string, error) { + return "", errors.New("no rpc") +} +func (f *fakeFacilitatorSigner) SendTransaction(_ context.Context, _ string, _ []byte) (string, error) { + return "", errors.New("no rpc") +} +func (f *fakeFacilitatorSigner) WaitForTransactionReceipt(_ context.Context, _ string) (*evm.TransactionReceipt, error) { + return nil, errors.New("no rpc") +} +func (f *fakeFacilitatorSigner) GetBalance(_ context.Context, _ string, _ string) (*big.Int, error) { + return big.NewInt(0), nil +} +func (f *fakeFacilitatorSigner) GetChainID(_ context.Context) (*big.Int, error) { + if f.chainId != nil { + return f.chainId, nil + } + return big.NewInt(8453), nil +} +func (f *fakeFacilitatorSigner) GetCode(_ context.Context, _ string) ([]byte, error) { + return nil, nil +} + +// fakeAuthorizerSigner is a no-op AuthorizerSigner. +type fakeAuthorizerSigner struct{ addr string } + +func (a *fakeAuthorizerSigner) Address() string { return a.addr } +func (a *fakeAuthorizerSigner) SignClaimBatch(_ context.Context, _ []batchsettlement.BatchSettlementVoucherClaim, _ string) ([]byte, error) { + return []byte("sig"), nil +} +func (a *fakeAuthorizerSigner) SignRefund(_ context.Context, _ string, _ string, _ string, _ string) ([]byte, error) { + return []byte("sig"), nil +} + +func newScheme() *BatchSettlementEvmScheme { + return NewBatchSettlementEvmScheme( + &fakeFacilitatorSigner{addresses: []string{"0xfacilitator"}}, + &fakeAuthorizerSigner{addr: "0xauthorizer"}, + ) +} + +func TestScheme_Identifier(t *testing.T) { + s := newScheme() + if s.Scheme() != batchsettlement.SchemeBatched { + t.Fatalf("scheme = %s", s.Scheme()) + } + if s.CaipFamily() != "eip155:*" { + t.Fatalf("caip = %s", s.CaipFamily()) + } +} + +func TestScheme_GetExtra(t *testing.T) { + s := newScheme() + got := s.GetExtra(x402.Network("eip155:8453")) + if got["receiverAuthorizer"] != "0xauthorizer" { + t.Fatalf("extra = %+v", got) + } +} + +func TestScheme_GetSigners(t *testing.T) { + s := newScheme() + got := s.GetSigners(x402.Network("eip155:8453")) + if len(got) != 1 || got[0] != "0xfacilitator" { + t.Fatalf("signers = %+v", got) + } +} + +func payloadEnvelope(network string, payload map[string]interface{}) types.PaymentPayload { + return types.PaymentPayload{ + X402Version: 2, + Payload: payload, + Accepted: types.PaymentRequirements{ + Scheme: batchsettlement.SchemeBatched, + Network: network, + }, + } +} + +func TestVerify_BadScheme(t *testing.T) { + s := newScheme() + pp := payloadEnvelope("eip155:8453", map[string]interface{}{"type": "voucher"}) + pp.Accepted.Scheme = "exact" + req := types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"} + resp, err := s.Verify(context.Background(), pp, req, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if resp.IsValid || resp.InvalidReason != ErrInvalidScheme { + t.Fatalf("got %+v", resp) + } +} + +func TestVerify_NetworkMismatch(t *testing.T) { + s := newScheme() + pp := payloadEnvelope("eip155:1", map[string]interface{}{"type": "voucher"}) + req := types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"} + resp, err := s.Verify(context.Background(), pp, req, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if resp.IsValid || resp.InvalidReason != ErrNetworkMismatch { + t.Fatalf("got %+v", resp) + } +} + +func TestVerify_UnknownPayload(t *testing.T) { + s := newScheme() + pp := payloadEnvelope("eip155:8453", map[string]interface{}{"type": "mystery"}) + req := types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"} + resp, err := s.Verify(context.Background(), pp, req, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if resp.IsValid || resp.InvalidReason != ErrInvalidPayload { + t.Fatalf("got %+v", resp) + } +} + +func TestVerify_MalformedDepositPayload(t *testing.T) { + s := newScheme() + // IsDepositPayload requires type=deposit + channelConfig + voucher + deposit. + // Pass them, but with channelConfig as a non-map so DepositPayloadFromMap errors. + pp := payloadEnvelope("eip155:8453", map[string]interface{}{ + "type": "deposit", + "channelConfig": "not-a-map", + "voucher": map[string]interface{}{}, + "deposit": map[string]interface{}{}, + }) + req := types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"} + _, err := s.Verify(context.Background(), pp, req, nil) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrInvalidDepositPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestVerify_MalformedVoucherPayload(t *testing.T) { + s := newScheme() + // IsVoucherPayload requires type=voucher + channelConfig + voucher. Pass them, + // but with channelConfig as a non-map so VoucherPayloadFromMap errors. + pp := payloadEnvelope("eip155:8453", map[string]interface{}{ + "type": "voucher", + "channelConfig": "not-a-map", + "voucher": map[string]interface{}{ + "channelId": "0xabc", + "maxClaimableAmount": "1", + "signature": "0xsig", + }, + }) + req := types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"} + _, err := s.Verify(context.Background(), pp, req, nil) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrInvalidVoucherPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestSettle_UnknownAction(t *testing.T) { + s := newScheme() + pp := payloadEnvelope("eip155:8453", map[string]interface{}{"settleAction": "no-such-thing"}) + req := types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"} + _, err := s.Settle(context.Background(), pp, req, nil) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrUnknownSettleAction { + t.Fatalf("got err = %v", err) + } +} + +func TestSettle_MalformedDepositPayload(t *testing.T) { + s := newScheme() + pp := payloadEnvelope("eip155:8453", map[string]interface{}{ + "type": "deposit", + "channelConfig": "not-a-map", + "voucher": map[string]interface{}{}, + "deposit": map[string]interface{}{}, + }) + req := types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"} + _, err := s.Settle(context.Background(), pp, req, nil) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrInvalidDepositPayload { + t.Fatalf("got err = %v", err) + } +} + +func TestSettle_MalformedClaimPayload(t *testing.T) { + s := newScheme() + // IsClaimPayload requires type=claim + claims. Pass a non-list claims so + // ClaimPayloadFromMap errors. + pp := payloadEnvelope("eip155:8453", map[string]interface{}{ + "type": "claim", + "claims": "not-a-list", + }) + req := types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"} + _, err := s.Settle(context.Background(), pp, req, nil) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrInvalidClaimPayload { + t.Fatalf("got err = %v", err) + } +} + +// TestVerify_MalformedRefundPayload ensures refund payloads route to +// VerifyRefundVoucher. A malformed refund must surface as +// `invalid_batch_settlement_evm_refund_payload`, not the generic invalid type. +func TestVerify_MalformedRefundPayload(t *testing.T) { + s := newScheme() + pp := payloadEnvelope("eip155:8453", map[string]interface{}{ + "type": "refund", + "channelConfig": "not-a-map", + "voucher": map[string]interface{}{ + "channelId": "0xabc", + "maxClaimableAmount": "0", + "signature": "0xsig", + }, + }) + req := types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"} + _, err := s.Verify(context.Background(), pp, req, nil) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrInvalidRefundPayload { + t.Fatalf("got err = %v (want %s)", err, ErrInvalidRefundPayload) + } +} + +func TestSettle_MalformedRefundPayload(t *testing.T) { + s := newScheme() + // IsEnrichedRefundPayload requires type=refund + channelConfig + voucher + + // amount + refundNonce + claims. Pass them, but with channelConfig as a + // non-map so EnrichedRefundPayloadFromMap errors. + pp := payloadEnvelope("eip155:8453", map[string]interface{}{ + "type": "refund", + "channelConfig": "not-a-map", + "voucher": map[string]interface{}{}, + "amount": "1", + "refundNonce": "1", + "claims": []interface{}{}, + }) + req := types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"} + _, err := s.Settle(context.Background(), pp, req, nil) + var se *x402.SettleError + if !errors.As(err, &se) || se.ErrorReason != ErrInvalidRefundPayload { + t.Fatalf("got err = %v", err) + } +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/settle.go b/go/mechanisms/evm/batch-settlement/facilitator/settle.go new file mode 100644 index 0000000000..0507025b58 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/settle.go @@ -0,0 +1,71 @@ +package facilitator + +import ( + "context" + "fmt" + + "github.com/ethereum/go-ethereum/common" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// ExecuteSettle executes a settle action, transferring claimed funds to the receiver. +// Calls settle(receiver, token) on the BatchSettlement contract. +func ExecuteSettle( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + payload *batchsettlement.BatchSettlementSettlePayload, + requirements types.PaymentRequirements, +) (*x402.SettleResponse, error) { + network := x402.Network(requirements.Network) + + // Simulate before submitting + _, simErr := signer.ReadContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementSettleABI, + "settle", + common.HexToAddress(payload.Receiver), + common.HexToAddress(payload.Token), + ) + if simErr != nil { + return &x402.SettleResponse{ //nolint:nilerr // simulation failure → error encoded in response + Success: false, + ErrorReason: ErrSettleSimulationFailed, + Transaction: "", + Network: network, + }, nil + } + + txHash, err := signer.WriteContract( + ctx, + batchsettlement.BatchSettlementAddress, + batchsettlement.BatchSettlementSettleABI, + "settle", + common.HexToAddress(payload.Receiver), + common.HexToAddress(payload.Token), + ) + if err != nil { + return nil, x402.NewSettleError(ErrSettleTransactionFailed, "", network, "", + fmt.Sprintf("settle transaction failed: %s", err)) + } + + receipt, err := signer.WaitForTransactionReceipt(ctx, txHash) + if err != nil { + return nil, x402.NewSettleError(ErrWaitForReceipt, txHash, network, "", + fmt.Sprintf("failed waiting for settle receipt: %s", err)) + } + if receipt.Status != evm.TxStatusSuccess { + return nil, x402.NewSettleError(ErrTransactionReverted, txHash, network, "", + "settle transaction reverted") + } + + return &x402.SettleResponse{ + Success: true, + Transaction: txHash, + Network: network, + }, nil +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/utils.go b/go/mechanisms/evm/batch-settlement/facilitator/utils.go new file mode 100644 index 0000000000..bcdb775ec7 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/utils.go @@ -0,0 +1,317 @@ +package facilitator + +import ( + "context" + "fmt" + "math/big" + "strings" + "time" + + "github.com/ethereum/go-ethereum/common" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +var zeroAddress = "0x0000000000000000000000000000000000000000" + +// ContractChannelConfigTuple is the concrete struct shape passed to BatchSettlement +// contract calls (deposit, refund, claim). Field names and ordering match the +// Solidity ChannelConfig struct so go-ethereum's ABI packer can map them by reflection. +type ContractChannelConfigTuple struct { + Payer common.Address + PayerAuthorizer common.Address + Receiver common.Address + ReceiverAuthorizer common.Address + Token common.Address + WithdrawDelay *big.Int + Salt [32]byte +} + +// ToContractChannelConfig normalizes a ChannelConfig into the address-checksummed +// Solidity tuple expected by the batch-settlement contract's deposit / refund / +// claim entry points. +func ToContractChannelConfig(config batchsettlement.ChannelConfig) ContractChannelConfigTuple { + withdrawDelay := new(big.Int).SetInt64(int64(config.WithdrawDelay)) + + saltBytes := common.FromHex(config.Salt) + var salt [32]byte + copy(salt[:], saltBytes) + + return ContractChannelConfigTuple{ + Payer: common.HexToAddress(config.Payer), + PayerAuthorizer: common.HexToAddress(config.PayerAuthorizer), + Receiver: common.HexToAddress(config.Receiver), + ReceiverAuthorizer: common.HexToAddress(config.ReceiverAuthorizer), + Token: common.HexToAddress(config.Token), + WithdrawDelay: withdrawDelay, + Salt: salt, + } +} + +// ReadChannelState reads onchain channel state via a 3-call multicall: +// channels(channelId), pendingWithdrawals(channelId), refundNonce(channelId). +// Returns an error tagged with ErrRpcReadFailed when any sub-call fails so +// callers can distinguish RPC failures from a missing channel (which returns +// zero balance/totalClaimed/refundNonce). +func ReadChannelState( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + channelId string, +) (*batchsettlement.ChannelState, error) { + channelIdBytes := common.HexToHash(channelId) + + results, err := evm.Multicall(ctx, signer, []evm.MulticallCall{ + { + Address: batchsettlement.BatchSettlementAddress, + ABI: batchsettlement.BatchSettlementChannelsABI, + FunctionName: "channels", + Args: []interface{}{channelIdBytes}, + }, + { + Address: batchsettlement.BatchSettlementAddress, + ABI: batchsettlement.BatchSettlementPendingWithdrawalsABI, + FunctionName: "pendingWithdrawals", + Args: []interface{}{channelIdBytes}, + }, + { + Address: batchsettlement.BatchSettlementAddress, + ABI: batchsettlement.BatchSettlementRefundNonceABI, + FunctionName: "refundNonce", + Args: []interface{}{channelIdBytes}, + }, + }) + if err != nil { + return nil, fmt.Errorf("multicall failed: %w", err) + } + + if !results[0].Success() || !results[1].Success() || !results[2].Success() { + return nil, fmt.Errorf("%s: multicall returned failure for %s", ErrRpcReadFailed, channelId) + } + + state := &batchsettlement.ChannelState{ + Balance: big.NewInt(0), + TotalClaimed: big.NewInt(0), + RefundNonce: big.NewInt(0), + } + + // Parse channels result: [balance (uint128), totalClaimed (uint128)] + if channelResult, ok := results[0].Result.([]interface{}); ok && len(channelResult) >= 2 { + if bal, ok := channelResult[0].(*big.Int); ok { + state.Balance = bal + } + if tc, ok := channelResult[1].(*big.Int); ok { + state.TotalClaimed = tc + } + } + + // Parse pendingWithdrawals result: [amount (uint128), initiatedAt (uint40)] + if wdResult, ok := results[1].Result.([]interface{}); ok && len(wdResult) >= 2 { + if initiatedAt, ok := wdResult[1].(*big.Int); ok { + state.WithdrawRequestedAt = int(initiatedAt.Int64()) + } + } + + // Parse refundNonce result: uint256 + if nonce, ok := results[2].Result.(*big.Int); ok { + state.RefundNonce = nonce + } + + return state, nil +} + +// ValidateChannelConfig validates a ChannelConfig against payment requirements. +func ValidateChannelConfig( + config batchsettlement.ChannelConfig, + channelId string, + requirements types.PaymentRequirements, +) error { + // Validate receiver matches + if !strings.EqualFold(config.Receiver, requirements.PayTo) { + return x402.NewVerifyError(ErrReceiverMismatch, "", + fmt.Sprintf("channel receiver %s does not match payTo %s", config.Receiver, requirements.PayTo)) + } + + // Validate token matches + if !strings.EqualFold(config.Token, requirements.Asset) { + return x402.NewVerifyError(ErrTokenMismatch, "", + fmt.Sprintf("channel token %s does not match asset %s", config.Token, requirements.Asset)) + } + + // Validate withdraw delay bounds + if config.WithdrawDelay < batchsettlement.MinWithdrawDelay { + return x402.NewVerifyError(ErrWithdrawDelayOutOfRange, "", + fmt.Sprintf("withdrawDelay %d is below minimum %d", config.WithdrawDelay, batchsettlement.MinWithdrawDelay)) + } + if config.WithdrawDelay > batchsettlement.MaxWithdrawDelay { + return x402.NewVerifyError(ErrWithdrawDelayOutOfRange, "", + fmt.Sprintf("withdrawDelay %d exceeds maximum %d", config.WithdrawDelay, batchsettlement.MaxWithdrawDelay)) + } + + // Validate channelId matches computed + computed, err := batchsettlement.ComputeChannelId(config, requirements.Network) + if err != nil { + return x402.NewVerifyError(ErrChannelIdMismatch, "", fmt.Sprintf("failed to compute channel id: %s", err)) + } + if !strings.EqualFold(computed, channelId) { + return x402.NewVerifyError(ErrChannelIdMismatch, "", + fmt.Sprintf("computed channelId %s does not match provided %s", computed, channelId)) + } + + // Validate against the requirement's `extra` map. Only `receiverAuthorizer` + // and `withdrawDelay` participate in this check — other fields + // (`name` / `version` / `assetTransferMethod`) are consumed elsewhere or + // only exist to round-trip to the client, so they don't need to be + // decoded here. + // + // receiverAuthorizer is mandatory and must agree with the channel's bound + // authorizer. + expectedAuthorizer, _ := requirements.Extra["receiverAuthorizer"].(string) + if expectedAuthorizer == "" || strings.EqualFold(expectedAuthorizer, zeroAddress) || + !strings.EqualFold(config.ReceiverAuthorizer, expectedAuthorizer) { + return x402.NewVerifyError(ErrReceiverAuthorizerMismatch, "", + fmt.Sprintf("channel receiverAuthorizer %s does not match required %s", + config.ReceiverAuthorizer, expectedAuthorizer)) + } + if requirements.Extra != nil { + var expectedDelay int + switch v := requirements.Extra["withdrawDelay"].(type) { + case float64: + expectedDelay = int(v) + case int: + expectedDelay = v + case int64: + expectedDelay = int(v) + } + if expectedDelay != 0 && config.WithdrawDelay != expectedDelay { + return x402.NewVerifyError(ErrWithdrawDelayMismatch, "", + fmt.Sprintf("channel withdrawDelay %d does not match required %d", + config.WithdrawDelay, expectedDelay)) + } + } + + return nil +} + +// VerifyBatchedVoucherTypedData verifies a voucher signature using dual-path verification. +// If payerAuthorizer != 0x0: ECDSA verification against payerAuthorizer (fast, stateless). +// If payerAuthorizer == 0x0: ERC-1271 verification against payer (smart wallet path). +func VerifyBatchedVoucherTypedData( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + channelId string, + maxClaimableAmount string, + payerAuthorizer string, + payer string, + signature string, + chainId *big.Int, +) (bool, error) { + domain := batchsettlement.GetBatchSettlementEip712Domain(chainId) + + maxClaimable, ok := new(big.Int).SetString(maxClaimableAmount, 10) + if !ok { + return false, fmt.Errorf("invalid maxClaimableAmount: %s", maxClaimableAmount) + } + + channelIdBytes, err := evm.HexToBytes(channelId) + if err != nil { + return false, fmt.Errorf("invalid channelId: %w", err) + } + + sigBytes, err := evm.HexToBytes(signature) + if err != nil { + return false, fmt.Errorf("invalid signature: %w", err) + } + + message := map[string]interface{}{ + "channelId": channelIdBytes, + "maxClaimableAmount": maxClaimable, + } + + // If payerAuthorizer is non-zero, verify via ECDSA against payerAuthorizer + if payerAuthorizer != zeroAddress && payerAuthorizer != "" { + return signer.VerifyTypedData( + ctx, + payerAuthorizer, + domain, + batchsettlement.VoucherTypes, + "Voucher", + message, + sigBytes, + ) + } + + // Otherwise, verify via ERC-1271 against payer (smart wallet) + return signer.VerifyTypedData( + ctx, + payer, + domain, + batchsettlement.VoucherTypes, + "Voucher", + message, + sigBytes, + ) +} + +// channelStateFields builds the shared field set used by both verify and +// settle response extras: { channelId, balance, totalClaimed, +// withdrawRequestedAt, refundNonce }. It does not include +// `chargedCumulativeAmount` because the resource server adds that field during +// settlement-response enrichment; the additive enrichment policy rejects +// duplicates emitted by the facilitator. +func channelStateFields(channelId string, state *batchsettlement.ChannelState) map[string]interface{} { + return map[string]interface{}{ + "channelId": channelId, + "balance": state.Balance.String(), + "totalClaimed": state.TotalClaimed.String(), + "withdrawRequestedAt": state.WithdrawRequestedAt, + "refundNonce": state.RefundNonce.String(), + } +} + +// BuildVerifyExtra creates the Extensions map for VERIFY responses: +// +// { channelId, balance, totalClaimed, withdrawRequestedAt, refundNonce } +// +// Server-side `AfterVerifyHook` reads these fields directly off `extra` (e.g. +// `extra["balance"]`); wrapping them in `channelState` like the settle +// response would silently break state tracking. +func BuildVerifyExtra(channelId string, state *batchsettlement.ChannelState) map[string]interface{} { + return channelStateFields(channelId, state) +} + +// BuildSettleExtra creates the Extensions map for SETTLE responses: +// +// { "channelState": { channelId, balance, totalClaimed, withdrawRequestedAt, +// refundNonce } } +// +// Server-side `AfterSettleHook` reads `extra.channelState.*` and the resource +// server's `enrichSettlementResponse` hook then adds `chargedCumulativeAmount` +// (and, for deposits, `chargedAmount`) on top via additive enrichment. +func BuildSettleExtra(channelId string, state *batchsettlement.ChannelState) map[string]interface{} { + return map[string]interface{}{ + "channelState": channelStateFields(channelId, state), + } +} + +// Erc3009AuthorizationTimeInvalidReason checks the validity window of an ERC-3009 authorization. +// Returns an error code string if invalid, or empty string if valid. +func Erc3009AuthorizationTimeInvalidReason(validAfter, validBefore *big.Int) string { + now := big.NewInt(currentTimestamp()) + nowPlusBuffer := new(big.Int).Add(now, big.NewInt(6)) + + if validBefore.Cmp(nowPlusBuffer) < 0 { + return ErrValidBeforeExpired + } + if validAfter.Cmp(now) > 0 { + return ErrValidAfterInFuture + } + return "" +} + +// currentTimestamp returns the current unix timestamp in seconds. +func currentTimestamp() int64 { + return time.Now().Unix() +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/utils_test.go b/go/mechanisms/evm/batch-settlement/facilitator/utils_test.go new file mode 100644 index 0000000000..5c970e7b6c --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/utils_test.go @@ -0,0 +1,328 @@ +package facilitator + +import ( + "errors" + "math/big" + "strings" + "testing" + "time" + + x402 "github.com/x402-foundation/x402/go" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// validConfig returns a ChannelConfig whose computed channel id is deterministic. +func validConfig() batchsettlement.ChannelConfig { + return batchsettlement.ChannelConfig{ + Payer: "0x1111111111111111111111111111111111111111", + PayerAuthorizer: "0x2222222222222222222222222222222222222222", + Receiver: "0x3333333333333333333333333333333333333333", + ReceiverAuthorizer: "0x4444444444444444444444444444444444444444", + Token: "0x5555555555555555555555555555555555555555", + WithdrawDelay: 900, + Salt: "0x0000000000000000000000000000000000000000000000000000000000000001", + } +} + +func TestToContractChannelConfig_Roundtrips(t *testing.T) { + cfg := validConfig() + v := ToContractChannelConfig(cfg) + if !strings.EqualFold(v.Payer.Hex(), cfg.Payer) { + t.Fatalf("payer = %s", v.Payer.Hex()) + } + if !strings.EqualFold(v.Receiver.Hex(), cfg.Receiver) { + t.Fatalf("receiver = %s", v.Receiver.Hex()) + } + if v.WithdrawDelay.Int64() != int64(cfg.WithdrawDelay) { + t.Fatalf("withdrawDelay = %s", v.WithdrawDelay) + } + if v.Salt[31] != 0x01 { + t.Fatalf("salt last byte = %x", v.Salt[31]) + } +} + +func TestToContractChannelConfig_ShortSaltLeftPads(t *testing.T) { + cfg := validConfig() + cfg.Salt = "0xff" + v := ToContractChannelConfig(cfg) + if v.Salt[0] != 0xff { + t.Fatalf("expected leading 0xff, got %x", v.Salt[0]) + } + for i := 1; i < 32; i++ { + if v.Salt[i] != 0x00 { + t.Fatalf("byte %d should be zero, got %x", i, v.Salt[i]) + } + } +} + +func reqs(payTo, asset string) types.PaymentRequirements { + return types.PaymentRequirements{ + PayTo: payTo, + Asset: asset, + Network: "eip155:8453", + Extra: map[string]interface{}{ + "receiverAuthorizer": "0x4444444444444444444444444444444444444444", + }, + } +} + +func TestValidateChannelConfig_OK(t *testing.T) { + cfg := validConfig() + id, err := batchsettlement.ComputeChannelId(cfg, "eip155:8453") + if err != nil { + t.Fatalf("compute: %v", err) + } + if err := ValidateChannelConfig(cfg, id, reqs(cfg.Receiver, cfg.Token)); err != nil { + t.Fatalf("expected valid: %v", err) + } +} + +func TestValidateChannelConfig_ReceiverMismatch(t *testing.T) { + cfg := validConfig() + id, _ := batchsettlement.ComputeChannelId(cfg, "eip155:8453") + err := ValidateChannelConfig(cfg, id, reqs("0xabc", cfg.Token)) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrReceiverMismatch { + t.Fatalf("got %v", err) + } +} + +func TestValidateChannelConfig_TokenMismatch(t *testing.T) { + cfg := validConfig() + id, _ := batchsettlement.ComputeChannelId(cfg, "eip155:8453") + err := ValidateChannelConfig(cfg, id, reqs(cfg.Receiver, "0xabc")) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrTokenMismatch { + t.Fatalf("got %v", err) + } +} + +func TestValidateChannelConfig_DelayBelowMin(t *testing.T) { + cfg := validConfig() + cfg.WithdrawDelay = batchsettlement.MinWithdrawDelay - 1 + id, _ := batchsettlement.ComputeChannelId(cfg, "eip155:8453") + err := ValidateChannelConfig(cfg, id, reqs(cfg.Receiver, cfg.Token)) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrWithdrawDelayOutOfRange { + t.Fatalf("got %v", err) + } +} + +func TestValidateChannelConfig_DelayAboveMax(t *testing.T) { + cfg := validConfig() + cfg.WithdrawDelay = batchsettlement.MaxWithdrawDelay + 1 + id, _ := batchsettlement.ComputeChannelId(cfg, "eip155:8453") + err := ValidateChannelConfig(cfg, id, reqs(cfg.Receiver, cfg.Token)) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrWithdrawDelayOutOfRange { + t.Fatalf("got %v", err) + } +} + +func TestValidateChannelConfig_ChannelIdMismatch(t *testing.T) { + cfg := validConfig() + err := ValidateChannelConfig(cfg, "0xdeadbeef", reqs(cfg.Receiver, cfg.Token)) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrChannelIdMismatch { + t.Fatalf("got %v", err) + } +} + +func TestValidateChannelConfig_ExtraReceiverAuthorizerMismatch(t *testing.T) { + cfg := validConfig() + id, _ := batchsettlement.ComputeChannelId(cfg, "eip155:8453") + r := reqs(cfg.Receiver, cfg.Token) + r.Extra = map[string]interface{}{ + "receiverAuthorizer": "0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef", + } + err := ValidateChannelConfig(cfg, id, r) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrReceiverAuthorizerMismatch { + t.Fatalf("got %v", err) + } +} + +func TestValidateChannelConfig_ExtraWithdrawDelayMismatch(t *testing.T) { + cfg := validConfig() + id, _ := batchsettlement.ComputeChannelId(cfg, "eip155:8453") + r := reqs(cfg.Receiver, cfg.Token) + r.Extra = map[string]interface{}{ + "receiverAuthorizer": cfg.ReceiverAuthorizer, + "withdrawDelay": float64(2000), + } + err := ValidateChannelConfig(cfg, id, r) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrWithdrawDelayMismatch { + t.Fatalf("got %v", err) + } +} + +func TestValidateChannelConfig_ExtraMatching(t *testing.T) { + cfg := validConfig() + id, _ := batchsettlement.ComputeChannelId(cfg, "eip155:8453") + r := reqs(cfg.Receiver, cfg.Token) + r.Extra = map[string]interface{}{ + "receiverAuthorizer": cfg.ReceiverAuthorizer, + "withdrawDelay": float64(cfg.WithdrawDelay), + } + if err := ValidateChannelConfig(cfg, id, r); err != nil { + t.Fatalf("expected ok with matching extra: %v", err) + } +} + +// TestValidateChannelConfig_ExtraWithdrawDelayNumberShapes covers the inlined +// numeric coercion for `withdrawDelay`: JSON decoders surface int/int64/float64 +// depending on source, and the validator must accept all three so callers +// don't fail on benign type drift. +func TestValidateChannelConfig_ExtraWithdrawDelayNumberShapes(t *testing.T) { + cfg := validConfig() + id, _ := batchsettlement.ComputeChannelId(cfg, "eip155:8453") + for label, value := range map[string]interface{}{ + "int": int(cfg.WithdrawDelay), + "int64": int64(cfg.WithdrawDelay), + "float64": float64(cfg.WithdrawDelay), + } { + t.Run(label, func(t *testing.T) { + r := reqs(cfg.Receiver, cfg.Token) + r.Extra = map[string]interface{}{ + "receiverAuthorizer": cfg.ReceiverAuthorizer, + "withdrawDelay": value, + } + if err := ValidateChannelConfig(cfg, id, r); err != nil { + t.Fatalf("delay=%v (%s): expected ok, got %v", value, label, err) + } + }) + } +} + +// TestValidateChannelConfig_ExtraTypeTolerance pins parser behavior for the +// two participating Extra fields. `withdrawDelay` is silently ignored when +// non-numeric (benign type drift in JSON decoders). `receiverAuthorizer` is +// strictly required: a non-string value is treated as missing and rejected. +func TestValidateChannelConfig_ExtraTypeTolerance(t *testing.T) { + cfg := validConfig() + id, _ := batchsettlement.ComputeChannelId(cfg, "eip155:8453") + + // Non-numeric withdrawDelay is ignored; receiverAuthorizer is valid. + r := reqs(cfg.Receiver, cfg.Token) + r.Extra = map[string]interface{}{ + "receiverAuthorizer": cfg.ReceiverAuthorizer, + "withdrawDelay": "not-a-number", + } + if err := ValidateChannelConfig(cfg, id, r); err != nil { + t.Fatalf("expected non-numeric withdrawDelay to be ignored, got %v", err) + } + + // Non-string receiverAuthorizer is rejected (the field is mandatory). + r.Extra = map[string]interface{}{"receiverAuthorizer": 42} + err := ValidateChannelConfig(cfg, id, r) + var ve *x402.VerifyError + if !errors.As(err, &ve) || ve.InvalidReason != ErrReceiverAuthorizerMismatch { + t.Fatalf("expected ErrReceiverAuthorizerMismatch, got %v", err) + } +} + +// TestBuildVerifyExtra_FlatShape pins the wire shape of the verify response. +// Verify responses return a flat extra (channelId, balance, totalClaimed, +// withdrawRequestedAt, refundNonce). If the facilitator wraps these under +// `channelState`, the server falls back to "0" for balance/totalClaimed and +// silently corrupts its tracked channel record. +// The downstream symptom is `invalid_batch_settlement_evm_refund_no_balance` at refund +// time because `channel.balance == 0 < chargedCumulativeAmount`. +func TestBuildVerifyExtra_FlatShape(t *testing.T) { + state := &batchsettlement.ChannelState{ + Balance: big.NewInt(900), + TotalClaimed: big.NewInt(100), + WithdrawRequestedAt: 42, + RefundNonce: big.NewInt(7), + } + out := BuildVerifyExtra("0xabc", state) + + if _, hasNested := out["channelState"]; hasNested { + t.Fatalf("verify extra must NOT wrap fields under `channelState`, got %+v", out) + } + if _, hasCharged := out["chargedCumulativeAmount"]; hasCharged { + t.Fatalf("verify extra must NOT include chargedCumulativeAmount (server-only field), got %+v", out) + } + if out["channelId"] != "0xabc" { + t.Fatalf("channelId = %v", out["channelId"]) + } + if out["balance"] != "900" { + t.Fatalf("balance = %v", out["balance"]) + } + if out["totalClaimed"] != "100" { + t.Fatalf("totalClaimed = %v", out["totalClaimed"]) + } + if out["withdrawRequestedAt"] != 42 { + t.Fatalf("withdrawRequestedAt = %v", out["withdrawRequestedAt"]) + } + if out["refundNonce"] != "7" { + t.Fatalf("refundNonce = %v", out["refundNonce"]) + } +} + +// TestBuildSettleExtra_NestedShapeNoChargedCumulative pins the wire shape of +// the settle response. It returns a nested `channelState` containing +// channelId/balance/totalClaimed/withdrawRequestedAt/refundNonce, but NOT +// chargedCumulativeAmount, which the resource server's +// `enrichSettlementResponse` hook adds via additive merge afterwards. Emitting +// `chargedCumulativeAmount` from the facilitator triggers the enrichment policy +// to reject the duplicate field, which suppresses the merge and breaks +// downstream state. +func TestBuildSettleExtra_NestedShapeNoChargedCumulative(t *testing.T) { + state := &batchsettlement.ChannelState{ + Balance: big.NewInt(900), + TotalClaimed: big.NewInt(100), + WithdrawRequestedAt: 42, + RefundNonce: big.NewInt(7), + } + out := BuildSettleExtra("0xabc", state) + + cs, ok := out["channelState"].(map[string]interface{}) + if !ok { + t.Fatalf("settle extra must wrap fields under `channelState`, got %+v", out) + } + if _, hasCharged := cs["chargedCumulativeAmount"]; hasCharged { + t.Fatalf("settle extra MUST NOT include chargedCumulativeAmount (server enrichSettlementResponse adds it), got %+v", cs) + } + if cs["channelId"] != "0xabc" { + t.Fatalf("channelId = %v", cs["channelId"]) + } + if cs["balance"] != "900" { + t.Fatalf("balance = %v", cs["balance"]) + } + if cs["totalClaimed"] != "100" { + t.Fatalf("totalClaimed = %v", cs["totalClaimed"]) + } + if cs["withdrawRequestedAt"] != 42 { + t.Fatalf("withdrawRequestedAt = %v", cs["withdrawRequestedAt"]) + } + if cs["refundNonce"] != "7" { + t.Fatalf("refundNonce = %v", cs["refundNonce"]) + } +} + +func TestErc3009AuthorizationTimeInvalidReason_Valid(t *testing.T) { + now := time.Now().Unix() + r := Erc3009AuthorizationTimeInvalidReason(big.NewInt(now-60), big.NewInt(now+3600)) + if r != "" { + t.Fatalf("expected valid, got %q", r) + } +} + +func TestErc3009AuthorizationTimeInvalidReason_Expired(t *testing.T) { + now := time.Now().Unix() + r := Erc3009AuthorizationTimeInvalidReason(big.NewInt(now-3600), big.NewInt(now-60)) + if r != ErrValidBeforeExpired { + t.Fatalf("expected expired, got %q", r) + } +} + +func TestErc3009AuthorizationTimeInvalidReason_FutureValidAfter(t *testing.T) { + now := time.Now().Unix() + r := Erc3009AuthorizationTimeInvalidReason(big.NewInt(now+3600), big.NewInt(now+7200)) + if r != ErrValidAfterInFuture { + t.Fatalf("expected future, got %q", r) + } +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/voucher.go b/go/mechanisms/evm/batch-settlement/facilitator/voucher.go new file mode 100644 index 0000000000..ca5440eda3 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/voucher.go @@ -0,0 +1,115 @@ +package facilitator + +import ( + "context" + "fmt" + "math/big" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// VerifyVoucher verifies a batched voucher-only payload. +// Checks voucher signature, reads onchain channel state, validates cumulative ceiling. +func VerifyVoucher( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + payload *batchsettlement.BatchSettlementVoucherPayload, + requirements types.PaymentRequirements, + channelConfig batchsettlement.ChannelConfig, +) (*x402.VerifyResponse, error) { + return verifyVoucherFields(ctx, signer, &payload.Voucher, channelConfig, requirements, false) +} + +// VerifyRefundVoucher verifies a cooperative-refund payload's voucher. +// The voucher is zero-charge: maxClaimableAmount == chargedCumulativeAmount, +// which on a fresh channel may equal totalClaimed exactly. +func VerifyRefundVoucher( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + payload *batchsettlement.BatchSettlementRefundPayload, + requirements types.PaymentRequirements, + channelConfig batchsettlement.ChannelConfig, +) (*x402.VerifyResponse, error) { + return verifyVoucherFields(ctx, signer, &payload.Voucher, channelConfig, requirements, true) +} + +func verifyVoucherFields( + ctx context.Context, + signer evm.FacilitatorEvmSigner, + voucher *batchsettlement.BatchSettlementVoucherFields, + channelConfig batchsettlement.ChannelConfig, + requirements types.PaymentRequirements, + isRefund bool, +) (*x402.VerifyResponse, error) { + if err := ValidateChannelConfig(channelConfig, voucher.ChannelId, requirements); err != nil { + return nil, err + } + + chainId, err := signer.GetChainID(ctx) + if err != nil { + return nil, x402.NewVerifyError(ErrChannelStateReadFailed, "", fmt.Sprintf("failed to get chain ID: %s", err)) + } + + valid, err := VerifyBatchedVoucherTypedData( + ctx, signer, + voucher.ChannelId, + voucher.MaxClaimableAmount, + channelConfig.PayerAuthorizer, + channelConfig.Payer, + voucher.Signature, + chainId, + ) + if err != nil { + return nil, x402.NewVerifyError(ErrVoucherSignatureInvalid, channelConfig.Payer, + fmt.Sprintf("voucher signature verification failed: %s", err)) + } + if !valid { + return nil, x402.NewVerifyError(ErrVoucherSignatureInvalid, channelConfig.Payer, + "voucher signature is invalid") + } + + state, err := ReadChannelState(ctx, signer, voucher.ChannelId) + if err != nil { + return nil, x402.NewVerifyError(ErrChannelStateReadFailed, channelConfig.Payer, + fmt.Sprintf("failed to read channel state: %s", err)) + } + + // A non-existent or fully-drained channel reports balance==0 onchain + if state.Balance.Sign() == 0 { + return nil, x402.NewVerifyError(ErrChannelNotFound, channelConfig.Payer, + fmt.Sprintf("channel %s not found or fully drained (balance=0)", voucher.ChannelId)) + } + + maxClaimable, ok := new(big.Int).SetString(voucher.MaxClaimableAmount, 10) + if !ok { + return nil, x402.NewVerifyError(ErrInvalidVoucherPayload, channelConfig.Payer, + "invalid maxClaimableAmount") + } + + // Refund vouchers are zero-charge and may equal totalClaimed; non-refund + // vouchers must strictly increase claimable above totalClaimed. + belowClaimed := false + if isRefund { + belowClaimed = maxClaimable.Cmp(state.TotalClaimed) < 0 + } else { + belowClaimed = maxClaimable.Cmp(state.TotalClaimed) <= 0 + } + if belowClaimed { + return nil, x402.NewVerifyError(ErrMaxClaimableTooLow, channelConfig.Payer, + fmt.Sprintf("maxClaimableAmount %s is below totalClaimed %s", maxClaimable.String(), state.TotalClaimed.String())) + } + + if maxClaimable.Cmp(state.Balance) > 0 { + return nil, x402.NewVerifyError(ErrMaxClaimableExceedsBal, channelConfig.Payer, + fmt.Sprintf("maxClaimableAmount %s exceeds balance %s", maxClaimable.String(), state.Balance.String())) + } + + return &x402.VerifyResponse{ + IsValid: true, + Payer: channelConfig.Payer, + Extra: BuildVerifyExtra(voucher.ChannelId, state), + }, nil +} diff --git a/go/mechanisms/evm/batch-settlement/facilitator/voucher_typed_test.go b/go/mechanisms/evm/batch-settlement/facilitator/voucher_typed_test.go new file mode 100644 index 0000000000..c8d270e942 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/facilitator/voucher_typed_test.go @@ -0,0 +1,96 @@ +package facilitator + +import ( + "context" + "math/big" + "strings" + "testing" +) + +func chainID() *big.Int { return big.NewInt(8453) } + +func TestVerifyBatchedVoucherTypedData_BadMaxClaimable(t *testing.T) { + signer := &fakeFacilitatorSigner{} + _, err := VerifyBatchedVoucherTypedData(context.Background(), signer, + "0xabc", "not-a-number", "0xauth", "0xpayer", "0xdead", chainID()) + if err == nil { + t.Fatal("expected error") + } +} + +func TestVerifyBatchedVoucherTypedData_BadChannelId(t *testing.T) { + signer := &fakeFacilitatorSigner{} + _, err := VerifyBatchedVoucherTypedData(context.Background(), signer, + "not-hex", "100", "0xauth", "0xpayer", "0xdead", chainID()) + if err == nil { + t.Fatal("expected error") + } +} + +func TestVerifyBatchedVoucherTypedData_BadSignature(t *testing.T) { + signer := &fakeFacilitatorSigner{} + _, err := VerifyBatchedVoucherTypedData(context.Background(), signer, + "0xabcd", "100", "0xauth", "0xpayer", "not-hex", chainID()) + if err == nil { + t.Fatal("expected error") + } +} + +func TestVerifyBatchedVoucherTypedData_RoutesToPayerAuthorizer(t *testing.T) { + signer := &fakeFacilitatorSigner{ + verifyTypedData: func(_ string) (bool, error) { return true, nil }, + } + ok, err := VerifyBatchedVoucherTypedData(context.Background(), signer, + "0xabcd", "100", + "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", // payerAuthorizer + "0xbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb", // payer + "0xdead", chainID()) + if err != nil || !ok { + t.Fatalf("ok=%v err=%v", ok, err) + } + if signer.verifyCalls != 1 || !strings.EqualFold(signer.verifyAddrs[0], "0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") { + t.Fatalf("called with %+v", signer.verifyAddrs) + } +} + +func TestVerifyBatchedVoucherTypedData_RoutesToPayerWhenAuthorizerZero(t *testing.T) { + signer := &fakeFacilitatorSigner{ + verifyTypedData: func(_ string) (bool, error) { return true, nil }, + } + _, err := VerifyBatchedVoucherTypedData(context.Background(), signer, + "0xabcd", "100", + zeroAddress, + "0xpayer", + "0xdead", chainID()) + if err != nil { + t.Fatalf("err: %v", err) + } + if signer.verifyCalls != 1 || signer.verifyAddrs[0] != "0xpayer" { + t.Fatalf("called with %+v", signer.verifyAddrs) + } +} + +func TestVerifyBatchedVoucherTypedData_RoutesToPayerWhenAuthorizerEmpty(t *testing.T) { + signer := &fakeFacilitatorSigner{ + verifyTypedData: func(_ string) (bool, error) { return true, nil }, + } + _, err := VerifyBatchedVoucherTypedData(context.Background(), signer, + "0xabcd", "100", "", "0xpayer", "0xdead", chainID()) + if err != nil { + t.Fatalf("err: %v", err) + } + if signer.verifyAddrs[0] != "0xpayer" { + t.Fatalf("called with %+v", signer.verifyAddrs) + } +} + +func TestReadChannelState_RpcFailure(t *testing.T) { + signer := &fakeFacilitatorSigner{} + _, err := ReadChannelState(context.Background(), signer, "0xabc") + if err == nil { + t.Fatal("expected RPC error") + } + if !strings.Contains(err.Error(), "multicall failed") { + t.Fatalf("got %v", err) + } +} diff --git a/go/mechanisms/evm/batch-settlement/server/channel_manager.go b/go/mechanisms/evm/batch-settlement/server/channel_manager.go new file mode 100644 index 0000000000..192e4a4f60 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/server/channel_manager.go @@ -0,0 +1,879 @@ +package server + +import ( + "context" + "encoding/json" + "fmt" + "log" + "math/big" + "strings" + "sync" + "time" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +// ChannelManagerConfig wires the channel manager to its dependencies. +// +// Receiver and Token are required: the manager calls +// `settle(receiver, token)` directly, so storage may be empty when settle() +// fires, for example immediately after a flush. +type ChannelManagerConfig struct { + Scheme *BatchSettlementEvmScheme + Facilitator x402.FacilitatorClient + Receiver string + Token string + Network x402.Network +} + +// AutoSettlementContext is the policy context passed to caller-provided +// claim/settle/refund selectors. +type AutoSettlementContext struct { + Now int64 + LastClaimTime int64 + LastSettleTime int64 + PendingSettle bool +} + +// ClaimChannelSelector picks the channel set the manager should consider for +// claiming on each pass. Returning a subset of `channels` is the supported way +// to express custom claim policy (e.g. only channels with non-trivial pending +// amounts). +type ClaimChannelSelector func(channels []*ChannelSession, ctx AutoSettlementContext) ([]*ChannelSession, error) + +// ShouldSettleFunc decides whether a settle pass should fire for this tick. +// Return false to skip; the next interval will re-evaluate. +type ShouldSettleFunc func(ctx AutoSettlementContext) (bool, error) + +// RefundChannelSelector picks idle channels for cooperative refund. +type RefundChannelSelector func(channels []*ChannelSession, ctx AutoSettlementContext) ([]*ChannelSession, error) + +// ClaimOptions tunes a one-shot Claim call. +type ClaimOptions struct { + // MaxClaimsPerBatch caps the number of vouchers per facilitator claim tx. + // Defaults to 100. + MaxClaimsPerBatch int + // IdleSecs filters out channels that received a request within the last + // `IdleSecs` seconds. Zero means "no idle filter". + IdleSecs int + // SelectClaimChannels narrows the channel set considered for claiming. + SelectClaimChannels ClaimChannelSelector +} + +// AutoSettlementConfig configures interval-driven auto claim/settle/refund. +// +// Each *IntervalSecs schedules an independent timer; passing zero leaves that +// job disabled. Selector callbacks let callers express custom claim/refund +// policy (e.g. claim only after a withdrawal trigger, refund only stale +// channels). +type AutoSettlementConfig struct { + ClaimIntervalSecs int + SettleIntervalSecs int + RefundIntervalSecs int + MaxClaimsPerBatch int + SelectClaimChannels ClaimChannelSelector + ShouldSettle ShouldSettleFunc + SelectRefundChannels RefundChannelSelector + OnClaim func(ClaimResult) + OnSettle func(SettleResult) + OnRefund func(RefundResult) + OnError func(error) +} + +// ClaimResult is one batch worth of claim submission. +type ClaimResult struct { + Vouchers int + Transaction string +} + +// SettleResult is one settle transaction. +type SettleResult struct { + Transaction string +} + +// RefundResult is one cooperative refund transaction (one channel). +// +// Each refunded channel returns one result. +type RefundResult struct { + Channel string + Transaction string +} + +type autoJob string + +const ( + autoJobClaim autoJob = "claim" + autoJobSettle autoJob = "settle" + autoJobRefund autoJob = "refund" +) + +// autoJobPriority orders the queue: claim drains before settle drains before +// refund. +var autoJobPriority = []autoJob{autoJobClaim, autoJobSettle, autoJobRefund} + +// BatchSettlementChannelManager handles auto-settlement of batched payment channels. +// Provides one-shot operations (Claim, Settle, ClaimAndSettle, Refund, +// RefundIdleChannels) and an interval runner via Start/Stop. +type BatchSettlementChannelManager struct { + scheme *BatchSettlementEvmScheme + facilitator x402.FacilitatorClient + receiver string + token string + network x402.Network + + mu sync.Mutex + timers map[autoJob]*time.Ticker + stopCh chan struct{} + wg sync.WaitGroup + autoSettleConfig AutoSettlementConfig + running bool + lastClaimTime int64 + lastSettleTime int64 + pendingSettle bool + pendingJobs map[autoJob]struct{} + pendingJobsCh chan struct{} +} + +// NewBatchSettlementChannelManager creates a new channel manager. +func NewBatchSettlementChannelManager(config ChannelManagerConfig) *BatchSettlementChannelManager { + return &BatchSettlementChannelManager{ + scheme: config.Scheme, + facilitator: config.Facilitator, + receiver: config.Receiver, + token: config.Token, + network: config.Network, + } +} + +// hasLivePendingRequest returns true when the channel currently has a +// non-expired payer request reservation. +func hasLivePendingRequest(s *ChannelSession, nowMs int64) bool { + return s != nil && s.PendingRequest != nil && s.PendingRequest.ExpiresAt > nowMs +} + +// formatFacilitatorFailure renders a SettleResponse error consistently across +// claim/settle/refund operations. +func formatFacilitatorFailure(operation string, resp *x402.SettleResponse) string { + if resp == nil { + return fmt.Sprintf("%s failed: nil response", operation) + } + reason := resp.ErrorReason + if reason == "" { + reason = "unknown" + } + return fmt.Sprintf("%s failed: %s — %s", operation, reason, resp.ErrorMessage) +} + +// ----- One-shot operations --------------------------------------------------- + +// GetClaimableVouchersOpts filters claimable vouchers by idle time. +type GetClaimableVouchersOpts struct { + IdleSecs int +} + +// GetClaimableVouchers returns voucher claims ready for onchain settlement. +// Skips entries whose `chargedCumulativeAmount` does not exceed `totalClaimed`. +func (m *BatchSettlementChannelManager) GetClaimableVouchers(opts *GetClaimableVouchersOpts) ([]batchsettlement.BatchSettlementVoucherClaim, error) { + channels, err := m.scheme.storage.List() + if err != nil { + return nil, err + } + idleSecs := 0 + if opts != nil { + idleSecs = opts.IdleSecs + } + return m.collectClaimsFromChannels(channels, idleSecs), nil +} + +// GetWithdrawalPendingSessions returns sessions that have a pending payer-initiated +// withdrawal (withdrawRequestedAt > 0). +func (m *BatchSettlementChannelManager) GetWithdrawalPendingSessions() ([]*ChannelSession, error) { + channels, err := m.scheme.storage.List() + if err != nil { + return nil, err + } + out := make([]*ChannelSession, 0, len(channels)) + for _, c := range channels { + if c.WithdrawRequestedAt > 0 { + out = append(out, c) + } + } + return out, nil +} + +// Claim collects claimable vouchers and submits them in batches. +func (m *BatchSettlementChannelManager) Claim(ctx context.Context, opts *ClaimOptions) ([]ClaimResult, error) { + resolved := normalizeClaimOptions(opts) + channels, err := m.selectClaimTargets(resolved.SelectClaimChannels) + if err != nil { + return nil, err + } + return m.claimFromChannels(ctx, channels, resolved.MaxClaimsPerBatch, resolved.IdleSecs) +} + +// Settle transfers claimed funds to the receiver via a `settle(receiver, token)` call. +func (m *BatchSettlementChannelManager) Settle(ctx context.Context) (*SettleResult, error) { + payload := m.buildSettlePaymentPayloadMap() + resp, err := m.facilitatorSettle(ctx, payload) + if err != nil { + return nil, err + } + if !resp.Success { + return nil, fmt.Errorf("%s", formatFacilitatorFailure("Settle", resp)) + } + m.mu.Lock() + m.pendingSettle = false + m.mu.Unlock() + return &SettleResult{Transaction: resp.Transaction}, nil +} + +// ClaimAndSettle claims any eligible vouchers, then settles when claims fired. +func (m *BatchSettlementChannelManager) ClaimAndSettle(ctx context.Context, opts *ClaimOptions) ([]ClaimResult, *SettleResult, error) { + claims, err := m.Claim(ctx, opts) + if err != nil { + return nil, nil, err + } + if len(claims) == 0 { + return claims, nil, nil + } + settle, err := m.Settle(ctx) + if err != nil { + return claims, nil, err + } + return claims, settle, nil +} + +// Refund refunds the listed channels. Channels with a live in-flight request +// reservation are skipped. Pass an empty slice to refund every stored channel. +func (m *BatchSettlementChannelManager) Refund(ctx context.Context, channelIds []string) ([]RefundResult, error) { + channels, err := m.scheme.storage.List() + if err != nil { + return nil, err + } + now := time.Now().UnixMilli() + var targets []*ChannelSession + if len(channelIds) == 0 { + targets = channels + } else { + want := make(map[string]struct{}, len(channelIds)) + for _, id := range channelIds { + want[strings.ToLower(id)] = struct{}{} + } + for _, c := range channels { + if _, ok := want[strings.ToLower(c.ChannelId)]; ok { + targets = append(targets, c) + } + } + } + live := make([]*ChannelSession, 0, len(targets)) + for _, c := range targets { + if !hasLivePendingRequest(c, now) { + live = append(live, c) + } + } + if len(live) == 0 { + return nil, nil + } + return m.refundChannels(ctx, live) +} + +// RefundIdleChannels cooperatively refunds channels that have been idle for at +// least `idleSecs` seconds and still hold a non-zero balance. +func (m *BatchSettlementChannelManager) RefundIdleChannels(ctx context.Context, idleSecs int) ([]RefundResult, error) { + channels, err := m.scheme.storage.List() + if err != nil { + return nil, err + } + idle := getIdleChannelsForRefund(channels, idleSecs) + if len(idle) == 0 { + return nil, nil + } + return m.refundChannels(ctx, idle) +} + +// ----- Auto-settlement loop -------------------------------------------------- + +// Start begins auto-settlement with the given configuration. Each non-zero +// *IntervalSecs schedules an independent timer; jobs are queued and drained in +// {claim, settle, refund} priority. +func (m *BatchSettlementChannelManager) Start(config AutoSettlementConfig) { + m.mu.Lock() + if m.running { + m.mu.Unlock() + return + } + now := time.Now().UnixMilli() + m.lastClaimTime = now + m.lastSettleTime = now + m.running = true + m.autoSettleConfig = config + m.timers = make(map[autoJob]*time.Ticker) + m.stopCh = make(chan struct{}) + m.pendingJobs = make(map[autoJob]struct{}) + m.pendingJobsCh = make(chan struct{}, 1) + m.mu.Unlock() + + m.startAutoTimer(autoJobClaim, config.ClaimIntervalSecs) + m.startAutoTimer(autoJobSettle, config.SettleIntervalSecs) + m.startAutoTimer(autoJobRefund, config.RefundIntervalSecs) + + m.wg.Add(1) + go m.drainLoop() +} + +// Stop halts auto-settlement. When opts.Flush is true, runs a final +// ClaimAndSettle before returning. +type StopOptions struct { + Flush bool +} + +func (m *BatchSettlementChannelManager) Stop(ctx context.Context, opts *StopOptions) error { + m.mu.Lock() + if !m.running { + m.mu.Unlock() + return nil + } + m.running = false + for _, t := range m.timers { + t.Stop() + } + m.timers = nil + m.pendingJobs = nil + close(m.stopCh) + m.mu.Unlock() + + m.wg.Wait() + + if opts != nil && opts.Flush { + _, _, err := m.ClaimAndSettle(ctx, &ClaimOptions{ + MaxClaimsPerBatch: m.autoSettleConfig.MaxClaimsPerBatch, + SelectClaimChannels: m.autoSettleConfig.SelectClaimChannels, + }) + return err + } + return nil +} + +func (m *BatchSettlementChannelManager) startAutoTimer(job autoJob, intervalSecs int) { + if intervalSecs <= 0 { + return + } + ticker := time.NewTicker(time.Duration(intervalSecs) * time.Second) + m.mu.Lock() + m.timers[job] = ticker + m.mu.Unlock() + + m.wg.Add(1) + go func() { + defer m.wg.Done() + for { + select { + case <-ticker.C: + m.enqueueJob(job) + case <-m.stopCh: + return + } + } + }() +} + +func (m *BatchSettlementChannelManager) enqueueJob(job autoJob) { + m.mu.Lock() + if !m.running { + m.mu.Unlock() + return + } + if m.pendingJobs == nil { + m.pendingJobs = make(map[autoJob]struct{}) + } + m.pendingJobs[job] = struct{}{} + m.mu.Unlock() + + select { + case m.pendingJobsCh <- struct{}{}: + default: + // drain loop already has a wakeup pending + } +} + +func (m *BatchSettlementChannelManager) drainLoop() { + defer m.wg.Done() + for { + select { + case <-m.stopCh: + return + case <-m.pendingJobsCh: + for { + job, ok := m.popNextPendingJob() + if !ok { + break + } + m.runAutoJob(job) + } + } + } +} + +func (m *BatchSettlementChannelManager) popNextPendingJob() (autoJob, bool) { + m.mu.Lock() + defer m.mu.Unlock() + if !m.running || len(m.pendingJobs) == 0 { + return "", false + } + for _, j := range autoJobPriority { + if _, ok := m.pendingJobs[j]; ok { + delete(m.pendingJobs, j) + return j, true + } + } + return "", false +} + +func (m *BatchSettlementChannelManager) runAutoJob(job autoJob) { + ctx := context.Background() + switch job { + case autoJobClaim: + m.runClaimJob(ctx) + case autoJobSettle: + m.runSettleJob(ctx) + case autoJobRefund: + m.runRefundJob(ctx) + } +} + +func (m *BatchSettlementChannelManager) runClaimJob(ctx context.Context) { + cfg := m.snapshotAutoSettlementConfig() + results, err := m.Claim(ctx, &ClaimOptions{ + MaxClaimsPerBatch: cfg.MaxClaimsPerBatch, + SelectClaimChannels: cfg.SelectClaimChannels, + }) + if err != nil { + if cfg.OnError != nil { + cfg.OnError(fmt.Errorf("auto-claim: %w", err)) + } + return + } + m.mu.Lock() + m.lastClaimTime = time.Now().UnixMilli() + m.mu.Unlock() + for _, r := range results { + if cfg.OnClaim != nil { + cfg.OnClaim(r) + } + } +} + +func (m *BatchSettlementChannelManager) runSettleJob(ctx context.Context) { + cfg := m.snapshotAutoSettlementConfig() + autoCtx := m.buildAutoSettlementContext(time.Now().UnixMilli()) + if !autoCtx.PendingSettle { + return + } + if cfg.ShouldSettle != nil { + ok, err := cfg.ShouldSettle(autoCtx) + if err != nil { + if cfg.OnError != nil { + cfg.OnError(fmt.Errorf("auto-settle shouldSettle: %w", err)) + } + return + } + if !ok { + return + } + } + result, err := m.Settle(ctx) + if err != nil { + if cfg.OnError != nil { + cfg.OnError(fmt.Errorf("auto-settle: %w", err)) + } + return + } + m.mu.Lock() + m.lastSettleTime = time.Now().UnixMilli() + m.mu.Unlock() + if result != nil && cfg.OnSettle != nil { + cfg.OnSettle(*result) + } +} + +func (m *BatchSettlementChannelManager) runRefundJob(ctx context.Context) { + cfg := m.snapshotAutoSettlementConfig() + if cfg.SelectRefundChannels == nil { + return + } + channels, err := m.scheme.storage.List() + if err != nil { + if cfg.OnError != nil { + cfg.OnError(fmt.Errorf("auto-refund list: %w", err)) + } + return + } + autoCtx := m.buildAutoSettlementContext(time.Now().UnixMilli()) + targets, err := cfg.SelectRefundChannels(channels, autoCtx) + if err != nil { + if cfg.OnError != nil { + cfg.OnError(fmt.Errorf("auto-refund select: %w", err)) + } + return + } + results, err := m.refundChannels(ctx, targets) + if err != nil { + if cfg.OnError != nil { + cfg.OnError(fmt.Errorf("auto-refund: %w", err)) + } + return + } + for _, r := range results { + if cfg.OnRefund != nil { + cfg.OnRefund(r) + } + } +} + +func (m *BatchSettlementChannelManager) snapshotAutoSettlementConfig() AutoSettlementConfig { + m.mu.Lock() + defer m.mu.Unlock() + return m.autoSettleConfig +} + +func (m *BatchSettlementChannelManager) buildAutoSettlementContext(nowMs int64) AutoSettlementContext { + m.mu.Lock() + defer m.mu.Unlock() + return AutoSettlementContext{ + Now: nowMs, + LastClaimTime: m.lastClaimTime, + LastSettleTime: m.lastSettleTime, + PendingSettle: m.pendingSettle, + } +} + +// ----- internals -------------------------------------------------------------- + +type resolvedClaimOptions struct { + MaxClaimsPerBatch int + IdleSecs int + SelectClaimChannels ClaimChannelSelector +} + +func normalizeClaimOptions(opts *ClaimOptions) resolvedClaimOptions { + out := resolvedClaimOptions{MaxClaimsPerBatch: 100} + if opts != nil { + if opts.MaxClaimsPerBatch > 0 { + out.MaxClaimsPerBatch = opts.MaxClaimsPerBatch + } + out.IdleSecs = opts.IdleSecs + out.SelectClaimChannels = opts.SelectClaimChannels + } + return out +} + +func (m *BatchSettlementChannelManager) selectClaimTargets(selector ClaimChannelSelector) ([]*ChannelSession, error) { + channels, err := m.scheme.storage.List() + if err != nil { + return nil, err + } + if selector == nil { + return channels, nil + } + autoCtx := m.buildAutoSettlementContext(time.Now().UnixMilli()) + out, err := selector(channels, autoCtx) + if err != nil { + return nil, fmt.Errorf("selectClaimChannels: %w", err) + } + return out, nil +} + +func (m *BatchSettlementChannelManager) collectClaimsFromChannels(channels []*ChannelSession, idleSecs int) []batchsettlement.BatchSettlementVoucherClaim { + now := time.Now().UnixMilli() + out := make([]batchsettlement.BatchSettlementVoucherClaim, 0, len(channels)) + for _, c := range channels { + charged, _ := new(big.Int).SetString(c.ChargedCumulativeAmount, 10) + claimed, _ := new(big.Int).SetString(c.TotalClaimed, 10) + if charged == nil || claimed == nil || charged.Cmp(claimed) <= 0 { + continue + } + if idleSecs > 0 { + idleMs := now - c.LastRequestTimestamp + if idleMs < int64(idleSecs)*1000 { + continue + } + } + out = append(out, batchsettlement.BatchSettlementVoucherClaim{ + Voucher: struct { + Channel batchsettlement.ChannelConfig `json:"channel"` + MaxClaimableAmount string `json:"maxClaimableAmount"` + }{ + Channel: c.ChannelConfig, + MaxClaimableAmount: c.SignedMaxClaimable, + }, + Signature: c.Signature, + TotalClaimed: c.ChargedCumulativeAmount, + }) + } + return out +} + +func (m *BatchSettlementChannelManager) claimFromChannels( + ctx context.Context, + channels []*ChannelSession, + maxClaimsPerBatch int, + idleSecs int, +) ([]ClaimResult, error) { + all := m.collectClaimsFromChannels(channels, idleSecs) + if len(all) == 0 { + return nil, nil + } + results := make([]ClaimResult, 0) + for i := 0; i < len(all); i += maxClaimsPerBatch { + end := i + maxClaimsPerBatch + if end > len(all) { + end = len(all) + } + batch := all[i:end] + res, err := m.submitClaim(ctx, batch) + if err != nil { + return results, err + } + results = append(results, *res) + if err := m.updateClaimedSessions(batch); err != nil { + log.Printf("[batched] post-claim storage update failed: %v", err) + } + } + if len(results) > 0 { + m.mu.Lock() + m.pendingSettle = true + m.mu.Unlock() + } + return results, nil +} + +// submitClaim sends a single claim batch to the facilitator. +func (m *BatchSettlementChannelManager) submitClaim(ctx context.Context, claims []batchsettlement.BatchSettlementVoucherClaim) (*ClaimResult, error) { + claim := &batchsettlement.BatchSettlementClaimPayload{Type: "claim", Claims: claims} + if m.scheme.receiverAuthorizerSigner != nil { + sig, err := m.scheme.SignClaimBatch(ctx, claims, string(m.network)) + if err != nil { + return nil, fmt.Errorf("sign claim batch: %w", err) + } + claim.ClaimAuthorizerSignature = evm.BytesToHex(sig) + } + resp, err := m.facilitatorSettle(ctx, claim.ToMap()) + if err != nil { + return nil, err + } + if !resp.Success { + return nil, fmt.Errorf("%s", formatFacilitatorFailure("Claim", resp)) + } + return &ClaimResult{Vouchers: len(claims), Transaction: resp.Transaction}, nil +} + +// refundChannels refunds each eligible channel independently and returns one +// RefundResult per successful refund. +func (m *BatchSettlementChannelManager) refundChannels(ctx context.Context, channels []*ChannelSession) ([]RefundResult, error) { + results := make([]RefundResult, 0, len(channels)) + now := time.Now().UnixMilli() + for _, c := range channels { + if hasLivePendingRequest(c, now) { + continue + } + res, err := m.refundChannel(ctx, c) + if err != nil { + return results, err + } + if res != nil { + results = append(results, *res) + } + } + return results, nil +} + +func (m *BatchSettlementChannelManager) refundChannel(ctx context.Context, target *ChannelSession) (*RefundResult, error) { + normalizedId := batchsettlement.NormalizeChannelId(target.ChannelId) + + balance, _ := new(big.Int).SetString(target.Balance, 10) + charged, _ := new(big.Int).SetString(target.ChargedCumulativeAmount, 10) + if balance == nil || charged == nil { + return nil, nil + } + refundAmount := new(big.Int).Sub(balance, charged) + if refundAmount.Sign() <= 0 { + return nil, nil + } + + // Build the outstanding voucher claim that must be settled before the + // refund can move the unclaimed balance. + var claims []batchsettlement.BatchSettlementVoucherClaim + totalClaimedBig, _ := new(big.Int).SetString(target.TotalClaimed, 10) + if charged != nil && totalClaimedBig != nil && charged.Cmp(totalClaimedBig) > 0 { + claims = []batchsettlement.BatchSettlementVoucherClaim{{ + Voucher: struct { + Channel batchsettlement.ChannelConfig `json:"channel"` + MaxClaimableAmount string `json:"maxClaimableAmount"` + }{ + Channel: target.ChannelConfig, + MaxClaimableAmount: target.SignedMaxClaimable, + }, + Signature: target.Signature, + TotalClaimed: target.ChargedCumulativeAmount, + }} + } + + nonce := fmt.Sprintf("%d", target.RefundNonce) + refund := &batchsettlement.BatchSettlementEnrichedRefundPayload{ + Type: "refund", + ChannelConfig: target.ChannelConfig, + Voucher: batchsettlement.BatchSettlementVoucherFields{ + ChannelId: normalizedId, + MaxClaimableAmount: target.SignedMaxClaimable, + Signature: target.Signature, + }, + Amount: refundAmount.String(), + RefundNonce: nonce, + Claims: claims, + } + + if m.scheme.receiverAuthorizerSigner != nil { + authSig, err := m.scheme.SignRefund(ctx, normalizedId, refundAmount.String(), nonce, string(m.network)) + if err != nil { + return nil, fmt.Errorf("sign refund for %s: %w", normalizedId, err) + } + refund.RefundAuthorizerSignature = evm.BytesToHex(authSig) + if len(claims) > 0 { + claimAuthSig, err := m.scheme.SignClaimBatch(ctx, claims, string(m.network)) + if err != nil { + return nil, fmt.Errorf("sign claim batch for %s: %w", normalizedId, err) + } + refund.ClaimAuthorizerSignature = evm.BytesToHex(claimAuthSig) + } + } + + resp, err := m.facilitatorSettle(ctx, refund.ToMap()) + if err != nil { + return nil, fmt.Errorf("refund settle for %s: %w", normalizedId, err) + } + if !resp.Success { + return nil, fmt.Errorf("%s", formatFacilitatorFailure("Refund", resp)) + } + + // Drop the session so it doesn't churn through future refund cycles. + _, _ = m.scheme.storage.UpdateChannel(normalizedId, func(current *ChannelSession) *ChannelSession { + if current == nil { + return current + } + if hasLivePendingRequest(current, time.Now().UnixMilli()) { + return current + } + return nil + }) + + return &RefundResult{Channel: normalizedId, Transaction: resp.Transaction}, nil +} + +// updateClaimedSessions advances each session's TotalClaimed to the just-claimed +// cumulative amount so GetClaimableVouchers stops returning the same channel +// until a fresh voucher pushes ChargedCumulativeAmount higher. +func (m *BatchSettlementChannelManager) updateClaimedSessions(claims []batchsettlement.BatchSettlementVoucherClaim) error { + for _, claim := range claims { + channelId, err := batchsettlement.ComputeChannelId(claim.Voucher.Channel, string(m.network)) + if err != nil { + return fmt.Errorf("compute channel id: %w", err) + } + normalizedId := batchsettlement.NormalizeChannelId(channelId) + claimedAmount, ok := new(big.Int).SetString(claim.TotalClaimed, 10) + if !ok || claimedAmount == nil { + continue + } + _, err = m.scheme.storage.UpdateChannel(normalizedId, func(current *ChannelSession) *ChannelSession { + if current == nil { + return current + } + curClaimed, _ := new(big.Int).SetString(current.TotalClaimed, 10) + if curClaimed != nil && claimedAmount.Cmp(curClaimed) <= 0 { + return current + } + next := *current + next.TotalClaimed = claimedAmount.String() + return &next + }) + if err != nil { + return fmt.Errorf("update session %s: %w", normalizedId, err) + } + } + return nil +} + +// getIdleChannelsForRefund returns channels that have been idle for at least +// `idleSecs` seconds and still hold a non-zero balance. Skips channels with a +// live in-flight request reservation. +// +// Callers wanting "refund all idle channels" should inline this predicate +// inside their SelectRefundChannels callback. +func getIdleChannelsForRefund(channels []*ChannelSession, idleSecs int) []*ChannelSession { + if idleSecs <= 0 { + return nil + } + now := time.Now().UnixMilli() + idleMs := int64(idleSecs) * 1000 + out := make([]*ChannelSession, 0, len(channels)) + for _, c := range channels { + balance, _ := new(big.Int).SetString(c.Balance, 10) + if balance == nil || balance.Sign() == 0 { + continue + } + if hasLivePendingRequest(c, now) { + continue + } + if now-c.LastRequestTimestamp < idleMs { + continue + } + out = append(out, c) + } + return out +} + +// buildSettlePaymentPayloadMap produces the v2 PaymentPayload JSON map for +// `settle(receiver, token)`. The manager passes `(payload, requirements)` to +// the FacilitatorClient as marshaled JSON, so we keep this as a map shape that +// matches `BatchSettlementSettlePayload.ToMap()`. +func (m *BatchSettlementChannelManager) buildSettlePaymentPayloadMap() map[string]interface{} { + settle := &batchsettlement.BatchSettlementSettlePayload{ + Type: "settle", + Receiver: m.receiver, + Token: m.token, + } + return settle.ToMap() +} + +// facilitatorSettle marshals the (payload, requirements) pair this manager uses +// for its claim/settle/refund calls and forwards them to the facilitator. +func (m *BatchSettlementChannelManager) facilitatorSettle(ctx context.Context, payloadMap map[string]interface{}) (*x402.SettleResponse, error) { + payloadBytes, err := json.Marshal(map[string]interface{}{ + "x402Version": 2, + "payload": payloadMap, + "accepted": m.requirementsMap(), + }) + if err != nil { + return nil, fmt.Errorf("marshal payload: %w", err) + } + requirementsBytes, err := json.Marshal(m.requirementsMap()) + if err != nil { + return nil, fmt.Errorf("marshal requirements: %w", err) + } + return m.facilitator.Settle(ctx, payloadBytes, requirementsBytes) +} + +// requirementsMap returns the minimal PaymentRequirements shape used for the +// manager's own facilitator calls. +func (m *BatchSettlementChannelManager) requirementsMap() map[string]interface{} { + return map[string]interface{}{ + "scheme": batchsettlement.SchemeBatched, + "network": string(m.network), + "asset": m.token, + "amount": "0", + "payTo": m.receiver, + "maxTimeoutSeconds": 0, + "extra": map[string]interface{}{}, + } +} diff --git a/go/mechanisms/evm/batch-settlement/server/channel_manager_test.go b/go/mechanisms/evm/batch-settlement/server/channel_manager_test.go new file mode 100644 index 0000000000..d5fbf18cde --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/server/channel_manager_test.go @@ -0,0 +1,702 @@ +package server + +import ( + "context" + "encoding/json" + "errors" + "sync" + "testing" + "time" + + x402 "github.com/x402-foundation/x402/go" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +// fakeFacilitator records Settle/Verify calls and returns canned responses. +type fakeFacilitator struct { + mu sync.Mutex + settleCalls int + settlePayloads []map[string]interface{} + settleResp *x402.SettleResponse + settleErr error + verifyCalls int + verifyResp *x402.VerifyResponse + verifyErr error +} + +func (f *fakeFacilitator) Verify(_ context.Context, _ []byte, _ []byte) (*x402.VerifyResponse, error) { + f.mu.Lock() + defer f.mu.Unlock() + f.verifyCalls++ + if f.verifyResp != nil { + return f.verifyResp, f.verifyErr + } + return &x402.VerifyResponse{IsValid: true}, f.verifyErr +} + +func (f *fakeFacilitator) Settle(_ context.Context, payloadBytes []byte, _ []byte) (*x402.SettleResponse, error) { + f.mu.Lock() + defer f.mu.Unlock() + f.settleCalls++ + var env map[string]interface{} + if json.Unmarshal(payloadBytes, &env) == nil { + if p, ok := env["payload"].(map[string]interface{}); ok { + f.settlePayloads = append(f.settlePayloads, p) + } + } + if f.settleErr != nil { + return nil, f.settleErr + } + if f.settleResp != nil { + return f.settleResp, nil + } + return &x402.SettleResponse{Success: true, Transaction: "0xtx"}, nil +} + +func (f *fakeFacilitator) GetSupported(_ context.Context) (x402.SupportedResponse, error) { + return x402.SupportedResponse{}, nil +} + +func newManager(s *BatchSettlementEvmScheme, f *fakeFacilitator) *BatchSettlementChannelManager { + return NewBatchSettlementChannelManager(ChannelManagerConfig{ + Scheme: s, + Facilitator: f, + Receiver: "0xreceiver", + Token: "0xtoken", + Network: x402.Network("eip155:8453"), + }) +} + +func TestNewBatchSettlementChannelManager(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + f := &fakeFacilitator{} + m := newManager(s, f) + if m == nil { + t.Fatal("expected non-nil manager") + } +} + +func TestClaim_NoClaimableVouchers(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + f := &fakeFacilitator{} + m := newManager(s, f) + results, err := m.Claim(context.Background(), nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if len(results) != 0 || f.settleCalls != 0 { + t.Fatalf("expected no settle calls, got %d", f.settleCalls) + } +} + +func TestClaim_SingleBatch(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.SignedMaxClaimable = "1000" + sess.TotalClaimed = "100" + sess.ChargedCumulativeAmount = "1000" + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + results, err := m.Claim(context.Background(), nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if len(results) != 1 || results[0].Vouchers != 1 || results[0].Transaction != "0xtx" { + t.Fatalf("got %+v", results) + } + if f.settleCalls != 1 { + t.Fatalf("settleCalls = %d", f.settleCalls) + } + if f.settlePayloads[0]["type"] != "claim" { + t.Fatalf("payload = %+v", f.settlePayloads[0]) + } +} + +// Regression: a successful claim must advance session.TotalClaimed in storage so +// that GetClaimableVouchers no longer returns the same channel until a fresh +// voucher pushes ChargedCumulativeAmount higher. Without this fix, every tick +// re-submits the same claim transaction. +func TestClaim_AdvancesTotalClaimedInStorageAfterSuccess(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + // Use a real ChannelConfig so the manager's post-claim storage lookup + // (keyed by ComputeChannelId(claim.Voucher.Channel, network)) hits the + // session we just stored. + cfg := batchsettlement.ChannelConfig{ + Payer: "0xabc1000000000000000000000000000000000001", + PayerAuthorizer: "0xabc1000000000000000000000000000000000001", + Receiver: "0xabc2000000000000000000000000000000000002", + ReceiverAuthorizer: "0xabc3000000000000000000000000000000000003", + Token: "0xabc4000000000000000000000000000000000004", + WithdrawDelay: 900, + Salt: "0x0000000000000000000000000000000000000000000000000000000000000000", + } + channelId, err := batchsettlement.ComputeChannelId(cfg, "eip155:8453") + if err != nil { + t.Fatalf("ComputeChannelId: %v", err) + } + channelId = batchsettlement.NormalizeChannelId(channelId) + + sess := sampleSession(channelId, "1000") + sess.ChannelConfig = cfg + sess.SignedMaxClaimable = "1000" + sess.TotalClaimed = "100" + _ = s.UpdateSession(channelId, sess) + + f := &fakeFacilitator{} + m := &BatchSettlementChannelManager{scheme: s, facilitator: f, network: "eip155:8453"} + + // First claim: storage advances from 100 -> 1000. + if _, err := m.Claim(context.Background(), nil); err != nil { + t.Fatalf("first claim: %v", err) + } + got, _ := s.GetSession(channelId) + if got == nil || got.TotalClaimed != "1000" { + t.Fatalf("expected TotalClaimed=1000 after claim, got %+v", got) + } + + // Second tick should be a no-op — channel no longer claimable. + if _, err := m.Claim(context.Background(), nil); err != nil { + t.Fatalf("second claim: %v", err) + } + if f.settleCalls != 1 { + t.Fatalf("expected 1 facilitator settle call total, got %d (channel was re-claimed)", f.settleCalls) + } +} + +func TestClaim_BatchesAcrossMaxClaimsPerBatch(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + for _, id := range []string{"0xa", "0xb", "0xc"} { + sess := sampleSession(id, "100") + sess.SignedMaxClaimable = "1000" + sess.TotalClaimed = "100" + sess.ChargedCumulativeAmount = "1000" + _ = s.UpdateSession(id, sess) + } + + f := &fakeFacilitator{} + m := newManager(s, f) + results, err := m.Claim(context.Background(), &ClaimOptions{MaxClaimsPerBatch: 2}) + if err != nil { + t.Fatalf("err: %v", err) + } + if f.settleCalls != 2 { + t.Fatalf("expected 2 batches, got %d", f.settleCalls) + } + total := 0 + for _, r := range results { + total += r.Vouchers + } + if total != 3 { + t.Fatalf("expected 3 vouchers across batches, got %d", total) + } +} + +func TestClaim_FacilitatorError(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.SignedMaxClaimable = "1000" + sess.TotalClaimed = "100" + sess.ChargedCumulativeAmount = "1000" + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{settleErr: errors.New("boom")} + m := newManager(s, f) + _, err := m.Claim(context.Background(), nil) + if err == nil { + t.Fatal("expected error") + } +} + +func TestSettle_Success(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.ChannelConfig.Token = "0xtoken" + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + res, err := m.Settle(context.Background()) + if err != nil { + t.Fatalf("err: %v", err) + } + if res == nil || res.Transaction != "0xtx" { + t.Fatalf("got %+v", res) + } + if f.settlePayloads[0]["type"] != "settle" { + t.Fatalf("payload = %+v", f.settlePayloads[0]) + } + if f.settlePayloads[0]["token"] != "0xtoken" { + t.Fatalf("token = %v", f.settlePayloads[0]["token"]) + } +} + +func TestSettle_FacilitatorError(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + f := &fakeFacilitator{settleErr: errors.New("boom")} + m := newManager(s, f) + if _, err := m.Settle(context.Background()); err == nil { + t.Fatal("expected error") + } +} + +func TestRefund_EmptyChannelIdsRefundsAll(t *testing.T) { + // Passing nil/empty refunds every stored channel. + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + f := &fakeFacilitator{} + m := newManager(s, f) + res, err := m.Refund(context.Background(), nil) + if err != nil || res != nil { + t.Fatalf("got res=%+v err=%v", res, err) + } + if f.settleCalls != 0 { + t.Fatalf("settleCalls = %d", f.settleCalls) + } +} + +func TestRefund_SkipsMissingSession(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + f := &fakeFacilitator{} + m := newManager(s, f) + res, _ := m.Refund(context.Background(), []string{"0xnope"}) + if len(res) != 0 { + t.Fatalf("expected empty, got %+v", res) + } + if f.settleCalls != 0 { + t.Fatalf("settleCalls = %d", f.settleCalls) + } +} + +func TestRefund_SkipsZeroRefundAmount(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "500") + sess.Balance = "500" // balance == charged → refund = 0 + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + res, _ := m.Refund(context.Background(), []string{"0xa"}) + if len(res) != 0 { + t.Fatalf("expected empty, got %+v", res) + } + if f.settleCalls != 0 { + t.Fatalf("settleCalls = %d", f.settleCalls) + } +} + +func TestRefund_SkipsMalformedNumbers(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "not-a-number") + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + res, _ := m.Refund(context.Background(), []string{"0xa"}) + if len(res) != 0 { + t.Fatalf("expected empty, got %+v", res) + } +} + +func TestRefund_SuccessDeletesSession(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.Balance = "1000" + sess.ChargedCumulativeAmount = "100" + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + res, err := m.Refund(context.Background(), []string{"0xa"}) + if err != nil { + t.Fatalf("err: %v", err) + } + if len(res) != 1 || res[0].Channel != "0xa" { + t.Fatalf("got %+v", res) + } + if res[0].Transaction != "0xtx" { + t.Fatalf("tx = %s", res[0].Transaction) + } + if f.settlePayloads[0]["type"] != "refund" { + t.Fatalf("payload = %+v", f.settlePayloads[0]) + } + // Session should be deleted. + if got, _ := s.GetSession("0xa"); got != nil { + t.Fatalf("expected session deleted, got %+v", got) + } +} + +func TestRefund_FacilitatorErrorIsReturned(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.Balance = "1000" + sess.ChargedCumulativeAmount = "100" + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{settleErr: errors.New("boom")} + m := newManager(s, f) + res, err := m.Refund(context.Background(), []string{"0xa"}) + if err == nil { + t.Fatal("expected error from facilitator failure") + } + if len(res) != 0 { + t.Fatalf("expected empty results on facilitator error, got %+v", res) + } + // Session must NOT be deleted on failure. + if got, _ := s.GetSession("0xa"); got == nil { + t.Fatal("session unexpectedly deleted after refund error") + } +} + +func TestRefund_WithAuthorizerSignerAttachesSignatures(t *testing.T) { + auth := &mockAuthorizerSigner{address: "0xauth", sig: []byte{0xde, 0xad}} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ + ReceiverAuthorizerSigner: auth, + }) + sess := sampleSession("0xab", "500") + sess.Balance = "1000" + sess.ChargedCumulativeAmount = "500" // > TotalClaimed (100) → claim batch is non-empty + _ = s.UpdateSession("0xab", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + if _, err := m.Refund(context.Background(), []string{"0xab"}); err != nil { + t.Fatalf("err: %v", err) + } + if len(f.settlePayloads) == 0 { + t.Fatalf("expected settle to be called, got %d calls", f.settleCalls) + } + p := f.settlePayloads[0] + if p["refundAuthorizerSignature"] == nil || p["claimAuthorizerSignature"] == nil { + t.Fatalf("missing pre-signed sigs in %+v", p) + } + if auth.calls < 2 { + t.Fatalf("expected SignTypedData called for refund + claim, got %d", auth.calls) + } +} + +func TestRefund_SkipsChannelWithLivePendingRequest(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.Balance = "1000" + sess.ChargedCumulativeAmount = "100" + sess.PendingRequest = &PendingRequest{ + PendingId: "p1", + ExpiresAt: time.Now().Add(time.Minute).UnixMilli(), + } + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + res, err := m.Refund(context.Background(), []string{"0xa"}) + if err != nil { + t.Fatalf("err: %v", err) + } + if len(res) != 0 { + t.Fatalf("expected refund to skip in-flight channel, got %+v", res) + } +} + +func TestClaimAndSettle_PropagatesClaimError(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.SignedMaxClaimable = "1000" + sess.TotalClaimed = "100" + sess.ChargedCumulativeAmount = "1000" + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{settleErr: errors.New("boom")} + m := newManager(s, f) + if _, _, err := m.ClaimAndSettle(context.Background(), nil); err == nil { + t.Fatal("expected error") + } +} + +func TestClaimAndSettle_SettlesAfterClaim(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.SignedMaxClaimable = "1000" + sess.TotalClaimed = "100" + sess.ChargedCumulativeAmount = "1000" + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + claims, settle, err := m.ClaimAndSettle(context.Background(), nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if len(claims) != 1 || claims[0].Transaction != "0xtx" { + t.Fatalf("claims = %+v", claims) + } + if settle == nil || settle.Transaction != "0xtx" { + t.Fatalf("settle = %+v", settle) + } + if f.settleCalls != 2 { + t.Fatalf("expected claim + settle, got %d", f.settleCalls) + } + if f.settlePayloads[0]["type"] != "claim" { + t.Fatalf("first payload = %+v", f.settlePayloads[0]) + } + if f.settlePayloads[1]["type"] != "settle" { + t.Fatalf("second payload = %+v", f.settlePayloads[1]) + } +} + +func TestClaimAndSettle_SkipsSettleWhenNothingClaimed(t *testing.T) { + // No claimable vouchers → claim returns empty, settle should not run. + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + f := &fakeFacilitator{} + m := newManager(s, f) + claims, settle, err := m.ClaimAndSettle(context.Background(), nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if len(claims) != 0 { + t.Fatalf("expected 0 claims, got %d", len(claims)) + } + if settle != nil { + t.Fatalf("expected nil settle, got %+v", settle) + } + if f.settleCalls != 0 { + t.Fatalf("expected no facilitator calls, got %d", f.settleCalls) + } +} + +func TestStop_NotRunningIsNoop(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + f := &fakeFacilitator{} + m := newManager(s, f) + if err := m.Stop(context.Background(), nil); err != nil { + t.Fatalf("err: %v", err) + } +} + +func TestStartStop_Idempotent(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + f := &fakeFacilitator{} + m := newManager(s, f) + + // Long intervals so the goroutines never fire while we're testing. + m.Start(AutoSettlementConfig{ClaimIntervalSecs: 3600, SettleIntervalSecs: 3600}) + m.Start(AutoSettlementConfig{ClaimIntervalSecs: 3600}) // second Start is a no-op + + if err := m.Stop(context.Background(), nil); err != nil { + t.Fatalf("stop: %v", err) + } + if err := m.Stop(context.Background(), nil); err != nil { + t.Fatalf("second stop: %v", err) + } +} + +func TestStop_FlushTriggersClaimAndSettle(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.SignedMaxClaimable = "1000" + sess.TotalClaimed = "100" + sess.ChargedCumulativeAmount = "1000" + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + m.Start(AutoSettlementConfig{ClaimIntervalSecs: 3600}) + if err := m.Stop(context.Background(), &StopOptions{Flush: true}); err != nil { + t.Fatalf("stop: %v", err) + } + if f.settleCalls != 2 { + t.Fatalf("expected claim + settle on flush, got %d", f.settleCalls) + } +} + +// runClaimJob, runSettleJob, runRefundJob are private but covered through the +// public auto-loop here. We seed lastClaimTime/pendingSettle directly via the +// runtime helpers to avoid needing a full timer dance. +func TestRunClaimJob_FiresOnClaim(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.SignedMaxClaimable = "1000" + sess.TotalClaimed = "100" + sess.ChargedCumulativeAmount = "1000" + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + var claims []ClaimResult + m.autoSettleConfig = AutoSettlementConfig{ + OnClaim: func(r ClaimResult) { claims = append(claims, r) }, + } + m.runClaimJob(context.Background()) + if f.settleCalls != 1 { + t.Fatalf("expected 1 claim, got %d", f.settleCalls) + } + if len(claims) != 1 { + t.Fatalf("expected 1 OnClaim, got %d", len(claims)) + } + m.mu.Lock() + pendingSettle := m.pendingSettle + m.mu.Unlock() + if !pendingSettle { + t.Fatal("expected pendingSettle = true after claim") + } +} + +func TestRunSettleJob_NoOpUnlessPendingSettle(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + f := &fakeFacilitator{} + m := newManager(s, f) + m.autoSettleConfig = AutoSettlementConfig{} + // pendingSettle = false → runSettleJob is a no-op. + m.runSettleJob(context.Background()) + if f.settleCalls != 0 { + t.Fatalf("expected no settle when nothing pending, got %d", f.settleCalls) + } +} + +func TestRunSettleJob_FiresOnSettle(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + f := &fakeFacilitator{} + m := newManager(s, f) + var settles []SettleResult + m.autoSettleConfig = AutoSettlementConfig{ + OnSettle: func(r SettleResult) { settles = append(settles, r) }, + } + m.mu.Lock() + m.pendingSettle = true + m.mu.Unlock() + m.runSettleJob(context.Background()) + if f.settleCalls != 1 { + t.Fatalf("expected 1 settle, got %d", f.settleCalls) + } + if len(settles) != 1 { + t.Fatalf("expected OnSettle, got %d", len(settles)) + } +} + +func TestRunSettleJob_ShouldSettleFalseSkips(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + f := &fakeFacilitator{} + m := newManager(s, f) + m.autoSettleConfig = AutoSettlementConfig{ + ShouldSettle: func(_ AutoSettlementContext) (bool, error) { return false, nil }, + } + m.mu.Lock() + m.pendingSettle = true + m.mu.Unlock() + m.runSettleJob(context.Background()) + if f.settleCalls != 0 { + t.Fatalf("expected ShouldSettle=false to skip settle, got %d", f.settleCalls) + } +} + +func TestRunRefundJob_UsesSelectRefundChannels(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.Balance = "1000" + sess.ChargedCumulativeAmount = "100" + sess.LastRequestTimestamp = time.Now().Add(-1 * time.Hour).UnixMilli() + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + var refunds []RefundResult + m.autoSettleConfig = AutoSettlementConfig{ + SelectRefundChannels: func(channels []*ChannelSession, _ AutoSettlementContext) ([]*ChannelSession, error) { + return channels, nil + }, + OnRefund: func(r RefundResult) { refunds = append(refunds, r) }, + } + m.runRefundJob(context.Background()) + if len(refunds) != 1 { + t.Fatalf("expected refund callback, got %d", len(refunds)) + } +} + +func TestRunRefundJob_NoOpWithoutSelectRefundChannels(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.Balance = "1000" + sess.ChargedCumulativeAmount = "100" + _ = s.UpdateSession("0xa", sess) + + f := &fakeFacilitator{} + m := newManager(s, f) + m.autoSettleConfig = AutoSettlementConfig{} + m.runRefundJob(context.Background()) + if f.settleCalls != 0 { + t.Fatalf("expected no facilitator calls without selector, got %d", f.settleCalls) + } +} + +func TestGetClaimableVouchers_NoSessions(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + m := newManager(s, &fakeFacilitator{}) + got, err := m.GetClaimableVouchers(nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if len(got) != 0 { + t.Fatalf("expected zero claims, got %d", len(got)) + } +} + +func TestGetClaimableVouchers_FiltersUnclaimed(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "10") + sess.SignedMaxClaimable = "10" + sess.TotalClaimed = "10" + _ = s.UpdateSession("0xa", sess) + m := newManager(s, &fakeFacilitator{}) + got, _ := m.GetClaimableVouchers(nil) + if len(got) != 0 { + t.Fatalf("expected 0, got %d", len(got)) + } +} + +func TestGetClaimableVouchers_ReturnsClaimable(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.SignedMaxClaimable = "1000" + sess.TotalClaimed = "100" + sess.ChargedCumulativeAmount = "1000" + _ = s.UpdateSession("0xa", sess) + m := newManager(s, &fakeFacilitator{}) + got, err := m.GetClaimableVouchers(nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if len(got) != 1 || got[0].Voucher.MaxClaimableAmount != "1000" { + t.Fatalf("got %+v", got) + } +} + +func TestGetClaimableVouchers_FiltersByIdle(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xa", "100") + sess.SignedMaxClaimable = "1000" + sess.TotalClaimed = "100" + sess.ChargedCumulativeAmount = "1000" + sess.LastRequestTimestamp = nowMs() // very recent + _ = s.UpdateSession("0xa", sess) + m := newManager(s, &fakeFacilitator{}) + got, _ := m.GetClaimableVouchers(&GetClaimableVouchersOpts{IdleSecs: 3600}) + if len(got) != 0 { + t.Fatalf("expected idle filter to drop session, got %d", len(got)) + } +} + +func TestGetWithdrawalPendingSessions(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + a := sampleSession("0xa", "10") + b := sampleSession("0xb", "10") + b.WithdrawRequestedAt = 12345 + _ = s.UpdateSession("0xa", a) + _ = s.UpdateSession("0xb", b) + m := newManager(s, &fakeFacilitator{}) + got, err := m.GetWithdrawalPendingSessions() + if err != nil { + t.Fatalf("err: %v", err) + } + if len(got) != 1 || got[0].ChannelId != "0xb" { + t.Fatalf("got %+v", got) + } +} diff --git a/go/mechanisms/evm/batch-settlement/server/file_storage.go b/go/mechanisms/evm/batch-settlement/server/file_storage.go new file mode 100644 index 0000000000..b809966bd2 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/server/file_storage.go @@ -0,0 +1,188 @@ +package server + +import ( + "encoding/json" + "errors" + "fmt" + "os" + "path/filepath" + "sort" + "strings" + + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +// FileChannelStorage is a file-backed SessionStorage. Each session is stored +// as {root}/server/{channelId}.json. CompareAndSet is serialised through an +// exclusive lock file ({channelId}.json.lock) so concurrent writers see the +// loser as a no-op rather than racing. +type FileChannelStorage struct { + root string +} + +// NewFileChannelStorage returns a file-backed server session storage. +func NewFileChannelStorage(opts batchsettlement.FileChannelStorageOptions) *FileChannelStorage { + return &FileChannelStorage{root: opts.Directory} +} + +func (s *FileChannelStorage) filePath(channelId string) string { + return filepath.Join(s.root, "server", strings.ToLower(channelId)+".json") +} + +func (s *FileChannelStorage) Get(channelId string) (*ChannelSession, error) { + out := &ChannelSession{} + ok, err := batchsettlement.ReadJSONFile(s.filePath(channelId), out) + if err != nil { + return nil, err + } + if !ok { + return nil, nil + } + return out, nil +} + +func (s *FileChannelStorage) Set(channelId string, session *ChannelSession) error { + return batchsettlement.WriteJSONAtomic(s.filePath(channelId), session) +} + +func (s *FileChannelStorage) Delete(channelId string) error { + if err := os.Remove(s.filePath(channelId)); err != nil && !batchsettlement.IsNotExist(err) { + return err + } + return nil +} + +func (s *FileChannelStorage) List() ([]*ChannelSession, error) { + dir := filepath.Join(s.root, "server") + entries, err := os.ReadDir(dir) + if err != nil { + if batchsettlement.IsNotExist(err) { + return []*ChannelSession{}, nil + } + return nil, err + } + + sessions := make([]*ChannelSession, 0, len(entries)) + for _, entry := range entries { + name := entry.Name() + if !strings.HasSuffix(name, ".json") || strings.HasSuffix(name, ".lock") { + continue + } + raw, err := os.ReadFile(filepath.Join(dir, name)) + if err != nil { + // Skip files that disappeared between readdir and read (concurrent delete). + if batchsettlement.IsNotExist(err) { + continue + } + return nil, err + } + out := &ChannelSession{} + if err := json.Unmarshal(raw, out); err != nil { + return nil, fmt.Errorf("unmarshal %s: %w", name, err) + } + sessions = append(sessions, out) + } + sort.Slice(sessions, func(i, j int) bool { return sessions[i].ChannelId < sessions[j].ChannelId }) + return sessions, nil +} + +// CompareAndSet uses an exclusive lock file to serialise concurrent writers. +// The mkdir call ensures the very first CompareAndSet on a fresh directory +// does not fail with ENOENT on the lock file. +func (s *FileChannelStorage) CompareAndSet(channelId string, expectedCharged string, session *ChannelSession) (bool, error) { + path := s.filePath(channelId) + lockPath := path + ".lock" + + if err := os.MkdirAll(filepath.Dir(lockPath), 0o755); err != nil { + return false, fmt.Errorf("mkdir %s: %w", filepath.Dir(lockPath), err) + } + + lockFile, err := os.OpenFile(lockPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o644) + if err != nil { + if errors.Is(err, os.ErrExist) { + return false, nil + } + return false, fmt.Errorf("acquire lock %s: %w", lockPath, err) + } + defer func() { + _ = lockFile.Close() + _ = os.Remove(lockPath) + }() + + current := &ChannelSession{} + ok, err := batchsettlement.ReadJSONFile(path, current) + if err != nil { + return false, err + } + if ok && current.ChargedCumulativeAmount != expectedCharged { + return false, nil + } + if err := batchsettlement.WriteJSONAtomic(path, session); err != nil { + return false, err + } + return true, nil +} + +// UpdateChannel atomically reads, mutates, and writes a channel record under an +// exclusive lock file. Returning a different pointer commits the new session; +// returning nil deletes the file; returning the same pointer is treated as a +// no-op (status: unchanged). +func (s *FileChannelStorage) UpdateChannel(channelId string, update func(current *ChannelSession) *ChannelSession) (*ChannelUpdateResult, error) { + path := s.filePath(channelId) + lockPath := path + ".lock" + + if err := os.MkdirAll(filepath.Dir(lockPath), 0o755); err != nil { + return nil, fmt.Errorf("mkdir %s: %w", filepath.Dir(lockPath), err) + } + + // Spin-lock until we acquire the exclusive lock file. Concurrent writers see + // ErrExist and retry; bounded retries keep this from hanging on stale locks. + const maxAttempts = 50 + var lockFile *os.File + for attempt := 0; attempt < maxAttempts; attempt++ { + f, err := os.OpenFile(lockPath, os.O_CREATE|os.O_EXCL|os.O_WRONLY, 0o644) + if err == nil { + lockFile = f + break + } + if !errors.Is(err, os.ErrExist) { + return nil, fmt.Errorf("acquire lock %s: %w", lockPath, err) + } + } + if lockFile == nil { + return nil, fmt.Errorf("acquire lock %s: contended", lockPath) + } + defer func() { + _ = lockFile.Close() + _ = os.Remove(lockPath) + }() + + var current *ChannelSession + out := &ChannelSession{} + ok, err := batchsettlement.ReadJSONFile(path, out) + if err != nil { + return nil, err + } + if ok { + current = out + } + + next := update(current) + switch { + case next == nil: + if !ok { + return &ChannelUpdateResult{Status: ChannelUnchanged}, nil + } + if rmErr := os.Remove(path); rmErr != nil && !batchsettlement.IsNotExist(rmErr) { + return nil, rmErr + } + return &ChannelUpdateResult{Status: ChannelDeleted}, nil + case current != nil && next == current: + return &ChannelUpdateResult{Channel: current, Status: ChannelUnchanged}, nil + default: + if err := batchsettlement.WriteJSONAtomic(path, next); err != nil { + return nil, err + } + return &ChannelUpdateResult{Channel: next, Status: ChannelUpdated}, nil + } +} diff --git a/go/mechanisms/evm/batch-settlement/server/file_storage_test.go b/go/mechanisms/evm/batch-settlement/server/file_storage_test.go new file mode 100644 index 0000000000..2a6a1c940e --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/server/file_storage_test.go @@ -0,0 +1,192 @@ +package server + +import ( + "os" + "path/filepath" + "reflect" + "sort" + "testing" + + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +func newServerFileStore(t *testing.T) (*FileChannelStorage, string) { + t.Helper() + dir := t.TempDir() + return NewFileChannelStorage(batchsettlement.FileChannelStorageOptions{Directory: dir}), dir +} + +func TestServerFileStorage_GetMissing(t *testing.T) { + s, _ := newServerFileStore(t) + got, err := s.Get("missing") + if err != nil { + t.Fatalf("err: %v", err) + } + if got != nil { + t.Fatalf("got %+v", got) + } +} + +func TestServerFileStorage_SetGetRoundTrip(t *testing.T) { + s, _ := newServerFileStore(t) + in := sampleSession("ch", "5") + if err := s.Set("ch", in); err != nil { + t.Fatalf("Set: %v", err) + } + got, err := s.Get("ch") + if err != nil { + t.Fatalf("Get: %v", err) + } + if !reflect.DeepEqual(in, got) { + t.Fatalf("mismatch:\nwant %+v\ngot %+v", in, got) + } +} + +func TestServerFileStorage_PathLowercased(t *testing.T) { + s, dir := newServerFileStore(t) + _ = s.Set("0xABCDEF", sampleSession("0xABCDEF", "1")) + expected := filepath.Join(dir, "server", "0xabcdef.json") + if _, err := os.Stat(expected); err != nil { + t.Fatalf("expected file at %s: %v", expected, err) + } +} + +func TestServerFileStorage_Delete(t *testing.T) { + s, _ := newServerFileStore(t) + _ = s.Set("ch", sampleSession("ch", "1")) + if err := s.Delete("ch"); err != nil { + t.Fatalf("Delete: %v", err) + } + if got, _ := s.Get("ch"); got != nil { + t.Fatalf("expected nil after delete") + } + if err := s.Delete("ch"); err != nil { + t.Fatalf("Delete-missing should not error: %v", err) + } +} + +func TestServerFileStorage_List_Empty(t *testing.T) { + s, _ := newServerFileStore(t) + got, err := s.List() + if err != nil { + t.Fatalf("err: %v", err) + } + if len(got) != 0 { + t.Fatalf("expected empty list, got %d", len(got)) + } +} + +func TestServerFileStorage_List_Populated(t *testing.T) { + s, _ := newServerFileStore(t) + _ = s.Set("b", sampleSession("b", "2")) + _ = s.Set("a", sampleSession("a", "1")) + got, err := s.List() + if err != nil { + t.Fatalf("err: %v", err) + } + if len(got) != 2 { + t.Fatalf("expected 2 sessions, got %d", len(got)) + } + // Should be sorted by ChannelId + sort.SliceIsSorted(got, func(i, j int) bool { return got[i].ChannelId < got[j].ChannelId }) + if got[0].ChannelId != "a" || got[1].ChannelId != "b" { + t.Fatalf("not sorted: %s, %s", got[0].ChannelId, got[1].ChannelId) + } +} + +func TestServerFileStorage_List_SkipsNonJSON(t *testing.T) { + s, dir := newServerFileStore(t) + _ = s.Set("a", sampleSession("a", "1")) + // Drop a non-JSON file in the same directory + _ = os.WriteFile(filepath.Join(dir, "server", "junk.txt"), []byte("noise"), 0o644) + got, err := s.List() + if err != nil { + t.Fatalf("err: %v", err) + } + if len(got) != 1 { + t.Fatalf("expected 1 session, got %d", len(got)) + } +} + +func TestServerFileStorage_List_Malformed(t *testing.T) { + s, dir := newServerFileStore(t) + _ = os.MkdirAll(filepath.Join(dir, "server"), 0o755) + _ = os.WriteFile(filepath.Join(dir, "server", "bad.json"), []byte("not json{"), 0o644) + if _, err := s.List(); err == nil { + t.Fatal("expected unmarshal error") + } +} + +func TestServerFileStorage_CompareAndSet_FirstWriteWins(t *testing.T) { + s, _ := newServerFileStore(t) + ok, err := s.CompareAndSet("ch", "0", sampleSession("ch", "10")) + if err != nil || !ok { + t.Fatalf("expected ok, got ok=%v err=%v", ok, err) + } + got, _ := s.Get("ch") + if got == nil || got.ChargedCumulativeAmount != "10" { + t.Fatalf("not stored") + } +} + +func TestServerFileStorage_CompareAndSet_StaleFails(t *testing.T) { + s, _ := newServerFileStore(t) + _ = s.Set("ch", sampleSession("ch", "10")) + ok, err := s.CompareAndSet("ch", "0", sampleSession("ch", "20")) + if err != nil { + t.Fatalf("err: %v", err) + } + if ok { + t.Fatal("stale CAS should fail") + } + got, _ := s.Get("ch") + if got.ChargedCumulativeAmount != "10" { + t.Fatalf("storage mutated by failed CAS") + } +} + +func TestServerFileStorage_CompareAndSet_FreshSucceeds(t *testing.T) { + s, _ := newServerFileStore(t) + _ = s.Set("ch", sampleSession("ch", "10")) + ok, err := s.CompareAndSet("ch", "10", sampleSession("ch", "20")) + if err != nil || !ok { + t.Fatalf("expected ok, got ok=%v err=%v", ok, err) + } + got, _ := s.Get("ch") + if got.ChargedCumulativeAmount != "20" { + t.Fatalf("CAS did not update") + } +} + +func TestServerFileStorage_CompareAndSet_LockHeld(t *testing.T) { + s, dir := newServerFileStore(t) + // Manually create the lock file to simulate a concurrent writer. + lockDir := filepath.Join(dir, "server") + _ = os.MkdirAll(lockDir, 0o755) + lockPath := filepath.Join(lockDir, "ch.json.lock") + if err := os.WriteFile(lockPath, []byte("held"), 0o644); err != nil { + t.Fatalf("setup: %v", err) + } + defer os.Remove(lockPath) + ok, err := s.CompareAndSet("ch", "0", sampleSession("ch", "10")) + if err != nil { + t.Fatalf("err: %v", err) + } + if ok { + t.Fatal("CAS should yield to lock holder") + } +} + +func TestServerFileStorage_CompareAndSet_CreatesDirectoryFromCold(t *testing.T) { + // Mirrors the 5a007ae70 fix — a brand-new directory must not blow up on + // the very first CompareAndSet. + dir := t.TempDir() + s := NewFileChannelStorage(batchsettlement.FileChannelStorageOptions{Directory: dir}) + ok, err := s.CompareAndSet("ch", "0", sampleSession("ch", "1")) + if err != nil { + t.Fatalf("err: %v", err) + } + if !ok { + t.Fatal("CAS from cold should succeed") + } +} diff --git a/go/mechanisms/evm/batch-settlement/server/hooks.go b/go/mechanisms/evm/batch-settlement/server/hooks.go new file mode 100644 index 0000000000..c28f64aac4 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/server/hooks.go @@ -0,0 +1,1111 @@ +package server + +import ( + "context" + "errors" + "fmt" + "log" + "math/big" + "strings" + "time" + + "github.com/ethereum/go-ethereum/common" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/facilitator" + "github.com/x402-foundation/x402/go/types" +) + +const zeroAddress = "0x0000000000000000000000000000000000000000" + +// Pending reservation TTL bounds. Cleanup hooks normally clear reservations on +// failure; these bounds release the channel if cleanup never runs. +const ( + minPendingTtlMs = 5_000 // 5 seconds + maxPendingTtlMs = 10 * 60 * 1000 // 10 minutes +) + +// BeforeVerifyHook reserves the channel for this request via an atomic +// UpdateChannel call. Three outcomes are possible: +// - busy: a live (unexpired) reservation already exists → abort +// - mismatch: client's signed cap does not match server's expected base → +// remember the snapshot so EnrichPaymentRequiredResponse can return +// corrective state, then abort with ErrCumulativeAmountMismatch +// - reserved: write a new PendingRequest into storage and merge the +// channelId/pendingId/snapshot into the per-payload request context so +// AfterVerifyHook / BeforeSettleHook can commit (or release) it +// +// When no local channel record exists, a provisional one is created so the +// reservation has somewhere to live; ClearPendingRequest will delete it +// later if the request fails (snapshot is nil). +func (s *BatchSettlementEvmScheme) BeforeVerifyHook() x402.BeforeVerifyHook { + return func(ctx x402.VerifyContext) (*x402.BeforeHookResult, error) { + if ctx.Requirements.GetScheme() != batchsettlement.SchemeBatched { + return nil, nil + } + + payload := ctx.Payload.GetPayload() + + isPaid := batchsettlement.IsVoucherPayload(payload) || batchsettlement.IsDepositPayload(payload) + isZeroCharge := batchsettlement.IsRefundPayload(payload) + if !isPaid && !isZeroCharge { + return nil, nil + } + + voucherFields, _ := payload["voucher"].(map[string]interface{}) + if voucherFields == nil { + return nil, nil + } + rawChannelId, _ := voucherFields["channelId"].(string) + channelId := batchsettlement.NormalizeChannelId(rawChannelId) + signedMaxStr, _ := voucherFields["maxClaimableAmount"].(string) + signature, _ := voucherFields["signature"].(string) + signedMax, _ := new(big.Int).SetString(signedMaxStr, 10) + if signedMax == nil { + signedMax = big.NewInt(0) + } + + reqAmount, _ := new(big.Int).SetString(ctx.Requirements.GetAmount(), 10) + if reqAmount == nil { + reqAmount = big.NewInt(0) + } + + now := time.Now().UnixMilli() + pendingNonce, err := evm.CreateNonce() + if err != nil { + return nil, fmt.Errorf("create pending nonce: %w", err) + } + pendingId := pendingNonce + + var ( + outcomeStatus string // "busy" | "mismatch" | "reserved" + outcomeChannel *ChannelSession + outcomePrevSession *ChannelSession // when "reserved" with existing row + ) + + _, updateErr := s.storage.UpdateChannel(channelId, func(current *ChannelSession) *ChannelSession { + // A live (unexpired) reservation already exists → abort. + if current != nil && current.PendingRequest != nil && current.PendingRequest.ExpiresAt > now { + outcomeStatus = "busy" + return current + } + + var prevCharged *big.Int + if current != nil { + prevCharged, _ = new(big.Int).SetString(current.ChargedCumulativeAmount, 10) + } + if prevCharged == nil { + // When storage has no row yet, derive a sensible charged base so + // the mismatch check still works for the first request on a + // brand-new channel. + switch { + case !isPaid: + prevCharged = new(big.Int).Set(signedMax) + case signedMax.Cmp(reqAmount) < 0: + prevCharged = big.NewInt(0) + default: + prevCharged = new(big.Int).Sub(signedMax, reqAmount) + } + } + + var expectedMax *big.Int + if isZeroCharge { + expectedMax = new(big.Int).Set(prevCharged) + } else { + expectedMax = new(big.Int).Add(prevCharged, reqAmount) + } + + if signedMax.Cmp(expectedMax) != 0 { + outcomeStatus = "mismatch" + if current != nil { + outcomeChannel = current + } else { + outcomeChannel = buildProvisionalChannelFromPayload( + channelId, signedMaxStr, signature, payload, prevCharged.String(), now, + ) + } + return current + } + + outcomeStatus = "reserved" + outcomePrevSession = current + next := &ChannelSession{} + if current != nil { + cp := *current + next = &cp + } else { + prov := buildProvisionalChannelFromPayload( + channelId, signedMaxStr, signature, payload, prevCharged.String(), now, + ) + next = prov + } + // Compute the reservation expiry as now + clamp(maxTimeoutSeconds*1000, [min,max]) ms. + ttl := int64(ctx.Requirements.GetMaxTimeoutSeconds()) * 1000 + if ttl < minPendingTtlMs { + ttl = minPendingTtlMs + } + if ttl > maxPendingTtlMs { + ttl = maxPendingTtlMs + } + next.PendingRequest = &PendingRequest{ + PendingId: pendingId, + SignedMaxClaimable: signedMaxStr, + ExpiresAt: now + ttl, + } + next.LastRequestTimestamp = now + return next + }) + if updateErr != nil { + return nil, updateErr + } + + switch outcomeStatus { + case "busy": + return &x402.BeforeHookResult{ + Abort: true, + Reason: batchsettlement.ErrChannelBusy, + Message: "Channel is already processing a request", + }, nil + case "mismatch": + s.RememberChannelSnapshot(ctx.Payload, outcomeChannel) + return &x402.BeforeHookResult{ + Abort: true, + Reason: batchsettlement.ErrCumulativeAmountMismatch, + Message: "Client voucher base does not match server state", + }, nil + case "reserved": + s.MergeRequestContext(ctx.Payload, BatchSettlementRequestContext{ + ChannelId: channelId, + PendingId: pendingId, + ChannelSnapshot: outcomePrevSession, + }) + + // Try a local voucher verification when cached onchain state is fresh. + // Only voucher payloads (not deposit/refund) qualify. + if batchsettlement.IsVoucherPayload(payload) { + localResult := s.verifyVoucherLocally(ctx.Requirements, payload, outcomePrevSession, now) + if localResult != nil { + s.MergeRequestContext(ctx.Payload, BatchSettlementRequestContext{LocalVerify: true}) + return &x402.BeforeHookResult{ + Skip: true, + SkipVerifyResult: localResult, + }, nil + } + } + } + return nil, nil + } +} + +// verifyVoucherLocally returns a successful VerifyResponse when the voucher can +// be verified entirely against locally cached channel state — i.e. the cache is +// within the configured TTL of last onchain sync, the channel config validates, +// the recomputed channelId matches, and the voucher signature recovers to the +// payerAuthorizer. Returns nil on any check that requires falling back to the +// facilitator, and an explicit invalid VerifyResponse when a local check fails. +// +// The smart-wallet (ERC-1271) path is intentionally not supported — vouchers +// signed by a non-zero EOA payerAuthorizer are the only candidates. +func (s *BatchSettlementEvmScheme) verifyVoucherLocally( + requirements x402.PaymentRequirementsView, + payload map[string]interface{}, + channel *ChannelSession, + now int64, +) *x402.VerifyResponse { + if channel == nil { + return nil + } + // Skip the local fast path when the cached onchain fields for this + // channel are stale (or never synced) — the dispatcher will fall back + // to the remote facilitator verify. + if channel.OnchainSyncedAt == 0 || now-channel.OnchainSyncedAt > s.GetOnchainStateTtlMs() { + return nil + } + + vp, err := batchsettlement.VoucherPayloadFromMap(payload) + if err != nil { + return nil + } + if strings.EqualFold(vp.ChannelConfig.PayerAuthorizer, zeroAddress) { + return nil + } + + payer := vp.ChannelConfig.Payer + + // Construct a types.PaymentRequirements from the view to reuse the + // shared validator (avoids duplicating receiver/token/delay/channelId checks). + reqs := types.PaymentRequirements{ + Scheme: requirements.GetScheme(), + Network: requirements.GetNetwork(), + Asset: requirements.GetAsset(), + Amount: requirements.GetAmount(), + PayTo: requirements.GetPayTo(), + MaxTimeoutSeconds: requirements.GetMaxTimeoutSeconds(), + Extra: requirements.GetExtra(), + } + if cfgErr := facilitator.ValidateChannelConfig(vp.ChannelConfig, vp.Voucher.ChannelId, reqs); cfgErr != nil { + reason := facilitator.ErrChannelIdMismatch + var ve *x402.VerifyError + if errors.As(cfgErr, &ve) && ve.InvalidReason != "" { + reason = ve.InvalidReason + } + return invalidLocalVerifyResponse(payer, reason) + } + + computed, err := batchsettlement.ComputeChannelId(vp.ChannelConfig, requirements.GetNetwork()) + if err != nil || !strings.EqualFold(computed, channel.ChannelId) { + return invalidLocalVerifyResponse(payer, facilitator.ErrChannelIdMismatch) + } + + // Verify the EIP-712 voucher signature against the channel's + // payerAuthorizer using ECDSA. Smart-wallet (ERC-1271) signatures are + // intentionally not supported here — the early `vp.ChannelConfig + // .PayerAuthorizer == zeroAddress` skip above ensures this path only + // runs against EOA payerAuthorizers. + sigOk := false + chainID, sigErr := evm.GetEvmChainId(requirements.GetNetwork()) + if sigErr == nil { + maxClaimable, ok := new(big.Int).SetString(vp.Voucher.MaxClaimableAmount, 10) + if !ok { + return invalidLocalVerifyResponse(payer, facilitator.ErrVoucherSignatureInvalid) + } + hash, hashErr := evm.HashTypedData( + batchsettlement.GetBatchSettlementEip712Domain(chainID), + batchsettlement.VoucherTypes, + "Voucher", + map[string]interface{}{ + "channelId": vp.Voucher.ChannelId, + "maxClaimableAmount": maxClaimable, + }, + ) + if hashErr == nil { + sigBytes := common.FromHex(vp.Voucher.Signature) + sigOk, sigErr = evm.VerifyEOASignature( + hash, sigBytes, common.HexToAddress(vp.ChannelConfig.PayerAuthorizer), + ) + } else { + sigErr = hashErr + } + } + if sigErr != nil || !sigOk { + return invalidLocalVerifyResponse(payer, facilitator.ErrVoucherSignatureInvalid) + } + + maxClaimable, ok := new(big.Int).SetString(vp.Voucher.MaxClaimableAmount, 10) + if !ok { + return nil + } + balance, _ := new(big.Int).SetString(channel.Balance, 10) + if balance == nil { + balance = big.NewInt(0) + } + if maxClaimable.Cmp(balance) > 0 { + return invalidLocalVerifyResponse(payer, facilitator.ErrMaxClaimableExceedsBal) + } + totalClaimed, _ := new(big.Int).SetString(channel.TotalClaimed, 10) + if totalClaimed == nil { + totalClaimed = big.NewInt(0) + } + if maxClaimable.Cmp(totalClaimed) <= 0 { + return invalidLocalVerifyResponse(payer, facilitator.ErrMaxClaimableTooLow) + } + + return &x402.VerifyResponse{ + IsValid: true, + Payer: payer, + Extra: map[string]interface{}{ + "channelId": vp.Voucher.ChannelId, + "balance": channel.Balance, + "totalClaimed": channel.TotalClaimed, + "withdrawRequestedAt": channel.WithdrawRequestedAt, + "refundNonce": fmt.Sprintf("%d", channel.RefundNonce), + }, + } +} + +// invalidLocalVerifyResponse builds a failed VerifyResponse preserving the +// payer for client-side reporting. +func invalidLocalVerifyResponse(payer, invalidReason string) *x402.VerifyResponse { + return &x402.VerifyResponse{ + IsValid: false, + Payer: payer, + InvalidReason: invalidReason, + } +} + +// buildProvisionalChannelFromPayload constructs the minimal ChannelSession +// needed to host a pending reservation when storage has no row yet. +func buildProvisionalChannelFromPayload( + channelId, signedMax, signature string, + payload map[string]interface{}, + chargedCumulativeAmount string, + now int64, +) *ChannelSession { + cfg := batchsettlement.ChannelConfig{} + if cfgMap, ok := payload["channelConfig"].(map[string]interface{}); ok { + if parsed, err := batchsettlement.ChannelConfigFromMap(cfgMap); err == nil { + cfg = parsed + } + } + return &ChannelSession{ + ChannelId: channelId, + ChannelConfig: cfg, + ChargedCumulativeAmount: chargedCumulativeAmount, + SignedMaxClaimable: signedMax, + Signature: signature, + Balance: "0", + TotalClaimed: "0", + WithdrawRequestedAt: 0, + RefundNonce: 0, + LastRequestTimestamp: now, + } +} + +// AfterVerifyHook returns a hook that persists channel session state after +// successful verification. It extracts channelId, voucher signature, and +// onchain snapshot from the verify response and stores/updates the session. +// +// For refund vouchers (refund: true), additionally returns a SkipHandler +// directive so the resource server bypasses the application handler and +// settles inline. +func (s *BatchSettlementEvmScheme) AfterVerifyHook() x402.AfterVerifyHook { + return func(ctx x402.VerifyResultContext) (*x402.AfterVerifyResult, error) { + if ctx.Requirements.GetScheme() != batchsettlement.SchemeBatched { + return nil, nil + } + if ctx.Result == nil || !ctx.Result.IsValid || ctx.Result.Payer == "" { + // Verify failed or returned invalid: release this request's reservation. + _ = s.ClearPendingRequest(ctx.Payload) + return nil, nil + } + + payload := ctx.Payload.GetPayload() + + var channelId, signedMaxClaimable, signature string + var channelConfig *batchsettlement.ChannelConfig + isRefundVoucher := false + + switch { + case batchsettlement.IsDepositPayload(payload): + dp, parseErr := batchsettlement.DepositPayloadFromMap(payload) + if parseErr != nil { + return nil, nil //nolint:nilerr // parse failure in after-hook is non-fatal + } + channelId = dp.Voucher.ChannelId + signedMaxClaimable = dp.Voucher.MaxClaimableAmount + signature = dp.Voucher.Signature + cfg := dp.ChannelConfig + channelConfig = &cfg + case batchsettlement.IsVoucherPayload(payload): + vp, parseErr := batchsettlement.VoucherPayloadFromMap(payload) + if parseErr != nil { + return nil, nil //nolint:nilerr // parse failure in after-hook is non-fatal + } + channelId = vp.Voucher.ChannelId + signedMaxClaimable = vp.Voucher.MaxClaimableAmount + signature = vp.Voucher.Signature + cfg := vp.ChannelConfig + channelConfig = &cfg + case batchsettlement.IsRefundPayload(payload): + rp, parseErr := batchsettlement.RefundPayloadFromMap(payload) + if parseErr != nil { + return nil, nil //nolint:nilerr // parse failure in after-hook is non-fatal + } + channelId = rp.Voucher.ChannelId + signedMaxClaimable = rp.Voucher.MaxClaimableAmount + signature = rp.Voucher.Signature + cfg := rp.ChannelConfig + channelConfig = &cfg + isRefundVoucher = true + default: + return nil, nil + } + + ex := ctx.Result.Extra + balance := mapStringField(ex, "balance", "0") + totalClaimed := mapStringField(ex, "totalClaimed", "0") + withdrawRequestedAt := mapIntField(ex, "withdrawRequestedAt", 0) + refundNonce := mapIntField(ex, "refundNonce", 0) + + normalizedId := batchsettlement.NormalizeChannelId(channelId) + now := time.Now().UnixMilli() + + // Only commit when current.PendingRequest.PendingId matches this + // request's reservation. Without a valid reservation context (e.g. + // hooks invoked out-of-band by tests), fall back to a plain Set so + // existing direct-call behavior is preserved. + rc := s.ReadRequestContext(ctx.Payload) + if rc == nil || rc.PendingId == "" { + prev, _ := s.storage.Get(normalizedId) + resolvedConfig := channelConfig + if resolvedConfig == nil && prev != nil { + resolvedConfig = &prev.ChannelConfig + } + if resolvedConfig == nil { + return nil, nil + } + prevCharged := totalClaimed + if prev != nil { + prevCharged = prev.ChargedCumulativeAmount + } + session := &ChannelSession{ + ChannelId: normalizedId, + ChannelConfig: *resolvedConfig, + ChargedCumulativeAmount: prevCharged, + SignedMaxClaimable: signedMaxClaimable, + Signature: signature, + Balance: balance, + TotalClaimed: totalClaimed, + WithdrawRequestedAt: withdrawRequestedAt, + RefundNonce: refundNonce, + LastRequestTimestamp: now, + OnchainSyncedAt: now, + } + if err := s.storage.Set(normalizedId, session); err != nil { + return nil, err + } + if isRefundVoucher { + return &x402.AfterVerifyResult{ + SkipHandler: true, + Response: &x402.SkipHandlerDirective{ + ContentType: "application/json", + Body: map[string]interface{}{ + "message": "Refund acknowledged", + "channelId": normalizedId, + }, + }, + }, nil + } + return nil, nil + } + + // When local verify already succeeded for a voucher payload, the cached + // onchain fields were trusted as-is — preserve the existing + // OnchainSyncedAt rather than treating this commit as a fresh sync. + updateRes, err := s.storage.UpdateChannel(normalizedId, func(current *ChannelSession) *ChannelSession { + if current == nil || current.PendingRequest == nil || + current.PendingRequest.PendingId != rc.PendingId { + return current + } + onchainSyncedAt := now + if rc.LocalVerify && batchsettlement.IsVoucherPayload(payload) { + onchainSyncedAt = current.OnchainSyncedAt + } + next := &ChannelSession{ + ChannelId: normalizedId, + ChargedCumulativeAmount: current.ChargedCumulativeAmount, + SignedMaxClaimable: signedMaxClaimable, + Signature: signature, + Balance: balance, + TotalClaimed: totalClaimed, + WithdrawRequestedAt: withdrawRequestedAt, + RefundNonce: refundNonce, + OnchainSyncedAt: onchainSyncedAt, + LastRequestTimestamp: now, + PendingRequest: current.PendingRequest, + } + if channelConfig != nil { + next.ChannelConfig = *channelConfig + } else { + next.ChannelConfig = current.ChannelConfig + } + return next + }) + if err != nil { + return nil, err + } + if updateRes.Status == ChannelUpdated && updateRes.Channel != nil { + s.RememberChannelSnapshot(ctx.Payload, updateRes.Channel) + } + + if isRefundVoucher && updateRes.Status == ChannelUpdated { + return &x402.AfterVerifyResult{ + SkipHandler: true, + Response: &x402.SkipHandlerDirective{ + ContentType: "application/json", + Body: map[string]interface{}{ + "message": "Refund acknowledged", + "channelId": normalizedId, + }, + }, + }, nil + } + return nil, nil + } +} + +// OnVerifyFailureHook releases a reservation when facilitator verification fails. +func (s *BatchSettlementEvmScheme) OnVerifyFailureHook() x402.OnVerifyFailureHook { + return func(ctx x402.VerifyFailureContext) (*x402.VerifyFailureHookResult, error) { + if ctx.Requirements.GetScheme() != batchsettlement.SchemeBatched { + return nil, nil + } + return nil, s.ClearPendingRequest(ctx.Payload) + } +} + +// BeforeSettleHook returns a hook that implements the core batched settlement +// logic. For voucher payloads it: +// - Increments chargedCumulativeAmount locally via UpdateChannel +// - Returns a Skip result so onchain settlement is NOT triggered +// - If the voucher has refund=true, rewrites the payload to a refund settle +// action that the facilitator will execute onchain +// +// For deposit payloads it annotates responseExtra with the new charged amount. +// All other payload types pass through to the facilitator. +func (s *BatchSettlementEvmScheme) BeforeSettleHook() x402.BeforeSettleHook { + return func(ctx x402.SettleContext) (*x402.BeforeHookResult, error) { + if ctx.Requirements.GetScheme() != batchsettlement.SchemeBatched { + return nil, nil + } + + payload := ctx.Payload.GetPayload() + + // Deposit and refund payloads pass through to the facilitator. Server- + // owned enrichment for refunds (claims + authorizer signatures) lives + // in EnrichSettlementPayload below. + if !batchsettlement.IsVoucherPayload(payload) { + return nil, nil + } + + // --- Voucher path: short-circuit on-chain settlement --- + + voucherMap, _ := payload["voucher"].(map[string]interface{}) + if voucherMap == nil { + return nil, nil + } + channelId, _ := voucherMap["channelId"].(string) + normalizedId := batchsettlement.NormalizeChannelId(channelId) + + session, storageErr := s.storage.Get(normalizedId) + if storageErr != nil || session == nil { + return &x402.BeforeHookResult{ //nolint:nilerr // storage error treated as missing session + Abort: true, + Reason: batchsettlement.ErrMissingChannel, + Message: "No session for channel; verify may not have completed", + }, nil + } + + _ = session // existence already enforced above; UpdateChannel re-reads under lock + + increment, _ := new(big.Int).SetString(ctx.Requirements.GetAmount(), 10) + if increment == nil { + increment = big.NewInt(0) + } + maxClaimable, _ := voucherMap["maxClaimableAmount"].(string) + sig, _ := voucherMap["signature"].(string) + rc := s.ReadRequestContext(ctx.Payload) + var pendingId string + if rc != nil { + pendingId = rc.PendingId + } + + var ( + outcome string // "missing" | "pending_mismatch" | "cap_exceeded" | "committed" + capExceededAmount string + committedPrev *ChannelSession + committedNew *ChannelSession + committedNewCharged *big.Int + ) + + _, updateErr := s.storage.UpdateChannel(normalizedId, func(current *ChannelSession) *ChannelSession { + if current == nil { + outcome = "missing" + return current + } + if pendingId == "" || current.PendingRequest == nil || + current.PendingRequest.PendingId != pendingId { + outcome = "pending_mismatch" + return current + } + curCharged, _ := new(big.Int).SetString(current.ChargedCumulativeAmount, 10) + if curCharged == nil { + curCharged = big.NewInt(0) + } + next := new(big.Int).Add(curCharged, increment) + cap2, _ := new(big.Int).SetString(maxClaimable, 10) + if cap2 != nil && next.Cmp(cap2) > 0 { + outcome = "cap_exceeded" + capExceededAmount = next.String() + cleared := *current + cleared.PendingRequest = nil + return &cleared + } + updated := *current + updated.ChargedCumulativeAmount = next.String() + updated.SignedMaxClaimable = maxClaimable + updated.Signature = sig + updated.LastRequestTimestamp = time.Now().UnixMilli() + updated.PendingRequest = nil + outcome = "committed" + committedPrev = current + committedNew = &updated + committedNewCharged = next + return &updated + }) + if updateErr != nil { + return nil, updateErr + } + + switch outcome { + case "missing": + s.TakeRequestContext(ctx.Payload) + return &x402.BeforeHookResult{ + Abort: true, + Reason: batchsettlement.ErrMissingChannel, + Message: "No channel record", + }, nil + case "pending_mismatch": + s.TakeRequestContext(ctx.Payload) + return &x402.BeforeHookResult{ + Abort: true, + Reason: batchsettlement.ErrChannelBusy, + Message: "Concurrent request modified channel state", + }, nil + case "cap_exceeded": + capStr := maxClaimable + s.TakeRequestContext(ctx.Payload) + return &x402.BeforeHookResult{ + Abort: true, + Reason: batchsettlement.ErrChargeExceedsSignedCumulative, + Message: fmt.Sprintf("Charged %s exceeds signed max %s", capExceededAmount, capStr), + }, nil + } + + s.TakeRequestContext(ctx.Payload) + // Emit the nested response shape: chargedAmount + channelState. + skipExtra := &batchsettlement.BatchSettlementPaymentResponseExtra{ + ChargedAmount: ctx.Requirements.GetAmount(), + ChannelState: &batchsettlement.BatchSettlementChannelStateExtra{ + ChannelId: normalizedId, + Balance: committedNew.Balance, + TotalClaimed: committedNew.TotalClaimed, + WithdrawRequestedAt: committedNew.WithdrawRequestedAt, + RefundNonce: fmt.Sprintf("%d", committedNew.RefundNonce), + ChargedCumulativeAmount: committedNewCharged.String(), + }, + } + return &x402.BeforeHookResult{ + Skip: true, + SkipResult: &x402.SettleResponse{ + Success: true, + Transaction: "", + Network: x402.Network(ctx.Requirements.GetNetwork()), + Payer: committedPrev.ChannelConfig.Payer, + Amount: "", + Extra: skipExtra.ToMap(), + }, + }, nil + } +} + +// OnSettleFailureHook releases a reservation when facilitator settlement fails. +func (s *BatchSettlementEvmScheme) OnSettleFailureHook() x402.OnSettleFailureHook { + return func(ctx x402.SettleFailureContext) (*x402.SettleFailureHookResult, error) { + if ctx.Requirements.GetScheme() != batchsettlement.SchemeBatched { + return nil, nil + } + return nil, s.ClearPendingRequest(ctx.Payload) + } +} + +// EnrichSettlementPayload supplies server-owned settlement-payload fields +// before the facilitator settles. For refund payloads it returns the additive +// `{amount?, refundNonce, claims, refundAuthorizerSignature?, claimAuthorizerSignature?}` +// map; the framework's additive policy (AssertAdditivePayloadEnrichment) +// rejects any attempt to overwrite existing client-set keys. +// +// Returns nil for non-refund payloads. Returns a structured error on +// validation failure; the framework converts it into a settle abort with +// the error string as the reason. +func (s *BatchSettlementEvmScheme) EnrichSettlementPayload(ctx x402.SettleContext) (map[string]interface{}, error) { + if ctx.Requirements.GetScheme() != batchsettlement.SchemeBatched { + return nil, nil + } + payload := ctx.Payload.GetPayload() + if !batchsettlement.IsRefundPayload(payload) { + return nil, nil + } + + voucherMap, _ := payload["voucher"].(map[string]interface{}) + if voucherMap == nil { + voucherMap = map[string]interface{}{} + } + channelIdStr, _ := voucherMap["channelId"].(string) + normalizedId := batchsettlement.NormalizeChannelId(channelIdStr) + + session, storageErr := s.storage.Get(normalizedId) + if storageErr != nil || session == nil { + return nil, errors.New(batchsettlement.ErrMissingChannel) + } + rc := s.ReadRequestContext(ctx.Payload) + if rc == nil || rc.PendingId == "" || session.PendingRequest == nil || + session.PendingRequest.PendingId != rc.PendingId { + return nil, errors.New(batchsettlement.ErrChannelBusy) + } + + maxClaimable, _ := voucherMap["maxClaimableAmount"].(string) + sig, _ := voucherMap["signature"].(string) + if maxClaimable != session.SignedMaxClaimable { + return nil, errors.New(batchsettlement.ErrCumulativeAmountMismatch) + } + if sig != session.Signature { + return nil, errors.New(facilitator.ErrVoucherSignatureInvalid) + } + + config := session.ChannelConfig + + // Refund vouchers are zero-charge: claim's totalClaimed == session.chargedCumulativeAmount. + claimEntry := batchsettlement.BatchSettlementVoucherClaim{ + Voucher: struct { + Channel batchsettlement.ChannelConfig `json:"channel"` + MaxClaimableAmount string `json:"maxClaimableAmount"` + }{ + Channel: config, + MaxClaimableAmount: maxClaimable, + }, + Signature: sig, + TotalClaimed: session.ChargedCumulativeAmount, + } + + balance, _ := new(big.Int).SetString(session.Balance, 10) + if balance == nil { + balance = big.NewInt(0) + } + charged, _ := new(big.Int).SetString(session.ChargedCumulativeAmount, 10) + if charged == nil { + charged = big.NewInt(0) + } + remainder := new(big.Int).Sub(balance, charged) + if remainder.Sign() <= 0 { + return nil, errors.New(batchsettlement.ErrRefundNoBalance) + } + + refundAmount := new(big.Int).Set(remainder) + requestedStr, hasRequestedAmount := payload["amount"].(string) + hasRequestedAmount = hasRequestedAmount && requestedStr != "" + if hasRequestedAmount { + requested, ok := new(big.Int).SetString(requestedStr, 10) + if !ok || requested.Sign() <= 0 { + return nil, errors.New(batchsettlement.ErrRefundAmountInvalid) + } + if requested.Cmp(remainder) > 0 { + return nil, errors.New(batchsettlement.ErrRefundAmountExceedsBalance) + } + refundAmount = requested + } + + nonce := fmt.Sprintf("%d", session.RefundNonce) + + enrichment := map[string]interface{}{ + "refundNonce": nonce, + "claims": []batchsettlement.BatchSettlementVoucherClaim{claimEntry}, + } + if !hasRequestedAmount { + // Only fill `amount` when the client omitted it; otherwise the additive + // policy would reject the overwrite. + enrichment["amount"] = refundAmount.String() + } + + if s.receiverAuthorizerSigner != nil { + network := ctx.Requirements.GetNetwork() + authSig, err := s.SignRefund(context.Background(), normalizedId, refundAmount.String(), nonce, network) + if err != nil { + return nil, fmt.Errorf("failed to sign refund: %w", err) + } + claimAuthSig, err := s.SignClaimBatch(context.Background(), []batchsettlement.BatchSettlementVoucherClaim{claimEntry}, network) + if err != nil { + return nil, fmt.Errorf("failed to sign claim batch for refund: %w", err) + } + enrichment["refundAuthorizerSignature"] = evm.BytesToHex(authSig) + enrichment["claimAuthorizerSignature"] = evm.BytesToHex(claimAuthSig) + } + + // Snapshot the pre-refund channel state for EnrichSettlementResponse, which + // adds chargedCumulativeAmount onto the post-facilitator response. + s.RememberChannelSnapshot(ctx.Payload, session) + + return enrichment, nil +} + +// AfterSettleHook returns a hook that updates local session state after the +// facilitator settles. Pure state-update — Result.Extra is NOT mutated here; +// EnrichSettlementResponse runs after this hook and additively adds the +// server-owned `chargedCumulativeAmount` (and `chargedAmount` for deposits). +// +// For deposits: read the facilitator's channelState snapshot, compute +// chargedCumulativeAmount = current + requirements.amount, store the new +// session state, and remember the channel snapshot so EnrichSettlementResponse +// can echo chargedCumulativeAmount back to the client. +// +// For refunds: read the facilitator's post-refund channelState, store the +// updated session (or delete on full-refund when balance <= chargedCumulative). +// +// For vouchers: state was already updated in BeforeSettleHook; nothing to do. +func (s *BatchSettlementEvmScheme) AfterSettleHook() x402.AfterSettleHook { + return func(ctx x402.SettleResultContext) error { + if ctx.Requirements.GetScheme() != batchsettlement.SchemeBatched { + return nil + } + if ctx.Result == nil || !ctx.Result.Success { + return nil + } + + payload := ctx.Payload.GetPayload() + + // --- Deposit: storage update from facilitator channelState --- + if batchsettlement.IsDepositPayload(payload) { + dp, parseErr := batchsettlement.DepositPayloadFromMap(payload) + if parseErr != nil { + log.Printf("[batched] AfterSettle deposit: parse payload failed: %v", parseErr) + return nil //nolint:nilerr // parse failure in after-hook is non-fatal + } + normalizedId := batchsettlement.NormalizeChannelId(dp.Voucher.ChannelId) + rc := s.ReadRequestContext(ctx.Payload) + var pendingId string + if rc != nil { + pendingId = rc.PendingId + } + + // Read channelState from facilitator response. + cs := readChannelStateFromExtra(ctx.Result.Extra) + now := time.Now().UnixMilli() + reqAmount, _ := new(big.Int).SetString(ctx.Requirements.GetAmount(), 10) + if reqAmount == nil { + reqAmount = big.NewInt(0) + } + + updateRes, updateErr := s.storage.UpdateChannel(normalizedId, func(current *ChannelSession) *ChannelSession { + if current == nil { + return current + } + if pendingId == "" || current.PendingRequest == nil || + current.PendingRequest.PendingId != pendingId { + return current + } + curCharged, _ := new(big.Int).SetString(current.ChargedCumulativeAmount, 10) + if curCharged == nil { + curCharged = big.NewInt(0) + } + next := *current + next.ChannelConfig = dp.ChannelConfig + next.ChargedCumulativeAmount = new(big.Int).Add(curCharged, reqAmount).String() + next.SignedMaxClaimable = dp.Voucher.MaxClaimableAmount + next.Signature = dp.Voucher.Signature + if cs != nil { + if cs.Balance != "" { + next.Balance = cs.Balance + } + if cs.TotalClaimed != "" { + next.TotalClaimed = cs.TotalClaimed + } + if cs.WithdrawRequestedAt != 0 { + next.WithdrawRequestedAt = cs.WithdrawRequestedAt + } + if cs.RefundNonce != "" { + if n, ok := new(big.Int).SetString(cs.RefundNonce, 10); ok { + next.RefundNonce = int(n.Int64()) + } + } + } + next.OnchainSyncedAt = now + next.LastRequestTimestamp = now + next.PendingRequest = nil + return &next + }) + if updateErr != nil { + return updateErr + } + if updateRes.Status == ChannelUpdated && updateRes.Channel != nil { + // Snapshot for EnrichSettlementResponse to read + // chargedCumulativeAmount additively into the response. + s.RememberChannelSnapshot(ctx.Payload, updateRes.Channel) + } + return nil + } + + // --- Refund: storage update from facilitator post-refund snapshot --- + if batchsettlement.IsEnrichedRefundPayload(payload) { + refundPayload, err := batchsettlement.EnrichedRefundPayloadFromMap(payload) + if err != nil { + log.Printf("[batched] AfterSettle refund: parse payload failed: %v", err) + return nil //nolint:nilerr // parse failure in after-hook is non-fatal + } + channelId, err := batchsettlement.ComputeChannelId(refundPayload.ChannelConfig, ctx.Requirements.GetNetwork()) + if err != nil { + log.Printf("[batched] AfterSettle refund: ComputeChannelId failed: %v", err) + return nil //nolint:nilerr + } + normalizedId := batchsettlement.NormalizeChannelId(channelId) + rc := s.ReadRequestContext(ctx.Payload) + var pendingId string + if rc != nil { + pendingId = rc.PendingId + } + + snapshot := readChannelStateFromExtra(ctx.Result.Extra) + if snapshot == nil { + return nil + } + now := time.Now().UnixMilli() + outcome := "" + + _, updateErr := s.storage.UpdateChannel(normalizedId, func(current *ChannelSession) *ChannelSession { + if current == nil { + outcome = "missing" + return current + } + if pendingId == "" || current.PendingRequest == nil || + current.PendingRequest.PendingId != pendingId { + outcome = "pending_mismatch" + return current + } + postBalance, _ := new(big.Int).SetString(snapshot.Balance, 10) + if postBalance == nil { + postBalance = big.NewInt(0) + } + curCharged, _ := new(big.Int).SetString(current.ChargedCumulativeAmount, 10) + if curCharged == nil { + curCharged = big.NewInt(0) + } + if postBalance.Cmp(curCharged) <= 0 { + // Full refund: delete the channel session. + outcome = "deleted" + return nil + } + next := *current + if snapshot.Balance != "" { + next.Balance = snapshot.Balance + } + if snapshot.TotalClaimed != "" { + next.TotalClaimed = snapshot.TotalClaimed + } + if snapshot.WithdrawRequestedAt != 0 { + next.WithdrawRequestedAt = snapshot.WithdrawRequestedAt + } + if snapshot.RefundNonce != "" { + if n, ok := new(big.Int).SetString(snapshot.RefundNonce, 10); ok { + next.RefundNonce = int(n.Int64()) + } + } + next.OnchainSyncedAt = now + next.LastRequestTimestamp = now + next.PendingRequest = nil + outcome = "updated" + return &next + }) + if updateErr != nil { + return updateErr + } + if outcome == "pending_mismatch" { + return errors.New(batchsettlement.ErrChannelBusy) + } + return nil + } + + return nil + } +} + +// EnrichSettlementResponse supplies server-owned settlement-response fields +// after the facilitator settles. Returns the additive +// `{channelState: {chargedCumulativeAmount}, chargedAmount?}` map so the +// framework can deep-merge it into result.extra without overwriting the +// channelState.{balance,totalClaimed,...} fields the facilitator already +// populated. +// +// The snapshot is set by EnrichSettlementPayload (refund) or by +// AfterSettleHook (deposit) via RememberChannelSnapshot. +func (s *BatchSettlementEvmScheme) EnrichSettlementResponse(ctx x402.SettleResultContext) (map[string]interface{}, error) { + if ctx.Requirements.GetScheme() != batchsettlement.SchemeBatched { + return nil, nil + } + payload := ctx.Payload.GetPayload() + if batchsettlement.IsVoucherPayload(payload) { + return nil, nil + } + channel := s.TakeChannelSnapshot(ctx.Payload) + if channel == nil { + return nil, nil + } + out := map[string]interface{}{ + "channelState": map[string]interface{}{ + "chargedCumulativeAmount": channel.ChargedCumulativeAmount, + }, + } + if batchsettlement.IsDepositPayload(payload) { + out["chargedAmount"] = ctx.Requirements.GetAmount() + } + return out, nil +} + +// readChannelStateFromExtra extracts the nested channelState map from a +// settle-response extra. Returns nil when absent or wrong-typed. +func readChannelStateFromExtra(extra map[string]interface{}) *batchsettlement.BatchSettlementChannelStateExtra { + if extra == nil { + return nil + } + raw, ok := extra["channelState"].(map[string]interface{}) + if !ok { + return nil + } + out := &batchsettlement.BatchSettlementChannelStateExtra{} + if v, ok := raw["channelId"].(string); ok { + out.ChannelId = v + } + if v, ok := raw["balance"].(string); ok { + out.Balance = v + } else if v, ok := raw["balance"].(float64); ok { + out.Balance = fmt.Sprintf("%.0f", v) + } + if v, ok := raw["totalClaimed"].(string); ok { + out.TotalClaimed = v + } else if v, ok := raw["totalClaimed"].(float64); ok { + out.TotalClaimed = fmt.Sprintf("%.0f", v) + } + if v, ok := raw["withdrawRequestedAt"].(float64); ok { + out.WithdrawRequestedAt = int(v) + } else if v, ok := raw["withdrawRequestedAt"].(int); ok { + out.WithdrawRequestedAt = v + } + if v, ok := raw["refundNonce"].(string); ok { + out.RefundNonce = v + } else if v, ok := raw["refundNonce"].(float64); ok { + out.RefundNonce = fmt.Sprintf("%.0f", v) + } + return out +} + +// mapStringField extracts a string field from a map with a default. +func mapStringField(m map[string]interface{}, key string, defaultVal string) string { + if m == nil { + return defaultVal + } + if v, ok := m[key].(string); ok { + return v + } + if v, ok := m[key].(float64); ok { + return fmt.Sprintf("%.0f", v) + } + return defaultVal +} + +// mapIntField extracts an int field from a map with a default. +func mapIntField(m map[string]interface{}, key string, defaultVal int) int { + if m == nil { + return defaultVal + } + switch v := m[key].(type) { + case float64: + return int(v) + case int: + return v + case string: + n, _ := new(big.Int).SetString(v, 10) + if n != nil { + return int(n.Int64()) + } + } + return defaultVal +} diff --git a/go/mechanisms/evm/batch-settlement/server/hooks_test.go b/go/mechanisms/evm/batch-settlement/server/hooks_test.go new file mode 100644 index 0000000000..e34fff8e18 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/server/hooks_test.go @@ -0,0 +1,913 @@ +package server + +import ( + "context" + "testing" + "time" + + x402 "github.com/x402-foundation/x402/go" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// stubPayload satisfies types.PaymentPayloadView with a mutable underlying map. +type stubPayload struct{ data map[string]interface{} } + +func (s *stubPayload) GetVersion() int { return 2 } +func (s *stubPayload) GetScheme() string { return batchsettlement.SchemeBatched } +func (s *stubPayload) GetNetwork() string { return "eip155:8453" } +func (s *stubPayload) GetPayload() map[string]interface{} { return s.data } + +type stubRequirements struct { + scheme string + network string + asset string + amount string +} + +func (s stubRequirements) GetScheme() string { return s.scheme } +func (s stubRequirements) GetNetwork() string { return s.network } +func (s stubRequirements) GetAsset() string { return s.asset } +func (s stubRequirements) GetAmount() string { return s.amount } +func (s stubRequirements) GetPayTo() string { return "" } +func (s stubRequirements) GetMaxTimeoutSeconds() int { return 60 } +func (s stubRequirements) GetExtra() map[string]interface{} { return nil } + +func batchedReqs() stubRequirements { + return stubRequirements{scheme: batchsettlement.SchemeBatched, network: "eip155:8453", amount: "10"} +} + +func voucherPayload(channelId, maxClaimable, sig string) map[string]interface{} { + return map[string]interface{}{ + "type": "voucher", + "channelConfig": batchsettlement.ChannelConfigToMap(testConfig()), + "voucher": map[string]interface{}{ + "channelId": channelId, + "maxClaimableAmount": maxClaimable, + "signature": sig, + }, + } +} + +func refundPayload(channelId, maxClaimable, sig string) map[string]interface{} { + return map[string]interface{}{ + "type": "refund", + "channelConfig": batchsettlement.ChannelConfigToMap(testConfig()), + "voucher": map[string]interface{}{ + "channelId": channelId, + "maxClaimableAmount": maxClaimable, + "signature": sig, + }, + } +} + +func depositPayloadFor(channelId, maxClaimable, sig string) map[string]interface{} { + cfg := testConfig() + return map[string]interface{}{ + "type": "deposit", + "channelConfig": batchsettlement.ChannelConfigToMap(cfg), + "deposit": map[string]interface{}{ + "amount": "1000", + "authorization": map[string]interface{}{}, + }, + "voucher": map[string]interface{}{ + "channelId": channelId, + "maxClaimableAmount": maxClaimable, + "signature": sig, + }, + } +} + +func testConfig() batchsettlement.ChannelConfig { + return batchsettlement.ChannelConfig{ + Payer: "0x1111111111111111111111111111111111111111", + PayerAuthorizer: "0x2222222222222222222222222222222222222222", + Receiver: "0x3333333333333333333333333333333333333333", + ReceiverAuthorizer: "0xauth", + Token: "0x5555555555555555555555555555555555555555", + WithdrawDelay: 900, + Salt: "0x01", + } +} + +// ----- BeforeVerifyHook ----- + +func TestBeforeVerifyHook_NonBatchedSchemeIgnored(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + req := batchedReqs() + req.scheme = "exact" + res, err := s.BeforeVerifyHook()(x402.VerifyContext{ + Payload: &stubPayload{data: map[string]interface{}{}}, + Requirements: req, + }) + if err != nil || res != nil { + t.Fatalf("expected pass-through, got %v / %v", res, err) + } +} + +func TestBeforeVerifyHook_NonVoucherIgnored(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + res, err := s.BeforeVerifyHook()(x402.VerifyContext{ + Payload: &stubPayload{data: map[string]interface{}{"type": "deposit"}}, + Requirements: batchedReqs(), + }) + if err != nil || res != nil { + t.Fatalf("expected pass-through, got %v / %v", res, err) + } +} + +func TestBeforeVerifyHook_RefundWithoutSessionPassesThrough(t *testing.T) { + // When no local session exists for a refund voucher, BeforeVerify must + // pass through so the facilitator can verify against onchain state and + // AfterVerify can rebuild the session. + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + res, err := s.BeforeVerifyHook()(x402.VerifyContext{ + Payload: &stubPayload{data: refundPayload("0xabcd", "0", "0xsig")}, + Requirements: batchedReqs(), + }) + if err != nil || res != nil { + t.Fatalf("expected pass-through, got %+v / %v", res, err) + } +} + +func TestBeforeVerifyHook_NoSessionNonRefundPasses(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + res, err := s.BeforeVerifyHook()(x402.VerifyContext{ + Payload: &stubPayload{data: voucherPayload("0xabcd", "10", "0xsig")}, + Requirements: batchedReqs(), + }) + if err != nil || res != nil { + t.Fatalf("expected pass-through, got %v / %v", res, err) + } +} + +func TestBeforeVerifyHook_StaleCumulativeAborts(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xabcd", "10") + _ = s.UpdateSession("0xabcd", sess) + res, err := s.BeforeVerifyHook()(x402.VerifyContext{ + Payload: &stubPayload{data: voucherPayload("0xabcd", "999", "0xsig")}, + Requirements: batchedReqs(), + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if res == nil || !res.Abort || res.Reason != batchsettlement.ErrCumulativeAmountMismatch { + t.Fatalf("got %+v", res) + } +} + +func TestBeforeVerifyHook_StaleCumulativeCapturesSnapshot(t *testing.T) { + // When the payload is a real *types.PaymentPayload (not a stub), aborting + // must also stash the current session as a snapshot so the resource server + // can echo ChannelState in the corrective 402. + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xabcd", "10") + _ = s.UpdateSession("0xabcd", sess) + + pp := &types.PaymentPayload{ + X402Version: 2, + Payload: voucherPayload("0xabcd", "999", "0xsig"), + Accepted: types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}, + } + res, err := s.BeforeVerifyHook()(x402.VerifyContext{ + Payload: pp, + Requirements: batchedReqs(), + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if res == nil || !res.Abort { + t.Fatalf("expected abort, got %+v", res) + } + got := s.TakeChannelSnapshot(pp) + if got == nil || got.ChargedCumulativeAmount != "10" { + t.Fatalf("expected snapshot for payload, got %+v", got) + } +} + +func TestBeforeVerifyHook_FreshCumulativePasses(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xabcd", "10") + _ = s.UpdateSession("0xabcd", sess) + // expected = 10 + 10 (req amount) = 20 + res, err := s.BeforeVerifyHook()(x402.VerifyContext{ + Payload: &stubPayload{data: voucherPayload("0xabcd", "20", "0xsig")}, + Requirements: batchedReqs(), + }) + if err != nil || res != nil { + t.Fatalf("expected pass-through, got %v / %v", res, err) + } +} + +func TestBeforeVerifyHook_RefundFreshCumulativePasses(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xabcd", "10") + _ = s.UpdateSession("0xabcd", sess) + // Refund: expected = prevCharged (10), no req amount added. + res, err := s.BeforeVerifyHook()(x402.VerifyContext{ + Payload: &stubPayload{data: refundPayload("0xabcd", "10", "0xsig")}, + Requirements: batchedReqs(), + }) + if err != nil || res != nil { + t.Fatalf("expected pass-through, got %v / %v", res, err) + } +} + +func TestBeforeVerifyHook_LivePendingRejectsSameChannel(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + sess := sampleSession("0xabcd", "10") + sess.PendingRequest = &PendingRequest{PendingId: "p-live", ExpiresAt: time.Now().Add(time.Minute).UnixMilli()} + _ = s.UpdateSession("0xabcd", sess) + + res, err := s.BeforeVerifyHook()(x402.VerifyContext{ + Payload: &stubPayload{data: voucherPayload("0xabcd", "20", "0xsig")}, + Requirements: batchedReqs(), + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if res == nil || !res.Abort || res.Reason != batchsettlement.ErrChannelBusy { + t.Fatalf("got %+v", res) + } +} + +// ----- AfterVerifyHook ----- + +func TestAfterVerifyHook_NonBatchedIgnored(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + req := batchedReqs() + req.scheme = "exact" + res, err := s.AfterVerifyHook()(x402.VerifyResultContext{ + VerifyContext: x402.VerifyContext{ + Payload: &stubPayload{data: voucherPayload("0xabcd", "10", "0xsig")}, + Requirements: req, + }, + Result: &x402.VerifyResponse{IsValid: true, Payer: "0xpayer"}, + }) + if err != nil || res != nil { + t.Fatalf("expected pass-through, got %v / %v", res, err) + } +} + +func TestAfterVerifyHook_InvalidResultIgnored(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + res, err := s.AfterVerifyHook()(x402.VerifyResultContext{ + VerifyContext: x402.VerifyContext{ + Payload: &stubPayload{data: voucherPayload("0xabcd", "10", "0xsig")}, + Requirements: batchedReqs(), + }, + Result: &x402.VerifyResponse{IsValid: false}, + }) + if err != nil || res != nil { + t.Fatalf("expected pass-through, got %v / %v", res, err) + } +} + +func TestAfterVerifyHook_VoucherStoresSession(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + res, err := s.AfterVerifyHook()(x402.VerifyResultContext{ + VerifyContext: x402.VerifyContext{ + Payload: &stubPayload{data: voucherPayload("0xabcd", "10", "0xsig")}, + Requirements: batchedReqs(), + }, + Result: &x402.VerifyResponse{ + IsValid: true, Payer: "0xpayer", + Extra: map[string]interface{}{"balance": "1000", "totalClaimed": "0"}, + }, + }) + if err != nil || res != nil { + t.Fatalf("got res=%+v err=%v", res, err) + } + got, _ := s.GetSession("0xabcd") + if got == nil || got.Balance != "1000" || got.SignedMaxClaimable != "10" { + t.Fatalf("session = %+v", got) + } +} + +func TestAfterVerifyHook_DepositStoresSession(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + _, err := s.AfterVerifyHook()(x402.VerifyResultContext{ + VerifyContext: x402.VerifyContext{ + Payload: &stubPayload{data: depositPayloadFor(id, "100", "0xsig")}, + Requirements: batchedReqs(), + }, + Result: &x402.VerifyResponse{ + IsValid: true, Payer: "0xpayer", + Extra: map[string]interface{}{"balance": "1000", "totalClaimed": "0"}, + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + got, _ := s.GetSession(id) + if got == nil || got.SignedMaxClaimable != "100" { + t.Fatalf("session = %+v", got) + } +} + +func TestAfterVerifyHook_RefundReturnsSkipHandler(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + res, err := s.AfterVerifyHook()(x402.VerifyResultContext{ + VerifyContext: x402.VerifyContext{ + Payload: &stubPayload{data: refundPayload("0xabcd", "10", "0xsig")}, + Requirements: batchedReqs(), + }, + Result: &x402.VerifyResponse{ + IsValid: true, Payer: "0xpayer", + Extra: map[string]interface{}{"balance": "1000", "totalClaimed": "0"}, + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if res == nil || !res.SkipHandler || res.Response == nil { + t.Fatalf("got %+v", res) + } +} + +func TestOnVerifyFailureHook_ClearsPendingRequest(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id := "0xabcd" + sess := sampleSession(id, "10") + _ = s.UpdateSession(id, sess) + reserveDepositPending(t, s, id, "p-verify") + stub := &stubPayload{data: voucherPayload(id, "20", "0xsig")} + s.MergeRequestContext(stub, BatchSettlementRequestContext{ChannelId: id, PendingId: "p-verify", ChannelSnapshot: sess}) + + res, err := s.OnVerifyFailureHook()(x402.VerifyFailureContext{ + VerifyContext: x402.VerifyContext{Payload: stub, Requirements: batchedReqs()}, + }) + if err != nil || res != nil { + t.Fatalf("got res=%+v err=%v", res, err) + } + got, _ := s.GetSession(id) + if got == nil || got.PendingRequest != nil { + t.Fatalf("pending not cleared: %+v", got) + } +} + +// ----- BeforeSettleHook ----- + +// TestBeforeSettleHook_DepositPassThrough pins the new BeforeSettleHook +// behavior for deposits: pass through to the facilitator with no payload +// mutation. Server-owned deposit enrichment lives in EnrichSettlementResponse +// (which adds chargedCumulativeAmount + chargedAmount additively post-settle). +func TestBeforeSettleHook_DepositPassThrough(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + _ = s.UpdateSession(id, sampleSession(id, "5")) + payload := depositPayloadFor(id, "100", "0xsig") + res, err := s.BeforeSettleHook()(x402.SettleContext{ + Payload: &stubPayload{data: payload}, + Requirements: batchedReqs(), + }) + if err != nil || res != nil { + t.Fatalf("got %v / %v", res, err) + } + if _, ok := payload["responseExtra"]; ok { + t.Fatalf("BeforeSettleHook must not annotate responseExtra anymore: %+v", payload) + } +} + +func TestBeforeSettleHook_VoucherWithoutSessionAborts(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + res, err := s.BeforeSettleHook()(x402.SettleContext{ + Payload: &stubPayload{data: voucherPayload("0xabcd", "10", "0xsig")}, + Requirements: batchedReqs(), + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if res == nil || !res.Abort || res.Reason != batchsettlement.ErrMissingChannel { + t.Fatalf("got %+v", res) + } +} + +func TestBeforeSettleHook_VoucherSkipsAndUpdates(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + _ = s.UpdateSession("0xabcd", sampleSession("0xabcd", "10")) + stub := &stubPayload{data: voucherPayload("0xabcd", "20", "0xsig")} + if _, err := s.BeforeVerifyHook()(x402.VerifyContext{Payload: stub, Requirements: batchedReqs()}); err != nil { + t.Fatalf("setup verify: %v", err) + } + res, err := s.BeforeSettleHook()(x402.SettleContext{ + Payload: stub, + Requirements: batchedReqs(), + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if res == nil || !res.Skip || res.SkipResult == nil || !res.SkipResult.Success { + t.Fatalf("got %+v", res) + } + got, _ := s.GetSession("0xabcd") + if got == nil || got.ChargedCumulativeAmount != "20" { + t.Fatalf("session not updated: %+v", got) + } +} + +func TestBeforeSettleHook_VoucherExceedsSignedCapAborts(t *testing.T) { + // Simulate chargedCumulativeAmount changing after reservation. + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + _ = s.UpdateSession("0xabcd", sampleSession("0xabcd", "10")) + stub := &stubPayload{data: voucherPayload("0xabcd", "20", "0xsig")} + if _, err := s.BeforeVerifyHook()(x402.VerifyContext{Payload: stub, Requirements: batchedReqs()}); err != nil { + t.Fatalf("setup verify: %v", err) + } + cur, _ := s.GetSession("0xabcd") + cur.ChargedCumulativeAmount = "15" + _ = s.UpdateSession("0xabcd", cur) + res, err := s.BeforeSettleHook()(x402.SettleContext{ + Payload: stub, + Requirements: batchedReqs(), + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if res == nil || !res.Abort || res.Reason != batchsettlement.ErrChargeExceedsSignedCumulative { + t.Fatalf("got %+v", res) + } +} + +// reserveRefundPending sets a pending request on the session so +// EnrichSettlementPayload's pending-id guard passes. Mirrors the way +// BeforeVerifyHook normally provisions the reservation in production flows. +func reserveRefundPending(t *testing.T, s *BatchSettlementEvmScheme, id, pendingId, signedMax, sig string) { + t.Helper() + sess, _ := s.GetSession(id) + if sess == nil { + t.Fatalf("expected session for %s", id) + } + sess.SignedMaxClaimable = signedMax + sess.Signature = sig + sess.PendingRequest = &PendingRequest{PendingId: pendingId, ExpiresAt: time.Now().Add(time.Minute).UnixMilli()} + _ = s.UpdateSession(id, sess) +} + +// TestEnrichSettlementPayload_RefundReturnsAdditiveFields pins the new +// EnrichSettlementPayload behavior for refund payloads: returns additive +// `{amount, refundNonce, claims}` (plus signatures when an authorizer signer +// is configured) and never mutates the input payload. +func TestEnrichSettlementPayload_RefundReturnsAdditiveFields(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + sess := sampleSession(id, "10") + sess.ChannelConfig = testConfig() + sess.Balance = "1000" + _ = s.UpdateSession(id, sess) + reserveRefundPending(t, s, id, "p-refund", "10", "0xsig") + payload := refundPayload(id, "10", "0xsig") + stub := &stubPayload{data: payload} + s.MergeRequestContext(stub, BatchSettlementRequestContext{ChannelId: id, PendingId: "p-refund"}) + + out, err := s.EnrichSettlementPayload(x402.SettleContext{ + Payload: stub, + Requirements: batchedReqs(), + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if out["refundNonce"] == nil || out["claims"] == nil { + t.Fatalf("missing additive fields: %+v", out) + } + // Original payload must NOT be mutated by EnrichSettlementPayload. + if _, exists := payload["claims"]; exists { + t.Fatalf("EnrichSettlementPayload mutated input payload: %+v", payload) + } +} + +func TestEnrichSettlementPayload_RefundNoBalanceErrors(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + sess := sampleSession(id, "1000") + sess.ChannelConfig = testConfig() + sess.Balance = "1000" + _ = s.UpdateSession(id, sess) + reserveRefundPending(t, s, id, "p-refund", "1000", "0xsig") + stub := &stubPayload{data: refundPayload(id, "1000", "0xsig")} + s.MergeRequestContext(stub, BatchSettlementRequestContext{ChannelId: id, PendingId: "p-refund"}) + + _, err := s.EnrichSettlementPayload(x402.SettleContext{Payload: stub, Requirements: batchedReqs()}) + if err == nil || err.Error() != batchsettlement.ErrRefundNoBalance { + t.Fatalf("got %v", err) + } +} + +func TestEnrichSettlementPayload_RefundAmountInvalidErrors(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + sess := sampleSession(id, "10") + sess.ChannelConfig = testConfig() + sess.Balance = "1000" + _ = s.UpdateSession(id, sess) + reserveRefundPending(t, s, id, "p-refund", "10", "0xsig") + payload := refundPayload(id, "10", "0xsig") + payload["amount"] = "not-a-number" + stub := &stubPayload{data: payload} + s.MergeRequestContext(stub, BatchSettlementRequestContext{ChannelId: id, PendingId: "p-refund"}) + + _, err := s.EnrichSettlementPayload(x402.SettleContext{Payload: stub, Requirements: batchedReqs()}) + if err == nil || err.Error() != batchsettlement.ErrRefundAmountInvalid { + t.Fatalf("got %v", err) + } +} + +func TestEnrichSettlementPayload_RefundAmountExceedsRemainderErrors(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + sess := sampleSession(id, "10") + sess.ChannelConfig = testConfig() + sess.Balance = "1000" + _ = s.UpdateSession(id, sess) + reserveRefundPending(t, s, id, "p-refund", "10", "0xsig") + payload := refundPayload(id, "10", "0xsig") + payload["amount"] = "9999" + stub := &stubPayload{data: payload} + s.MergeRequestContext(stub, BatchSettlementRequestContext{ChannelId: id, PendingId: "p-refund"}) + + _, err := s.EnrichSettlementPayload(x402.SettleContext{Payload: stub, Requirements: batchedReqs()}) + if err == nil || err.Error() != batchsettlement.ErrRefundAmountExceedsBalance { + t.Fatalf("got %v", err) + } +} + +func TestOnSettleFailureHook_ClearsPendingRequest(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id := "0xabcd" + sess := sampleSession(id, "10") + _ = s.UpdateSession(id, sess) + reserveDepositPending(t, s, id, "p-settle") + stub := &stubPayload{data: voucherPayload(id, "20", "0xsig")} + s.MergeRequestContext(stub, BatchSettlementRequestContext{ChannelId: id, PendingId: "p-settle", ChannelSnapshot: sess}) + + res, err := s.OnSettleFailureHook()(x402.SettleFailureContext{ + SettleContext: x402.SettleContext{Payload: stub, Requirements: batchedReqs()}, + }) + if err != nil || res != nil { + t.Fatalf("got res=%+v err=%v", res, err) + } + got, _ := s.GetSession(id) + if got == nil || got.PendingRequest != nil { + t.Fatalf("pending not cleared: %+v", got) + } +} + +// ----- AfterSettleHook ----- + +func TestAfterSettleHook_NonBatchedIgnored(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + req := batchedReqs() + req.scheme = "exact" + err := s.AfterSettleHook()(x402.SettleResultContext{ + SettleContext: x402.SettleContext{ + Payload: &stubPayload{data: depositPayloadFor("0xabcd", "100", "0xsig")}, + Requirements: req, + }, + Result: &x402.SettleResponse{Success: true}, + }) + if err != nil { + t.Fatalf("err: %v", err) + } +} + +func TestAfterSettleHook_FailedResultIgnored(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + err := s.AfterSettleHook()(x402.SettleResultContext{ + SettleContext: x402.SettleContext{ + Payload: &stubPayload{data: depositPayloadFor("0xabcd", "100", "0xsig")}, + Requirements: batchedReqs(), + }, + Result: &x402.SettleResponse{Success: false}, + }) + if err != nil { + t.Fatalf("err: %v", err) + } +} + +// reserveDepositPending puts a pending reservation on the session so the +// new AfterSettleHook (which gates on matching pendingId before applying +// the on-chain snapshot) accepts the update. +func reserveDepositPending(t *testing.T, s *BatchSettlementEvmScheme, id, pendingId string) { + t.Helper() + sess, _ := s.GetSession(id) + if sess == nil { + t.Fatalf("expected session for %s", id) + } + sess.PendingRequest = &PendingRequest{PendingId: pendingId, ExpiresAt: time.Now().Add(time.Minute).UnixMilli()} + _ = s.UpdateSession(id, sess) +} + +func TestAfterSettleHook_DepositUpdatesBalance(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + _ = s.UpdateSession(id, sampleSession(id, "0")) + reserveDepositPending(t, s, id, "p-deposit") + payload := depositPayloadFor(id, "100", "0xsig") + stub := &stubPayload{data: payload} + s.MergeRequestContext(stub, BatchSettlementRequestContext{ChannelId: id, PendingId: "p-deposit"}) + // reqAmount is 10 (from batchedReqs); current charged is 0 → expected 10. + err := s.AfterSettleHook()(x402.SettleResultContext{ + SettleContext: x402.SettleContext{ + Payload: stub, + Requirements: batchedReqs(), + }, + Result: &x402.SettleResponse{ + Success: true, + Extra: map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": id, + "balance": "2000", + "totalClaimed": "0", + }, + }, + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + got, _ := s.GetSession(id) + if got == nil || got.Balance != "2000" || got.ChargedCumulativeAmount != "10" { + t.Fatalf("session = %+v", got) + } +} + +// Regression: after a successful deposit settle, the AfterSettleHook must +// clear PendingRequest. Otherwise the next voucher hits the 5s pending-TTL +// guard in BeforeVerifyHook and 402's with `invalid_batch_settlement_evm_channel_busy`. +func TestAfterSettleHook_DepositClearsPendingRequest(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + _ = s.UpdateSession(id, sampleSession(id, "0")) + reserveDepositPending(t, s, id, "p-deposit") + payload := depositPayloadFor(id, "100", "0xsig") + stub := &stubPayload{data: payload} + s.MergeRequestContext(stub, BatchSettlementRequestContext{ChannelId: id, PendingId: "p-deposit"}) + err := s.AfterSettleHook()(x402.SettleResultContext{ + SettleContext: x402.SettleContext{ + Payload: stub, + Requirements: batchedReqs(), + }, + Result: &x402.SettleResponse{ + Success: true, + Extra: map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": id, + "balance": "2000", + "totalClaimed": "0", + }, + }, + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + got, _ := s.GetSession(id) + if got == nil { + t.Fatal("session unexpectedly missing after deposit AfterSettle") + } + if got.PendingRequest != nil { + t.Fatalf("PendingRequest not cleared after deposit settle: %+v", got.PendingRequest) + } +} + +func TestAfterSettleHook_RefundFullDeletes(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + sess := sampleSession(id, "100") + sess.ChannelConfig = testConfig() + sess.Balance = "1000" + _ = s.UpdateSession(id, sess) + reserveDepositPending(t, s, id, "p-refund") + // Refund the full remainder: post-refund balance == chargedCumulative → delete. + rp := map[string]interface{}{ + "type": "refund", + "channelConfig": batchsettlement.ChannelConfigToMap(testConfig()), + "voucher": map[string]interface{}{ + "channelId": id, + "maxClaimableAmount": "100", + "signature": "0xsig", + }, + "amount": "900", + "refundNonce": "0", + "claims": []interface{}{}, + } + stub := &stubPayload{data: rp} + s.MergeRequestContext(stub, BatchSettlementRequestContext{ChannelId: id, PendingId: "p-refund"}) + err := s.AfterSettleHook()(x402.SettleResultContext{ + SettleContext: x402.SettleContext{ + Payload: stub, + Requirements: batchedReqs(), + }, + Result: &x402.SettleResponse{ + Success: true, + Extra: map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": id, + "balance": "100", // post-refund: equals chargedCumulative → delete + "totalClaimed": "100", + "refundNonce": "1", + }, + }, + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if got, _ := s.GetSession(id); got != nil { + t.Fatalf("expected nil after full refund, got %+v", got) + } +} + +func TestAfterSettleHook_RefundFullDeletesAfterPayloadEnrichment(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + sess := sampleSession(id, "100") + sess.ChannelConfig = testConfig() + sess.Balance = "1000" + _ = s.UpdateSession(id, sess) + pp := &types.PaymentPayload{ + X402Version: 2, + Payload: refundPayload(id, "100", "0xsig"), + Accepted: types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}, + } + + res, err := s.BeforeVerifyHook()(x402.VerifyContext{Payload: pp, Requirements: batchedReqs()}) + if err != nil || res != nil { + t.Fatalf("reserve got %+v / %v", res, err) + } + pp.Payload["amount"] = "900" + pp.Payload["refundNonce"] = "0" + pp.Payload["claims"] = []interface{}{} + + err = s.AfterSettleHook()(x402.SettleResultContext{ + SettleContext: x402.SettleContext{ + Payload: pp, + Requirements: batchedReqs(), + }, + Result: &x402.SettleResponse{ + Success: true, + Extra: map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": id, + "balance": "100", + "totalClaimed": "100", + "refundNonce": "1", + }, + }, + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + if got, _ := s.GetSession(id); got != nil { + t.Fatalf("expected nil after full refund, got %+v", got) + } +} + +func TestAfterSettleHook_RefundPartialUpdates(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + sess := sampleSession(id, "100") + sess.ChannelConfig = testConfig() + sess.Balance = "1000" + sess.RefundNonce = 0 + _ = s.UpdateSession(id, sess) + reserveDepositPending(t, s, id, "p-refund") + rp := map[string]interface{}{ + "type": "refund", + "channelConfig": batchsettlement.ChannelConfigToMap(testConfig()), + "voucher": map[string]interface{}{ + "channelId": id, + "maxClaimableAmount": "100", + "signature": "0xsig", + }, + "amount": "100", + "refundNonce": "0", + "claims": []interface{}{}, + } + stub := &stubPayload{data: rp} + s.MergeRequestContext(stub, BatchSettlementRequestContext{ChannelId: id, PendingId: "p-refund"}) + err := s.AfterSettleHook()(x402.SettleResultContext{ + SettleContext: x402.SettleContext{ + Payload: stub, + Requirements: batchedReqs(), + }, + Result: &x402.SettleResponse{ + Success: true, + Extra: map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": id, + "balance": "900", // post-partial-refund balance > chargedCumulative + "totalClaimed": "100", + "refundNonce": "1", + }, + }, + }, + }) + if err != nil { + t.Fatalf("err: %v", err) + } + got, _ := s.GetSession(id) + if got == nil { + t.Fatal("expected session preserved after partial refund") + } + if got.Balance != "900" { + t.Fatalf("balance = %s", got.Balance) + } + if got.RefundNonce != 1 { + t.Fatalf("nonce = %d", got.RefundNonce) + } + if got.PendingRequest != nil { + t.Fatalf("PendingRequest not cleared after partial refund: %+v", got.PendingRequest) + } +} + +func TestAfterSettleHook_RefundPendingMismatchReturnsBusy(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + id, _ := batchsettlement.ComputeChannelId(testConfig(), "eip155:8453") + sess := sampleSession(id, "100") + sess.ChannelConfig = testConfig() + sess.Balance = "1000" + _ = s.UpdateSession(id, sess) + reserveDepositPending(t, s, id, "p-current") + rp := map[string]interface{}{ + "type": "refund", + "channelConfig": batchsettlement.ChannelConfigToMap(testConfig()), + "voucher": map[string]interface{}{ + "channelId": id, + "maxClaimableAmount": "100", + "signature": "0xsig", + }, + "amount": "100", + "refundNonce": "0", + "claims": []interface{}{}, + } + stub := &stubPayload{data: rp} + s.MergeRequestContext(stub, BatchSettlementRequestContext{ChannelId: id, PendingId: "p-stale"}) + + err := s.AfterSettleHook()(x402.SettleResultContext{ + SettleContext: x402.SettleContext{ + Payload: stub, + Requirements: batchedReqs(), + }, + Result: &x402.SettleResponse{ + Success: true, + Extra: map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": id, + "balance": "900", + "totalClaimed": "100", + "refundNonce": "1", + }, + }, + }, + }) + if err == nil || err.Error() != batchsettlement.ErrChannelBusy { + t.Fatalf("got %v", err) + } +} + +// ----- helpers ----- + +func TestMapStringField(t *testing.T) { + if got := mapStringField(nil, "k", "default"); got != "default" { + t.Fatalf("nil = %s", got) + } + m := map[string]interface{}{"a": "x", "b": float64(42)} + if got := mapStringField(m, "a", "d"); got != "x" { + t.Fatalf("string = %s", got) + } + if got := mapStringField(m, "b", "d"); got != "42" { + t.Fatalf("float = %s", got) + } + if got := mapStringField(m, "c", "d"); got != "d" { + t.Fatalf("missing = %s", got) + } +} + +func TestMapIntField(t *testing.T) { + if got := mapIntField(nil, "k", 7); got != 7 { + t.Fatalf("nil = %d", got) + } + m := map[string]interface{}{"a": float64(1), "b": int(2), "c": "3", "d": "nope"} + if got := mapIntField(m, "a", 0); got != 1 { + t.Fatalf("float = %d", got) + } + if got := mapIntField(m, "b", 0); got != 2 { + t.Fatalf("int = %d", got) + } + if got := mapIntField(m, "c", 0); got != 3 { + t.Fatalf("string = %d", got) + } + if got := mapIntField(m, "d", 99); got != 99 { + t.Fatalf("bad string fallback = %d", got) + } + if got := mapIntField(m, "missing", 5); got != 5 { + t.Fatalf("missing = %d", got) + } +} + +// Avoid unused-import error from context import. +var _ = context.Background diff --git a/go/mechanisms/evm/batch-settlement/server/scheme.go b/go/mechanisms/evm/batch-settlement/server/scheme.go new file mode 100644 index 0000000000..8042e43e56 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/server/scheme.go @@ -0,0 +1,759 @@ +package server + +import ( + "context" + "errors" + "fmt" + "math/big" + "strconv" + "strings" + "sync" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// BatchSettlementRequestContext carries per-request state across the verify->settle +// lifecycle for a single payment. +type BatchSettlementRequestContext struct { + ChannelId string + PendingId string + ChannelSnapshot *ChannelSession + LocalVerify bool +} + +const ( + ErrAmountMustBeString = "amount must be a string for batched scheme" + ErrAssetAddressRequired = "asset address is required for batched scheme" + ErrFailedToParsePrice = "failed to parse price" + ErrUnsupportedPriceType = "unsupported price type" + ErrFailedToConvertAmt = "failed to convert amount" + ErrNoAssetSpecified = "no asset specified for batched scheme" + ErrFailedToParseAmount = "failed to parse amount" +) + +// AuthorizerSigner is the interface for the server-controlled receiverAuthorizer key. +// Used for signing refund and claim batch authorizations. +type AuthorizerSigner interface { + Address() string + SignTypedData(ctx context.Context, domain evm.TypedDataDomain, types map[string][]evm.TypedDataField, primaryType string, message map[string]interface{}) ([]byte, error) +} + +// BatchSettlementEvmSchemeServerConfig configures the batched server scheme. +type BatchSettlementEvmSchemeServerConfig struct { + // Storage is the session persistence backend. Defaults to in-memory. + Storage SessionStorage + // ReceiverAuthorizerSigner is the server-controlled key for signing refund/claim authorizations. + ReceiverAuthorizerSigner AuthorizerSigner + // WithdrawDelay is the withdraw delay in seconds. Defaults to 900 (15 min). + WithdrawDelay int + // OnchainStateTtlMs is the maximum age of cached onchain state, in + // milliseconds, that may be trusted for local voucher verification. + // When zero, derived from WithdrawDelay (clamped between 30s and 5min). + OnchainStateTtlMs int64 +} + +// BatchSettlementEvmScheme implements SchemeNetworkServer for batched settlement. +type BatchSettlementEvmScheme struct { + receiverAddress string + storage SessionStorage + receiverAuthorizerSigner AuthorizerSigner + withdrawDelay int + onchainStateTtlMs int64 + moneyParsers []x402.MoneyParser + + // requestContexts maps a per-payment key to state carried across verify and + // settle hooks. + requestContextsMu sync.Mutex + requestContexts map[string]*BatchSettlementRequestContext +} + +// requestContextKey returns a payment identity that stays stable when server +// enrichment adds settlement-only fields to the payload. +func requestContextKey(payload any) string { + if payload == nil { + return "" + } + if view, ok := payload.(x402.PaymentPayloadView); ok { + payloadMap := view.GetPayload() + payloadType, _ := payloadMap["type"].(string) + voucher, _ := payloadMap["voucher"].(map[string]interface{}) + channelId, _ := voucher["channelId"].(string) + maxClaimable, _ := voucher["maxClaimableAmount"].(string) + signature, _ := voucher["signature"].(string) + return strings.Join([]string{ + strconv.Itoa(view.GetVersion()), + view.GetScheme(), + view.GetNetwork(), + payloadType, + batchsettlement.NormalizeChannelId(channelId), + maxClaimable, + signature, + channelConfigKey(payloadMap["channelConfig"]), + }, "\x00") + } + return fmt.Sprintf("%p", payload) +} + +func channelConfigKey(raw any) string { + switch cfg := raw.(type) { + case batchsettlement.ChannelConfig: + return formatChannelConfigKey(cfg) + case *batchsettlement.ChannelConfig: + if cfg == nil { + return "" + } + return formatChannelConfigKey(*cfg) + case map[string]interface{}: + parsed, err := batchsettlement.ChannelConfigFromMap(cfg) + if err != nil { + return "" + } + return formatChannelConfigKey(parsed) + default: + return "" + } +} + +func formatChannelConfigKey(cfg batchsettlement.ChannelConfig) string { + return strings.Join([]string{ + strings.ToLower(cfg.Payer), + strings.ToLower(cfg.PayerAuthorizer), + strings.ToLower(cfg.Receiver), + strings.ToLower(cfg.ReceiverAuthorizer), + strings.ToLower(cfg.Token), + strconv.Itoa(cfg.WithdrawDelay), + cfg.Salt, + }, "\x00") +} + +// NewBatchSettlementEvmScheme creates a new batched server scheme. +func NewBatchSettlementEvmScheme(receiverAddress string, config *BatchSettlementEvmSchemeServerConfig) *BatchSettlementEvmScheme { + storage := SessionStorage(nil) + var authSigner AuthorizerSigner + withdrawDelay := batchsettlement.MinWithdrawDelay + var onchainStateTtlMs int64 + + if config != nil { + storage = config.Storage + authSigner = config.ReceiverAuthorizerSigner + if config.WithdrawDelay > 0 { + withdrawDelay = config.WithdrawDelay + } + onchainStateTtlMs = config.OnchainStateTtlMs + } + + if onchainStateTtlMs <= 0 { + onchainStateTtlMs = defaultOnchainStateTtlMs(withdrawDelay) + } + + if storage == nil { + storage = NewInMemoryChannelStorage() + } + + return &BatchSettlementEvmScheme{ + receiverAddress: receiverAddress, + storage: storage, + receiverAuthorizerSigner: authSigner, + withdrawDelay: withdrawDelay, + onchainStateTtlMs: onchainStateTtlMs, + moneyParsers: []x402.MoneyParser{}, + requestContexts: make(map[string]*BatchSettlementRequestContext), + } +} + +// GetOnchainStateTtlMs returns the configured TTL (in ms) for trusting cached +// onchain channel state for local voucher verification. +func (s *BatchSettlementEvmScheme) GetOnchainStateTtlMs() int64 { + return s.onchainStateTtlMs +} + +// defaultOnchainStateTtlMs derives a reasonable TTL from the channel withdraw +// delay: WithdrawDelay/3, clamped to [30s, 5min]. +func defaultOnchainStateTtlMs(withdrawDelaySeconds int) int64 { + if withdrawDelaySeconds < 0 { + withdrawDelaySeconds = 0 + } + withdrawDelayMs := int64(withdrawDelaySeconds) * 1000 + ttl := withdrawDelayMs / 3 + const minTtl = int64(30 * 1000) + const maxTtl = int64(5 * 60 * 1000) + if ttl < minTtl { + ttl = minTtl + } + if ttl > maxTtl { + ttl = maxTtl + } + return ttl +} + +// MergeRequestContext merges fields into the per-payload request context, +// creating one if none exists. +func (s *BatchSettlementEvmScheme) MergeRequestContext(payload any, partial BatchSettlementRequestContext) { + key := requestContextKey(payload) + if key == "" { + return + } + s.requestContextsMu.Lock() + defer s.requestContextsMu.Unlock() + merged := BatchSettlementRequestContext{} + if cur := s.requestContexts[key]; cur != nil { + merged = *cur + } + if partial.ChannelId != "" { + merged.ChannelId = partial.ChannelId + } + if partial.PendingId != "" { + merged.PendingId = partial.PendingId + } + if partial.ChannelSnapshot != nil { + merged.ChannelSnapshot = partial.ChannelSnapshot + } + if partial.LocalVerify { + merged.LocalVerify = true + } + s.requestContexts[key] = &merged +} + +// ReadRequestContext returns the per-payload request context without clearing it. +func (s *BatchSettlementEvmScheme) ReadRequestContext(payload any) *BatchSettlementRequestContext { + key := requestContextKey(payload) + if key == "" { + return nil + } + s.requestContextsMu.Lock() + defer s.requestContextsMu.Unlock() + return s.requestContexts[key] +} + +// TakeRequestContext reads and clears the per-payload request context. +func (s *BatchSettlementEvmScheme) TakeRequestContext(payload any) *BatchSettlementRequestContext { + key := requestContextKey(payload) + if key == "" { + return nil + } + s.requestContextsMu.Lock() + defer s.requestContextsMu.Unlock() + rc := s.requestContexts[key] + delete(s.requestContexts, key) + return rc +} + +// RememberChannelSnapshot stores a channel snapshot keyed to a specific payload +// so EnrichPaymentRequiredResponse can echo it in the corrective 402. +func (s *BatchSettlementEvmScheme) RememberChannelSnapshot(payload any, session *ChannelSession) { + if payload == nil || session == nil { + return + } + s.MergeRequestContext(payload, BatchSettlementRequestContext{ + ChannelId: session.ChannelId, + ChannelSnapshot: session, + }) +} + +// TakeChannelSnapshot reads and clears the channel snapshot for a payload. +func (s *BatchSettlementEvmScheme) TakeChannelSnapshot(payload any) *ChannelSession { + rc := s.TakeRequestContext(payload) + if rc == nil { + return nil + } + return rc.ChannelSnapshot +} + +// ClearPendingRequest clears this request's pending reservation in storage, +// without affecting any newer reservation that may have replaced it. If the +// stored channel only existed for this reservation (no snapshot), the channel +// record is deleted entirely. +func (s *BatchSettlementEvmScheme) ClearPendingRequest(payload any) error { + rc := s.TakeRequestContext(payload) + if rc == nil || rc.ChannelId == "" || rc.PendingId == "" { + return nil + } + _, err := s.storage.UpdateChannel(rc.ChannelId, func(current *ChannelSession) *ChannelSession { + if current == nil { + return current + } + if current.PendingRequest == nil || current.PendingRequest.PendingId != rc.PendingId { + return current + } + if rc.ChannelSnapshot == nil { + return nil // delete: this reservation is the only reason the row exists + } + next := *current + next.PendingRequest = nil + return &next + }) + return err +} + +// EnrichPaymentRequiredResponse implements x402.PaymentRequiredEnricher. +// On a cumulative-amount-mismatch verify failure it adds corrective ChannelState +// (sourced first from a BeforeVerifyHook snapshot, then from storage) to each +// matching batch-settlement requirement so the client can resync. +func (s *BatchSettlementEvmScheme) EnrichPaymentRequiredResponse(ctx x402.PaymentRequiredContext) { + if ctx.Error != batchsettlement.ErrCumulativeAmountMismatch || ctx.PaymentPayload == nil { + return + } + + channelId := extractChannelIdFromPayload(ctx.PaymentPayload.Payload) + if channelId == "" { + return + } + + var session *ChannelSession + if ctx.PaymentPayload != nil { + session = s.TakeChannelSnapshot(ctx.PaymentPayload) + } + if session == nil { + stored, err := s.storage.Get(batchsettlement.NormalizeChannelId(channelId)) + if err != nil || stored == nil { + return + } + session = stored + } + + channelStateMap := map[string]interface{}{ + "channelId": session.ChannelId, + "balance": session.Balance, + "totalClaimed": session.TotalClaimed, + "withdrawRequestedAt": session.WithdrawRequestedAt, + "refundNonce": fmt.Sprintf("%d", session.RefundNonce), + "chargedCumulativeAmount": session.ChargedCumulativeAmount, + } + voucherStateMap := map[string]interface{}{} + if session.SignedMaxClaimable != "" { + voucherStateMap["signedMaxClaimable"] = session.SignedMaxClaimable + } + if session.Signature != "" { + voucherStateMap["signature"] = session.Signature + } + + network := ctx.PaymentPayload.Accepted.Network + for i := range ctx.Requirements { + if ctx.Requirements[i].Scheme != batchsettlement.SchemeBatched { + continue + } + if ctx.Requirements[i].Network != network { + continue + } + if ctx.Requirements[i].Extra == nil { + ctx.Requirements[i].Extra = make(map[string]interface{}) + } + ctx.Requirements[i].Extra["channelState"] = channelStateMap + if len(voucherStateMap) > 0 { + ctx.Requirements[i].Extra["voucherState"] = voucherStateMap + } + } +} + +// OnVerifiedPaymentCanceledHook returns a hook that releases this request's +// pending reservation when the resource handler errors or returns a non-2xx +// response. +func (s *BatchSettlementEvmScheme) OnVerifiedPaymentCanceledHook() x402.OnVerifiedPaymentCanceledHook { + return func(ctx x402.VerifiedPaymentCanceledContext) error { + if ctx.Reason != x402.CancellationReasonHandlerThrew && + ctx.Reason != x402.CancellationReasonHandlerFailed { + return nil + } + return s.ClearPendingRequest(ctx.Payload) + } +} + +// extractChannelIdFromPayload pulls voucher.channelId from a deposit/voucher/refund payload map. +func extractChannelIdFromPayload(payload map[string]interface{}) string { + if payload == nil { + return "" + } + if v, ok := payload["voucher"].(map[string]interface{}); ok { + if id, ok := v["channelId"].(string); ok { + return id + } + } + return "" +} + +// Scheme returns the scheme identifier. +func (s *BatchSettlementEvmScheme) Scheme() string { + return batchsettlement.SchemeBatched +} + +// GetAssetDecimals implements AssetDecimalsProvider. +func (s *BatchSettlementEvmScheme) GetAssetDecimals(asset string, network x402.Network) int { + info, err := evm.GetAssetInfo(string(network), asset) + if err != nil || info == nil { + return 6 + } + return info.Decimals +} + +// RegisterMoneyParser registers a custom money parser. +func (s *BatchSettlementEvmScheme) RegisterMoneyParser(parser x402.MoneyParser) *BatchSettlementEvmScheme { + s.moneyParsers = append(s.moneyParsers, parser) + return s +} + +// GetStorage returns the underlying session storage. +func (s *BatchSettlementEvmScheme) GetStorage() SessionStorage { + return s.storage +} + +// GetReceiverAddress returns the receiver address. +func (s *BatchSettlementEvmScheme) GetReceiverAddress() string { + return s.receiverAddress +} + +// GetWithdrawDelay returns the configured withdraw delay. +func (s *BatchSettlementEvmScheme) GetWithdrawDelay() int { + return s.withdrawDelay +} + +// GetReceiverAuthorizerAddress returns the receiver authorizer's address. +func (s *BatchSettlementEvmScheme) GetReceiverAuthorizerAddress() string { + if s.receiverAuthorizerSigner != nil { + return s.receiverAuthorizerSigner.Address() + } + return "" +} + +// ParsePrice parses a price and converts it to an asset amount. +func (s *BatchSettlementEvmScheme) ParsePrice(price x402.Price, network x402.Network) (x402.AssetAmount, error) { + // If already an AssetAmount map, return directly + if priceMap, ok := price.(map[string]interface{}); ok { + if amountVal, hasAmount := priceMap["amount"]; hasAmount { + amountStr, ok := amountVal.(string) + if !ok { + return x402.AssetAmount{}, errors.New(ErrAmountMustBeString) + } + asset := "" + if assetVal, hasAsset := priceMap["asset"]; hasAsset { + if assetStr, ok := assetVal.(string); ok { + asset = assetStr + } + } + if asset == "" { + return x402.AssetAmount{}, errors.New(ErrAssetAddressRequired) + } + extra := make(map[string]interface{}) + if extraVal, hasExtra := priceMap["extra"]; hasExtra { + if extraMap, ok := extraVal.(map[string]interface{}); ok { + extra = extraMap + } + } + return x402.AssetAmount{ + Amount: amountStr, + Asset: asset, + Extra: extra, + }, nil + } + } + + decimalAmount, err := parseMoneyToDecimal(price) + if err != nil { + return x402.AssetAmount{}, err + } + + for _, parser := range s.moneyParsers { + result, err := parser(decimalAmount, network) + if err != nil { + continue + } + if result != nil { + return *result, nil + } + } + + return defaultMoneyConversion(decimalAmount, network) +} + +// EnhancePaymentRequirements adds batched-specific fields to payment requirements. +func (s *BatchSettlementEvmScheme) EnhancePaymentRequirements( + ctx context.Context, + requirements types.PaymentRequirements, + supportedKind types.SupportedKind, + extensionKeys []string, +) (types.PaymentRequirements, error) { + networkStr := string(requirements.Network) + + // Get or set asset + var assetInfo *evm.AssetInfo + var err error + if requirements.Asset != "" { + assetInfo, err = evm.GetAssetInfo(networkStr, requirements.Asset) + if err != nil { + return requirements, err + } + } else { + assetInfo, err = evm.GetAssetInfo(networkStr, "") + if err != nil { + return requirements, fmt.Errorf(ErrNoAssetSpecified+": %w", err) + } + requirements.Asset = assetInfo.Address + } + + // Normalize amount to smallest unit + if requirements.Amount != "" && strings.Contains(requirements.Amount, ".") { + amount, err := evm.ParseAmount(requirements.Amount, assetInfo.Decimals) + if err != nil { + return requirements, fmt.Errorf(ErrFailedToParseAmount+": %w", err) + } + requirements.Amount = amount.String() + } + + // Initialize Extra + if requirements.Extra == nil { + requirements.Extra = make(map[string]interface{}) + } + + // Token EIP-712 domain (`name` / `version`). Always populated when the asset + // metadata provides them because the ERC-3009 deposit collector and the + // gas-sponsored EIP-2612 permit segment recompute the token's EIP-712 digest + // off-chain. + if _, ok := requirements.Extra["name"]; !ok { + requirements.Extra["name"] = assetInfo.Name + } + if _, ok := requirements.Extra["version"]; !ok { + requirements.Extra["version"] = assetInfo.Version + } + + // Add batched-specific fields. Receiver authorizer resolution order: + // 1. Pre-existing requirements.Extra["receiverAuthorizer"] (caller override). + // 2. Locally-configured ReceiverAuthorizerSigner address. + // 3. Facilitator-advertised authorizer from supportedKind.Extra (delegated mode). + // + // Hard-fails if all three sources are empty/zero — clients would otherwise + // derive the wrong channelId, and the onchain deposit transaction would + // revert at the contract boundary. + if existing, ok := requirements.Extra["receiverAuthorizer"].(string); !ok || existing == "" || strings.EqualFold(existing, zeroAddress) { + receiverAuth := s.GetReceiverAuthorizerAddress() + if (receiverAuth == "" || strings.EqualFold(receiverAuth, zeroAddress)) && supportedKind.Extra != nil { + if facilitatorAuth, ok := supportedKind.Extra["receiverAuthorizer"].(string); ok { + receiverAuth = facilitatorAuth + } + } + if receiverAuth == "" || strings.EqualFold(receiverAuth, zeroAddress) { + return requirements, fmt.Errorf("payment requirements must include a non-zero extra.receiverAuthorizer") + } + requirements.Extra["receiverAuthorizer"] = receiverAuth + } + if _, ok := requirements.Extra["withdrawDelay"]; !ok { + requirements.Extra["withdrawDelay"] = s.withdrawDelay + } + + // Copy extensions from supportedKind + if supportedKind.Extra != nil { + for _, key := range extensionKeys { + if val, ok := supportedKind.Extra[key]; ok { + requirements.Extra[key] = val + } + } + } + + return requirements, nil +} + +// SignRefund signs a cooperative refund EIP-712 message. +func (s *BatchSettlementEvmScheme) SignRefund(ctx context.Context, channelId string, amount string, nonce string, network string) ([]byte, error) { + if s.receiverAuthorizerSigner == nil { + return nil, fmt.Errorf("no receiver authorizer signer configured") + } + + chainId, err := evm.GetEvmChainId(network) + if err != nil { + return nil, err + } + + refundAmount, ok := new(big.Int).SetString(amount, 10) + if !ok { + return nil, fmt.Errorf("invalid refund amount: %s", amount) + } + refundNonce, ok := new(big.Int).SetString(nonce, 10) + if !ok { + return nil, fmt.Errorf("invalid nonce: %s", nonce) + } + + channelIdBytes, err := evm.HexToBytes(channelId) + if err != nil { + return nil, err + } + + domain := evm.TypedDataDomain{ + Name: batchsettlement.BatchSettlementDomain.Name, + Version: batchsettlement.BatchSettlementDomain.Version, + ChainID: chainId, + VerifyingContract: batchsettlement.BatchSettlementAddress, + } + + allTypes := map[string][]evm.TypedDataField{ + "EIP712Domain": { + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "Refund": batchsettlement.RefundTypes["Refund"], + } + + message := map[string]interface{}{ + "channelId": channelIdBytes, + "nonce": refundNonce, + "amount": refundAmount, + } + + return s.receiverAuthorizerSigner.SignTypedData(ctx, domain, allTypes, "Refund", message) +} + +// SignClaimBatch signs a ClaimBatch EIP-712 message. +func (s *BatchSettlementEvmScheme) SignClaimBatch(ctx context.Context, claims []batchsettlement.BatchSettlementVoucherClaim, network string) ([]byte, error) { + if s.receiverAuthorizerSigner == nil { + return nil, fmt.Errorf("no receiver authorizer signer configured") + } + + chainId, err := evm.GetEvmChainId(network) + if err != nil { + return nil, err + } + + domain := evm.TypedDataDomain{ + Name: batchsettlement.BatchSettlementDomain.Name, + Version: batchsettlement.BatchSettlementDomain.Version, + ChainID: chainId, + VerifyingContract: batchsettlement.BatchSettlementAddress, + } + + allTypes := map[string][]evm.TypedDataField{ + "EIP712Domain": { + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + }, + "ClaimBatch": batchsettlement.ClaimBatchTypes["ClaimBatch"], + "ClaimEntry": batchsettlement.ClaimBatchTypes["ClaimEntry"], + } + + entries := make([]map[string]interface{}, len(claims)) + for i, claim := range claims { + channelId, _ := batchsettlement.ComputeChannelId(claim.Voucher.Channel, network) + channelIdBytes, _ := evm.HexToBytes(channelId) + maxClaimable, _ := new(big.Int).SetString(claim.Voucher.MaxClaimableAmount, 10) + totalClaimed, _ := new(big.Int).SetString(claim.TotalClaimed, 10) + + entries[i] = map[string]interface{}{ + "channelId": channelIdBytes, + "maxClaimableAmount": maxClaimable, + "totalClaimed": totalClaimed, + } + } + + message := map[string]interface{}{ + "claims": entries, + } + + return s.receiverAuthorizerSigner.SignTypedData(ctx, domain, allTypes, "ClaimBatch", message) +} + +// CreateChannelManager creates a new channel manager for auto-settlement +// rooted at this scheme's receiver and the network's default settlement asset. +// +// Pass a custom token via NewBatchSettlementChannelManager directly when you need a +// non-default settlement asset for this manager. +func (s *BatchSettlementEvmScheme) CreateChannelManager(facilitator x402.FacilitatorClient, network x402.Network) *BatchSettlementChannelManager { + token := "" + if cfg, err := evm.GetNetworkConfig(string(network)); err == nil { + token = cfg.DefaultAsset.Address + } + return NewBatchSettlementChannelManager(ChannelManagerConfig{ + Scheme: s, + Facilitator: facilitator, + Receiver: s.receiverAddress, + Token: token, + Network: network, + }) +} + +// UpdateSession updates or creates a session for a channel. +func (s *BatchSettlementEvmScheme) UpdateSession(channelId string, session *ChannelSession) error { + return s.storage.Set(batchsettlement.NormalizeChannelId(channelId), session) +} + +// GetSession retrieves a session for a channel. +func (s *BatchSettlementEvmScheme) GetSession(channelId string) (*ChannelSession, error) { + return s.storage.Get(batchsettlement.NormalizeChannelId(channelId)) +} + +// DeleteSession removes a session for a channel. +func (s *BatchSettlementEvmScheme) DeleteSession(channelId string) error { + return s.storage.Delete(batchsettlement.NormalizeChannelId(channelId)) +} + +// Helper functions + +func parseMoneyToDecimal(price x402.Price) (float64, error) { + switch v := price.(type) { + case string: + cleanPrice := strings.TrimSpace(v) + cleanPrice = strings.TrimPrefix(cleanPrice, "$") + cleanPrice = strings.TrimSpace(cleanPrice) + amount, err := strconv.ParseFloat(cleanPrice, 64) + if err != nil { + return 0, fmt.Errorf(ErrFailedToParsePrice+": '%s': %w", v, err) + } + return amount, nil + case float64: + return v, nil + case int: + return float64(v), nil + case int64: + return float64(v), nil + default: + return 0, fmt.Errorf(ErrUnsupportedPriceType+": %T", price) + } +} + +func defaultMoneyConversion(amount float64, network x402.Network) (x402.AssetAmount, error) { + networkStr := string(network) + config, err := evm.GetNetworkConfig(networkStr) + if err != nil { + return x402.AssetAmount{}, err + } + if config.DefaultAsset.Address == "" { + return x402.AssetAmount{}, fmt.Errorf("no default stablecoin for network %s", networkStr) + } + + extra := map[string]interface{}{ + // Token EIP-712 domain — see comment in GetExtra above for why both + // ERC-3009 and Permit2(+EIP-2612) paths need name/version. + "name": config.DefaultAsset.Name, + "version": config.DefaultAsset.Version, + } + if config.DefaultAsset.AssetTransferMethod != "" { + extra["assetTransferMethod"] = string(config.DefaultAsset.AssetTransferMethod) + } + + oneUnit := float64(1) + for i := 0; i < config.DefaultAsset.Decimals; i++ { + oneUnit *= 10 + } + + if amount >= oneUnit && amount == float64(int64(amount)) { + return x402.AssetAmount{ + Asset: config.DefaultAsset.Address, + Amount: fmt.Sprintf("%.0f", amount), + Extra: extra, + }, nil + } + + amountStr := fmt.Sprintf("%.6f", amount) + parsedAmount, err := evm.ParseAmount(amountStr, config.DefaultAsset.Decimals) + if err != nil { + return x402.AssetAmount{}, fmt.Errorf(ErrFailedToConvertAmt+": %w", err) + } + + return x402.AssetAmount{ + Asset: config.DefaultAsset.Address, + Amount: parsedAmount.String(), + Extra: extra, + }, nil +} diff --git a/go/mechanisms/evm/batch-settlement/server/scheme_test.go b/go/mechanisms/evm/batch-settlement/server/scheme_test.go new file mode 100644 index 0000000000..49888e001a --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/server/scheme_test.go @@ -0,0 +1,655 @@ +package server + +import ( + "context" + "errors" + "math/big" + "testing" + + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + "github.com/x402-foundation/x402/go/types" +) + +// mockAuthorizerSigner records calls and returns canned bytes. +type mockAuthorizerSigner struct { + address string + sig []byte + err error + calls int +} + +func (m *mockAuthorizerSigner) Address() string { return m.address } +func (m *mockAuthorizerSigner) SignTypedData(_ context.Context, _ evm.TypedDataDomain, _ map[string][]evm.TypedDataField, _ string, _ map[string]interface{}) ([]byte, error) { + m.calls++ + return m.sig, m.err +} + +func TestNewBatchSettlementEvmScheme_NilConfigDefaults(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + if s.GetReceiverAddress() != "0xreceiver" { + t.Fatalf("receiver = %q", s.GetReceiverAddress()) + } + if s.GetWithdrawDelay() != batchsettlement.MinWithdrawDelay { + t.Fatalf("withdrawDelay = %d", s.GetWithdrawDelay()) + } + if s.GetReceiverAuthorizerAddress() != "" { + t.Fatalf("expected empty receiverAuthorizer, got %q", s.GetReceiverAuthorizerAddress()) + } + if s.GetStorage() == nil { + t.Fatal("expected default in-memory storage") + } + if s.Scheme() != batchsettlement.SchemeBatched { + t.Fatalf("scheme = %s", s.Scheme()) + } +} + +func TestNewBatchSettlementEvmScheme_OverridesApplied(t *testing.T) { + storage := NewInMemoryChannelStorage() + auth := &mockAuthorizerSigner{address: "0xauth"} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ + Storage: storage, + ReceiverAuthorizerSigner: auth, + WithdrawDelay: 1800, + }) + if s.GetWithdrawDelay() != 1800 { + t.Fatalf("withdrawDelay = %d", s.GetWithdrawDelay()) + } + if s.GetReceiverAuthorizerAddress() != "0xauth" { + t.Fatalf("receiverAuthorizer = %q", s.GetReceiverAuthorizerAddress()) + } + if s.GetStorage() != storage { + t.Fatalf("expected provided storage") + } +} + +func TestNewBatchSettlementEvmScheme_ZeroWithdrawDelayFallsBackToMin(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{WithdrawDelay: 0}) + if s.GetWithdrawDelay() != batchsettlement.MinWithdrawDelay { + t.Fatalf("withdrawDelay = %d", s.GetWithdrawDelay()) + } +} + +func TestParsePrice_AssetAmountMap(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + got, err := s.ParsePrice(map[string]interface{}{ + "amount": "1000", + "asset": "0xtoken", + "extra": map[string]interface{}{"name": "USDC"}, + }, x402.Network("eip155:8453")) + if err != nil { + t.Fatalf("err: %v", err) + } + if got.Amount != "1000" || got.Asset != "0xtoken" { + t.Fatalf("got = %+v", got) + } + if got.Extra["name"] != "USDC" { + t.Fatalf("extra = %+v", got.Extra) + } +} + +func TestParsePrice_AssetAmountMap_AmountNotString(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + _, err := s.ParsePrice(map[string]interface{}{ + "amount": 1000, + "asset": "0xtoken", + }, x402.Network("eip155:8453")) + if err == nil { + t.Fatal("expected error") + } +} + +func TestParsePrice_AssetAmountMap_MissingAsset(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + _, err := s.ParsePrice(map[string]interface{}{"amount": "1000"}, x402.Network("eip155:8453")) + if err == nil { + t.Fatal("expected error") + } +} + +func TestParsePrice_String(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + got, err := s.ParsePrice("$0.01", x402.Network("eip155:8453")) + if err != nil { + t.Fatalf("err: %v", err) + } + if got.Amount == "" || got.Asset == "" { + t.Fatalf("got = %+v", got) + } +} + +func TestParsePrice_UnsupportedType(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + _, err := s.ParsePrice(struct{}{}, x402.Network("eip155:8453")) + if err == nil { + t.Fatal("expected error") + } +} + +func TestRegisterMoneyParser_OverridesDefault(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + called := false + s.RegisterMoneyParser(func(_ float64, _ x402.Network) (*x402.AssetAmount, error) { + called = true + return &x402.AssetAmount{Amount: "777", Asset: "0xcustom"}, nil + }) + got, err := s.ParsePrice("0.50", x402.Network("eip155:8453")) + if err != nil { + t.Fatalf("err: %v", err) + } + if !called || got.Amount != "777" || got.Asset != "0xcustom" { + t.Fatalf("custom parser not invoked: called=%v got=%+v", called, got) + } +} + +func TestEnhancePaymentRequirements_ExplicitAsset(t *testing.T) { + auth := &mockAuthorizerSigner{address: "0xauth"} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ + ReceiverAuthorizerSigner: auth, + WithdrawDelay: 1800, + }) + req := types.PaymentRequirements{ + Network: "eip155:8453", + Asset: "0x1234567890abcdef1234567890abcdef12345678", + Amount: "1000", + } + out, err := s.EnhancePaymentRequirements(context.Background(), req, types.SupportedKind{}, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if out.Extra["receiverAuthorizer"] != "0xauth" { + t.Fatalf("receiverAuthorizer = %v", out.Extra["receiverAuthorizer"]) + } + if out.Extra["withdrawDelay"] != 1800 { + t.Fatalf("withdrawDelay = %v", out.Extra["withdrawDelay"]) + } +} + +// In delegated-authorizer mode (no local ReceiverAuthorizerSigner) the server +// must surface the facilitator-advertised authorizer from supportedKind.Extra so +// clients build channelConfig.receiverAuthorizer correctly. Without this fallback +// the delegated mode produced channelId mismatches and onchain deposit reverts. +func TestEnhancePaymentRequirements_FallsBackToFacilitatorAuthorizerInDelegatedMode(t *testing.T) { + // No ReceiverAuthorizerSigner configured — delegated to facilitator. + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + req := types.PaymentRequirements{ + Network: "eip155:8453", + Asset: "0x1234567890abcdef1234567890abcdef12345678", + Amount: "1000", + } + supported := types.SupportedKind{ + Extra: map[string]interface{}{ + "receiverAuthorizer": "0xCFA51eEAF6B2831d2A7e09829477E88154647cbB", + }, + } + out, err := s.EnhancePaymentRequirements(context.Background(), req, supported, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + got, _ := out.Extra["receiverAuthorizer"].(string) + if got != "0xCFA51eEAF6B2831d2A7e09829477E88154647cbB" { + t.Fatalf("expected facilitator authorizer to be surfaced, got %q", got) + } +} + +// Local signer must take precedence over the facilitator-advertised authorizer. +func TestEnhancePaymentRequirements_LocalAuthorizerWinsOverFacilitator(t *testing.T) { + auth := &mockAuthorizerSigner{address: "0xLocalAuth"} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ReceiverAuthorizerSigner: auth}) + req := types.PaymentRequirements{ + Network: "eip155:8453", + Asset: "0x1234567890abcdef1234567890abcdef12345678", + Amount: "1000", + } + supported := types.SupportedKind{ + Extra: map[string]interface{}{"receiverAuthorizer": "0xFacilitator"}, + } + out, err := s.EnhancePaymentRequirements(context.Background(), req, supported, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if got := out.Extra["receiverAuthorizer"]; got != "0xLocalAuth" { + t.Fatalf("local signer should win, got %v", got) + } +} + +// Routes can set `extra.assetTransferMethod = "permit2"` on the accept config to +// switch the deposit transport. EnhancePaymentRequirements must pass it +// through unchanged so the client picks the right deposit signer. +func TestEnhancePaymentRequirements_PassesThroughAssetTransferMethod(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + req := types.PaymentRequirements{ + Network: "eip155:8453", + Asset: "0x1234567890abcdef1234567890abcdef12345678", + Amount: "1000", + Extra: map[string]interface{}{ + "assetTransferMethod": "permit2", + "receiverAuthorizer": "0x4444444444444444444444444444444444444444", + }, + } + out, err := s.EnhancePaymentRequirements(context.Background(), req, types.SupportedKind{}, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if got, _ := out.Extra["assetTransferMethod"].(string); got != "permit2" { + t.Fatalf("expected assetTransferMethod=permit2 to pass through, got %q", got) + } +} + +func TestEnhancePaymentRequirements_DecimalAmountNormalized(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + req := types.PaymentRequirements{ + Network: "eip155:8453", + Asset: "0x1234567890abcdef1234567890abcdef12345678", + Amount: "1.5", + Extra: map[string]interface{}{ + "receiverAuthorizer": "0x4444444444444444444444444444444444444444", + }, + } + out, err := s.EnhancePaymentRequirements(context.Background(), req, types.SupportedKind{}, nil) + if err != nil { + t.Fatalf("err: %v", err) + } + if out.Amount == "1.5" { + t.Fatalf("amount not normalized: %s", out.Amount) + } +} + +// Rejects requirements when neither the server nor facilitator provides receiverAuthorizer. +func TestEnhancePaymentRequirements_RejectsMissingReceiverAuthorizer(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + req := types.PaymentRequirements{ + Network: "eip155:8453", + Asset: "0x1234567890abcdef1234567890abcdef12345678", + Amount: "100", + } + if _, err := s.EnhancePaymentRequirements(context.Background(), req, types.SupportedKind{}, nil); err == nil { + t.Fatalf("expected error when receiverAuthorizer is unavailable") + } +} + +func TestSignRefund_NoSignerErrors(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + _, err := s.SignRefund(context.Background(), "0xabcd", "100", "1", "eip155:8453") + if err == nil { + t.Fatal("expected error") + } +} + +func TestSignRefund_BadNetwork(t *testing.T) { + auth := &mockAuthorizerSigner{address: "0xauth", sig: []byte{0x01}} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ReceiverAuthorizerSigner: auth}) + _, err := s.SignRefund(context.Background(), "0xabcd", "100", "1", "not-a-network") + if err == nil { + t.Fatal("expected error") + } +} + +func TestSignRefund_BadAmount(t *testing.T) { + auth := &mockAuthorizerSigner{address: "0xauth", sig: []byte{0x01}} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ReceiverAuthorizerSigner: auth}) + _, err := s.SignRefund(context.Background(), "0xabcd", "not-a-number", "1", "eip155:8453") + if err == nil { + t.Fatal("expected error") + } +} + +func TestSignRefund_BadNonce(t *testing.T) { + auth := &mockAuthorizerSigner{address: "0xauth", sig: []byte{0x01}} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ReceiverAuthorizerSigner: auth}) + _, err := s.SignRefund(context.Background(), "0xabcd", "100", "not-a-number", "eip155:8453") + if err == nil { + t.Fatal("expected error") + } +} + +func TestSignRefund_BadChannelId(t *testing.T) { + auth := &mockAuthorizerSigner{address: "0xauth", sig: []byte{0x01}} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ReceiverAuthorizerSigner: auth}) + _, err := s.SignRefund(context.Background(), "not-hex", "100", "1", "eip155:8453") + if err == nil { + t.Fatal("expected error") + } +} + +func TestSignRefund_OK(t *testing.T) { + auth := &mockAuthorizerSigner{address: "0xauth", sig: []byte{0xde, 0xad}} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ReceiverAuthorizerSigner: auth}) + sig, err := s.SignRefund(context.Background(), "0xabcd", "100", "1", "eip155:8453") + if err != nil { + t.Fatalf("err: %v", err) + } + if len(sig) != 2 || sig[0] != 0xde { + t.Fatalf("sig = %x", sig) + } + if auth.calls != 1 { + t.Fatalf("calls = %d", auth.calls) + } +} + +func TestSignRefund_PropagatesSignerError(t *testing.T) { + auth := &mockAuthorizerSigner{address: "0xauth", err: errors.New("kms down")} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ReceiverAuthorizerSigner: auth}) + _, err := s.SignRefund(context.Background(), "0xabcd", "100", "1", "eip155:8453") + if err == nil { + t.Fatal("expected error") + } +} + +func TestSignClaimBatch_NoSignerErrors(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + _, err := s.SignClaimBatch(context.Background(), nil, "eip155:8453") + if err == nil { + t.Fatal("expected error") + } +} + +func TestSignClaimBatch_BadNetwork(t *testing.T) { + auth := &mockAuthorizerSigner{address: "0xauth", sig: []byte{0x01}} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ReceiverAuthorizerSigner: auth}) + _, err := s.SignClaimBatch(context.Background(), nil, "not-a-network") + if err == nil { + t.Fatal("expected error") + } +} + +func TestSignClaimBatch_OK(t *testing.T) { + auth := &mockAuthorizerSigner{address: "0xauth", sig: []byte{0xbe, 0xef}} + s := NewBatchSettlementEvmScheme("0xreceiver", &BatchSettlementEvmSchemeServerConfig{ReceiverAuthorizerSigner: auth}) + claim := batchsettlement.BatchSettlementVoucherClaim{Signature: "0xsig", TotalClaimed: "0"} + claim.Voucher.Channel = batchsettlement.ChannelConfig{ + Payer: "0x1111111111111111111111111111111111111111", + PayerAuthorizer: "0x2222222222222222222222222222222222222222", + Receiver: "0x3333333333333333333333333333333333333333", + ReceiverAuthorizer: "0xauth", + Token: "0x5555555555555555555555555555555555555555", + WithdrawDelay: 900, + Salt: "0x01", + } + claim.Voucher.MaxClaimableAmount = "100" + sig, err := s.SignClaimBatch(context.Background(), []batchsettlement.BatchSettlementVoucherClaim{claim}, "eip155:8453") + if err != nil { + t.Fatalf("err: %v", err) + } + if len(sig) != 2 || sig[1] != 0xef { + t.Fatalf("sig = %x", sig) + } +} + +func TestSession_RoundTrip_CaseInsensitive(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + in := sampleSession("0xABCD", "10") + if err := s.UpdateSession("0xABCD", in); err != nil { + t.Fatalf("update: %v", err) + } + got, err := s.GetSession("0xabcd") + if err != nil { + t.Fatalf("get: %v", err) + } + if got == nil || got.ChannelId != "0xABCD" { + t.Fatalf("got %+v", got) + } + if err := s.DeleteSession("0XABCD"); err != nil { + t.Fatalf("delete: %v", err) + } + if got2, _ := s.GetSession("0xabcd"); got2 != nil { + t.Fatalf("expected nil after delete") + } +} + +func TestGetAssetDecimals_DefaultsTo6(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + if got := s.GetAssetDecimals("0xunknown", x402.Network("nope")); got != 6 { + t.Fatalf("got %d", got) + } +} + +func TestCreateChannelManager_NotNil(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + cm := s.CreateChannelManager(nil, x402.Network("eip155:8453")) + if cm == nil { + t.Fatal("expected non-nil manager") + } +} + +func TestParseMoneyToDecimal_AllNumericTypes(t *testing.T) { + cases := []struct { + in x402.Price + want float64 + }{ + {"1.5", 1.5}, + {"$2.25", 2.25}, + {float64(3.5), 3.5}, + {int(4), 4.0}, + {int64(5), 5.0}, + } + for _, c := range cases { + got, err := parseMoneyToDecimal(c.in) + if err != nil { + t.Fatalf("err on %v: %v", c.in, err) + } + if got != c.want { + t.Fatalf("got %v, want %v for %v", got, c.want, c.in) + } + } +} + +func TestParseMoneyToDecimal_BadString(t *testing.T) { + if _, err := parseMoneyToDecimal("nope"); err == nil { + t.Fatal("expected error") + } +} + +func TestParseMoneyToDecimal_UnsupportedType(t *testing.T) { + if _, err := parseMoneyToDecimal(big.NewInt(1)); err == nil { + t.Fatal("expected error") + } +} + +func nowMs() int64 { + return int64(1) << 50 // far in the future, simulates "very recent" +} + +// ----- Snapshot + EnrichPaymentRequiredResponse ----- + +func makeBatchedPayload(channelId string) *types.PaymentPayload { + return &types.PaymentPayload{ + X402Version: 2, + Payload: map[string]interface{}{ + "type": "voucher", + "voucher": map[string]interface{}{ + "channelId": channelId, + "maxClaimableAmount": "100", + "signature": "0xsig", + }, + }, + Accepted: types.PaymentRequirements{ + Scheme: batchsettlement.SchemeBatched, + Network: "eip155:8453", + }, + } +} + +// enrich is a test helper that invokes EnrichPaymentRequiredResponse with a +// minimal context, mutating reqs in place and returning the same slice for +// chained assertions. +func enrich(s *BatchSettlementEvmScheme, pp *types.PaymentPayload, errReason string, reqs []types.PaymentRequirements) []types.PaymentRequirements { + s.EnrichPaymentRequiredResponse(x402.PaymentRequiredContext{ + Requirements: reqs, + PaymentPayload: pp, + Error: errReason, + }) + return reqs +} + +func TestRememberAndTakeChannelSnapshot_RoundTrip(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + pp := makeBatchedPayload("0xabcd") + sess := sampleSession("0xabcd", "10") + + s.RememberChannelSnapshot(pp, sess) + got := s.TakeChannelSnapshot(pp) + if got != sess { + t.Fatalf("expected snapshot back, got %+v", got) + } + // Second take returns nil (snapshot consumed). + if got2 := s.TakeChannelSnapshot(pp); got2 != nil { + t.Fatalf("expected nil after take, got %+v", got2) + } +} + +func TestRememberChannelSnapshot_NilInputsAreNoOp(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + pp := makeBatchedPayload("0xabcd") + s.RememberChannelSnapshot(nil, sampleSession("0xabcd", "10")) + s.RememberChannelSnapshot(pp, nil) + if got := s.TakeChannelSnapshot(pp); got != nil { + t.Fatalf("expected nil snapshot, got %+v", got) + } + if got := s.TakeChannelSnapshot(nil); got != nil { + t.Fatalf("expected nil for nil payload") + } +} + +func TestEnrichPaymentRequiredResponse_WrongReasonNoOp(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + pp := makeBatchedPayload("0xabcd") + s.RememberChannelSnapshot(pp, sampleSession("0xabcd", "10")) + reqs := enrich(s, pp, "some_other_reason", + []types.PaymentRequirements{{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}}) + if reqs[0].Extra != nil { + t.Fatalf("expected no enrichment, got %+v", reqs[0].Extra) + } +} + +func TestEnrichPaymentRequiredResponse_NilPayloadNoOp(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + reqs := enrich(s, nil, batchsettlement.ErrCumulativeAmountMismatch, + []types.PaymentRequirements{{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}}) + if reqs[0].Extra != nil { + t.Fatalf("expected no enrichment, got %+v", reqs[0].Extra) + } +} + +func TestEnrichPaymentRequiredResponse_FromSnapshot(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + pp := makeBatchedPayload("0xabcd") + s.RememberChannelSnapshot(pp, sampleSession("0xabcd", "42")) + + reqs := enrich(s, pp, batchsettlement.ErrCumulativeAmountMismatch, + []types.PaymentRequirements{{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}}) + + channelState, ok := reqs[0].Extra["channelState"].(map[string]interface{}) + if !ok { + t.Fatalf("expected channelState map, got %+v", reqs[0].Extra) + } + if channelState["channelId"] != "0xabcd" { + t.Fatalf("channelId = %v", channelState["channelId"]) + } + if channelState["chargedCumulativeAmount"] != "42" { + t.Fatalf("chargedCumulativeAmount = %v", channelState["chargedCumulativeAmount"]) + } + if channelState["balance"] == "" { + t.Fatalf("expected balance present, got %+v", channelState) + } + voucherState, ok := reqs[0].Extra["voucherState"].(map[string]interface{}) + if !ok { + t.Fatalf("expected voucherState map, got %+v", reqs[0].Extra) + } + if voucherState["signedMaxClaimable"] != "1000" { + t.Fatalf("signedMaxClaimable = %v", voucherState["signedMaxClaimable"]) + } + if voucherState["signature"] != "0xsig" { + t.Fatalf("signature = %v", voucherState["signature"]) + } + // Snapshot should be consumed. + if got := s.TakeChannelSnapshot(pp); got != nil { + t.Fatalf("expected snapshot consumed") + } +} + +func TestEnrichPaymentRequiredResponse_FallsBackToStorage(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + pp := makeBatchedPayload("0xabcd") + _ = s.UpdateSession("0xabcd", sampleSession("0xabcd", "77")) + + reqs := enrich(s, pp, batchsettlement.ErrCumulativeAmountMismatch, + []types.PaymentRequirements{{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}}) + + state, ok := reqs[0].Extra["channelState"].(map[string]interface{}) + if !ok { + t.Fatalf("expected channelState map from storage fallback, got %+v", reqs[0].Extra) + } + if state["chargedCumulativeAmount"] != "77" { + t.Fatalf("chargedCumulativeAmount = %v", state["chargedCumulativeAmount"]) + } +} + +func TestEnrichPaymentRequiredResponse_NoSessionNoOp(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + pp := makeBatchedPayload("0xabcd") + reqs := enrich(s, pp, batchsettlement.ErrCumulativeAmountMismatch, + []types.PaymentRequirements{{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}}) + if reqs[0].Extra != nil { + t.Fatalf("expected no enrichment without session, got %+v", reqs[0].Extra) + } +} + +func TestEnrichPaymentRequiredResponse_SkipsNonBatchedAndMismatchedNetwork(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + pp := makeBatchedPayload("0xabcd") + s.RememberChannelSnapshot(pp, sampleSession("0xabcd", "10")) + + reqs := enrich(s, pp, batchsettlement.ErrCumulativeAmountMismatch, []types.PaymentRequirements{ + {Scheme: "exact", Network: "eip155:8453"}, + {Scheme: batchsettlement.SchemeBatched, Network: "eip155:1"}, + {Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}, + }) + + if reqs[0].Extra != nil { + t.Fatalf("non-batched req should not be enriched: %+v", reqs[0].Extra) + } + if reqs[1].Extra != nil { + t.Fatalf("network-mismatch req should not be enriched: %+v", reqs[1].Extra) + } + if _, ok := reqs[2].Extra["channelState"]; !ok { + t.Fatalf("matching req should be enriched: %+v", reqs[2].Extra) + } +} + +func TestEnrichPaymentRequiredResponse_MissingChannelIdNoOp(t *testing.T) { + s := NewBatchSettlementEvmScheme("0xreceiver", nil) + pp := &types.PaymentPayload{ + X402Version: 2, + Payload: map[string]interface{}{"type": "voucher"}, + Accepted: types.PaymentRequirements{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}, + } + reqs := enrich(s, pp, batchsettlement.ErrCumulativeAmountMismatch, + []types.PaymentRequirements{{Scheme: batchsettlement.SchemeBatched, Network: "eip155:8453"}}) + if reqs[0].Extra != nil { + t.Fatalf("expected no enrichment without channelId, got %+v", reqs[0].Extra) + } +} + +func TestExtractChannelIdFromPayload(t *testing.T) { + if got := extractChannelIdFromPayload(nil); got != "" { + t.Fatalf("nil payload: got %q", got) + } + if got := extractChannelIdFromPayload(map[string]interface{}{}); got != "" { + t.Fatalf("missing voucher: got %q", got) + } + if got := extractChannelIdFromPayload(map[string]interface{}{"voucher": "not-a-map"}); got != "" { + t.Fatalf("voucher non-map: got %q", got) + } + if got := extractChannelIdFromPayload(map[string]interface{}{ + "voucher": map[string]interface{}{"channelId": 123}, + }); got != "" { + t.Fatalf("channelId non-string: got %q", got) + } + if got := extractChannelIdFromPayload(map[string]interface{}{ + "voucher": map[string]interface{}{"channelId": "0xabcd"}, + }); got != "0xabcd" { + t.Fatalf("got %q", got) + } +} diff --git a/go/mechanisms/evm/batch-settlement/server/storage.go b/go/mechanisms/evm/batch-settlement/server/storage.go new file mode 100644 index 0000000000..864ed2afa9 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/server/storage.go @@ -0,0 +1,194 @@ +package server + +import ( + "sync" + + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +// PendingRequest reserves a channel against concurrent same-channel requests. +// A request is allowed when no live (unexpired) pending entry exists. Cleanup +// hooks clear the reservation; the bounded TTL guarantees release if cleanup +// never runs. +type PendingRequest struct { + PendingId string `json:"pendingId"` + SignedMaxClaimable string `json:"signedMaxClaimable"` + ExpiresAt int64 `json:"expiresAt"` // unix millis +} + +// ChannelSession holds per-channel session state on the server side. +type ChannelSession struct { + ChannelId string `json:"channelId"` + ChannelConfig batchsettlement.ChannelConfig `json:"channelConfig"` + ChargedCumulativeAmount string `json:"chargedCumulativeAmount"` + SignedMaxClaimable string `json:"signedMaxClaimable"` + Signature string `json:"signature"` + Balance string `json:"balance"` + TotalClaimed string `json:"totalClaimed"` + WithdrawRequestedAt int `json:"withdrawRequestedAt"` + RefundNonce int `json:"refundNonce"` + LastRequestTimestamp int64 `json:"lastRequestTimestamp"` + // OnchainSyncedAt is the wall-clock time (unix millis) when balance/totalClaimed/ + // withdrawRequestedAt/refundNonce were last refreshed from onchain state. + // Used by the local voucher verifier to decide whether to skip facilitator verify. + OnchainSyncedAt int64 `json:"onchainSyncedAt,omitempty"` + // PendingRequest is the in-flight reservation for this channel, if any. + PendingRequest *PendingRequest `json:"pendingRequest,omitempty"` +} + +// ChannelUpdateStatus describes the outcome of an UpdateChannel call. +type ChannelUpdateStatus string + +const ( + ChannelUpdated ChannelUpdateStatus = "updated" + ChannelUnchanged ChannelUpdateStatus = "unchanged" + ChannelDeleted ChannelUpdateStatus = "deleted" +) + +// ChannelUpdateResult is the result of an UpdateChannel call. +type ChannelUpdateResult struct { + Channel *ChannelSession + Status ChannelUpdateStatus +} + +// SessionStorage is the interface for persisting server-side channel sessions. +type SessionStorage interface { + Get(channelId string) (*ChannelSession, error) + Set(channelId string, session *ChannelSession) error + Delete(channelId string) error + List() ([]*ChannelSession, error) + // CompareAndSet atomically updates a session only if the current + // chargedCumulativeAmount matches expectedCharged. Returns true if the + // swap succeeded, false if the value changed underneath (concurrent request). + // + // Deprecated: prefer UpdateChannel for richer atomic mutations. + CompareAndSet(channelId string, expectedCharged string, session *ChannelSession) (bool, error) + // UpdateChannel atomically inspects and mutates a channel record. + // The update callback receives the current session (or nil) and returns + // the next session (or nil to delete). Returning the unchanged input is + // a no-op (status: unchanged). The implementation must guarantee no + // concurrent mutation can interleave between read and write. + UpdateChannel(channelId string, update func(current *ChannelSession) *ChannelSession) (*ChannelUpdateResult, error) +} + +// InMemoryChannelStorage is a volatile in-memory implementation of SessionStorage. +// +// Note on unbounded growth: the per-channel lock map is allocated lazily and +// dropped when Delete is called for that channel. For long-lived servers that +// see an effectively unbounded set of distinct channelIds without ever calling +// Delete, this map will grow over time. Production deployments backed by a +// persistent store (e.g. FileChannelStorage) should prefer Delete-on-drain. +type InMemoryChannelStorage struct { + mu sync.Mutex + sessions map[string]*ChannelSession + locks map[string]*sync.Mutex // per-channel locks for UpdateChannel +} + +// NewInMemoryChannelStorage creates a new in-memory server session storage. +func NewInMemoryChannelStorage() *InMemoryChannelStorage { + return &InMemoryChannelStorage{ + sessions: make(map[string]*ChannelSession), + locks: make(map[string]*sync.Mutex), + } +} + +func (s *InMemoryChannelStorage) lockFor(channelId string) *sync.Mutex { + s.mu.Lock() + defer s.mu.Unlock() + lock, ok := s.locks[channelId] + if !ok { + lock = &sync.Mutex{} + s.locks[channelId] = lock + } + return lock +} + +func (s *InMemoryChannelStorage) Get(channelId string) (*ChannelSession, error) { + s.mu.Lock() + defer s.mu.Unlock() + session, ok := s.sessions[channelId] + if !ok { + return nil, nil + } + cp := *session + return &cp, nil +} + +func (s *InMemoryChannelStorage) Set(channelId string, session *ChannelSession) error { + s.mu.Lock() + defer s.mu.Unlock() + cp := *session + s.sessions[channelId] = &cp + return nil +} + +func (s *InMemoryChannelStorage) Delete(channelId string) error { + s.mu.Lock() + defer s.mu.Unlock() + delete(s.sessions, channelId) + // NOTE: the per-channel lock entry is intentionally retained. Removing it + // would let a stale lockFor caller (already holding the old *sync.Mutex) + // race with a fresh caller (allocating a new *sync.Mutex) for the same + // channelId. The lock map grows monotonically with the channel-id set; + // see the type-level note. + return nil +} + +func (s *InMemoryChannelStorage) List() ([]*ChannelSession, error) { + s.mu.Lock() + defer s.mu.Unlock() + result := make([]*ChannelSession, 0, len(s.sessions)) + for _, session := range s.sessions { + cp := *session + result = append(result, &cp) + } + return result, nil +} + +func (s *InMemoryChannelStorage) CompareAndSet(channelId string, expectedCharged string, session *ChannelSession) (bool, error) { + s.mu.Lock() + defer s.mu.Unlock() + current, ok := s.sessions[channelId] + if ok && current.ChargedCumulativeAmount != expectedCharged { + return false, nil + } + cp := *session + s.sessions[channelId] = &cp + return true, nil +} + +func (s *InMemoryChannelStorage) UpdateChannel(channelId string, update func(current *ChannelSession) *ChannelSession) (*ChannelUpdateResult, error) { + lock := s.lockFor(channelId) + lock.Lock() + defer lock.Unlock() + + s.mu.Lock() + current, exists := s.sessions[channelId] + var currentCopy *ChannelSession + if exists { + cp := *current + currentCopy = &cp + } + s.mu.Unlock() + + next := update(currentCopy) + + // "unchanged" means the callback returned the same pointer it received. + if next == currentCopy { + return &ChannelUpdateResult{Channel: currentCopy, Status: ChannelUnchanged}, nil + } + + s.mu.Lock() + defer s.mu.Unlock() + if next == nil { + if exists { + delete(s.sessions, channelId) + return &ChannelUpdateResult{Channel: nil, Status: ChannelDeleted}, nil + } + return &ChannelUpdateResult{Channel: nil, Status: ChannelUnchanged}, nil + } + cp := *next + s.sessions[channelId] = &cp + stored := cp + return &ChannelUpdateResult{Channel: &stored, Status: ChannelUpdated}, nil +} diff --git a/go/mechanisms/evm/batch-settlement/server/storage_test.go b/go/mechanisms/evm/batch-settlement/server/storage_test.go new file mode 100644 index 0000000000..4f056c3790 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/server/storage_test.go @@ -0,0 +1,157 @@ +package server + +import ( + "reflect" + "sort" + "sync" + "testing" + + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" +) + +func sampleSession(id, charged string) *ChannelSession { + return &ChannelSession{ + ChannelId: id, + ChannelConfig: batchsettlement.ChannelConfig{Payer: "0x1", Receiver: "0x2"}, + ChargedCumulativeAmount: charged, + SignedMaxClaimable: "1000", + Signature: "0xsig", + Balance: "900", + TotalClaimed: "100", + WithdrawRequestedAt: 0, + RefundNonce: 0, + LastRequestTimestamp: 1, + } +} + +func TestInMemoryChannelStorage_GetMissing(t *testing.T) { + s := NewInMemoryChannelStorage() + got, err := s.Get("missing") + if err != nil { + t.Fatalf("err: %v", err) + } + if got != nil { + t.Fatalf("expected nil") + } +} + +func TestInMemoryChannelStorage_SetGet(t *testing.T) { + s := NewInMemoryChannelStorage() + in := sampleSession("ch", "10") + if err := s.Set("ch", in); err != nil { + t.Fatalf("Set: %v", err) + } + got, err := s.Get("ch") + if err != nil { + t.Fatalf("Get: %v", err) + } + if !reflect.DeepEqual(in, got) { + t.Fatalf("round-trip mismatch") + } +} + +func TestInMemoryChannelStorage_ReturnsCopy(t *testing.T) { + s := NewInMemoryChannelStorage() + in := sampleSession("ch", "10") + _ = s.Set("ch", in) + in.Balance = "999" + got, _ := s.Get("ch") + if got.Balance != "900" { + t.Fatalf("input pointer shared") + } + got.Balance = "1" + got2, _ := s.Get("ch") + if got2.Balance != "900" { + t.Fatalf("output pointer shared") + } +} + +func TestInMemoryChannelStorage_Delete(t *testing.T) { + s := NewInMemoryChannelStorage() + _ = s.Set("ch", sampleSession("ch", "10")) + if err := s.Delete("ch"); err != nil { + t.Fatalf("Delete: %v", err) + } + if got, _ := s.Get("ch"); got != nil { + t.Fatalf("expected nil after delete") + } + if err := s.Delete("missing"); err != nil { + t.Fatalf("Delete missing: %v", err) + } +} + +func TestInMemoryChannelStorage_List(t *testing.T) { + s := NewInMemoryChannelStorage() + _ = s.Set("a", sampleSession("a", "1")) + _ = s.Set("b", sampleSession("b", "2")) + got, err := s.List() + if err != nil { + t.Fatalf("List: %v", err) + } + if len(got) != 2 { + t.Fatalf("expected 2 sessions, got %d", len(got)) + } + sort.Slice(got, func(i, j int) bool { return got[i].ChannelId < got[j].ChannelId }) + if got[0].ChannelId != "a" || got[1].ChannelId != "b" { + t.Fatalf("ids = %s, %s", got[0].ChannelId, got[1].ChannelId) + } +} + +func TestInMemoryChannelStorage_CompareAndSet_FirstWriteWins(t *testing.T) { + s := NewInMemoryChannelStorage() + ok, err := s.CompareAndSet("ch", "0", sampleSession("ch", "10")) + if err != nil || !ok { + t.Fatalf("CAS on missing should succeed: ok=%v err=%v", ok, err) + } + got, _ := s.Get("ch") + if got.ChargedCumulativeAmount != "10" { + t.Fatalf("not stored") + } +} + +func TestInMemoryChannelStorage_CompareAndSet_StaleFails(t *testing.T) { + s := NewInMemoryChannelStorage() + _ = s.Set("ch", sampleSession("ch", "10")) + ok, err := s.CompareAndSet("ch", "0", sampleSession("ch", "20")) + if err != nil { + t.Fatalf("err: %v", err) + } + if ok { + t.Fatal("stale CAS should fail") + } + got, _ := s.Get("ch") + if got.ChargedCumulativeAmount != "10" { + t.Fatalf("storage mutated by failed CAS: %s", got.ChargedCumulativeAmount) + } +} + +func TestInMemoryChannelStorage_CompareAndSet_FreshSucceeds(t *testing.T) { + s := NewInMemoryChannelStorage() + _ = s.Set("ch", sampleSession("ch", "10")) + ok, err := s.CompareAndSet("ch", "10", sampleSession("ch", "20")) + if err != nil || !ok { + t.Fatalf("CAS with matching expected should succeed: ok=%v err=%v", ok, err) + } + got, _ := s.Get("ch") + if got.ChargedCumulativeAmount != "20" { + t.Fatalf("CAS did not update: %s", got.ChargedCumulativeAmount) + } +} + +func TestInMemoryChannelStorage_Concurrent(t *testing.T) { + s := NewInMemoryChannelStorage() + var wg sync.WaitGroup + for i := range 50 { + wg.Add(2) + go func(i int) { + defer wg.Done() + _ = s.Set("ch", sampleSession("ch", "10")) + _ = i + }(i) + go func() { + defer wg.Done() + _, _ = s.List() + }() + } + wg.Wait() +} diff --git a/go/mechanisms/evm/batch-settlement/storage_utils.go b/go/mechanisms/evm/batch-settlement/storage_utils.go new file mode 100644 index 0000000000..8f4bdc0e53 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/storage_utils.go @@ -0,0 +1,66 @@ +package batchsettlement + +import ( + "crypto/rand" + "encoding/hex" + "encoding/json" + "errors" + "fmt" + "io/fs" + "os" + "path/filepath" +) + +// IsNotExist returns true when err is a "file does not exist" error. +func IsNotExist(err error) bool { + return errors.Is(err, fs.ErrNotExist) || errors.Is(err, os.ErrNotExist) +} + +// ReadJSONFile reads filePath and unmarshals the JSON into out. +// Returns (false, nil) if the file does not exist; (true, nil) on success. +// Other errors (permissions, malformed JSON) are returned as-is. +func ReadJSONFile(filePath string, out interface{}) (bool, error) { + raw, err := os.ReadFile(filePath) + if err != nil { + if IsNotExist(err) { + return false, nil + } + return false, fmt.Errorf("read %s: %w", filePath, err) + } + if err := json.Unmarshal(raw, out); err != nil { + return false, fmt.Errorf("unmarshal %s: %w", filePath, err) + } + return true, nil +} + +// WriteJSONAtomic writes value as JSON to filePath atomically (write to temp file +// in the same directory, then rename). Creates parent directories as needed. +func WriteJSONAtomic(filePath string, value interface{}) error { + dir := filepath.Dir(filePath) + if err := os.MkdirAll(dir, 0o755); err != nil { + return fmt.Errorf("mkdir %s: %w", dir, err) + } + body, err := json.MarshalIndent(value, "", " ") + if err != nil { + return fmt.Errorf("marshal: %w", err) + } + body = append(body, '\n') + + var randSuffix [8]byte + if _, err := rand.Read(randSuffix[:]); err != nil { + return fmt.Errorf("rand: %w", err) + } + tmp := filepath.Join(dir, fmt.Sprintf(".%d.%s.tmp", os.Getpid(), hex.EncodeToString(randSuffix[:]))) + if err := os.WriteFile(tmp, body, 0o644); err != nil { + return fmt.Errorf("write tmp %s: %w", tmp, err) + } + if err := os.Rename(tmp, filePath); err != nil { + // On Windows, rename onto an existing file fails; unlink + rename is intentional. + _ = os.Remove(filePath) + if err2 := os.Rename(tmp, filePath); err2 != nil { + _ = os.Remove(tmp) + return fmt.Errorf("rename %s -> %s: %w", tmp, filePath, err2) + } + } + return nil +} diff --git a/go/mechanisms/evm/batch-settlement/storage_utils_test.go b/go/mechanisms/evm/batch-settlement/storage_utils_test.go new file mode 100644 index 0000000000..fc0da5de0e --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/storage_utils_test.go @@ -0,0 +1,131 @@ +package batchsettlement + +import ( + "errors" + "io/fs" + "os" + "path/filepath" + "reflect" + "testing" +) + +func TestIsNotExist(t *testing.T) { + if !IsNotExist(fs.ErrNotExist) { + t.Fatal("fs.ErrNotExist should be NotExist") + } + if !IsNotExist(os.ErrNotExist) { + t.Fatal("os.ErrNotExist should be NotExist") + } + if IsNotExist(errors.New("other")) { + t.Fatal("arbitrary error should not be NotExist") + } + if IsNotExist(nil) { + t.Fatal("nil should not be NotExist") + } +} + +func TestReadJSONFile_Missing(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "missing.json") + var out map[string]interface{} + exists, err := ReadJSONFile(path, &out) + if err != nil { + t.Fatalf("err: %v", err) + } + if exists { + t.Fatal("expected exists=false") + } +} + +func TestReadJSONFile_RoundTrip(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "data.json") + + in := map[string]interface{}{"k": "v", "n": float64(42)} + if err := WriteJSONAtomic(path, in); err != nil { + t.Fatalf("WriteJSONAtomic: %v", err) + } + + var out map[string]interface{} + exists, err := ReadJSONFile(path, &out) + if err != nil { + t.Fatalf("ReadJSONFile: %v", err) + } + if !exists { + t.Fatal("expected exists=true") + } + if !reflect.DeepEqual(in, out) { + t.Fatalf("round-trip mismatch:\nwant %v\ngot %v", in, out) + } +} + +func TestReadJSONFile_Malformed(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "bad.json") + if err := os.WriteFile(path, []byte("not json{"), 0o644); err != nil { + t.Fatalf("setup: %v", err) + } + var out map[string]interface{} + if _, err := ReadJSONFile(path, &out); err == nil { + t.Fatal("expected error") + } +} + +func TestWriteJSONAtomic_CreatesParentDirs(t *testing.T) { + dir := t.TempDir() + nested := filepath.Join(dir, "a", "b", "c", "data.json") + if err := WriteJSONAtomic(nested, map[string]interface{}{"x": 1}); err != nil { + t.Fatalf("err: %v", err) + } + if _, err := os.Stat(nested); err != nil { + t.Fatalf("file not created: %v", err) + } +} + +func TestWriteJSONAtomic_Overwrites(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "data.json") + + if err := WriteJSONAtomic(path, map[string]interface{}{"v": 1}); err != nil { + t.Fatalf("first write: %v", err) + } + if err := WriteJSONAtomic(path, map[string]interface{}{"v": 2}); err != nil { + t.Fatalf("overwrite: %v", err) + } + + var out map[string]interface{} + if _, err := ReadJSONFile(path, &out); err != nil { + t.Fatalf("read: %v", err) + } + if out["v"].(float64) != 2 { + t.Fatalf("not overwritten: got %v", out) + } +} + +func TestWriteJSONAtomic_NoTempLeaks(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "data.json") + if err := WriteJSONAtomic(path, map[string]interface{}{"x": 1}); err != nil { + t.Fatalf("err: %v", err) + } + entries, err := os.ReadDir(dir) + if err != nil { + t.Fatalf("readdir: %v", err) + } + for _, e := range entries { + if e.Name() == "data.json" { + continue + } + t.Fatalf("leaked temp file: %s", e.Name()) + } +} + +type unmarshalable struct{ Ch chan int } + +func TestWriteJSONAtomic_MarshalError(t *testing.T) { + dir := t.TempDir() + path := filepath.Join(dir, "data.json") + if err := WriteJSONAtomic(path, unmarshalable{Ch: make(chan int)}); err == nil { + t.Fatal("expected marshal error") + } +} diff --git a/go/mechanisms/evm/batch-settlement/types.go b/go/mechanisms/evm/batch-settlement/types.go new file mode 100644 index 0000000000..125ceefc30 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/types.go @@ -0,0 +1,845 @@ +package batchsettlement + +import ( + "context" + "fmt" + "math/big" +) + +// AuthorizerSigner is the interface for a dedicated key that provides EIP-712 +// signatures for claim / refund settle-action payloads. +type AuthorizerSigner interface { + Address() string + SignClaimBatch(ctx context.Context, claims []BatchSettlementVoucherClaim, network string) ([]byte, error) + SignRefund(ctx context.Context, channelId string, amount string, nonce string, network string) ([]byte, error) +} + +// ChannelConfig is the immutable configuration for a payment channel. +// channelId = EIP-712 hashTypedData of ChannelConfig with the BatchSettlement domain. +type ChannelConfig struct { + Payer string `json:"payer"` + PayerAuthorizer string `json:"payerAuthorizer"` + Receiver string `json:"receiver"` + ReceiverAuthorizer string `json:"receiverAuthorizer"` + Token string `json:"token"` + WithdrawDelay int `json:"withdrawDelay"` + Salt string `json:"salt"` +} + +// ChannelState represents onchain state read from the BatchSettlement contract. +type ChannelState struct { + Balance *big.Int + TotalClaimed *big.Int + WithdrawRequestedAt int + RefundNonce *big.Int +} + +// AssetTransferMethod identifies how a deposit moves tokens into the channel: +// either an ERC-3009 ReceiveWithAuthorization (default) or a Permit2 +// channel-bound PermitWitnessTransferFrom. Servers opt into a non-default +// method by setting `accepts.extra.assetTransferMethod` on payment +// requirements; clients dispatch on the same field. +type AssetTransferMethod string + +const ( + // AssetTransferMethodEip3009 is the default — uses USDC's + // `transferWithAuthorization` (EIP-3009) via the ERC3009DepositCollector. + AssetTransferMethodEip3009 AssetTransferMethod = "eip3009" + + // AssetTransferMethodPermit2 funds the deposit via a channel-bound + // `PermitWitnessTransferFrom` against the universal Permit2 contract, + // brokered by the Permit2DepositCollector. + AssetTransferMethodPermit2 AssetTransferMethod = "permit2" +) + +// BatchSettlementErc3009Authorization represents the ERC-3009 ReceiveWithAuthorization params. +type BatchSettlementErc3009Authorization struct { + ValidAfter string `json:"validAfter"` + ValidBefore string `json:"validBefore"` + Salt string `json:"salt"` + Signature string `json:"signature"` +} + +// BatchSettlementPermit2TokenPermissions is the {token, amount} pair signed inside a +// Permit2 `PermitWitnessTransferFrom` authorization. +type BatchSettlementPermit2TokenPermissions struct { + Token string `json:"token"` + Amount string `json:"amount"` +} + +// BatchSettlementPermit2Witness is the channel-bound witness binding a Permit2 transfer +// to a specific batch-settlement channel id. +type BatchSettlementPermit2Witness struct { + ChannelId string `json:"channelId"` +} + +// BatchSettlementPermit2Authorization is the Permit2 PermitWitnessTransferFrom +// authorization signed by the payer when the deposit uses the permit2 transfer +// method. +type BatchSettlementPermit2Authorization struct { + From string `json:"from"` + Permitted BatchSettlementPermit2TokenPermissions `json:"permitted"` + Spender string `json:"spender"` + Nonce string `json:"nonce"` + Deadline string `json:"deadline"` + Witness BatchSettlementPermit2Witness `json:"witness"` + Signature string `json:"signature"` +} + +// BatchSettlementVoucherFields holds the cumulative-ceiling voucher. +type BatchSettlementVoucherFields struct { + ChannelId string `json:"channelId"` + MaxClaimableAmount string `json:"maxClaimableAmount"` + Signature string `json:"signature"` +} + +// BatchSettlementDepositAuthorization wraps asset-transfer authorization data. +// Exactly one of the fields is populated per deposit (`erc3009Authorization` +// XOR `permit2Authorization`). +type BatchSettlementDepositAuthorization struct { + Erc3009Authorization *BatchSettlementErc3009Authorization `json:"erc3009Authorization,omitempty"` + Permit2Authorization *BatchSettlementPermit2Authorization `json:"permit2Authorization,omitempty"` +} + +// BatchSettlementDepositData is the deposit portion of a deposit payload. +type BatchSettlementDepositData struct { + Amount string `json:"amount"` + Authorization BatchSettlementDepositAuthorization `json:"authorization"` +} + +// BatchSettlementDepositPayload is sent on the first request to fund a channel. +type BatchSettlementDepositPayload struct { + Type string `json:"type"` // "deposit" + ChannelConfig ChannelConfig `json:"channelConfig"` + Voucher BatchSettlementVoucherFields `json:"voucher"` + Deposit BatchSettlementDepositData `json:"deposit"` +} + +// BatchSettlementVoucherPayload is sent on subsequent requests (no new deposit). +type BatchSettlementVoucherPayload struct { + Type string `json:"type"` // "voucher" + ChannelConfig ChannelConfig `json:"channelConfig"` + Voucher BatchSettlementVoucherFields `json:"voucher"` +} + +// BatchSettlementRefundPayload is the client-side cooperative-refund request. +// `Amount` is optional — when absent, it defaults to the full remaining balance. +type BatchSettlementRefundPayload struct { + Type string `json:"type"` // "refund" + ChannelConfig ChannelConfig `json:"channelConfig"` + Voucher BatchSettlementVoucherFields `json:"voucher"` + Amount string `json:"amount,omitempty"` +} + +// BatchSettlementVoucherClaim is used in claim operations onchain. +type BatchSettlementVoucherClaim struct { + Voucher struct { + Channel ChannelConfig `json:"channel"` + MaxClaimableAmount string `json:"maxClaimableAmount"` + } `json:"voucher"` + Signature string `json:"signature"` + TotalClaimed string `json:"totalClaimed"` +} + +// BatchSettlementChannelStateExtra is the public per-channel state snapshot embedded in +// settle/verify response extras. +type BatchSettlementChannelStateExtra struct { + ChannelId string `json:"channelId"` + Balance string `json:"balance"` + TotalClaimed string `json:"totalClaimed"` + WithdrawRequestedAt int `json:"withdrawRequestedAt"` + RefundNonce string `json:"refundNonce"` + ChargedCumulativeAmount string `json:"chargedCumulativeAmount,omitempty"` +} + +// BatchSettlementVoucherStateExtra is the public latest-voucher snapshot embedded in +// settle/verify response extras. +type BatchSettlementVoucherStateExtra struct { + SignedMaxClaimable string `json:"signedMaxClaimable,omitempty"` + Signature string `json:"signature,omitempty"` +} + +// BatchSettlementPaymentResponseExtra carries channel state in settle/verify responses. +type BatchSettlementPaymentResponseExtra struct { + ChargedAmount string `json:"chargedAmount,omitempty"` + ChannelState *BatchSettlementChannelStateExtra `json:"channelState,omitempty"` + VoucherState *BatchSettlementVoucherStateExtra `json:"voucherState,omitempty"` +} + +// BatchSettlementPaymentRequirementsExtra is the typed shape of the `extra` +// field on PaymentRequirements for the batch-settlement scheme. The +// corrective-402 recovery payload is split across two camelCase keys: +// `channelState` (channel snapshot) and `voucherState` (latest signed voucher +// proof). +type BatchSettlementPaymentRequirementsExtra struct { + ReceiverAuthorizer string `json:"receiverAuthorizer"` + WithdrawDelay int `json:"withdrawDelay"` + Name string `json:"name"` + Version string `json:"version"` + AssetTransferMethod string `json:"assetTransferMethod,omitempty"` // "eip3009" or "permit2" + ChannelState *BatchSettlementChannelStateExtra `json:"channelState,omitempty"` + VoucherState *BatchSettlementVoucherStateExtra `json:"voucherState,omitempty"` +} + +// FileChannelStorageOptions configures file-backed channel storage. +// Channels are stored under {Directory}/{client|server}/{channelId}.json. +type FileChannelStorageOptions struct { + Directory string +} + +// --- Settle Action Payloads (server -> facilitator) --- +// All settle-action payloads use the `type` discriminator, the same field as +// client-side payloads. + +// BatchSettlementClaimPayload batches claims with receiverAuthorizer signature. +// ClaimAuthorizerSignature is optional — when absent, the facilitator auto-signs +// using its AuthorizerSigner. +type BatchSettlementClaimPayload struct { + Type string `json:"type"` // "claim" + Claims []BatchSettlementVoucherClaim `json:"claims"` + ClaimAuthorizerSignature string `json:"claimAuthorizerSignature,omitempty"` +} + +// BatchSettlementSettlePayload transfers claimed funds to receiver. +type BatchSettlementSettlePayload struct { + Type string `json:"type"` // "settle" + Receiver string `json:"receiver"` + Token string `json:"token"` +} + +// BatchSettlementEnrichedRefundPayload is a refund payload enriched by the server with +// the resolved amount, refundNonce, and any claims that need to be included +// atomically with the refund. RefundAuthorizerSignature and +// ClaimAuthorizerSignature are optional — when absent, the facilitator +// auto-signs via its AuthorizerSigner. +type BatchSettlementEnrichedRefundPayload struct { + Type string `json:"type"` // "refund" + ChannelConfig ChannelConfig `json:"channelConfig"` + Voucher BatchSettlementVoucherFields `json:"voucher"` + Amount string `json:"amount"` + RefundNonce string `json:"refundNonce"` + Claims []BatchSettlementVoucherClaim `json:"claims"` + RefundAuthorizerSignature string `json:"refundAuthorizerSignature,omitempty"` + ClaimAuthorizerSignature string `json:"claimAuthorizerSignature,omitempty"` +} + +// ============================================================================ +// Type Guard Functions +// ============================================================================ + +// IsDepositPayload checks if a raw payload map is a batched deposit payload. +func IsDepositPayload(data map[string]interface{}) bool { + typ, _ := data["type"].(string) + _, hasConfig := data["channelConfig"] + _, hasVoucher := data["voucher"] + _, hasDeposit := data["deposit"] + return typ == "deposit" && hasConfig && hasVoucher && hasDeposit +} + +// IsVoucherPayload checks if a raw payload map is a batched voucher-only payload. +func IsVoucherPayload(data map[string]interface{}) bool { + typ, _ := data["type"].(string) + _, hasConfig := data["channelConfig"] + _, hasVoucher := data["voucher"] + return typ == "voucher" && hasConfig && hasVoucher +} + +// IsRefundPayload checks if a raw payload map is a client-side refund payload. +func IsRefundPayload(data map[string]interface{}) bool { + typ, _ := data["type"].(string) + _, hasConfig := data["channelConfig"] + _, hasVoucher := data["voucher"] + return typ == "refund" && hasConfig && hasVoucher +} + +// IsClaimPayload checks if a raw payload map is a claim settle-action payload. +// The claimAuthorizerSignature field is optional (facilitator auto-signs when absent). +func IsClaimPayload(data map[string]interface{}) bool { + typ, _ := data["type"].(string) + _, hasClaims := data["claims"] + return typ == "claim" && hasClaims +} + +// IsSettlePayload checks if a raw payload map is a settle action (transfer to receiver). +func IsSettlePayload(data map[string]interface{}) bool { + typ, _ := data["type"].(string) + _, hasReceiver := data["receiver"] + _, hasToken := data["token"] + return typ == "settle" && hasReceiver && hasToken +} + +// IsEnrichedRefundPayload checks if a raw payload is an enriched refund settle-action. +// The amount + refundNonce + claims fields are added by the server's enrichment hook. +func IsEnrichedRefundPayload(data map[string]interface{}) bool { + if !IsRefundPayload(data) { + return false + } + _, hasAmount := data["amount"] + _, hasRefundNonce := data["refundNonce"] + _, hasClaims := data["claims"] + return hasAmount && hasRefundNonce && hasClaims +} + +// IsBatchedPayload checks if a raw payload map is any batched payload type. +func IsBatchedPayload(data map[string]interface{}) bool { + return IsDepositPayload(data) || IsVoucherPayload(data) || IsRefundPayload(data) +} + +// ============================================================================ +// FromMap Converters +// ============================================================================ + +// ChannelConfigFromMap parses a ChannelConfig from a raw map. +func ChannelConfigFromMap(data map[string]interface{}) (ChannelConfig, error) { + config := ChannelConfig{} + var ok bool + if config.Payer, ok = data["payer"].(string); !ok { + return config, fmt.Errorf("missing or invalid channelConfig.payer") + } + if config.PayerAuthorizer, ok = data["payerAuthorizer"].(string); !ok { + return config, fmt.Errorf("missing or invalid channelConfig.payerAuthorizer") + } + if config.Receiver, ok = data["receiver"].(string); !ok { + return config, fmt.Errorf("missing or invalid channelConfig.receiver") + } + if config.ReceiverAuthorizer, ok = data["receiverAuthorizer"].(string); !ok { + return config, fmt.Errorf("missing or invalid channelConfig.receiverAuthorizer") + } + if config.Token, ok = data["token"].(string); !ok { + return config, fmt.Errorf("missing or invalid channelConfig.token") + } + if config.Salt, ok = data["salt"].(string); !ok { + return config, fmt.Errorf("missing or invalid channelConfig.salt") + } + switch v := data["withdrawDelay"].(type) { + case float64: + config.WithdrawDelay = int(v) + case int: + config.WithdrawDelay = v + case int64: + config.WithdrawDelay = int(v) + default: + return config, fmt.Errorf("missing or invalid channelConfig.withdrawDelay") + } + return config, nil +} + +// voucherFieldsFromMap parses BatchSettlementVoucherFields from a raw map. +func voucherFieldsFromMap(data map[string]interface{}) BatchSettlementVoucherFields { + v := BatchSettlementVoucherFields{} + v.ChannelId, _ = data["channelId"].(string) + v.MaxClaimableAmount, _ = data["maxClaimableAmount"].(string) + v.Signature, _ = data["signature"].(string) + return v +} + +// erc3009AuthFromMap parses an ERC-3009 authorization from a raw map. +func erc3009AuthFromMap(data map[string]interface{}) *BatchSettlementErc3009Authorization { + auth := &BatchSettlementErc3009Authorization{} + auth.ValidAfter, _ = data["validAfter"].(string) + auth.ValidBefore, _ = data["validBefore"].(string) + auth.Salt, _ = data["salt"].(string) + auth.Signature, _ = data["signature"].(string) + return auth +} + +// permit2AuthFromMap parses a Permit2 PermitWitnessTransferFrom authorization +// from a raw map. Returns nil if `permitted` or `witness` are missing. +func permit2AuthFromMap(data map[string]interface{}) *BatchSettlementPermit2Authorization { + if data == nil { + return nil + } + auth := &BatchSettlementPermit2Authorization{} + auth.From, _ = data["from"].(string) + auth.Spender, _ = data["spender"].(string) + auth.Nonce, _ = data["nonce"].(string) + auth.Deadline, _ = data["deadline"].(string) + auth.Signature, _ = data["signature"].(string) + if permitted, ok := data["permitted"].(map[string]interface{}); ok { + auth.Permitted.Token, _ = permitted["token"].(string) + auth.Permitted.Amount, _ = permitted["amount"].(string) + } else { + return nil + } + if witness, ok := data["witness"].(map[string]interface{}); ok { + auth.Witness.ChannelId, _ = witness["channelId"].(string) + } else { + return nil + } + return auth +} + +// DepositPayloadFromMap creates a BatchSettlementDepositPayload from a raw map. +func DepositPayloadFromMap(data map[string]interface{}) (*BatchSettlementDepositPayload, error) { + payload := &BatchSettlementDepositPayload{Type: "deposit"} + + configMap, ok := data["channelConfig"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid channelConfig") + } + config, err := ChannelConfigFromMap(configMap) + if err != nil { + return nil, fmt.Errorf("invalid channelConfig: %w", err) + } + payload.ChannelConfig = config + + voucherMap, ok := data["voucher"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid voucher") + } + payload.Voucher = voucherFieldsFromMap(voucherMap) + + depositMap, ok := data["deposit"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid deposit field") + } + payload.Deposit.Amount, _ = depositMap["amount"].(string) + + if authMap, ok := depositMap["authorization"].(map[string]interface{}); ok { + if erc3009Map, ok := authMap["erc3009Authorization"].(map[string]interface{}); ok { + payload.Deposit.Authorization.Erc3009Authorization = erc3009AuthFromMap(erc3009Map) + } + if permit2Map, ok := authMap["permit2Authorization"].(map[string]interface{}); ok { + payload.Deposit.Authorization.Permit2Authorization = permit2AuthFromMap(permit2Map) + } + } + + return payload, nil +} + +// VoucherPayloadFromMap creates a BatchSettlementVoucherPayload from a raw map. +func VoucherPayloadFromMap(data map[string]interface{}) (*BatchSettlementVoucherPayload, error) { + payload := &BatchSettlementVoucherPayload{Type: "voucher"} + + configMap, ok := data["channelConfig"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid channelConfig") + } + config, err := ChannelConfigFromMap(configMap) + if err != nil { + return nil, fmt.Errorf("invalid channelConfig: %w", err) + } + payload.ChannelConfig = config + + voucherMap, ok := data["voucher"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid voucher") + } + payload.Voucher = voucherFieldsFromMap(voucherMap) + return payload, nil +} + +// RefundPayloadFromMap creates a BatchSettlementRefundPayload from a raw map. +func RefundPayloadFromMap(data map[string]interface{}) (*BatchSettlementRefundPayload, error) { + payload := &BatchSettlementRefundPayload{Type: "refund"} + + configMap, ok := data["channelConfig"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid channelConfig") + } + config, err := ChannelConfigFromMap(configMap) + if err != nil { + return nil, fmt.Errorf("invalid channelConfig: %w", err) + } + payload.ChannelConfig = config + + voucherMap, ok := data["voucher"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid voucher") + } + payload.Voucher = voucherFieldsFromMap(voucherMap) + payload.Amount, _ = data["amount"].(string) + return payload, nil +} + +// VoucherClaimFromMap parses a single BatchSettlementVoucherClaim from a raw map. +func VoucherClaimFromMap(data map[string]interface{}) (*BatchSettlementVoucherClaim, error) { + claim := &BatchSettlementVoucherClaim{} + + voucherMap, ok := data["voucher"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid voucher field") + } + channelMap, ok := voucherMap["channel"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid voucher.channel") + } + config, err := ChannelConfigFromMap(channelMap) + if err != nil { + return nil, fmt.Errorf("invalid voucher.channel: %w", err) + } + claim.Voucher.Channel = config + claim.Voucher.MaxClaimableAmount, _ = voucherMap["maxClaimableAmount"].(string) + claim.Signature, _ = data["signature"].(string) + claim.TotalClaimed, _ = data["totalClaimed"].(string) + return claim, nil +} + +// VoucherClaimsFromList parses a list of BatchSettlementVoucherClaim from a raw slice. +func VoucherClaimsFromList(data []interface{}) ([]BatchSettlementVoucherClaim, error) { + claims := make([]BatchSettlementVoucherClaim, 0, len(data)) + for i, item := range data { + itemMap, ok := item.(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("claims[%d] is not a map", i) + } + claim, err := VoucherClaimFromMap(itemMap) + if err != nil { + return nil, fmt.Errorf("claims[%d]: %w", i, err) + } + claims = append(claims, *claim) + } + return claims, nil +} + +// ClaimPayloadFromMap creates a BatchSettlementClaimPayload from a raw map. +func ClaimPayloadFromMap(data map[string]interface{}) (*BatchSettlementClaimPayload, error) { + payload := &BatchSettlementClaimPayload{Type: "claim"} + claimsList, ok := data["claims"].([]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid claims") + } + claims, err := VoucherClaimsFromList(claimsList) + if err != nil { + return nil, err + } + payload.Claims = claims + payload.ClaimAuthorizerSignature, _ = data["claimAuthorizerSignature"].(string) + return payload, nil +} + +// SettlePayloadFromMap creates a BatchSettlementSettlePayload from a raw map. +func SettlePayloadFromMap(data map[string]interface{}) (*BatchSettlementSettlePayload, error) { + payload := &BatchSettlementSettlePayload{Type: "settle"} + payload.Receiver, _ = data["receiver"].(string) + payload.Token, _ = data["token"].(string) + return payload, nil +} + +// EnrichedRefundPayloadFromMap creates a BatchSettlementEnrichedRefundPayload from a raw map. +func EnrichedRefundPayloadFromMap(data map[string]interface{}) (*BatchSettlementEnrichedRefundPayload, error) { + payload := &BatchSettlementEnrichedRefundPayload{Type: "refund"} + configMap, ok := data["channelConfig"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid channelConfig") + } + config, err := ChannelConfigFromMap(configMap) + if err != nil { + return nil, err + } + payload.ChannelConfig = config + + voucherMap, ok := data["voucher"].(map[string]interface{}) + if !ok { + return nil, fmt.Errorf("missing or invalid voucher") + } + payload.Voucher = voucherFieldsFromMap(voucherMap) + + payload.Amount, _ = data["amount"].(string) + payload.RefundNonce, _ = data["refundNonce"].(string) + payload.RefundAuthorizerSignature, _ = data["refundAuthorizerSignature"].(string) + payload.ClaimAuthorizerSignature, _ = data["claimAuthorizerSignature"].(string) + if claimsList, ok := data["claims"].([]interface{}); ok { + claims, err := VoucherClaimsFromList(claimsList) + if err != nil { + return nil, err + } + payload.Claims = claims + } + return payload, nil +} + +// ============================================================================ +// ToMap Converters +// ============================================================================ + +// ChannelConfigToMap converts a ChannelConfig to a map. +func ChannelConfigToMap(c ChannelConfig) map[string]interface{} { + return map[string]interface{}{ + "payer": c.Payer, + "payerAuthorizer": c.PayerAuthorizer, + "receiver": c.Receiver, + "receiverAuthorizer": c.ReceiverAuthorizer, + "token": c.Token, + "withdrawDelay": c.WithdrawDelay, + "salt": c.Salt, + } +} + +func voucherFieldsToMap(v BatchSettlementVoucherFields) map[string]interface{} { + return map[string]interface{}{ + "channelId": v.ChannelId, + "maxClaimableAmount": v.MaxClaimableAmount, + "signature": v.Signature, + } +} + +// ToMap converts a BatchSettlementDepositPayload to a map. +func (p *BatchSettlementDepositPayload) ToMap() map[string]interface{} { + authMap := map[string]interface{}{} + if p.Deposit.Authorization.Erc3009Authorization != nil { + a := p.Deposit.Authorization.Erc3009Authorization + authMap["erc3009Authorization"] = map[string]interface{}{ + "validAfter": a.ValidAfter, + "validBefore": a.ValidBefore, + "salt": a.Salt, + "signature": a.Signature, + } + } + if p.Deposit.Authorization.Permit2Authorization != nil { + a := p.Deposit.Authorization.Permit2Authorization + authMap["permit2Authorization"] = map[string]interface{}{ + "from": a.From, + "permitted": map[string]interface{}{ + "token": a.Permitted.Token, + "amount": a.Permitted.Amount, + }, + "spender": a.Spender, + "nonce": a.Nonce, + "deadline": a.Deadline, + "witness": map[string]interface{}{ + "channelId": a.Witness.ChannelId, + }, + "signature": a.Signature, + } + } + return map[string]interface{}{ + "type": "deposit", + "channelConfig": ChannelConfigToMap(p.ChannelConfig), + "voucher": voucherFieldsToMap(p.Voucher), + "deposit": map[string]interface{}{ + "amount": p.Deposit.Amount, + "authorization": authMap, + }, + } +} + +// ToMap converts a BatchSettlementVoucherPayload to a map. +func (p *BatchSettlementVoucherPayload) ToMap() map[string]interface{} { + return map[string]interface{}{ + "type": "voucher", + "channelConfig": ChannelConfigToMap(p.ChannelConfig), + "voucher": voucherFieldsToMap(p.Voucher), + } +} + +// ToMap converts a BatchSettlementRefundPayload to a map. +func (p *BatchSettlementRefundPayload) ToMap() map[string]interface{} { + result := map[string]interface{}{ + "type": "refund", + "channelConfig": ChannelConfigToMap(p.ChannelConfig), + "voucher": voucherFieldsToMap(p.Voucher), + } + if p.Amount != "" { + result["amount"] = p.Amount + } + return result +} + +// ToMap converts a BatchSettlementClaimPayload to a map. +func (p *BatchSettlementClaimPayload) ToMap() map[string]interface{} { + result := map[string]interface{}{ + "type": "claim", + "claims": VoucherClaimsToList(p.Claims), + } + if p.ClaimAuthorizerSignature != "" { + result["claimAuthorizerSignature"] = p.ClaimAuthorizerSignature + } + return result +} + +// ToMap converts a BatchSettlementSettlePayload to a map. +func (p *BatchSettlementSettlePayload) ToMap() map[string]interface{} { + return map[string]interface{}{ + "type": "settle", + "receiver": p.Receiver, + "token": p.Token, + } +} + +// ToMap converts a BatchSettlementEnrichedRefundPayload to a map. +func (p *BatchSettlementEnrichedRefundPayload) ToMap() map[string]interface{} { + result := map[string]interface{}{ + "type": "refund", + "channelConfig": ChannelConfigToMap(p.ChannelConfig), + "voucher": voucherFieldsToMap(p.Voucher), + "amount": p.Amount, + "refundNonce": p.RefundNonce, + "claims": VoucherClaimsToList(p.Claims), + } + if p.RefundAuthorizerSignature != "" { + result["refundAuthorizerSignature"] = p.RefundAuthorizerSignature + } + if p.ClaimAuthorizerSignature != "" { + result["claimAuthorizerSignature"] = p.ClaimAuthorizerSignature + } + return result +} + +// VoucherClaimToMap converts a BatchSettlementVoucherClaim to a map. +func VoucherClaimToMap(c BatchSettlementVoucherClaim) map[string]interface{} { + return map[string]interface{}{ + "voucher": map[string]interface{}{ + "channel": ChannelConfigToMap(c.Voucher.Channel), + "maxClaimableAmount": c.Voucher.MaxClaimableAmount, + }, + "signature": c.Signature, + "totalClaimed": c.TotalClaimed, + } +} + +// VoucherClaimsToList converts a slice of claims to a raw list. +func VoucherClaimsToList(claims []BatchSettlementVoucherClaim) []interface{} { + list := make([]interface{}, len(claims)) + for i, c := range claims { + list[i] = VoucherClaimToMap(c) + } + return list +} + +// ToMap converts a BatchSettlementPaymentResponseExtra to its canonical nested wire shape. +func (e *BatchSettlementPaymentResponseExtra) ToMap() map[string]interface{} { + out := map[string]interface{}{} + if e.ChargedAmount != "" { + out["chargedAmount"] = e.ChargedAmount + } + if cs := e.ChannelState; cs != nil { + csMap := map[string]interface{}{ + "channelId": cs.ChannelId, + "balance": cs.Balance, + "totalClaimed": cs.TotalClaimed, + "withdrawRequestedAt": cs.WithdrawRequestedAt, + "refundNonce": cs.RefundNonce, + } + if cs.ChargedCumulativeAmount != "" { + csMap["chargedCumulativeAmount"] = cs.ChargedCumulativeAmount + } + out["channelState"] = csMap + } + if vs := e.VoucherState; vs != nil { + vsMap := map[string]interface{}{} + if vs.SignedMaxClaimable != "" { + vsMap["signedMaxClaimable"] = vs.SignedMaxClaimable + } + if vs.Signature != "" { + vsMap["signature"] = vs.Signature + } + if len(vsMap) > 0 { + out["voucherState"] = vsMap + } + } + return out +} + +// PaymentResponseExtraFromMap parses the canonical nested +// `BatchSettlementPaymentResponseExtra` shape from a map. +func PaymentResponseExtraFromMap(data map[string]interface{}) (*BatchSettlementPaymentResponseExtra, error) { + extra := &BatchSettlementPaymentResponseExtra{} + if data == nil { + return extra, nil + } + if v, ok := data["chargedAmount"].(string); ok { + extra.ChargedAmount = v + } + if csRaw, ok := data["channelState"].(map[string]interface{}); ok && csRaw != nil { + cs := &BatchSettlementChannelStateExtra{} + cs.ChannelId, _ = csRaw["channelId"].(string) + cs.Balance, _ = csRaw["balance"].(string) + cs.TotalClaimed, _ = csRaw["totalClaimed"].(string) + cs.RefundNonce, _ = csRaw["refundNonce"].(string) + cs.ChargedCumulativeAmount, _ = csRaw["chargedCumulativeAmount"].(string) + switch v := csRaw["withdrawRequestedAt"].(type) { + case float64: + cs.WithdrawRequestedAt = int(v) + case int: + cs.WithdrawRequestedAt = v + } + extra.ChannelState = cs + } + if vsRaw, ok := data["voucherState"].(map[string]interface{}); ok && vsRaw != nil { + vs := &BatchSettlementVoucherStateExtra{} + vs.SignedMaxClaimable, _ = vsRaw["signedMaxClaimable"].(string) + vs.Signature, _ = vsRaw["signature"].(string) + extra.VoucherState = vs + } + return extra, nil +} + +// ChannelStateRequirementsFromMap parses a channelState entry on +// PaymentRequirements.extra. Returns nil when absent or missing channelId. +func ChannelStateRequirementsFromMap(data map[string]interface{}) *BatchSettlementChannelStateExtra { + if data == nil { + return nil + } + cs := &BatchSettlementChannelStateExtra{} + cs.ChannelId, _ = data["channelId"].(string) + cs.Balance, _ = data["balance"].(string) + cs.TotalClaimed, _ = data["totalClaimed"].(string) + cs.RefundNonce, _ = data["refundNonce"].(string) + cs.ChargedCumulativeAmount, _ = data["chargedCumulativeAmount"].(string) + switch v := data["withdrawRequestedAt"].(type) { + case float64: + cs.WithdrawRequestedAt = int(v) + case int: + cs.WithdrawRequestedAt = v + case int64: + cs.WithdrawRequestedAt = int(v) + } + if cs.ChannelId == "" { + return nil + } + return cs +} + +// VoucherStateRequirementsFromMap parses a voucherState entry on +// PaymentRequirements.extra. Returns nil when absent or empty. +func VoucherStateRequirementsFromMap(data map[string]interface{}) *BatchSettlementVoucherStateExtra { + if data == nil { + return nil + } + vs := &BatchSettlementVoucherStateExtra{} + vs.SignedMaxClaimable, _ = data["signedMaxClaimable"].(string) + vs.Signature, _ = data["signature"].(string) + if vs.SignedMaxClaimable == "" && vs.Signature == "" { + return nil + } + return vs +} + +// ToMap converts a BatchSettlementChannelStateExtra to a map (used for emitting +// `extra.channelState` on corrective-402 PaymentRequirements). +func (cs *BatchSettlementChannelStateExtra) ToMap() map[string]interface{} { + if cs == nil { + return nil + } + result := map[string]interface{}{ + "channelId": cs.ChannelId, + "balance": cs.Balance, + "totalClaimed": cs.TotalClaimed, + "withdrawRequestedAt": cs.WithdrawRequestedAt, + "refundNonce": cs.RefundNonce, + } + if cs.ChargedCumulativeAmount != "" { + result["chargedCumulativeAmount"] = cs.ChargedCumulativeAmount + } + return result +} + +// ToMap converts a BatchSettlementVoucherStateExtra to a map (used for emitting +// `extra.voucherState` on corrective-402 PaymentRequirements). +func (vs *BatchSettlementVoucherStateExtra) ToMap() map[string]interface{} { + if vs == nil { + return nil + } + result := map[string]interface{}{} + if vs.SignedMaxClaimable != "" { + result["signedMaxClaimable"] = vs.SignedMaxClaimable + } + if vs.Signature != "" { + result["signature"] = vs.Signature + } + if len(result) == 0 { + return nil + } + return result +} diff --git a/go/mechanisms/evm/batch-settlement/types_test.go b/go/mechanisms/evm/batch-settlement/types_test.go new file mode 100644 index 0000000000..452b23dd6e --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/types_test.go @@ -0,0 +1,714 @@ +package batchsettlement + +import ( + "reflect" + "testing" +) + +func validChannelConfigMap() map[string]interface{} { + return map[string]interface{}{ + "payer": "0x1111111111111111111111111111111111111111", + "payerAuthorizer": "0x2222222222222222222222222222222222222222", + "receiver": "0x3333333333333333333333333333333333333333", + "receiverAuthorizer": "0x4444444444444444444444444444444444444444", + "token": "0x5555555555555555555555555555555555555555", + "withdrawDelay": float64(900), + "salt": "0x0000000000000000000000000000000000000000000000000000000000000001", + } +} + +func validVoucherSubMap() map[string]interface{} { + return map[string]interface{}{ + "channelId": "0xabc", + "maxClaimableAmount": "1000", + "signature": "0xsig", + } +} + +func validDepositPayloadMap() map[string]interface{} { + return map[string]interface{}{ + "type": "deposit", + "channelConfig": validChannelConfigMap(), + "voucher": validVoucherSubMap(), + "deposit": map[string]interface{}{ + "amount": "1000", + "authorization": map[string]interface{}{ + "erc3009Authorization": map[string]interface{}{ + "validAfter": "0", + "validBefore": "9999999999", + "salt": "0x01", + "signature": "0xdeadbeef", + }, + }, + }, + } +} + +func validVoucherPayloadMap() map[string]interface{} { + return map[string]interface{}{ + "type": "voucher", + "channelConfig": validChannelConfigMap(), + "voucher": validVoucherSubMap(), + } +} + +func validRefundPayloadMap() map[string]interface{} { + return map[string]interface{}{ + "type": "refund", + "channelConfig": validChannelConfigMap(), + "voucher": validVoucherSubMap(), + } +} + +// ---------- Type guards ---------- + +func TestIsDepositPayload(t *testing.T) { + tests := []struct { + name string + in map[string]interface{} + want bool + }{ + {"valid", validDepositPayloadMap(), true}, + {"wrong type", map[string]interface{}{"type": "voucher", "channelConfig": 1, "voucher": 1, "deposit": 1}, false}, + {"missing deposit", map[string]interface{}{"type": "deposit", "channelConfig": 1, "voucher": 1}, false}, + {"missing voucher", map[string]interface{}{"type": "deposit", "channelConfig": 1, "deposit": 1}, false}, + {"missing channelConfig", map[string]interface{}{"type": "deposit", "voucher": 1, "deposit": 1}, false}, + {"empty", map[string]interface{}{}, false}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if got := IsDepositPayload(tc.in); got != tc.want { + t.Fatalf("IsDepositPayload = %v, want %v", got, tc.want) + } + }) + } +} + +func TestIsVoucherPayload(t *testing.T) { + tests := []struct { + name string + in map[string]interface{} + want bool + }{ + {"valid", validVoucherPayloadMap(), true}, + {"wrong type", map[string]interface{}{"type": "deposit", "channelConfig": 1, "voucher": 1}, false}, + {"missing config", map[string]interface{}{"type": "voucher", "voucher": 1}, false}, + {"missing voucher", map[string]interface{}{"type": "voucher", "channelConfig": 1}, false}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if got := IsVoucherPayload(tc.in); got != tc.want { + t.Fatalf("IsVoucherPayload = %v, want %v", got, tc.want) + } + }) + } +} + +func TestIsRefundPayload(t *testing.T) { + tests := []struct { + name string + in map[string]interface{} + want bool + }{ + {"valid", validRefundPayloadMap(), true}, + {"wrong type", map[string]interface{}{"type": "voucher", "channelConfig": 1, "voucher": 1}, false}, + {"missing config", map[string]interface{}{"type": "refund", "voucher": 1}, false}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if got := IsRefundPayload(tc.in); got != tc.want { + t.Fatalf("IsRefundPayload = %v, want %v", got, tc.want) + } + }) + } +} + +func TestIsClaimPayload(t *testing.T) { + tests := []struct { + name string + in map[string]interface{} + want bool + }{ + {"valid", map[string]interface{}{"type": "claim", "claims": []interface{}{}}, true}, + {"wrong type", map[string]interface{}{"type": "settle", "claims": []interface{}{}}, false}, + {"missing claims", map[string]interface{}{"type": "claim"}, false}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if got := IsClaimPayload(tc.in); got != tc.want { + t.Fatalf("got %v, want %v", got, tc.want) + } + }) + } +} + +func TestIsSettlePayload(t *testing.T) { + tests := []struct { + name string + in map[string]interface{} + want bool + }{ + {"valid", map[string]interface{}{"type": "settle", "receiver": "0x1", "token": "0x2"}, true}, + {"wrong type", map[string]interface{}{"type": "claim", "receiver": "0x1", "token": "0x2"}, false}, + {"missing receiver", map[string]interface{}{"type": "settle", "token": "0x2"}, false}, + {"missing token", map[string]interface{}{"type": "settle", "receiver": "0x1"}, false}, + } + for _, tc := range tests { + t.Run(tc.name, func(t *testing.T) { + if got := IsSettlePayload(tc.in); got != tc.want { + t.Fatalf("got %v, want %v", got, tc.want) + } + }) + } +} + +func TestIsEnrichedRefundPayload(t *testing.T) { + enriched := validRefundPayloadMap() + enriched["amount"] = "100" + enriched["refundNonce"] = "0" + enriched["claims"] = []interface{}{} + if !IsEnrichedRefundPayload(enriched) { + t.Fatal("expected enriched refund to be detected") + } + if IsEnrichedRefundPayload(validRefundPayloadMap()) { + t.Fatal("plain refund should not be detected as enriched") + } +} + +func TestIsBatchedPayload(t *testing.T) { + if !IsBatchedPayload(validDepositPayloadMap()) { + t.Fatal("deposit map should be batched") + } + if !IsBatchedPayload(validVoucherPayloadMap()) { + t.Fatal("voucher map should be batched") + } + if !IsBatchedPayload(validRefundPayloadMap()) { + t.Fatal("refund map should be batched") + } + if IsBatchedPayload(map[string]interface{}{"type": "other"}) { + t.Fatal("unrelated map should not be batched") + } +} + +// ---------- ChannelConfigFromMap ---------- + +func TestChannelConfigFromMap_AllNumericTypes(t *testing.T) { + for _, delay := range []interface{}{float64(900), int(900), int64(900)} { + m := validChannelConfigMap() + m["withdrawDelay"] = delay + cc, err := ChannelConfigFromMap(m) + if err != nil { + t.Fatalf("withdrawDelay %T: %v", delay, err) + } + if cc.WithdrawDelay != 900 { + t.Fatalf("withdrawDelay %T: got %d", delay, cc.WithdrawDelay) + } + } +} + +func TestChannelConfigFromMap_MissingFields(t *testing.T) { + required := []string{"payer", "payerAuthorizer", "receiver", "receiverAuthorizer", "token", "salt", "withdrawDelay"} + for _, field := range required { + m := validChannelConfigMap() + delete(m, field) + if _, err := ChannelConfigFromMap(m); err == nil { + t.Fatalf("expected error when missing %s", field) + } + } +} + +func TestChannelConfigFromMap_InvalidWithdrawDelay(t *testing.T) { + m := validChannelConfigMap() + m["withdrawDelay"] = "string" + if _, err := ChannelConfigFromMap(m); err == nil { + t.Fatal("expected error for string withdrawDelay") + } +} + +// ---------- DepositPayloadFromMap / ToMap round-trip ---------- + +func TestDepositPayloadFromMap_ToMap_RoundTrip(t *testing.T) { + original := validDepositPayloadMap() + + p, err := DepositPayloadFromMap(original) + if err != nil { + t.Fatalf("DepositPayloadFromMap: %v", err) + } + if p.Type != "deposit" { + t.Fatalf("Type = %s", p.Type) + } + if p.Deposit.Amount != "1000" { + t.Fatalf("Amount = %s", p.Deposit.Amount) + } + if p.Deposit.Authorization.Erc3009Authorization == nil { + t.Fatal("missing erc3009 authorization") + } + if p.Voucher.ChannelId != "0xabc" || p.Voucher.MaxClaimableAmount != "1000" { + t.Fatalf("voucher fields = %+v", p.Voucher) + } + + out := p.ToMap() + if out["type"] != "deposit" { + t.Fatalf("ToMap type = %v", out["type"]) + } + voucher := out["voucher"].(map[string]interface{}) + if voucher["channelId"] != "0xabc" { + t.Fatalf("ToMap voucher = %v", voucher) + } +} + +func TestDepositPayloadFromMap_MissingDeposit(t *testing.T) { + in := map[string]interface{}{ + "type": "deposit", + "channelConfig": validChannelConfigMap(), + "voucher": validVoucherSubMap(), + } + if _, err := DepositPayloadFromMap(in); err == nil { + t.Fatal("expected error") + } +} + +func TestDepositPayloadFromMap_MissingChannelConfig(t *testing.T) { + in := map[string]interface{}{ + "type": "deposit", + "voucher": validVoucherSubMap(), + "deposit": map[string]interface{}{"amount": "1"}, + } + if _, err := DepositPayloadFromMap(in); err == nil { + t.Fatal("expected error") + } +} + +func TestDepositPayloadFromMap_InvalidChannelConfig(t *testing.T) { + bad := validChannelConfigMap() + delete(bad, "payer") + in := map[string]interface{}{ + "type": "deposit", + "channelConfig": bad, + "voucher": validVoucherSubMap(), + "deposit": map[string]interface{}{"amount": "1"}, + } + if _, err := DepositPayloadFromMap(in); err == nil { + t.Fatal("expected error") + } +} + +// ---------- VoucherPayloadFromMap / ToMap round-trip ---------- + +func TestVoucherPayloadFromMap_ToMap_RoundTrip(t *testing.T) { + original := validVoucherPayloadMap() + p, err := VoucherPayloadFromMap(original) + if err != nil { + t.Fatalf("VoucherPayloadFromMap: %v", err) + } + if p.Voucher.ChannelId != "0xabc" || p.Voucher.MaxClaimableAmount != "1000" || p.Voucher.Signature != "0xsig" { + t.Fatalf("payload fields not parsed: %+v", p) + } + out := p.ToMap() + if out["type"] != "voucher" { + t.Fatalf("ToMap = %v", out) + } +} + +func TestVoucherPayloadFromMap_MissingConfig(t *testing.T) { + if _, err := VoucherPayloadFromMap(map[string]interface{}{"type": "voucher"}); err == nil { + t.Fatal("expected error") + } +} + +func TestVoucherPayloadFromMap_InvalidConfig(t *testing.T) { + bad := validChannelConfigMap() + delete(bad, "payer") + if _, err := VoucherPayloadFromMap(map[string]interface{}{"channelConfig": bad}); err == nil { + t.Fatal("expected error") + } +} + +// ---------- VoucherClaim & list ---------- + +func TestVoucherClaimFromMap_ToMap_RoundTrip(t *testing.T) { + in := map[string]interface{}{ + "voucher": map[string]interface{}{ + "channel": validChannelConfigMap(), + "maxClaimableAmount": "1000", + }, + "signature": "0xsig", + "totalClaimed": "999", + } + c, err := VoucherClaimFromMap(in) + if err != nil { + t.Fatalf("VoucherClaimFromMap: %v", err) + } + if c.Voucher.MaxClaimableAmount != "1000" || c.Signature != "0xsig" || c.TotalClaimed != "999" { + t.Fatalf("parsed = %+v", c) + } + out := VoucherClaimToMap(*c) + if out["totalClaimed"] != "999" { + t.Fatalf("ToMap = %v", out) + } +} + +func TestVoucherClaimFromMap_Errors(t *testing.T) { + if _, err := VoucherClaimFromMap(map[string]interface{}{}); err == nil { + t.Fatal("expected error: missing voucher") + } + if _, err := VoucherClaimFromMap(map[string]interface{}{"voucher": map[string]interface{}{}}); err == nil { + t.Fatal("expected error: missing channel") + } + bad := validChannelConfigMap() + delete(bad, "payer") + if _, err := VoucherClaimFromMap(map[string]interface{}{"voucher": map[string]interface{}{"channel": bad}}); err == nil { + t.Fatal("expected error: invalid channel") + } +} + +func TestVoucherClaimsFromList_RoundTrip(t *testing.T) { + item := map[string]interface{}{ + "voucher": map[string]interface{}{ + "channel": validChannelConfigMap(), + "maxClaimableAmount": "1", + }, + "signature": "0xs", + "totalClaimed": "0", + } + in := []interface{}{item, item} + claims, err := VoucherClaimsFromList(in) + if err != nil { + t.Fatalf("VoucherClaimsFromList: %v", err) + } + if len(claims) != 2 { + t.Fatalf("got %d claims", len(claims)) + } + out := VoucherClaimsToList(claims) + if len(out) != 2 { + t.Fatalf("ToList len = %d", len(out)) + } +} + +func TestVoucherClaimsFromList_Errors(t *testing.T) { + if _, err := VoucherClaimsFromList([]interface{}{"not a map"}); err == nil { + t.Fatal("expected error") + } + if _, err := VoucherClaimsFromList([]interface{}{map[string]interface{}{}}); err == nil { + t.Fatal("expected error") + } +} + +// ---------- ClaimPayloadFromMap ---------- + +func TestClaimPayloadFromMap(t *testing.T) { + in := map[string]interface{}{ + "type": "claim", + "claims": []interface{}{}, + "claimAuthorizerSignature": "0xauth", + } + p, err := ClaimPayloadFromMap(in) + if err != nil { + t.Fatalf("err: %v", err) + } + if p.Type != "claim" || p.ClaimAuthorizerSignature != "0xauth" { + t.Fatalf("parsed = %+v", p) + } + if _, err := ClaimPayloadFromMap(map[string]interface{}{}); err == nil { + t.Fatal("expected error: missing claims") + } + bad := map[string]interface{}{"claims": []interface{}{"not a map"}} + if _, err := ClaimPayloadFromMap(bad); err == nil { + t.Fatal("expected error: bad claim") + } +} + +// ---------- SettlePayloadFromMap ---------- + +func TestSettlePayloadFromMap(t *testing.T) { + p, err := SettlePayloadFromMap(map[string]interface{}{"type": "settle", "receiver": "0x1", "token": "0x2"}) + if err != nil { + t.Fatalf("err: %v", err) + } + if p.Receiver != "0x1" || p.Token != "0x2" || p.Type != "settle" { + t.Fatalf("parsed = %+v", p) + } +} + +// ---------- EnrichedRefundPayloadFromMap ---------- + +func TestEnrichedRefundPayloadFromMap(t *testing.T) { + in := map[string]interface{}{ + "type": "refund", + "channelConfig": validChannelConfigMap(), + "voucher": validVoucherSubMap(), + "amount": "100", + "refundNonce": "1", + "refundAuthorizerSignature": "0xrefund", + "claimAuthorizerSignature": "0xclaim", + "claims": []interface{}{ + map[string]interface{}{ + "voucher": map[string]interface{}{ + "channel": validChannelConfigMap(), + "maxClaimableAmount": "1", + }, + "signature": "0x", + "totalClaimed": "0", + }, + }, + } + p, err := EnrichedRefundPayloadFromMap(in) + if err != nil { + t.Fatalf("err: %v", err) + } + if p.Amount != "100" || p.RefundNonce != "1" || len(p.Claims) != 1 { + t.Fatalf("parsed = %+v", p) + } + + if _, err := EnrichedRefundPayloadFromMap(map[string]interface{}{}); err == nil { + t.Fatal("expected error: missing channelConfig") + } + bad := validChannelConfigMap() + delete(bad, "payer") + if _, err := EnrichedRefundPayloadFromMap(map[string]interface{}{"channelConfig": bad}); err == nil { + t.Fatal("expected error: invalid channelConfig") + } +} + +// ---------- ChannelConfigToMap round-trip ---------- + +func TestChannelConfigToMap_RoundTrip(t *testing.T) { + cc := ChannelConfig{ + Payer: "0x1", + PayerAuthorizer: "0x2", + Receiver: "0x3", + ReceiverAuthorizer: "0x4", + Token: "0x5", + WithdrawDelay: 900, + Salt: "0xdead", + } + m := ChannelConfigToMap(cc) + parsed, err := ChannelConfigFromMap(m) + if err != nil { + t.Fatalf("err: %v", err) + } + if !reflect.DeepEqual(cc, parsed) { + t.Fatalf("round-trip mismatch:\nwant %+v\ngot %+v", cc, parsed) + } +} + +// ---------- PaymentResponseExtra round-trip ---------- + +func TestPaymentResponseExtra_RoundTrip(t *testing.T) { + e := &BatchSettlementPaymentResponseExtra{ + ChargedAmount: "10", + ChannelState: &BatchSettlementChannelStateExtra{ + ChannelId: "0xabc", + Balance: "900", + TotalClaimed: "50", + WithdrawRequestedAt: 1234, + RefundNonce: "1", + ChargedCumulativeAmount: "100", + }, + VoucherState: &BatchSettlementVoucherStateExtra{ + SignedMaxClaimable: "200", + Signature: "0xdeadbeef", + }, + } + out := e.ToMap() + parsed, err := PaymentResponseExtraFromMap(out) + if err != nil { + t.Fatalf("err: %v", err) + } + if parsed.ChargedAmount != e.ChargedAmount { + t.Fatalf("ChargedAmount = %q, want %q", parsed.ChargedAmount, e.ChargedAmount) + } + if !reflect.DeepEqual(parsed.ChannelState, e.ChannelState) { + t.Fatalf("ChannelState mismatch:\nwant %+v\ngot %+v", e.ChannelState, parsed.ChannelState) + } + if !reflect.DeepEqual(parsed.VoucherState, e.VoucherState) { + t.Fatalf("VoucherState mismatch:\nwant %+v\ngot %+v", e.VoucherState, parsed.VoucherState) + } +} + +func TestPaymentResponseExtra_FromMap_NumericWithdrawRequestedAt(t *testing.T) { + for _, v := range []interface{}{float64(1234), int(1234)} { + m := map[string]interface{}{ + "channelState": map[string]interface{}{ + "channelId": "0xabc", + "withdrawRequestedAt": v, + }, + } + parsed, err := PaymentResponseExtraFromMap(m) + if err != nil { + t.Fatalf("err: %v", err) + } + if parsed.ChannelState == nil || parsed.ChannelState.WithdrawRequestedAt != 1234 { + t.Fatalf("withdrawRequestedAt = %+v", parsed.ChannelState) + } + } +} + +// ---------- RefundPayload round-trip ---------- + +func TestRefundPayloadFromMap_ToMap_RoundTrip(t *testing.T) { + in := validRefundPayloadMap() + in["amount"] = "250" + p, err := RefundPayloadFromMap(in) + if err != nil { + t.Fatalf("err: %v", err) + } + if p.Amount != "250" || p.Voucher.ChannelId != "0xabc" { + t.Fatalf("parsed = %+v", p) + } + out := p.ToMap() + if out["type"] != "refund" || out["amount"] != "250" { + t.Fatalf("ToMap = %+v", out) + } + if _, ok := out["channelConfig"].(map[string]interface{}); !ok { + t.Fatalf("missing channelConfig in %+v", out) + } + + // Empty amount should be omitted. + p.Amount = "" + if _, hasAmount := p.ToMap()["amount"]; hasAmount { + t.Fatal("expected amount omitted when empty") + } +} + +func TestRefundPayloadFromMap_Errors(t *testing.T) { + if _, err := RefundPayloadFromMap(map[string]interface{}{}); err == nil { + t.Fatal("expected error: missing channelConfig") + } + bad := map[string]interface{}{"channelConfig": map[string]interface{}{}} + if _, err := RefundPayloadFromMap(bad); err == nil { + t.Fatal("expected error: invalid channelConfig") + } + noVoucher := map[string]interface{}{"channelConfig": validChannelConfigMap()} + if _, err := RefundPayloadFromMap(noVoucher); err == nil { + t.Fatal("expected error: missing voucher") + } +} + +// ---------- Wire-format ToMap converters used by the channel manager ---------- + +func TestClaimPayload_ToMap(t *testing.T) { + p := &BatchSettlementClaimPayload{Type: "claim"} + if got := p.ToMap(); got["type"] != "claim" { + t.Fatalf("ToMap = %+v", got) + } + if _, has := p.ToMap()["claimAuthorizerSignature"]; has { + t.Fatal("expected claimAuthorizerSignature omitted when empty") + } + + p.ClaimAuthorizerSignature = "0xsig" + out := p.ToMap() + if out["claimAuthorizerSignature"] != "0xsig" { + t.Fatalf("ToMap = %+v", out) + } +} + +func TestSettlePayload_ToMap(t *testing.T) { + p := &BatchSettlementSettlePayload{Type: "settle", Receiver: "0xrcv", Token: "0xtok"} + out := p.ToMap() + if out["type"] != "settle" || out["receiver"] != "0xrcv" || out["token"] != "0xtok" { + t.Fatalf("ToMap = %+v", out) + } +} + +func TestEnrichedRefundPayload_ToMap(t *testing.T) { + p := &BatchSettlementEnrichedRefundPayload{ + Type: "refund", + ChannelConfig: ChannelConfig{ + Payer: "0x1", PayerAuthorizer: "0x2", Receiver: "0x3", + ReceiverAuthorizer: "0x4", Token: "0x5", WithdrawDelay: 900, + Salt: "0x6", + }, + Voucher: BatchSettlementVoucherFields{ChannelId: "0xabc", MaxClaimableAmount: "1000", Signature: "0xsig"}, + Amount: "100", + RefundNonce: "1", + Claims: []BatchSettlementVoucherClaim{}, + } + out := p.ToMap() + if out["type"] != "refund" || out["amount"] != "100" || out["refundNonce"] != "1" { + t.Fatalf("ToMap = %+v", out) + } + if _, has := out["refundAuthorizerSignature"]; has { + t.Fatal("expected refundAuthorizerSignature omitted when empty") + } + + p.RefundAuthorizerSignature = "0xref" + p.ClaimAuthorizerSignature = "0xclm" + out = p.ToMap() + if out["refundAuthorizerSignature"] != "0xref" || out["claimAuthorizerSignature"] != "0xclm" { + t.Fatalf("ToMap with sigs = %+v", out) + } +} + +// ---------- ChannelState / VoucherState requirements ---------- + +func TestChannelStateRequirements_FromMapAndToMap(t *testing.T) { + in := map[string]interface{}{ + "channelId": "0xabc", + "balance": "1000", + "totalClaimed": "100", + "withdrawRequestedAt": 0, + "refundNonce": "1", + "chargedCumulativeAmount": "200", + } + cs := ChannelStateRequirementsFromMap(in) + if cs == nil || cs.ChannelId != "0xabc" || cs.ChargedCumulativeAmount != "200" { + t.Fatalf("parsed = %+v", cs) + } + + out := cs.ToMap() + if out["channelId"] != "0xabc" || out["chargedCumulativeAmount"] != "200" { + t.Fatalf("ToMap = %+v", out) + } + if out["balance"] != "1000" || out["totalClaimed"] != "100" { + t.Fatalf("ToMap missing channel snapshot: %+v", out) + } + + // Missing channelId returns nil. + if got := ChannelStateRequirementsFromMap(map[string]interface{}{}); got != nil { + t.Fatalf("expected nil for empty map, got %+v", got) + } + // Nil input returns nil. + if got := ChannelStateRequirementsFromMap(nil); got != nil { + t.Fatalf("expected nil for nil map, got %+v", got) + } + // Receiver-nil ToMap returns nil. + var nilCS *BatchSettlementChannelStateExtra + if got := nilCS.ToMap(); got != nil { + t.Fatalf("expected nil ToMap for nil receiver, got %+v", got) + } + // Empty optional fields are omitted. + cs2 := &BatchSettlementChannelStateExtra{ChannelId: "0xabc"} + out2 := cs2.ToMap() + if _, has := out2["chargedCumulativeAmount"]; has { + t.Fatalf("expected optional fields omitted, got %+v", out2) + } +} + +func TestVoucherStateRequirements_FromMapAndToMap(t *testing.T) { + in := map[string]interface{}{ + "signedMaxClaimable": "1000", + "signature": "0xsig", + } + vs := VoucherStateRequirementsFromMap(in) + if vs == nil || vs.SignedMaxClaimable != "1000" || vs.Signature != "0xsig" { + t.Fatalf("parsed = %+v", vs) + } + out := vs.ToMap() + if out["signedMaxClaimable"] != "1000" || out["signature"] != "0xsig" { + t.Fatalf("ToMap = %+v", out) + } + // Empty inputs return nil. + if got := VoucherStateRequirementsFromMap(map[string]interface{}{}); got != nil { + t.Fatalf("expected nil for empty map, got %+v", got) + } + // Receiver-nil ToMap returns nil. + var nilVS *BatchSettlementVoucherStateExtra + if got := nilVS.ToMap(); got != nil { + t.Fatalf("expected nil ToMap for nil receiver, got %+v", got) + } + // Both fields empty produces nil ToMap. + if got := (&BatchSettlementVoucherStateExtra{}).ToMap(); got != nil { + t.Fatalf("expected nil ToMap when both fields empty, got %+v", got) + } +} diff --git a/go/mechanisms/evm/batch-settlement/utils.go b/go/mechanisms/evm/batch-settlement/utils.go new file mode 100644 index 0000000000..9abc7570e3 --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/utils.go @@ -0,0 +1,103 @@ +package batchsettlement + +import ( + "fmt" + "math/big" + "strings" + + "github.com/ethereum/go-ethereum/common" + + "github.com/x402-foundation/x402/go/mechanisms/evm" +) + +// ComputeChannelId computes the chain-bound channel ID from a ChannelConfig +// via EIP-712 hashTypedData. The networkOrChainID argument may be either a +// CAIP-2 network identifier (e.g. "eip155:84532") or a numeric chain id as +// a *big.Int. +func ComputeChannelId(config ChannelConfig, networkOrChainID interface{}) (string, error) { + chainID, err := resolveChainID(networkOrChainID) + if err != nil { + return "", err + } + + saltBytes, err := hexToBytes32(config.Salt) + if err != nil { + return "", fmt.Errorf("invalid salt: %w", err) + } + + message := map[string]interface{}{ + "payer": common.HexToAddress(config.Payer).Hex(), + "payerAuthorizer": common.HexToAddress(config.PayerAuthorizer).Hex(), + "receiver": common.HexToAddress(config.Receiver).Hex(), + "receiverAuthorizer": common.HexToAddress(config.ReceiverAuthorizer).Hex(), + "token": common.HexToAddress(config.Token).Hex(), + "withdrawDelay": big.NewInt(int64(config.WithdrawDelay)), + "salt": saltBytes[:], + } + + hash, err := evm.HashTypedData( + GetBatchSettlementEip712Domain(chainID), + ChannelConfigTypes, + "ChannelConfig", + message, + ) + if err != nil { + return "", fmt.Errorf("failed to hash channel config: %w", err) + } + return fmt.Sprintf("0x%x", hash), nil +} + +// resolveChainID accepts either a CAIP-2 network string (e.g. "eip155:84532"), +// a numeric chain id (*big.Int, int, int64, uint64), or anything that +// converts via fmt.Sprint to a CAIP-2 string. +func resolveChainID(networkOrChainID interface{}) (*big.Int, error) { + switch v := networkOrChainID.(type) { + case nil: + return nil, fmt.Errorf("networkOrChainID is required") + case string: + return evm.GetEvmChainId(v) + case *big.Int: + if v == nil { + return nil, fmt.Errorf("networkOrChainID is required") + } + return new(big.Int).Set(v), nil + case int: + return big.NewInt(int64(v)), nil + case int64: + return big.NewInt(v), nil + case uint64: + return new(big.Int).SetUint64(v), nil + default: + return nil, fmt.Errorf("unsupported networkOrChainID type %T", networkOrChainID) + } +} + +// NormalizeChannelId lowercases and normalizes a channel ID hex string. +func NormalizeChannelId(channelId string) string { + return strings.ToLower(channelId) +} + +// GetBatchSettlementEip712Domain returns the EIP-712 domain for the +// batch-settlement contract on the given chain. +func GetBatchSettlementEip712Domain(chainID *big.Int) evm.TypedDataDomain { + return evm.TypedDataDomain{ + Name: BatchSettlementDomain.Name, + Version: BatchSettlementDomain.Version, + ChainID: chainID, + VerifyingContract: common.HexToAddress(BatchSettlementAddress).Hex(), + } +} + +// hexToBytes32 converts a hex string to a [32]byte array. +func hexToBytes32(hex string) ([32]byte, error) { + var result [32]byte + hex = strings.TrimPrefix(hex, "0x") + if len(hex) > 64 { + return result, fmt.Errorf("hex string too long for bytes32: %s", hex) + } + // Left-pad with zeros + hex = strings.Repeat("0", 64-len(hex)) + hex + b := common.FromHex("0x" + hex) + copy(result[:], b) + return result, nil +} diff --git a/go/mechanisms/evm/batch-settlement/utils_test.go b/go/mechanisms/evm/batch-settlement/utils_test.go new file mode 100644 index 0000000000..31fa94e1ea --- /dev/null +++ b/go/mechanisms/evm/batch-settlement/utils_test.go @@ -0,0 +1,134 @@ +package batchsettlement + +import ( + "math/big" + "strings" + "testing" +) + +func sampleConfig() ChannelConfig { + return ChannelConfig{ + Payer: "0x1111111111111111111111111111111111111111", + PayerAuthorizer: "0x2222222222222222222222222222222222222222", + Receiver: "0x3333333333333333333333333333333333333333", + ReceiverAuthorizer: "0x4444444444444444444444444444444444444444", + Token: "0x5555555555555555555555555555555555555555", + WithdrawDelay: 900, + Salt: "0x0000000000000000000000000000000000000000000000000000000000000001", + } +} + +const testNetwork = "eip155:8453" + +func TestComputeChannelId_Deterministic(t *testing.T) { + cfg := sampleConfig() + a, err := ComputeChannelId(cfg, testNetwork) + if err != nil { + t.Fatalf("err: %v", err) + } + b, err := ComputeChannelId(cfg, testNetwork) + if err != nil { + t.Fatalf("err: %v", err) + } + if a != b { + t.Fatalf("non-deterministic: %s vs %s", a, b) + } + if !strings.HasPrefix(a, "0x") || len(a) != 66 { + t.Fatalf("expected 0x-prefixed 32-byte hex; got %q", a) + } +} + +func TestComputeChannelId_DistinctConfigsDiffer(t *testing.T) { + a, _ := ComputeChannelId(sampleConfig(), testNetwork) + cfg2 := sampleConfig() + cfg2.Salt = "0x0000000000000000000000000000000000000000000000000000000000000002" + b, _ := ComputeChannelId(cfg2, testNetwork) + if a == b { + t.Fatal("different salts produced same channelId") + } + + cfg3 := sampleConfig() + cfg3.WithdrawDelay = 901 + c, _ := ComputeChannelId(cfg3, testNetwork) + if a == c { + t.Fatal("different withdrawDelay produced same channelId") + } +} + +func TestComputeChannelId_AcceptsShortSalt(t *testing.T) { + cfg := sampleConfig() + cfg.Salt = "0x01" + if _, err := ComputeChannelId(cfg, testNetwork); err != nil { + t.Fatalf("short salt rejected: %v", err) + } +} + +func TestComputeChannelId_RejectsTooLongSalt(t *testing.T) { + cfg := sampleConfig() + cfg.Salt = "0x" + strings.Repeat("ab", 33) + if _, err := ComputeChannelId(cfg, testNetwork); err == nil { + t.Fatal("expected error") + } +} + +func TestNormalizeChannelId(t *testing.T) { + cases := map[string]string{ + "0xABCDEF": "0xabcdef", + "0xabc": "0xabc", + "0x": "0x", + "0xMixedCASE12345": "0xmixedcase12345", + } + for in, want := range cases { + if got := NormalizeChannelId(in); got != want { + t.Fatalf("NormalizeChannelId(%q) = %q, want %q", in, got, want) + } + } +} + +func TestGetBatchSettlementEip712Domain(t *testing.T) { + chainId := big.NewInt(8453) + d := GetBatchSettlementEip712Domain(chainId) + if d.Name != BatchSettlementDomain.Name { + t.Fatalf("Name = %q", d.Name) + } + if d.Version != BatchSettlementDomain.Version { + t.Fatalf("Version = %q", d.Version) + } + if d.ChainID == nil || d.ChainID.Cmp(chainId) != 0 { + t.Fatalf("ChainID = %v", d.ChainID) + } + if d.VerifyingContract != BatchSettlementAddress { + t.Fatalf("VerifyingContract = %q", d.VerifyingContract) + } +} + +func TestHexToBytes32_LeftPads(t *testing.T) { + out, err := hexToBytes32("0x01") + if err != nil { + t.Fatalf("err: %v", err) + } + for i := range 31 { + if out[i] != 0 { + t.Fatalf("byte %d should be zero, got %x", i, out[i]) + } + } + if out[31] != 1 { + t.Fatalf("byte 31 = %x, want 0x01", out[31]) + } +} + +func TestHexToBytes32_NoPrefix(t *testing.T) { + out, err := hexToBytes32("01") + if err != nil { + t.Fatalf("err: %v", err) + } + if out[31] != 1 { + t.Fatalf("byte 31 = %x", out[31]) + } +} + +func TestHexToBytes32_TooLong(t *testing.T) { + if _, err := hexToBytes32("0x" + strings.Repeat("a", 65)); err == nil { + t.Fatal("expected error") + } +} diff --git a/go/mechanisms/evm/constants.go b/go/mechanisms/evm/constants.go index d616f9449f..84bfe3ddd7 100644 --- a/go/mechanisms/evm/constants.go +++ b/go/mechanisms/evm/constants.go @@ -6,8 +6,9 @@ import ( const ( // Scheme identifiers - SchemeExact = "exact" - SchemeUpto = "upto" + SchemeExact = "exact" + SchemeUpto = "upto" + SchemeBatched = "batch-settlement" // Default token decimals for USDC DefaultDecimals = 6 @@ -79,6 +80,8 @@ var ( ChainIDPolygon = big.NewInt(137) ChainIDArbOne = big.NewInt(42161) ChainIDArbSepolia = big.NewInt(421614) + ChainIDRadius = big.NewInt(723487) + ChainIDRadiusTestnet = big.NewInt(72344) // Network configurations // See DEFAULT_ASSET.md for guidelines on adding new chains @@ -196,6 +199,30 @@ var ( Decimals: DefaultDecimals, }, }, + // Radius Network (uses Permit2 instead of EIP-3009, supports EIP-2612) + "eip155:723487": { + ChainID: ChainIDRadius, + DefaultAsset: AssetInfo{ + Address: "0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb", // SBC on Radius + Name: "Stable Coin", + Version: "1", + Decimals: DefaultDecimals, + AssetTransferMethod: AssetTransferMethodPermit2, + SupportsEip2612: true, + }, + }, + // Radius Testnet (uses Permit2 instead of EIP-3009, supports EIP-2612) + "eip155:72344": { + ChainID: ChainIDRadiusTestnet, + DefaultAsset: AssetInfo{ + Address: "0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb", // SBC on Radius Testnet + Name: "Stable Coin", + Version: "1", + Decimals: DefaultDecimals, + AssetTransferMethod: AssetTransferMethodPermit2, + SupportsEip2612: true, + }, + }, } // EIP-3009 ABI for transferWithAuthorization with v,r,s (EOA signatures) diff --git a/go/mechanisms/evm/eip2612.go b/go/mechanisms/evm/eip2612.go index 23e5e7e238..38d90665dc 100644 --- a/go/mechanisms/evm/eip2612.go +++ b/go/mechanisms/evm/eip2612.go @@ -6,7 +6,7 @@ import ( "strings" "time" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" ) // ValidateEip2612PermitForPayment validates EIP-2612 extension data for a Permit2 payment. diff --git a/go/mechanisms/evm/eip712.go b/go/mechanisms/evm/eip712.go index 7843c80373..c11c3f9884 100644 --- a/go/mechanisms/evm/eip712.go +++ b/go/mechanisms/evm/eip712.go @@ -57,14 +57,29 @@ func HashTypedData( typedData.Types[typeName] = typedFields } - // Add EIP712Domain type if not present + // Add EIP712Domain type if not present. + // Domains with empty Name/Version/VerifyingContract or nil ChainID are treated + // as "absent" — go-ethereum's apitypes.TypedDataDomain.Map() drops empty fields, + // so the EIP712Domain type list must match exactly what's in the domain map or + // HashStruct fails with "provided data '' doesn't match type 'string'". + // This mirrors viem's getTypesForEIP712Domain which only declares fields whose + // domain values are present. Permit2's domain (name + chainId + verifyingContract, + // no version) is the canonical case this guards against. if _, exists := typedData.Types["EIP712Domain"]; !exists { - typedData.Types["EIP712Domain"] = []apitypes.Type{ - {Name: "name", Type: "string"}, - {Name: "version", Type: "string"}, - {Name: "chainId", Type: "uint256"}, - {Name: "verifyingContract", Type: "address"}, + domainFields := make([]apitypes.Type, 0, 4) + if domain.Name != "" { + domainFields = append(domainFields, apitypes.Type{Name: "name", Type: "string"}) + } + if domain.Version != "" { + domainFields = append(domainFields, apitypes.Type{Name: "version", Type: "string"}) + } + if domain.ChainID != nil { + domainFields = append(domainFields, apitypes.Type{Name: "chainId", Type: "uint256"}) + } + if domain.VerifyingContract != "" { + domainFields = append(domainFields, apitypes.Type{Name: "verifyingContract", Type: "address"}) } + typedData.Types["EIP712Domain"] = domainFields } // Hash the struct data diff --git a/go/mechanisms/evm/eip712_test.go b/go/mechanisms/evm/eip712_test.go new file mode 100644 index 0000000000..2446e701dd --- /dev/null +++ b/go/mechanisms/evm/eip712_test.go @@ -0,0 +1,103 @@ +package evm + +import ( + "math/big" + "testing" +) + +// TestHashTypedData_Permit2NoVersionDomain is a regression test for the EIP-712 +// domain hashing bug where the auto-injected EIP712Domain type unconditionally +// declared `version: string`. Permit2's domain has no version, so the typed-data +// domain map omits "version", and HashStruct then fails with: +// +// "provided data '' doesn't match type 'string'" +// +// This propagates as `invalid_batch_settlement_evm_permit2_invalid_signature` +// on the facilitator and breaks every Permit2-based batch-settlement flow. The fix +// dynamically constructs the EIP712Domain type list from which domain fields +// are actually populated, matching viem's behavior. +func TestHashTypedData_Permit2NoVersionDomain(t *testing.T) { + domain := TypedDataDomain{ + Name: "Permit2", + ChainID: big.NewInt(84532), + VerifyingContract: "0x000000000022D473030F116dDEE9F6B43aC78BA3", + } + types := map[string][]TypedDataField{ + "PermitWitnessTransferFrom": { + {Name: "permitted", Type: "TokenPermissions"}, + {Name: "spender", Type: "address"}, + {Name: "nonce", Type: "uint256"}, + {Name: "deadline", Type: "uint256"}, + {Name: "witness", Type: "Witness"}, + }, + "TokenPermissions": { + {Name: "token", Type: "address"}, + {Name: "amount", Type: "uint256"}, + }, + "Witness": { + {Name: "channelId", Type: "bytes32"}, + }, + } + channelId := make([]byte, 32) + channelId[31] = 0x01 + message := map[string]interface{}{ + "permitted": map[string]interface{}{ + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "amount": big.NewInt(1_000_000), + }, + "spender": "0x0000000000000000000000000000000000000001", + "nonce": big.NewInt(1), + "deadline": big.NewInt(1_000_000_000_000), + "witness": map[string]interface{}{ + "channelId": channelId, + }, + } + + digest, err := HashTypedData(domain, types, "PermitWitnessTransferFrom", message) + if err != nil { + t.Fatalf("HashTypedData with no-version domain failed: %v", err) + } + if len(digest) != 32 { + t.Fatalf("expected 32-byte digest, got %d bytes", len(digest)) + } +} + +// TestHashTypedData_FullDomainStillHashes makes sure the dynamic EIP712Domain +// generation didn't regress the standard EIP-3009 case (name + version + chainId +// + verifyingContract). +func TestHashTypedData_FullDomainStillHashes(t *testing.T) { + domain := TypedDataDomain{ + Name: "USD Coin", + Version: "2", + ChainID: big.NewInt(84532), + VerifyingContract: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + } + types := map[string][]TypedDataField{ + "TransferWithAuthorization": { + {Name: "from", Type: "address"}, + {Name: "to", Type: "address"}, + {Name: "value", Type: "uint256"}, + {Name: "validAfter", Type: "uint256"}, + {Name: "validBefore", Type: "uint256"}, + {Name: "nonce", Type: "bytes32"}, + }, + } + nonce := make([]byte, 32) + nonce[0] = 0xab + message := map[string]interface{}{ + "from": "0x0000000000000000000000000000000000000001", + "to": "0x0000000000000000000000000000000000000002", + "value": big.NewInt(1_000_000), + "validAfter": big.NewInt(0), + "validBefore": big.NewInt(1_000_000_000_000), + "nonce": nonce, + } + + digest, err := HashTypedData(domain, types, "TransferWithAuthorization", message) + if err != nil { + t.Fatalf("HashTypedData with full domain failed: %v", err) + } + if len(digest) != 32 { + t.Fatalf("expected 32-byte digest, got %d", len(digest)) + } +} diff --git a/go/mechanisms/evm/exact/README.md b/go/mechanisms/evm/exact/README.md new file mode 100644 index 0000000000..941cfd5586 --- /dev/null +++ b/go/mechanisms/evm/exact/README.md @@ -0,0 +1,183 @@ +# Exact EVM Scheme (Go) + +The **exact** scheme is the default x402 payment scheme for EVM networks. The client pays the exact advertised price — no more, no less. It supports two on-chain transfer methods: **EIP-3009** (`transferWithAuthorization`) and **Permit2** (Uniswap's signature-based approval). + +## Import Paths + +| Role | Import | +|------|--------| +| Client | `github.com/x402-foundation/x402/go/mechanisms/evm/exact/client` | +| Server | `github.com/x402-foundation/x402/go/mechanisms/evm/exact/server` | +| Facilitator | `github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator` | +| Client (V1 legacy) | `github.com/x402-foundation/x402/go/mechanisms/evm/exact/v1/client` | +| Facilitator (V1 legacy) | `github.com/x402-foundation/x402/go/mechanisms/evm/exact/v1/facilitator` | + +## Client Usage + +Create an `ExactEvmScheme` and register it with an `x402Client` to automatically handle payments for EVM-network services that use the `exact` scheme. + +```go +import ( + x402 "github.com/x402-foundation/x402/go" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" +) + +evmSigner, err := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("EVM_PRIVATE_KEY")) + +x402Client := x402.Newx402Client(). + Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, nil)) +``` + +## Server Usage + +Register `ExactEvmScheme` with middleware to protect routes with fixed-price payments. + +```go +import ( + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" +) + +r.Use(ginmw.X402Payment(ginmw.Config{ + Routes: x402http.RoutesConfig{ + "GET /weather": { + Accepts: x402http.PaymentOptions{ + { + Scheme: "exact", + Price: "$0.001", + Network: "eip155:84532", + PayTo: "0xYourAddress", + }, + }, + }, + }, + Facilitator: facilitatorClient, + Schemes: []ginmw.SchemeConfig{ + {Network: x402.Network("eip155:84532"), Server: exactevm.NewExactEvmScheme()}, + }, +})) +``` + +## Facilitator Usage + +For custom facilitator implementations: + +```go +import ( + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" +) + +scheme := exactevm.NewExactEvmScheme(config) +``` + +## Supported Networks + +Works on any EIP-155 compatible network. Common networks: + +| Network | CAIP-2 ID | +|---------|-----------| +| Base Mainnet | `eip155:8453` | +| Base Sepolia | `eip155:84532` | + +## Transfer Methods + +| Method | Description | +|--------|-------------| +| EIP-3009 | `transferWithAuthorization` — gasless, single-signature transfer (default) | +| Permit2 | Uniswap Permit2 — signature-based approval + transfer via proxy contract | + +## Gas Sponsoring Extensions (Permit2 only) + +When using the Permit2 transfer method, the exact scheme integrates with two gas sponsoring extensions that let the **facilitator** pay for the client's Permit2 approval transaction on-chain. This is transparent to both server and client — the client SDK automatically detects advertised extensions and signs the appropriate data. + +> Gas sponsoring does **not** apply to the EIP-3009 path, which is already gasless by design. + +### EIP-2612 Gas Sponsoring + +The preferred path. If the payment token supports [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) (gasless `permit`), the client signs an off-chain EIP-2612 permit and the facilitator calls `settleWithPermit` — bundling the approval and settlement in a single transaction with no gas cost to the client. + +**Server:** Declare the extension in your route config and ensure the token's `name` and `version` are included (the default for EIP-2612-compatible tokens): + +```go +import ( + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" +) + +routes := x402http.RoutesConfig{ + "GET /weather": { + Accepts: x402http.PaymentOptions{ + { + Scheme: "exact", + Price: "$0.001", + Network: "eip155:84532", + PayTo: "0xYourAddress", + }, + }, + Extensions: eip2612gassponsor.DeclareEip2612GasSponsoringExtension(), + }, +} +``` + +**Client:** No additional setup required. `ExactEvmScheme` automatically checks for the `eip2612GasSponsoring` extension and signs the permit when applicable. + +**Facilitator:** Register the extension: + +```go +import ( + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" +) + +facilitator.RegisterExtension(eip2612gassponsor.EIP2612GasSponsoring) +``` + +### ERC-20 Approval Gas Sponsoring + +Fallback for tokens that **do not** support EIP-2612. The client signs a raw ERC-20 `approve(Permit2, MaxUint256)` transaction off-chain and includes it in the payment payload. The facilitator broadcasts this approval transaction on-chain before settling. + +**Server:** Declare the extension and omit `name`/`version` from the token config to signal clients to skip EIP-2612: + +```go +import ( + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" +) + +routes := x402http.RoutesConfig{ + "GET /weather": { + Accepts: x402http.PaymentOptions{ /* ... */ }, + Extensions: erc20approvalgassponsor.DeclareExtension(), + }, +} +``` + +**Client:** The signer must support transaction signing (nonce resolution, fee estimation). `ExactEvmScheme` falls back to this path when EIP-2612 is not available. + +**Facilitator:** Register with a signer that can broadcast transactions: + +```go +import ( + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" +) + +erc20Ext := &erc20approvalgassponsor.Erc20ApprovalFacilitatorExtension{Signer: evmSigner} +facilitator.RegisterExtension(erc20Ext) +``` + +### Extension Priority + +When **both** extensions are advertised, EIP-2612 takes priority. The client tries EIP-2612 first; if the token lacks `name`/`version` in `Extra` (meaning it doesn't support EIP-2612), it falls back to ERC-20 approval gas sponsoring. + +## Examples + +- [Gin server](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/gin) +- [net/http server](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/nethttp) +- [HTTP client](https://github.com/x402-foundation/x402/tree/main/examples/go/clients/http) +- [EIP-2612 gas sponsoring server](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/advanced/eip2612-gas-sponsoring.go) + +## See Also + +- [Upto EVM Scheme](../upto/README.md) — usage-based billing with partial settlement +- [x402 Docs: Quickstart for Sellers](https://docs.x402.org/getting-started/quickstart-for-sellers) +- [x402 Docs: Quickstart for Buyers](https://docs.x402.org/getting-started/quickstart-for-buyers) +- [Exact EVM Scheme Specification](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_evm.md) diff --git a/go/mechanisms/evm/exact/client/eip2612.go b/go/mechanisms/evm/exact/client/eip2612.go index 9e1c00ff39..4d61380c6f 100644 --- a/go/mechanisms/evm/exact/client/eip2612.go +++ b/go/mechanisms/evm/exact/client/eip2612.go @@ -7,8 +7,8 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // SignEip2612Permit signs an EIP-2612 permit authorizing the Permit2 contract diff --git a/go/mechanisms/evm/exact/client/erc20_approval.go b/go/mechanisms/evm/exact/client/erc20_approval.go index 99f626871e..0e1c4680be 100644 --- a/go/mechanisms/evm/exact/client/erc20_approval.go +++ b/go/mechanisms/evm/exact/client/erc20_approval.go @@ -11,8 +11,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // SignErc20ApprovalTransaction creates a signed (but unbroadcast) EIP-1559 transaction diff --git a/go/mechanisms/evm/exact/client/permit2.go b/go/mechanisms/evm/exact/client/permit2.go index 3a185a09bf..01834907e9 100644 --- a/go/mechanisms/evm/exact/client/permit2.go +++ b/go/mechanisms/evm/exact/client/permit2.go @@ -6,8 +6,8 @@ import ( "math/big" "time" - "github.com/coinbase/x402/go/mechanisms/evm" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/types" ) // CreatePermit2Payload creates a Permit2 payload using the x402Permit2Proxy witness pattern. diff --git a/go/mechanisms/evm/exact/client/rpc.go b/go/mechanisms/evm/exact/client/rpc.go index 5963beb174..21b58b03f0 100644 --- a/go/mechanisms/evm/exact/client/rpc.go +++ b/go/mechanisms/evm/exact/client/rpc.go @@ -3,7 +3,7 @@ package client import ( "context" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // ExactEvmChainConfig configures RPC behavior for one chain. diff --git a/go/mechanisms/evm/exact/client/rpc_test.go b/go/mechanisms/evm/exact/client/rpc_test.go index 414b5a89e5..779f64b3dd 100644 --- a/go/mechanisms/evm/exact/client/rpc_test.go +++ b/go/mechanisms/evm/exact/client/rpc_test.go @@ -7,7 +7,7 @@ import ( goethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) type rpcTestSigner struct { diff --git a/go/mechanisms/evm/exact/client/scheme.go b/go/mechanisms/evm/exact/client/scheme.go index 2a3aef2f1f..fdd55f6278 100644 --- a/go/mechanisms/evm/exact/client/scheme.go +++ b/go/mechanisms/evm/exact/client/scheme.go @@ -8,10 +8,10 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" - "github.com/coinbase/x402/go/mechanisms/evm" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/types" ) // ExactEvmScheme implements the SchemeNetworkClient interface for EVM exact payments (V2) diff --git a/go/mechanisms/evm/exact/facilitator/eip3009.go b/go/mechanisms/evm/exact/facilitator/eip3009.go index dd749e6f02..1195b1abd6 100644 --- a/go/mechanisms/evm/exact/facilitator/eip3009.go +++ b/go/mechanisms/evm/exact/facilitator/eip3009.go @@ -8,9 +8,9 @@ import ( "strings" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/evm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/types" ) // verifyEIP3009 verifies an EIP-3009 payment payload. @@ -113,7 +113,7 @@ func (f *ExactEvmScheme) verifyEIP3009( classification.SigData, ) if err != nil { - return nil, x402.NewVerifyError(ErrInvalidPayload, evmPayload.Authorization.From, err.Error()) + return nil, x402.NewVerifyError(ErrEip3009SimulationFailed, evmPayload.Authorization.From, err.Error()) } if !simulationSucceeded { reason := DiagnoseEIP3009SimulationFailure( @@ -193,7 +193,7 @@ func (f *ExactEvmScheme) settleEIP3009( txHash, err := ExecuteTransferWithAuthorization(ctx, f.signer, tokenAddress, parsedAuthorization, sigData) if err != nil { - return nil, x402.NewSettleError(ErrFailedToExecuteTransfer, verifyResp.Payer, network, "", err.Error()) + return nil, x402.NewSettleError(parseEIP3009TransferError(err), verifyResp.Payer, network, "", err.Error()) } receipt, err := f.signer.WaitForTransactionReceipt(ctx, txHash) diff --git a/go/mechanisms/evm/exact/facilitator/eip3009_helpers.go b/go/mechanisms/evm/exact/facilitator/eip3009_helpers.go index 5f072035ad..3528703ce0 100644 --- a/go/mechanisms/evm/exact/facilitator/eip3009_helpers.go +++ b/go/mechanisms/evm/exact/facilitator/eip3009_helpers.go @@ -9,7 +9,7 @@ import ( "github.com/ethereum/go-ethereum/accounts/abi" "github.com/ethereum/go-ethereum/common" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // ParsedEIP3009Authorization contains the parsed transfer arguments used by verify and settle. @@ -436,6 +436,25 @@ func mustNonce(nonce string) [32]byte { return nonceArray } +// parseEIP3009TransferError maps EIP-3009 contract revert reasons to specific error codes. +func parseEIP3009TransferError(err error) string { + msg := err.Error() + switch { + case strings.Contains(msg, "authorization is expired") || strings.Contains(msg, "AuthorizationExpired"): + return ErrValidBeforeExpired + case strings.Contains(msg, "authorization is not yet valid") || strings.Contains(msg, "AuthorizationNotYetValid"): + return ErrValidAfterInFuture + case strings.Contains(msg, "authorization is used") || strings.Contains(msg, "AuthorizationAlreadyUsed") || strings.Contains(msg, "AuthorizationUsedOrCanceled"): + return ErrNonceAlreadyUsed + case strings.Contains(msg, "transfer amount exceeds balance") || strings.Contains(msg, "ERC20InsufficientBalance"): + return ErrInsufficientBalance + case strings.Contains(msg, "invalid signature") || strings.Contains(msg, "SignerMismatch") || strings.Contains(msg, "InvalidSignatureV") || strings.Contains(msg, "InvalidSignatureS"): + return ErrInvalidSignature + default: + return ErrFailedToExecuteTransfer + } +} + func asBigInt(value interface{}) *big.Int { switch v := value.(type) { case *big.Int: diff --git a/go/mechanisms/evm/exact/facilitator/erc20_approval.go b/go/mechanisms/evm/exact/facilitator/erc20_approval.go index 3c15224d83..1161153e9a 100644 --- a/go/mechanisms/evm/exact/facilitator/erc20_approval.go +++ b/go/mechanisms/evm/exact/facilitator/erc20_approval.go @@ -8,8 +8,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core/types" - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // approveSelector is the 4-byte function selector for ERC-20 approve(address,uint256). diff --git a/go/mechanisms/evm/exact/facilitator/errors.go b/go/mechanisms/evm/exact/facilitator/errors.go index 4295e3d92f..b694cde6fa 100644 --- a/go/mechanisms/evm/exact/facilitator/errors.go +++ b/go/mechanisms/evm/exact/facilitator/errors.go @@ -1,6 +1,6 @@ package facilitator -import "github.com/coinbase/x402/go/mechanisms/evm" +import "github.com/x402-foundation/x402/go/mechanisms/evm" // Facilitator error constants for the exact EVM scheme const ( diff --git a/go/mechanisms/evm/exact/facilitator/permit2.go b/go/mechanisms/evm/exact/facilitator/permit2.go index 8b4a655010..2a170f083f 100644 --- a/go/mechanisms/evm/exact/facilitator/permit2.go +++ b/go/mechanisms/evm/exact/facilitator/permit2.go @@ -7,11 +7,11 @@ import ( "strings" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" - "github.com/coinbase/x402/go/mechanisms/evm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/types" ) // VerifyPermit2Options controls optional behaviour for VerifyPermit2. diff --git a/go/mechanisms/evm/exact/facilitator/permit2_eip2612_test.go b/go/mechanisms/evm/exact/facilitator/permit2_eip2612_test.go index eb74fd8bd2..4ec587e23f 100644 --- a/go/mechanisms/evm/exact/facilitator/permit2_eip2612_test.go +++ b/go/mechanisms/evm/exact/facilitator/permit2_eip2612_test.go @@ -5,8 +5,8 @@ import ( "testing" "time" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) func TestValidateEip2612PermitForPayment(t *testing.T) { diff --git a/go/mechanisms/evm/exact/facilitator/permit2_erc20_test.go b/go/mechanisms/evm/exact/facilitator/permit2_erc20_test.go index 2caf759ca9..a0c6c1482a 100644 --- a/go/mechanisms/evm/exact/facilitator/permit2_erc20_test.go +++ b/go/mechanisms/evm/exact/facilitator/permit2_erc20_test.go @@ -10,8 +10,8 @@ import ( "github.com/ethereum/go-ethereum/core/types" "github.com/ethereum/go-ethereum/crypto" - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // buildSignedApproveTransaction creates a signed approve(Permit2, MaxUint256) transaction diff --git a/go/mechanisms/evm/exact/facilitator/permit2_helpers.go b/go/mechanisms/evm/exact/facilitator/permit2_helpers.go index 8ee9a44ced..571503f63d 100644 --- a/go/mechanisms/evm/exact/facilitator/permit2_helpers.go +++ b/go/mechanisms/evm/exact/facilitator/permit2_helpers.go @@ -6,8 +6,8 @@ import ( "github.com/ethereum/go-ethereum/common" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/evm" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // Permit2SettleArgs holds the parsed and typed arguments for settle() / settleWithPermit(). diff --git a/go/mechanisms/evm/exact/facilitator/scheme.go b/go/mechanisms/evm/exact/facilitator/scheme.go index 2ccc92740d..f0c9fec723 100644 --- a/go/mechanisms/evm/exact/facilitator/scheme.go +++ b/go/mechanisms/evm/exact/facilitator/scheme.go @@ -4,9 +4,9 @@ import ( "context" "fmt" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/evm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/types" ) // ExactEvmSchemeConfig holds configuration for the ExactEvmScheme facilitator diff --git a/go/mechanisms/evm/exact/server/scheme.go b/go/mechanisms/evm/exact/server/scheme.go index b554b1324f..a443f7f411 100644 --- a/go/mechanisms/evm/exact/server/scheme.go +++ b/go/mechanisms/evm/exact/server/scheme.go @@ -8,9 +8,9 @@ import ( "strconv" "strings" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/evm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/types" ) // ExactEvmScheme implements the SchemeNetworkServer interface for EVM exact payments (V2) diff --git a/go/mechanisms/evm/exact/server/server_money_parser_test.go b/go/mechanisms/evm/exact/server/server_money_parser_test.go index c429533d52..da96f1af0b 100644 --- a/go/mechanisms/evm/exact/server/server_money_parser_test.go +++ b/go/mechanisms/evm/exact/server/server_money_parser_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - x402 "github.com/coinbase/x402/go" + x402 "github.com/x402-foundation/x402/go" ) // Base mainnet USDC address diff --git a/go/mechanisms/evm/exact/v1/README.md b/go/mechanisms/evm/exact/v1/README.md index 3388dbcd7b..2defe35d78 100644 --- a/go/mechanisms/evm/exact/v1/README.md +++ b/go/mechanisms/evm/exact/v1/README.md @@ -16,8 +16,8 @@ This package contains the V1 implementation of the EVM mechanism for x402. ```go import ( - x402 "github.com/coinbase/x402/go" - evmv1 "github.com/coinbase/x402/go/mechanisms/evm/exact/v1" + x402 "github.com/x402-foundation/x402/go" + evmv1 "github.com/x402-foundation/x402/go/mechanisms/evm/exact/v1" ) // Register V1 client diff --git a/go/mechanisms/evm/exact/v1/client/scheme.go b/go/mechanisms/evm/exact/v1/client/scheme.go index 2c853f4dab..30d3312606 100644 --- a/go/mechanisms/evm/exact/v1/client/scheme.go +++ b/go/mechanisms/evm/exact/v1/client/scheme.go @@ -7,9 +7,9 @@ import ( "math/big" "time" - "github.com/coinbase/x402/go/mechanisms/evm" - evmv1 "github.com/coinbase/x402/go/mechanisms/evm/v1" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/mechanisms/evm" + evmv1 "github.com/x402-foundation/x402/go/mechanisms/evm/v1" + "github.com/x402-foundation/x402/go/types" ) // ExactEvmSchemeV1 implements the SchemeNetworkClientV1 interface for EVM exact payments (V1) diff --git a/go/mechanisms/evm/exact/v1/facilitator/scheme.go b/go/mechanisms/evm/exact/v1/facilitator/scheme.go index ebd1c7d2d1..d10c70fa4c 100644 --- a/go/mechanisms/evm/exact/v1/facilitator/scheme.go +++ b/go/mechanisms/evm/exact/v1/facilitator/scheme.go @@ -11,11 +11,11 @@ import ( "github.com/ethereum/go-ethereum/common" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/evm" - exactfacilitator "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - evmv1 "github.com/coinbase/x402/go/mechanisms/evm/v1" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + exactfacilitator "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + evmv1 "github.com/x402-foundation/x402/go/mechanisms/evm/v1" + "github.com/x402-foundation/x402/go/types" ) // ExactEvmSchemeV1Config holds configuration for the ExactEvmSchemeV1 facilitator @@ -215,7 +215,7 @@ func (f *ExactEvmSchemeV1) verify( classification.SigData, ) if err != nil { - return nil, x402.NewVerifyError(ErrInvalidPayload, evmPayload.Authorization.From, err.Error()) + return nil, x402.NewVerifyError(exactfacilitator.ErrEip3009SimulationFailed, evmPayload.Authorization.From, err.Error()) } if !simulationSucceeded { reason := exactfacilitator.DiagnoseEIP3009SimulationFailure( diff --git a/go/mechanisms/evm/upto/README.md b/go/mechanisms/evm/upto/README.md new file mode 100644 index 0000000000..f8e0bdad4b --- /dev/null +++ b/go/mechanisms/evm/upto/README.md @@ -0,0 +1,211 @@ +# Upto EVM Scheme (Go) + +The **upto** scheme enables usage-based billing on EVM networks. The client authorizes a **maximum** payment amount, but the server settles **only what was actually used**. This is ideal for variable-cost endpoints like LLM token generation, compute time, or bandwidth metering. + +Uses **Permit2** exclusively (no EIP-3009 path). The on-chain proxy contract accepts a variable `amount` parameter at settlement time, so the facilitator can settle any amount up to the authorized maximum. + +## Import Paths + +| Role | Import | +|------|--------| +| Client | `github.com/x402-foundation/x402/go/mechanisms/evm/upto/client` | +| Server | `github.com/x402-foundation/x402/go/mechanisms/evm/upto/server` | +| Facilitator | `github.com/x402-foundation/x402/go/mechanisms/evm/upto/facilitator` | + +## Client Usage + +Register `UptoEvmScheme` with an `x402Client` to handle payments for services that use the `upto` scheme. From the buyer's perspective, usage is transparent — the SDK signs a max-authorization and the server charges only what was consumed. + +```go +import ( + x402 "github.com/x402-foundation/x402/go" + exactevm "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" +) + +evmSigner, err := evmsigners.NewClientSignerFromPrivateKey(os.Getenv("EVM_PRIVATE_KEY")) + +x402Client := x402.Newx402Client(). + Register("eip155:*", exactevm.NewExactEvmScheme(evmSigner, nil)). // fixed-price services + Register("eip155:*", uptoevm.NewUptoEvmScheme(evmSigner, nil)) // usage-based services +``` + +### Key Difference from Exact + +The upto client requires `PaymentRequirements.Extra["facilitatorAddress"]` (provided automatically by the facilitator via `GetExtra()`). This address is embedded in the Permit2 witness so only the designated facilitator can settle the payment. + +## Server Usage + +Register `UptoEvmScheme` with middleware and use `SetSettlementOverrides` in your handler to specify the actual charge. + +```go +import ( + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + ginmw "github.com/x402-foundation/x402/go/http/gin" + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/server" +) + +r.Use(ginmw.X402Payment(ginmw.Config{ + Routes: x402http.RoutesConfig{ + "GET /api/generate": { + Accepts: x402http.PaymentOptions{ + { + Scheme: "upto", + Price: "$0.10", // client authorizes up to 10 cents + Network: "eip155:84532", + PayTo: "0xYourAddress", + }, + }, + Description: "AI text generation - billed by token usage", + }, + }, + Facilitator: facilitatorClient, + Schemes: []ginmw.SchemeConfig{ + {Network: x402.Network("eip155:84532"), Server: uptoevm.NewUptoEvmScheme()}, + }, +})) + +// In your handler, settle the actual usage: +r.GET("/api/generate", func(c *gin.Context) { + actualUsage := computeActualCost() // your billing logic + ginmw.SetSettlementOverrides(c, &x402.SettlementOverrides{ + Amount: fmt.Sprintf("%d", actualUsage), + }) + c.JSON(http.StatusOK, gin.H{"result": "..."}) +}) +``` + +### Settlement Override Formats + +The `Amount` in `SettlementOverrides` supports three formats: + +| Format | Example | Description | +|--------|---------|-------------| +| Raw atomic units | `"50000"` | Settles exactly 50,000 atomic units | +| Percentage | `"50%"` | Settles 50% of the authorized maximum | +| Dollar price | `"$0.05"` | Converts to atomic units (when route used `$` pricing) | + +Setting `Amount` to `"0"` skips on-chain settlement entirely — the client is not charged. + +## Facilitator Usage + +For custom facilitator implementations: + +```go +import ( + uptoevm "github.com/x402-foundation/x402/go/mechanisms/evm/upto/facilitator" +) + +scheme := uptoevm.NewUptoEvmScheme(config) +``` + +The upto facilitator's `GetExtra()` returns a `facilitatorAddress` that the client embeds in the signed Permit2 witness. Only this address can call `settle()` on the upto proxy contract. + +## Supported Networks + +Works on any EIP-155 compatible network that has the Permit2 and x402 upto proxy contracts deployed: + +| Network | CAIP-2 ID | +|---------|-----------| +| Base Mainnet | `eip155:8453` | +| Base Sepolia | `eip155:84532` | + +## How It Works + +1. Server advertises `scheme: "upto"` with a max `price` +2. Client signs a Permit2 authorization for the max amount, with a witness containing the `facilitator` address +3. Server performs work, calculates actual cost +4. Server calls `SetSettlementOverrides` with the actual amount +5. Facilitator settles on-chain for the actual amount (≤ max) +6. If actual amount is `0`, no on-chain transaction occurs + +## Gas Sponsoring Extensions + +Since the upto scheme uses Permit2 exclusively, it fully supports both gas sponsoring extensions. These let the **facilitator** pay for the client's Permit2 approval transaction, removing all gas costs from the client. The client SDK detects advertised extensions automatically. + +### EIP-2612 Gas Sponsoring + +The preferred path. If the payment token supports [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612), the client signs an off-chain permit and the facilitator bundles approval + settlement in a single `settleWithPermit` call — zero gas for the client. + +**Server:** Declare the extension in your route config: + +```go +import ( + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" +) + +routes := x402http.RoutesConfig{ + "GET /api/generate": { + Accepts: x402http.PaymentOptions{ + { + Scheme: "upto", + Price: "$0.10", + Network: "eip155:84532", + PayTo: "0xYourAddress", + }, + }, + Extensions: eip2612gassponsor.DeclareEip2612GasSponsoringExtension(), + }, +} +``` + +**Client:** No additional setup. `UptoEvmScheme` automatically checks for the extension and signs the permit when applicable. + +**Facilitator:** Register the extension: + +```go +import ( + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" +) + +facilitator.RegisterExtension(eip2612gassponsor.EIP2612GasSponsoring) +``` + +### ERC-20 Approval Gas Sponsoring + +Fallback for tokens that do not support EIP-2612. The client signs a raw `approve(Permit2, MaxUint256)` transaction off-chain; the facilitator broadcasts it before settling. + +**Server:** Declare the extension (omit `name`/`version` from token config to signal non-EIP-2612 tokens): + +```go +import ( + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" +) + +routes := x402http.RoutesConfig{ + "GET /api/generate": { + Accepts: x402http.PaymentOptions{ /* ... */ }, + Extensions: erc20approvalgassponsor.DeclareExtension(), + }, +} +``` + +**Client:** The signer must support transaction signing (nonce resolution, fee estimation). `UptoEvmScheme` falls back to this when EIP-2612 is unavailable. + +**Facilitator:** Register with a signer that can broadcast transactions: + +```go +import ( + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" +) + +erc20Ext := &erc20approvalgassponsor.Erc20ApprovalFacilitatorExtension{Signer: evmSigner} +facilitator.RegisterExtension(erc20Ext) +``` + +### Extension Priority + +When both extensions are advertised, EIP-2612 takes priority. The client tries EIP-2612 first; if the token lacks `name`/`version` in `Extra`, it falls back to ERC-20 approval gas sponsoring. + +## Examples + +- [Gin upto server](https://github.com/x402-foundation/x402/tree/main/examples/go/servers/upto) + +## See Also + +- [Exact EVM Scheme](../exact/README.md) — fixed-price payments +- [x402 Docs: Payment Schemes](https://docs.x402.org/getting-started/quickstart-for-sellers#payment-schemes-exact-vs-upto) +- [x402 Docs: Quickstart for Sellers](https://docs.x402.org/getting-started/quickstart-for-sellers) +- [x402 Docs: Quickstart for Buyers](https://docs.x402.org/getting-started/quickstart-for-buyers) diff --git a/go/mechanisms/evm/upto/client/permit2.go b/go/mechanisms/evm/upto/client/permit2.go index bbb8ff75cc..cf94aa56b0 100644 --- a/go/mechanisms/evm/upto/client/permit2.go +++ b/go/mechanisms/evm/upto/client/permit2.go @@ -6,8 +6,8 @@ import ( "math/big" "time" - "github.com/coinbase/x402/go/mechanisms/evm" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/types" ) // CreateUptoPermit2Payload creates a Permit2 payload using the x402UptoPermit2Proxy witness pattern. diff --git a/go/mechanisms/evm/upto/client/rpc.go b/go/mechanisms/evm/upto/client/rpc.go index 55105b3c67..327093f267 100644 --- a/go/mechanisms/evm/upto/client/rpc.go +++ b/go/mechanisms/evm/upto/client/rpc.go @@ -3,7 +3,7 @@ package client import ( "context" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // UptoEvmChainConfig configures RPC behavior for one chain. diff --git a/go/mechanisms/evm/upto/client/rpc_test.go b/go/mechanisms/evm/upto/client/rpc_test.go index 3bec8d9a3c..68611993a9 100644 --- a/go/mechanisms/evm/upto/client/rpc_test.go +++ b/go/mechanisms/evm/upto/client/rpc_test.go @@ -7,7 +7,7 @@ import ( goethtypes "github.com/ethereum/go-ethereum/core/types" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) type rpcTestSigner struct { diff --git a/go/mechanisms/evm/upto/client/scheme.go b/go/mechanisms/evm/upto/client/scheme.go index dcd865a63e..2424d36fbc 100644 --- a/go/mechanisms/evm/upto/client/scheme.go +++ b/go/mechanisms/evm/upto/client/scheme.go @@ -8,11 +8,11 @@ import ( "github.com/ethereum/go-ethereum/common" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" - "github.com/coinbase/x402/go/mechanisms/evm" - exactclient "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" + exactclient "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + "github.com/x402-foundation/x402/go/types" ) // UptoEvmScheme implements SchemeNetworkClient and ExtensionAwareClient for EVM upto payments. diff --git a/go/mechanisms/evm/upto/facilitator/errors.go b/go/mechanisms/evm/upto/facilitator/errors.go index e124d0ec3a..1f627c2900 100644 --- a/go/mechanisms/evm/upto/facilitator/errors.go +++ b/go/mechanisms/evm/upto/facilitator/errors.go @@ -1,6 +1,6 @@ package facilitator -import "github.com/coinbase/x402/go/mechanisms/evm" +import "github.com/x402-foundation/x402/go/mechanisms/evm" // Upto-specific error constants. const ( diff --git a/go/mechanisms/evm/upto/facilitator/permit2.go b/go/mechanisms/evm/upto/facilitator/permit2.go index 4ae438165c..f66c5b6d65 100644 --- a/go/mechanisms/evm/upto/facilitator/permit2.go +++ b/go/mechanisms/evm/upto/facilitator/permit2.go @@ -7,12 +7,12 @@ import ( "strings" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/extensions/erc20approvalgassponsor" - "github.com/coinbase/x402/go/mechanisms/evm" - exactfacilitator "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/extensions/erc20approvalgassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" + exactfacilitator "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + "github.com/x402-foundation/x402/go/types" ) // VerifyUptoPermit2 verifies an upto Permit2 payment payload against the given requirements. diff --git a/go/mechanisms/evm/upto/facilitator/permit2_helpers.go b/go/mechanisms/evm/upto/facilitator/permit2_helpers.go index 7a2417e666..e8c2b5610d 100644 --- a/go/mechanisms/evm/upto/facilitator/permit2_helpers.go +++ b/go/mechanisms/evm/upto/facilitator/permit2_helpers.go @@ -6,8 +6,8 @@ import ( "github.com/ethereum/go-ethereum/common" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/evm" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // EIP2612PermitData holds the parsed EIP-2612 permit fields for settleWithPermit() calls. diff --git a/go/mechanisms/evm/upto/facilitator/permit2_test.go b/go/mechanisms/evm/upto/facilitator/permit2_test.go index 4bd5624826..b16043feb3 100644 --- a/go/mechanisms/evm/upto/facilitator/permit2_test.go +++ b/go/mechanisms/evm/upto/facilitator/permit2_test.go @@ -8,10 +8,10 @@ import ( "testing" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/extensions/eip2612gassponsor" - "github.com/coinbase/x402/go/mechanisms/evm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/eip2612gassponsor" + "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/types" ) // ─── Mock facilitator signer ──────────────────────────────────────────────── diff --git a/go/mechanisms/evm/upto/facilitator/scheme.go b/go/mechanisms/evm/upto/facilitator/scheme.go index 9feb489675..e75c560b4b 100644 --- a/go/mechanisms/evm/upto/facilitator/scheme.go +++ b/go/mechanisms/evm/upto/facilitator/scheme.go @@ -5,9 +5,9 @@ import ( "fmt" "math/rand" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/evm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/types" ) type UptoEvmSchemeConfig struct { diff --git a/go/mechanisms/evm/upto/server/scheme.go b/go/mechanisms/evm/upto/server/scheme.go index c24c6f1b62..4f787e696b 100644 --- a/go/mechanisms/evm/upto/server/scheme.go +++ b/go/mechanisms/evm/upto/server/scheme.go @@ -8,9 +8,9 @@ import ( "strconv" "strings" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/evm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/types" ) // UptoEvmScheme implements the SchemeNetworkServer interface for EVM upto payments (V2). diff --git a/go/mechanisms/evm/upto/server/server_money_parser_test.go b/go/mechanisms/evm/upto/server/server_money_parser_test.go index b26b858230..95602d124a 100644 --- a/go/mechanisms/evm/upto/server/server_money_parser_test.go +++ b/go/mechanisms/evm/upto/server/server_money_parser_test.go @@ -5,7 +5,7 @@ import ( "fmt" "testing" - x402 "github.com/coinbase/x402/go" + x402 "github.com/x402-foundation/x402/go" ) const baseMainnetUSDC = "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" diff --git a/go/mechanisms/evm/v1/network.go b/go/mechanisms/evm/v1/network.go index 85259ddb73..3064880bbe 100644 --- a/go/mechanisms/evm/v1/network.go +++ b/go/mechanisms/evm/v1/network.go @@ -3,7 +3,7 @@ package v1 import ( "math/big" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // NetworkChainIDs maps v1 legacy network names to their chain IDs. diff --git a/go/mechanisms/evm/v1/utils.go b/go/mechanisms/evm/v1/utils.go index 1c4e6abc96..b6eef85abb 100644 --- a/go/mechanisms/evm/v1/utils.go +++ b/go/mechanisms/evm/v1/utils.go @@ -4,7 +4,7 @@ import ( "fmt" "math/big" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // GetEvmChainId returns the chain ID for a v1 legacy network name. diff --git a/go/mechanisms/svm/README.md b/go/mechanisms/svm/README.md index 2b05f7ace4..93266ad572 100644 --- a/go/mechanisms/svm/README.md +++ b/go/mechanisms/svm/README.md @@ -18,7 +18,7 @@ The exact scheme is organized by role: **Import Path:** ``` -github.com/coinbase/x402/go/mechanisms/svm/exact/client +github.com/x402-foundation/x402/go/mechanisms/svm/exact/client ``` **Exports:** @@ -29,7 +29,7 @@ github.com/coinbase/x402/go/mechanisms/svm/exact/client **Import Path:** ``` -github.com/coinbase/x402/go/mechanisms/svm/exact/server +github.com/x402-foundation/x402/go/mechanisms/svm/exact/server ``` **Exports:** @@ -41,7 +41,7 @@ github.com/coinbase/x402/go/mechanisms/svm/exact/server **Import Path:** ``` -github.com/coinbase/x402/go/mechanisms/svm/exact/facilitator +github.com/x402-foundation/x402/go/mechanisms/svm/exact/facilitator ``` **Exports:** @@ -76,7 +76,7 @@ This package includes a built-in `SettlementCache` that prevents a known race co The cache rejects concurrent `/settle` calls that carry the same transaction payload, returning a `duplicate_settlement` error for the second and subsequent attempts. Entries are automatically evicted after 120 seconds (approximately twice the Solana blockhash lifetime). ```go -import svm "github.com/coinbase/x402/go/mechanisms/svm" +import svm "github.com/x402-foundation/x402/go/mechanisms/svm" cache := svm.NewSettlementCache() diff --git a/go/mechanisms/svm/constants.go b/go/mechanisms/svm/constants.go index 597f8f23e1..2a23ca958e 100644 --- a/go/mechanisms/svm/constants.go +++ b/go/mechanisms/svm/constants.go @@ -24,12 +24,15 @@ const ( // Set to 20000 to accommodate: transfer (~6200 CUs) + memo (~8500 CUs without signer) + budget instructions (~300 CUs) + headroom DefaultComputeUnitLimit uint32 = 20000 + // MaxMemoBytes is the maximum byte length for seller-defined memo data (extra.memo) + MaxMemoBytes = 256 + // LighthouseProgramAddress is the Phantom/Solflare Lighthouse program address // Phantom and Solflare wallets inject Lighthouse instructions for user protection on mainnet transactions. // - Phantom adds 1 Lighthouse instruction (4th instruction) // - Solflare adds 2 Lighthouse instructions (4th and 5th instructions) // We allow these as optional instructions to support these wallets. - // See: https://github.com/coinbase/x402/issues/828 + // See: https://github.com/x402-foundation/x402/issues/828 LighthouseProgramAddress = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95" // MemoProgramAddress is the SPL Memo program address diff --git a/go/mechanisms/svm/exact/client/duplicate_tx_test.go b/go/mechanisms/svm/exact/client/duplicate_tx_test.go index a3994f339c..f9ad1dd3d4 100644 --- a/go/mechanisms/svm/exact/client/duplicate_tx_test.go +++ b/go/mechanisms/svm/exact/client/duplicate_tx_test.go @@ -12,13 +12,13 @@ import ( "testing" "unicode/utf8" - "github.com/coinbase/x402/go/mechanisms/svm" - "github.com/coinbase/x402/go/types" bin "github.com/gagliardetto/binary" solana "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/programs/token" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" + "github.com/x402-foundation/x402/go/mechanisms/svm" + "github.com/x402-foundation/x402/go/types" ) const ( @@ -479,3 +479,165 @@ func TestMemoInstructionHasNoSigners(t *testing.T) { // Empty accounts is critical - signers break facilitator verification assert.Empty(t, memoIx.Accounts, "memo must have no accounts") } + +func TestSellerMemo(t *testing.T) { + t.Run("uses extra.memo as memo data when provided", func(t *testing.T) { + server := httptest.NewServer(mockSolanaRPCHandler(t, func() string { + return fixedBlockhash + })) + defer server.Close() + + signer := &mockClientSigner{keypair: solana.NewWallet().PrivateKey} + client := NewExactSvmScheme(signer, &svm.ClientConfig{RPCURL: server.URL}) + + sellerMemo := "pi_3abc123def456" + requirements := types.PaymentRequirements{ + Scheme: "exact", + Network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + Asset: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + Amount: "100000", + PayTo: solana.NewWallet().PublicKey().String(), + MaxTimeoutSeconds: 3600, + Extra: map[string]interface{}{ + "feePayer": solana.NewWallet().PublicKey().String(), + "memo": sellerMemo, + }, + } + + payload, err := client.CreatePaymentPayload(context.Background(), requirements) + require.NoError(t, err) + + decoded, err := svm.DecodeTransaction(payload.Payload["transaction"].(string)) + require.NoError(t, err) + require.GreaterOrEqual(t, len(decoded.Message.Instructions), 4) + + memoIx := decoded.Message.Instructions[3] + memoProgramID := decoded.Message.AccountKeys[memoIx.ProgramIDIndex] + assert.Equal(t, solana.MustPublicKeyFromBase58(svm.MemoProgramAddress), memoProgramID) + + // Memo data should contain a length prefix byte followed by the seller memo + memoData := memoIx.Data + assert.True(t, utf8.Valid(memoData), "Memo data must be valid UTF-8") + assert.Contains(t, string(memoData), sellerMemo, "Memo data should contain seller memo") + }) + + t.Run("produces identical memo data with extra.memo across calls", func(t *testing.T) { + server := httptest.NewServer(mockSolanaRPCHandler(t, func() string { + return fixedBlockhash + })) + defer server.Close() + + signer := &mockClientSigner{keypair: solana.NewWallet().PrivateKey} + client := NewExactSvmScheme(signer, &svm.ClientConfig{RPCURL: server.URL}) + + feePayer := solana.NewWallet().PublicKey() + payTo := solana.NewWallet().PublicKey() + sellerMemo := "order_12345" + + requirements := types.PaymentRequirements{ + Scheme: "exact", + Network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + Asset: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + Amount: "100000", + PayTo: payTo.String(), + MaxTimeoutSeconds: 3600, + Extra: map[string]interface{}{ + "feePayer": feePayer.String(), + "memo": sellerMemo, + }, + } + + ctx := context.Background() + + payload1, err := client.CreatePaymentPayload(ctx, requirements) + require.NoError(t, err) + payload2, err := client.CreatePaymentPayload(ctx, requirements) + require.NoError(t, err) + + decoded1, err := svm.DecodeTransaction(payload1.Payload["transaction"].(string)) + require.NoError(t, err) + decoded2, err := svm.DecodeTransaction(payload2.Payload["transaction"].(string)) + require.NoError(t, err) + + memo1 := string(decoded1.Message.Instructions[3].Data) + memo2 := string(decoded2.Message.Instructions[3].Data) + + assert.Equal(t, memo1, memo2, "Seller memo should be deterministic across calls") + assert.Contains(t, memo1, sellerMemo) + }) + + t.Run("rejects extra.memo exceeding max size", func(t *testing.T) { + server := httptest.NewServer(mockSolanaRPCHandler(t, func() string { + return fixedBlockhash + })) + defer server.Close() + + signer := &mockClientSigner{keypair: solana.NewWallet().PrivateKey} + client := NewExactSvmScheme(signer, &svm.ClientConfig{RPCURL: server.URL}) + + longMemo := "" + for i := 0; i < 257; i++ { + longMemo += "x" + } + + requirements := types.PaymentRequirements{ + Scheme: "exact", + Network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + Asset: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + Amount: "100000", + PayTo: solana.NewWallet().PublicKey().String(), + MaxTimeoutSeconds: 3600, + Extra: map[string]interface{}{ + "feePayer": solana.NewWallet().PublicKey().String(), + "memo": longMemo, + }, + } + + _, err := client.CreatePaymentPayload(context.Background(), requirements) + require.Error(t, err) + assert.Contains(t, err.Error(), ErrMemoExceedsMaxSize) + }) + + t.Run("falls back to random nonce when extra.memo is absent", func(t *testing.T) { + server := httptest.NewServer(mockSolanaRPCHandler(t, func() string { + return fixedBlockhash + })) + defer server.Close() + + signer := &mockClientSigner{keypair: solana.NewWallet().PrivateKey} + client := NewExactSvmScheme(signer, &svm.ClientConfig{RPCURL: server.URL}) + + feePayer := solana.NewWallet().PublicKey() + payTo := solana.NewWallet().PublicKey() + + requirements := types.PaymentRequirements{ + Scheme: "exact", + Network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", + Asset: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU", + Amount: "100000", + PayTo: payTo.String(), + MaxTimeoutSeconds: 3600, + Extra: map[string]interface{}{ + "feePayer": feePayer.String(), + // no memo + }, + } + + ctx := context.Background() + + payload1, err := client.CreatePaymentPayload(ctx, requirements) + require.NoError(t, err) + payload2, err := client.CreatePaymentPayload(ctx, requirements) + require.NoError(t, err) + + decoded1, err := svm.DecodeTransaction(payload1.Payload["transaction"].(string)) + require.NoError(t, err) + decoded2, err := svm.DecodeTransaction(payload2.Payload["transaction"].(string)) + require.NoError(t, err) + + memo1 := string(decoded1.Message.Instructions[3].Data) + memo2 := string(decoded2.Message.Instructions[3].Data) + + assert.NotEqual(t, memo1, memo2, "Random nonces should differ between calls") + }) +} diff --git a/go/mechanisms/svm/exact/client/errors.go b/go/mechanisms/svm/exact/client/errors.go index 5827d215dc..35e8d425ba 100644 --- a/go/mechanisms/svm/exact/client/errors.go +++ b/go/mechanisms/svm/exact/client/errors.go @@ -21,4 +21,5 @@ const ( ErrFailedToCreateTransaction = "invalid_exact_solana_client_failed_to_create_transaction" ErrFailedToSignTransaction = "invalid_exact_solana_client_failed_to_sign_transaction" ErrFailedToEncodeTransaction = "invalid_exact_solana_client_failed_to_encode_transaction" + ErrMemoExceedsMaxSize = "invalid_exact_solana_client_memo_exceeds_max_size" ) diff --git a/go/mechanisms/svm/exact/client/scheme.go b/go/mechanisms/svm/exact/client/scheme.go index 637aebade3..3c0dc4cd93 100644 --- a/go/mechanisms/svm/exact/client/scheme.go +++ b/go/mechanisms/svm/exact/client/scheme.go @@ -14,8 +14,8 @@ import ( "github.com/gagliardetto/solana-go/programs/token" "github.com/gagliardetto/solana-go/rpc" - "github.com/coinbase/x402/go/mechanisms/svm" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/mechanisms/svm" + "github.com/x402-foundation/x402/go/types" ) // ExactSvmScheme implements the SchemeNetworkClient interface for SVM (Solana) exact payments (V2) @@ -163,15 +163,24 @@ func (c *ExactSvmScheme) CreatePaymentPayload( return types.PaymentPayload{}, fmt.Errorf(ErrFailedToBuildTransferIx+": %w", err) } - // Memo with random nonce for transaction uniqueness (empty accounts - SPL Memo doesn't require signers) - memoBytes := make([]byte, 16) - if _, err := rand.Read(memoBytes); err != nil { - return types.PaymentPayload{}, fmt.Errorf(ErrFailedToBuildMemoIx+": %w", err) + // Memo instruction: use seller-defined memo from extra.memo, or random nonce for uniqueness + var memoPayload []byte + if memoStr, ok := requirements.Extra["memo"].(string); ok && memoStr != "" { + memoPayload = []byte(memoStr) + if len(memoPayload) > svm.MaxMemoBytes { + return types.PaymentPayload{}, errors.New(ErrMemoExceedsMaxSize) + } + } else { + memoBytes := make([]byte, 16) + if _, err := rand.Read(memoBytes); err != nil { + return types.PaymentPayload{}, fmt.Errorf(ErrFailedToBuildMemoIx+": %w", err) + } + memoPayload = []byte(hex.EncodeToString(memoBytes)) } memoIx := solana.NewInstruction( solana.MustPublicKeyFromBase58(svm.MemoProgramAddress), solana.AccountMetaSlice{}, - []byte(hex.EncodeToString(memoBytes)), + memoPayload, ) // Create final transaction diff --git a/go/mechanisms/svm/exact/facilitator/duplicate_tx_test.go b/go/mechanisms/svm/exact/facilitator/duplicate_tx_test.go index 5c96be2ba3..69271ecf60 100644 --- a/go/mechanisms/svm/exact/facilitator/duplicate_tx_test.go +++ b/go/mechanisms/svm/exact/facilitator/duplicate_tx_test.go @@ -4,8 +4,8 @@ import ( "testing" "time" - "github.com/coinbase/x402/go/mechanisms/svm" "github.com/stretchr/testify/assert" + "github.com/x402-foundation/x402/go/mechanisms/svm" ) func TestFacilitatorInstructionConstraints(t *testing.T) { diff --git a/go/mechanisms/svm/exact/facilitator/errors.go b/go/mechanisms/svm/exact/facilitator/errors.go index 9142123ac7..7f8087daf9 100644 --- a/go/mechanisms/svm/exact/facilitator/errors.go +++ b/go/mechanisms/svm/exact/facilitator/errors.go @@ -25,6 +25,10 @@ const ( ErrTransactionSigningFailed = "invalid_exact_solana_transaction_signing_failed" ErrTransactionSimulationFailed = "invalid_exact_solana_transaction_simulation_failed" + // Memo verification errors + ErrMemoMismatch = "invalid_exact_solana_payload_memo_mismatch" + ErrMemoCount = "invalid_exact_solana_payload_memo_count" + // Settle errors ErrVerificationFailed = "invalid_exact_solana_verification_failed" ErrFeePayerMismatch = "invalid_exact_solana_fee_payer_mismatch" diff --git a/go/mechanisms/svm/exact/facilitator/scheme.go b/go/mechanisms/svm/exact/facilitator/scheme.go index 7c846dbf85..f34d95c3f9 100644 --- a/go/mechanisms/svm/exact/facilitator/scheme.go +++ b/go/mechanisms/svm/exact/facilitator/scheme.go @@ -11,9 +11,9 @@ import ( computebudget "github.com/gagliardetto/solana-go/programs/compute-budget" "github.com/gagliardetto/solana-go/programs/token" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/svm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/svm" + "github.com/x402-foundation/x402/go/types" ) // ExactSvmScheme implements the SchemeNetworkFacilitator interface for SVM (Solana) exact payments (V2) @@ -136,7 +136,7 @@ func (f *ExactSvmScheme) Verify( // - 4 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse or Memo // - 5 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse + Lighthouse or Memo // - 6 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse + Lighthouse + Memo - // See: https://github.com/coinbase/x402/issues/828 + // See: https://github.com/x402-foundation/x402/issues/828 numInstructions := len(tx.Message.Instructions) if numInstructions < 3 || numInstructions > 6 { return nil, x402.NewVerifyError(ErrTransactionInstructionsLength, "", fmt.Sprintf("transaction instructions length mismatch: %d < 3 or %d > 6", numInstructions, numInstructions)) @@ -200,6 +200,25 @@ func (f *ExactSvmScheme) Verify( return nil, x402.NewVerifyError(reason, payer, fmt.Sprintf("unknown optional instruction: %s", progID.String())) } + + // Step 5b: Verify memo content matches extra.memo when present + if expectedMemo, ok := requirements.Extra["memo"].(string); ok && expectedMemo != "" { + var memoCount int + var actualMemoData []byte + for _, instruction := range optionalInstructions { + progID := tx.Message.AccountKeys[instruction.ProgramIDIndex] + if progID.Equals(memoPubkey) { + memoCount++ + actualMemoData = instruction.Data + } + } + if memoCount != 1 { + return nil, x402.NewVerifyError(ErrMemoCount, payer, "expected exactly one memo instruction when extra.memo is present") + } + if string(actualMemoData) != expectedMemo { + return nil, x402.NewVerifyError(ErrMemoMismatch, payer, "memo data does not match extra.memo") + } + } } // Step 6: Sign and Simulate Transaction diff --git a/go/mechanisms/svm/exact/server/scheme.go b/go/mechanisms/svm/exact/server/scheme.go index f6228ac4a9..709e6d5b88 100644 --- a/go/mechanisms/svm/exact/server/scheme.go +++ b/go/mechanisms/svm/exact/server/scheme.go @@ -7,9 +7,9 @@ import ( "strconv" "strings" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/svm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/svm" + "github.com/x402-foundation/x402/go/types" ) // ExactSvmScheme implements the SchemeNetworkServer interface for SVM (Solana) exact payments (V2) diff --git a/go/mechanisms/svm/exact/server/server_money_parser_test.go b/go/mechanisms/svm/exact/server/server_money_parser_test.go index e79207469e..c8aed7dd43 100644 --- a/go/mechanisms/svm/exact/server/server_money_parser_test.go +++ b/go/mechanisms/svm/exact/server/server_money_parser_test.go @@ -4,7 +4,7 @@ import ( "fmt" "testing" - x402 "github.com/coinbase/x402/go" + x402 "github.com/x402-foundation/x402/go" ) // TestRegisterMoneyParser_SingleCustomParser tests a single custom money parser diff --git a/go/mechanisms/svm/exact/v1/README.md b/go/mechanisms/svm/exact/v1/README.md index 69f5248114..7acc46f6df 100644 --- a/go/mechanisms/svm/exact/v1/README.md +++ b/go/mechanisms/svm/exact/v1/README.md @@ -32,8 +32,8 @@ The V1 implementation exists solely for backwards compatibility. **New implement ```go import ( - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/solana/v1" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/solana/v1" ) client := x402.NewX402Client() @@ -47,8 +47,8 @@ v1.RegisterClient(client, signer, "solana", "solana-devnet") ```go import ( - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/solana/v1" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/solana/v1" ) facilitator := x402.NewX402Facilitator() @@ -64,14 +64,14 @@ If you're currently using V1, consider migrating to V2: **Before (V1)**: ```go -import "github.com/coinbase/x402/go/mechanisms/solana/v1" +import "github.com/x402-foundation/x402/go/mechanisms/solana/v1" v1.RegisterClient(client, signer, "solana") ``` **After (V2)**: ```go -import "github.com/coinbase/x402/go/mechanisms/solana" +import "github.com/x402-foundation/x402/go/mechanisms/solana" solana.RegisterClient(client, signer, "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp") ``` diff --git a/go/mechanisms/svm/exact/v1/client/errors.go b/go/mechanisms/svm/exact/v1/client/errors.go index ff0785cc00..57d43dffb9 100644 --- a/go/mechanisms/svm/exact/v1/client/errors.go +++ b/go/mechanisms/svm/exact/v1/client/errors.go @@ -22,4 +22,5 @@ const ( ErrFailedToCreateTransaction = "invalid_exact_solana_client_failed_to_create_transaction" ErrFailedToSignTransaction = "invalid_exact_solana_client_failed_to_sign_transaction" ErrFailedToEncodeTransaction = "invalid_exact_solana_client_failed_to_encode_transaction" + ErrMemoExceedsMaxSize = "invalid_exact_solana_client_memo_exceeds_max_size" ) diff --git a/go/mechanisms/svm/exact/v1/client/scheme.go b/go/mechanisms/svm/exact/v1/client/scheme.go index f3640c1462..685c42de50 100644 --- a/go/mechanisms/svm/exact/v1/client/scheme.go +++ b/go/mechanisms/svm/exact/v1/client/scheme.go @@ -15,8 +15,8 @@ import ( "github.com/gagliardetto/solana-go/programs/token" "github.com/gagliardetto/solana-go/rpc" - svm "github.com/coinbase/x402/go/mechanisms/svm" - "github.com/coinbase/x402/go/types" + svm "github.com/x402-foundation/x402/go/mechanisms/svm" + "github.com/x402-foundation/x402/go/types" ) // ExactSvmSchemeV1 implements the SchemeNetworkClientV1 interface for SVM (Solana) exact payments (V1) @@ -174,15 +174,24 @@ func (c *ExactSvmSchemeV1) CreatePaymentPayload( return types.PaymentPayloadV1{}, fmt.Errorf(ErrFailedToBuildTransferIx+": %w", err) } - // Memo with random nonce for transaction uniqueness (empty accounts - SPL Memo doesn't require signers) - memoBytes := make([]byte, 16) - if _, err := rand.Read(memoBytes); err != nil { - return types.PaymentPayloadV1{}, fmt.Errorf(ErrFailedToBuildMemoIx+": %w", err) + // Memo instruction: use seller-defined memo from extra.memo, or random nonce for uniqueness + var memoPayload []byte + if memoStr, ok := extraMap["memo"].(string); ok && memoStr != "" { + memoPayload = []byte(memoStr) + if len(memoPayload) > svm.MaxMemoBytes { + return types.PaymentPayloadV1{}, errors.New(ErrMemoExceedsMaxSize) + } + } else { + memoBytes := make([]byte, 16) + if _, err := rand.Read(memoBytes); err != nil { + return types.PaymentPayloadV1{}, fmt.Errorf(ErrFailedToBuildMemoIx+": %w", err) + } + memoPayload = []byte(hex.EncodeToString(memoBytes)) } memoIx := solana.NewInstruction( solana.MustPublicKeyFromBase58(svm.MemoProgramAddress), solana.AccountMetaSlice{}, - []byte(hex.EncodeToString(memoBytes)), + memoPayload, ) // Create final transaction diff --git a/go/mechanisms/svm/exact/v1/facilitator/duplicate_tx_test.go b/go/mechanisms/svm/exact/v1/facilitator/duplicate_tx_test.go index 68fabf6d6f..f2201f6cbe 100644 --- a/go/mechanisms/svm/exact/v1/facilitator/duplicate_tx_test.go +++ b/go/mechanisms/svm/exact/v1/facilitator/duplicate_tx_test.go @@ -4,8 +4,8 @@ import ( "testing" "time" - "github.com/coinbase/x402/go/mechanisms/svm" "github.com/stretchr/testify/assert" + "github.com/x402-foundation/x402/go/mechanisms/svm" ) func TestDuplicateSettlementCacheV1(t *testing.T) { diff --git a/go/mechanisms/svm/exact/v1/facilitator/errors.go b/go/mechanisms/svm/exact/v1/facilitator/errors.go index 980162f4c1..0f4852b186 100644 --- a/go/mechanisms/svm/exact/v1/facilitator/errors.go +++ b/go/mechanisms/svm/exact/v1/facilitator/errors.go @@ -26,6 +26,10 @@ const ( ErrTransactionSigningFailed = "invalid_exact_solana_transaction_signing_failed" ErrTransactionSimulationFailed = "invalid_exact_solana_transaction_simulation_failed" + // Memo verification errors + ErrMemoMismatch = "invalid_exact_solana_payload_memo_mismatch" + ErrMemoCount = "invalid_exact_solana_payload_memo_count" + // Settle errors ErrVerificationFailed = "invalid_exact_solana_verification_failed" ErrFeePayerMismatch = "invalid_exact_solana_fee_payer_mismatch" diff --git a/go/mechanisms/svm/exact/v1/facilitator/scheme.go b/go/mechanisms/svm/exact/v1/facilitator/scheme.go index 1d289c980d..f7a4027a61 100644 --- a/go/mechanisms/svm/exact/v1/facilitator/scheme.go +++ b/go/mechanisms/svm/exact/v1/facilitator/scheme.go @@ -12,9 +12,9 @@ import ( computebudget "github.com/gagliardetto/solana-go/programs/compute-budget" "github.com/gagliardetto/solana-go/programs/token" - x402 "github.com/coinbase/x402/go" - svm "github.com/coinbase/x402/go/mechanisms/svm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + svm "github.com/x402-foundation/x402/go/mechanisms/svm" + "github.com/x402-foundation/x402/go/types" ) // ExactSvmSchemeV1 implements the SchemeNetworkFacilitator interface for SVM (Solana) exact payments (V1) @@ -146,7 +146,7 @@ func (f *ExactSvmSchemeV1) Verify( // - 4 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse or Memo // - 5 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse + Lighthouse or Memo // - 6 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse + Lighthouse + Memo - // See: https://github.com/coinbase/x402/issues/828 + // See: https://github.com/x402-foundation/x402/issues/828 numInstructions := len(tx.Message.Instructions) if numInstructions < 3 || numInstructions > 6 { return nil, x402.NewVerifyError(ErrTransactionInstructionsLength, "", fmt.Sprintf("transaction instructions length mismatch: %d < 3 or %d > 6", numInstructions, numInstructions)) @@ -197,6 +197,25 @@ func (f *ExactSvmSchemeV1) Verify( return nil, x402.NewVerifyError(reason, payer, fmt.Sprintf("unknown optional instruction: %s", progID.String())) } + + // Step 5b: Verify memo content matches extra.memo when present + if expectedMemo, ok := reqExtraMap["memo"].(string); ok && expectedMemo != "" { + var memoCount int + var actualMemoData []byte + for _, instruction := range optionalInstructions { + progID := tx.Message.AccountKeys[instruction.ProgramIDIndex] + if progID.Equals(memoPubkey) { + memoCount++ + actualMemoData = instruction.Data + } + } + if memoCount != 1 { + return nil, x402.NewVerifyError(ErrMemoCount, payer, "expected exactly one memo instruction when extra.memo is present") + } + if string(actualMemoData) != expectedMemo { + return nil, x402.NewVerifyError(ErrMemoMismatch, payer, "memo data does not match extra.memo") + } + } } // Step 6: Sign and Simulate Transaction diff --git a/go/server.go b/go/server.go index f2890b8c95..88834a72ce 100644 --- a/go/server.go +++ b/go/server.go @@ -11,7 +11,7 @@ import ( "sync" "time" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) var ( @@ -74,13 +74,48 @@ type x402ResourceServer struct { registeredExtensions map[string]types.ResourceServerExtension supportedCache *SupportedCache - // Lifecycle hooks - beforeVerifyHooks []BeforeVerifyHook - afterVerifyHooks []AfterVerifyHook - onVerifyFailureHooks []OnVerifyFailureHook - beforeSettleHooks []BeforeSettleHook - afterSettleHooks []AfterSettleHook - onSettleFailureHooks []OnSettleFailureHook + // Manual lifecycle hooks registered via OnBeforeVerify / OnAfterVerify / etc. + // These fire for every request regardless of scheme/network. Mirrors TS + // `beforeVerifyHooks: BeforeVerifyHook[]` arrays. + beforeVerifyHooks []BeforeVerifyHook + afterVerifyHooks []AfterVerifyHook + onVerifyFailureHooks []OnVerifyFailureHook + beforeSettleHooks []BeforeSettleHook + afterSettleHooks []AfterSettleHook + onSettleFailureHooks []OnSettleFailureHook + onVerifiedPaymentCanceledHooks []OnVerifiedPaymentCanceledHook + + // Per-scheme hook adapters: only the matched (network, scheme) entry + // fires for a given request. Mirrors TS `schemeHookAdapters: Map>`. Replaces the previous behavior of + // appending scheme hooks into the global lists, which leaked hooks across + // unrelated schemes registered on the same server. + schemeHookAdapters map[Network]map[string]*hookAdapterHandles + + // Per-extension hook adapters: only fire when the extension key is + // declared on the route via `declaredExtensions`. Mirrors TS + // `extensionHookAdapters: Map`. + extensionHookAdapters map[string]*hookAdapterHandles +} + +// hookAdapterHandles bundles the optional per-phase hook funcs contributed +// by a scheme or extension. Phases left nil are skipped at invocation time. +// Mirrors TS `HookAdapterHandles`. +type hookAdapterHandles struct { + BeforeVerify BeforeVerifyHook + AfterVerify AfterVerifyHook + OnVerifyFailure OnVerifyFailureHook + BeforeSettle BeforeSettleHook + AfterSettle AfterSettleHook + OnSettleFailure OnSettleFailureHook + OnVerifiedPaymentCanceled OnVerifiedPaymentCanceledHook +} + +// labeledHook tags a hook function with its source for diagnostics. The +// source string is one of "manual #N", `scheme "X"`, or `extension "Y"`. +type labeledHook[F any] struct { + Label string + Hook F } // SupportedCache caches facilitator capabilities @@ -117,6 +152,15 @@ func (c *SupportedCache) Get(key string) (SupportedResponse, bool) { return response, true } +// Clear removes all cached supported responses and expiry entries +func (c *SupportedCache) Clear() { + c.mu.Lock() + defer c.mu.Unlock() + + clear(c.data) + clear(c.expiry) +} + // ResourceServerOption configures the server type ResourceServerOption func(*x402ResourceServer) @@ -147,9 +191,11 @@ func WithCacheTTL(ttl time.Duration) ResourceServerOption { func Newx402ResourceServer(opts ...ResourceServerOption) *x402ResourceServer { s := &x402ResourceServer{ - schemes: make(map[Network]map[string]SchemeNetworkServer), - facilitatorClients: make(map[Network]map[string]FacilitatorClient), - registeredExtensions: make(map[string]types.ResourceServerExtension), + schemes: make(map[Network]map[string]SchemeNetworkServer), + facilitatorClients: make(map[Network]map[string]FacilitatorClient), + registeredExtensions: make(map[string]types.ResourceServerExtension), + schemeHookAdapters: make(map[Network]map[string]*hookAdapterHandles), + extensionHookAdapters: make(map[string]*hookAdapterHandles), supportedCache: &SupportedCache{ data: make(map[string]SupportedResponse), expiry: make(map[string]time.Time), @@ -224,7 +270,18 @@ func (s *x402ResourceServer) HasFacilitatorSupport(network Network, scheme strin return exists } -// Register registers a payment mechanism (V2, default) +// Register registers a payment mechanism (V2, default). +// +// Auto-wires lifecycle hooks contributed by the scheme via the optional +// BeforeVerifyHookProvider / AfterVerifyHookProvider / BeforeSettleHookProvider +// / AfterSettleHookProvider / OnVerifyFailureHookProvider / OnSettleFailureHookProvider +// / OnVerifiedPaymentCanceledHookProvider interfaces (mirrors the TS schemeHooks field). +// +// Scheme hooks are stored per (network, scheme) and fire ONLY when the +// matched requirements use that scheme/network — they do NOT leak across +// other registered schemes. Manual hooks registered via OnBeforeVerify etc. +// run for every request and execute BEFORE the matched scheme's hooks +// (mirrors TS hook ordering: manual → matched scheme → declared extensions). func (s *x402ResourceServer) Register(network Network, schemeServer SchemeNetworkServer) *x402ResourceServer { s.mu.Lock() defer s.mu.Unlock() @@ -232,19 +289,151 @@ func (s *x402ResourceServer) Register(network Network, schemeServer SchemeNetwor if s.schemes[network] == nil { s.schemes[network] = make(map[string]SchemeNetworkServer) } - s.schemes[network][schemeServer.Scheme()] = schemeServer + + handles := &hookAdapterHandles{} + if h, ok := schemeServer.(BeforeVerifyHookProvider); ok { + if hook := h.BeforeVerifyHook(); hook != nil { + handles.BeforeVerify = hook + } + } + if h, ok := schemeServer.(AfterVerifyHookProvider); ok { + if hook := h.AfterVerifyHook(); hook != nil { + handles.AfterVerify = hook + } + } + if h, ok := schemeServer.(OnVerifyFailureHookProvider); ok { + if hook := h.OnVerifyFailureHook(); hook != nil { + handles.OnVerifyFailure = hook + } + } + if h, ok := schemeServer.(BeforeSettleHookProvider); ok { + if hook := h.BeforeSettleHook(); hook != nil { + handles.BeforeSettle = hook + } + } + if h, ok := schemeServer.(AfterSettleHookProvider); ok { + if hook := h.AfterSettleHook(); hook != nil { + handles.AfterSettle = hook + } + } + if h, ok := schemeServer.(OnSettleFailureHookProvider); ok { + if hook := h.OnSettleFailureHook(); hook != nil { + handles.OnSettleFailure = hook + } + } + if h, ok := schemeServer.(OnVerifiedPaymentCanceledHookProvider); ok { + if hook := h.OnVerifiedPaymentCanceledHook(); hook != nil { + handles.OnVerifiedPaymentCanceled = hook + } + } + + if handles.isEmpty() { + // No scheme hooks; clear any prior registration for this slot so + // re-registering a scheme without hooks doesn't keep stale entries. + if byScheme, ok := s.schemeHookAdapters[network]; ok { + delete(byScheme, schemeServer.Scheme()) + if len(byScheme) == 0 { + delete(s.schemeHookAdapters, network) + } + } + } else { + if s.schemeHookAdapters[network] == nil { + s.schemeHookAdapters[network] = make(map[string]*hookAdapterHandles) + } + s.schemeHookAdapters[network][schemeServer.Scheme()] = handles + } + return s } +// isEmpty reports whether no hook phases are populated. +func (h *hookAdapterHandles) isEmpty() bool { + return h.BeforeVerify == nil && h.AfterVerify == nil && h.OnVerifyFailure == nil && + h.BeforeSettle == nil && h.AfterSettle == nil && h.OnSettleFailure == nil && + h.OnVerifiedPaymentCanceled == nil +} + func (s *x402ResourceServer) RegisterExtension(extension types.ResourceServerExtension) *x402ResourceServer { s.mu.Lock() defer s.mu.Unlock() - s.registeredExtensions[extension.Key()] = extension + key := extension.Key() + s.registeredExtensions[key] = extension + + hp, ok := extension.(ResourceServerExtensionHookProvider) + if !ok { + delete(s.extensionHookAdapters, key) + return s + } + + // Wire optional per-extension lifecycle hooks. Each phase is wrapped so it + // only fires when `ctx.DeclaredExtensions[key]` is set — mirrors TS + // `bindExtensionHookAdapter`. + hooks := hp.ResourceServerExtensionHooks() + handles := &hookAdapterHandles{ + BeforeVerify: gateExtensionHook(key, hooks.OnBeforeVerify, func(c VerifyContext) map[string]interface{} { return c.DeclaredExtensions }), + AfterVerify: gateExtensionHook(key, hooks.OnAfterVerify, func(c VerifyResultContext) map[string]interface{} { return c.DeclaredExtensions }), + OnVerifyFailure: gateExtensionHook(key, hooks.OnVerifyFailure, func(c VerifyFailureContext) map[string]interface{} { return c.DeclaredExtensions }), + BeforeSettle: gateExtensionHook(key, hooks.OnBeforeSettle, func(c SettleContext) map[string]interface{} { return c.DeclaredExtensions }), + AfterSettle: gateExtensionVoidHook(key, hooks.OnAfterSettle, func(c SettleResultContext) map[string]interface{} { return c.DeclaredExtensions }), + OnSettleFailure: gateExtensionHook(key, hooks.OnSettleFailure, func(c SettleFailureContext) map[string]interface{} { return c.DeclaredExtensions }), + OnVerifiedPaymentCanceled: gateExtensionVoidHook(key, hooks.OnVerifiedPaymentCanceled, func(c VerifiedPaymentCanceledContext) map[string]interface{} { return c.DeclaredExtensions }), + } + if handles.isEmpty() { + delete(s.extensionHookAdapters, key) + } else { + s.extensionHookAdapters[key] = handles + } return s } +// gateExtensionHook returns a wrapper that invokes `impl` only when the +// declared-extension map carries `key`. Mirrors TS `bindExtensionHookAdapter`'s +// `if (ctx.declaredExtensions[extensionKey] === undefined) return;` guard. +// Returns nil when `impl` is nil so RegisterExtension can drop the phase. +func gateExtensionHook[Ctx any, Result any]( + key string, + impl func(Ctx) (*Result, error), + declared func(Ctx) map[string]interface{}, +) func(Ctx) (*Result, error) { + if impl == nil { + return nil + } + return func(ctx Ctx) (*Result, error) { + ext := declared(ctx) + if ext == nil { + return nil, nil + } + if _, ok := ext[key]; !ok { + return nil, nil + } + return impl(ctx) + } +} + +// gateExtensionVoidHook is the error-only variant of gateExtensionHook for +// hooks that don't return a result struct (AfterSettle, OnVerifiedPaymentCanceled). +func gateExtensionVoidHook[Ctx any]( + key string, + impl func(Ctx) error, + declared func(Ctx) map[string]interface{}, +) func(Ctx) error { + if impl == nil { + return nil + } + return func(ctx Ctx) error { + ext := declared(ctx) + if ext == nil { + return nil + } + if _, ok := ext[key]; !ok { + return nil + } + return impl(ctx) + } +} + // ============================================================================ // Hook Registration Methods (Chainable) // ============================================================================ @@ -291,6 +480,114 @@ func (s *x402ResourceServer) OnSettleFailure(hook OnSettleFailureHook) *x402Reso return s } +func (s *x402ResourceServer) OnVerifiedPaymentCanceled(hook OnVerifiedPaymentCanceledHook) *x402ResourceServer { + s.mu.Lock() + defer s.mu.Unlock() + s.onVerifiedPaymentCanceledHooks = append(s.onVerifiedPaymentCanceledHooks, hook) + return s +} + +// matchedSchemeHooks returns the per-(network, scheme) hook handles for the +// scheme that matched the current request, or nil when no scheme is registered +// for that pair. Caller must hold s.mu (read). +func (s *x402ResourceServer) matchedSchemeHooks(network Network, scheme string) *hookAdapterHandles { + if byScheme, ok := s.schemeHookAdapters[network]; ok { + if h, ok := byScheme[scheme]; ok { + return h + } + } + return nil +} + +// orderedHooks returns the hooks for `phase` in the canonical execution order: +// manual → matched scheme → declared extensions. Mirrors TS `getLabeledHooks`. +// +// `pickPhase` extracts the per-phase hook from a `*hookAdapterHandles` (passing +// nil-safe). Caller must hold s.mu (read). +func orderedHooks[F any]( + s *x402ResourceServer, + phase string, + manual []F, + scheme *hookAdapterHandles, + declaredExtensions map[string]interface{}, + pickPhase func(*hookAdapterHandles) F, + isNil func(F) bool, +) []labeledHook[F] { + out := make([]labeledHook[F], 0, len(manual)+1+len(declaredExtensions)) + for i, h := range manual { + out = append(out, labeledHook[F]{Label: fmt.Sprintf("manual %s hook #%d", phase, i), Hook: h}) + } + if scheme != nil { + if h := pickPhase(scheme); !isNil(h) { + out = append(out, labeledHook[F]{Label: fmt.Sprintf("scheme %s", phase), Hook: h}) + } + } + for key := range declaredExtensions { + if handles, ok := s.extensionHookAdapters[key]; ok { + if h := pickPhase(handles); !isNil(h) { + out = append(out, labeledHook[F]{Label: fmt.Sprintf("extension %q %s", key, phase), Hook: h}) + } + } + } + return out +} + +// CreatePaymentCancellationDispatcher returns a dispatcher with no declared +// extensions. Equivalent to CreatePaymentCancellationDispatcherWithExtensions(..., +// nil). Kept for callers that don't track route extension declarations. +func (s *x402ResourceServer) CreatePaymentCancellationDispatcher( + ctx context.Context, + payload types.PaymentPayload, + requirements types.PaymentRequirements, +) *PaymentCancellationDispatcher { + return s.CreatePaymentCancellationDispatcherWithExtensions(ctx, payload, requirements, nil) +} + +// CreatePaymentCancellationDispatcherWithExtensions returns a dispatcher +// that, when Cancel'd, invokes onVerifiedPaymentCanceled hooks exactly once. +// The HTTP transport calls this after a successful Verify but before/instead +// of Settle when the resource handler errors or returns a non-2xx response. +// +// Hook execution order (mirrors verify/settle): manual → matched scheme → +// declared extensions. Extension hooks gate on `declaredExtensions[key]` +// being set on the route. +func (s *x402ResourceServer) CreatePaymentCancellationDispatcherWithExtensions( + ctx context.Context, + payload types.PaymentPayload, + requirements types.PaymentRequirements, + declaredExtensions map[string]interface{}, +) *PaymentCancellationDispatcher { + payloadBytes, _ := json.Marshal(payload) + requirementsBytes, _ := json.Marshal(requirements) + settleCtx := SettleContext{ + Ctx: ctx, + Payload: payload, + Requirements: requirements, + DeclaredExtensions: declaredExtensions, + PayloadBytes: payloadBytes, + RequirementsBytes: requirementsBytes, + } + return &PaymentCancellationDispatcher{ + fire: func(opts VerifiedPaymentCancelOptions) { + cancelCtx := VerifiedPaymentCanceledContext{ + SettleContext: settleCtx, + Reason: opts.Reason, + Err: opts.Err, + ResponseStatus: opts.ResponseStatus, + } + s.mu.RLock() + matchedScheme := s.matchedSchemeHooks(Network(requirements.Network), requirements.Scheme) + hooks := orderedHooks(s, "onVerifiedPaymentCanceled", s.onVerifiedPaymentCanceledHooks, matchedScheme, + declaredExtensions, func(h *hookAdapterHandles) OnVerifiedPaymentCanceledHook { return h.OnVerifiedPaymentCanceled }, + func(f OnVerifiedPaymentCanceledHook) bool { return f == nil }) + s.mu.RUnlock() + for _, lh := range hooks { + _ = lh.Hook(cancelCtx) + } + }, + } +} + // ============================================================================ // Core Payment Methods (V2 Only) // ============================================================================ @@ -379,8 +676,22 @@ func (s *x402ResourceServer) FindMatchingRequirements(available []types.PaymentR return nil } -// VerifyPayment verifies a V2 payment +// VerifyPayment verifies a V2 payment with no declared extensions. +// Equivalent to VerifyPaymentWithExtensions(ctx, payload, requirements, nil). func (s *x402ResourceServer) VerifyPayment(ctx context.Context, payload types.PaymentPayload, requirements types.PaymentRequirements) (*VerifyResponse, error) { + return s.VerifyPaymentWithExtensions(ctx, payload, requirements, nil) +} + +// VerifyPaymentWithExtensions verifies a V2 payment, gating extension hooks +// on the supplied `declaredExtensions` map (keys must be present for the +// extension's hook to fire). Hook execution order: manual → matched scheme → +// declared extensions. +func (s *x402ResourceServer) VerifyPaymentWithExtensions( + ctx context.Context, + payload types.PaymentPayload, + requirements types.PaymentRequirements, + declaredExtensions map[string]interface{}, +) (*VerifyResponse, error) { // Marshal to bytes early for hooks (escape hatch for extensions) payloadBytes, err := json.Marshal(payload) if err != nil { @@ -392,34 +703,68 @@ func (s *x402ResourceServer) VerifyPayment(ctx context.Context, payload types.Pa return nil, NewVerifyError(ErrFailedToMarshalRequirements, "", err.Error()) } - // Execute beforeVerify hooks hookCtx := VerifyContext{ - Ctx: ctx, - Payload: payload, - Requirements: requirements, - PayloadBytes: payloadBytes, - RequirementsBytes: requirementsBytes, + Ctx: ctx, + Payload: payload, + Requirements: requirements, + DeclaredExtensions: declaredExtensions, + PayloadBytes: payloadBytes, + RequirementsBytes: requirementsBytes, } - for _, hook := range s.beforeVerifyHooks { - result, err := hook(hookCtx) + s.mu.RLock() + scheme := requirements.Scheme + network := Network(requirements.Network) + matchedScheme := s.matchedSchemeHooks(network, scheme) + beforeVerifyHooks := orderedHooks(s, "beforeVerify", s.beforeVerifyHooks, matchedScheme, + declaredExtensions, func(h *hookAdapterHandles) BeforeVerifyHook { return h.BeforeVerify }, + func(f BeforeVerifyHook) bool { return f == nil }) + afterVerifyHooks := orderedHooks(s, "afterVerify", s.afterVerifyHooks, matchedScheme, + declaredExtensions, func(h *hookAdapterHandles) AfterVerifyHook { return h.AfterVerify }, + func(f AfterVerifyHook) bool { return f == nil }) + verifyFailureHooks := orderedHooks(s, "onVerifyFailure", s.onVerifyFailureHooks, matchedScheme, + declaredExtensions, func(h *hookAdapterHandles) OnVerifyFailureHook { return h.OnVerifyFailure }, + func(f OnVerifyFailureHook) bool { return f == nil }) + facilitator := s.facilitatorClients[network][scheme] + s.mu.RUnlock() + + var skipVerifyResult *VerifyResponse + for _, lh := range beforeVerifyHooks { + result, err := lh.Hook(hookCtx) if err != nil { return nil, err } - if result != nil && result.Abort { + if result == nil { + continue + } + if result.Abort { return nil, NewVerifyError(result.Reason, "", result.Message) } + if result.Skip && result.SkipVerifyResult != nil { + // Last skip wins, like SettleResponse for after-hooks + skipVerifyResult = result.SkipVerifyResult + } } - s.mu.RLock() - scheme := requirements.Scheme - network := Network(requirements.Network) - - facilitator := s.facilitatorClients[network][scheme] - s.mu.RUnlock() + // Short-circuit: a BeforeVerify hook produced a local verify result. Still run + // AfterVerify hooks so cooperative-refund SkipHandler signaling works. + if skipVerifyResult != nil { + resultCtx := VerifyResultContext{VerifyContext: hookCtx, Result: skipVerifyResult} + for _, lh := range afterVerifyHooks { + directive, _ := lh.Hook(resultCtx) + if directive != nil && directive.SkipHandler { + resp := directive.Response + if resp == nil { + resp = &SkipHandlerDirective{} + } + skipVerifyResult.SkipHandler = resp + } + } + return skipVerifyResult, nil + } if facilitator == nil { - return nil, NewVerifyError(ErrNoFacilitatorForNetwork, "", fmt.Sprintf("no facilitator for %s on %s", scheme, network)) + return nil, NewVerifyError(ErrNoFacilitatorForNetwork, "", fmt.Sprintf("no facilitator for scheme=%q network=%q", scheme, network)) } // Use already marshaled bytes for network call @@ -428,8 +773,8 @@ func (s *x402ResourceServer) VerifyPayment(ctx context.Context, payload types.Pa // Handle failure if verifyErr != nil { failureCtx := VerifyFailureContext{VerifyContext: hookCtx, Error: verifyErr} - for _, hook := range s.onVerifyFailureHooks { - result, _ := hook(failureCtx) + for _, lh := range verifyFailureHooks { + result, _ := lh.Hook(failureCtx) if result != nil && result.Recovered { return result.Result, nil } @@ -437,19 +782,46 @@ func (s *x402ResourceServer) VerifyPayment(ctx context.Context, payload types.Pa return verifyResult, verifyErr } - // Execute afterVerify hooks + // Execute afterVerify hooks. The last hook to return a SkipHandler directive + // wins; this lets schemes signal that a self-contained operation (e.g. + // cooperative refund) should bypass the resource handler and settle inline. resultCtx := VerifyResultContext{VerifyContext: hookCtx, Result: verifyResult} - for _, hook := range s.afterVerifyHooks { - _ = hook(resultCtx) // Log errors but don't fail + for _, lh := range afterVerifyHooks { + directive, _ := lh.Hook(resultCtx) // Log errors but don't fail + if directive != nil && directive.SkipHandler { + resp := directive.Response + if resp == nil { + resp = &SkipHandlerDirective{} + } + verifyResult.SkipHandler = resp + } } return verifyResult, nil } -// SettlePayment settles a V2 payment. -// If overrides is non-nil and overrides.Amount is set, the effective requirements amount -// is replaced before settlement (partial settlement for upto scheme). +// SettlePayment settles a V2 payment with no declared extensions. +// Equivalent to SettlePaymentWithExtensions(ctx, payload, requirements, overrides, nil). func (s *x402ResourceServer) SettlePayment(ctx context.Context, payload types.PaymentPayload, requirements types.PaymentRequirements, overrides *SettlementOverrides) (*SettleResponse, error) { + return s.SettlePaymentWithExtensions(ctx, payload, requirements, overrides, nil) +} + +// SettlePaymentWithExtensions settles a V2 payment, gating extension hooks on +// the supplied `declaredExtensions` map (keys must be present for the +// extension's hook to fire). Hook execution order: manual → matched scheme → +// declared extensions. Mirrors TS `settlePayment(payload, requirements, +// overrides, declaredExtensions)`. +// +// If overrides is non-nil and overrides.Amount is set, the effective +// requirements amount is replaced before settlement (partial settlement for +// upto scheme). +func (s *x402ResourceServer) SettlePaymentWithExtensions( + ctx context.Context, + payload types.PaymentPayload, + requirements types.PaymentRequirements, + overrides *SettlementOverrides, + declaredExtensions map[string]interface{}, +) (*SettleResponse, error) { effectiveRequirements := requirements if overrides != nil && overrides.Amount != "" { decimals := 6 @@ -481,44 +853,94 @@ func (s *x402ResourceServer) SettlePayment(ctx context.Context, payload types.Pa return nil, NewSettleError("failed_to_marshal_requirements", "", Network(effectiveRequirements.Network), "", err.Error()) } - // Execute beforeSettle hooks hookCtx := SettleContext{ - Ctx: ctx, - Payload: payload, - Requirements: effectiveRequirements, - PayloadBytes: payloadBytes, - RequirementsBytes: requirementsBytes, + Ctx: ctx, + Payload: payload, + Requirements: effectiveRequirements, + DeclaredExtensions: declaredExtensions, + PayloadBytes: payloadBytes, + RequirementsBytes: requirementsBytes, } - for _, hook := range s.beforeSettleHooks { - result, err := hook(hookCtx) + s.mu.RLock() + scheme := effectiveRequirements.Scheme + network := Network(effectiveRequirements.Network) + matchedScheme := s.matchedSchemeHooks(network, scheme) + beforeSettleHooks := orderedHooks(s, "beforeSettle", s.beforeSettleHooks, matchedScheme, + declaredExtensions, func(h *hookAdapterHandles) BeforeSettleHook { return h.BeforeSettle }, + func(f BeforeSettleHook) bool { return f == nil }) + afterSettleHooks := orderedHooks(s, "afterSettle", s.afterSettleHooks, matchedScheme, + declaredExtensions, func(h *hookAdapterHandles) AfterSettleHook { return h.AfterSettle }, + func(f AfterSettleHook) bool { return f == nil }) + settleFailureHooks := orderedHooks(s, "onSettleFailure", s.onSettleFailureHooks, matchedScheme, + declaredExtensions, func(h *hookAdapterHandles) OnSettleFailureHook { return h.OnSettleFailure }, + func(f OnSettleFailureHook) bool { return f == nil }) + facilitator := s.facilitatorClients[network][scheme] + s.mu.RUnlock() + + for _, lh := range beforeSettleHooks { + result, err := lh.Hook(hookCtx) if err != nil { return nil, err } - if result != nil && result.Abort { - return nil, NewSettleError(result.Reason, "", Network(effectiveRequirements.Network), "", "") + if result != nil { + if result.Abort { + return nil, NewSettleError(result.Reason, "", Network(effectiveRequirements.Network), "", result.Message) + } + if result.Skip && result.SkipResult != nil { + // Execute afterSettle hooks even when skipping + skipResultCtx := SettleResultContext{SettleContext: hookCtx, Result: result.SkipResult} + for _, ah := range afterSettleHooks { + _ = ah.Hook(skipResultCtx) + } + return result.SkipResult, nil + } } } + // Scheme-level settlement-payload enrichment. Mirrors TS + // `enrichSettlementPayload`: schemes return additive fields that the + // framework merges into payload.Payload after the additive policy has + // rejected any attempt to overwrite existing keys. s.mu.RLock() - scheme := effectiveRequirements.Scheme - network := Network(effectiveRequirements.Network) - - facilitator := s.facilitatorClients[network][scheme] + matchedSchemeServer := s.schemes[network][scheme] s.mu.RUnlock() + if enricher, ok := matchedSchemeServer.(EnrichSettlementPayloadProvider); ok { + enrichment, err := enricher.EnrichSettlementPayload(hookCtx) + if err != nil { + return nil, NewSettleError("scheme_enrich_settlement_payload_failed", "", network, "", err.Error()) + } + if len(enrichment) > 0 { + rawPayload := payload.GetPayload() + if err := AssertAdditivePayloadEnrichment(rawPayload, enrichment, fmt.Sprintf(`scheme %q`, scheme)); err != nil { + return nil, NewSettleError("scheme_enrich_settlement_payload_policy_violation", "", network, "", err.Error()) + } + for k, v := range enrichment { + rawPayload[k] = v + } + } + } if facilitator == nil { - return nil, NewSettleError("no_facilitator", "", network, "", fmt.Sprintf("no facilitator for %s on %s", scheme, network)) + return nil, NewSettleError("no_facilitator", "", network, "", fmt.Sprintf("no facilitator for scheme=%q network=%q", scheme, network)) + } + + // Re-marshal payload after hooks: BeforeSettle hooks AND scheme enrichment + // may have mutated payload.Payload (e.g., the batch-settlement refund + // enrich path adds the refund authorizer signatures). The pre-hook bytes + // would carry the original shape and the facilitator would reject it. + payloadBytes, err = json.Marshal(payload) + if err != nil { + return nil, NewSettleError("failed_to_marshal_payload", "", Network(effectiveRequirements.Network), "", err.Error()) } - // Use already marshaled bytes for network call settleResult, settleErr := facilitator.Settle(ctx, payloadBytes, requirementsBytes) // Handle failure if settleErr != nil { failureCtx := SettleFailureContext{SettleContext: hookCtx, Error: settleErr} - for _, hook := range s.onSettleFailureHooks { - result, _ := hook(failureCtx) + for _, lh := range settleFailureHooks { + result, _ := lh.Hook(failureCtx) if result != nil && result.Recovered { return result.Result, nil } @@ -528,8 +950,29 @@ func (s *x402ResourceServer) SettlePayment(ctx context.Context, payload types.Pa // Execute afterSettle hooks resultCtx := SettleResultContext{SettleContext: hookCtx, Result: settleResult} - for _, hook := range s.afterSettleHooks { - _ = hook(resultCtx) // Log errors but don't fail + for _, lh := range afterSettleHooks { + _ = lh.Hook(resultCtx) // Log errors but don't fail + } + + // Scheme-level settlement-response enrichment. Mirrors TS + // `enrichSettlementResponse`: returned fields are deep-merged into + // settleResult.Extra after the additive policy has rejected any attempt + // to overwrite existing extras (recursively for nested maps). + if enricher, ok := matchedSchemeServer.(EnrichSettlementResponseProvider); ok { + enrichment, err := enricher.EnrichSettlementResponse(resultCtx) + if err != nil { + return settleResult, NewSettleError("scheme_enrich_settlement_response_failed", "", network, "", err.Error()) + } + if len(enrichment) > 0 { + extra := settleResult.Extra + if extra == nil { + extra = map[string]interface{}{} + } + if err := AssertAdditiveSettlementExtra(extra, enrichment, fmt.Sprintf(`scheme %q`, scheme)); err != nil { + return settleResult, NewSettleError("scheme_enrich_settlement_response_policy_violation", "", network, "", err.Error()) + } + settleResult.Extra = MergeAdditiveSettlementExtra(extra, enrichment) + } } return settleResult, nil @@ -555,20 +998,65 @@ func (s *x402ResourceServer) EnrichExtensions( return enriched } -// CreatePaymentRequiredResponse creates a V2 PaymentRequired response +// CreatePaymentRequiredResponse creates a V2 PaymentRequired response. +// Equivalent to CreatePaymentRequiredResponseWithPayload with a nil payload — +// scheme enrichers that depend on the failed payload (e.g. batched corrective +// ChannelState) become no-ops. func (s *x402ResourceServer) CreatePaymentRequiredResponse( requirements []types.PaymentRequirements, resourceInfo *types.ResourceInfo, errorMsg string, extensions map[string]interface{}, ) types.PaymentRequired { - return types.PaymentRequired{ + return s.CreatePaymentRequiredResponseWithPayload(requirements, resourceInfo, errorMsg, extensions, nil) +} + +// CreatePaymentRequiredResponseWithPayload creates a V2 PaymentRequired response +// and runs each registered scheme's PaymentRequiredEnricher (when implemented). +// Pass the failing payment payload on the verify-failure branch so per-scheme +// enrichers can attach corrective recovery state (e.g. batched ChannelState) +// to matching requirements; pass nil otherwise. +func (s *x402ResourceServer) CreatePaymentRequiredResponseWithPayload( + requirements []types.PaymentRequirements, + resourceInfo *types.ResourceInfo, + errorMsg string, + extensions map[string]interface{}, + paymentPayload *types.PaymentPayload, +) types.PaymentRequired { + response := types.PaymentRequired{ X402Version: 2, Error: errorMsg, Resource: resourceInfo, Accepts: requirements, Extensions: extensions, } + + s.mu.RLock() + defer s.mu.RUnlock() + + for i := range requirements { + networkSchemes, ok := s.schemes[Network(requirements[i].Network)] + if !ok { + continue + } + scheme, ok := networkSchemes[requirements[i].Scheme] + if !ok { + continue + } + enricher, ok := scheme.(PaymentRequiredEnricher) + if !ok { + continue + } + enricher.EnrichPaymentRequiredResponse(PaymentRequiredContext{ + Requirements: requirements, + PaymentPayload: paymentPayload, + ResourceInfo: resourceInfo, + Error: errorMsg, + PaymentRequiredResponse: &response, + }) + } + + return response } // ProcessPaymentRequest processes a payment request end-to-end diff --git a/go/server_hook_policy.go b/go/server_hook_policy.go new file mode 100644 index 0000000000..69560024a6 --- /dev/null +++ b/go/server_hook_policy.go @@ -0,0 +1,283 @@ +package x402 + +import ( + "fmt" + "reflect" + "strings" + + "github.com/x402-foundation/x402/go/types" +) + +// ============================================================================ +// Hook Mutation Policy Guards +// ============================================================================ +// +// These helpers enforce hook-context immutability at runtime: extensions and +// schemes are free to inspect everything but allowed to mutate only specific +// fields. The framework snapshots the affected structures before invoking a +// hook and asserts the diff afterwards. +// +// Violations panic-via-error rather than silently corrupting downstream +// state — catching policy bugs at the point of misuse. + +// IsVacantStringField reports whether a string field is treated as unset +// and may be filled by `enrichPaymentRequiredResponse`. +func IsVacantStringField(value string) bool { + return strings.TrimSpace(value) == "" +} + +// SnapshotPaymentRequirementsList deep-clones `requirements` so the result +// can serve as an immutable baseline for policy checks. +func SnapshotPaymentRequirementsList(requirements []types.PaymentRequirements) []types.PaymentRequirements { + if requirements == nil { + return nil + } + out := make([]types.PaymentRequirements, len(requirements)) + for i, req := range requirements { + clone := req + clone.Extra = cloneStringAnyMap(req.Extra) + out[i] = clone + } + return out +} + +// AssertAcceptsAllowlistedAfterExtensionEnrich enforces the extension-side +// `enrichPaymentRequiredResponse` mutation policy: extensions may fill vacant +// `payTo` / `amount` / `asset` and add new `extra` keys; everything else is +// immutable. +func AssertAcceptsAllowlistedAfterExtensionEnrich( + baseline, current []types.PaymentRequirements, + extensionKey string, +) error { + if len(baseline) != len(current) { + return fmt.Errorf(`[x402] extension %q violated accepts mutation policy: accepts length changed (%d → %d)`, + extensionKey, len(baseline), len(current)) + } + for i := range baseline { + b := baseline[i] + c := current[i] + if b.Scheme != c.Scheme || b.Network != c.Network { + return fmt.Errorf(`[x402] extension %q violated accepts mutation policy: scheme/network are immutable (index %d)`, + extensionKey, i) + } + if b.MaxTimeoutSeconds != c.MaxTimeoutSeconds { + return fmt.Errorf(`[x402] extension %q violated accepts mutation policy: maxTimeoutSeconds is immutable (index %d)`, + extensionKey, i) + } + if !IsVacantStringField(b.PayTo) && b.PayTo != c.PayTo { + return fmt.Errorf(`[x402] extension %q violated accepts mutation policy: "payTo" may only be set when the resource left it vacant (""); non-vacant values are immutable (index %d)`, extensionKey, i) + } + if !IsVacantStringField(b.Amount) && b.Amount != c.Amount { + return fmt.Errorf(`[x402] extension %q violated accepts mutation policy: "amount" may only be set when the resource left it vacant (""); non-vacant values are immutable (index %d)`, extensionKey, i) + } + if !IsVacantStringField(b.Asset) && b.Asset != c.Asset { + return fmt.Errorf(`[x402] extension %q violated accepts mutation policy: "asset" may only be set when the resource left it vacant (""); non-vacant values are immutable (index %d)`, extensionKey, i) + } + for key, bv := range b.Extra { + cv, ok := c.Extra[key] + if !ok { + return fmt.Errorf(`[x402] extension %q violated accepts mutation policy: extra[%q] was removed (index %d)`, + extensionKey, key, i) + } + if !reflect.DeepEqual(cv, bv) { + return fmt.Errorf(`[x402] extension %q violated accepts mutation policy: extra[%q] may not be changed (index %d)`, + extensionKey, key, i) + } + } + } + return nil +} + +// AssertAcceptsAdditiveExtraAfterSchemeEnrich enforces the scheme-side +// `enrichPaymentRequiredResponse` policy: schemes may only ADD new `extra` +// keys to the matching accept entry; payment terms (payTo / amount / asset / +// maxTimeoutSeconds) and scheme/network are immutable; non-matching accepts +// must be untouched. +func AssertAcceptsAdditiveExtraAfterSchemeEnrich( + baseline, current []types.PaymentRequirements, + scheme, network string, +) error { + if len(baseline) != len(current) { + return fmt.Errorf(`[x402] scheme %q violated accepts mutation policy: accepts length changed (%d → %d)`, + scheme, len(baseline), len(current)) + } + for i := range baseline { + b := baseline[i] + c := current[i] + isMatchingAccept := b.Scheme == scheme && b.Network == network + if b.Scheme != c.Scheme || b.Network != c.Network { + return fmt.Errorf(`[x402] scheme %q violated accepts mutation policy: scheme/network are immutable (index %d)`, scheme, i) + } + if b.MaxTimeoutSeconds != c.MaxTimeoutSeconds || b.PayTo != c.PayTo || b.Amount != c.Amount || b.Asset != c.Asset { + return fmt.Errorf(`[x402] scheme %q violated accepts mutation policy: payment terms are immutable (index %d)`, scheme, i) + } + for key, bv := range b.Extra { + cv, ok := c.Extra[key] + if !ok { + return fmt.Errorf(`[x402] scheme %q violated accepts mutation policy: extra[%q] was removed (index %d)`, scheme, key, i) + } + if !reflect.DeepEqual(cv, bv) { + return fmt.Errorf(`[x402] scheme %q violated accepts mutation policy: extra[%q] may not be changed (index %d)`, scheme, key, i) + } + } + if !isMatchingAccept && len(c.Extra) != len(b.Extra) { + return fmt.Errorf(`[x402] scheme %q violated accepts mutation policy: only matching accepts may receive new extra fields (index %d)`, scheme, i) + } + } + return nil +} + +// SettleResponseCoreSnapshot captures facilitator-settled fields that +// extensions must not rewrite. +type SettleResponseCoreSnapshot struct { + Success bool + Transaction string + Network Network + Amount string + Payer string + ErrorReason string + ErrorMessage string +} + +// SnapshotSettleResponseCore captures facilitator-settled fields. +func SnapshotSettleResponseCore(result *SettleResponse) SettleResponseCoreSnapshot { + if result == nil { + return SettleResponseCoreSnapshot{} + } + return SettleResponseCoreSnapshot{ + Success: result.Success, + Transaction: result.Transaction, + Network: result.Network, + Amount: result.Amount, + Payer: result.Payer, + ErrorReason: result.ErrorReason, + ErrorMessage: result.ErrorMessage, + } +} + +// AssertSettleResponseCoreUnchanged enforces that an extension did not +// rewrite facilitator outcome fields. +func AssertSettleResponseCoreUnchanged(before SettleResponseCoreSnapshot, after *SettleResponse, extensionKey string) error { + if after == nil { + return fmt.Errorf(`[x402] extension %q violated settlement mutation policy: settle result became nil`, extensionKey) + } + if after.Success != before.Success { + return fmt.Errorf(`[x402] extension %q violated settlement mutation policy: field "success" is immutable after facilitator settle`, extensionKey) + } + if after.Transaction != before.Transaction { + return fmt.Errorf(`[x402] extension %q violated settlement mutation policy: field "transaction" is immutable after facilitator settle`, extensionKey) + } + if after.Network != before.Network { + return fmt.Errorf(`[x402] extension %q violated settlement mutation policy: field "network" is immutable after facilitator settle`, extensionKey) + } + if after.Amount != before.Amount { + return fmt.Errorf(`[x402] extension %q violated settlement mutation policy: field "amount" is immutable after facilitator settle`, extensionKey) + } + if after.Payer != before.Payer { + return fmt.Errorf(`[x402] extension %q violated settlement mutation policy: field "payer" is immutable after facilitator settle`, extensionKey) + } + if after.ErrorReason != before.ErrorReason { + return fmt.Errorf(`[x402] extension %q violated settlement mutation policy: field "errorReason" is immutable after facilitator settle`, extensionKey) + } + if after.ErrorMessage != before.ErrorMessage { + return fmt.Errorf(`[x402] extension %q violated settlement mutation policy: field "errorMessage" is immutable after facilitator settle`, extensionKey) + } + return nil +} + +// AssertAdditivePayloadEnrichment ensures a scheme's +// `EnrichSettlementPayload` only ADDS new keys to the existing payload. +func AssertAdditivePayloadEnrichment(payload, enrichment map[string]interface{}, callerLabel string) error { + for key := range enrichment { + if _, exists := payload[key]; exists { + return fmt.Errorf(`[x402] %s violated settlement payload enrichment policy: %q already exists on the client payload`, callerLabel, key) + } + } + return nil +} + +// AssertAdditiveSettlementExtra ensures a scheme's +// `EnrichSettlementResponse` only ADDS new fields to the response extra, +// recursively for nested plain objects. +func AssertAdditiveSettlementExtra(extra, enrichment map[string]interface{}, callerLabel string) error { + return assertAdditiveRecord(extra, enrichment, callerLabel, "extra") +} + +// MergeAdditiveSettlementExtra deep-merges `enrichment` into `extra` after +// the additive policy has been validated. +func MergeAdditiveSettlementExtra(extra, enrichment map[string]interface{}) map[string]interface{} { + return mergeAdditiveRecord(extra, enrichment) +} + +// ----- internal helpers ----- + +func cloneStringAnyMap(m map[string]interface{}) map[string]interface{} { + if m == nil { + return nil + } + out := make(map[string]interface{}, len(m)) + for k, v := range m { + out[k] = deepCloneAny(v) + } + return out +} + +func deepCloneAny(v interface{}) interface{} { + switch t := v.(type) { + case map[string]interface{}: + return cloneStringAnyMap(t) + case []interface{}: + out := make([]interface{}, len(t)) + for i, item := range t { + out[i] = deepCloneAny(item) + } + return out + default: + return v + } +} + +func isPlainRecord(v interface{}) (map[string]interface{}, bool) { + m, ok := v.(map[string]interface{}) + return m, ok +} + +func assertAdditiveRecord(target, enrichment map[string]interface{}, callerLabel, path string) error { + for key, enrichmentValue := range enrichment { + nextPath := fmt.Sprintf("%s[%q]", path, key) + targetValue, exists := target[key] + if !exists { + continue + } + targetMap, targetIsRecord := isPlainRecord(targetValue) + enrichmentMap, enrichmentIsRecord := isPlainRecord(enrichmentValue) + if targetIsRecord && enrichmentIsRecord { + if err := assertAdditiveRecord(targetMap, enrichmentMap, callerLabel, nextPath); err != nil { + return err + } + continue + } + return fmt.Errorf(`[x402] %s violated settlement response enrichment policy: %s already exists on the settlement result`, callerLabel, nextPath) + } + return nil +} + +func mergeAdditiveRecord(target, enrichment map[string]interface{}) map[string]interface{} { + merged := make(map[string]interface{}, len(target)+len(enrichment)) + for k, v := range target { + merged[k] = v + } + for key, enrichmentValue := range enrichment { + targetValue, exists := merged[key] + if exists { + if targetMap, ok := isPlainRecord(targetValue); ok { + if enrichmentMap, ok := isPlainRecord(enrichmentValue); ok { + merged[key] = mergeAdditiveRecord(targetMap, enrichmentMap) + continue + } + } + } + merged[key] = enrichmentValue + } + return merged +} diff --git a/go/server_hooks.go b/go/server_hooks.go index 75e8b62e98..429a1c4a73 100644 --- a/go/server_hooks.go +++ b/go/server_hooks.go @@ -2,6 +2,7 @@ package x402 import ( "context" + "sync" ) // ============================================================================ @@ -12,11 +13,15 @@ import ( // Uses view interfaces for version-agnostic hooks // PayloadBytes and RequirementsBytes provide escape hatch for extensions (e.g., Bazaar) type VerifyContext struct { - Ctx context.Context - Payload PaymentPayloadView - Requirements PaymentRequirementsView - PayloadBytes []byte // Raw bytes for extensions needing full data - RequirementsBytes []byte // Raw bytes for extensions needing full data + Ctx context.Context + Payload PaymentPayloadView + Requirements PaymentRequirementsView + // DeclaredExtensions carries the extension declarations attached to the + // route. Extension hooks gate on `DeclaredExtensions[extKey]` being set + // before firing — mirrors TS `ctx.declaredExtensions[extensionKey]`. + DeclaredExtensions map[string]interface{} + PayloadBytes []byte // Raw bytes for extensions needing full data + RequirementsBytes []byte // Raw bytes for extensions needing full data } // VerifyResultContext contains verify operation result and context @@ -31,15 +36,36 @@ type VerifyFailureContext struct { Error error } +// SkipHandlerDirective is an optional acknowledgement body returned to the caller +// when an AfterVerifyHook requests that the resource handler be skipped for a +// self-contained operation. Travels in-process only — +// never on the facilitator wire. +type SkipHandlerDirective struct { + ContentType string + Body interface{} +} + +// AfterVerifyResult is the optional return value of an AfterVerifyHook. +// When SkipHandler is true, the resource handler is bypassed and settlement is +// performed inline; the optional Response is used to craft the success body. +type AfterVerifyResult struct { + SkipHandler bool + Response *SkipHandlerDirective +} + // SettleContext contains information passed to settle hooks // Uses view interfaces for version-agnostic hooks // PayloadBytes and RequirementsBytes provide escape hatch for extensions (e.g., Bazaar) type SettleContext struct { - Ctx context.Context - Payload PaymentPayloadView - Requirements PaymentRequirementsView - PayloadBytes []byte // Raw bytes for extensions needing full data - RequirementsBytes []byte // Raw bytes for extensions needing full data + Ctx context.Context + Payload PaymentPayloadView + Requirements PaymentRequirementsView + // DeclaredExtensions carries the extension declarations attached to the + // route. Extension hooks gate on `DeclaredExtensions[extKey]` being set + // before firing — mirrors TS `ctx.declaredExtensions[extensionKey]`. + DeclaredExtensions map[string]interface{} + PayloadBytes []byte // Raw bytes for extensions needing full data + RequirementsBytes []byte // Raw bytes for extensions needing full data } // SettleResultContext contains settle operation result and context @@ -54,16 +80,66 @@ type SettleFailureContext struct { Error error } +// VerifiedPaymentCancellationReason describes why a verified payment is being canceled +// before settlement runs. Mirrors TS `VerifiedPaymentCancellationReason`. +type VerifiedPaymentCancellationReason string + +const ( + // CancellationReasonHandlerThrew indicates the resource handler panicked or returned an error. + CancellationReasonHandlerThrew VerifiedPaymentCancellationReason = "handler_threw" + // CancellationReasonHandlerFailed indicates the resource handler completed but with a failing + // response status (>= 400). + CancellationReasonHandlerFailed VerifiedPaymentCancellationReason = "handler_failed" +) + +// VerifiedPaymentCanceledContext is delivered to OnVerifiedPaymentCanceled hooks when a +// verified payment is canceled before settlement. +type VerifiedPaymentCanceledContext struct { + SettleContext + Reason VerifiedPaymentCancellationReason + Err error + ResponseStatus int +} + +// VerifiedPaymentCancelOptions describes a single cancellation event. +type VerifiedPaymentCancelOptions struct { + Reason VerifiedPaymentCancellationReason + Err error + ResponseStatus int +} + +// PaymentCancellationDispatcher fires onVerifiedPaymentCanceled hooks at most once. +type PaymentCancellationDispatcher struct { + once sync.Once + fire func(VerifiedPaymentCancelOptions) +} + +// Cancel fires the underlying hooks. Safe to call multiple times — only the first call wins. +func (d *PaymentCancellationDispatcher) Cancel(opts VerifiedPaymentCancelOptions) { + if d == nil || d.fire == nil { + return + } + d.once.Do(func() { d.fire(opts) }) +} + // ============================================================================ // Resource Server Hook Result Types // ============================================================================ -// BeforeHookResult represents the result of a "before" hook -// If Abort is true, the operation will be aborted with the given Reason +// BeforeHookResult represents the result of a "before" hook. +// If Abort is true, the operation will be aborted with the given Reason. +// If Skip is true, the operation will be short-circuited; the hook supplies +// either SkipResult (settle hooks) or SkipVerifyResult (verify hooks). The +// batched scheme uses this to handle voucher payloads without on-chain +// settlement and to short-circuit verification when local channel state is +// fresh enough to verify against. type BeforeHookResult struct { - Abort bool - Reason string - Message string + Abort bool + Reason string + Message string + Skip bool + SkipResult *SettleResponse + SkipVerifyResult *VerifyResponse } // VerifyFailureHookResult represents the result of a verify failure hook @@ -88,9 +164,12 @@ type SettleFailureHookResult struct { // and an invalid VerifyResponse will be returned with the provided reason type BeforeVerifyHook func(VerifyContext) (*BeforeHookResult, error) -// AfterVerifyHook is called after successful payment verification -// Any error returned will be logged but will not affect the verification result -type AfterVerifyHook func(VerifyResultContext) error +// AfterVerifyHook is called after successful payment verification. +// Any error returned will be logged but will not affect the verification result. +// Returning an AfterVerifyResult with SkipHandler=true signals the HTTP layer to +// bypass the resource handler and perform settlement inline (e.g. cooperative refund). +// The last hook to return a SkipHandler directive wins. +type AfterVerifyHook func(VerifyResultContext) (*AfterVerifyResult, error) // OnVerifyFailureHook is called when payment verification fails // If it returns a result with Recovered=true, the provided VerifyResponse @@ -111,6 +190,11 @@ type AfterSettleHook func(SettleResultContext) error // will be returned instead of the error type OnSettleFailureHook func(SettleFailureContext) (*SettleFailureHookResult, error) +// OnVerifiedPaymentCanceledHook is called when a verified payment is canceled +// before settlement runs (e.g. resource handler error or non-2xx response). +// Returned errors are logged but do not affect the response. +type OnVerifiedPaymentCanceledHook func(VerifiedPaymentCanceledContext) error + // ============================================================================ // Resource Server Hook Registration Options // ============================================================================ @@ -156,3 +240,127 @@ func WithOnSettleFailureHook(hook OnSettleFailureHook) ResourceServerOption { s.onSettleFailureHooks = append(s.onSettleFailureHooks, hook) } } + +// WithOnVerifiedPaymentCanceledHook registers a hook fired when a verified payment +// is canceled before settlement (handler error or non-2xx response). +func WithOnVerifiedPaymentCanceledHook(hook OnVerifiedPaymentCanceledHook) ResourceServerOption { + return func(s *x402ResourceServer) { + s.onVerifiedPaymentCanceledHooks = append(s.onVerifiedPaymentCanceledHooks, hook) + } +} + +// ============================================================================ +// Scheme-Provided Hook Provider Interfaces (Auto-Wiring) +// ============================================================================ +// +// SchemeNetworkServer implementations may optionally satisfy these interfaces to +// have their lifecycle hooks auto-registered when the scheme is registered with +// an x402ResourceServer (mirrors the TS schemeHooks field). User code does not +// need to call OnBeforeVerify / OnAfterVerify / OnBeforeSettle / OnAfterSettle / +// OnVerifiedPaymentCanceled manually — Register inspects the scheme via type +// assertion and wires hooks automatically. + +// BeforeVerifyHookProvider is implemented by schemes that contribute a +// BeforeVerifyHook to the resource server's lifecycle pipeline. +type BeforeVerifyHookProvider interface { + BeforeVerifyHook() BeforeVerifyHook +} + +// AfterVerifyHookProvider is implemented by schemes that contribute an +// AfterVerifyHook to the resource server's lifecycle pipeline. +type AfterVerifyHookProvider interface { + AfterVerifyHook() AfterVerifyHook +} + +// OnVerifyFailureHookProvider is implemented by schemes that contribute an +// OnVerifyFailureHook to the resource server's lifecycle pipeline. +type OnVerifyFailureHookProvider interface { + OnVerifyFailureHook() OnVerifyFailureHook +} + +// BeforeSettleHookProvider is implemented by schemes that contribute a +// BeforeSettleHook to the resource server's lifecycle pipeline. +type BeforeSettleHookProvider interface { + BeforeSettleHook() BeforeSettleHook +} + +// AfterSettleHookProvider is implemented by schemes that contribute an +// AfterSettleHook to the resource server's lifecycle pipeline. +type AfterSettleHookProvider interface { + AfterSettleHook() AfterSettleHook +} + +// OnSettleFailureHookProvider is implemented by schemes that contribute an +// OnSettleFailureHook to the resource server's lifecycle pipeline. +type OnSettleFailureHookProvider interface { + OnSettleFailureHook() OnSettleFailureHook +} + +// OnVerifiedPaymentCanceledHookProvider is implemented by schemes that contribute +// an OnVerifiedPaymentCanceledHook to the resource server's lifecycle pipeline. +type OnVerifiedPaymentCanceledHookProvider interface { + OnVerifiedPaymentCanceledHook() OnVerifiedPaymentCanceledHook +} + +// ============================================================================ +// Scheme-Level Enrichment Hook Provider Interfaces +// ============================================================================ +// +// These complement the lifecycle hooks above. A scheme exposes them when it +// needs to enrich settlement payload (pre-facilitator) or settlement +// response (post-facilitator) with server-owned fields. Mirrors TS +// `enrichSettlementPayload` / `enrichSettlementResponse` on +// `BatchSettlementEvmScheme`. Returned maps are merged ADDITIVELY — the +// framework rejects any attempt to overwrite existing fields via +// AssertAdditivePayloadEnrichment / AssertAdditiveSettlementExtra. + +// EnrichSettlementPayloadProvider is implemented by schemes that need to +// add server-owned fields to the payment payload before the facilitator +// settles. Return nil/empty for no-op. The framework asserts the result is +// additive (no existing payload key may be present in the returned map) +// before merging. +type EnrichSettlementPayloadProvider interface { + EnrichSettlementPayload(ctx SettleContext) (map[string]interface{}, error) +} + +// EnrichSettlementResponseProvider is implemented by schemes that need to +// add server-owned fields to the facilitator's settle response `extra`. +// Return nil/empty for no-op. The framework asserts the result is additive +// (no existing extra key may be present in the returned map, recursively +// for nested maps) before deep-merging. +type EnrichSettlementResponseProvider interface { + EnrichSettlementResponse(ctx SettleResultContext) (map[string]interface{}, error) +} + +// ============================================================================ +// Extension Hook Provider Interfaces +// ============================================================================ +// +// ResourceServerExtension implementations may also satisfy the per-phase hook +// provider interfaces below to install hooks that fire ONLY when the +// extension key is present in the request's `declaredExtensions` map. This +// matches TS `ResourceServerExtensionHooks` — hooks gate on +// `ctx.declaredExtensions[extensionKey] !== undefined`. +// +// Hooks registered this way run AFTER manual hooks and the matched scheme's +// hook for the same phase (mirrors TS hook ordering). + +// ResourceServerExtensionHookProvider lets an extension expose any subset of +// the seven lifecycle hooks. Returning nil from any phase means "no hook +// for that phase" — the server skips it. +type ResourceServerExtensionHookProvider interface { + ResourceServerExtensionHooks() ResourceServerExtensionHooks +} + +// ResourceServerExtensionHooks is an extension's optional bundle of +// lifecycle hooks. Mirrors the TS `ResourceServerExtensionHooks` interface +// shape — fields left nil mean "no hook for that phase". +type ResourceServerExtensionHooks struct { + OnBeforeVerify BeforeVerifyHook + OnAfterVerify AfterVerifyHook + OnVerifyFailure OnVerifyFailureHook + OnBeforeSettle BeforeSettleHook + OnAfterSettle AfterSettleHook + OnSettleFailure OnSettleFailureHook + OnVerifiedPaymentCanceled OnVerifiedPaymentCanceledHook +} diff --git a/go/server_hooks_test.go b/go/server_hooks_test.go index 9e18bdc42c..d109d62a41 100644 --- a/go/server_hooks_test.go +++ b/go/server_hooks_test.go @@ -5,7 +5,7 @@ import ( "errors" "testing" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // Mock facilitator client for testing @@ -123,9 +123,9 @@ func TestAfterVerifyHook(t *testing.T) { server := Newx402ResourceServer() // Register hook to capture result - server.OnAfterVerify(func(ctx VerifyResultContext) error { + server.OnAfterVerify(func(ctx VerifyResultContext) (*AfterVerifyResult, error) { capturedResult = ctx.Result - return nil + return nil, nil }) // Mock facilitator that returns success @@ -416,14 +416,14 @@ func TestMultipleHooks_ExecutionOrder(t *testing.T) { return nil, nil }) - server.OnAfterVerify(func(ctx VerifyResultContext) error { + server.OnAfterVerify(func(ctx VerifyResultContext) (*AfterVerifyResult, error) { executionOrder = append(executionOrder, "after1") - return nil + return nil, nil }) - server.OnAfterVerify(func(ctx VerifyResultContext) error { + server.OnAfterVerify(func(ctx VerifyResultContext) (*AfterVerifyResult, error) { executionOrder = append(executionOrder, "after2") - return nil + return nil, nil }) // Mock facilitator diff --git a/go/server_test.go b/go/server_test.go index f1da18f4bf..07dbe62d7a 100644 --- a/go/server_test.go +++ b/go/server_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // Mock server for testing @@ -345,6 +345,80 @@ func TestServerCreatePaymentRequiredResponse(t *testing.T) { } } +// stubEnricherScheme records EnrichPaymentRequiredResponse calls and mutates +// the matching requirement's Extra to verify core wiring. +type stubEnricherScheme struct { + calls int + lastErrorReason string + lastPayload *types.PaymentPayload +} + +func (s *stubEnricherScheme) Scheme() string { return "stub-enricher" } +func (s *stubEnricherScheme) ParsePrice(_ Price, _ Network) (AssetAmount, error) { + return AssetAmount{}, nil +} +func (s *stubEnricherScheme) EnhancePaymentRequirements( + _ context.Context, + r types.PaymentRequirements, + _ types.SupportedKind, + _ []string, +) (types.PaymentRequirements, error) { + return r, nil +} +func (s *stubEnricherScheme) EnrichPaymentRequiredResponse(ctx PaymentRequiredContext) { + s.calls++ + s.lastErrorReason = ctx.Error + s.lastPayload = ctx.PaymentPayload + for i := range ctx.Requirements { + if ctx.Requirements[i].Scheme != "stub-enricher" { + continue + } + if ctx.Requirements[i].Extra == nil { + ctx.Requirements[i].Extra = map[string]interface{}{} + } + ctx.Requirements[i].Extra["EnrichedBy"] = "stub-enricher" + } +} + +func TestCreatePaymentRequiredResponse_InvokesEnricher(t *testing.T) { + server := Newx402ResourceServer() + enricher := &stubEnricherScheme{} + server.Register(Network("eip155:1"), enricher) + + pp := &types.PaymentPayload{X402Version: 2} + requirements := []types.PaymentRequirements{ + {Scheme: "stub-enricher", Network: "eip155:1", Asset: "USDC", Amount: "1"}, + } + resp := server.CreatePaymentRequiredResponseWithPayload( + requirements, &types.ResourceInfo{URL: "https://x"}, "some_error", nil, pp, + ) + + if enricher.calls != 1 { + t.Fatalf("expected 1 enricher call, got %d", enricher.calls) + } + if enricher.lastErrorReason != "some_error" { + t.Fatalf("unexpected error reason: %q", enricher.lastErrorReason) + } + if enricher.lastPayload != pp { + t.Fatalf("expected payload to flow through") + } + if resp.Accepts[0].Extra["EnrichedBy"] != "stub-enricher" { + t.Fatalf("expected enrichment mutation, got %+v", resp.Accepts[0].Extra) + } +} + +func TestCreatePaymentRequiredResponse_NoEnricherForUnknownScheme(t *testing.T) { + server := Newx402ResourceServer() + requirements := []types.PaymentRequirements{ + {Scheme: "unknown", Network: "eip155:1"}, + } + // Must not panic and must return baseline response. + resp := server.CreatePaymentRequiredResponse(requirements, nil, "err", nil) + if len(resp.Accepts) != 1 { + t.Fatalf("expected requirements untouched") + } +} + func TestServerVerifyPayment(t *testing.T) { ctx := context.Background() @@ -571,8 +645,6 @@ func TestServerProcessPaymentRequest(t *testing.T) { } */ -// TestSupportedCache - SKIPPED: Cache.Clear method not implemented -/* func TestSupportedCache(t *testing.T) { cache := &SupportedCache{ data: make(map[string]SupportedResponse), @@ -588,16 +660,22 @@ func TestSupportedCache(t *testing.T) { Signers: make(map[string][]string), } - // Set and verify + // Set stores the value. cache.Set("test", response) if len(cache.data) != 1 { t.Fatal("Expected item in cache") } - // Wait for expiry - time.Sleep(150 * time.Millisecond) + // Get returns the stored value before expiry. + cached, ok := cache.Get("test") + if !ok { + t.Fatal("Expected cached item to be found") + } + if len(cached.Kinds) != 1 || cached.Kinds[0].Scheme != "exact" || cached.Kinds[0].Network != "eip155:1" { + t.Fatalf("Expected cached response to match stored value, got %+v", cached) + } - // Clear cache + // Clear removes all data and expiry state. cache.Clear() if len(cache.data) != 0 { t.Fatal("Expected cache to be cleared") @@ -605,8 +683,12 @@ func TestSupportedCache(t *testing.T) { if len(cache.expiry) != 0 { t.Fatal("Expected expiry map to be cleared") } + + // Get returns false after the cache is cleared. + if _, ok := cache.Get("test"); ok { + t.Fatal("Expected cache miss after Clear") + } } -*/ func TestResolveSettlementOverrideAmount(t *testing.T) { baseReqs := types.PaymentRequirements{ diff --git a/go/signers/README.md b/go/signers/README.md index 435a7559ce..50dc6cb305 100644 --- a/go/signers/README.md +++ b/go/signers/README.md @@ -144,7 +144,7 @@ signers/ ### EVM Client Signer ```go -import evmsigners "github.com/coinbase/x402/go/signers/evm" +import evmsigners "github.com/x402-foundation/x402/go/signers/evm" signer, _ := evmsigners.NewClientSignerFromPrivateKey("0x...") // Returns: mechanisms/evm.ClientEvmSigner implementation @@ -153,7 +153,7 @@ signer, _ := evmsigners.NewClientSignerFromPrivateKey("0x...") ### SVM Client Signer ```go -import svmsigners "github.com/coinbase/x402/go/signers/svm" +import svmsigners "github.com/x402-foundation/x402/go/signers/svm" signer, _ := svmsigners.NewClientSignerFromPrivateKey("5J...") // Returns: mechanisms/svm.ClientSvmSigner implementation diff --git a/go/signers/evm/README.md b/go/signers/evm/README.md index 7b97edd672..a487226d30 100644 --- a/go/signers/evm/README.md +++ b/go/signers/evm/README.md @@ -6,8 +6,8 @@ Client-side EIP-712 signing for Ethereum-based x402 payments. ```go import ( - evmclient "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmsigners "github.com/coinbase/x402/go/signers/evm" + evmclient "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) // Create signer from private key @@ -137,7 +137,7 @@ signer, _ := evmsigners.NewClientSignerFromPrivateKey("0x1234...") Run tests: ```bash -go test github.com/coinbase/x402/go/signers/evm -v +go test github.com/x402-foundation/x402/go/signers/evm -v ``` Use in your own tests: @@ -145,7 +145,7 @@ Use in your own tests: ```go import ( "testing" - evmsigners "github.com/coinbase/x402/go/signers/evm" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) func TestPayment(t *testing.T) { @@ -160,7 +160,7 @@ func TestPayment(t *testing.T) { ## Dependencies - `github.com/ethereum/go-ethereum` - Core Ethereum library -- `github.com/coinbase/x402/go/mechanisms/evm` - x402 EVM types +- `github.com/x402-foundation/x402/go/mechanisms/evm` - x402 EVM types ## Related diff --git a/go/signers/evm/client.go b/go/signers/evm/client.go index b5efdbcd43..8b534df232 100644 --- a/go/signers/evm/client.go +++ b/go/signers/evm/client.go @@ -16,7 +16,7 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/signer/core/apitypes" - x402evm "github.com/coinbase/x402/go/mechanisms/evm" + x402evm "github.com/x402-foundation/x402/go/mechanisms/evm" ) // ClientSigner implements x402evm.ClientEvmSigner using an ECDSA private key. @@ -125,14 +125,30 @@ func (s *ClientSigner) SignTypedData( typedData.Types[typeName] = typedFields } - // Add EIP712Domain type if not present + // Add EIP712Domain type if not present. + // + // Domain fields are conditionally declared based on which TypedDataDomain + // fields are populated. go-ethereum's `apitypes.TypedDataDomain.Map()` + // drops empty Name/Version/VerifyingContract and nil ChainID; if the type + // list still names them, `HashStruct("EIP712Domain", ...)` errors with + // "provided data '' doesn't match type 'string'" (Permit2's no-version + // domain is the canonical case). Mirrors viem's `getTypesForEIP712Domain` + // and the same fix applied to `go/mechanisms/evm/eip712.go`. if _, exists := typedData.Types["EIP712Domain"]; !exists { - typedData.Types["EIP712Domain"] = []apitypes.Type{ - {Name: "name", Type: "string"}, - {Name: "version", Type: "string"}, - {Name: "chainId", Type: "uint256"}, - {Name: "verifyingContract", Type: "address"}, + domainFields := make([]apitypes.Type, 0, 4) + if typedData.Domain.Name != "" { + domainFields = append(domainFields, apitypes.Type{Name: "name", Type: "string"}) } + if typedData.Domain.Version != "" { + domainFields = append(domainFields, apitypes.Type{Name: "version", Type: "string"}) + } + if typedData.Domain.ChainId != nil { + domainFields = append(domainFields, apitypes.Type{Name: "chainId", Type: "uint256"}) + } + if typedData.Domain.VerifyingContract != "" { + domainFields = append(domainFields, apitypes.Type{Name: "verifyingContract", Type: "address"}) + } + typedData.Types["EIP712Domain"] = domainFields } // Hash the struct data diff --git a/go/signers/evm/client_test.go b/go/signers/evm/client_test.go index 3b5c5d14af..a1b04f1e81 100644 --- a/go/signers/evm/client_test.go +++ b/go/signers/evm/client_test.go @@ -6,7 +6,7 @@ import ( "strings" "testing" - x402evm "github.com/coinbase/x402/go/mechanisms/evm" + x402evm "github.com/x402-foundation/x402/go/mechanisms/evm" ) // Test private key (deterministic for testing) @@ -198,6 +198,65 @@ func TestClientSigner_SignTypedData_WithEIP712DomainInTypes(t *testing.T) { } } +// TestClientSigner_SignTypedData_Permit2NoVersionDomain is a regression test +// for the EIP-712 domain hashing bug where the auto-injected EIP712Domain +// type unconditionally declared `version: string`. Permit2's domain has no +// version, so the typed-data domain map omits "version" and HashStruct then +// fails with "provided data '' doesn't match type 'string'". The fix +// dynamically constructs the EIP712Domain type list from the populated +// domain fields (matching viem's behavior). Mirrors the test in +// `go/mechanisms/evm/eip712_test.go`. +func TestClientSigner_SignTypedData_Permit2NoVersionDomain(t *testing.T) { + signer, err := NewClientSignerFromPrivateKey(testPrivateKeyHex) + if err != nil { + t.Fatalf("NewClientSignerFromPrivateKey() failed: %v", err) + } + + domain := x402evm.TypedDataDomain{ + Name: "Permit2", + ChainID: big.NewInt(84532), + VerifyingContract: "0x000000000022D473030F116dDEE9F6B43aC78BA3", + } + types := map[string][]x402evm.TypedDataField{ + "PermitWitnessTransferFrom": { + {Name: "permitted", Type: "TokenPermissions"}, + {Name: "spender", Type: "address"}, + {Name: "nonce", Type: "uint256"}, + {Name: "deadline", Type: "uint256"}, + {Name: "witness", Type: "Witness"}, + }, + "TokenPermissions": { + {Name: "token", Type: "address"}, + {Name: "amount", Type: "uint256"}, + }, + "Witness": { + {Name: "channelId", Type: "bytes32"}, + }, + } + channelId := make([]byte, 32) + channelId[31] = 0x01 + message := map[string]interface{}{ + "permitted": map[string]interface{}{ + "token": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + "amount": big.NewInt(1_000_000), + }, + "spender": "0x0000000000000000000000000000000000000001", + "nonce": big.NewInt(1), + "deadline": big.NewInt(1_000_000_000_000), + "witness": map[string]interface{}{ + "channelId": channelId, + }, + } + + signature, err := signer.SignTypedData(context.Background(), domain, types, "PermitWitnessTransferFrom", message) + if err != nil { + t.Fatalf("SignTypedData() with no-version domain failed: %v", err) + } + if len(signature) != 65 { + t.Errorf("signature length = %d, want 65", len(signature)) + } +} + // testRecovery verifies that a signature can be recovered to the expected address func testRecovery(t *testing.T, signature []byte, _ string, _ x402evm.TypedDataDomain, _ map[string][]x402evm.TypedDataField, _ map[string]interface{}) { // This would require implementing the full recovery logic diff --git a/go/signers/svm/README.md b/go/signers/svm/README.md index ed136d072b..b97191a216 100644 --- a/go/signers/svm/README.md +++ b/go/signers/svm/README.md @@ -6,8 +6,8 @@ Client-side Ed25519 signing for Solana-based x402 payments. ```go import ( - svmclient "github.com/coinbase/x402/go/mechanisms/svm/exact/client" - svmsigners "github.com/coinbase/x402/go/signers/svm" + svmclient "github.com/x402-foundation/x402/go/mechanisms/svm/exact/client" + svmsigners "github.com/x402-foundation/x402/go/signers/svm" ) // Create signer from private key @@ -166,7 +166,7 @@ signer, _ := svmsigners.NewClientSignerFromPrivateKey("4Z7cX...") Run tests: ```bash -go test github.com/coinbase/x402/go/signers/svm -v +go test github.com/x402-foundation/x402/go/signers/svm -v ``` Use in your own tests: @@ -174,7 +174,7 @@ Use in your own tests: ```go import ( "testing" - svmsigners "github.com/coinbase/x402/go/signers/svm" + svmsigners "github.com/x402-foundation/x402/go/signers/svm" ) func TestPayment(t *testing.T) { @@ -189,7 +189,7 @@ func TestPayment(t *testing.T) { ## Dependencies - `github.com/gagliardetto/solana-go` - Core Solana library -- `github.com/coinbase/x402/go/mechanisms/svm` - x402 SVM types +- `github.com/x402-foundation/x402/go/mechanisms/svm` - x402 SVM types ## Generating Test Keys diff --git a/go/signers/svm/client.go b/go/signers/svm/client.go index eb2022ed22..96858a7a53 100644 --- a/go/signers/svm/client.go +++ b/go/signers/svm/client.go @@ -6,7 +6,7 @@ import ( solana "github.com/gagliardetto/solana-go" - x402svm "github.com/coinbase/x402/go/mechanisms/svm" + x402svm "github.com/x402-foundation/x402/go/mechanisms/svm" ) // ClientSigner implements x402svm.ClientSvmSigner using an Ed25519 private key. diff --git a/go/test/integration/README.md b/go/test/integration/README.md index cc11986401..44a4dd76fc 100644 --- a/go/test/integration/README.md +++ b/go/test/integration/README.md @@ -14,6 +14,21 @@ These integration tests verify the complete x402 payment flows with real mechani - 🔐 **TestSVMIntegrationV2** - Full SVM V2 payment flow (Solana Devnet) - 🔐 **TestSVMIntegrationV1** - Full SVM V1 payment flow (Solana Devnet) +### Batch-Settlement (Batched) Integration Tests (Require Configuration) +EVM batched mechanism tests in `evm_batch_settlement_test.go`. All tests +issue **real Base Sepolia transactions** and skip when env vars are missing. + +- 🔐 **TestBatchSettlementIntegration_DepositThenVoucher** — direct API: deposit + follow-up voucher +- 🔐 **TestBatchSettlementIntegration_HTTPMiddleware** — full HTTP middleware end-to-end +- 🔐 **TestBatchSettlementIntegration_MultiVoucherClaimSettle** — 4 requests + manager.Claim + manager.Settle +- 🔐 **TestBatchSettlementIntegration_RefundPartial** — partial refund leaves channel open +- 🔐 **TestBatchSettlementIntegration_RefundDrainedChannelShortCircuit** — local short-circuit on drained channel +- 🔐 **TestBatchSettlementIntegration_RefundNonRecoverableFastFail** — `amount_exceeds_balance` errors immediately +- 🔐 **TestBatchSettlementIntegration_RefundRecoverableRetryExhaustion** — recoverable 402 → retry → exhaust +- 🔐 **TestBatchSettlementIntegration_AutoClaimTick** — `ClaimIntervalSecs` triggers OnClaim +- 🔐 **TestBatchSettlementIntegration_AutoClaimAndSettleTick** — both OnClaim and OnSettle fire +- 🔐 **TestBatchSettlementIntegration_WithdrawalPendingRefund** — pending-withdraw detection + manager.Refund + Tests marked with 🔐 require environment variables and will **skip** if not configured. ## Running Tests @@ -62,6 +77,10 @@ EVM_CLIENT_PRIVATE_KEY= EVM_FACILITATOR_PRIVATE_KEY= EVM_RESOURCE_SERVER_ADDRESS=<0x_ethereum_address> +# Batch-Settlement reuses the EVM_* keys above (EVM_RESOURCE_SERVER_ADDRESS is the payee) +EVM_AUTHORIZER_PRIVATE_KEY= # optional, defaults to EVM_FACILITATOR_PRIVATE_KEY +EVM_RPC_URL=https://sepolia.base.org # optional, defaults to Base Sepolia public RPC + # SVM Configuration (Solana Devnet) SVM_CLIENT_PRIVATE_KEY= SVM_FACILITATOR_PRIVATE_KEY= diff --git a/go/test/integration/core_test.go b/go/test/integration/core_test.go index c6cedbe970..926df56f37 100644 --- a/go/test/integration/core_test.go +++ b/go/test/integration/core_test.go @@ -4,9 +4,9 @@ import ( "context" "testing" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/test/mocks/cash" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/test/mocks/cash" + "github.com/x402-foundation/x402/go/types" ) // TestCoreIntegration tests the integration between x402Client, x402ResourceServer, and x402Facilitator diff --git a/go/test/integration/evm_batch_settlement_test.go b/go/test/integration/evm_batch_settlement_test.go new file mode 100644 index 0000000000..e86bbf0be1 --- /dev/null +++ b/go/test/integration/evm_batch_settlement_test.go @@ -0,0 +1,1158 @@ +// Package integration_test contains integration tests for the x402 Go SDK. +// This file specifically tests the EVM batch-settlement (batched) mechanism with +// REAL on-chain transactions on Base Sepolia using private keys from environment +// variables. Tests skip automatically when required env vars are missing. +// +// Required env vars: +// - EVM_CLIENT_PRIVATE_KEY — payer key (must hold USDC + ETH on Base Sepolia) +// - EVM_FACILITATOR_PRIVATE_KEY — facilitator key (must hold ETH on Base Sepolia) +// - EVM_RESOURCE_SERVER_ADDRESS — receiver/payee address +// +// Optional: +// - EVM_AUTHORIZER_PRIVATE_KEY — receiver-authorizer key (defaults to facilitator key) +// - EVM_RPC_URL — RPC endpoint (defaults to https://sepolia.base.org) +package integration_test + +import ( + "context" + "crypto/ecdsa" + "crypto/rand" + "encoding/base64" + "encoding/hex" + "encoding/json" + "fmt" + "io" + "math/big" + "net/http" + "net/http/httptest" + "os" + "strings" + "testing" + "time" + + "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/math" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/ethclient" + "github.com/ethereum/go-ethereum/signer/core/apitypes" + + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + nethttpmw "github.com/x402-foundation/x402/go/http/nethttp" + evmmech "github.com/x402-foundation/x402/go/mechanisms/evm" + batchsettlement "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement" + batchedclient "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/client" + batchedfacilitator "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/facilitator" + batchedserver "github.com/x402-foundation/x402/go/mechanisms/evm/batch-settlement/server" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" + "github.com/x402-foundation/x402/go/types" +) + +const ( + batchedTestNetwork = x402.Network("eip155:84532") + batchedTestUSDC = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" + batchedTestRPCDefault = "https://sepolia.base.org" +) + +// batchedTestKeys holds the parsed env-var keys for a batched integration test run. +type batchedTestKeys struct { + clientPK string + facilitatorPK string + authorizerPK string + receiver string + rpcURL string +} + +// loadBatchedTestKeys reads required env vars or returns nil and skips the test. +func loadBatchedTestKeys(t *testing.T) *batchedTestKeys { + t.Helper() + clientPK := os.Getenv("EVM_CLIENT_PRIVATE_KEY") + facilitatorPK := os.Getenv("EVM_FACILITATOR_PRIVATE_KEY") + receiver := os.Getenv("EVM_RESOURCE_SERVER_ADDRESS") + if clientPK == "" || facilitatorPK == "" || receiver == "" { + t.Skip("Skipping batched integration test: set EVM_CLIENT_PRIVATE_KEY, EVM_FACILITATOR_PRIVATE_KEY, EVM_RESOURCE_SERVER_ADDRESS") + } + authorizerPK := os.Getenv("EVM_AUTHORIZER_PRIVATE_KEY") + if authorizerPK == "" { + authorizerPK = facilitatorPK + } + rpcURL := os.Getenv("EVM_RPC_URL") + if rpcURL == "" { + rpcURL = batchedTestRPCDefault + } + return &batchedTestKeys{ + clientPK: clientPK, + facilitatorPK: facilitatorPK, + authorizerPK: authorizerPK, + receiver: receiver, + rpcURL: rpcURL, + } +} + +// batchedAuthorizerSigner implements both batchedserver.AuthorizerSigner (for the +// server scheme; SignTypedData) and batchsettlement.AuthorizerSigner (for the facilitator +// scheme; SignClaimBatch + SignRefund), backed by a single ECDSA key. +type batchedAuthorizerSigner struct { + privateKey *ecdsa.PrivateKey + address common.Address +} + +func newBatchedAuthorizerSigner(privateKeyHex string) (*batchedAuthorizerSigner, error) { + pk, err := crypto.HexToECDSA(strings.TrimPrefix(privateKeyHex, "0x")) + if err != nil { + return nil, fmt.Errorf("parse authorizer key: %w", err) + } + return &batchedAuthorizerSigner{ + privateKey: pk, + address: crypto.PubkeyToAddress(pk.PublicKey), + }, nil +} + +func (s *batchedAuthorizerSigner) Address() string { return s.address.Hex() } + +func (s *batchedAuthorizerSigner) SignTypedData( + _ context.Context, + domain evmmech.TypedDataDomain, + allTypes map[string][]evmmech.TypedDataField, + primaryType string, + message map[string]interface{}, +) ([]byte, error) { + td := buildBatchedTypedData(domain, allTypes, primaryType, message) + return s.signEIP712(td) +} + +func (s *batchedAuthorizerSigner) SignClaimBatch( + _ context.Context, + claims []batchsettlement.BatchSettlementVoucherClaim, + network string, +) ([]byte, error) { + chainId, err := evmmech.GetEvmChainId(network) + if err != nil { + return nil, err + } + domain := batchsettlement.GetBatchSettlementEip712Domain(chainId) + allTypes := map[string][]evmmech.TypedDataField{ + "ClaimBatch": batchsettlement.ClaimBatchTypes["ClaimBatch"], + "ClaimEntry": batchsettlement.ClaimBatchTypes["ClaimEntry"], + } + entries := make([]map[string]interface{}, len(claims)) + for i, claim := range claims { + channelId, _ := batchsettlement.ComputeChannelId(claim.Voucher.Channel, network) + channelIdBytes, _ := evmmech.HexToBytes(channelId) + maxClaimable, _ := new(big.Int).SetString(claim.Voucher.MaxClaimableAmount, 10) + totalClaimed, _ := new(big.Int).SetString(claim.TotalClaimed, 10) + entries[i] = map[string]interface{}{ + "channelId": channelIdBytes, + "maxClaimableAmount": maxClaimable, + "totalClaimed": totalClaimed, + } + } + td := buildBatchedTypedData(domain, allTypes, "ClaimBatch", map[string]interface{}{"claims": entries}) + return s.signEIP712(td) +} + +func (s *batchedAuthorizerSigner) SignRefund( + _ context.Context, + channelId, amount, nonce, network string, +) ([]byte, error) { + chainId, err := evmmech.GetEvmChainId(network) + if err != nil { + return nil, err + } + channelIdBytes, err := evmmech.HexToBytes(channelId) + if err != nil { + return nil, err + } + amt, ok := new(big.Int).SetString(amount, 10) + if !ok { + return nil, fmt.Errorf("invalid refund amount %q", amount) + } + non, ok := new(big.Int).SetString(nonce, 10) + if !ok { + return nil, fmt.Errorf("invalid refund nonce %q", nonce) + } + domain := batchsettlement.GetBatchSettlementEip712Domain(chainId) + allTypes := map[string][]evmmech.TypedDataField{"Refund": batchsettlement.RefundTypes["Refund"]} + td := buildBatchedTypedData(domain, allTypes, "Refund", map[string]interface{}{ + "channelId": channelIdBytes, + "nonce": non, + "amount": amt, + }) + return s.signEIP712(td) +} + +func (s *batchedAuthorizerSigner) signEIP712(td apitypes.TypedData) ([]byte, error) { + dataHash, err := td.HashStruct(td.PrimaryType, td.Message) + if err != nil { + return nil, fmt.Errorf("hash struct: %w", err) + } + domainSep, err := td.HashStruct("EIP712Domain", td.Domain.Map()) + if err != nil { + return nil, fmt.Errorf("hash domain: %w", err) + } + digest := crypto.Keccak256(append([]byte{0x19, 0x01}, append(domainSep, dataHash...)...)) + sig, err := crypto.Sign(digest, s.privateKey) + if err != nil { + return nil, fmt.Errorf("sign: %w", err) + } + sig[64] += 27 + return sig, nil +} + +func buildBatchedTypedData( + domain evmmech.TypedDataDomain, + allTypes map[string][]evmmech.TypedDataField, + primaryType string, + message map[string]interface{}, +) apitypes.TypedData { + td := apitypes.TypedData{ + Types: apitypes.Types{}, + PrimaryType: primaryType, + Domain: apitypes.TypedDataDomain{ + Name: domain.Name, + Version: domain.Version, + ChainId: (*math.HexOrDecimal256)(domain.ChainID), + VerifyingContract: domain.VerifyingContract, + }, + Message: message, + } + for name, fields := range allTypes { + conv := make([]apitypes.Type, len(fields)) + for i, f := range fields { + conv[i] = apitypes.Type{Name: f.Name, Type: f.Type} + } + td.Types[name] = conv + } + td.Types["EIP712Domain"] = []apitypes.Type{ + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + } + return td +} + +// batchedPipeline holds the wired client/server/facilitator + helpers for one test run. +type batchedPipeline struct { + clientScheme *batchedclient.BatchSettlementEvmScheme + serverScheme *batchedserver.BatchSettlementEvmScheme + facilitatorScheme *batchedfacilitator.BatchSettlementEvmScheme + x402Client *x402.X402Client + x402Server *x402.X402ResourceServer + x402Facilitator *x402.X402Facilitator + facilitatorClient x402.FacilitatorClient + facilitatorSigner *realFacilitatorEvmSigner + authorizerSigner *batchedAuthorizerSigner + clientSigner evmmech.ClientEvmSigner + clientAddress string + receiverAddress string + channelSalt string +} + +// buildBatchedPipeline wires up a complete batched pipeline for the given keys +// and a fresh random channel salt (so each test gets an isolated channel). +func buildBatchedPipeline(t *testing.T, keys *batchedTestKeys) *batchedPipeline { + t.Helper() + + // The refund flow needs to read on-chain channel state via the client signer, + // so build the signer with an ethclient bound to the test RPC URL. + clientEthClient, err := ethclient.Dial(keys.rpcURL) + if err != nil { + t.Fatalf("dial client RPC: %v", err) + } + clientSigner, err := evmsigners.NewClientSignerFromPrivateKeyWithClient(keys.clientPK, clientEthClient) + if err != nil { + t.Fatalf("client signer: %v", err) + } + facilitatorSigner, err := newRealFacilitatorEvmSigner(keys.facilitatorPK, keys.rpcURL) + if err != nil { + t.Fatalf("facilitator signer: %v", err) + } + authorizerSigner, err := newBatchedAuthorizerSigner(keys.authorizerPK) + if err != nil { + t.Fatalf("authorizer signer: %v", err) + } + + salt := randomChannelSalt(t) + + clientScheme := batchedclient.NewBatchSettlementEvmScheme(clientSigner, &batchedclient.BatchSettlementEvmSchemeOptions{ + DepositMultiplier: 5, + Salt: salt, + }) + x402Client := x402.Newx402Client() + x402Client.Register(batchedTestNetwork, clientScheme) + + facilitatorScheme := batchedfacilitator.NewBatchSettlementEvmScheme(facilitatorSigner, authorizerSigner) + x402Facilitator := x402.Newx402Facilitator() + x402Facilitator.Register([]x402.Network{batchedTestNetwork}, facilitatorScheme) + facClient := &localEvmFacilitatorClient{facilitator: x402Facilitator} + + serverScheme := batchedserver.NewBatchSettlementEvmScheme(keys.receiver, &batchedserver.BatchSettlementEvmSchemeServerConfig{ + ReceiverAuthorizerSigner: authorizerSigner, + }) + x402Server := x402.Newx402ResourceServer(x402.WithFacilitatorClient(facClient)) + // Register auto-wires scheme-provided lifecycle hooks (BeforeVerify, AfterVerify, + // BeforeSettle, AfterSettle, OnVerifiedPaymentCanceled) — no manual On*(...) calls + // needed; mirrors TS schemeHooks auto-registration. + x402Server.Register(batchedTestNetwork, serverScheme) + + if err := x402Server.Initialize(context.Background()); err != nil { + t.Fatalf("server initialize: %v", err) + } + + return &batchedPipeline{ + clientScheme: clientScheme, + serverScheme: serverScheme, + facilitatorScheme: facilitatorScheme, + x402Client: x402Client, + x402Server: x402Server, + x402Facilitator: x402Facilitator, + facilitatorClient: facClient, + facilitatorSigner: facilitatorSigner, + authorizerSigner: authorizerSigner, + clientSigner: clientSigner, + clientAddress: clientSigner.Address(), + receiverAddress: keys.receiver, + channelSalt: salt, + } +} + +// randomChannelSalt generates a fresh 32-byte salt so each test owns an isolated channel. +func randomChannelSalt(t *testing.T) string { + t.Helper() + b := make([]byte, 32) + if _, err := rand.Read(b); err != nil { + t.Fatalf("random salt: %v", err) + } + return "0x" + hex.EncodeToString(b) +} + +// batchedRequirements builds payment requirements for a batched payment. +func (p *batchedPipeline) requirements(amount string) types.PaymentRequirements { + return types.PaymentRequirements{ + Scheme: batchsettlement.SchemeBatched, + Network: string(batchedTestNetwork), + Asset: batchedTestUSDC, + Amount: amount, + PayTo: p.receiverAddress, + MaxTimeoutSeconds: 3600, + Extra: map[string]interface{}{ + "name": "USDC", + "version": "2", + "assetTransferMethod": "eip3009", + "receiverAuthorizer": p.authorizerSigner.Address(), + }, + } +} + +// onChainChannel reads (balance, totalClaimed) from the BatchSettlement contract. +func onChainChannel(ctx context.Context, signer *realFacilitatorEvmSigner, channelId string) (*big.Int, *big.Int, error) { + channelIdBytes := common.HexToHash(channelId) + result, err := signer.ReadContract(ctx, batchsettlement.BatchSettlementAddress, batchsettlement.BatchSettlementChannelsABI, "channels", channelIdBytes) + if err != nil { + return nil, nil, err + } + results, ok := result.([]interface{}) + if !ok || len(results) < 2 { + return nil, nil, fmt.Errorf("unexpected channels() result: %v", result) + } + balance, _ := results[0].(*big.Int) + claimed, _ := results[1].(*big.Int) + if balance == nil { + balance = big.NewInt(0) + } + if claimed == nil { + claimed = big.NewInt(0) + } + return balance, claimed, nil +} + +// assertChannelHasBalance reads the channel state once and fails if balance is not positive. +// The facilitator's settle path already waits for the deposit receipt, so the contract state +// is up to date by the time this is called — no polling needed. +func assertChannelHasBalance(ctx context.Context, t *testing.T, signer *realFacilitatorEvmSigner, channelId string) { + t.Helper() + balance, _, err := onChainChannel(ctx, signer, channelId) + if err != nil { + t.Fatalf("read channel %s: %v", channelId, err) + } + if balance == nil || balance.Sign() <= 0 { + t.Fatalf("expected channel %s to have nonzero balance, got %v", channelId, balance) + } +} + +// assertTotalClaimedAtLeast polls totalClaimed briefly. Even though the facilitator +// waits for the claim receipt before returning, public Base Sepolia RPCs can lag a +// few hundred milliseconds behind the canonical chain head — the call we just made +// to confirm the receipt may have hit a node that hasn't ingested the block yet. +// Retry for up to 3 s with a short backoff. +func assertTotalClaimedAtLeast(ctx context.Context, t *testing.T, signer *realFacilitatorEvmSigner, channelId string, expected *big.Int) { + t.Helper() + deadline := time.Now().Add(3 * time.Second) + var claimed *big.Int + for { + var err error + _, claimed, err = onChainChannel(ctx, signer, channelId) + if err == nil && claimed != nil && claimed.Cmp(expected) >= 0 { + return + } + if time.Now().After(deadline) { + if err != nil { + t.Fatalf("read channel %s: %v", channelId, err) + } + t.Fatalf("expected channel %s totalClaimed >= %s, got %v", channelId, expected, claimed) + } + time.Sleep(150 * time.Millisecond) + } +} + +// channelIdForRequirements computes the channel ID the client will derive for these requirements. +func (p *batchedPipeline) channelIdForRequirements(req types.PaymentRequirements) string { + cfg, err := p.clientScheme.BuildChannelConfig(req) + if err != nil { + return "" + } + id, err := batchsettlement.ComputeChannelId(cfg, req.Network) + if err != nil { + return "" + } + return batchsettlement.NormalizeChannelId(id) +} + +// resourceInfo returns a stub resource descriptor for createPaymentPayload. +func batchedResourceInfo() *types.ResourceInfo { + return &types.ResourceInfo{ + URL: "https://example.com/api/batched-test", + Description: "Batched integration test resource", + MimeType: "application/json", + } +} + +// ---------------------------------------------------------------------------- +// Scenario 1: deposit + voucher follow-up via direct API +// ---------------------------------------------------------------------------- + +func TestBatchSettlementIntegration_DepositThenVoucher(t *testing.T) { + keys := loadBatchedTestKeys(t) + pipe := buildBatchedPipeline(t, keys) + + ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second) + defer cancel() + + accepts := []types.PaymentRequirements{pipe.requirements("1000")} + resource := batchedResourceInfo() + + prr := pipe.x402Server.CreatePaymentRequiredResponse(accepts, resource, "", nil) + if prr.X402Version != 2 { + t.Fatalf("expected X402Version 2, got %d", prr.X402Version) + } + + firstPayload, err := pipe.x402Client.CreatePaymentPayload(ctx, accepts[0], resource, prr.Extensions) + if err != nil { + t.Fatalf("first createPaymentPayload: %v", err) + } + if firstPayload.Accepted.Scheme != batchsettlement.SchemeBatched { + t.Fatalf("expected scheme %s, got %s", batchsettlement.SchemeBatched, firstPayload.Accepted.Scheme) + } + if pType, _ := firstPayload.Payload["type"].(string); pType != "deposit" { + t.Fatalf("expected first payload type=deposit, got %v", firstPayload.Payload["type"]) + } + + accepted := pipe.x402Server.FindMatchingRequirements(accepts, firstPayload) + if accepted == nil { + t.Fatal("no matching requirements") + } + + verify, err := pipe.x402Server.VerifyPayment(ctx, firstPayload, *accepted) + if err != nil { + t.Fatalf("verify deposit: %v", err) + } + if !verify.IsValid { + t.Fatalf("deposit verify failed: %s", verify.InvalidReason) + } + if !strings.EqualFold(verify.Payer, pipe.clientAddress) { + t.Fatalf("expected payer %s, got %s", pipe.clientAddress, verify.Payer) + } + + settle, err := pipe.x402Server.SettlePayment(ctx, firstPayload, *accepted, nil) + if err != nil { + t.Fatalf("settle deposit: %v", err) + } + if !settle.Success { + t.Fatalf("deposit settle failed: %s — %s", settle.ErrorReason, settle.ErrorMessage) + } + if settle.Transaction == "" { + t.Fatal("expected deposit transaction hash") + } + t.Logf("deposit settled, tx=%s", settle.Transaction) + + channelId := pipe.channelIdForRequirements(accepts[0]) + if channelId == "" { + t.Fatal("could not derive channel ID") + } + assertChannelHasBalance(ctx, t, pipe.facilitatorSigner, channelId) + + // Mirror the TS flow: feed the settle response back so the client can update local state. + if err := pipe.clientScheme.ProcessSettleResponse(asMap(settle.Extra)); err != nil { + t.Fatalf("processSettleResponse: %v", err) + } + + // Second request — pure voucher (no chain tx). + secondPayload, err := pipe.x402Client.CreatePaymentPayload(ctx, accepts[0], resource, prr.Extensions) + if err != nil { + t.Fatalf("second createPaymentPayload: %v", err) + } + if pType, _ := secondPayload.Payload["type"].(string); pType != "voucher" { + t.Fatalf("expected second payload type=voucher, got %v", secondPayload.Payload["type"]) + } + + accepted2 := pipe.x402Server.FindMatchingRequirements(accepts, secondPayload) + verify2, err := pipe.x402Server.VerifyPayment(ctx, secondPayload, *accepted2) + if err != nil { + t.Fatalf("verify voucher: %v", err) + } + if !verify2.IsValid { + t.Fatalf("voucher verify failed: %s", verify2.InvalidReason) + } + settle2, err := pipe.x402Server.SettlePayment(ctx, secondPayload, *accepted2, nil) + if err != nil { + t.Fatalf("settle voucher: %v", err) + } + if !settle2.Success { + t.Fatalf("voucher settle failed: %s — %s", settle2.ErrorReason, settle2.ErrorMessage) + } + // Voucher path should NOT produce a chain tx — settlement is off-chain. + if settle2.Transaction != "" { + t.Logf("voucher settle returned tx=%s (unexpected for off-chain voucher path; non-fatal)", settle2.Transaction) + } +} + +// asMap converts a *Extra-like value (map or interface) to map[string]interface{}. +func asMap(v interface{}) map[string]interface{} { + if v == nil { + return nil + } + if m, ok := v.(map[string]interface{}); ok { + return m + } + return nil +} + +// ---------------------------------------------------------------------------- +// Scenario 2: deposit + voucher via HTTP middleware end-to-end +// ---------------------------------------------------------------------------- + +// startBatchedHTTPServer wires a real httptest.Server with the batched scheme +// and returns the URL + a shutdown func. Reuses the pipeline's facilitator +// scheme directly (no remote facilitator round-trip). +func startBatchedHTTPServer(t *testing.T, pipe *batchedPipeline, route string, price string) (string, func()) { + t.Helper() + + routes := x402http.RoutesConfig{ + "GET " + route: { + Accepts: x402http.PaymentOptions{ + { + Scheme: batchsettlement.SchemeBatched, + Price: price, + Network: batchedTestNetwork, + PayTo: pipe.receiverAddress, + Extra: map[string]interface{}{ + "name": "USDC", + "version": "2", + "assetTransferMethod": "eip3009", + "receiverAuthorizer": pipe.authorizerSigner.Address(), + }, + }, + }, + Description: "batched HTTP integration test", + MimeType: "application/json", + }, + } + + mux := http.NewServeMux() + mux.HandleFunc("GET "+route, func(w http.ResponseWriter, r *http.Request) { + w.Header().Set("Content-Type", "application/json") + _ = json.NewEncoder(w).Encode(map[string]string{"status": "ok"}) + }) + + // Use the pipeline's pre-built x402Server so the BatchSettlementEvmScheme hooks + // (AfterVerify SkipHandler for refunds, BeforeSettle voucher accumulation / + // refund-payload rewrite) are wired into the middleware. X402Payment(Config) + // would create a fresh server with no hooks and break the refund flow. + httpServer := x402http.Wrappedx402HTTPResourceServer(routes, pipe.x402Server) + handler := nethttpmw.PaymentMiddlewareFromHTTPServer(httpServer, + nethttpmw.WithTimeout(60*time.Second), + nethttpmw.WithSyncFacilitatorOnStart(false), + )(mux) + + srv := httptest.NewServer(handler) + return srv.URL + route, srv.Close +} + +func TestBatchSettlementIntegration_HTTPMiddleware(t *testing.T) { + keys := loadBatchedTestKeys(t) + pipe := buildBatchedPipeline(t, keys) + + url, shutdown := startBatchedHTTPServer(t, pipe, "/api/test", "$0.001") + defer shutdown() + + httpClient := x402http.WrapHTTPClientWithPayment(&http.Client{}, x402http.Newx402HTTPClient(pipe.x402Client)) + + ctx, cancel := context.WithTimeout(context.Background(), 90*time.Second) + defer cancel() + + req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + resp, err := httpClient.Do(req) + if err != nil { + t.Fatalf("HTTP request: %v", err) + } + defer resp.Body.Close() + body, _ := io.ReadAll(resp.Body) + if resp.StatusCode != http.StatusOK { + t.Fatalf("expected 200 after payment, got %d: %s", resp.StatusCode, string(body)) + } + + settleHeader := resp.Header.Get("PAYMENT-RESPONSE") + if settleHeader == "" { + t.Fatal("expected PAYMENT-RESPONSE header on success") + } + decoded, err := base64.StdEncoding.DecodeString(settleHeader) + if err != nil { + t.Fatalf("decode PAYMENT-RESPONSE: %v", err) + } + var settle x402.SettleResponse + if err := json.Unmarshal(decoded, &settle); err != nil { + t.Fatalf("unmarshal settle: %v", err) + } + if !settle.Success { + t.Fatalf("settle failed: %s — %s", settle.ErrorReason, settle.ErrorMessage) + } + if settle.Transaction == "" { + t.Fatal("expected deposit transaction hash on first request") + } + t.Logf("HTTP deposit settled, tx=%s", settle.Transaction) + + // Second request — should use a voucher (no chain tx). + req2, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + resp2, err := httpClient.Do(req2) + if err != nil { + t.Fatalf("HTTP request 2: %v", err) + } + defer resp2.Body.Close() + _, _ = io.ReadAll(resp2.Body) + if resp2.StatusCode != http.StatusOK { + t.Fatalf("expected 200 on voucher request, got %d", resp2.StatusCode) + } +} + +// ---------------------------------------------------------------------------- +// Scenario 3: multi-voucher session + manual claim+settle through facilitator +// ---------------------------------------------------------------------------- + +func TestBatchSettlementIntegration_MultiVoucherClaimSettle(t *testing.T) { + keys := loadBatchedTestKeys(t) + pipe := buildBatchedPipeline(t, keys) + + ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second) + defer cancel() + + accepts := []types.PaymentRequirements{pipe.requirements("500")} + resource := batchedResourceInfo() + _ = pipe.x402Server.CreatePaymentRequiredResponse(accepts, resource, "", nil) + + channelId := pipe.channelIdForRequirements(accepts[0]) + + // 1st request: deposit + depositPayload, err := pipe.x402Client.CreatePaymentPayload(ctx, accepts[0], resource, nil) + if err != nil { + t.Fatalf("deposit createPaymentPayload: %v", err) + } + depositMatch := pipe.x402Server.FindMatchingRequirements(accepts, depositPayload) + if v, err := pipe.x402Server.VerifyPayment(ctx, depositPayload, *depositMatch); err != nil || !v.IsValid { + t.Fatalf("deposit verify: %v / %v", err, v) + } + depositSettle, err := pipe.x402Server.SettlePayment(ctx, depositPayload, *depositMatch, nil) + if err != nil || !depositSettle.Success { + t.Fatalf("deposit settle: %v / %+v", err, depositSettle) + } + assertChannelHasBalance(ctx, t, pipe.facilitatorSigner, channelId) + _ = pipe.clientScheme.ProcessSettleResponse(asMap(depositSettle.Extra)) + + // Vouchers 2..4 (no chain tx — accumulates session.signedMaxClaimable). + for i := 0; i < 3; i++ { + voucher, err := pipe.x402Client.CreatePaymentPayload(ctx, accepts[0], resource, nil) + if err != nil { + t.Fatalf("voucher %d: %v", i, err) + } + match := pipe.x402Server.FindMatchingRequirements(accepts, voucher) + v, err := pipe.x402Server.VerifyPayment(ctx, voucher, *match) + if err != nil || !v.IsValid { + t.Fatalf("voucher %d verify: %v / %v", i, err, v) + } + s, err := pipe.x402Server.SettlePayment(ctx, voucher, *match, nil) + if err != nil || !s.Success { + t.Fatalf("voucher %d settle: %v / %+v", i, err, s) + } + _ = pipe.clientScheme.ProcessSettleResponse(asMap(s.Extra)) + } + + // Now manually trigger a claim through the channel manager. + manager := pipe.serverScheme.CreateChannelManager(pipe.facilitatorClient, batchedTestNetwork) + claims, err := manager.GetClaimableVouchers(nil) + if err != nil { + t.Fatalf("GetClaimableVouchers: %v", err) + } + if len(claims) != 1 { + t.Fatalf("expected 1 claim entry, got %d", len(claims)) + } + results, err := manager.Claim(ctx, &batchedserver.ClaimOptions{MaxClaimsPerBatch: 50}) + if err != nil { + t.Fatalf("Claim: %v", err) + } + if len(results) == 0 || results[0].Transaction == "" { + t.Fatalf("expected claim transaction, got %+v (claims=%d)", results, len(claims)) + } + t.Logf("claim tx=%s vouchers=%d", results[0].Transaction, results[0].Vouchers) + + // Wait for on-chain totalClaimed to reflect the vouchers. + expectedClaimed := new(big.Int).SetInt64(2000) // 4 requests * 500 + assertTotalClaimedAtLeast(ctx, t, pipe.facilitatorSigner, channelId, expectedClaimed) + + // Settle (transfer claimed funds to receiver). + settleResult, err := manager.Settle(ctx) + if err != nil { + t.Fatalf("manager.Settle: %v", err) + } + if settleResult == nil || settleResult.Transaction == "" { + t.Fatal("expected settle transaction") + } + t.Logf("settle tx=%s", settleResult.Transaction) +} + +// ---------------------------------------------------------------------------- +// Refund helpers (used by scenarios 4-7) +// ---------------------------------------------------------------------------- + +// makePaidRequest issues a single payment-aware GET against url and asserts 200. +// Returns the decoded settle response (from the PAYMENT-RESPONSE header) for tests +// that want to inspect the deposit/voucher tx. +func makePaidRequest(ctx context.Context, t *testing.T, pipe *batchedPipeline, url string) *x402.SettleResponse { + t.Helper() + httpClient := x402http.WrapHTTPClientWithPayment(&http.Client{}, x402http.Newx402HTTPClient(pipe.x402Client)) + req, _ := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) + resp, err := httpClient.Do(req) + if err != nil { + t.Fatalf("paid request: %v", err) + } + defer resp.Body.Close() + body, _ := io.ReadAll(resp.Body) + if resp.StatusCode != http.StatusOK { + t.Fatalf("expected 200 from paid request, got %d: %s", resp.StatusCode, string(body)) + } + header := resp.Header.Get("PAYMENT-RESPONSE") + if header == "" { + return nil + } + decoded, err := base64.StdEncoding.DecodeString(header) + if err != nil { + t.Fatalf("decode PAYMENT-RESPONSE: %v", err) + } + var settle x402.SettleResponse + if err := json.Unmarshal(decoded, &settle); err != nil { + t.Fatalf("unmarshal settle: %v", err) + } + // PaymentRoundTripper now auto-dispatches the scheme's OnPaymentResponse hook + // after each paid retry, so local session state is folded back without a + // manual ProcessSettleResponse call (mirrors TS @x402/fetch behavior). + return &settle +} + +// ---------------------------------------------------------------------------- +// Scenario 4: cooperative partial refund — channel stays open, balance drops +// ---------------------------------------------------------------------------- + +func TestBatchSettlementIntegration_RefundPartial(t *testing.T) { + keys := loadBatchedTestKeys(t) + pipe := buildBatchedPipeline(t, keys) + + // Per-request 500, default DepositMultiplier=5 from buildBatchedPipeline → deposit=2500. + url, shutdown := startBatchedHTTPServer(t, pipe, "/api/refund-partial", "$0.0005") + defer shutdown() + + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + + depositSettle := makePaidRequest(ctx, t, pipe, url) + if depositSettle == nil || depositSettle.Transaction == "" { + t.Fatal("expected deposit transaction on first request") + } + t.Logf("deposit tx=%s", depositSettle.Transaction) + + // Confirm the channel is funded on chain. + channelId := pipe.channelIdForRequirements(pipe.requirements("500")) + assertChannelHasBalance(ctx, t, pipe.facilitatorSigner, channelId) + + balanceBefore, _, err := onChainChannel(ctx, pipe.facilitatorSigner, channelId) + if err != nil { + t.Fatalf("read pre-refund balance: %v", err) + } + + // Partial refund — request 1000 of the remaining balance back. + refundResp, err := pipe.clientScheme.Refund(ctx, url, &batchedclient.RefundOptions{Amount: "1000"}) + if err != nil { + t.Fatalf("partial refund: %v", err) + } + if !refundResp.Success { + t.Fatalf("partial refund failed: %s — %s", refundResp.ErrorReason, refundResp.ErrorMessage) + } + if refundResp.Transaction == "" { + t.Fatal("expected refund transaction hash") + } + t.Logf("refund tx=%s", refundResp.Transaction) + + // Public Base Sepolia RPCs occasionally lag a few hundred ms behind the + // canonical chain head, so poll briefly for the post-refund balance to land. + expected := new(big.Int).Sub(balanceBefore, big.NewInt(1000)) + deadline := time.Now().Add(3 * time.Second) + var balanceAfter *big.Int + for { + balanceAfter, _, err = onChainChannel(ctx, pipe.facilitatorSigner, channelId) + if err == nil && balanceAfter != nil && balanceAfter.Cmp(expected) == 0 { + break + } + if time.Now().After(deadline) { + if err != nil { + t.Fatalf("read channel after refund: %v", err) + } + t.Fatalf("on-chain balance after partial refund: got %s, want %s (before=%s)", balanceAfter, expected, balanceBefore) + } + time.Sleep(150 * time.Millisecond) + } + + // Local session must still exist (partial refund leaves the channel open). + if !pipe.clientScheme.HasSession(channelId) { + t.Fatal("expected local session to survive partial refund") + } +} + +// ---------------------------------------------------------------------------- +// Scenario 5: drained channel — local short-circuit prevents network round-trip +// ---------------------------------------------------------------------------- + +func TestBatchSettlementIntegration_RefundDrainedChannelShortCircuit(t *testing.T) { + keys := loadBatchedTestKeys(t) + pipe := buildBatchedPipeline(t, keys) + + url, shutdown := startBatchedHTTPServer(t, pipe, "/api/refund-drained", "$0.0005") + defer shutdown() + + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + + // Deposit via the first paid request. + depositSettle := makePaidRequest(ctx, t, pipe, url) + if depositSettle == nil || depositSettle.Transaction == "" { + t.Fatal("expected deposit tx on first request") + } + + // Issue a full refund first to drain the channel locally + on chain. + full, err := pipe.clientScheme.Refund(ctx, url, nil) + if err != nil { + t.Fatalf("full refund: %v", err) + } + if !full.Success { + t.Fatalf("full refund failed: %s — %s", full.ErrorReason, full.ErrorMessage) + } + t.Logf("full refund tx=%s", full.Transaction) + + // A second refund should short-circuit locally with "no remaining balance" + // — no HTTP call, no chain interaction. + _, err = pipe.clientScheme.Refund(ctx, url, nil) + if err == nil { + t.Fatal("expected refund on drained channel to error locally") + } + if !strings.Contains(err.Error(), "no remaining balance") { + t.Fatalf("expected drained-channel short-circuit, got: %v", err) + } +} + +// ---------------------------------------------------------------------------- +// Scenario 6: non-recoverable refund error — fast fail, no retry +// ---------------------------------------------------------------------------- + +func TestBatchSettlementIntegration_RefundNonRecoverableFastFail(t *testing.T) { + keys := loadBatchedTestKeys(t) + pipe := buildBatchedPipeline(t, keys) + + url, shutdown := startBatchedHTTPServer(t, pipe, "/api/refund-exceeds", "$0.0005") + defer shutdown() + + ctx, cancel := context.WithTimeout(context.Background(), 120*time.Second) + defer cancel() + + depositSettle := makePaidRequest(ctx, t, pipe, url) + if depositSettle == nil || depositSettle.Transaction == "" { + t.Fatal("expected deposit tx on first request") + } + + // Request a refund larger than the on-chain remainder. + // Server returns 402 with PAYMENT-REQUIRED Error=invalid_batch_settlement_evm_refund_amount_exceeds_balance. + // Client must fail fast (non-recoverable error) without retry. + start := time.Now() + _, err := pipe.clientScheme.Refund(ctx, url, &batchedclient.RefundOptions{Amount: "999999999"}) + elapsed := time.Since(start) + if err == nil { + t.Fatal("expected non-recoverable refund error") + } + if !strings.Contains(err.Error(), batchsettlement.ErrRefundAmountExceedsBalance) { + t.Fatalf("expected non-recoverable error code, got: %v", err) + } + t.Logf("fast-failed in %s with: %v", elapsed, err) +} + +// ---------------------------------------------------------------------------- +// Scenario 7: recoverable refund error — retry budget exhausted +// ---------------------------------------------------------------------------- + +// alwaysStaleRefundHandler serves a payment-required probe (so the client can +// build a refund payload) and then always responds to PAYMENT-SIGNATURE with a +// recoverable 402 (ErrCumulativeAmountMismatch). Used to exercise the client's +// retry-exhaustion path. +func alwaysStaleRefundHandler(t *testing.T, pipe *batchedPipeline, price string) http.HandlerFunc { + t.Helper() + return func(w http.ResponseWriter, r *http.Request) { + req := pipe.requirements(price) + + paymentRequired := x402.PaymentRequired{ + X402Version: 2, + Accepts: []types.PaymentRequirements{req}, + } + if r.Header.Get("PAYMENT-SIGNATURE") != "" { + paymentRequired.Error = batchsettlement.ErrCumulativeAmountMismatch + } + + bytes, _ := json.Marshal(paymentRequired) + w.Header().Set("PAYMENT-REQUIRED", base64.StdEncoding.EncodeToString(bytes)) + w.Header().Set("Content-Type", "application/json") + w.WriteHeader(http.StatusPaymentRequired) + _, _ = w.Write(bytes) + } +} + +// ---------------------------------------------------------------------------- +// Scenario 8: tick claim phase — auto-claim fires after ClaimIntervalSecs +// ---------------------------------------------------------------------------- + +func TestBatchSettlementIntegration_AutoClaimTick(t *testing.T) { + keys := loadBatchedTestKeys(t) + pipe := buildBatchedPipeline(t, keys) + + url, shutdown := startBatchedHTTPServer(t, pipe, "/api/auto-claim", "$0.0003") + defer shutdown() + + ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second) + defer cancel() + + // Seed channel: deposit + 2 vouchers so signedMaxClaimable > totalClaimed. + if d := makePaidRequest(ctx, t, pipe, url); d == nil || d.Transaction == "" { + t.Fatal("deposit tx missing") + } + for i := 0; i < 2; i++ { + _ = makePaidRequest(ctx, t, pipe, url) + } + + channelId := pipe.channelIdForRequirements(pipe.requirements("300")) + assertChannelHasBalance(ctx, t, pipe.facilitatorSigner, channelId) + + manager := pipe.serverScheme.CreateChannelManager(pipe.facilitatorClient, batchedTestNetwork) + + claimCh := make(chan batchedserver.ClaimResult, 4) + errCh := make(chan error, 4) + manager.Start(batchedserver.AutoSettlementConfig{ + ClaimIntervalSecs: 2, + MaxClaimsPerBatch: 50, + OnClaim: func(r batchedserver.ClaimResult) { claimCh <- r }, + OnError: func(err error) { errCh <- err }, + }) + defer func() { _ = manager.Stop(context.Background(), nil) }() + + select { + case r := <-claimCh: + if r.Transaction == "" { + t.Fatal("OnClaim fired with empty tx hash") + } + t.Logf("auto-claim tx=%s vouchers=%d", r.Transaction, r.Vouchers) + case err := <-errCh: + t.Fatalf("auto-claim emitted error: %v", err) + case <-time.After(45 * time.Second): + t.Fatal("timed out waiting for auto-claim tick") + } + + // On-chain totalClaimed should have advanced. + expected := big.NewInt(900) // 3 requests * 300 + assertTotalClaimedAtLeast(ctx, t, pipe.facilitatorSigner, channelId, expected) +} + +// ---------------------------------------------------------------------------- +// Scenario 9: tick settle phase — claim then settle on interval triggers +// ---------------------------------------------------------------------------- + +func TestBatchSettlementIntegration_AutoClaimAndSettleTick(t *testing.T) { + keys := loadBatchedTestKeys(t) + pipe := buildBatchedPipeline(t, keys) + + url, shutdown := startBatchedHTTPServer(t, pipe, "/api/auto-settle", "$0.0003") + defer shutdown() + + ctx, cancel := context.WithTimeout(context.Background(), 240*time.Second) + defer cancel() + + if d := makePaidRequest(ctx, t, pipe, url); d == nil || d.Transaction == "" { + t.Fatal("deposit tx missing") + } + for i := 0; i < 2; i++ { + _ = makePaidRequest(ctx, t, pipe, url) + } + + channelId := pipe.channelIdForRequirements(pipe.requirements("300")) + assertChannelHasBalance(ctx, t, pipe.facilitatorSigner, channelId) + + manager := pipe.serverScheme.CreateChannelManager(pipe.facilitatorClient, batchedTestNetwork) + + claimCh := make(chan batchedserver.ClaimResult, 4) + settleCh := make(chan batchedserver.SettleResult, 4) + errCh := make(chan error, 4) + manager.Start(batchedserver.AutoSettlementConfig{ + ClaimIntervalSecs: 2, + SettleIntervalSecs: 2, + OnClaim: func(r batchedserver.ClaimResult) { claimCh <- r }, + OnSettle: func(r batchedserver.SettleResult) { settleCh <- r }, + OnError: func(err error) { errCh <- err }, + }) + defer func() { _ = manager.Stop(context.Background(), nil) }() + + // Wait for claim first. + select { + case r := <-claimCh: + t.Logf("auto-claim tx=%s vouchers=%d", r.Transaction, r.Vouchers) + case err := <-errCh: + t.Fatalf("auto-claim error: %v", err) + case <-time.After(60 * time.Second): + t.Fatal("timed out waiting for auto-claim") + } + + // Then wait for the settle phase to trigger on a subsequent tick. + select { + case r := <-settleCh: + if r.Transaction == "" { + t.Fatal("OnSettle fired with empty tx hash") + } + t.Logf("auto-settle tx=%s", r.Transaction) + case err := <-errCh: + t.Fatalf("auto-settle error: %v", err) + case <-time.After(60 * time.Second): + t.Fatal("timed out waiting for auto-settle") + } +} + +// ---------------------------------------------------------------------------- +// Scenario 10: withdrawal-pending detection + manager refund flow +// ---------------------------------------------------------------------------- + +func TestBatchSettlementIntegration_WithdrawalPendingRefund(t *testing.T) { + keys := loadBatchedTestKeys(t) + pipe := buildBatchedPipeline(t, keys) + + url, shutdown := startBatchedHTTPServer(t, pipe, "/api/withdraw-pending", "$0.0004") + defer shutdown() + + ctx, cancel := context.WithTimeout(context.Background(), 180*time.Second) + defer cancel() + + // Deposit + 1 voucher so the session has signedMaxClaimable + remainder. + if d := makePaidRequest(ctx, t, pipe, url); d == nil || d.Transaction == "" { + t.Fatal("deposit tx missing") + } + _ = makePaidRequest(ctx, t, pipe, url) + + channelId := pipe.channelIdForRequirements(pipe.requirements("400")) + assertChannelHasBalance(ctx, t, pipe.facilitatorSigner, channelId) + + // Simulate an on-chain withdrawal-initiation by stamping the local session's + // WithdrawRequestedAt field — this is what the deposit hook would do after + // the payer called BatchSettlement.initiateWithdraw on chain. Real on-chain + // initiateWithdraw would also work, but it requires payer-side chain writes + // (out of scope for the helpers exposed in test/integration/). + storage := pipe.serverScheme.GetStorage() + session, err := storage.Get(channelId) + if err != nil || session == nil { + t.Fatalf("expected session for channel %s: %v", channelId, err) + } + session.WithdrawRequestedAt = int(time.Now().Unix()) + if err := storage.Set(channelId, session); err != nil { + t.Fatalf("update session: %v", err) + } + + manager := pipe.serverScheme.CreateChannelManager(pipe.facilitatorClient, batchedTestNetwork) + + pending, err := manager.GetWithdrawalPendingSessions() + if err != nil { + t.Fatalf("GetWithdrawalPendingSessions: %v", err) + } + if len(pending) != 1 { + t.Fatalf("expected 1 withdrawal-pending session, got %d", len(pending)) + } + if !strings.EqualFold(batchsettlement.NormalizeChannelId(pending[0].ChannelId), channelId) { + t.Fatalf("expected channel %s, got %s", channelId, pending[0].ChannelId) + } + + // Manager-driven cooperative refund — claims the outstanding voucher and + // refunds the unclaimed remainder. Produces a real onchain tx. + results, err := manager.Refund(ctx, []string{channelId}) + if err != nil { + t.Fatalf("manager.Refund: %v", err) + } + if len(results) != 1 || results[0].Transaction == "" { + t.Fatalf("expected 1 refund result with tx hash, got %+v", results) + } + t.Logf("manager refund tx=%s channel=%s", results[0].Transaction, results[0].Channel) + + // Session should be deleted post-refund. + post, _ := storage.Get(channelId) + if post != nil { + t.Fatalf("expected session deleted after refund, still present: %+v", post) + } +} + +func TestBatchSettlementIntegration_RefundRecoverableRetryExhaustion(t *testing.T) { + keys := loadBatchedTestKeys(t) + pipe := buildBatchedPipeline(t, keys) + + // Real HTTP server for the deposit (so we have a real on-chain channel to recover from). + depositURL, depositShutdown := startBatchedHTTPServer(t, pipe, "/api/refund-retry", "$0.0005") + defer depositShutdown() + + depositSettle := makePaidRequest(context.Background(), t, pipe, depositURL) + if depositSettle == nil || depositSettle.Transaction == "" { + t.Fatal("expected deposit tx") + } + channelId := pipe.channelIdForRequirements(pipe.requirements("500")) + assertChannelHasBalance(context.Background(), t, pipe.facilitatorSigner, channelId) + + // Mock URL that always returns the recoverable 402 on signed requests. + mock := httptest.NewServer(alwaysStaleRefundHandler(t, pipe, "500")) + defer mock.Close() + + ctx, cancel := context.WithTimeout(context.Background(), 60*time.Second) + defer cancel() + + _, err := pipe.clientScheme.Refund(ctx, mock.URL+"/api/refund-retry", nil) + if err == nil { + t.Fatal("expected refund to fail after retry exhaustion") + } + // The client should retry once and then bail out with "after 2 attempt(s)". + if !strings.Contains(err.Error(), "after 2 attempt(s)") { + t.Fatalf("expected retry-exhaustion error, got: %v", err) + } + t.Logf("retry exhaustion observed: %v", err) +} diff --git a/go/test/integration/evm_test.go b/go/test/integration/evm_test.go index 3993ae4ea6..0d957a1db6 100644 --- a/go/test/integration/evm_test.go +++ b/go/test/integration/evm_test.go @@ -22,16 +22,16 @@ import ( "github.com/ethereum/go-ethereum/ethclient" "github.com/ethereum/go-ethereum/signer/core/apitypes" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/evm" - exactevmclient "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - exactevmfacilitator "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - exactevmserver "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - uptoevmclient "github.com/coinbase/x402/go/mechanisms/evm/upto/client" - uptoevmfacilitator "github.com/coinbase/x402/go/mechanisms/evm/upto/facilitator" - uptoevmserver "github.com/coinbase/x402/go/mechanisms/evm/upto/server" - evmsigners "github.com/coinbase/x402/go/signers/evm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + exactevmclient "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + exactevmfacilitator "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + exactevmserver "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + uptoevmclient "github.com/x402-foundation/x402/go/mechanisms/evm/upto/client" + uptoevmfacilitator "github.com/x402-foundation/x402/go/mechanisms/evm/upto/facilitator" + uptoevmserver "github.com/x402-foundation/x402/go/mechanisms/evm/upto/server" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" + "github.com/x402-foundation/x402/go/types" ) // newRealClientEvmSigner creates a client signer using the helper @@ -325,7 +325,15 @@ func (s *realFacilitatorEvmSigner) VerifyTypedData( typedData.Types[typeName] = typedFields } - // Hash the data + if _, exists := typedData.Types["EIP712Domain"]; !exists { + typedData.Types["EIP712Domain"] = []apitypes.Type{ + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + } + } + dataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) if err != nil { return false, err @@ -341,12 +349,10 @@ func (s *realFacilitatorEvmSigner) VerifyTypedData( rawData = append(rawData, dataHash...) digest := crypto.Keccak256(rawData) - // Recover the public key from the signature if len(signature) != 65 { return false, fmt.Errorf("invalid signature length: %d", len(signature)) } - // Adjust v value back for recovery v := signature[64] if v >= 27 { v -= 27 @@ -1018,7 +1024,15 @@ func (s *permit2FacilitatorEvmSigner) VerifyTypedData( typedData.Types[typeName] = typedFields } - // Hash the data + if _, exists := typedData.Types["EIP712Domain"]; !exists { + typedData.Types["EIP712Domain"] = []apitypes.Type{ + {Name: "name", Type: "string"}, + {Name: "version", Type: "string"}, + {Name: "chainId", Type: "uint256"}, + {Name: "verifyingContract", Type: "address"}, + } + } + dataHash, err := typedData.HashStruct(typedData.PrimaryType, typedData.Message) if err != nil { return false, err @@ -1034,12 +1048,10 @@ func (s *permit2FacilitatorEvmSigner) VerifyTypedData( rawData = append(rawData, dataHash...) digest := crypto.Keccak256(rawData) - // Recover the public key from the signature if len(signature) != 65 { return false, fmt.Errorf("invalid signature length: %d", len(signature)) } - // Adjust v value back for recovery v := signature[64] if v >= 27 { v -= 27 diff --git a/go/test/integration/http_test.go b/go/test/integration/http_test.go index 7397977872..99dc5a9cb4 100644 --- a/go/test/integration/http_test.go +++ b/go/test/integration/http_test.go @@ -7,10 +7,10 @@ import ( "strings" "testing" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - "github.com/coinbase/x402/go/test/mocks/cash" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/test/mocks/cash" + "github.com/x402-foundation/x402/go/types" ) // mockHTTPAdapter implements the HTTPAdapter interface for testing @@ -218,6 +218,7 @@ func TestHTTPIntegration(t *testing.T) { *httpProcessResult2.PaymentRequirements, nil, nil, + nil, ) if !settlementResult.Success { t.Fatalf("Failed to process settlement: %v", settlementResult.ErrorReason) diff --git a/go/test/integration/mcp_evm_test.go b/go/test/integration/mcp_evm_test.go index ce5c75c1c4..5d2b92a266 100644 --- a/go/test/integration/mcp_evm_test.go +++ b/go/test/integration/mcp_evm_test.go @@ -32,13 +32,14 @@ import ( "testing" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mcp" - evmclient "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmfacilitator "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - evmserver "github.com/coinbase/x402/go/mechanisms/evm/exact/server" - evmsigners "github.com/coinbase/x402/go/signers/evm" mcpsdk "github.com/modelcontextprotocol/go-sdk/mcp" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/extensions/bazaar" + "github.com/x402-foundation/x402/go/mcp" + evmclient "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + evmfacilitator "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + evmserver "github.com/x402-foundation/x402/go/mechanisms/evm/exact/server" + evmsigners "github.com/x402-foundation/x402/go/signers/evm" ) const ( @@ -150,6 +151,22 @@ func TestMCPEVMIntegration(t *testing.T) { Version: "1.0.0", }, nil) + // Declare bazaar MCP discovery extension for weather tool + bazaarExtension, err := bazaar.DeclareMcpDiscoveryExtension(bazaar.DeclareMcpDiscoveryConfig{ + ToolName: "get_weather", + Description: "Get weather for a city", + Transport: bazaar.TransportSSE, + InputSchema: map[string]interface{}{ + "type": "object", + "properties": map[string]interface{}{ + "city": map[string]interface{}{"type": "string"}, + }, + }, + }) + if err != nil { + t.Fatalf("Failed to declare bazaar extension: %v", err) + } + // Create payment wrapper paymentWrapper := mcp.NewPaymentWrapper(resourceServer, mcp.PaymentWrapperConfig{ Accepts: accepts, @@ -158,6 +175,9 @@ func TestMCPEVMIntegration(t *testing.T) { Description: "Get weather for a city", MimeType: "application/json", }, + Extensions: map[string]interface{}{ + bazaar.BAZAAR.Key(): bazaarExtension, + }, }) // Register free tool @@ -299,7 +319,62 @@ func TestMCPEVMIntegration(t *testing.T) { }) // ======================================================================== - // Test 3: Paid tool with payment succeeds (REAL BLOCKCHAIN TRANSACTION) + // Test 3: 402 response includes bazaar extensions + // ======================================================================== + t.Run("402 response includes bazaar extensions", func(t *testing.T) { + manualClient := mcp.NewX402MCPClient(clientSession, paymentClient, mcp.Options{ + AutoPayment: mcp.BoolPtr(false), + }) + + _, err := manualClient.CallTool(ctx, "get_weather", map[string]interface{}{"city": "San Francisco"}) + if err == nil { + t.Fatal("Expected 402 error") + } + + paymentErr, ok := err.(*mcp.PaymentRequiredError) + if !ok { + t.Fatalf("Expected PaymentRequiredError, got %T: %v", err, err) + } + if paymentErr.PaymentRequired == nil { + t.Fatal("Expected PaymentRequired to be set") + } + if paymentErr.PaymentRequired.Extensions == nil { + t.Fatal("Expected Extensions to be set in PaymentRequired") + } + + bazaarRaw, ok := paymentErr.PaymentRequired.Extensions[bazaar.BAZAAR.Key()] + if !ok { + t.Fatal("Expected 'bazaar' key in Extensions") + } + + // Round-trip through JSON to verify it deserializes to a valid DiscoveryExtension + bazaarJSON, err := json.Marshal(bazaarRaw) + if err != nil { + t.Fatalf("Failed to marshal bazaar extension: %v", err) + } + + var ext bazaar.DiscoveryExtension + if err := json.Unmarshal(bazaarJSON, &ext); err != nil { + t.Fatalf("Failed to unmarshal bazaar extension: %v", err) + } + + // Verify the MCP input contains the expected tool name + mcpInput, ok := ext.Info.Input.(bazaar.McpInput) + if !ok { + t.Fatalf("Expected McpInput in bazaar extension Info.Input, got %T", ext.Info.Input) + } + if mcpInput.ToolName != "get_weather" { + t.Errorf("Expected toolName 'get_weather', got '%s'", mcpInput.ToolName) + } + if mcpInput.Type != "mcp" { + t.Errorf("Expected type 'mcp', got '%s'", mcpInput.Type) + } + + t.Logf("✅ Bazaar extension present in 402 response with toolName: %s", mcpInput.ToolName) + }) + + // ======================================================================== + // Test 4: Paid tool with payment succeeds (REAL BLOCKCHAIN TRANSACTION) // ======================================================================== t.Run("Paid tool with auto-payment and real blockchain settlement", func(t *testing.T) { t.Log("\n🔄 Starting paid tool call with real blockchain settlement...\n") @@ -343,7 +418,7 @@ func TestMCPEVMIntegration(t *testing.T) { }) // ======================================================================== - // Test 4: Multiple paid tool calls work + // Test 5: Multiple paid tool calls work // ======================================================================== t.Run("Multiple paid tool calls work", func(t *testing.T) { // Wait for the previous test's settlement tx to be mined @@ -376,7 +451,7 @@ func TestMCPEVMIntegration(t *testing.T) { }) // ======================================================================== - // Test 5: List tools works + // Test 6: List tools works // ======================================================================== t.Run("List tools works", func(t *testing.T) { session, ok := x402McpClient.Client().(*mcpsdk.ClientSession) diff --git a/go/test/integration/svm_test.go b/go/test/integration/svm_test.go index 960bdc4ecd..18271df0c6 100644 --- a/go/test/integration/svm_test.go +++ b/go/test/integration/svm_test.go @@ -13,13 +13,13 @@ import ( solana "github.com/gagliardetto/solana-go" "github.com/gagliardetto/solana-go/rpc" - x402 "github.com/coinbase/x402/go" - svm "github.com/coinbase/x402/go/mechanisms/svm" - svmclient "github.com/coinbase/x402/go/mechanisms/svm/exact/client" - svmfacilitator "github.com/coinbase/x402/go/mechanisms/svm/exact/facilitator" - svmserver "github.com/coinbase/x402/go/mechanisms/svm/exact/server" - svmsigners "github.com/coinbase/x402/go/signers/svm" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + svm "github.com/x402-foundation/x402/go/mechanisms/svm" + svmclient "github.com/x402-foundation/x402/go/mechanisms/svm/exact/client" + svmfacilitator "github.com/x402-foundation/x402/go/mechanisms/svm/exact/facilitator" + svmserver "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" + svmsigners "github.com/x402-foundation/x402/go/signers/svm" + "github.com/x402-foundation/x402/go/types" ) // newRealClientSvmSigner creates a client signer using the helper diff --git a/go/test/mocks/cash/cash.go b/go/test/mocks/cash/cash.go index 510d810021..080fd6bc2a 100644 --- a/go/test/mocks/cash/cash.go +++ b/go/test/mocks/cash/cash.go @@ -8,8 +8,8 @@ import ( "strings" "time" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/types" ) // ============================================================================ diff --git a/go/test/unit/evm_client_facilitator_test.go b/go/test/unit/evm_client_facilitator_test.go index 6837e0c13d..f92c37dd7d 100644 --- a/go/test/unit/evm_client_facilitator_test.go +++ b/go/test/unit/evm_client_facilitator_test.go @@ -12,11 +12,11 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/crypto" - "github.com/coinbase/x402/go/mechanisms/evm" - evmclient "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmfacilitator "github.com/coinbase/x402/go/mechanisms/evm/exact/facilitator" - evmv1facilitator "github.com/coinbase/x402/go/mechanisms/evm/exact/v1/facilitator" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/mechanisms/evm" + evmclient "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + evmfacilitator "github.com/x402-foundation/x402/go/mechanisms/evm/exact/facilitator" + evmv1facilitator "github.com/x402-foundation/x402/go/mechanisms/evm/exact/v1/facilitator" + "github.com/x402-foundation/x402/go/types" ) // ========================================================================= diff --git a/go/test/unit/evm_eip712_test.go b/go/test/unit/evm_eip712_test.go index 1864a6f0ba..01069bd450 100644 --- a/go/test/unit/evm_eip712_test.go +++ b/go/test/unit/evm_eip712_test.go @@ -4,7 +4,7 @@ import ( "math/big" "testing" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // TestHashEIP3009Authorization tests EIP-3009 authorization hashing diff --git a/go/test/unit/evm_test.go b/go/test/unit/evm_test.go index e0363dc0aa..55cca6c052 100644 --- a/go/test/unit/evm_test.go +++ b/go/test/unit/evm_test.go @@ -5,11 +5,11 @@ import ( "fmt" "testing" - x402 "github.com/coinbase/x402/go" - "github.com/coinbase/x402/go/mechanisms/evm" - evmclient "github.com/coinbase/x402/go/mechanisms/evm/exact/client" - evmv1client "github.com/coinbase/x402/go/mechanisms/evm/exact/v1/client" - "github.com/coinbase/x402/go/types" + x402 "github.com/x402-foundation/x402/go" + "github.com/x402-foundation/x402/go/mechanisms/evm" + evmclient "github.com/x402-foundation/x402/go/mechanisms/evm/exact/client" + evmv1client "github.com/x402-foundation/x402/go/mechanisms/evm/exact/v1/client" + "github.com/x402-foundation/x402/go/types" ) // Mock EVM signer for client diff --git a/go/test/unit/evm_types_test.go b/go/test/unit/evm_types_test.go index 66243dd4f1..f051a61826 100644 --- a/go/test/unit/evm_types_test.go +++ b/go/test/unit/evm_types_test.go @@ -3,7 +3,7 @@ package unit_test import ( "testing" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // TestEIP3009PayloadParsing tests EIP-3009 payload parsing and serialization diff --git a/go/test/unit/evm_utils_test.go b/go/test/unit/evm_utils_test.go index 6c5a947bd8..5d4f535c14 100644 --- a/go/test/unit/evm_utils_test.go +++ b/go/test/unit/evm_utils_test.go @@ -6,7 +6,7 @@ import ( "testing" "time" - "github.com/coinbase/x402/go/mechanisms/evm" + "github.com/x402-foundation/x402/go/mechanisms/evm" ) // TestGetEvmChainId tests chain ID retrieval for various network formats diff --git a/go/test/unit/evm_v1_utils_test.go b/go/test/unit/evm_v1_utils_test.go index dfd278bb91..0c49d3df6b 100644 --- a/go/test/unit/evm_v1_utils_test.go +++ b/go/test/unit/evm_v1_utils_test.go @@ -3,7 +3,7 @@ package unit_test import ( "testing" - evmv1 "github.com/coinbase/x402/go/mechanisms/evm/v1" + evmv1 "github.com/x402-foundation/x402/go/mechanisms/evm/v1" ) func TestV1GetEvmChainId(t *testing.T) { diff --git a/go/test/unit/http_test.go b/go/test/unit/http_test.go index 5389802d9e..932010f82e 100644 --- a/go/test/unit/http_test.go +++ b/go/test/unit/http_test.go @@ -5,9 +5,9 @@ import ( "strings" "testing" - x402 "github.com/coinbase/x402/go" - x402http "github.com/coinbase/x402/go/http" - "github.com/coinbase/x402/go/test/mocks/cash" + x402 "github.com/x402-foundation/x402/go" + x402http "github.com/x402-foundation/x402/go/http" + "github.com/x402-foundation/x402/go/test/mocks/cash" ) // mockBrowserHTTPAdapter implements the HTTPAdapter interface for browser testing diff --git a/go/test/unit/permit2_fixtures_test.go b/go/test/unit/permit2_fixtures_test.go index dd68c3ce74..c428895b53 100644 --- a/go/test/unit/permit2_fixtures_test.go +++ b/go/test/unit/permit2_fixtures_test.go @@ -1,6 +1,6 @@ package unit_test -import "github.com/coinbase/x402/go/mechanisms/evm" +import "github.com/x402-foundation/x402/go/mechanisms/evm" // defaultTestWitness returns a standard Permit2Witness fixture for unit tests. // Tests that need to vary one field should call this and override only that field, diff --git a/go/test/unit/svm_test.go b/go/test/unit/svm_test.go index 3496eff5d4..810fcf0163 100644 --- a/go/test/unit/svm_test.go +++ b/go/test/unit/svm_test.go @@ -6,9 +6,9 @@ import ( solana "github.com/gagliardetto/solana-go" - x402 "github.com/coinbase/x402/go" - svm "github.com/coinbase/x402/go/mechanisms/svm" - svmserver "github.com/coinbase/x402/go/mechanisms/svm/exact/server" + x402 "github.com/x402-foundation/x402/go" + svm "github.com/x402-foundation/x402/go/mechanisms/svm" + svmserver "github.com/x402-foundation/x402/go/mechanisms/svm/exact/server" ) // TestSolanaServerPriceParsing tests V2 server price parsing diff --git a/go/types.go b/go/types.go index 97ae1fdc1d..7bf66c9414 100644 --- a/go/types.go +++ b/go/types.go @@ -5,7 +5,7 @@ import ( "fmt" "strings" - "github.com/coinbase/x402/go/types" + "github.com/x402-foundation/x402/go/types" ) // Network represents a blockchain network identifier in CAIP-2 format @@ -86,6 +86,12 @@ type VerifyResponse struct { InvalidMessage string `json:"invalidMessage,omitempty"` Payer string `json:"payer,omitempty"` Extensions map[string]interface{} `json:"extensions,omitempty"` + Extra map[string]interface{} `json:"extra,omitempty"` + + // SkipHandler is an in-process directive set by an AfterVerifyHook that wants + // the HTTP layer to bypass the resource handler and settle inline. It is never + // serialized to the facilitator wire. + SkipHandler *SkipHandlerDirective `json:"-"` } // SettleResponse contains the settlement result @@ -99,6 +105,7 @@ type SettleResponse struct { Network Network `json:"network"` Amount string `json:"amount,omitempty"` Extensions map[string]interface{} `json:"extensions,omitempty"` + Extra map[string]interface{} `json:"extra,omitempty"` } // SettlementOverrides allows overriding settlement parameters. diff --git a/go/types/extensions.go b/go/types/extensions.go index 1b35f46b3a..dd37a39116 100644 --- a/go/types/extensions.go +++ b/go/types/extensions.go @@ -1,5 +1,14 @@ package types +// ResourceServerExtension is a resource-side extension. Implementations +// surface a stable `Key()` plus an enrichment callback used to expand the +// extension declaration on the route. +// +// Optional capabilities are exposed via the per-capability interfaces in +// `go/server_hooks.go` (e.g. `ResourceServerExtensionHookProvider`, +// `ResourceServerExtensionEnrichPaymentRequiredProvider`, +// `ResourceServerExtensionEnrichSettleResponseProvider`). The resource +// server type-asserts to those interfaces at registration time. type ResourceServerExtension interface { Key() string EnrichDeclaration(declaration interface{}, transportContext interface{}) interface{} diff --git a/go/types/v2.go b/go/types/v2.go index 928572dd17..3ab7c00dec 100644 --- a/go/types/v2.go +++ b/go/types/v2.go @@ -49,11 +49,18 @@ type PaymentRequired struct { Extensions map[string]interface{} `json:"extensions,omitempty"` } -// ResourceInfo describes the resource being accessed +// ResourceInfo describes the resource being accessed. +// +// ServiceName, Tags, and IconUrl are bazaar service metadata fields. See +// specs/extensions/bazaar.md "Service Metadata on `resource`" for the +// soft-drop validation rules facilitators apply during extraction. type ResourceInfo struct { - URL string `json:"url"` - Description string `json:"description,omitempty"` - MimeType string `json:"mimeType,omitempty"` + URL string `json:"url"` + Description string `json:"description,omitempty"` + MimeType string `json:"mimeType,omitempty"` + ServiceName string `json:"serviceName,omitempty"` + Tags []string `json:"tags,omitempty"` + IconUrl string `json:"iconUrl,omitempty"` } // SupportedKind represents a supported payment configuration diff --git a/java/README.md b/java/README.md index 3c1ac69e78..111f1021b5 100644 --- a/java/README.md +++ b/java/README.md @@ -1,10 +1,10 @@ # x402 Java -[![Coverage](https://img.shields.io/badge/coverage-90%25-brightgreen.svg)](https://github.com/coinbase/x402/java) -[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/coinbase/x402/blob/main/LICENSE) -[![Java Version](https://img.shields.io/badge/java-17%2B-orange)](https://github.com/coinbase/x402/java) +[![Coverage](https://img.shields.io/badge/coverage-90%25-brightgreen.svg)](https://github.com/x402-foundation/x402/java) +[![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg)](https://github.com/x402-foundation/x402/blob/main/LICENSE) +[![Java Version](https://img.shields.io/badge/java-17%2B-orange)](https://github.com/x402-foundation/x402/java) -Java implementation of [x402](https://github.com/coinbase/x402) +Java implementation of [x402](https://github.com/x402-foundation/x402) ## Quick Start @@ -47,7 +47,7 @@ To use this library, you need to build and install it locally: ```bash # Clone the repository -git clone https://github.com/coinbase/x402.git +git clone https://github.com/x402-foundation/x402.git cd x402/java # Build and install to your local Maven repository @@ -58,7 +58,7 @@ Then add the dependency to your Maven project: ```xml - com.coinbase + org.x402 x402 0.1.0-SNAPSHOT @@ -71,8 +71,8 @@ Then add the dependency to your Maven project: Integrate the `x402` filter into your servlet-based application to require payment for specific paths: ```java -import com.coinbase.x402.server.PaymentFilter; -import com.coinbase.x402.client.HttpFacilitatorClient; +import org.x402.server.PaymentFilter; +import org.x402.client.HttpFacilitatorClient; import java.math.BigInteger; import java.util.Map; @@ -113,8 +113,8 @@ public FilterRegistration paymentFilter(ServletContext servletContext) { To make HTTP requests that include payment proofs: ```java -import com.coinbase.x402.client.X402HttpClient; -import com.coinbase.x402.crypto.CryptoSigner; +import org.x402.client.X402HttpClient; +import org.x402.crypto.CryptoSigner; import java.math.BigInteger; import java.net.URI; @@ -149,8 +149,8 @@ System.out.println("Response: " + response.body()); Here's a complete example of a Spring Boot application with a paid joke API: ```java -import com.coinbase.x402.server.PaymentFilter; -import com.coinbase.x402.client.HttpFacilitatorClient; +import org.x402.server.PaymentFilter; +import org.x402.client.HttpFacilitatorClient; import javax.servlet.DispatcherType; import javax.servlet.FilterRegistration; import javax.servlet.ServletContext; diff --git a/java/pom.xml b/java/pom.xml index 9731e5b795..dd8d26666e 100644 --- a/java/pom.xml +++ b/java/pom.xml @@ -5,7 +5,7 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.coinbase + org.x402 x402 1.0.0-SNAPSHOT jar diff --git a/java/spotbugs-exclude.xml b/java/spotbugs-exclude.xml index a5700e7c93..4d5b7571a0 100644 --- a/java/spotbugs-exclude.xml +++ b/java/spotbugs-exclude.xml @@ -8,19 +8,19 @@ - + - + - + diff --git a/java/src/main/java/com/coinbase/x402/client/FacilitatorClient.java b/java/src/main/java/org/x402/client/FacilitatorClient.java similarity index 95% rename from java/src/main/java/com/coinbase/x402/client/FacilitatorClient.java rename to java/src/main/java/org/x402/client/FacilitatorClient.java index 320b8434f7..9798660bf0 100644 --- a/java/src/main/java/com/coinbase/x402/client/FacilitatorClient.java +++ b/java/src/main/java/org/x402/client/FacilitatorClient.java @@ -1,6 +1,6 @@ -package com.coinbase.x402.client; +package org.x402.client; -import com.coinbase.x402.model.PaymentRequirements; +import org.x402.model.PaymentRequirements; import java.io.IOException; import java.util.Set; diff --git a/java/src/main/java/com/coinbase/x402/client/HttpFacilitatorClient.java b/java/src/main/java/org/x402/client/HttpFacilitatorClient.java similarity index 97% rename from java/src/main/java/com/coinbase/x402/client/HttpFacilitatorClient.java rename to java/src/main/java/org/x402/client/HttpFacilitatorClient.java index 5d5638ad99..09fd159444 100644 --- a/java/src/main/java/com/coinbase/x402/client/HttpFacilitatorClient.java +++ b/java/src/main/java/org/x402/client/HttpFacilitatorClient.java @@ -1,7 +1,7 @@ -package com.coinbase.x402.client; +package org.x402.client; -import com.coinbase.x402.model.PaymentRequirements; -import com.coinbase.x402.util.Json; +import org.x402.model.PaymentRequirements; +import org.x402.util.Json; import java.io.IOException; import java.net.URI; diff --git a/java/src/main/java/com/coinbase/x402/client/Kind.java b/java/src/main/java/org/x402/client/Kind.java similarity index 95% rename from java/src/main/java/com/coinbase/x402/client/Kind.java rename to java/src/main/java/org/x402/client/Kind.java index 49bc16f915..888be00c3e 100644 --- a/java/src/main/java/com/coinbase/x402/client/Kind.java +++ b/java/src/main/java/org/x402/client/Kind.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.client; +package org.x402.client; /** Identifies a payment scheme+network pair that a facilitator supports. */ public class Kind { diff --git a/java/src/main/java/com/coinbase/x402/client/SettlementResponse.java b/java/src/main/java/org/x402/client/SettlementResponse.java similarity index 92% rename from java/src/main/java/com/coinbase/x402/client/SettlementResponse.java rename to java/src/main/java/org/x402/client/SettlementResponse.java index 636e761fec..66150635a1 100644 --- a/java/src/main/java/com/coinbase/x402/client/SettlementResponse.java +++ b/java/src/main/java/org/x402/client/SettlementResponse.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.client; +package org.x402.client; /** JSON returned by POST /settle on the facilitator. */ public class SettlementResponse { diff --git a/java/src/main/java/com/coinbase/x402/client/VerificationResponse.java b/java/src/main/java/org/x402/client/VerificationResponse.java similarity index 89% rename from java/src/main/java/com/coinbase/x402/client/VerificationResponse.java rename to java/src/main/java/org/x402/client/VerificationResponse.java index e34c843c97..946a835fe5 100644 --- a/java/src/main/java/com/coinbase/x402/client/VerificationResponse.java +++ b/java/src/main/java/org/x402/client/VerificationResponse.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.client; +package org.x402.client; /** JSON returned by POST /verify on the facilitator. */ public class VerificationResponse { diff --git a/java/src/main/java/com/coinbase/x402/client/X402HttpClient.java b/java/src/main/java/org/x402/client/X402HttpClient.java similarity index 94% rename from java/src/main/java/com/coinbase/x402/client/X402HttpClient.java rename to java/src/main/java/org/x402/client/X402HttpClient.java index d646ee29c3..5b1c258fca 100644 --- a/java/src/main/java/com/coinbase/x402/client/X402HttpClient.java +++ b/java/src/main/java/org/x402/client/X402HttpClient.java @@ -1,8 +1,8 @@ -package com.coinbase.x402.client; +package org.x402.client; -import com.coinbase.x402.crypto.CryptoSigner; -import com.coinbase.x402.crypto.CryptoSignException; -import com.coinbase.x402.model.PaymentPayload; +import org.x402.crypto.CryptoSigner; +import org.x402.crypto.CryptoSignException; +import org.x402.model.PaymentPayload; import java.io.IOException; import java.math.BigInteger; diff --git a/java/src/main/java/com/coinbase/x402/crypto/CryptoSignException.java b/java/src/main/java/org/x402/crypto/CryptoSignException.java similarity index 94% rename from java/src/main/java/com/coinbase/x402/crypto/CryptoSignException.java rename to java/src/main/java/org/x402/crypto/CryptoSignException.java index 4d92d90130..4aba7a43f2 100644 --- a/java/src/main/java/com/coinbase/x402/crypto/CryptoSignException.java +++ b/java/src/main/java/org/x402/crypto/CryptoSignException.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.crypto; +package org.x402.crypto; /** * Exception thrown when cryptographic signing operations fail. diff --git a/java/src/main/java/com/coinbase/x402/crypto/CryptoSigner.java b/java/src/main/java/org/x402/crypto/CryptoSigner.java similarity index 97% rename from java/src/main/java/com/coinbase/x402/crypto/CryptoSigner.java rename to java/src/main/java/org/x402/crypto/CryptoSigner.java index 52980bbdeb..7b0e98058f 100644 --- a/java/src/main/java/com/coinbase/x402/crypto/CryptoSigner.java +++ b/java/src/main/java/org/x402/crypto/CryptoSigner.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.crypto; +package org.x402.crypto; import java.util.Map; diff --git a/java/src/main/java/com/coinbase/x402/model/Authorization.java b/java/src/main/java/org/x402/model/Authorization.java similarity index 96% rename from java/src/main/java/com/coinbase/x402/model/Authorization.java rename to java/src/main/java/org/x402/model/Authorization.java index 8f6f93c686..2319b31ef8 100644 --- a/java/src/main/java/com/coinbase/x402/model/Authorization.java +++ b/java/src/main/java/org/x402/model/Authorization.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.model; +package org.x402.model; /** * ERC-3009 authorization information within a payment payload. diff --git a/java/src/main/java/com/coinbase/x402/model/ExactSchemePayload.java b/java/src/main/java/org/x402/model/ExactSchemePayload.java similarity index 93% rename from java/src/main/java/com/coinbase/x402/model/ExactSchemePayload.java rename to java/src/main/java/org/x402/model/ExactSchemePayload.java index 0f592bf21f..8f92818084 100644 --- a/java/src/main/java/com/coinbase/x402/model/ExactSchemePayload.java +++ b/java/src/main/java/org/x402/model/ExactSchemePayload.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.model; +package org.x402.model; /** * Payload structure for the "exact" EVM payment scheme. diff --git a/java/src/main/java/com/coinbase/x402/model/PaymentPayload.java b/java/src/main/java/org/x402/model/PaymentPayload.java similarity index 93% rename from java/src/main/java/com/coinbase/x402/model/PaymentPayload.java rename to java/src/main/java/org/x402/model/PaymentPayload.java index 3a31c8246d..ae2543e391 100644 --- a/java/src/main/java/com/coinbase/x402/model/PaymentPayload.java +++ b/java/src/main/java/org/x402/model/PaymentPayload.java @@ -1,6 +1,6 @@ -package com.coinbase.x402.model; +package org.x402.model; -import com.coinbase.x402.util.Json; +import org.x402.util.Json; import java.io.IOException; import java.nio.charset.StandardCharsets; diff --git a/java/src/main/java/com/coinbase/x402/model/PaymentRequiredResponse.java b/java/src/main/java/org/x402/model/PaymentRequiredResponse.java similarity index 89% rename from java/src/main/java/com/coinbase/x402/model/PaymentRequiredResponse.java rename to java/src/main/java/org/x402/model/PaymentRequiredResponse.java index b332aca13d..e97dee8267 100644 --- a/java/src/main/java/com/coinbase/x402/model/PaymentRequiredResponse.java +++ b/java/src/main/java/org/x402/model/PaymentRequiredResponse.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.model; +package org.x402.model; import java.util.ArrayList; import java.util.List; diff --git a/java/src/main/java/com/coinbase/x402/model/PaymentRequirements.java b/java/src/main/java/org/x402/model/PaymentRequirements.java similarity index 95% rename from java/src/main/java/com/coinbase/x402/model/PaymentRequirements.java rename to java/src/main/java/org/x402/model/PaymentRequirements.java index 34d6b39b44..bee6634cb4 100644 --- a/java/src/main/java/com/coinbase/x402/model/PaymentRequirements.java +++ b/java/src/main/java/org/x402/model/PaymentRequirements.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.model; +package org.x402.model; import java.util.Map; diff --git a/java/src/main/java/com/coinbase/x402/model/SettlementResponseHeader.java b/java/src/main/java/org/x402/model/SettlementResponseHeader.java similarity index 97% rename from java/src/main/java/com/coinbase/x402/model/SettlementResponseHeader.java rename to java/src/main/java/org/x402/model/SettlementResponseHeader.java index a41c970f8b..5e1faaecc5 100644 --- a/java/src/main/java/com/coinbase/x402/model/SettlementResponseHeader.java +++ b/java/src/main/java/org/x402/model/SettlementResponseHeader.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.model; +package org.x402.model; import com.fasterxml.jackson.annotation.JsonInclude; diff --git a/java/src/main/java/com/coinbase/x402/server/PaymentFilter.java b/java/src/main/java/org/x402/server/PaymentFilter.java similarity index 95% rename from java/src/main/java/com/coinbase/x402/server/PaymentFilter.java rename to java/src/main/java/org/x402/server/PaymentFilter.java index d850efab6d..e049a76463 100644 --- a/java/src/main/java/com/coinbase/x402/server/PaymentFilter.java +++ b/java/src/main/java/org/x402/server/PaymentFilter.java @@ -1,14 +1,14 @@ -package com.coinbase.x402.server; +package org.x402.server; -import com.coinbase.x402.client.FacilitatorClient; -import com.coinbase.x402.client.SettlementResponse; -import com.coinbase.x402.client.VerificationResponse; -import com.coinbase.x402.model.ExactSchemePayload; -import com.coinbase.x402.model.PaymentPayload; -import com.coinbase.x402.model.PaymentRequirements; -import com.coinbase.x402.model.PaymentRequiredResponse; -import com.coinbase.x402.model.SettlementResponseHeader; -import com.coinbase.x402.util.Json; +import org.x402.client.FacilitatorClient; +import org.x402.client.SettlementResponse; +import org.x402.client.VerificationResponse; +import org.x402.model.ExactSchemePayload; +import org.x402.model.PaymentPayload; +import org.x402.model.PaymentRequirements; +import org.x402.model.PaymentRequiredResponse; +import org.x402.model.SettlementResponseHeader; +import org.x402.util.Json; import jakarta.servlet.Filter; import jakarta.servlet.FilterChain; diff --git a/java/src/main/java/com/coinbase/x402/util/Json.java b/java/src/main/java/org/x402/util/Json.java similarity index 95% rename from java/src/main/java/com/coinbase/x402/util/Json.java rename to java/src/main/java/org/x402/util/Json.java index 1a2554490c..fca8364ebd 100644 --- a/java/src/main/java/com/coinbase/x402/util/Json.java +++ b/java/src/main/java/org/x402/util/Json.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.util; +package org.x402.util; import com.fasterxml.jackson.annotation.JsonInclude; import com.fasterxml.jackson.databind.DeserializationFeature; diff --git a/java/src/test/java/com/coinbase/x402/client/HttpFacilitatorClientTest.java b/java/src/test/java/org/x402/client/HttpFacilitatorClientTest.java similarity index 98% rename from java/src/test/java/com/coinbase/x402/client/HttpFacilitatorClientTest.java rename to java/src/test/java/org/x402/client/HttpFacilitatorClientTest.java index 79ee175720..3d27cecb2c 100644 --- a/java/src/test/java/com/coinbase/x402/client/HttpFacilitatorClientTest.java +++ b/java/src/test/java/org/x402/client/HttpFacilitatorClientTest.java @@ -1,6 +1,6 @@ -package com.coinbase.x402.client; +package org.x402.client; -import com.coinbase.x402.model.PaymentRequirements; +import org.x402.model.PaymentRequirements; import com.github.tomakehurst.wiremock.WireMockServer; import org.junit.jupiter.api.*; import static com.github.tomakehurst.wiremock.client.WireMock.*; diff --git a/java/src/test/java/com/coinbase/x402/client/X402HttpClientTest.java b/java/src/test/java/org/x402/client/X402HttpClientTest.java similarity index 95% rename from java/src/test/java/com/coinbase/x402/client/X402HttpClientTest.java rename to java/src/test/java/org/x402/client/X402HttpClientTest.java index 4e67dad10a..6eb074992d 100644 --- a/java/src/test/java/com/coinbase/x402/client/X402HttpClientTest.java +++ b/java/src/test/java/org/x402/client/X402HttpClientTest.java @@ -1,7 +1,7 @@ -package com.coinbase.x402.client; +package org.x402.client; -import com.coinbase.x402.crypto.CryptoSigner; -import com.coinbase.x402.crypto.CryptoSignException; +import org.x402.crypto.CryptoSigner; +import org.x402.crypto.CryptoSignException; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.Mock; diff --git a/java/src/test/java/com/coinbase/x402/integration/FilterIntegrationTest.java b/java/src/test/java/org/x402/integration/FilterIntegrationTest.java similarity index 86% rename from java/src/test/java/com/coinbase/x402/integration/FilterIntegrationTest.java rename to java/src/test/java/org/x402/integration/FilterIntegrationTest.java index aa7ffd64b0..6f1af9ce2f 100644 --- a/java/src/test/java/com/coinbase/x402/integration/FilterIntegrationTest.java +++ b/java/src/test/java/org/x402/integration/FilterIntegrationTest.java @@ -1,9 +1,9 @@ -package com.coinbase.x402.integration; +package org.x402.integration; -import com.coinbase.x402.client.FacilitatorClient; -import com.coinbase.x402.client.VerificationResponse; -import com.coinbase.x402.model.PaymentPayload; -import com.coinbase.x402.server.PaymentFilter; +import org.x402.client.FacilitatorClient; +import org.x402.client.VerificationResponse; +import org.x402.model.PaymentPayload; +import org.x402.server.PaymentFilter; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; @@ -37,13 +37,13 @@ class FilterIntegrationTest { static void startJetty() throws Exception { // ----- stub facilitator ----------------------------------------- FacilitatorClient stubFac = new FacilitatorClient() { - @Override public VerificationResponse verify(String hdr, com.coinbase.x402.model.PaymentRequirements r) { + @Override public VerificationResponse verify(String hdr, org.x402.model.PaymentRequirements r) { VerificationResponse vr = new VerificationResponse(); vr.isValid = true; // always accept return vr; } - @Override public com.coinbase.x402.client.SettlementResponse settle(String h, com.coinbase.x402.model.PaymentRequirements r) { return new com.coinbase.x402.client.SettlementResponse(); } - @Override public java.util.Set supported() { return java.util.Set.of(); } + @Override public org.x402.client.SettlementResponse settle(String h, org.x402.model.PaymentRequirements r) { return new org.x402.client.SettlementResponse(); } + @Override public java.util.Set supported() { return java.util.Set.of(); } }; // price-table: /private costs 1 (value irrelevant here) diff --git a/java/src/test/java/com/coinbase/x402/model/PaymentPayloadTest.java b/java/src/test/java/org/x402/model/PaymentPayloadTest.java similarity index 96% rename from java/src/test/java/com/coinbase/x402/model/PaymentPayloadTest.java rename to java/src/test/java/org/x402/model/PaymentPayloadTest.java index f7c94b1ea9..dc1d443e0d 100644 --- a/java/src/test/java/com/coinbase/x402/model/PaymentPayloadTest.java +++ b/java/src/test/java/org/x402/model/PaymentPayloadTest.java @@ -1,4 +1,4 @@ -package com.coinbase.x402.model; +package org.x402.model; import org.junit.jupiter.api.Test; diff --git a/java/src/test/java/com/coinbase/x402/server/PaymentFilterTest.java b/java/src/test/java/org/x402/server/PaymentFilterTest.java similarity index 98% rename from java/src/test/java/com/coinbase/x402/server/PaymentFilterTest.java rename to java/src/test/java/org/x402/server/PaymentFilterTest.java index 9fa6f70d59..7db545dc33 100644 --- a/java/src/test/java/com/coinbase/x402/server/PaymentFilterTest.java +++ b/java/src/test/java/org/x402/server/PaymentFilterTest.java @@ -1,11 +1,11 @@ -package com.coinbase.x402.server; - -import com.coinbase.x402.client.FacilitatorClient; -import com.coinbase.x402.client.SettlementResponse; -import com.coinbase.x402.client.VerificationResponse; -import com.coinbase.x402.model.Authorization; -import com.coinbase.x402.model.ExactSchemePayload; -import com.coinbase.x402.model.PaymentPayload; +package org.x402.server; + +import org.x402.client.FacilitatorClient; +import org.x402.client.SettlementResponse; +import org.x402.client.VerificationResponse; +import org.x402.model.Authorization; +import org.x402.model.ExactSchemePayload; +import org.x402.model.PaymentPayload; import jakarta.servlet.FilterChain; import jakarta.servlet.ServletRequest; import jakarta.servlet.ServletResponse; diff --git a/package.json b/package.json index bda4bf1da6..44f9e67e1b 100644 --- a/package.json +++ b/package.json @@ -1,4 +1,4 @@ { "private": true, - "packageManager": "pnpm@10.7.0" + "packageManager": "pnpm@11.1.1" } \ No newline at end of file diff --git a/python/legacy/README.md b/python/legacy/README.md index 7901d15059..804507ebe3 100644 --- a/python/legacy/README.md +++ b/python/legacy/README.md @@ -1,5 +1,9 @@ # x402 Python +> **Deprecated (v1)** +> The code in `python/legacy` implements x402 **v1**. It is **deprecated** and will only receive **security patches**. Please migrate to **v2** on PyPI: use the `x402` package at version **> 2.0.0** (imports and APIs change). See the [Migration guide: v1 to v2](https://docs.x402.org/guides/migration-v1-to-v2). +> Legacy examples are available at git tag `archive/legacy-v1-examples`. + Python package for the x402 payments protocol. ## Installation @@ -218,4 +222,4 @@ async def foo(request: Request, response: Response): ) ``` -For more examples and advanced usage patterns, check out our [examples directory](https://github.com/coinbase/x402/tree/main/examples/python/legacy/). +For more examples and advanced usage patterns, check out our [examples directory](https://github.com/x402-foundation/x402/tree/main/examples/python/legacy/). diff --git a/python/legacy/pyproject.toml b/python/legacy/pyproject.toml index a34e26bab7..41bc42a2c7 100644 --- a/python/legacy/pyproject.toml +++ b/python/legacy/pyproject.toml @@ -6,7 +6,7 @@ readme = "README.md" license = { text = "Apache-2.0" } authors = [ { name = "erik", email = "erik.reppel@coinbase.com" }, - { name = "Coinbase Developer Platform", email = "" } + { name = "x402 Foundation", email = "" } ] requires-python = ">=3.10" keywords = ["x402", "sdk", "crypto", "cdp", "payments", "web3"] @@ -44,3 +44,6 @@ packages = ["src/x402"] [tool.hatch.metadata] allow-direct-references = true + +[tool.uv] +exclude-newer = "3 days" diff --git a/python/x402/CHANGELOG.md b/python/x402/CHANGELOG.md index 20d25d31f8..a35496f7f9 100644 --- a/python/x402/CHANGELOG.md +++ b/python/x402/CHANGELOG.md @@ -2,63 +2,116 @@ +## [2.10.0] - 2026-05-13 + +### Added + +- Add Radius Network (chain ID 723487) and Radius Testnet (chain ID 72344) support with SBC as the default stablecoin ([#radius-network-default-asset](https://github.com/x402-foundation/x402/pull/radius-network-default-asset)) +- Added the TVM exact-payment mechanism to the Python SDK, including client, server, facilitator, and example coverage for TON testnet/mainnet flows. ([#tvm-python-sdk](https://github.com/x402-foundation/x402/pull/tvm-python-sdk)) +- Added Bazaar service metadata fields (`service_name`, `tags`, `icon_url`) on `ResourceInfo`, plus `_is_valid_service_name` / `_sanitize_tags` / `_is_valid_icon_url` / `_sanitize_resource_service_metadata` helpers in `x402.extensions.bazaar.facilitator` that `extract_discovery_info` now applies with soft-drop semantics. ([#150](https://github.com/x402-foundation/x402/pull/150)) +- Log the `EXTENSION-RESPONSES` header from facilitator verify/settle responses. The HTTP facilitator client decodes the header and logs allowlisted fields (`status`, `rejectedReason`, `reason`, `code`) without attaching data to `VerifyResponse` or `SettleResponse`. ([#2161](https://github.com/x402-foundation/x402/pull/2161)) + +### Misc + +- Expose `DEFAULT_MAX_FEE_PER_GAS` and `DEFAULT_MAX_PRIORITY_FEE_PER_GAS` from `x402.mechanisms.evm.constants` and use them as the fallback when fee estimation is unavailable in `sign_erc20_approval_transaction`. Mirrors the TypeScript SDK's named constants; numeric defaults (1 gwei / 0.1 gwei) are unchanged. ([#erc20-approval-default-gas-fees](https://github.com/x402-foundation/x402/pull/erc20-approval-default-gas-fees)) + + +## [2.9.0] - 2026-04-27 + +### Added + +- Added `extensions` parameter to MCP payment wrapper config and `declare_mcp_discovery_extension` helper so paid MCP tools can declare Bazaar discovery metadata and appear in `/discovery/resources`. ([#2087](https://github.com/x402-foundation/x402/pull/2087)) + + +## [2.8.0] - 2026-04-17 + +### Added + +- Add Arbitrum One (chain ID 42161) and Arbitrum Sepolia (chain ID 421614) support with USDC as the default stablecoin ([#1877](https://github.com/x402-foundation/x402/pull/1877)) +- Add `upto` scheme support for Python SDK, including EVM client, server, and facilitator implementations with partial settlement support ([#2023](https://github.com/x402-foundation/x402/pull/2023)) + + +## [2.7.0] - 2026-04-13 + +### Added + +- Add optional `extra.memo` support to SVM exact scheme. When present, the client uses the seller-provided memo as Memo instruction data instead of a random nonce, and the facilitator verifies the memo content matches. ([#1682](https://github.com/x402-foundation/x402/pull/1682)) + + +## [2.6.0] - 2026-04-02 + +### Fixed + +- Fixed author attribution to reference x402 Foundation instead of Coinbase ([#123](https://github.com/x402-foundation/x402/pull/123)) +- Fixed race condition in lazy facilitator initialization for FastAPI and Flask middleware under concurrent requests. ([#1584](https://github.com/x402-foundation/x402/pull/1584)) +- Fix extra: null incompatibility between python facilitator and TS zod schema ([#1762](https://github.com/x402-foundation/x402/pull/1762)) + +### Added + +- Add Mezo Testnet (chain ID 31611) support with mUSD as the default stablecoin ([#mezo-testnet-default-asset](https://github.com/x402-foundation/x402/pull/mezo-testnet-default-asset)) +- Add Polygon mainnet (chain ID 137) support with USDC as the default stablecoin ([#polygon-support](https://github.com/x402-foundation/x402/pull/polygon-support)) +- Add Stable mainnet (chain ID 988) support with USDT0 as the default stablecoin ([#stable-support](https://github.com/x402-foundation/x402/pull/stable-support)) +- Add Stable testnet (chain ID 2201) support with USDT0 as the default stablecoin ([#stable-testnet-support](https://github.com/x402-foundation/x402/pull/stable-testnet-support)) +- Added dynamic route support to the Bazaar discovery extension — servers can now declare ``[param]`` route segments that consolidate to a single catalog entry per route template, with automatic ``pathParams`` enrichment and ``:param``-style ``routeTemplate`` in discovery output. ([#424](https://github.com/x402-foundation/x402/pull/424)) + + ## [2.5.0] - 2026-03-19 ### Fixed -- Fixed Python HTTP middleware to return `502` instead of `500` when the facilitator responds with invalid JSON or schema-invalid data. ([#545](https://github.com/coinbase/x402/pull/545)) +- Fixed Python HTTP middleware to return `502` instead of `500` when the facilitator responds with invalid JSON or schema-invalid data. ([#545](https://github.com/x402-foundation/x402/pull/545)) ### Added -- Added Permit2 support to the Python SDK exact EVM mechanism with full TS/Go parity. The client routes to Permit2 (`PermitWitnessTransferFrom`) when `assetTransferMethod == "permit2"` in payment requirements extra, and the facilitator verifies and settles via the `x402ExactPermit2Proxy` contract. Includes `eip2612GasSponsoring` and `erc20ApprovalGasSponsoring` extension support for gasless Permit2 approval flows, universal signature verification via `signer.verify_typed_data` (EOA + EIP-1271 + ERC-6492), and `settleWithPermit` settlement path. Added E2E `/protected-permit2`, `/protected-permit2-eip2612`, and `/protected-permit2-erc20` endpoints to Flask server, and updated httpx client for cross-language Permit2 testing. ([#689](https://github.com/coinbase/x402/pull/689)) +- Added Permit2 support to the Python SDK exact EVM mechanism with full TS/Go parity. The client routes to Permit2 (`PermitWitnessTransferFrom`) when `assetTransferMethod == "permit2"` in payment requirements extra, and the facilitator verifies and settles via the `x402ExactPermit2Proxy` contract. Includes `eip2612GasSponsoring` and `erc20ApprovalGasSponsoring` extension support for gasless Permit2 approval flows, universal signature verification via `signer.verify_typed_data` (EOA + EIP-1271 + ERC-6492), and `settleWithPermit` settlement path. Added E2E `/protected-permit2`, `/protected-permit2-eip2612`, and `/protected-permit2-erc20` endpoints to Flask server, and updated httpx client for cross-language Permit2 testing. ([#689](https://github.com/x402-foundation/x402/pull/689)) ## [2.4.0] - 2026-03-16 ### Fixed -- Fixed paywall config injection targeting causing SVG parse errors in the browser ([#1550](https://github.com/coinbase/x402/pull/1550)) +- Fixed paywall config injection targeting causing SVG parse errors in the browser ([#1550](https://github.com/x402-foundation/x402/pull/1550)) ### Added -- Simulate transaction in verify and (optional) settle; Added multicall utility for efficient rpc calls; Fixed undeployed smart wallet handling to prevent facilitator grieving and account for implementation dependent verifyTypedData; Enforce strict amount equality per spec in evm exact; Fix extra field passthrough in resource configs ([#1474](https://github.com/coinbase/x402/pull/1474)) +- Simulate transaction in verify and (optional) settle; Added multicall utility for efficient rpc calls; Fixed undeployed smart wallet handling to prevent facilitator grieving and account for implementation dependent verifyTypedData; Enforce strict amount equality per spec in evm exact; Fix extra field passthrough in resource configs ([#1474](https://github.com/x402-foundation/x402/pull/1474)) ## [2.3.0] - 2026-03-06 ### Fixed -- Add in-memory SettlementCache to prevent duplicate SVM transaction settlement during on-chain confirmation window ([#svm-duplicate-settlement](https://github.com/coinbase/x402/pull/svm-duplicate-settlement)) -- Added serialize_by_alias=True to BaseX402Model so model_dump_json() produces spec-compliant camelCase by default ([#1120](https://github.com/coinbase/x402/pull/1120)) -- Auto-wrap eth_account LocalAccount in EthAccountSigner when passed to ExactEvmScheme or ExactEvmSchemeV1 ([#1121](https://github.com/coinbase/x402/pull/1121)) -- Added assetTransferMethod and supportsEip2612 flag to defaultAssets ([#1359](https://github.com/coinbase/x402/pull/1359)) -- Added dynamic function for servers to generate custom response for settlement failures defaulting to empty ([#1430](https://github.com/coinbase/x402/pull/1430)) +- Add in-memory SettlementCache to prevent duplicate SVM transaction settlement during on-chain confirmation window ([#svm-duplicate-settlement](https://github.com/x402-foundation/x402/pull/svm-duplicate-settlement)) +- Added serialize_by_alias=True to BaseX402Model so model_dump_json() produces spec-compliant camelCase by default ([#1120](https://github.com/x402-foundation/x402/pull/1120)) +- Auto-wrap eth_account LocalAccount in EthAccountSigner when passed to ExactEvmScheme or ExactEvmSchemeV1 ([#1121](https://github.com/x402-foundation/x402/pull/1121)) +- Added assetTransferMethod and supportsEip2612 flag to defaultAssets ([#1359](https://github.com/x402-foundation/x402/pull/1359)) +- Added dynamic function for servers to generate custom response for settlement failures defaulting to empty ([#1430](https://github.com/x402-foundation/x402/pull/1430)) ### Added -- Separated v1 legacy network name resolution from v2 CAIP-2 resolution; get_evm_chain_id now only accepts eip155:CHAIN_ID format, v1 code uses evm.v1.utils ([#split-v1-v2-networks](https://github.com/coinbase/x402/pull/split-v1-v2-networks)) +- Separated v1 legacy network name resolution from v2 CAIP-2 resolution; get_evm_chain_id now only accepts eip155:CHAIN_ID format, v1 code uses evm.v1.utils ([#split-v1-v2-networks](https://github.com/x402-foundation/x402/pull/split-v1-v2-networks)) ## [2.2.0] - 2026-02-20 ### Fixed -- Fixed SVM V1 client transaction signing to use `VersionedTransaction.populate()` with explicit signature slots, matching the V2 approach and fixing "not enough signers" errors. ([#v1-svm-signers](https://github.com/coinbase/x402/pull/v1-svm-signers)) -- Added payment-identifier extension for tracking and validating payment identifiers ([#1111](https://github.com/coinbase/x402/pull/1111)) +- Fixed SVM V1 client transaction signing to use `VersionedTransaction.populate()` with explicit signature slots, matching the V2 approach and fixing "not enough signers" errors. ([#v1-svm-signers](https://github.com/x402-foundation/x402/pull/v1-svm-signers)) +- Added payment-identifier extension for tracking and validating payment identifiers ([#1111](https://github.com/x402-foundation/x402/pull/1111)) ### Added -- Upgraded facilitator extension registration from string keys to FacilitatorExtension dataclass. Added FacilitatorContext passed through SchemeNetworkFacilitator.verify/settle for mechanism access to extension capabilities. ([#facilitator-extension-objects](https://github.com/coinbase/x402/pull/facilitator-extension-objects)) -- Increased EVM validAfter buffer from 30 seconds to 10 minutes for consistency with TypeScript SDK. ([#validafter-buffer](https://github.com/coinbase/x402/pull/validafter-buffer)) +- Upgraded facilitator extension registration from string keys to FacilitatorExtension dataclass. Added FacilitatorContext passed through SchemeNetworkFacilitator.verify/settle for mechanism access to extension capabilities. ([#facilitator-extension-objects](https://github.com/x402-foundation/x402/pull/facilitator-extension-objects)) +- Increased EVM validAfter buffer from 30 seconds to 10 minutes for consistency with TypeScript SDK. ([#validafter-buffer](https://github.com/x402-foundation/x402/pull/validafter-buffer)) ## [2.1.0] - 2026-02-11 ### Added -- Add MegaETH mainnet (chain ID 4326) support with USDM as the default stablecoin ([#megaeth-support](https://github.com/coinbase/x402/pull/megaeth-support)) -- Added memo instruction with random nonce to SVM transactions to ensure uniqueness and prevent duplicate transaction attacks ([#1048](https://github.com/coinbase/x402/pull/1048)) -- Added MCP transport integration for x402 payment protocol ([#1131](https://github.com/coinbase/x402/pull/1131)) +- Add MegaETH mainnet (chain ID 4326) support with USDM as the default stablecoin ([#megaeth-support](https://github.com/x402-foundation/x402/pull/megaeth-support)) +- Added memo instruction with random nonce to SVM transactions to ensure uniqueness and prevent duplicate transaction attacks ([#1048](https://github.com/x402-foundation/x402/pull/1048)) +- Added MCP transport integration for x402 payment protocol ([#1131](https://github.com/x402-foundation/x402/pull/1131)) ## 2.0.0 diff --git a/python/x402/README.md b/python/x402/README.md index acf7bbf58b..05bfae0923 100644 --- a/python/x402/README.md +++ b/python/x402/README.md @@ -15,9 +15,10 @@ uv add x402[requests] # requests client uv add x402[fastapi] # FastAPI middleware uv add x402[flask] # Flask middleware -# Blockchain mechanisms (pick one or both) +# Blockchain mechanisms (pick one or more) uv add x402[evm] # EVM/Ethereum uv add x402[svm] # Solana +uv add x402[tvm] # TON/TVM # Multiple extras uv add x402[fastapi,httpx,evm] @@ -53,6 +54,34 @@ client.register("eip155:*", ExactEvmScheme(signer=my_signer)) payload = client.create_payment_payload(payment_required) ``` +### TVM Client (Async) + +```python +import os + +from x402 import x402Client +from x402.mechanisms.tvm import ( + TVM_PROVIDER_TONAPI, + TVM_TESTNET, + WalletV5R1Config, + WalletV5R1MnemonicSigner, +) +from x402.mechanisms.tvm.exact import ExactTvmScheme + +tvm_config = WalletV5R1Config.from_private_key( + TVM_TESTNET, + os.environ["TVM_PRIVATE_KEY"], +) +tvm_config.api_key = os.environ.get("TONCENTER_API_KEY") +# Optional: use TonAPI instead of Toncenter. +# tvm_config.provider = TVM_PROVIDER_TONAPI +# tvm_config.api_key = os.environ.get("TONAPI_API_KEY") +# tvm_config.provider_base_url = os.environ.get("TONAPI_BASE_URL") + +client = x402Client() +client.register(TVM_TESTNET, ExactTvmScheme(WalletV5R1MnemonicSigner(tvm_config))) +``` + ### Server (Async) ```python @@ -153,11 +182,16 @@ Use `from_config()` for declarative setup: ```python from x402 import x402Client, x402ClientConfig, SchemeRegistration +from x402 import prefer_network +from x402.mechanisms.evm.exact import ExactEvmScheme +from x402.mechanisms.svm.exact import ExactSvmScheme +from x402.mechanisms.tvm.exact import ExactTvmScheme config = x402ClientConfig( schemes=[ SchemeRegistration(network="eip155:*", client=ExactEvmScheme(signer)), SchemeRegistration(network="solana:*", client=ExactSvmScheme(signer)), + SchemeRegistration(network="tvm:*", client=ExactTvmScheme(tvm_signer)), ], policies=[prefer_network("eip155:8453")], ) @@ -256,8 +290,9 @@ client.register("eip155:8453", CustomScheme()) - `x402.http` - HTTP clients, middleware, and facilitator client - `x402.mechanisms.evm` - EVM/Ethereum implementation - `x402.mechanisms.svm` - Solana implementation +- `x402.mechanisms.tvm` - TON/TVM implementation - `x402.extensions` - Protocol extensions (Bazaar discovery) ## Examples -See [examples/python](https://github.com/coinbase/x402/tree/main/examples/python). +See [examples/python](https://github.com/x402-foundation/x402/tree/main/examples/python). diff --git a/python/x402/__init__.py b/python/x402/__init__.py index 619b316efe..1401ef353d 100644 --- a/python/x402/__init__.py +++ b/python/x402/__init__.py @@ -137,7 +137,7 @@ x402ResourceServerSync, ) -__version__ = "2.5.0" +__version__ = "2.10.0" __all__ = [ # Version diff --git a/python/x402/changelog.d/1584.bugfix.md b/python/x402/changelog.d/1584.bugfix.md deleted file mode 100644 index 15b102d338..0000000000 --- a/python/x402/changelog.d/1584.bugfix.md +++ /dev/null @@ -1 +0,0 @@ -Fixed race condition in lazy facilitator initialization for FastAPI and Flask middleware under concurrent requests. diff --git a/python/x402/changelog.d/1762.bugfix.md b/python/x402/changelog.d/1762.bugfix.md deleted file mode 100644 index bb194ca8d5..0000000000 --- a/python/x402/changelog.d/1762.bugfix.md +++ /dev/null @@ -1 +0,0 @@ -Fix extra: null incompatibility between python facilitator and TS zod schema diff --git a/python/x402/changelog.d/424.feature.md b/python/x402/changelog.d/424.feature.md deleted file mode 100644 index 2fd38e1354..0000000000 --- a/python/x402/changelog.d/424.feature.md +++ /dev/null @@ -1 +0,0 @@ -Added dynamic route support to the Bazaar discovery extension — servers can now declare ``[param]`` route segments that consolidate to a single catalog entry per route template, with automatic ``pathParams`` enrichment and ``:param``-style ``routeTemplate`` in discovery output. diff --git a/python/x402/changelog.d/add-arbitrum-one-and-arbitrum-sepolia-default-stablecoin.md b/python/x402/changelog.d/add-arbitrum-one-and-arbitrum-sepolia-default-stablecoin.md deleted file mode 100644 index 9db05707e8..0000000000 --- a/python/x402/changelog.d/add-arbitrum-one-and-arbitrum-sepolia-default-stablecoin.md +++ /dev/null @@ -1 +0,0 @@ -Add Arbitrum One (chain ID 42161) and Arbitrum Sepolid (chain ID 421614) support with USDC as the default stablecoin \ No newline at end of file diff --git a/python/x402/changelog.d/mezo-testnet-default-asset.feature.md b/python/x402/changelog.d/mezo-testnet-default-asset.feature.md deleted file mode 100644 index 2afafe9f2d..0000000000 --- a/python/x402/changelog.d/mezo-testnet-default-asset.feature.md +++ /dev/null @@ -1 +0,0 @@ -Add Mezo Testnet (chain ID 31611) support with mUSD as the default stablecoin diff --git a/python/x402/changelog.d/polygon-support.feature.md b/python/x402/changelog.d/polygon-support.feature.md deleted file mode 100644 index dec21aa58e..0000000000 --- a/python/x402/changelog.d/polygon-support.feature.md +++ /dev/null @@ -1 +0,0 @@ -Add Polygon mainnet (chain ID 137) support with USDC as the default stablecoin diff --git a/python/x402/changelog.d/stable-support.feature.md b/python/x402/changelog.d/stable-support.feature.md deleted file mode 100644 index 3af2817ed9..0000000000 --- a/python/x402/changelog.d/stable-support.feature.md +++ /dev/null @@ -1 +0,0 @@ -Add Stable mainnet (chain ID 988) support with USDT0 as the default stablecoin diff --git a/python/x402/changelog.d/stable-testnet-support.feature.md b/python/x402/changelog.d/stable-testnet-support.feature.md deleted file mode 100644 index e9fb7c99c8..0000000000 --- a/python/x402/changelog.d/stable-testnet-support.feature.md +++ /dev/null @@ -1 +0,0 @@ -Add Stable testnet (chain ID 2201) support with USDT0 as the default stablecoin diff --git a/python/x402/extensions/README.md b/python/x402/extensions/README.md index efa53f3822..d651e741b4 100644 --- a/python/x402/extensions/README.md +++ b/python/x402/extensions/README.md @@ -65,6 +65,34 @@ routes = { } ``` +#### MCP Tool + +For paid MCP tools, use `declare_mcp_discovery_extension` instead: + +```python +from x402.mcp import create_payment_wrapper +from x402.extensions.bazaar import DeclareMcpDiscoveryConfig, declare_mcp_discovery_extension + +weather_discovery = declare_mcp_discovery_extension( + DeclareMcpDiscoveryConfig( + tool_name="get_weather", + description="Get current weather for a city", + input_schema={ + "properties": {"city": {"type": "string", "description": "City name"}}, + "required": ["city"], + }, + example={"city": "San Francisco"}, + ) +) + +weather_wrapper = create_payment_wrapper( + resource_server, + accepts=weather_accepts, + resource=ResourceInfo(url="mcp://tool/get_weather"), + extensions=weather_discovery, # Bazaar metadata attached to PaymentRequired +) +``` + ### For Facilitators Extract discovery information from payment requests: diff --git a/python/x402/extensions/bazaar/__init__.py b/python/x402/extensions/bazaar/__init__.py index 60d2239b66..95ad4c9d48 100644 --- a/python/x402/extensions/bazaar/__init__.py +++ b/python/x402/extensions/bazaar/__init__.py @@ -60,18 +60,24 @@ ) from .facilitator_client import ( BazaarClientExtension, - BazaarDiscoveryExtension, BazaarExtendedClient, + BazaarExtension, DiscoveryResource, DiscoveryResourcesResponse, ListDiscoveryResourcesParams, + Pagination, + SearchDiscoveryResourcesParams, + SearchDiscoveryResourcesResponse, + SearchPagination, with_bazaar, ) from .resource_service import ( DeclareBodyDiscoveryConfig, + DeclareMcpDiscoveryConfig, DeclareQueryDiscoveryConfig, OutputConfig, declare_discovery_extension, + declare_mcp_discovery_extension, ) from .server import bazaar_resource_server_extension from .types import ( @@ -83,6 +89,10 @@ BodyType, DiscoveryExtension, DiscoveryInfo, + McpDiscoveryExtension, + McpDiscoveryInfo, + McpInput, + McpTransport, OutputInfo, QueryDiscoveryExtension, QueryDiscoveryInfo, @@ -100,18 +110,23 @@ # Input types "QueryInput", "BodyInput", + "McpInput", + "McpTransport", "OutputInfo", # Discovery info types "QueryDiscoveryInfo", "BodyDiscoveryInfo", + "McpDiscoveryInfo", "DiscoveryInfo", # Extension types "QueryDiscoveryExtension", "BodyDiscoveryExtension", + "McpDiscoveryExtension", "DiscoveryExtension", # Config types "DeclareQueryDiscoveryConfig", "DeclareBodyDiscoveryConfig", + "DeclareMcpDiscoveryConfig", "OutputConfig", # Result types "ValidationResult", @@ -120,13 +135,18 @@ "bazaar_resource_server_extension", # Client extension types "ListDiscoveryResourcesParams", + "SearchDiscoveryResourcesParams", "DiscoveryResource", "DiscoveryResourcesResponse", + "Pagination", + "SearchDiscoveryResourcesResponse", + "SearchPagination", "BazaarClientExtension", - "BazaarDiscoveryExtension", + "BazaarExtension", "BazaarExtendedClient", # Functions "declare_discovery_extension", + "declare_mcp_discovery_extension", "validate_discovery_extension", "extract_discovery_info", "extract_discovery_info_from_extension", diff --git a/python/x402/extensions/bazaar/facilitator.py b/python/x402/extensions/bazaar/facilitator.py index f03ba51f29..b9ee58abcf 100644 --- a/python/x402/extensions/bazaar/facilitator.py +++ b/python/x402/extensions/bazaar/facilitator.py @@ -8,18 +8,28 @@ from __future__ import annotations +import ipaddress import logging import re +import unicodedata from dataclasses import dataclass, field from typing import TYPE_CHECKING, Any from urllib.parse import unquote, urlparse, urlunparse +try: + import idna +except ImportError as e: + raise ImportError( + "Extensions validation requires idna. Install with: pip install x402[extensions]" + ) from e + from .types import ( BAZAAR, BodyDiscoveryInfo, BodyInput, DiscoveryExtension, DiscoveryInfo, + McpDiscoveryInfo, QueryDiscoveryInfo, QueryInput, parse_discovery_extension, @@ -44,6 +54,55 @@ _ROUTE_TEMPLATE_RE = re.compile(r"^/[a-zA-Z0-9_/:.\-~%]+$") +# Maximum lengths for resource service metadata fields. Spec: see +# specs/extensions/bazaar.md "Service Metadata on `resource`". +_MAX_SERVICE_NAME_LEN = 32 +_MAX_TAG_LEN = 32 +_MAX_TAGS = 5 +_MAX_ICON_URL_LEN = 2048 + +# Matches ASCII control characters: C0 range (U+0000–U+001F) plus DEL (U+007F). +_CONTROL_CHAR_RE = re.compile(r"[\x00-\x1f\x7f]") +# Printable ASCII range (U+0020–U+007E). `service_name` and `tags` are +# constrained to this range so that String.length (UTF-16 code units) in TS, +# len() (code points) here, and len() (UTF-8 bytes) in Go all agree on the +# character count. Same convention as paymentidentifier.id. +_PRINTABLE_ASCII_RE = re.compile(r"^[\x20-\x7e]+$") + +# Loopback hostnames that must be rejected for SSRF defense. Includes the +# common /etc/hosts aliases on Linux/macOS (`localhost.localdomain`, +# `ip6-localhost`, `ip6-loopback`) — without these, a hostile provider could +# route the facilitator's image fetcher to its own loopback interface. +_LOOPBACK_HOSTNAMES = frozenset( + { + "localhost", + "localhost.localdomain", + "ip6-localhost", + "ip6-loopback", + } +) + + +def _contains_control_char(s: str) -> bool: + """Report whether s contains any Unicode control character (category Cc). + + Defense-in-depth: the printable-ASCII regex used by + ``_is_valid_service_name`` / ``_sanitize_tags`` already rejects every + control character, but this explicit check documents intent and would + survive any future relaxation of the ASCII restriction. + """ + return any(unicodedata.category(c) == "Cc" for c in s) + + +# SSRF defense: any all-digit hostname is suspect because no legitimate DNS name +# is purely numeric. Catches decimal-encoded IPs (`http://2130706433/` → 127.0.0.1) +# and short-form IPs (`http://0/` → 0.0.0.0, treated as loopback on Linux). +_ALL_DIGITS_RE = re.compile(r"^\d+$") +# SSRF defense: hex-encoded IPs (`http://0x7f000001/` → 127.0.0.1) — same family +# of bypasses as the decimal form above. +_HEX_LITERAL_RE = re.compile(r"^0x[0-9a-f]+$", re.IGNORECASE) + + def _is_valid_route_template(value: str | None) -> bool: """Check whether a routeTemplate value is structurally valid. @@ -79,6 +138,179 @@ def _is_valid_route_template(value: str | None) -> bool: return True +def _is_valid_service_name(value: Any) -> bool: + """Check whether a serviceName value is structurally valid. + + Non-empty string of printable ASCII (U+0020–U+007E), length ≤ 32. + + The ASCII restriction matches the ``paymentidentifier.id`` convention + and keeps ``len()`` semantics identical across TS / Python / Go. + + Mirrors `isValidServiceName` (TypeScript, Go). + All three implementations must stay in sync. + """ + if not isinstance(value, str): + return False + if len(value) == 0 or len(value) > _MAX_SERVICE_NAME_LEN: + return False + if _contains_control_char(value): + return False + if not _PRINTABLE_ASCII_RE.match(value): + return False + return True + + +def _sanitize_tags(value: Any) -> list[str] | None: + """Sanitize a tags array. + + Drops entries that are not non-empty printable-ASCII strings of at most + 32 characters, then truncates to the first 5 valid entries. Returns None + when nothing survives so the field can be omitted from the catalog. + + The ASCII restriction matches the ``paymentidentifier.id`` convention + and keeps ``len()`` semantics identical across TS / Python / Go. + + Mirrors `sanitizeTags` (TypeScript, Go). + All three implementations must stay in sync. + """ + if not isinstance(value, list): + return None + out: list[str] = [] + # Case-insensitive dedup: keeps the first occurrence's casing. + # Prevents catalog noise like ["Weather", "weather", "WEATHER"]. + seen: set[str] = set() + for entry in value: + if not isinstance(entry, str): + continue + if len(entry) == 0 or len(entry) > _MAX_TAG_LEN: + continue + if _contains_control_char(entry): + continue + if not _PRINTABLE_ASCII_RE.match(entry): + continue + key = entry.lower() + if key in seen: + continue + seen.add(key) + out.append(entry) + if len(out) == _MAX_TAGS: + break + return out if out else None + + +def _is_valid_icon_url(value: Any) -> bool: + """Check whether an iconUrl value is structurally safe. + + Rules (see specs/extensions/bazaar.md "Service Metadata on `resource`"): + - String of length ≤ 2048 + - No ASCII control characters + - Parses as an absolute http:// or https:// URL + - No userinfo (user@host) + - Host is IDN-normalized (UTS #46) before checks, so confusable + full-width / Unicode forms (e.g. ``localhost``) collapse to + their ASCII canonical and get caught by the loopback check + - Host is not an IP literal (v4 or v6), not in the loopback set + (``localhost``, ``localhost.localdomain``, ``ip6-localhost``, + ``ip6-loopback``) + - Host is not a decimal IP encoding (e.g. ``2130706433`` → 127.0.0.1) or + hex literal (e.g. ``0x7f000001``) — common SSRF bypass forms + + Percent-decoding is applied to the hostname before IDN normalization, and + IDN normalization runs before the IP / loopback checks (parallel to the + routeTemplate decoder). + + Mirrors `isValidIconUrl` (TypeScript, Go). + All three implementations must stay in sync. + """ + if not isinstance(value, str): + return False + if len(value) == 0 or len(value) > _MAX_ICON_URL_LEN: + return False + if _CONTROL_CHAR_RE.search(value): + return False + try: + parsed = urlparse(value) + except ValueError: + return False + if parsed.scheme not in ("http", "https"): + return False + if parsed.username or parsed.password: + return False + raw_host = parsed.hostname + if not raw_host: + return False + try: + decoded = unquote(raw_host) + except ValueError: + return False + # IDN/full-width normalization: e.g. "localhost" (full-width Latin) + # → "localhost". Without this the loopback alias check would miss + # confusable Unicode hostnames. uts46=True applies the same UTS #46 + # mapping that idna.Lookup.ToASCII (Go) and domainToASCII (Node) use. + try: + host = idna.encode(decoded, uts46=True).decode("ascii").lower() + except idna.IDNAError: + return False + if host == "": + return False + if host in _LOOPBACK_HOSTNAMES: + return False + try: + ipaddress.ip_address(host) + except ValueError: + pass + else: + return False + # urlparse strips IPv6 brackets from .hostname; if the original netloc had + # brackets but the bare host failed ip_address parsing (e.g. "::1"), still + # reject any colon-bearing host as an IPv6 literal candidate. + if ":" in host: + return False + if _ALL_DIGITS_RE.match(host): + return False + if _HEX_LITERAL_RE.match(host): + return False + return True + + +@dataclass +class SanitizedResourceServiceMetadata: + """Sanitized service metadata extracted from a ``resource`` object.""" + + service_name: str | None = None + tags: list[str] | None = None + icon_url: str | None = None + + +def _sanitize_resource_service_metadata( + resource: dict[str, Any] | None, +) -> SanitizedResourceServiceMetadata: + """Apply the bazaar service-metadata validation rules to a ``resource`` object. + + Returns only the fields that survive. Missing or invalid fields are dropped + silently (soft-drop semantics — see spec). + + Accepts both camelCase (``serviceName`` / ``iconUrl``) and snake_case + (``service_name`` / ``icon_url``) keys, matching the dual-naming convention + used elsewhere when extracting from raw payload dicts. + """ + out = SanitizedResourceServiceMetadata() + if not isinstance(resource, dict): + return out + raw_name = resource.get("serviceName") + if raw_name is None: + raw_name = resource.get("service_name") + if _is_valid_service_name(raw_name): + out.service_name = raw_name + out.tags = _sanitize_tags(resource.get("tags")) + raw_icon = resource.get("iconUrl") + if raw_icon is None: + raw_icon = resource.get("icon_url") + if _is_valid_icon_url(raw_icon): + out.icon_url = raw_icon + return out + + @dataclass class ValidationResult: """Result of validating a discovery extension.""" @@ -92,12 +324,17 @@ class DiscoveredResource: """A discovered x402 resource with its metadata.""" resource_url: str - method: str x402_version: int discovery_info: DiscoveryInfo + method: str = "" + tool_name: str | None = None description: str | None = None mime_type: str | None = None route_template: str | None = None + # Sanitized service metadata. See `_sanitize_resource_service_metadata`. + service_name: str | None = None + tags: list[str] | None = None + icon_url: str | None = None @dataclass @@ -157,23 +394,21 @@ def validate_discovery_extension(extension: DiscoveryExtension) -> ValidationRes def _get_method_from_info(info: DiscoveryInfo | dict[str, Any]) -> str: - """Extract HTTP method from discovery info. + """Extract HTTP method from discovery info. Returns empty string for MCP resources.""" + if isinstance(info, McpDiscoveryInfo): + return "" - Args: - info: Discovery info object or dictionary. - - Returns: - HTTP method string or "UNKNOWN" if not found. - """ if isinstance(info, dict): input_data = info.get("input", {}) - return input_data.get("method", "UNKNOWN") + if input_data.get("type") == "mcp": + return "" + return input_data.get("method", "") if isinstance(info, QueryDiscoveryInfo | BodyDiscoveryInfo): if isinstance(info.input, QueryInput | BodyInput): - return info.input.method or "UNKNOWN" + return info.input.method or "" - return "UNKNOWN" + return "" def extract_discovery_info( @@ -269,6 +504,14 @@ def extract_discovery_info( return None method = _get_method_from_info(discovery_info) + tool_name: str | None = None + if isinstance(discovery_info, McpDiscoveryInfo): + tool_name = discovery_info.input.tool_name + + if not method and not tool_name: + logger.warning("Failed to extract method or tool_name from discovery info") + return None + # Strip query params (?) and hash sections (#) for discovery cataloging parsed = urlparse(resource_url) # If a routeTemplate is present (dynamic route), use it as the canonical path @@ -280,26 +523,32 @@ def extract_discovery_info( # Extract description and mime_type from resource info (V2) or requirements (V1) description: str | None = None mime_type: str | None = None + service_metadata = SanitizedResourceServiceMetadata() if version == 2: - # V2: description and mime_type are in PaymentPayload.resource + # V2: description, mime_type, and service metadata are in PaymentPayload.resource resource = payload_dict.get("resource", {}) if isinstance(resource, dict): description = resource.get("description") or None mime_type = resource.get("mimeType") or resource.get("mime_type") or None + service_metadata = _sanitize_resource_service_metadata(resource) else: - # V1: description and mime_type are in PaymentRequirements + # V1: description and mime_type are in PaymentRequirements; no service metadata. description = requirements_dict.get("description") or None mime_type = requirements_dict.get("mimeType") or requirements_dict.get("mime_type") or None return DiscoveredResource( resource_url=normalized_url, - method=method, x402_version=version, discovery_info=discovery_info, + method=method, + tool_name=tool_name, description=description, mime_type=mime_type, route_template=route_template, + service_name=service_metadata.service_name, + tags=service_metadata.tags, + icon_url=service_metadata.icon_url, ) diff --git a/python/x402/extensions/bazaar/facilitator_client.py b/python/x402/extensions/bazaar/facilitator_client.py index b4992b546c..eaa94f1c7e 100644 --- a/python/x402/extensions/bazaar/facilitator_client.py +++ b/python/x402/extensions/bazaar/facilitator_client.py @@ -21,9 +21,19 @@ class ListDiscoveryResourcesParams: """ type: str | None = None - """Filter by protocol type (e.g., "http", "mcp"). - Currently, the only supported protocol type is "http". - """ + """Filter by protocol type (e.g., "http", "mcp").""" + + pay_to: str | None = None + """Filter by payment recipient address.""" + + scheme: str | None = None + """Filter by payment scheme (e.g., "exact").""" + + network: str | None = None + """Filter by payment network (e.g., "eip155:8453").""" + + extensions: str | None = None + """Filter by extension key present on the discovered resource.""" limit: int | None = None """The number of discovered x402 resources to return per page.""" @@ -32,46 +42,118 @@ class ListDiscoveryResourcesParams: """The offset of the first discovered x402 resource to return.""" +@dataclass +class SearchDiscoveryResourcesParams: + """Parameters for searching discovery resources.""" + + query: str = "" + """Natural-language search query (required).""" + + type: str | None = None + """Filter by protocol type (e.g., "http", "mcp").""" + + pay_to: str | None = None + """Filter by payment recipient address.""" + + scheme: str | None = None + """Filter by payment scheme (e.g., "exact").""" + + network: str | None = None + """Filter by payment network (e.g., "eip155:8453").""" + + extensions: str | None = None + """Filter by extension key present on the discovered resource.""" + + limit: int | None = None + """Advisory maximum number of results. The server may return fewer or ignore this.""" + + cursor: str | None = None + """Advisory continuation token from a previous response. The server may ignore this.""" + + @dataclass class DiscoveryResource: """A discovered x402 resource from the bazaar.""" - url: str - """The URL of the discovered resource.""" + resource: str + """The URL or identifier of the discovered resource.""" type: str """The protocol type of the resource.""" - metadata: dict[str, Any] | None = None - """Additional metadata about the resource.""" + x402_version: int = 0 + """The x402 protocol version supported by this resource.""" + + accepts: list[Any] | None = None + """Array of accepted payment methods for this resource.""" + + last_updated: str | None = None + """ISO 8601 timestamp of when the resource was last updated.""" + + extensions: dict[str, Any] | None = None + """Additional extension payloads attached to this discovered resource.""" + + +@dataclass +class Pagination: + """Pagination information for a list response.""" + + limit: int = 0 + offset: int = 0 + total: int = 0 @dataclass class DiscoveryResourcesResponse: """Response from listing discovery resources.""" - resources: list[DiscoveryResource] + x402_version: int + """The x402 protocol version of this response.""" + + items: list[DiscoveryResource] """The list of discovered resources.""" - total: int | None = None - """Total count of resources matching the query.""" + pagination: Pagination + """Pagination information for the response.""" - limit: int | None = None - """The limit used for this query.""" - offset: int | None = None - """The offset used for this query.""" +@dataclass +class SearchPagination: + """Pagination details for a paginated search response.""" + + limit: int + """Number of results in this page.""" + + cursor: str | None + """Continuation cursor for the next page; may be None.""" + + +@dataclass +class SearchDiscoveryResourcesResponse: + """Response from searching discovery resources.""" + + x402_version: int + """The x402 protocol version of this response.""" + + resources: list[DiscoveryResource] + """The list of matching discovered resources.""" + + partial_results: bool | None = None + """Whether additional matches were truncated by the facilitator.""" + pagination: SearchPagination | None = None + """Optional pagination details for paginated responses.""" -class BazaarDiscoveryExtension: - """Bazaar discovery extension providing query functionality. + +class BazaarExtension: + """Bazaar extension providing discovery list and search functionality. This extension is attached to a facilitator client via `with_bazaar()` and provides methods to query discovery resources from the facilitator. """ def __init__(self, client: HTTPFacilitatorClient) -> None: - """Initialize the discovery extension. + """Initialize the bazaar extension. Args: client: The facilitator client to use for requests. @@ -99,39 +181,40 @@ def list_resources( from x402.extensions.bazaar import with_bazaar client = with_bazaar(HTTPFacilitatorClient()) - resources = client.extensions.discovery.list_resources( + resources = client.extensions.bazaar.list_resources( ListDiscoveryResourcesParams(type="http", limit=10) ) - for resource in resources.resources: - print(f"Resource: {resource.url}") + for resource in resources.items: + print(f"Resource: {resource.resource}") ``` """ - params = params or ListDiscoveryResourcesParams() - # Build headers headers: dict[str, str] = {"Content-Type": "application/json"} - # Add auth headers if available if self._client._auth_provider: - # Use 'supported' auth as a reasonable default for discovery auth = self._client._auth_provider.get_auth_headers() - headers.update(auth.supported) + headers.update(auth.bazaar) - # Build query parameters query_params: dict[str, str] = {} if params.type is not None: query_params["type"] = params.type + if params.pay_to is not None: + query_params["payTo"] = params.pay_to + if params.scheme is not None: + query_params["scheme"] = params.scheme + if params.network is not None: + query_params["network"] = params.network + if params.extensions is not None: + query_params["extensions"] = params.extensions if params.limit is not None: query_params["limit"] = str(params.limit) if params.offset is not None: query_params["offset"] = str(params.offset) - # Build endpoint URL endpoint = f"{self._client.url}/discovery/resources" - # Get or create HTTP client - http_client = self._client._get_client() + http_client = self._client._get_client() # type: ignore[attr-defined] response = http_client.get( endpoint, @@ -145,19 +228,94 @@ def list_resources( ) data = response.json() - return _parse_discovery_resources_response(data) + return _parse_list_response(data) + + def search( + self, + params: SearchDiscoveryResourcesParams, + ) -> SearchDiscoveryResourcesResponse: + """Search x402 discovery resources from the bazaar using a natural-language query. + + Pagination is optional: facilitators may ignore `limit` and `cursor`, or include + `response.pagination` when pagination is used. + + Args: + params: Search parameters including the required query string. + + Returns: + A response containing matched discovery resources and optional pagination hints. + + Raises: + ValueError: If query is empty or the request fails. + + Example: + ```python + from x402.http import HTTPFacilitatorClient + from x402.extensions.bazaar import with_bazaar, SearchDiscoveryResourcesParams + + client = with_bazaar(HTTPFacilitatorClient()) + results = client.extensions.bazaar.search( + SearchDiscoveryResourcesParams(query="weather APIs", type="http") + ) + if results.cursor is not None: + # facilitator returned continuation cursor for the next page + pass + ``` + """ + if not params.query: + raise ValueError("search query is required") + + headers: dict[str, str] = {"Content-Type": "application/json"} + + if self._client._auth_provider: + auth = self._client._auth_provider.get_auth_headers() + headers.update(auth.bazaar) + + query_params: dict[str, str] = {"query": params.query} + if params.type is not None: + query_params["type"] = params.type + if params.pay_to is not None: + query_params["payTo"] = params.pay_to + if params.scheme is not None: + query_params["scheme"] = params.scheme + if params.network is not None: + query_params["network"] = params.network + if params.extensions is not None: + query_params["extensions"] = params.extensions + if params.limit is not None: + query_params["limit"] = str(params.limit) + if params.cursor is not None: + query_params["cursor"] = params.cursor + + endpoint = f"{self._client.url}/discovery/search" + + http_client = self._client._get_client() # type: ignore[attr-defined] + + response = http_client.get( + endpoint, + headers=headers, + params=query_params, + ) + + if response.status_code != 200: + raise ValueError( + f"Facilitator searchDiscoveryResources failed ({response.status_code}): {response.text}" + ) + + data = response.json() + return _parse_search_response(data) class BazaarClientExtension: """Bazaar client extension interface providing discovery query functionality.""" def __init__(self, client: HTTPFacilitatorClient) -> None: - """Initialize the bazaar extension. + """Initialize the bazaar client extension. Args: client: The facilitator client to use. """ - self.discovery = BazaarDiscoveryExtension(client) + self.bazaar = BazaarExtension(client) class BazaarExtendedClient: @@ -181,11 +339,11 @@ def __getattr__(self, name: str) -> Any: return getattr(self._client, name) def __enter__(self) -> BazaarExtendedClient: - self._client.__enter__() + self._client.__enter__() # type: ignore[attr-defined] return self def __exit__(self, *args: Any) -> None: - self._client.__exit__(*args) + self._client.__exit__(*args) # type: ignore[attr-defined] def with_bazaar(client: HTTPFacilitatorClient) -> BazaarExtendedClient: @@ -202,13 +360,13 @@ def with_bazaar(client: HTTPFacilitatorClient) -> BazaarExtendedClient: from x402.http import HTTPFacilitatorClient, FacilitatorConfig from x402.extensions.bazaar import with_bazaar, ListDiscoveryResourcesParams - # Basic usage + # List resources client = with_bazaar(HTTPFacilitatorClient()) - resources = client.extensions.discovery.list_resources() + resources = client.extensions.bazaar.list_resources() - # With parameters - resources = client.extensions.discovery.list_resources( - ListDiscoveryResourcesParams(type="http", limit=10, offset=0) + # Search resources + results = client.extensions.bazaar.search( + SearchDiscoveryResourcesParams(query="weather APIs", limit=10) ) # Access wrapped client methods @@ -218,30 +376,67 @@ def with_bazaar(client: HTTPFacilitatorClient) -> BazaarExtendedClient: return BazaarExtendedClient(client) -def _parse_discovery_resources_response( +def _parse_list_response( data: dict[str, Any], ) -> DiscoveryResourcesResponse: - """Parse discovery resources response from JSON data. + """Parse a list discovery resources response from JSON data.""" + items = [] + for item in data.get("items", []): + items.append( + DiscoveryResource( + resource=item.get("resource", ""), + type=item.get("type", ""), + x402_version=item.get("x402Version", 0), + accepts=item.get("accepts"), + last_updated=item.get("lastUpdated"), + extensions=item.get("extensions"), + ) + ) - Args: - data: JSON response data. + raw_pagination = data.get("pagination", {}) + pagination = Pagination( + limit=raw_pagination.get("limit", 0), + offset=raw_pagination.get("offset", 0), + total=raw_pagination.get("total", 0), + ) - Returns: - Parsed DiscoveryResourcesResponse. - """ - resources = [] + return DiscoveryResourcesResponse( + x402_version=data.get("x402Version", 0), + items=items, + pagination=pagination, + ) + + +def _parse_search_response( + data: dict[str, Any], +) -> SearchDiscoveryResourcesResponse: + """Parse a search discovery resources response from JSON data.""" + items = [] for item in data.get("resources", []): - resources.append( + items.append( DiscoveryResource( - url=item.get("url", ""), + resource=item.get("resource", ""), type=item.get("type", ""), - metadata=item.get("metadata"), + x402_version=item.get("x402Version", 0), + accepts=item.get("accepts"), + last_updated=item.get("lastUpdated"), + extensions=item.get("extensions"), ) ) - return DiscoveryResourcesResponse( - resources=resources, - total=data.get("total"), - limit=data.get("limit"), - offset=data.get("offset"), + raw_pagination = data.get("pagination") + pagination = ( + SearchPagination( + limit=raw_pagination.get("limit", 0), + cursor=raw_pagination.get("cursor"), + ) + if raw_pagination is not None + else None + ) + + return SearchDiscoveryResourcesResponse( + x402_version=data.get("x402Version", 0), + resources=items, + partial_results=data.get("partialResults"), + pagination=pagination, ) diff --git a/python/x402/extensions/bazaar/resource_service.py b/python/x402/extensions/bazaar/resource_service.py index 11ca3fcdbd..13b1eac317 100644 --- a/python/x402/extensions/bazaar/resource_service.py +++ b/python/x402/extensions/bazaar/resource_service.py @@ -15,6 +15,10 @@ BodyDiscoveryInfo, BodyInput, BodyType, + McpDiscoveryExtension, + McpDiscoveryInfo, + McpInput, + McpTransport, OutputInfo, QueryDiscoveryExtension, QueryDiscoveryInfo, @@ -223,6 +227,113 @@ def _create_body_discovery_extension( return BodyDiscoveryExtension(info=body_info, schema=schema) +@dataclass +class DeclareMcpDiscoveryConfig: + """Configuration for declaring an MCP tool discovery extension.""" + + tool_name: str + input_schema: dict[str, Any] + description: str | None = None + transport: McpTransport | None = None + example: dict[str, Any] | None = None + output: OutputConfig | None = None + + +def declare_mcp_discovery_extension( + config: DeclareMcpDiscoveryConfig, +) -> dict[str, Any]: + """Create a Bazaar discovery extension for an MCP tool. + + Use this when registering a paid MCP tool so facilitators can catalog and + index it in the Bazaar under the ``"mcp"`` resource type. + + Args: + config: MCP tool declaration configuration. + + Returns: + A dict with ``"bazaar"`` key containing the discovery extension. + Pass this as ``extensions`` in your payment wrapper config. + + Example: + ```python + from x402.extensions.bazaar import declare_mcp_discovery_extension, DeclareMcpDiscoveryConfig + + extensions = declare_mcp_discovery_extension( + DeclareMcpDiscoveryConfig( + tool_name="get_weather", + description="Get current weather for a city", + input_schema={ + "properties": {"city": {"type": "string"}}, + "required": ["city"], + }, + example={"city": "San Francisco"}, + ) + ) + ``` + """ + mcp_input = McpInput( + toolName=config.tool_name, + description=config.description, + transport=config.transport, + inputSchema=config.input_schema, + example=config.example, + ) + + output_info = None + if config.output and config.output.example is not None: + output_info = OutputInfo(type="json", example=config.output.example) + + mcp_info = McpDiscoveryInfo(input=mcp_input, output=output_info) + + # Build the JSON Schema that validates the info structure + input_properties: dict[str, Any] = { + "type": {"type": "string", "const": "mcp"}, + "toolName": {"type": "string"}, + "inputSchema": {"type": "object"}, + } + if config.description is not None: + input_properties["description"] = {"type": "string"} + if config.transport is not None: + input_properties["transport"] = { + "type": "string", + "enum": ["streamable-http", "sse"], + } + if config.example is not None: + input_properties["example"] = {"type": "object"} + + schema_properties: dict[str, Any] = { + "input": { + "type": "object", + "properties": input_properties, + "required": ["type", "toolName", "inputSchema"], + "additionalProperties": False, + } + } + + if config.output and config.output.example is not None: + output_schema: dict[str, Any] = { + "type": "object", + "properties": { + "type": {"type": "string"}, + "example": {}, + }, + "required": ["type"], + } + if config.output.schema: + output_schema["properties"]["example"].update(config.output.schema) + schema_properties["output"] = output_schema + + schema = { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": schema_properties, + "required": ["input"], + } + + extension = McpDiscoveryExtension(info=mcp_info, schema=schema) + return {BAZAAR.key: extension.model_dump(by_alias=True, exclude_none=True)} + + def declare_discovery_extension( input: dict[str, Any] | None = None, # noqa: A002 input_schema: dict[str, Any] | None = None, diff --git a/python/x402/extensions/bazaar/types.py b/python/x402/extensions/bazaar/types.py index aa2e2e478d..ab6ffe1c1a 100644 --- a/python/x402/extensions/bazaar/types.py +++ b/python/x402/extensions/bazaar/types.py @@ -95,8 +95,42 @@ class BodyDiscoveryInfo(BaseModel): model_config = {"extra": "allow"} +McpTransport = Literal["streamable-http", "sse"] + + +class McpInput(BaseModel): + """Input information for MCP tools.""" + + type: Literal["mcp"] = "mcp" + tool_name: str = Field(alias="toolName") + description: str | None = None + transport: McpTransport | None = None + input_schema: dict[str, Any] = Field(alias="inputSchema") + example: dict[str, Any] | None = None + + model_config = {"extra": "allow", "populate_by_name": True} + + +class McpDiscoveryInfo(BaseModel): + """Discovery info for MCP tools.""" + + input: McpInput + output: OutputInfo | None = None + + model_config = {"extra": "allow"} + + +class McpDiscoveryExtension(BaseModel): + """Discovery extension for MCP tools.""" + + info: McpDiscoveryInfo + schema_: dict[str, Any] = Field(alias="schema") + + model_config = {"extra": "allow", "populate_by_name": True} + + # Union type for discovery info -DiscoveryInfo = QueryDiscoveryInfo | BodyDiscoveryInfo +DiscoveryInfo = QueryDiscoveryInfo | BodyDiscoveryInfo | McpDiscoveryInfo class QueryDiscoveryExtension(BaseModel): @@ -118,25 +152,25 @@ class BodyDiscoveryExtension(BaseModel): # Union type for discovery extension -DiscoveryExtension = QueryDiscoveryExtension | BodyDiscoveryExtension +DiscoveryExtension = QueryDiscoveryExtension | BodyDiscoveryExtension | McpDiscoveryExtension def parse_discovery_extension(data: dict[str, Any]) -> DiscoveryExtension: """Parse a discovery extension from a dictionary. - Automatically determines if it's a query or body extension based on - the presence of bodyType in the input. + Determines type from the input.type field (mcp) or bodyType presence (body vs query). Args: data: Dictionary containing extension data. Returns: - Parsed DiscoveryExtension (Query or Body variant). + Parsed DiscoveryExtension (Query, Body, or Mcp variant). """ info = data.get("info", {}) input_data = info.get("input", {}) - # Check if it's a body extension by looking for bodyType + if input_data.get("type") == "mcp": + return McpDiscoveryExtension.model_validate(data) if "bodyType" in input_data or "body_type" in input_data: return BodyDiscoveryExtension.model_validate(data) return QueryDiscoveryExtension.model_validate(data) @@ -145,18 +179,18 @@ def parse_discovery_extension(data: dict[str, Any]) -> DiscoveryExtension: def parse_discovery_info(data: dict[str, Any]) -> DiscoveryInfo: """Parse discovery info from a dictionary. - Automatically determines if it's query or body info based on - the presence of bodyType in the input. + Determines type from the input.type field (mcp) or bodyType presence (body vs query). Args: data: Dictionary containing discovery info. Returns: - Parsed DiscoveryInfo (Query or Body variant). + Parsed DiscoveryInfo (Query, Body, or Mcp variant). """ input_data = data.get("input", {}) - # Check if it's body info by looking for bodyType + if input_data.get("type") == "mcp": + return McpDiscoveryInfo.model_validate(data) if "bodyType" in input_data or "body_type" in input_data: return BodyDiscoveryInfo.model_validate(data) return QueryDiscoveryInfo.model_validate(data) diff --git a/python/x402/extensions/erc20_approval_gas_sponsoring/client.py b/python/x402/extensions/erc20_approval_gas_sponsoring/client.py index 9f66e16e6e..2947449e81 100644 --- a/python/x402/extensions/erc20_approval_gas_sponsoring/client.py +++ b/python/x402/extensions/erc20_approval_gas_sponsoring/client.py @@ -5,6 +5,8 @@ from typing import Any from ...mechanisms.evm.constants import ( + DEFAULT_MAX_FEE_PER_GAS, + DEFAULT_MAX_PRIORITY_FEE_PER_GAS, ERC20_APPROVE_ABI, ERC20_APPROVE_GAS_LIMIT, PERMIT2_ADDRESS, @@ -54,8 +56,8 @@ def sign_erc20_approval_transaction( nonce = signer.get_transaction_count(signer.address) - max_fee = 1_000_000_000 - max_priority_fee = 100_000_000 + max_fee = DEFAULT_MAX_FEE_PER_GAS + max_priority_fee = DEFAULT_MAX_PRIORITY_FEE_PER_GAS if hasattr(signer, "estimate_fees_per_gas"): try: fees = signer.estimate_fees_per_gas() diff --git a/python/x402/http/constants.py b/python/x402/http/constants.py index 9f62088933..47aff7a4d6 100644 --- a/python/x402/http/constants.py +++ b/python/x402/http/constants.py @@ -4,6 +4,7 @@ PAYMENT_SIGNATURE_HEADER = "PAYMENT-SIGNATURE" PAYMENT_REQUIRED_HEADER = "PAYMENT-REQUIRED" PAYMENT_RESPONSE_HEADER = "PAYMENT-RESPONSE" +SETTLEMENT_OVERRIDES_HEADER = "Settlement-Overrides" X_PAYMENT_HEADER = "X-PAYMENT" # V1 legacy X_PAYMENT_RESPONSE_HEADER = "X-PAYMENT-RESPONSE" # V1 legacy ACCESS_CONTROL_EXPOSE_HEADERS = "Access-Control-Expose-Headers" diff --git a/python/x402/http/facilitator_client.py b/python/x402/http/facilitator_client.py index 7d762dfec2..af4b16d6b8 100644 --- a/python/x402/http/facilitator_client.py +++ b/python/x402/http/facilitator_client.py @@ -6,7 +6,9 @@ from __future__ import annotations +import base64 import json +import logging from typing import TYPE_CHECKING, Any, TypeVar from pydantic import ValidationError @@ -87,6 +89,45 @@ def _parse_facilitator_response( ) from exc +_logger = logging.getLogger("x402") + +_EXTENSION_RESPONSE_LOG_FIELD_ALLOWLIST = ["status", "rejectedReason", "reason", "code"] + + +def _log_extension_responses_header(response: Any) -> None: + """Read the EXTENSION-RESPONSES header and log allowlisted fields. + + Silently ignores malformed headers. + + Args: + response: The HTTP response object (httpx.Response). + """ + header = response.headers.get("EXTENSION-RESPONSES") or response.headers.get( + "extension-responses" + ) + if not header: + return + try: + decoded = base64.b64decode(header).decode("utf-8") + header_extensions: dict[str, Any] = json.loads(decoded) + if not isinstance(header_extensions, dict): + return + sanitized: dict[str, dict[str, Any]] = {} + for extension_key, payload in header_extensions.items(): + filtered: dict[str, Any] = {} + if isinstance(payload, dict): + for field in _EXTENSION_RESPONSE_LOG_FIELD_ALLOWLIST: + if field in payload: + filtered[field] = payload[field] + sanitized[extension_key] = filtered + _logger.info( + "[x402] extension responses: %s", + json.dumps(sanitized), + ) + except Exception: + pass + + # ============================================================================ # Async HTTP Facilitator Client (Default) # ============================================================================ @@ -288,7 +329,9 @@ async def _verify_http( if response.status_code != 200: raise ValueError(f"Facilitator verify failed ({response.status_code}): {response.text}") - return _parse_facilitator_response(response, VerifyResponse, "verify") + result = _parse_facilitator_response(response, VerifyResponse, "verify") + _log_extension_responses_header(response) + return result async def _settle_http( self, @@ -309,7 +352,9 @@ async def _settle_http( if response.status_code != 200: raise ValueError(f"Facilitator settle failed ({response.status_code}): {response.text}") - return _parse_facilitator_response(response, SettleResponse, "settle") + result = _parse_facilitator_response(response, SettleResponse, "settle") + _log_extension_responses_header(response) + return result # ============================================================================ @@ -504,7 +549,9 @@ def _verify_http( if response.status_code != 200: raise ValueError(f"Facilitator verify failed ({response.status_code}): {response.text}") - return _parse_facilitator_response(response, VerifyResponse, "verify") + result = _parse_facilitator_response(response, VerifyResponse, "verify") + _log_extension_responses_header(response) + return result def _settle_http( self, @@ -525,4 +572,6 @@ def _settle_http( if response.status_code != 200: raise ValueError(f"Facilitator settle failed ({response.status_code}): {response.text}") - return _parse_facilitator_response(response, SettleResponse, "settle") + result = _parse_facilitator_response(response, SettleResponse, "settle") + _log_extension_responses_header(response) + return result diff --git a/python/x402/http/facilitator_client_base.py b/python/x402/http/facilitator_client_base.py index 9926f8b12c..f870d2428b 100644 --- a/python/x402/http/facilitator_client_base.py +++ b/python/x402/http/facilitator_client_base.py @@ -36,6 +36,7 @@ class AuthHeaders: verify: dict[str, str] = field(default_factory=dict) settle: dict[str, str] = field(default_factory=dict) supported: dict[str, str] = field(default_factory=dict) + bazaar: dict[str, str] = field(default_factory=dict) class AuthProvider(Protocol): @@ -63,6 +64,7 @@ def get_auth_headers(self) -> AuthHeaders: verify=result.get("verify", {}), settle=result.get("settle", {}), supported=result.get("supported", result.get("list", {})), + bazaar=result.get("bazaar", {}), ) diff --git a/python/x402/http/middleware/fastapi.py b/python/x402/http/middleware/fastapi.py index 84d2a8dff9..915a91f6ea 100644 --- a/python/x402/http/middleware/fastapi.py +++ b/python/x402/http/middleware/fastapi.py @@ -19,6 +19,7 @@ "FastAPI middleware requires fastapi and starlette. Install with: uv add x402[fastapi]" ) from e +from ..constants import SETTLEMENT_OVERRIDES_HEADER from ..facilitator_client_base import FacilitatorResponseError from ..types import ( HTTPAdapter, @@ -341,12 +342,22 @@ async def middleware( async for chunk in response.body_iterator: body += chunk + # Extract and strip settlement overrides from the upstream response + overrides = http_server._extract_settlement_overrides( + dict(response.headers), + ) + if overrides is not None: + for k in list(response.headers.keys()): + if k.lower() == SETTLEMENT_OVERRIDES_HEADER.lower(): + del response.headers[k] + # Process settlement (await async method) try: settle_result = await http_server.process_settlement( result.payment_payload, result.payment_requirements, context=context, + settlement_overrides=overrides, ) if not settle_result.success: @@ -390,6 +401,21 @@ async def middleware( return middleware +def set_settlement_overrides(response: Response, overrides: dict[str, Any]) -> None: + """Set settlement overrides on a FastAPI/Starlette response for partial settlement. + + The middleware extracts these before settlement and strips the header + from the client response. + + Args: + response: FastAPI ``Response`` object. + overrides: Settlement overrides, e.g. ``{"amount": "500"}``. + """ + import json + + response.headers[SETTLEMENT_OVERRIDES_HEADER] = json.dumps(overrides) + + def payment_middleware_from_config( routes: RoutesConfig, facilitator_client: Any = None, diff --git a/python/x402/http/middleware/flask.py b/python/x402/http/middleware/flask.py index 9987fcb8e0..a205a29844 100644 --- a/python/x402/http/middleware/flask.py +++ b/python/x402/http/middleware/flask.py @@ -18,6 +18,7 @@ "Flask middleware requires the flask package. Install with: uv add x402[flask]" ) from e +from ..constants import SETTLEMENT_OVERRIDES_HEADER from ..facilitator_client_base import FacilitatorResponseError from ..types import ( HTTPAdapter, @@ -437,12 +438,23 @@ def _wsgi_middleware( response_wrapper.status_code is not None and 200 <= response_wrapper.status_code < 300 ): + # Extract settlement overrides from response headers and strip them + overrides = self._http_server._extract_settlement_overrides( + response_wrapper.headers, + ) + response_wrapper.headers = [ + (k, v) + for k, v in response_wrapper.headers + if k.lower() != SETTLEMENT_OVERRIDES_HEADER.lower() + ] + # Settle payment try: settle_result = self._http_server.process_settlement( result.payment_payload, result.payment_requirements, context=context, + settlement_overrides=overrides, ) if settle_result.success: @@ -495,6 +507,19 @@ def _wsgi_middleware( # ============================================================================ +def set_settlement_overrides(response: Any, overrides: dict[str, Any]) -> None: + """Set settlement overrides on a Flask response for partial settlement. + + The middleware extracts these before settlement and strips the header + from the client response. + + Args: + response: Flask ``Response`` object (or ``make_response()`` result). + overrides: Settlement overrides, e.g. ``{"amount": "500"}``. + """ + response.headers[SETTLEMENT_OVERRIDES_HEADER] = json.dumps(overrides) + + def payment_middleware( app: Flask, routes: RoutesConfig, diff --git a/python/x402/http/paywall/avm_paywall_template.py b/python/x402/http/paywall/avm_paywall_template.py new file mode 100644 index 0000000000..ecba7cb260 --- /dev/null +++ b/python/x402/http/paywall/avm_paywall_template.py @@ -0,0 +1,2 @@ +# THIS FILE IS AUTO-GENERATED - DO NOT EDIT +AVM_PAYWALL_TEMPLATE = '\n \n \n Payment Required\n \n
\n \n \n ' diff --git a/python/x402/http/paywall/evm_paywall_template.py b/python/x402/http/paywall/evm_paywall_template.py index cb301fe539..6d6bb62ed5 100644 --- a/python/x402/http/paywall/evm_paywall_template.py +++ b/python/x402/http/paywall/evm_paywall_template.py @@ -1,2 +1,2 @@ # THIS FILE IS AUTO-GENERATED - DO NOT EDIT -EVM_PAYWALL_TEMPLATE = '\n \n \n Payment Required\n \n
\n \n \n ' +EVM_PAYWALL_TEMPLATE = '\n \n \n Payment Required\n \n
\n \n \n ' diff --git a/python/x402/http/paywall/svm_paywall_template.py b/python/x402/http/paywall/svm_paywall_template.py index de853d5bf5..0eafa61533 100644 --- a/python/x402/http/paywall/svm_paywall_template.py +++ b/python/x402/http/paywall/svm_paywall_template.py @@ -1,2 +1,2 @@ # THIS FILE IS AUTO-GENERATED - DO NOT EDIT -SVM_PAYWALL_TEMPLATE = '\n \n \n Payment Required\n \n
\n \n \n ' +SVM_PAYWALL_TEMPLATE = '\n \n \n Payment Required\n \n
\n \n \n ' diff --git a/python/x402/http/x402_http_server.py b/python/x402/http/x402_http_server.py index 4799aed5a0..1af911d2d6 100644 --- a/python/x402/http/x402_http_server.py +++ b/python/x402/http/x402_http_server.py @@ -23,7 +23,10 @@ ProcessSettleResult, RoutesConfig, ) -from .x402_http_server_base import PaywallProvider, x402HTTPServerBase +from .x402_http_server_base import ( + PaywallProvider, + x402HTTPServerBase, +) if TYPE_CHECKING: from ..server import x402ResourceServerSync @@ -128,6 +131,7 @@ async def process_settlement( payment_payload: PaymentPayload | PaymentPayloadV1, requirements: PaymentRequirements, context: HTTPRequestContext | None = None, + settlement_overrides: dict[str, Any] | None = None, ) -> ProcessSettleResult: """Process settlement after successful response (async). @@ -137,14 +141,19 @@ async def process_settlement( payment_payload: The verified payment payload. requirements: The matching payment requirements. context: Optional HTTP request context for route config lookup and hooks. + settlement_overrides: Optional overrides (e.g. ``{"amount": "1000"}`` + for partial settlement with the *upto* scheme). Returns: ProcessSettleResult with headers if success, or response if failure. """ + effective_requirements = self._apply_settlement_overrides( + requirements, settlement_overrides + ) try: settle_response = await self._server.settle_payment( payment_payload, - requirements, + effective_requirements, ) if not settle_response.success: diff --git a/python/x402/http/x402_http_server_base.py b/python/x402/http/x402_http_server_base.py index 189cfdfbf3..3155410174 100644 --- a/python/x402/http/x402_http_server_base.py +++ b/python/x402/http/x402_http_server_base.py @@ -26,6 +26,7 @@ PAYMENT_REQUIRED_HEADER, PAYMENT_RESPONSE_HEADER, PAYMENT_SIGNATURE_HEADER, + SETTLEMENT_OVERRIDES_HEADER, ) from .types import ( RESULT_NO_PAYMENT_REQUIRED, @@ -56,6 +57,7 @@ logger = logging.getLogger("x402") + # ============================================================================ # Paywall Provider Protocol # ============================================================================ @@ -421,11 +423,58 @@ def _process_request_core( # Settlement # ========================================================================= + @staticmethod + def _extract_settlement_overrides( + response_headers: dict[str, str] | list[tuple[str, str]] | None, + ) -> dict[str, Any] | None: + """Extract settlement overrides from response headers. + + Looks for the ``Settlement-Overrides`` header (case-insensitive) and + parses it as JSON. Returns *None* when the header is absent or + malformed so callers can fall through to the default behaviour. + """ + if response_headers is None: + return None + + key = SETTLEMENT_OVERRIDES_HEADER.lower() + raw: str | None = None + if isinstance(response_headers, dict): + for k, v in response_headers.items(): + if k.lower() == key: + raw = v + break + else: + for k, v in response_headers: + if k.lower() == key: + raw = v + break + + if raw is None: + return None + + try: + import json + + return json.loads(raw) + except (json.JSONDecodeError, TypeError): + return None + + @staticmethod + def _apply_settlement_overrides( + requirements: PaymentRequirements, + overrides: dict[str, Any] | None, + ) -> PaymentRequirements: + """Return *requirements* with the amount replaced by the override, if any.""" + if overrides is None or "amount" not in overrides: + return requirements + return requirements.model_copy(update={"amount": str(overrides["amount"])}) + def process_settlement( self, payment_payload: PaymentPayload | PaymentPayloadV1, requirements: PaymentRequirements, context: HTTPRequestContext | None = None, + settlement_overrides: dict[str, Any] | None = None, ) -> ProcessSettleResult: """Process settlement after successful response. @@ -435,14 +484,19 @@ def process_settlement( payment_payload: The verified payment payload. requirements: The matching payment requirements. context: Optional HTTP request context for route config lookup and hooks. + settlement_overrides: Optional overrides (e.g. ``{"amount": "1000"}`` + for partial settlement with the *upto* scheme). Returns: ProcessSettleResult with headers if success, or response if failure. """ + effective_requirements = self._apply_settlement_overrides( + requirements, settlement_overrides + ) try: settle_response = self._server.settle_payment( payment_payload, - requirements, + effective_requirements, ) if not settle_response.success: diff --git a/python/x402/mcp/server.py b/python/x402/mcp/server.py index 9689ac0624..c5f74f1293 100644 --- a/python/x402/mcp/server.py +++ b/python/x402/mcp/server.py @@ -52,6 +52,7 @@ def create_payment_wrapper( accepts: list[PaymentRequirements], resource: ResourceInfo | None = None, hooks: PaymentWrapperHooks | None = None, + extensions: dict[str, Any] | None = None, ) -> Callable: """Create a decorator that wraps a FastMCP tool handler with x402 payment logic. @@ -79,6 +80,9 @@ def create_payment_wrapper( Defaults to ``mcp://tool/{function_name}``. hooks: Optional ``PaymentWrapperHooks`` for on_before_execution, on_after_execution, on_after_settlement (matches server_async). + extensions: Optional x402 extensions to include in PaymentRequired responses. + Use this to attach Bazaar discovery metadata so facilitators can index + the tool. Example: ``declare_mcp_discovery_extension(config)`` Returns: A decorator to apply to a FastMCP tool handler function. @@ -127,7 +131,9 @@ async def wrapped(**kwargs: Any) -> CallToolResult: payment_data = _extract_payment_from_context(ctx) if not payment_data: - return _create_payment_required_result(accepts, tool_resource, "Payment Required") + return _create_payment_required_result( + accepts, tool_resource, "Payment Required", extensions + ) # Parse payment payload try: @@ -136,7 +142,7 @@ async def wrapped(**kwargs: Any) -> CallToolResult: payload = PaymentPayload.model_validate(payment_data) except Exception as e: return _create_payment_required_result( - accepts, tool_resource, f"Invalid payment payload: {e}" + accepts, tool_resource, f"Invalid payment payload: {e}", extensions ) if asyncio.iscoroutinefunction(resource_server.verify_payment): @@ -150,6 +156,7 @@ async def wrapped(**kwargs: Any) -> CallToolResult: accepts, tool_resource, f"Payment verification failed: {verify_result.invalid_reason}", + extensions, ) # OnBeforeExecution hook @@ -168,6 +175,7 @@ async def wrapped(**kwargs: Any) -> CallToolResult: accepts, tool_resource, "Execution blocked by on_before_execution hook", + extensions, ) # Execute the original handler @@ -230,16 +238,18 @@ async def wrapped(**kwargs: Any) -> CallToolResult: resource_server.settle_payment, payload, accepts[0] ) if not settle_result.success: - return _create_payment_required_result( + return _create_settlement_failed_result( accepts, tool_resource, - f"Settlement failed: {settle_result.error_reason}", + settle_result.error_reason or "Unknown settlement failure", + extensions, ) except Exception as e: - return _create_payment_required_result( + return _create_settlement_failed_result( accepts, tool_resource, - f"Settlement error: {e}", + str(e), + extensions, ) # OnAfterSettlement hook @@ -326,19 +336,53 @@ def _create_payment_required_result( accepts: list[PaymentRequirements], resource: ResourceInfo, error_message: str, + extensions: dict[str, Any] | None = None, ) -> Any: """Create a payment required CallToolResult.""" from mcp.types import CallToolResult, TextContent accepts_dicts = [req.model_dump(by_alias=True) for req in accepts] - payment_required = { + payment_required: dict[str, Any] = { "x402Version": 2, "accepts": accepts_dicts, "error": error_message, "resource": resource.model_dump(by_alias=True), } + if extensions: + payment_required["extensions"] = extensions return CallToolResult( content=[TextContent(type="text", text=json.dumps(payment_required))], structuredContent=payment_required, isError=True, ) + + +def _create_settlement_failed_result( + accepts: list[PaymentRequirements], + resource: ResourceInfo, + error_message: str, + extensions: dict[str, Any] | None = None, +) -> Any: + """Create a settlement failed CallToolResult.""" + from mcp.types import CallToolResult, TextContent + + accepts_dicts = [req.model_dump(by_alias=True) for req in accepts] + error_data: dict[str, Any] = { + "x402Version": 2, + "accepts": accepts_dicts, + "error": f"Payment settlement failed: {error_message}", + "resource": resource.model_dump(by_alias=True), + MCP_PAYMENT_RESPONSE_META_KEY: { + "success": False, + "errorReason": error_message, + "transaction": "", + "network": accepts[0].network, + }, + } + if extensions: + error_data["extensions"] = extensions + return CallToolResult( + content=[TextContent(type="text", text=json.dumps(error_data))], + structuredContent=error_data, + isError=True, + ) diff --git a/python/x402/mcp/server_async.py b/python/x402/mcp/server_async.py index 8072574200..6d0d86b67c 100644 --- a/python/x402/mcp/server_async.py +++ b/python/x402/mcp/server_async.py @@ -37,6 +37,7 @@ def __init__( accepts: list[PaymentRequirements], resource: ResourceInfo | None = None, hooks: PaymentWrapperHooks | None = None, + extensions: dict[str, Any] | None = None, ): """Initialize async payment wrapper config. @@ -44,12 +45,16 @@ def __init__( accepts: List of payment requirements resource: Optional resource info hooks: Optional async server-side hooks + extensions: Optional x402 extensions to include in PaymentRequired responses. + Use this to attach Bazaar discovery metadata so facilitators can index + the tool. Example: ``declare_mcp_discovery_extension(config)`` """ if not accepts: raise ValueError("accepts must have at least one payment requirement") self.accepts = accepts self.resource = resource self.hooks = hooks + self.extensions = extensions def wrap_fastmcp_tool( @@ -329,6 +334,7 @@ async def _create_payment_required_result_async( config.accepts, resource_info, error_message, + config.extensions, ) # Convert to dict for structuredContent @@ -377,6 +383,7 @@ async def _create_settlement_failed_result_async( config.accepts, resource_info, f"Payment settlement failed: {error_message}", + config.extensions, ) settlement_failure = { diff --git a/python/x402/mcp/server_sync.py b/python/x402/mcp/server_sync.py index cfd10f6f52..7c133b69b8 100644 --- a/python/x402/mcp/server_sync.py +++ b/python/x402/mcp/server_sync.py @@ -205,6 +205,7 @@ def _create_payment_required_result_sync( config.accepts, resource_info, error_message, + config.extensions, ) payment_required_dict = ( @@ -237,10 +238,11 @@ def _create_settlement_failed_result_sync( mime_type=(config.resource.mime_type if config.resource else "application/json"), ) - resource_server.create_payment_required_response( + payment_required = resource_server.create_payment_required_response( config.accepts, resource_info, f"Payment settlement failed: {error_message}", + config.extensions, ) settlement_failure = { @@ -250,14 +252,12 @@ def _create_settlement_failed_result_sync( "network": config.accepts[0].network, } - error_data = { - "x402Version": 2, - "accepts": [ - r.model_dump(by_alias=True) if hasattr(r, "model_dump") else r for r in config.accepts - ], - "error": f"Payment settlement failed: {error_message}", - MCP_PAYMENT_RESPONSE_META_KEY: settlement_failure, - } + error_data = ( + payment_required.model_dump(by_alias=True) + if hasattr(payment_required, "model_dump") + else payment_required + ) + error_data[MCP_PAYMENT_RESPONSE_META_KEY] = settlement_failure content_text = json.dumps(error_data) diff --git a/python/x402/mcp/types.py b/python/x402/mcp/types.py index fde734d545..3cec49acc3 100644 --- a/python/x402/mcp/types.py +++ b/python/x402/mcp/types.py @@ -182,6 +182,7 @@ def __init__( accepts: list[PaymentRequirements], resource: ResourceInfo | None = None, hooks: Optional["SyncPaymentWrapperHooks"] = None, # type: ignore + extensions: dict[str, Any] | None = None, ): """Initialize payment wrapper config. @@ -189,12 +190,16 @@ def __init__( accepts: List of payment requirements resource: Optional resource info hooks: Optional server-side hooks + extensions: Optional x402 extensions to include in PaymentRequired responses. + Use this to attach Bazaar discovery metadata so facilitators can index + the tool. Example: ``declare_mcp_discovery_extension(config)`` """ if not accepts: raise ValueError("accepts must have at least one payment requirement") self.accepts = accepts self.resource = resource self.hooks = hooks + self.extensions = extensions class ServerHookContext: diff --git a/python/x402/mechanisms/evm/README.md b/python/x402/mechanisms/evm/README.md index c51fc93eaa..06781b8d84 100644 --- a/python/x402/mechanisms/evm/README.md +++ b/python/x402/mechanisms/evm/README.md @@ -104,6 +104,8 @@ Supports ERC-3009 compatible tokens: - EURC - Any token implementing `transferWithAuthorization()` +For the current list of chains with default assets configured, see [Default Assets for Dollar-String Pricing](../../../../docs/core-concepts/network-and-token-support.mdx#default-assets-for-dollar-string-pricing) in the x402 docs. To add default asset support for a new chain, see [Adding Support for New Networks](../../../../docs/core-concepts/network-and-token-support.mdx#adding-support-for-new-networks). + ## Technical Details ### EIP-3009 TransferWithAuthorization diff --git a/python/x402/mechanisms/evm/__init__.py b/python/x402/mechanisms/evm/__init__.py index ddd4196c3a..a4b0619e0e 100644 --- a/python/x402/mechanisms/evm/__init__.py +++ b/python/x402/mechanisms/evm/__init__.py @@ -9,6 +9,7 @@ EIP1271_MAGIC_VALUE, ERC6492_MAGIC_VALUE, ERR_AUTHORIZATION_VALUE_MISMATCH, + ERR_ERC20_APPROVAL_BROADCAST_FAILED, ERR_FAILED_TO_GET_ASSET_INFO, ERR_FAILED_TO_GET_NETWORK_CONFIG, ERR_FAILED_TO_VERIFY_SIGNATURE, @@ -17,20 +18,34 @@ ERR_MISSING_EIP712_DOMAIN, ERR_NETWORK_MISMATCH, ERR_NONCE_ALREADY_USED, + ERR_PERMIT2_INSUFFICIENT_BALANCE, + ERR_PERMIT2_INVALID_DESTINATION, + ERR_PERMIT2_INVALID_OWNER, ERR_RECIPIENT_MISMATCH, ERR_SMART_WALLET_DEPLOYMENT_FAILED, ERR_TRANSACTION_FAILED, ERR_UNDEPLOYED_SMART_WALLET, ERR_UNSUPPORTED_SCHEME, + ERR_UPTO_AMOUNT_EXCEEDS_PERMITTED, + ERR_UPTO_FACILITATOR_MISMATCH, + ERR_UPTO_FAILED_TO_GET_NETWORK_CONFIG, + ERR_UPTO_INVALID_SCHEME, + ERR_UPTO_NETWORK_MISMATCH, + ERR_UPTO_SETTLEMENT_EXCEEDS_AMOUNT, + ERR_UPTO_TRANSACTION_FAILED, + ERR_UPTO_UNAUTHORIZED_FACILITATOR, ERR_VALID_AFTER_FUTURE, ERR_VALID_BEFORE_EXPIRED, IS_VALID_SIGNATURE_ABI, NETWORK_CONFIGS, SCHEME_EXACT, + SCHEME_UPTO, TRANSFER_WITH_AUTHORIZATION_BYTES_ABI, TRANSFER_WITH_AUTHORIZATION_VRS_ABI, TX_STATUS_FAILED, TX_STATUS_SUCCESS, + UPTO_PERMIT2_WITNESS_TYPES, + X402_UPTO_PERMIT2_PROXY_ADDRESS, AssetInfo, NetworkConfig, ) @@ -70,6 +85,10 @@ TransactionReceipt, TypedDataDomain, TypedDataField, + UptoPermit2Authorization, + UptoPermit2Payload, + UptoPermit2Witness, + is_upto_permit2_payload, ) # Utilities @@ -105,6 +124,7 @@ __all__ = [ # Constants "SCHEME_EXACT", + "SCHEME_UPTO", "DEFAULT_DECIMALS", "DEFAULT_VALIDITY_PERIOD", "TX_STATUS_SUCCESS", @@ -130,6 +150,20 @@ "ERR_FAILED_TO_GET_NETWORK_CONFIG", "ERR_FAILED_TO_GET_ASSET_INFO", "ERR_FAILED_TO_VERIFY_SIGNATURE", + "ERR_ERC20_APPROVAL_BROADCAST_FAILED", + "ERR_PERMIT2_INSUFFICIENT_BALANCE", + "ERR_PERMIT2_INVALID_DESTINATION", + "ERR_PERMIT2_INVALID_OWNER", + "ERR_UPTO_AMOUNT_EXCEEDS_PERMITTED", + "ERR_UPTO_FAILED_TO_GET_NETWORK_CONFIG", + "ERR_UPTO_FACILITATOR_MISMATCH", + "ERR_UPTO_INVALID_SCHEME", + "ERR_UPTO_NETWORK_MISMATCH", + "ERR_UPTO_SETTLEMENT_EXCEEDS_AMOUNT", + "ERR_UPTO_TRANSACTION_FAILED", + "ERR_UPTO_UNAUTHORIZED_FACILITATOR", + "UPTO_PERMIT2_WITNESS_TYPES", + "X402_UPTO_PERMIT2_PROXY_ADDRESS", "TRANSFER_WITH_AUTHORIZATION_VRS_ABI", "TRANSFER_WITH_AUTHORIZATION_BYTES_ABI", "AUTHORIZATION_STATE_ABI", @@ -148,6 +182,11 @@ "ERC6492SignatureData", "AUTHORIZATION_TYPES", "DOMAIN_TYPES", + # Upto types + "UptoPermit2Witness", + "UptoPermit2Authorization", + "UptoPermit2Payload", + "is_upto_permit2_payload", # Signer protocols "ClientEvmSigner", "FacilitatorEvmSigner", diff --git a/python/x402/mechanisms/evm/constants.py b/python/x402/mechanisms/evm/constants.py index d3f772e27c..682dbab7c2 100644 --- a/python/x402/mechanisms/evm/constants.py +++ b/python/x402/mechanisms/evm/constants.py @@ -2,8 +2,9 @@ from typing import TypedDict -# Scheme identifier +# Scheme identifiers SCHEME_EXACT = "exact" +SCHEME_UPTO = "upto" # Default token decimals for USDC DEFAULT_DECIMALS = 6 @@ -37,6 +38,9 @@ # x402ExactPermit2Proxy contract address X402_EXACT_PERMIT2_PROXY_ADDRESS = "0x402085c248EeA27D92E8b30b2C58ed07f9E20001" +# x402UptoPermit2Proxy contract address +X402_UPTO_PERMIT2_PROXY_ADDRESS = "0x4020A4f3b7b90ccA423B9fabCc0CE57C6C240002" + # Permit2 EIP-712 witness types for PermitWitnessTransferFrom # Note: Types must be in alphabetical order after primary type (TokenPermissions < Witness) PERMIT2_WITNESS_TYPES: dict[str, list[dict[str, str]]] = { @@ -57,6 +61,26 @@ ], } +# Upto Permit2 EIP-712 witness types (includes facilitator field) +UPTO_PERMIT2_WITNESS_TYPES: dict[str, list[dict[str, str]]] = { + "PermitWitnessTransferFrom": [ + {"name": "permitted", "type": "TokenPermissions"}, + {"name": "spender", "type": "address"}, + {"name": "nonce", "type": "uint256"}, + {"name": "deadline", "type": "uint256"}, + {"name": "witness", "type": "Witness"}, + ], + "TokenPermissions": [ + {"name": "token", "type": "address"}, + {"name": "amount", "type": "uint256"}, + ], + "Witness": [ + {"name": "to", "type": "address"}, + {"name": "facilitator", "type": "address"}, + {"name": "validAfter", "type": "uint256"}, + ], +} + # x402ExactPermit2Proxy settle ABI X402_EXACT_PERMIT2_PROXY_ABI = [ { @@ -169,6 +193,12 @@ # Gas limit for a standard ERC-20 approve() transaction ERC20_APPROVE_GAS_LIMIT = 70_000 +# Fallback max fee per gas (1 gwei) when fee estimation fails +DEFAULT_MAX_FEE_PER_GAS = 1_000_000_000 + +# Fallback max priority fee per gas (0.1 gwei) when fee estimation fails +DEFAULT_MAX_PRIORITY_FEE_PER_GAS = 100_000_000 + # Permit2 deadline buffer (seconds) for verification PERMIT2_DEADLINE_BUFFER = 6 @@ -200,6 +230,97 @@ } ] +# x402UptoPermit2Proxy settle ABI (note: extra `amount` param vs exact) +X402_UPTO_PERMIT2_PROXY_ABI = [ + { + "type": "function", + "name": "settle", + "inputs": [ + { + "name": "permit", + "type": "tuple", + "components": [ + { + "name": "permitted", + "type": "tuple", + "components": [ + {"name": "token", "type": "address"}, + {"name": "amount", "type": "uint256"}, + ], + }, + {"name": "nonce", "type": "uint256"}, + {"name": "deadline", "type": "uint256"}, + ], + }, + {"name": "amount", "type": "uint256"}, + {"name": "owner", "type": "address"}, + { + "name": "witness", + "type": "tuple", + "components": [ + {"name": "to", "type": "address"}, + {"name": "facilitator", "type": "address"}, + {"name": "validAfter", "type": "uint256"}, + ], + }, + {"name": "signature", "type": "bytes"}, + ], + "outputs": [], + "stateMutability": "nonpayable", + } +] + +# x402UptoPermit2Proxy settleWithPermit ABI (EIP-2612 extension path) +X402_UPTO_PERMIT2_PROXY_SETTLE_WITH_PERMIT_ABI = [ + { + "type": "function", + "name": "settleWithPermit", + "inputs": [ + { + "name": "permit2612", + "type": "tuple", + "components": [ + {"name": "value", "type": "uint256"}, + {"name": "deadline", "type": "uint256"}, + {"name": "r", "type": "bytes32"}, + {"name": "s", "type": "bytes32"}, + {"name": "v", "type": "uint8"}, + ], + }, + { + "name": "permit", + "type": "tuple", + "components": [ + { + "name": "permitted", + "type": "tuple", + "components": [ + {"name": "token", "type": "address"}, + {"name": "amount", "type": "uint256"}, + ], + }, + {"name": "nonce", "type": "uint256"}, + {"name": "deadline", "type": "uint256"}, + ], + }, + {"name": "amount", "type": "uint256"}, + {"name": "owner", "type": "address"}, + { + "name": "witness", + "type": "tuple", + "components": [ + {"name": "to", "type": "address"}, + {"name": "facilitator", "type": "address"}, + {"name": "validAfter", "type": "uint256"}, + ], + }, + {"name": "signature", "type": "bytes"}, + ], + "outputs": [], + "stateMutability": "nonpayable", + } +] + # Error codes ERR_INVALID_SIGNATURE = "invalid_exact_evm_payload_signature" ERR_UNDEPLOYED_SMART_WALLET = "invalid_exact_evm_payload_undeployed_smart_wallet" @@ -227,10 +348,24 @@ ERR_PERMIT2_RECIPIENT_MISMATCH = "invalid_permit2_recipient_mismatch" ERR_PERMIT2_DEADLINE_EXPIRED = "permit2_deadline_expired" ERR_PERMIT2_NOT_YET_VALID = "permit2_not_yet_valid" -ERR_PERMIT2_AMOUNT_MISMATCH = "invalid_exact_evm_payload_amount_mismatch" +ERR_PERMIT2_AMOUNT_MISMATCH = "permit2_amount_mismatch" ERR_PERMIT2_TOKEN_MISMATCH = "permit2_token_mismatch" ERR_PERMIT2_INVALID_SIGNATURE = "invalid_permit2_signature" ERR_PERMIT2_ALLOWANCE_REQUIRED = "permit2_allowance_required" +ERR_PERMIT2_INSUFFICIENT_BALANCE = "permit2_insufficient_balance" +ERR_PERMIT2_INVALID_DESTINATION = "permit2_invalid_destination" +ERR_PERMIT2_INVALID_OWNER = "permit2_invalid_owner" + +# Upto-specific error codes +ERR_UPTO_SETTLEMENT_EXCEEDS_AMOUNT = "invalid_upto_evm_payload_settlement_exceeds_amount" +ERR_UPTO_FACILITATOR_MISMATCH = "upto_facilitator_mismatch" +ERR_UPTO_INVALID_SCHEME = "invalid_upto_evm_scheme" +ERR_UPTO_NETWORK_MISMATCH = "invalid_upto_evm_network_mismatch" +ERR_UPTO_AMOUNT_EXCEEDS_PERMITTED = "upto_amount_exceeds_permitted" +ERR_UPTO_UNAUTHORIZED_FACILITATOR = "upto_unauthorized_facilitator" +ERR_UPTO_TRANSACTION_FAILED = "invalid_upto_evm_transaction_failed" +ERR_UPTO_FAILED_TO_GET_NETWORK_CONFIG = "invalid_upto_evm_failed_to_get_network_config" +ERR_ERC20_APPROVAL_BROADCAST_FAILED = "erc20_approval_broadcast_failed" class _AssetInfoRequired(TypedDict): @@ -375,6 +510,30 @@ class NetworkConfig(_NetworkConfigRequired, total=False): "decimals": 6, }, }, + # Radius Network (uses Permit2 instead of EIP-3009, supports EIP-2612) + "eip155:723487": { + "chain_id": 723487, + "default_asset": { + "address": "0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb", + "name": "Stable Coin", + "version": "1", + "decimals": 6, + "asset_transfer_method": "permit2", + "supports_eip2612": True, + }, + }, + # Radius Testnet (uses Permit2 instead of EIP-3009, supports EIP-2612) + "eip155:72344": { + "chain_id": 72344, + "default_asset": { + "address": "0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb", + "name": "Stable Coin", + "version": "1", + "decimals": 6, + "asset_transfer_method": "permit2", + "supports_eip2612": True, + }, + }, } # V1 legacy constants are in x402.mechanisms.evm.v1.constants diff --git a/python/x402/mechanisms/evm/exact/eip3009_utils.py b/python/x402/mechanisms/evm/exact/eip3009_utils.py index 0b0885e461..b1f096148d 100644 --- a/python/x402/mechanisms/evm/exact/eip3009_utils.py +++ b/python/x402/mechanisms/evm/exact/eip3009_utils.py @@ -9,10 +9,14 @@ BALANCE_OF_ABI, ERR_EIP3009_NOT_SUPPORTED, ERR_INSUFFICIENT_BALANCE, + ERR_INVALID_SIGNATURE, ERR_NONCE_ALREADY_USED, ERR_TOKEN_NAME_MISMATCH, ERR_TOKEN_VERSION_MISMATCH, + ERR_TRANSACTION_FAILED, ERR_TRANSACTION_SIMULATION_FAILED, + ERR_VALID_AFTER_FUTURE, + ERR_VALID_BEFORE_EXPIRED, FUNCTION_TRANSFER_WITH_AUTHORIZATION, NAME_ABI, TRANSFER_WITH_AUTHORIZATION_BYTES_ABI, @@ -267,6 +271,34 @@ def diagnose_eip3009_simulation_failure( return ERR_TRANSACTION_SIMULATION_FAILED +def parse_eip3009_transfer_error(error: Exception) -> str: + """Map an EIP-3009 contract revert to a specific error code. + + Falls back to ERR_TRANSACTION_FAILED when the revert reason is unknown. + """ + msg = str(error).lower() + if "authorization is expired" in msg or "authorizationexpired" in msg: + return ERR_VALID_BEFORE_EXPIRED + if "authorization is not yet valid" in msg or "authorizationnotyetvalid" in msg: + return ERR_VALID_AFTER_FUTURE + if ( + "authorization is used" in msg + or "authorizationalreadyused" in msg + or "authorizationusedorcanceled" in msg + ): + return ERR_NONCE_ALREADY_USED + if "transfer amount exceeds balance" in msg or "erc20insufficientbalance" in msg: + return ERR_INSUFFICIENT_BALANCE + if ( + "invalid signature" in msg + or "signermismatch" in msg + or "invalidsignaturev" in msg + or "invalidsignatures" in msg + ): + return ERR_INVALID_SIGNATURE + return ERR_TRANSACTION_FAILED + + def execute_transfer_with_authorization( signer: FacilitatorEvmSigner, token_address: str, diff --git a/python/x402/mechanisms/evm/exact/facilitator.py b/python/x402/mechanisms/evm/exact/facilitator.py index e7b61010d5..c8b0c67532 100644 --- a/python/x402/mechanisms/evm/exact/facilitator.py +++ b/python/x402/mechanisms/evm/exact/facilitator.py @@ -34,6 +34,7 @@ diagnose_eip3009_simulation_failure, execute_transfer_with_authorization, parse_eip3009_authorization, + parse_eip3009_transfer_error, simulate_eip3009_transfer, ) from ..exact.permit2_utils import settle_permit2, verify_permit2 @@ -379,7 +380,7 @@ def settle( except Exception as e: return SettleResponse( success=False, - error_reason=ERR_TRANSACTION_FAILED, + error_reason=parse_eip3009_transfer_error(e), error_message=str(e), network=network, payer=payer, diff --git a/python/x402/mechanisms/evm/exact/v1/facilitator.py b/python/x402/mechanisms/evm/exact/v1/facilitator.py index 412bece471..7bd59b7573 100644 --- a/python/x402/mechanisms/evm/exact/v1/facilitator.py +++ b/python/x402/mechanisms/evm/exact/v1/facilitator.py @@ -34,6 +34,7 @@ diagnose_eip3009_simulation_failure, execute_transfer_with_authorization, parse_eip3009_authorization, + parse_eip3009_transfer_error, simulate_eip3009_transfer, ) @@ -366,7 +367,7 @@ def settle( except Exception as e: return SettleResponse( success=False, - error_reason=ERR_TRANSACTION_FAILED, + error_reason=parse_eip3009_transfer_error(e), error_message=str(e), network=network, payer=payer, diff --git a/python/x402/mechanisms/evm/signers.py b/python/x402/mechanisms/evm/signers.py index 9774ecf8f5..7b493be70e 100644 --- a/python/x402/mechanisms/evm/signers.py +++ b/python/x402/mechanisms/evm/signers.py @@ -329,7 +329,7 @@ def read_contract( abi=abi, ) func = getattr(contract.functions, function_name) - return func(*args).call() + return func(*args).call({"from": Web3.to_checksum_address(self._account.address)}) def verify_typed_data( self, diff --git a/python/x402/mechanisms/evm/types.py b/python/x402/mechanisms/evm/types.py index 39c66a281c..6d18e2c85a 100644 --- a/python/x402/mechanisms/evm/types.py +++ b/python/x402/mechanisms/evm/types.py @@ -177,6 +177,98 @@ def is_permit2_payload(payload: dict[str, Any]) -> bool: return "permit2Authorization" in payload +@dataclass +class UptoPermit2Witness: + """Witness data for upto Permit2 PermitWitnessTransferFrom. + + Includes facilitator field for access control (vs exact which has only to + validAfter). + """ + + to: str + facilitator: str + valid_after: str + + +@dataclass +class UptoPermit2Authorization: + """Upto Permit2 PermitWitnessTransferFrom data.""" + + from_address: str + permitted: ExactPermit2TokenPermissions + spender: str + nonce: str + deadline: str + witness: UptoPermit2Witness + + +@dataclass +class UptoPermit2Payload: + """Upto payment payload for Permit2 flow.""" + + permit2_authorization: UptoPermit2Authorization + signature: str | None = None + + def to_dict(self) -> dict[str, Any]: + result: dict[str, Any] = { + "permit2Authorization": { + "from": self.permit2_authorization.from_address, + "permitted": { + "token": self.permit2_authorization.permitted.token, + "amount": self.permit2_authorization.permitted.amount, + }, + "spender": self.permit2_authorization.spender, + "nonce": self.permit2_authorization.nonce, + "deadline": self.permit2_authorization.deadline, + "witness": { + "to": self.permit2_authorization.witness.to, + "facilitator": self.permit2_authorization.witness.facilitator, + "validAfter": self.permit2_authorization.witness.valid_after, + }, + } + } + if self.signature: + result["signature"] = self.signature + return result + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> "UptoPermit2Payload": + auth = data.get("permit2Authorization", {}) + permitted = auth.get("permitted", {}) + witness = auth.get("witness", {}) + return cls( + permit2_authorization=UptoPermit2Authorization( + from_address=auth.get("from", ""), + permitted=ExactPermit2TokenPermissions( + token=permitted.get("token", ""), + amount=permitted.get("amount", ""), + ), + spender=auth.get("spender", ""), + nonce=auth.get("nonce", ""), + deadline=auth.get("deadline", ""), + witness=UptoPermit2Witness( + to=witness.get("to", ""), + facilitator=witness.get("facilitator", ""), + valid_after=witness.get("validAfter", ""), + ), + ), + signature=data.get("signature"), + ) + + +def is_upto_permit2_payload(payload: dict[str, Any]) -> bool: + """Check if a raw payload dict is an upto Permit2 payload. + + Distinguishes from exact Permit2 by checking for the facilitator field in witness. + """ + auth = payload.get("permit2Authorization") + if not isinstance(auth, dict): + return False + witness = auth.get("witness") + if not isinstance(witness, dict): + return False + return "facilitator" in witness + + def is_eip3009_payload(payload: dict[str, Any]) -> bool: """Check if a raw payload dict is an EIP-3009 payload. diff --git a/python/x402/mechanisms/evm/upto/__init__.py b/python/x402/mechanisms/evm/upto/__init__.py new file mode 100644 index 0000000000..aab5f5b6f6 --- /dev/null +++ b/python/x402/mechanisms/evm/upto/__init__.py @@ -0,0 +1,20 @@ +"""Upto EVM payment scheme for x402.""" + +from .client import UptoEvmScheme as UptoEvmClientScheme +from .facilitator import ( + UptoEvmScheme as UptoEvmFacilitatorScheme, +) +from .facilitator import ( + UptoEvmSchemeConfig, +) +from .server import UptoEvmScheme as UptoEvmServerScheme + +UptoEvmScheme = UptoEvmClientScheme + +__all__ = [ + "UptoEvmScheme", + "UptoEvmClientScheme", + "UptoEvmServerScheme", + "UptoEvmFacilitatorScheme", + "UptoEvmSchemeConfig", +] diff --git a/python/x402/mechanisms/evm/upto/client.py b/python/x402/mechanisms/evm/upto/client.py new file mode 100644 index 0000000000..8e32b734e5 --- /dev/null +++ b/python/x402/mechanisms/evm/upto/client.py @@ -0,0 +1,299 @@ +"""EVM client implementation for the Upto payment scheme.""" + +from __future__ import annotations + +from typing import Any + +from ....schemas import PaymentRequirements +from ..constants import ( + ERC20_ALLOWANCE_ABI, + PERMIT2_ADDRESS, + SCHEME_UPTO, + UPTO_PERMIT2_WITNESS_TYPES, + X402_UPTO_PERMIT2_PROXY_ADDRESS, +) +from ..signer import ( + ClientEvmSigner, + ClientEvmSignerWithReadContract, + ClientEvmSignerWithSignTransaction, +) +from ..types import ( + ExactPermit2TokenPermissions, + TypedDataField, + UptoPermit2Authorization, + UptoPermit2Payload, + UptoPermit2Witness, +) +from ..utils import ( + create_permit2_nonce, + get_evm_chain_id, + normalize_address, +) + + +def _wrap_if_local_account(signer: Any) -> ClientEvmSigner: + """Auto-wrap eth_account LocalAccount in EthAccountSigner if needed.""" + try: + from eth_account.signers.local import LocalAccount + + if isinstance(signer, LocalAccount): + from ..signers import EthAccountSigner + + return EthAccountSigner(signer) + except ImportError: + pass + return signer + + +class UptoEvmScheme: + """EVM client implementation for the Upto payment scheme. + + Always uses Permit2 with an upto-specific witness that includes a facilitator field. + + Attributes: + scheme: The scheme identifier ("upto"). + """ + + scheme = SCHEME_UPTO + + def __init__(self, signer: ClientEvmSigner): + self._signer = _wrap_if_local_account(signer) + + def create_payment_payload( + self, + requirements: PaymentRequirements, + extensions: dict[str, Any] | None = None, + ) -> dict[str, Any]: + """Create signed upto Permit2 payment payload. + + Requires requirements.extra to contain 'facilitatorAddress'. + """ + result = _create_upto_permit2_payload(self._signer, requirements) + + if extensions: + ext_data = self._try_sign_extensions(requirements, result, extensions) + if ext_data: + result["__extensions"] = ext_data + + return result + + def _try_sign_extensions( + self, + requirements: PaymentRequirements, + result: dict[str, Any], + extensions: dict[str, Any], + ) -> dict[str, Any] | None: + eip2612_ext = self._try_sign_eip2612(requirements, result, extensions) + if eip2612_ext: + return eip2612_ext + + erc20_ext = self._try_sign_erc20_approval(requirements, extensions) + if erc20_ext: + return erc20_ext + + return None + + def _try_sign_eip2612( + self, + requirements: PaymentRequirements, + result: dict[str, Any], + extensions: dict[str, Any], + ) -> dict[str, Any] | None: + from ....extensions.eip2612_gas_sponsoring import EIP2612_GAS_SPONSORING_KEY + from ....extensions.eip2612_gas_sponsoring.client import sign_eip2612_permit + + if EIP2612_GAS_SPONSORING_KEY not in extensions: + return None + + if not isinstance(self._signer, ClientEvmSignerWithReadContract): + return None + + extra = requirements.extra or {} + token_name = extra.get("name") + token_version = extra.get("version") + if not token_name or not token_version: + return None + + chain_id = get_evm_chain_id(str(requirements.network)) + token_address = normalize_address(requirements.asset) + + try: + allowance = self._signer.read_contract( + token_address, + ERC20_ALLOWANCE_ABI, + "allowance", + self._signer.address, + PERMIT2_ADDRESS, + ) + if int(allowance) >= int(requirements.amount): + return None + except Exception: + pass + + permit2_auth = result.get("permit2Authorization", {}) + deadline = permit2_auth.get("deadline", "") + if not deadline: + import time + + deadline = str(int(time.time()) + (requirements.max_timeout_seconds or 3600)) + + info = sign_eip2612_permit( + self._signer, + token_address, + token_name, + token_version, + chain_id, + deadline, + requirements.amount, + ) + + return {EIP2612_GAS_SPONSORING_KEY: {"info": info.to_dict()}} + + def _try_sign_erc20_approval( + self, + requirements: PaymentRequirements, + extensions: dict[str, Any], + ) -> dict[str, Any] | None: + from ....extensions.erc20_approval_gas_sponsoring import ( + ERC20_APPROVAL_GAS_SPONSORING_KEY, + ) + from ....extensions.erc20_approval_gas_sponsoring.client import ( + sign_erc20_approval_transaction, + ) + + if ERC20_APPROVAL_GAS_SPONSORING_KEY not in extensions: + return None + + if not isinstance(self._signer, ClientEvmSignerWithSignTransaction): + return None + + chain_id = get_evm_chain_id(str(requirements.network)) + token_address = normalize_address(requirements.asset) + + if isinstance(self._signer, ClientEvmSignerWithReadContract): + try: + allowance = self._signer.read_contract( + token_address, + ERC20_ALLOWANCE_ABI, + "allowance", + self._signer.address, + PERMIT2_ADDRESS, + ) + if int(allowance) >= int(requirements.amount): + return None + except Exception: + pass + + info = sign_erc20_approval_transaction( + self._signer, + token_address, + chain_id, + ) + + return {ERC20_APPROVAL_GAS_SPONSORING_KEY: {"info": info.to_dict()}} + + +def _create_upto_permit2_payload( + signer: ClientEvmSigner, + requirements: PaymentRequirements, +) -> dict[str, Any]: + """Create a signed upto Permit2 PermitWitnessTransferFrom payload.""" + import time + + extra = requirements.extra or {} + facilitator_address = extra.get("facilitatorAddress") + if not facilitator_address: + raise ValueError( + "upto scheme requires facilitatorAddress in paymentRequirements.extra. " + "Ensure the server is configured with an upto facilitator that provides getExtra()." + ) + + now = int(time.time()) + nonce = create_permit2_nonce() + valid_after = str(now - 600) + deadline = str(now + (requirements.max_timeout_seconds or 3600)) + if int(deadline) <= int(valid_after): + raise ValueError( + f"Invalid time window: deadline ({deadline}) must be after validAfter ({valid_after}). " + f"Check that max_timeout_seconds ({requirements.max_timeout_seconds}) is positive." + ) + + permit2_authorization = UptoPermit2Authorization( + from_address=signer.address, + permitted=ExactPermit2TokenPermissions( + token=normalize_address(requirements.asset), + amount=requirements.amount, + ), + spender=X402_UPTO_PERMIT2_PROXY_ADDRESS, + nonce=nonce, + deadline=deadline, + witness=UptoPermit2Witness( + to=normalize_address(requirements.pay_to), + facilitator=normalize_address(facilitator_address), + valid_after=valid_after, + ), + ) + + signature = _sign_upto_permit2_authorization(signer, permit2_authorization, requirements) + + payload = UptoPermit2Payload( + permit2_authorization=permit2_authorization, + signature=signature, + ) + return payload.to_dict() + + +def _sign_upto_permit2_authorization( + signer: ClientEvmSigner, + permit2_authorization: UptoPermit2Authorization, + requirements: PaymentRequirements, +) -> str: + """Sign an upto Permit2 PermitWitnessTransferFrom using EIP-712.""" + chain_id = get_evm_chain_id(str(requirements.network)) + domain_dict, typed_fields, primary_type, message = _build_upto_permit2_typed_data( + permit2_authorization, chain_id + ) + + sig_bytes = signer.sign_typed_data( + domain_dict, # type: ignore[arg-type] + typed_fields, + primary_type, + message, + ) + return "0x" + sig_bytes.hex() + + +def _build_upto_permit2_typed_data( + permit2_authorization: UptoPermit2Authorization, + chain_id: int, +) -> tuple[dict[str, Any], dict[str, list[TypedDataField]], str, dict[str, Any]]: + """Build EIP-712 typed data for upto Permit2 signature.""" + from ..constants import PERMIT2_ADDRESS + + domain_dict: dict[str, Any] = { + "name": "Permit2", + "chainId": chain_id, + "verifyingContract": PERMIT2_ADDRESS, + } + + message = { + "permitted": { + "token": permit2_authorization.permitted.token, + "amount": int(permit2_authorization.permitted.amount), + }, + "spender": permit2_authorization.spender, + "nonce": int(permit2_authorization.nonce), + "deadline": int(permit2_authorization.deadline), + "witness": { + "to": permit2_authorization.witness.to, + "facilitator": permit2_authorization.witness.facilitator, + "validAfter": int(permit2_authorization.witness.valid_after), + }, + } + + typed_fields: dict[str, list[TypedDataField]] = { + type_name: [TypedDataField(name=f["name"], type=f["type"]) for f in fields] + for type_name, fields in UPTO_PERMIT2_WITNESS_TYPES.items() + } + + return domain_dict, typed_fields, "PermitWitnessTransferFrom", message diff --git a/python/x402/mechanisms/evm/upto/facilitator.py b/python/x402/mechanisms/evm/upto/facilitator.py new file mode 100644 index 0000000000..f8853c8430 --- /dev/null +++ b/python/x402/mechanisms/evm/upto/facilitator.py @@ -0,0 +1,88 @@ +"""EVM facilitator implementation for the Upto payment scheme.""" + +import random +from dataclasses import dataclass +from typing import Any + +from ....schemas import ( + Network, + PaymentPayload, + PaymentRequirements, + SettleResponse, + VerifyResponse, +) +from ..constants import SCHEME_UPTO +from ..signer import FacilitatorEvmSigner +from ..types import is_upto_permit2_payload +from .permit2_utils import settle_upto_permit2, verify_upto_permit2 + + +@dataclass +class UptoEvmSchemeConfig: + """Configuration for upto facilitator behavior.""" + + simulate_in_settle: bool = False + + +class UptoEvmScheme: + """EVM facilitator implementation for the Upto payment scheme. + + Attributes: + scheme: The scheme identifier ("upto"). + caip_family: The CAIP family pattern ("eip155:*"). + """ + + scheme = SCHEME_UPTO + caip_family = "eip155:*" + + def __init__( + self, + signer: FacilitatorEvmSigner, + config: UptoEvmSchemeConfig | None = None, + ): + self._signer = signer + self._config = config or UptoEvmSchemeConfig() + + def get_extra(self, network: Network) -> dict[str, Any] | None: + """Return facilitatorAddress so clients can bind the witness to this facilitator.""" + addresses = self._signer.get_addresses() + if not addresses: + return None + return {"facilitatorAddress": random.choice(addresses)} + + def get_signers(self, network: Network) -> list[str]: + return self._signer.get_addresses() + + def verify( + self, + payload: PaymentPayload, + requirements: PaymentRequirements, + context=None, + ) -> VerifyResponse: + if not is_upto_permit2_payload(payload.payload): + return VerifyResponse( + is_valid=False, invalid_reason="unsupported_payload_type", payer="" + ) + return verify_upto_permit2(self._signer, payload, requirements, context, simulate=True) + + def settle( + self, + payload: PaymentPayload, + requirements: PaymentRequirements, + context=None, + ) -> SettleResponse: + if not is_upto_permit2_payload(payload.payload): + return SettleResponse( + success=False, + error_reason="unsupported_payload_type", + network=str(payload.accepted.network), + payer="", + transaction="", + ) + return settle_upto_permit2( + self._signer, + payload, + requirements, + context, + simulate_in_settle=self._config.simulate_in_settle, + ) diff --git a/python/x402/mechanisms/evm/upto/permit2_utils.py b/python/x402/mechanisms/evm/upto/permit2_utils.py new file mode 100644 index 0000000000..a5727fabd6 --- /dev/null +++ b/python/x402/mechanisms/evm/upto/permit2_utils.py @@ -0,0 +1,847 @@ +"""Permit2 helpers for the upto EVM payment scheme.""" + +from __future__ import annotations + +import logging +import time +from typing import Any + +logger = logging.getLogger("x402.permit2") + +try: + from eth_utils import to_checksum_address +except ImportError as e: + raise ImportError( + "EVM mechanism requires ethereum packages. Install with: pip install x402[evm]" + ) from e + +from ....interfaces import FacilitatorContext # noqa: E402 +from ....schemas import ( # noqa: E402 + PaymentPayload, + PaymentRequirements, + SettleResponse, + VerifyResponse, +) +from ..constants import ( # noqa: E402 + BALANCE_OF_ABI, + ERR_ERC20_APPROVAL_BROADCAST_FAILED, + ERR_PERMIT2_AMOUNT_MISMATCH, + ERR_PERMIT2_DEADLINE_EXPIRED, + ERR_PERMIT2_INSUFFICIENT_BALANCE, + ERR_PERMIT2_INVALID_DESTINATION, + ERR_PERMIT2_INVALID_OWNER, + ERR_PERMIT2_INVALID_SIGNATURE, + ERR_PERMIT2_INVALID_SPENDER, + ERR_PERMIT2_NOT_YET_VALID, + ERR_PERMIT2_RECIPIENT_MISMATCH, + ERR_PERMIT2_TOKEN_MISMATCH, + ERR_UPTO_AMOUNT_EXCEEDS_PERMITTED, + ERR_UPTO_FACILITATOR_MISMATCH, + ERR_UPTO_FAILED_TO_GET_NETWORK_CONFIG, + ERR_UPTO_INVALID_SCHEME, + ERR_UPTO_NETWORK_MISMATCH, + ERR_UPTO_SETTLEMENT_EXCEEDS_AMOUNT, + ERR_UPTO_TRANSACTION_FAILED, + ERR_UPTO_UNAUTHORIZED_FACILITATOR, + PERMIT2_ADDRESS, + SCHEME_UPTO, + TX_STATUS_SUCCESS, + UPTO_PERMIT2_WITNESS_TYPES, + X402_UPTO_PERMIT2_PROXY_ABI, + X402_UPTO_PERMIT2_PROXY_ADDRESS, + X402_UPTO_PERMIT2_PROXY_SETTLE_WITH_PERMIT_ABI, +) + +# Reuse exact's allowance verification and settle error mapping +from ..exact.permit2_utils import ( # noqa: E402 + _verify_permit2_allowance, +) +from ..signer import FacilitatorEvmSigner # noqa: E402 +from ..types import ( # noqa: E402 + TypedDataField, + UptoPermit2Payload, +) +from ..utils import ( # noqa: E402 + get_evm_chain_id, + hex_to_bytes, + normalize_address, +) + + +def verify_upto_permit2( + signer: FacilitatorEvmSigner, + payload: PaymentPayload, + requirements: PaymentRequirements, + context: FacilitatorContext | None = None, + simulate: bool = True, +) -> VerifyResponse: + """Verify an upto Permit2 payment payload. + + Verification cascade: + 1. Scheme check (must be "upto") + 2. Network check + 3. Spender check (must be x402UptoPermit2Proxy) + 4. Recipient check (witness.to must match requirements.pay_to) + 5. Facilitator check (witness.facilitator must match our address) + 6. Deadline check + 7. validAfter check + 8. Amount check (permitted.amount == requirements.amount) + 9. Token check + 10. Signature verification + 11. Allowance check (with extension fallbacks) + 12. Balance check + """ + permit2_payload = UptoPermit2Payload.from_dict(payload.payload) + payer = permit2_payload.permit2_authorization.from_address + + # 1. Scheme check (both payload and requirements must be "upto") + if payload.accepted.scheme != SCHEME_UPTO or requirements.scheme != SCHEME_UPTO: + return VerifyResponse(is_valid=False, invalid_reason=ERR_UPTO_INVALID_SCHEME, payer=payer) + + # 2. Network check + if payload.accepted.network != requirements.network: + return VerifyResponse(is_valid=False, invalid_reason=ERR_UPTO_NETWORK_MISMATCH, payer=payer) + + try: + chain_id = get_evm_chain_id(str(requirements.network)) + except Exception: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_UPTO_FAILED_TO_GET_NETWORK_CONFIG, payer=payer + ) + token_address = normalize_address(requirements.asset) + + # 3. Spender check + try: + spender_norm = normalize_address(permit2_payload.permit2_authorization.spender) + proxy_norm = normalize_address(X402_UPTO_PERMIT2_PROXY_ADDRESS) + except Exception: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_PERMIT2_INVALID_SPENDER, payer=payer + ) + + if spender_norm != proxy_norm: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_PERMIT2_INVALID_SPENDER, payer=payer + ) + + # 4. Recipient check + try: + witness_to = normalize_address(permit2_payload.permit2_authorization.witness.to) + pay_to = normalize_address(requirements.pay_to) + except Exception: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_PERMIT2_RECIPIENT_MISMATCH, payer=payer + ) + + if witness_to != pay_to: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_PERMIT2_RECIPIENT_MISMATCH, payer=payer + ) + + # 5. Facilitator check + facilitator_addresses = signer.get_addresses() + try: + witness_facilitator = normalize_address( + permit2_payload.permit2_authorization.witness.facilitator + ) + except Exception: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_UPTO_FACILITATOR_MISMATCH, payer=payer + ) + + is_facilitator_match = any( + normalize_address(addr) == witness_facilitator for addr in facilitator_addresses + ) + if not is_facilitator_match: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_UPTO_FACILITATOR_MISMATCH, payer=payer + ) + + now = int(time.time()) + + # 6-8. Parse numeric fields + try: + deadline_val = int(permit2_payload.permit2_authorization.deadline) + valid_after_val = int(permit2_payload.permit2_authorization.witness.valid_after) + amount_val = int(permit2_payload.permit2_authorization.permitted.amount) + required_amount = int(requirements.amount) + except (ValueError, TypeError): + return VerifyResponse( + is_valid=False, invalid_reason="invalid_permit2_payload_format", payer=payer + ) + + # 6. Deadline check (6 second buffer) + if deadline_val < now + 6: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_PERMIT2_DEADLINE_EXPIRED, payer=payer + ) + + # 7. validAfter check + if valid_after_val > now: + return VerifyResponse(is_valid=False, invalid_reason=ERR_PERMIT2_NOT_YET_VALID, payer=payer) + + # 8. Amount check (permitted.amount == requirements.amount) + if amount_val != required_amount: + return VerifyResponse( + is_valid=False, + invalid_reason=ERR_PERMIT2_AMOUNT_MISMATCH, + payer=payer, + ) + + # 9. Token check + try: + permitted_token = normalize_address(permit2_payload.permit2_authorization.permitted.token) + except Exception: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_PERMIT2_TOKEN_MISMATCH, payer=payer + ) + + if permitted_token != token_address: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_PERMIT2_TOKEN_MISMATCH, payer=payer + ) + + # 10. Signature verification + if not permit2_payload.signature: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_PERMIT2_INVALID_SIGNATURE, payer=payer + ) + + try: + sig_bytes = hex_to_bytes(permit2_payload.signature) + is_valid_sig = _verify_upto_permit2_signature( + signer, + payer, + permit2_payload.permit2_authorization, + chain_id, + sig_bytes, + ) + if not is_valid_sig: + code = signer.get_code(payer) + if len(code) == 0: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_PERMIT2_INVALID_SIGNATURE, payer=payer + ) + except Exception: + return VerifyResponse( + is_valid=False, invalid_reason=ERR_PERMIT2_INVALID_SIGNATURE, payer=payer + ) + + # If simulation is disabled, skip allowance/balance/simulation checks (matches Go/TS). + if not simulate: + return VerifyResponse(is_valid=True, payer=payer) + + # 11. Allowance check (reuses exact's implementation which handles extension fallbacks) + allowance_result = _verify_permit2_allowance( + signer, payload, requirements, payer, token_address, context + ) + if allowance_result is not None: + return allowance_result + + # 12. Balance check + try: + balance = signer.read_contract(token_address, BALANCE_OF_ABI, "balanceOf", payer) + if int(balance) < int(requirements.amount): + return VerifyResponse( + is_valid=False, invalid_reason=ERR_PERMIT2_INSUFFICIENT_BALANCE, payer=payer + ) + except Exception: + return VerifyResponse(is_valid=False, invalid_reason="balance_check_failed", payer=payer) + + simulation_result = _simulate_upto_verification( + signer, + payload, + requirements, + permit2_payload, + token_address, + payer, + context, + ) + if simulation_result is not None: + return simulation_result + + return VerifyResponse(is_valid=True, payer=payer) + + +def _simulate_upto_settle( + signer: FacilitatorEvmSigner, + permit2_payload: UptoPermit2Payload, + settlement_amount: int, +) -> bool: + """Simulate x402UptoPermit2Proxy.settle(...) via eth_call.""" + try: + permit_tuple, amount, owner_addr, witness_tuple, sig_bytes = ( + _build_upto_permit2_settle_args(permit2_payload, settlement_amount) + ) + signer.read_contract( + X402_UPTO_PERMIT2_PROXY_ADDRESS, + X402_UPTO_PERMIT2_PROXY_ABI, + "settle", + permit_tuple, + amount, + owner_addr, + witness_tuple, + sig_bytes, + ) + return True + except Exception: + return False + + +def _simulate_upto_settle_with_eip2612( + signer: FacilitatorEvmSigner, + permit2_payload: UptoPermit2Payload, + eip2612_info: Any, + settlement_amount: int, +) -> bool: + """Simulate x402UptoPermit2Proxy.settleWithPermit(...) via eth_call.""" + try: + permit_tuple, amount, owner_addr, witness_tuple, sig_bytes = ( + _build_upto_permit2_settle_args(permit2_payload, settlement_amount) + ) + sig_raw = hex_to_bytes(eip2612_info.signature) + if len(sig_raw) != 65: + return False + r = sig_raw[:32] + s = sig_raw[32:64] + v = sig_raw[64] + permit2612_tuple = ( + int(eip2612_info.amount), + int(eip2612_info.deadline), + r, + s, + v, + ) + signer.read_contract( + X402_UPTO_PERMIT2_PROXY_ADDRESS, + X402_UPTO_PERMIT2_PROXY_SETTLE_WITH_PERMIT_ABI, + "settleWithPermit", + permit2612_tuple, + permit_tuple, + amount, + owner_addr, + witness_tuple, + sig_bytes, + ) + return True + except Exception: + return False + + +def _diagnose_upto_simulation_failure( + signer: FacilitatorEvmSigner, + payload: PaymentPayload, + requirements: PaymentRequirements, + token_address: str, + payer: str, + context: FacilitatorContext | None, +) -> str: + """Map failed settlement simulation to the most useful invalid reason.""" + try: + balance = signer.read_contract(token_address, BALANCE_OF_ABI, "balanceOf", payer) + if int(balance) < int(requirements.amount): + return ERR_PERMIT2_INSUFFICIENT_BALANCE + except Exception: + return "balance_check_failed" + + allowance_result = _verify_permit2_allowance( + signer, payload, requirements, payer, token_address, context + ) + if allowance_result is not None: + return allowance_result.invalid_reason + + return ERR_UPTO_TRANSACTION_FAILED + + +def _simulate_upto_verification( + signer: FacilitatorEvmSigner, + payload: PaymentPayload, + requirements: PaymentRequirements, + permit2_payload: UptoPermit2Payload, + token_address: str, + payer: str, + context: FacilitatorContext | None, +) -> VerifyResponse | None: + """Run settle-path simulations during verify for parity with Go/TS.""" + from ....extensions.eip2612_gas_sponsoring import ( + extract_eip2612_gas_sponsoring_info, + validate_eip2612_permit_for_payment, + ) + from ....extensions.erc20_approval_gas_sponsoring import ( + ERC20_APPROVAL_GAS_SPONSORING_KEY, + Erc20ApprovalFacilitatorExtension, + WriteContractCall, + extract_erc20_approval_gas_sponsoring_info, + validate_erc20_approval_for_payment, + ) + + settlement_amount = int(requirements.amount) + + eip2612_info = extract_eip2612_gas_sponsoring_info(payload) + if eip2612_info is not None: + reason = validate_eip2612_permit_for_payment(eip2612_info, payer, token_address) + if reason: + return VerifyResponse(is_valid=False, invalid_reason=reason, payer=payer) + if not _simulate_upto_settle_with_eip2612( + signer, permit2_payload, eip2612_info, settlement_amount + ): + return VerifyResponse( + is_valid=False, + invalid_reason=_diagnose_upto_simulation_failure( + signer, payload, requirements, token_address, payer, context + ), + payer=payer, + ) + return None + + erc20_info = extract_erc20_approval_gas_sponsoring_info(payload) + if erc20_info is not None and context is not None: + ext = context.get_extension(ERC20_APPROVAL_GAS_SPONSORING_KEY) + if isinstance(ext, Erc20ApprovalFacilitatorExtension): + reason, _msg = validate_erc20_approval_for_payment(erc20_info, payer, token_address) + if reason: + return VerifyResponse(is_valid=False, invalid_reason=reason, payer=payer) + + extension_signer = ext.resolve_signer(str(payload.accepted.network)) + simulate_transactions = ( + getattr(extension_signer, "simulate_transactions", None) + if extension_signer is not None + else None + ) + if callable(simulate_transactions): + try: + permit_tuple, amount, owner_addr, witness_tuple, sig_bytes = ( + _build_upto_permit2_settle_args(permit2_payload, settlement_amount) + ) + simulated_ok = bool( + simulate_transactions( + [ + erc20_info.signed_transaction, + WriteContractCall( + address=X402_UPTO_PERMIT2_PROXY_ADDRESS, + abi=X402_UPTO_PERMIT2_PROXY_ABI, + function="settle", + args=[ + permit_tuple, + amount, + owner_addr, + witness_tuple, + sig_bytes, + ], + ), + ] + ) + ) + except Exception: + simulated_ok = False + if not simulated_ok: + return VerifyResponse( + is_valid=False, + invalid_reason=_diagnose_upto_simulation_failure( + signer, payload, requirements, token_address, payer, context + ), + payer=payer, + ) + # Without extension simulation support, allowance/field checks are the best check. + return None + + if not _simulate_upto_settle(signer, permit2_payload, settlement_amount): + return VerifyResponse( + is_valid=False, + invalid_reason=_diagnose_upto_simulation_failure( + signer, payload, requirements, token_address, payer, context + ), + payer=payer, + ) + + return None + + +def settle_upto_permit2( + signer: FacilitatorEvmSigner, + payload: PaymentPayload, + requirements: PaymentRequirements, + context: FacilitatorContext | None = None, + simulate_in_settle: bool = False, +) -> SettleResponse: + """Settle an upto Permit2 payment on-chain. + + The settlement amount comes from requirements.amount (set by the resource server). + It must be <= the authorized maximum (permit2_authorization.permitted.amount). + """ + from ....extensions.eip2612_gas_sponsoring import extract_eip2612_gas_sponsoring_info + from ....extensions.erc20_approval_gas_sponsoring import ( + ERC20_APPROVAL_GAS_SPONSORING_KEY, + Erc20ApprovalFacilitatorExtension, + extract_erc20_approval_gas_sponsoring_info, + ) + + permit2_payload = UptoPermit2Payload.from_dict(payload.payload) + payer = permit2_payload.permit2_authorization.from_address + network = str(requirements.network) + try: + settlement_amount = int(requirements.amount) + except (ValueError, TypeError): + return SettleResponse( + success=False, + error_reason="invalid_permit2_payload_format", + network=network, + payer=payer, + transaction="", + ) + + # Re-verify with permitted.amount (the authorized max), not the settlement amount + verify_requirements = PaymentRequirements( + scheme=requirements.scheme, + network=requirements.network, + asset=requirements.asset, + amount=permit2_payload.permit2_authorization.permitted.amount, + pay_to=requirements.pay_to, + max_timeout_seconds=requirements.max_timeout_seconds, + extra=requirements.extra, + ) + + verify_result = verify_upto_permit2( + signer, + payload, + verify_requirements, + context, + simulate=simulate_in_settle, + ) + if not verify_result.is_valid: + return SettleResponse( + success=False, + error_reason=verify_result.invalid_reason, + network=network, + payer=payer, + transaction="", + ) + + # Zero settlement — no on-chain tx needed + if settlement_amount == 0: + return SettleResponse( + success=True, + transaction="", + network=network, + payer=payer, + amount="0", + ) + + # Guard: settlement amount must not exceed authorized maximum + permitted_amount = int(permit2_payload.permit2_authorization.permitted.amount) + if settlement_amount > permitted_amount: + return SettleResponse( + success=False, + error_reason=ERR_UPTO_SETTLEMENT_EXCEEDS_AMOUNT, + network=network, + payer=payer, + transaction="", + ) + + # Branch: EIP-2612 gas sponsoring (atomic settleWithPermit) + eip2612_info = extract_eip2612_gas_sponsoring_info(payload) + if eip2612_info is not None: + return _settle_upto_with_eip2612( + signer, payload, permit2_payload, eip2612_info, settlement_amount + ) + + # Branch: ERC-20 approval gas sponsoring + erc20_info = extract_erc20_approval_gas_sponsoring_info(payload) + if erc20_info is not None and context is not None: + ext = context.get_extension(ERC20_APPROVAL_GAS_SPONSORING_KEY) + if isinstance(ext, Erc20ApprovalFacilitatorExtension): + extension_signer = ext.resolve_signer(str(payload.accepted.network)) + if extension_signer is not None: + return _settle_upto_with_erc20_approval( + extension_signer, payload, permit2_payload, erc20_info, settlement_amount + ) + + # Branch: standard settle + return _settle_upto_direct(signer, payload, permit2_payload, settlement_amount) + + +def _build_upto_permit2_settle_args( + permit2_payload: UptoPermit2Payload, + settlement_amount: int, +) -> tuple: + """Build settle call arguments for the upto proxy. + + Returns (permit_tuple, amount, owner_addr, witness_tuple, sig_bytes). + """ + sig_bytes = hex_to_bytes(permit2_payload.signature or "") + permit_tuple = ( + ( + to_checksum_address(permit2_payload.permit2_authorization.permitted.token), + int(permit2_payload.permit2_authorization.permitted.amount), + ), + int(permit2_payload.permit2_authorization.nonce), + int(permit2_payload.permit2_authorization.deadline), + ) + owner_addr = to_checksum_address(permit2_payload.permit2_authorization.from_address) + witness_tuple = ( + to_checksum_address(permit2_payload.permit2_authorization.witness.to), + to_checksum_address(permit2_payload.permit2_authorization.witness.facilitator), + int(permit2_payload.permit2_authorization.witness.valid_after), + ) + return permit_tuple, settlement_amount, owner_addr, witness_tuple, sig_bytes + + +def _settle_upto_direct( + signer: FacilitatorEvmSigner, + payload: PaymentPayload, + permit2_payload: UptoPermit2Payload, + settlement_amount: int, +) -> SettleResponse: + """Standard upto Permit2 settle — allowance is already on-chain.""" + payer = permit2_payload.permit2_authorization.from_address + network = str(payload.accepted.network) + + try: + permit_tuple, amount, owner_addr, witness_tuple, sig_bytes = ( + _build_upto_permit2_settle_args(permit2_payload, settlement_amount) + ) + + tx_hash = signer.write_contract( + X402_UPTO_PERMIT2_PROXY_ADDRESS, + X402_UPTO_PERMIT2_PROXY_ABI, + "settle", + permit_tuple, + amount, + owner_addr, + witness_tuple, + sig_bytes, + ) + + receipt = signer.wait_for_transaction_receipt(tx_hash) + if receipt.status != TX_STATUS_SUCCESS: + return SettleResponse( + success=False, + error_reason=ERR_UPTO_TRANSACTION_FAILED, + transaction=tx_hash, + network=network, + payer=payer, + ) + + return SettleResponse( + success=True, + transaction=tx_hash, + network=network, + payer=payer, + amount=str(settlement_amount), + ) + + except Exception as e: + return _map_upto_settle_error(e, network, payer) + + +def _settle_upto_with_eip2612( + signer: FacilitatorEvmSigner, + payload: PaymentPayload, + permit2_payload: UptoPermit2Payload, + eip2612_info: Any, + settlement_amount: int, +) -> SettleResponse: + """Settle via settleWithPermit — includes the EIP-2612 permit atomically.""" + payer = permit2_payload.permit2_authorization.from_address + network = str(payload.accepted.network) + + try: + permit_tuple, amount, owner_addr, witness_tuple, sig_bytes = ( + _build_upto_permit2_settle_args(permit2_payload, settlement_amount) + ) + + sig_hex = eip2612_info.signature + sig_raw = hex_to_bytes(sig_hex) + if len(sig_raw) != 65: + return _map_upto_settle_error( + ValueError("EIP-2612 signature must be 65 bytes"), network, payer + ) + r = sig_raw[:32] + s = sig_raw[32:64] + v = sig_raw[64] + + permit2612_tuple = ( + int(eip2612_info.amount), + int(eip2612_info.deadline), + r, + s, + v, + ) + + tx_hash = signer.write_contract( + X402_UPTO_PERMIT2_PROXY_ADDRESS, + X402_UPTO_PERMIT2_PROXY_SETTLE_WITH_PERMIT_ABI, + "settleWithPermit", + permit2612_tuple, + permit_tuple, + amount, + owner_addr, + witness_tuple, + sig_bytes, + ) + + receipt = signer.wait_for_transaction_receipt(tx_hash) + if receipt.status != TX_STATUS_SUCCESS: + return SettleResponse( + success=False, + error_reason=ERR_UPTO_TRANSACTION_FAILED, + transaction=tx_hash, + network=network, + payer=payer, + ) + + return SettleResponse( + success=True, + transaction=tx_hash, + network=network, + payer=payer, + amount=str(settlement_amount), + ) + + except Exception as e: + return _map_upto_settle_error(e, network, payer) + + +def _settle_upto_with_erc20_approval( + extension_signer: Any, + payload: PaymentPayload, + permit2_payload: UptoPermit2Payload, + erc20_info: Any, + settlement_amount: int, +) -> SettleResponse: + """Settle via extension signer's send_transactions (approval + settle).""" + payer = permit2_payload.permit2_authorization.from_address + network = str(payload.accepted.network) + + try: + permit_tuple, amount, owner_addr, witness_tuple, sig_bytes = ( + _build_upto_permit2_settle_args(permit2_payload, settlement_amount) + ) + + from ....extensions.erc20_approval_gas_sponsoring.types import WriteContractCall + + tx_hashes = extension_signer.send_transactions( + [ + erc20_info.signed_transaction, + WriteContractCall( + address=X402_UPTO_PERMIT2_PROXY_ADDRESS, + abi=X402_UPTO_PERMIT2_PROXY_ABI, + function="settle", + args=[permit_tuple, amount, owner_addr, witness_tuple, sig_bytes], + ), + ] + ) + + settle_tx_hash = tx_hashes[-1] if tx_hashes else "" + receipt = extension_signer.wait_for_transaction_receipt(settle_tx_hash) + if receipt.status != TX_STATUS_SUCCESS: + return SettleResponse( + success=False, + error_reason=ERR_UPTO_TRANSACTION_FAILED, + transaction=settle_tx_hash, + network=network, + payer=payer, + ) + + return SettleResponse( + success=True, + transaction=settle_tx_hash, + network=network, + payer=payer, + amount=str(settlement_amount), + ) + + except Exception as e: + return _map_upto_settle_error(e, network, payer) + + +def _build_upto_permit2_typed_data( + permit2_authorization, + chain_id: int, +) -> tuple[dict[str, Any], dict[str, list[TypedDataField]], str, dict[str, Any]]: + """Build EIP-712 typed data for upto Permit2 signature verification.""" + domain_dict: dict[str, Any] = { + "name": "Permit2", + "chainId": chain_id, + "verifyingContract": PERMIT2_ADDRESS, + } + + message = { + "permitted": { + "token": permit2_authorization.permitted.token, + "amount": int(permit2_authorization.permitted.amount), + }, + "spender": permit2_authorization.spender, + "nonce": int(permit2_authorization.nonce), + "deadline": int(permit2_authorization.deadline), + "witness": { + "to": permit2_authorization.witness.to, + "facilitator": permit2_authorization.witness.facilitator, + "validAfter": int(permit2_authorization.witness.valid_after), + }, + } + + typed_fields: dict[str, list[TypedDataField]] = { + type_name: [TypedDataField(name=f["name"], type=f["type"]) for f in fields] + for type_name, fields in UPTO_PERMIT2_WITNESS_TYPES.items() + } + + return domain_dict, typed_fields, "PermitWitnessTransferFrom", message + + +def _verify_upto_permit2_signature( + signer: FacilitatorEvmSigner, + payer: str, + permit2_authorization, + chain_id: int, + signature: bytes, +) -> bool: + """Verify an upto Permit2 EIP-712 signature.""" + domain_dict, typed_fields, primary_type, message = _build_upto_permit2_typed_data( + permit2_authorization, chain_id + ) + + return signer.verify_typed_data( + payer, + domain_dict, # type: ignore[arg-type] + typed_fields, + primary_type, + message, + signature, + ) + + +def _map_upto_settle_error(error: Exception, network: str, payer: str) -> SettleResponse: + """Map contract revert errors to structured SettleResponse.""" + error_msg = str(error) + if "Permit2612AmountMismatch" in error_msg: + error_reason = "permit2_2612_amount_mismatch" + elif "InvalidAmount" in error_msg: + error_reason = "permit2_invalid_amount" + elif "AmountExceedsPermitted" in error_msg: + error_reason = ERR_UPTO_AMOUNT_EXCEEDS_PERMITTED + elif "UnauthorizedFacilitator" in error_msg: + error_reason = ERR_UPTO_UNAUTHORIZED_FACILITATOR + elif "InvalidDestination" in error_msg: + error_reason = ERR_PERMIT2_INVALID_DESTINATION + elif "InvalidOwner" in error_msg: + error_reason = ERR_PERMIT2_INVALID_OWNER + elif "PaymentTooEarly" in error_msg: + error_reason = "permit2_payment_too_early" + elif "InvalidSignature" in error_msg or "SignatureExpired" in error_msg: + error_reason = ERR_PERMIT2_INVALID_SIGNATURE + elif "InvalidNonce" in error_msg: + error_reason = "permit2_invalid_nonce" + elif "erc20_approval_tx_failed" in error_msg: + error_reason = ERR_ERC20_APPROVAL_BROADCAST_FAILED + else: + error_reason = ERR_UPTO_TRANSACTION_FAILED + + return SettleResponse( + success=False, + error_reason=error_reason, + error_message=error_msg[:500], + network=network, + payer=payer, + transaction="", + ) diff --git a/python/x402/mechanisms/evm/upto/server.py b/python/x402/mechanisms/evm/upto/server.py new file mode 100644 index 0000000000..b9a7508c6d --- /dev/null +++ b/python/x402/mechanisms/evm/upto/server.py @@ -0,0 +1,149 @@ +"""EVM server implementation for the Upto payment scheme.""" + +from collections.abc import Callable + +from ....schemas import AssetAmount, Network, PaymentRequirements, Price, SupportedKind +from ..constants import SCHEME_UPTO +from ..utils import ( + get_asset_info, + get_network_config, + parse_amount, + parse_money_to_decimal, +) + +MoneyParser = Callable[[float, str], AssetAmount | None] + + +class UptoEvmScheme: + """EVM server implementation for the Upto payment scheme. + + Always sets assetTransferMethod=permit2 and injects facilitatorAddress. + + Attributes: + scheme: The scheme identifier ("upto"). + """ + + scheme = SCHEME_UPTO + + def __init__(self): + self._money_parsers: list[MoneyParser] = [] + + def register_money_parser(self, parser: MoneyParser) -> "UptoEvmScheme": + self._money_parsers.append(parser) + return self + + def get_asset_decimals(self, _asset: str, network: Network) -> int: + try: + asset_info = get_asset_info(str(network), _asset) + return asset_info["decimals"] + except ValueError: + pass + return 6 + + def parse_price(self, price: Price, network: Network) -> AssetAmount: + if isinstance(price, dict) and "amount" in price: + if not price.get("asset"): + raise ValueError(f"Asset address required for AssetAmount on {network}") + return AssetAmount( + amount=price["amount"], + asset=price["asset"], + extra=price.get("extra", {}), + ) + + if isinstance(price, AssetAmount): + if not price.asset: + raise ValueError(f"Asset address required for AssetAmount on {network}") + return price + + decimal_amount = parse_money_to_decimal(price) + + for parser in self._money_parsers: + result = parser(decimal_amount, str(network)) + if result is not None: + return result + + return self._default_money_conversion(decimal_amount, str(network)) + + def enhance_payment_requirements( + self, + requirements: PaymentRequirements, + supported_kind: SupportedKind, + extension_keys: list[str], + ) -> PaymentRequirements: + """Add upto-specific enhancements: always permit2 + facilitatorAddress.""" + config = get_network_config(str(requirements.network)) + + if not requirements.asset: + default = config.get("default_asset") + if not default or not default.get("address"): + raise ValueError( + f"No default stablecoin configured for network {requirements.network}; " + "use register_money_parser or specify an explicit asset address" + ) + requirements.asset = default["address"] + + try: + asset_info = get_asset_info(str(requirements.network), requirements.asset) + except ValueError: + asset_info = None + + if "." in requirements.amount: + if asset_info is None: + raise ValueError( + f"Token {requirements.asset} is not a registered asset for network " + f"{requirements.network}; provide amount in atomic units" + ) + requirements.amount = str(parse_amount(requirements.amount, asset_info["decimals"])) + + if requirements.extra is None: + requirements.extra = {} + + # Upto always uses Permit2 + requirements.extra["assetTransferMethod"] = "permit2" + + if asset_info is not None: + requirements.extra.setdefault("name", asset_info.get("name")) + requirements.extra.setdefault("version", asset_info.get("version")) + + # Copy facilitatorAddress from supportedKind.extra (required for upto) + kind_extra = supported_kind.extra or {} + facilitator_address = kind_extra.get("facilitatorAddress") + if not facilitator_address: + raise ValueError( + "upto scheme requires facilitatorAddress in supported kinds. " + "Ensure facilitator get_extra() returns facilitatorAddress." + ) + requirements.extra["facilitatorAddress"] = facilitator_address + + # Copy extension data declared by the facilitator. + for key in extension_keys: + if key in kind_extra: + requirements.extra[key] = kind_extra[key] + + return requirements + + def _default_money_conversion(self, amount: float, network: str) -> AssetAmount: + config = get_network_config(network) + asset = config.get("default_asset") + + if not asset or not asset.get("address"): + raise ValueError( + f"No default stablecoin configured for network {network}; " + "use register_money_parser or specify an explicit AssetAmount" + ) + + token_amount = int(amount * (10 ** asset["decimals"])) + + extra: dict = { + "assetTransferMethod": "permit2", + } + if asset.get("name"): + extra["name"] = asset["name"] + if asset.get("version"): + extra["version"] = asset["version"] + + return AssetAmount( + amount=str(token_amount), + asset=asset["address"], + extra=extra, + ) diff --git a/python/x402/mechanisms/svm/__init__.py b/python/x402/mechanisms/svm/__init__.py index 08947a3ffc..dbf5c48677 100644 --- a/python/x402/mechanisms/svm/__init__.py +++ b/python/x402/mechanisms/svm/__init__.py @@ -17,6 +17,8 @@ ERR_INVALID_COMPUTE_PRICE, ERR_INVALID_INSTRUCTION_COUNT, ERR_INVALID_PAYLOAD, + ERR_MEMO_COUNT, + ERR_MEMO_MISMATCH, ERR_MINT_MISMATCH, ERR_NETWORK_MISMATCH, ERR_NO_TRANSFER_INSTRUCTION, @@ -32,6 +34,7 @@ MAINNET_RPC_URL, MAINNET_WS_URL, MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS, + MAX_MEMO_BYTES, MEMO_PROGRAM_ADDRESS, NETWORK_CONFIGS, SCHEME_EXACT, @@ -98,6 +101,7 @@ "DEFAULT_COMPUTE_UNIT_LIMIT", "DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS", "MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS", + "MAX_MEMO_BYTES", "DEVNET_RPC_URL", "TESTNET_RPC_URL", "MAINNET_RPC_URL", @@ -129,6 +133,8 @@ "ERR_INVALID_COMPUTE_PRICE", "ERR_COMPUTE_PRICE_TOO_HIGH", "ERR_NO_TRANSFER_INSTRUCTION", + "ERR_MEMO_MISMATCH", + "ERR_MEMO_COUNT", "ERR_MINT_MISMATCH", "ERR_RECIPIENT_MISMATCH", "ERR_AMOUNT_INSUFFICIENT", diff --git a/python/x402/mechanisms/svm/constants.py b/python/x402/mechanisms/svm/constants.py index bbe8748428..5ccfd23fac 100644 --- a/python/x402/mechanisms/svm/constants.py +++ b/python/x402/mechanisms/svm/constants.py @@ -35,6 +35,7 @@ DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1 MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 5_000_000 # 5 lamports DEFAULT_COMPUTE_UNIT_LIMIT = 20000 +MAX_MEMO_BYTES = 256 # Solana address validation regex (base58, 32-44 characters) SVM_ADDRESS_REGEX = r"^[1-9A-HJ-NP-Za-km-z]{32,44}$" @@ -86,6 +87,8 @@ ERR_SIMULATION_FAILED = "transaction_simulation_failed" ERR_TRANSACTION_FAILED = "transaction_failed" ERR_DUPLICATE_SETTLEMENT = "duplicate_settlement" +ERR_MEMO_MISMATCH = "invalid_exact_svm_payload_memo_mismatch" +ERR_MEMO_COUNT = "invalid_exact_svm_payload_memo_count" # How long a transaction is held in the duplicate settlement cache (seconds). # Covers the Solana blockhash lifetime (~60-90s) with margin. diff --git a/python/x402/mechanisms/svm/exact/client.py b/python/x402/mechanisms/svm/exact/client.py index 21037c0a27..424da54257 100644 --- a/python/x402/mechanisms/svm/exact/client.py +++ b/python/x402/mechanisms/svm/exact/client.py @@ -22,6 +22,7 @@ COMPUTE_BUDGET_PROGRAM_ADDRESS, DEFAULT_COMPUTE_UNIT_LIMIT, DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS, + MAX_MEMO_BYTES, MEMO_PROGRAM_ADDRESS, NETWORK_CONFIGS, SCHEME_EXACT, @@ -181,11 +182,18 @@ def create_payment_payload( data=transfer_data, ) - # Memo with random nonce for uniqueness (empty accounts - SPL Memo doesn't require signers) + # Memo instruction: use seller-defined memo from extra.memo, or random nonce for uniqueness + seller_memo = extra.get("memo") + if seller_memo and isinstance(seller_memo, str): + memo_data = seller_memo.encode("utf-8") + if len(memo_data) > MAX_MEMO_BYTES: + raise ValueError(f"extra.memo exceeds maximum {MAX_MEMO_BYTES} bytes") + else: + memo_data = binascii.hexlify(os.urandom(16)) memo_ix = Instruction( program_id=Pubkey.from_string(MEMO_PROGRAM_ADDRESS), accounts=[], - data=binascii.hexlify(os.urandom(16)), + data=memo_data, ) # Get latest blockhash diff --git a/python/x402/mechanisms/svm/exact/facilitator.py b/python/x402/mechanisms/svm/exact/facilitator.py index 42b90ce1e8..9211a60608 100644 --- a/python/x402/mechanisms/svm/exact/facilitator.py +++ b/python/x402/mechanisms/svm/exact/facilitator.py @@ -29,6 +29,8 @@ ERR_INVALID_COMPUTE_LIMIT, ERR_INVALID_COMPUTE_PRICE, ERR_INVALID_INSTRUCTION_COUNT, + ERR_MEMO_COUNT, + ERR_MEMO_MISMATCH, ERR_MINT_MISMATCH, ERR_NETWORK_MISMATCH, ERR_NO_TRANSFER_INSTRUCTION, @@ -265,6 +267,21 @@ def verify( ) return VerifyResponse(is_valid=False, invalid_reason=reason, payer=payer) + # Step 5b: Verify memo content matches extra.memo when present + expected_memo = extra.get("memo") + if expected_memo and isinstance(expected_memo, str): + memo_program = Pubkey.from_string(MEMO_PROGRAM_ADDRESS) + memo_ixs = [ + ix + for ix in optional_instructions + if static_accounts[ix.program_id_index] == memo_program + ] + if len(memo_ixs) != 1: + return VerifyResponse(is_valid=False, invalid_reason=ERR_MEMO_COUNT, payer=payer) + actual_memo = bytes(memo_ixs[0].data).decode("utf-8") + if actual_memo != expected_memo: + return VerifyResponse(is_valid=False, invalid_reason=ERR_MEMO_MISMATCH, payer=payer) + # Parse transfer instruction transfer_accounts = list(transfer_ix.accounts) transfer_data = bytes(transfer_ix.data) diff --git a/python/x402/mechanisms/svm/exact/v1/client.py b/python/x402/mechanisms/svm/exact/v1/client.py index 0058f3fde7..a18bdf8865 100644 --- a/python/x402/mechanisms/svm/exact/v1/client.py +++ b/python/x402/mechanisms/svm/exact/v1/client.py @@ -22,6 +22,7 @@ COMPUTE_BUDGET_PROGRAM_ADDRESS, DEFAULT_COMPUTE_UNIT_LIMIT, DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS, + MAX_MEMO_BYTES, MEMO_PROGRAM_ADDRESS, NETWORK_CONFIGS, SCHEME_EXACT, @@ -178,11 +179,18 @@ def create_payment_payload( data=transfer_data, ) - # Memo with random nonce for uniqueness (empty accounts - SPL Memo doesn't require signers) + # Memo instruction: use seller-defined memo from extra.memo, or random nonce for uniqueness + seller_memo = extra.get("memo") + if seller_memo and isinstance(seller_memo, str): + memo_data = seller_memo.encode("utf-8") + if len(memo_data) > MAX_MEMO_BYTES: + raise ValueError(f"extra.memo exceeds maximum {MAX_MEMO_BYTES} bytes") + else: + memo_data = binascii.hexlify(os.urandom(16)) memo_ix = Instruction( program_id=Pubkey.from_string(MEMO_PROGRAM_ADDRESS), accounts=[], - data=binascii.hexlify(os.urandom(16)), + data=memo_data, ) # Get latest blockhash diff --git a/python/x402/mechanisms/svm/exact/v1/facilitator.py b/python/x402/mechanisms/svm/exact/v1/facilitator.py index 389ac2f9a9..6f85bcaf29 100644 --- a/python/x402/mechanisms/svm/exact/v1/facilitator.py +++ b/python/x402/mechanisms/svm/exact/v1/facilitator.py @@ -24,6 +24,8 @@ ERR_INVALID_COMPUTE_LIMIT, ERR_INVALID_COMPUTE_PRICE, ERR_INVALID_INSTRUCTION_COUNT, + ERR_MEMO_COUNT, + ERR_MEMO_MISMATCH, ERR_MINT_MISMATCH, ERR_NETWORK_MISMATCH, ERR_NO_TRANSFER_INSTRUCTION, @@ -251,6 +253,22 @@ def verify( ) return VerifyResponse(is_valid=False, invalid_reason=reason, payer=payer) + # Verify memo content matches extra.memo when present + extra = requirements.extra or {} + expected_memo = extra.get("memo") + if expected_memo and isinstance(expected_memo, str): + memo_program = Pubkey.from_string(MEMO_PROGRAM_ADDRESS) + memo_ixs = [ + ix + for ix in optional_instructions + if static_accounts[ix.program_id_index] == memo_program + ] + if len(memo_ixs) != 1: + return VerifyResponse(is_valid=False, invalid_reason=ERR_MEMO_COUNT, payer=payer) + actual_memo = bytes(memo_ixs[0].data).decode("utf-8") + if actual_memo != expected_memo: + return VerifyResponse(is_valid=False, invalid_reason=ERR_MEMO_MISMATCH, payer=payer) + # Parse transfer instruction transfer_accounts = list(transfer_ix.accounts) transfer_data = bytes(transfer_ix.data) diff --git a/python/x402/mechanisms/tvm/README.md b/python/x402/mechanisms/tvm/README.md new file mode 100644 index 0000000000..52122406d2 --- /dev/null +++ b/python/x402/mechanisms/tvm/README.md @@ -0,0 +1,188 @@ +# x402 TVM Mechanism + +TON/TVM implementation of the x402 payment protocol using the **Exact** payment scheme with jetton transfers relayed through W5R1 and highload-wallet-v3 wallets. + +## Installation + +```bash +uv add x402[tvm] +``` + +## Overview + +Three components for handling x402 payments on TVM-compatible networks: + +- **Client** (`ExactTvmClientScheme`) - Creates signed W5R1 payment payloads +- **Server** (`ExactTvmServerScheme`) - Builds payment requirements and parses prices +- **Facilitator** (`ExactTvmFacilitatorScheme`) - Verifies payloads and relays settlements on-chain + +`ExactTvmScheme` in `x402.mechanisms.tvm.exact` is an alias for the client scheme (`ExactTvmClientScheme`). + +## Quick Start + +### Client + +```python +import os + +from x402 import x402Client +from x402.mechanisms.tvm import ( + TVM_PROVIDER_TONAPI, + TVM_TESTNET, + WalletV5R1Config, + WalletV5R1MnemonicSigner, +) +from x402.mechanisms.tvm.exact import ExactTvmScheme + +config = WalletV5R1Config.from_private_key( + TVM_TESTNET, + os.environ["TVM_CLIENT_PRIVATE_KEY"], +) +config.api_key = os.environ.get("TONCENTER_API_KEY") +# Optional: switch REST + compatible streaming routes to TonAPI. +# config.provider = TVM_PROVIDER_TONAPI +# config.api_key = os.environ.get("TONAPI_API_KEY") +# config.provider_base_url = os.environ.get("TONAPI_BASE_URL") + +signer = WalletV5R1MnemonicSigner(config) + +client = x402Client() +client.register(TVM_TESTNET, ExactTvmScheme(signer=signer)) + +payload = await client.create_payment_payload(payment_required) +``` + +Call `scheme.close()` when you are done with a long-lived `ExactTvmScheme` so its cached provider HTTP clients are released. + +### Server + +```python +from x402 import x402ResourceServer +from x402.mechanisms.tvm.exact import ExactTvmServerScheme + +server = x402ResourceServer(facilitator_client) +server.register("tvm:*", ExactTvmServerScheme()) +``` + +### Facilitator + +```python +import os + +from x402 import x402Facilitator +from x402.mechanisms.tvm import ( + FacilitatorHighloadV3Signer, + HighloadV3Config, + TVM_PROVIDER_TONAPI, + TVM_TESTNET, +) +from x402.mechanisms.tvm.exact import ExactTvmFacilitatorScheme + +config = HighloadV3Config.from_private_key(os.environ["TVM_FACILITATOR_PRIVATE_KEY"]) +config.api_key = os.environ.get("TONCENTER_API_KEY") +# Optional: switch REST + compatible streaming routes to TonAPI. +# config.provider = TVM_PROVIDER_TONAPI +# config.api_key = os.environ.get("TONAPI_API_KEY") +# config.provider_base_url = os.environ.get("TONAPI_BASE_URL") + +signer = FacilitatorHighloadV3Signer({TVM_TESTNET: config}) + +facilitator = x402Facilitator() +facilitator.register([TVM_TESTNET], ExactTvmFacilitatorScheme(signer)) +``` + +## Exports + +### `x402.mechanisms.tvm.exact` + +| Export | Description | +| --------------------------- | ------------------------------------------------ | +| `ExactTvmScheme` | Client scheme (alias for `ExactTvmClientScheme`) | +| `ExactTvmClientScheme` | Client-side payment creation | +| `ExactTvmServerScheme` | Server-side requirement building | +| `ExactTvmFacilitatorScheme` | Facilitator verification/settlement | + +### `x402.mechanisms.tvm` + +| Export | Description | +| ----------------------------- | ------------------------------------------- | +| `ClientTvmSigner` | Protocol for client signers | +| `FacilitatorTvmSigner` | Protocol for facilitator signers | +| `WalletV5R1MnemonicSigner` | Client signer using a W5R1 wallet | +| `FacilitatorHighloadV3Signer` | Facilitator signer using highload-wallet-v3 | +| `ToncenterRestClient` | Toncenter provider client | +| `TonapiRestClient` | TonAPI provider client | +| `create_tvm_provider_client` | Provider factory | +| `TVM_PROVIDER_TONCENTER` | Toncenter provider selector | +| `TVM_PROVIDER_TONAPI` | TonAPI provider selector | +| `TVM_MAINNET` | TON mainnet CAIP-2 identifier | +| `TVM_TESTNET` | TON testnet CAIP-2 identifier | + +## Provider Selection + +Toncenter remains the default provider. Set `config.provider = TVM_PROVIDER_TONAPI` on `WalletV5R1Config` or `HighloadV3Config` to switch REST calls and facilitator streaming to TonAPI. + +- Toncenter REST defaults: `https://toncenter.com`, `https://testnet.toncenter.com` +- TonAPI REST defaults: `https://tonapi.io`, `https://testnet.tonapi.io` + +`config.api_key` is used as `X-Api-Key` for Toncenter and `Authorization: Bearer ` for TonAPI. For custom deployments, set `config.provider_base_url`, `config.provider_timeout_seconds`, and `config.provider_emulation_timeout_seconds`. + +## Supported Networks + +- `tvm:-239` - TON mainnet +- `tvm:-3` - TON testnet +- `tvm:*` - Wildcard (all supported TVM chains) + +## Asset Support + +Supports [TEP-74](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md) jetton payments with explicit asset requirements: + +- Mainnet USDT (`USDT_MAINNET_MINTER`) +- Testnet USDT (`USDT_TESTNET_MINTER`) +- Any TEP-74 jetton when the server is given an explicit asset address + +Server-side prices may be supplied as: + +- `AssetAmount(...)` or `{"amount": "...", "asset": "..."}` for an explicit jetton +- `int`, `float`, or strings like `"$0.01"` and `"0.01 USDT"` for built-in USDT conversion + +For non-default jettons, provide either: + +- the amount in atomic units, or +- `extra.decimals` so decimal amounts can be normalized correctly + +## Testnet funding + +To fund a TVM payer wallet, request testnet TON from [@testgiver_ton_bot](https://t.me/testgiver_ton_bot) for fees. Then open the [testnet USDT transfer link](https://app.tonkeeper.com/transfer/kQDNUDJC0iQvJoZp0ml-YteL1NtTXKphU03CTI5v4VtBhGYs?amount=49000000&bin=te6cckEBAQEAFgAAKClXdJkAAAAAAAAAAAAAAAAAmJaAhDUekg) or scan the QR code below to obtain testnet USDT: + +The facilitator wallet also needs testnet TON (no USDT required) and must hold **at least 1.1 TON** before running tests. + +> **Note:** the facilitator uses a highload-wallet-v3 account, so the facilitator's wallet address differs from your W5 address — fund the highload-v3 address, not the W5 one derived from the same key. + +QR code for the testnet USDT transfer link + +## Technical Details + +### Client Wallet Format + +The TVM client flow uses Wallet V5R1: + +1. Build wallet state init from the configured private key +2. Read account state and seqno from the configured TVM provider +3. Derive the payer jetton wallet for the configured asset +4. Create a signed W5R1 internal message targeting the payer wallet +5. Wrap the message as a base64 BOC settlement payload + +The signer network must match the selected payment requirement network. + +### Facilitator Settlement Flow + +The facilitator batches relay requests through a highload-wallet-v3 account: + +1. Verify the settlement BOC, signature, wallet code hash, wallet id, seqno, timeout, and jetton transfer +2. Reserve the settlement in `SettlementCache` to reject duplicate settlements +3. Batch valid relay requests per network +4. Send the batched external message through the facilitator wallet +5. Wait for finalized trace confirmation through the configured provider APIs + +Call `signer.close()` when you are done with a long-lived facilitator signer so its provider clients and streaming watchers are released. diff --git a/python/x402/mechanisms/tvm/__init__.py b/python/x402/mechanisms/tvm/__init__.py new file mode 100644 index 0000000000..25086a450f --- /dev/null +++ b/python/x402/mechanisms/tvm/__init__.py @@ -0,0 +1,223 @@ +"""TVM mechanism for x402 payment protocol.""" + +from .codecs.common import ( + get_network_global_id, + normalize_address, + parse_amount, + parse_money_to_decimal, +) +from .codecs.jetton import build_jetton_transfer_body, build_jetton_transfer_body_fields +from .codecs.w5 import ( + address_from_state_init, + build_w5_signed_body, + build_w5r1_state_init, + make_w5r1_wallet_id, + verify_w5_signature, +) +from .constants import ( + ALLOWED_CLIENT_CODES, + DEFAULT_DECIMALS, + DEFAULT_HIGHLOAD_SUBWALLET_ID, + DEFAULT_HIGHLOAD_TIMEOUT, + DEFAULT_JETTON_WALLET_MESSAGE_AMOUNT, + DEFAULT_MAX_TIMEOUT_SECONDS, + DEFAULT_RELAY_AMOUNT, + DEFAULT_SETTLEMENT_BATCH_FLUSH_INTERVAL_SECONDS, + DEFAULT_SETTLEMENT_BATCH_FLUSH_SIZE, + DEFAULT_SETTLEMENT_BATCH_MAX_SIZE, + DEFAULT_SETTLEMENT_CONFIRMATION_WORKERS, + DEFAULT_STREAMING_CONFIRMATION_GRACE_SECONDS, + DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + DEFAULT_TONCENTER_TIMEOUT_SECONDS, + DEFAULT_TRACE_CONFIRMATION_TIMEOUT_SECONDS, + DEFAULT_TVM_EMULATION_ADDRESS, + DEFAULT_TVM_EMULATION_RELAY_AMOUNT, + DEFAULT_TVM_EMULATION_SEQNO, + DEFAULT_TVM_EMULATION_WALLET_ID, + DEFAULT_TVM_INNER_GAS_BUFFER, + DEFAULT_TVM_OUTER_GAS_BUFFER, + DEFAULT_W5R1_SUBWALLET_NUMBER, + ERR_EXACT_TVM_ACCOUNT_FROZEN, + ERR_EXACT_TVM_DUPLICATE_SETTLEMENT, + ERR_EXACT_TVM_FACILITATOR_INSUFFICIENT_BALANCE, + ERR_EXACT_TVM_INSUFFICIENT_BALANCE, + ERR_EXACT_TVM_INVALID_AMOUNT, + ERR_EXACT_TVM_INVALID_ASSET, + ERR_EXACT_TVM_INVALID_CODE_HASH, + ERR_EXACT_TVM_INVALID_EXTENSIONS_DICT, + ERR_EXACT_TVM_INVALID_JETTON_TRANSFER, + ERR_EXACT_TVM_INVALID_PAYLOAD, + ERR_EXACT_TVM_INVALID_RECIPIENT, + ERR_EXACT_TVM_INVALID_SEQNO, + ERR_EXACT_TVM_INVALID_SETTLEMENT_BOC, + ERR_EXACT_TVM_INVALID_SIGNATURE, + ERR_EXACT_TVM_INVALID_SIGNATURE_MODE, + ERR_EXACT_TVM_INVALID_UNTIL_EXPIRED, + ERR_EXACT_TVM_INVALID_W5_ACTIONS, + ERR_EXACT_TVM_INVALID_W5_MESSAGE, + ERR_EXACT_TVM_INVALID_WALLET_ID, + ERR_EXACT_TVM_NETWORK_MISMATCH, + ERR_EXACT_TVM_SIMULATION_FAILED, + ERR_EXACT_TVM_TON_AMOUNT_TOO_HIGH, + ERR_EXACT_TVM_TRANSACTION_FAILED, + ERR_EXACT_TVM_UNSUPPORTED_NETWORK, + ERR_EXACT_TVM_UNSUPPORTED_SCHEME, + ERR_EXACT_TVM_UNSUPPORTED_VERSION, + ERR_EXACT_TVM_VALID_UNTIL_TOO_FAR, + HIGHLOAD_V3_CODE_HASH, + HIGHLOAD_V3_CODE_HEX, + JETTON_TRANSFER_OPCODE, + MIN_FACILITATOR_TON_BALANCE, + SCHEME_EXACT, + SEND_MODE_BOUNCE_ON_ACTION_FAIL, + SEND_MODE_CARRY_ALL_BALANCE, + SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE, + SEND_MODE_DESTROY, + SEND_MODE_ESTIMATE_FEE_ONLY, + SEND_MODE_IGNORE_ERRORS, + SEND_MODE_PAY_FEES_SEPARATELY, + SEND_MODE_REGULAR, + SUPPORTED_NETWORKS, + SUPPORTED_TVM_PROVIDERS, + TONAPI_MAINNET_BASE_URL, + TONAPI_TESTNET_BASE_URL, + TONCENTER_MAINNET_BASE_URL, + TONCENTER_TESTNET_BASE_URL, + TVM_MAINNET, + TVM_PROVIDER_TONAPI, + TVM_PROVIDER_TONCENTER, + TVM_TESTNET, + USDT_MAINNET_MINTER, + USDT_TESTNET_MINTER, + W5_EXTERNAL_SIGNED_OPCODE, + W5_INTERNAL_SIGNED_OPCODE, + W5R1_CODE_HASH, + W5R1_CODE_HEX, +) +from .exact.codec import parse_exact_tvm_payload +from .provider import TonapiRestClient, ToncenterRestClient, create_tvm_provider_client +from .settlement_cache import SettlementCache +from .signer import ClientTvmSigner, FacilitatorTvmSigner +from .signers import ( + FacilitatorHighloadV3Signer, + HighloadV3Config, + WalletV5R1Config, + WalletV5R1MnemonicSigner, +) +from .types import ( + ExactTvmPayload, + ParsedJettonTransfer, + ParsedTvmSettlement, + TvmAccountState, + TvmJettonWalletData, + TvmRelayRequest, +) + +__all__ = [ + "SCHEME_EXACT", + "SUPPORTED_NETWORKS", + "TVM_MAINNET", + "TVM_TESTNET", + "DEFAULT_DECIMALS", + "DEFAULT_MAX_TIMEOUT_SECONDS", + "DEFAULT_W5R1_SUBWALLET_NUMBER", + "DEFAULT_HIGHLOAD_SUBWALLET_ID", + "DEFAULT_HIGHLOAD_TIMEOUT", + "DEFAULT_RELAY_AMOUNT", + "DEFAULT_JETTON_WALLET_MESSAGE_AMOUNT", + "MIN_FACILITATOR_TON_BALANCE", + "DEFAULT_TVM_INNER_GAS_BUFFER", + "DEFAULT_TVM_OUTER_GAS_BUFFER", + "DEFAULT_TRACE_CONFIRMATION_TIMEOUT_SECONDS", + "DEFAULT_STREAMING_CONFIRMATION_GRACE_SECONDS", + "DEFAULT_SETTLEMENT_BATCH_FLUSH_INTERVAL_SECONDS", + "DEFAULT_SETTLEMENT_BATCH_FLUSH_SIZE", + "DEFAULT_SETTLEMENT_CONFIRMATION_WORKERS", + "DEFAULT_SETTLEMENT_BATCH_MAX_SIZE", + "DEFAULT_TVM_EMULATION_ADDRESS", + "DEFAULT_TVM_EMULATION_WALLET_ID", + "DEFAULT_TVM_EMULATION_SEQNO", + "DEFAULT_TVM_EMULATION_RELAY_AMOUNT", + "DEFAULT_TONCENTER_TIMEOUT_SECONDS", + "DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS", + "TVM_PROVIDER_TONCENTER", + "TVM_PROVIDER_TONAPI", + "SUPPORTED_TVM_PROVIDERS", + "USDT_MAINNET_MINTER", + "USDT_TESTNET_MINTER", + "TONCENTER_MAINNET_BASE_URL", + "TONCENTER_TESTNET_BASE_URL", + "TONAPI_MAINNET_BASE_URL", + "TONAPI_TESTNET_BASE_URL", + "SEND_MODE_REGULAR", + "SEND_MODE_PAY_FEES_SEPARATELY", + "SEND_MODE_IGNORE_ERRORS", + "SEND_MODE_BOUNCE_ON_ACTION_FAIL", + "SEND_MODE_DESTROY", + "SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE", + "SEND_MODE_CARRY_ALL_BALANCE", + "SEND_MODE_ESTIMATE_FEE_ONLY", + "JETTON_TRANSFER_OPCODE", + "W5_EXTERNAL_SIGNED_OPCODE", + "W5_INTERNAL_SIGNED_OPCODE", + "W5R1_CODE_HASH", + "W5R1_CODE_HEX", + "ALLOWED_CLIENT_CODES", + "HIGHLOAD_V3_CODE_HEX", + "HIGHLOAD_V3_CODE_HASH", + "ERR_EXACT_TVM_UNSUPPORTED_SCHEME", + "ERR_EXACT_TVM_UNSUPPORTED_NETWORK", + "ERR_EXACT_TVM_NETWORK_MISMATCH", + "ERR_EXACT_TVM_UNSUPPORTED_VERSION", + "ERR_EXACT_TVM_INVALID_PAYLOAD", + "ERR_EXACT_TVM_INVALID_SETTLEMENT_BOC", + "ERR_EXACT_TVM_INVALID_W5_MESSAGE", + "ERR_EXACT_TVM_INVALID_W5_ACTIONS", + "ERR_EXACT_TVM_INVALID_JETTON_TRANSFER", + "ERR_EXACT_TVM_INVALID_SIGNATURE", + "ERR_EXACT_TVM_INVALID_CODE_HASH", + "ERR_EXACT_TVM_INVALID_ASSET", + "ERR_EXACT_TVM_TON_AMOUNT_TOO_HIGH", + "ERR_EXACT_TVM_INVALID_EXTENSIONS_DICT", + "ERR_EXACT_TVM_INVALID_RECIPIENT", + "ERR_EXACT_TVM_INVALID_AMOUNT", + "ERR_EXACT_TVM_ACCOUNT_FROZEN", + "ERR_EXACT_TVM_INVALID_SEQNO", + "ERR_EXACT_TVM_INVALID_SIGNATURE_MODE", + "ERR_EXACT_TVM_INVALID_UNTIL_EXPIRED", + "ERR_EXACT_TVM_INVALID_WALLET_ID", + "ERR_EXACT_TVM_VALID_UNTIL_TOO_FAR", + "ERR_EXACT_TVM_INSUFFICIENT_BALANCE", + "ERR_EXACT_TVM_FACILITATOR_INSUFFICIENT_BALANCE", + "ERR_EXACT_TVM_DUPLICATE_SETTLEMENT", + "ERR_EXACT_TVM_SIMULATION_FAILED", + "ERR_EXACT_TVM_TRANSACTION_FAILED", + "ClientTvmSigner", + "FacilitatorTvmSigner", + "WalletV5R1Config", + "WalletV5R1MnemonicSigner", + "FacilitatorHighloadV3Signer", + "HighloadV3Config", + "ToncenterRestClient", + "TonapiRestClient", + "create_tvm_provider_client", + "SettlementCache", + "ExactTvmPayload", + "ParsedJettonTransfer", + "ParsedTvmSettlement", + "TvmAccountState", + "TvmJettonWalletData", + "TvmRelayRequest", + "address_from_state_init", + "build_jetton_transfer_body", + "build_jetton_transfer_body_fields", + "build_w5_signed_body", + "build_w5r1_state_init", + "get_network_global_id", + "make_w5r1_wallet_id", + "normalize_address", + "parse_amount", + "parse_exact_tvm_payload", + "parse_money_to_decimal", + "verify_w5_signature", +] diff --git a/python/x402/mechanisms/tvm/codecs/__init__.py b/python/x402/mechanisms/tvm/codecs/__init__.py new file mode 100644 index 0000000000..caef3aa6b2 --- /dev/null +++ b/python/x402/mechanisms/tvm/codecs/__init__.py @@ -0,0 +1,67 @@ +"""TVM codec helpers for state, message, and payload encoding/decoding.""" + +from .common import ( + address_to_stack_item, + get_network_global_id, + normalize_address, + parse_amount, + parse_money_to_decimal, +) +from .highload_v3 import ( + MAX_BIT_NUMBER, + MAX_SHIFT, + MAX_USABLE_QUERY_SEQNO, + HighloadQueryState, + load_highload_query_state, + query_id_is_processed, + seqno_to_query_id, + serialize_internal_transfer, +) +from .jetton import ( + build_jetton_transfer_body, + build_jetton_transfer_body_fields, + parse_jetton_transfer, +) +from .w5 import ( + address_from_state_init, + build_w5_signed_body, + build_w5r1_state_init, + get_w5_seqno, + make_w5r1_wallet_id, + parse_active_w5_account_state, + parse_out_list, + parse_w5_init_data, + serialize_out_list, + serialize_send_msg_action, + verify_w5_signature, +) + +__all__ = [ + "address_from_state_init", + "address_to_stack_item", + "build_jetton_transfer_body", + "build_jetton_transfer_body_fields", + "build_w5_signed_body", + "build_w5r1_state_init", + "get_network_global_id", + "get_w5_seqno", + "HighloadQueryState", + "load_highload_query_state", + "make_w5r1_wallet_id", + "MAX_BIT_NUMBER", + "MAX_SHIFT", + "MAX_USABLE_QUERY_SEQNO", + "normalize_address", + "parse_active_w5_account_state", + "parse_amount", + "parse_jetton_transfer", + "parse_money_to_decimal", + "parse_out_list", + "parse_w5_init_data", + "query_id_is_processed", + "seqno_to_query_id", + "serialize_internal_transfer", + "serialize_out_list", + "serialize_send_msg_action", + "verify_w5_signature", +] diff --git a/python/x402/mechanisms/tvm/codecs/common.py b/python/x402/mechanisms/tvm/codecs/common.py new file mode 100644 index 0000000000..cf7cd5c4c7 --- /dev/null +++ b/python/x402/mechanisms/tvm/codecs/common.py @@ -0,0 +1,74 @@ +"""Shared TVM codec helpers that are not wallet-contract specific.""" + +from __future__ import annotations + +import base64 +import binascii +import re +from decimal import Decimal + +try: + from pytoniq_core import Address, Builder, Cell +except ImportError as e: + raise ImportError( + "TVM mechanism requires pytoniq packages. Install with: pip install x402[tvm]" + ) from e + + +def normalize_address(address: str | Address) -> str: + """Normalize a TVM address to raw ``wc:hex`` form.""" + if isinstance(address, Address): + return address.to_str(is_user_friendly=False) + return Address(address).to_str(is_user_friendly=False) + + +def address_to_stack_item(address: str) -> object: + """Serialize an address for the Toncenter getter stack.""" + cell = Builder().store_address(Address(address)).end_cell() + return { + "type": "slice", + "value": base64.b64encode(cell.to_boc()).decode("utf-8"), + } + + +def decode_base64_boc(value: object) -> Cell: + """Decode a base64-encoded BoC string into a ``Cell``.""" + if not isinstance(value, str): + raise ValueError("Expected a base64-encoded BoC string") + try: + return Cell.one_from_boc(base64.b64decode(value, validate=True)) + except (ValueError, binascii.Error) as exc: + raise ValueError("Expected a base64-encoded BoC string") from exc + + +def make_zero_bit_cell() -> Cell: + """Build the effective default forward payload: a zero-bit cell.""" + return Builder().store_bit(0).end_cell() + + +def encode_base64_boc(cell: Cell) -> str: + """Encode a single-cell BoC as base64 text.""" + return base64.b64encode(cell.to_boc()).decode("utf-8") + + +def get_network_global_id(network: str) -> int: + """Extract the TVM global network ID from a CAIP-2 network string.""" + if not network.startswith("tvm:"): + raise ValueError(f"Unsupported TVM network: {network}") + return int(network.split(":", 1)[1]) + + +def parse_amount(amount: str, decimals: int) -> int: + """Convert decimal string to smallest unit.""" + return int(Decimal(amount) * Decimal(10**decimals)) + + +def parse_money_to_decimal(money: str | float | int) -> float: + """Parse Money into a decimal float.""" + if isinstance(money, int | float): + return float(money) + + clean = money.strip() + clean = clean.lstrip("$") + clean = re.sub(r"\s*(USD|USDT|usd|usdt)\s*$", "", clean) + return float(clean.strip()) diff --git a/python/x402/mechanisms/tvm/codecs/highload_v3.py b/python/x402/mechanisms/tvm/codecs/highload_v3.py new file mode 100644 index 0000000000..93c27c7a8e --- /dev/null +++ b/python/x402/mechanisms/tvm/codecs/highload_v3.py @@ -0,0 +1,96 @@ +"""Highload V3 state and message codecs.""" + +from __future__ import annotations + +import time +from dataclasses import dataclass + +from ..types import TvmAccountState + +try: + from pytoniq_core import Cell, begin_cell +except ImportError as e: + raise ImportError( + "TVM mechanism requires pytoniq packages. Install with: pip install x402[tvm]" + ) from e + + +MAX_SHIFT = 8191 +MAX_BIT_NUMBER = 1022 +MAX_USABLE_QUERY_SEQNO = MAX_SHIFT * 1023 + (MAX_BIT_NUMBER - 1) + + +@dataclass +class HighloadQueryState: + old_queries: dict[int, Cell] + queries: dict[int, Cell] + + +def seqno_to_query_id(seqno: int) -> int: + """Convert a monotonic seqno into a Highload V3 query id.""" + if seqno < 0 or seqno > MAX_USABLE_QUERY_SEQNO: + raise ValueError("Highload V3 seqno is out of range") + shift = seqno // 1023 + bit_number = seqno % 1023 + return (shift << 10) + bit_number + + +def serialize_internal_transfer(actions: Cell, query_id: int) -> Cell: + """Serialize Highload V3 internal_transfer body that installs OutActions.""" + return ( + begin_cell() + .store_uint(0xAE42E5A4, 32) + .store_uint(query_id, 64) + .store_ref(actions) + .end_cell() + ) + + +def load_highload_query_state( + account_state: TvmAccountState, + *, + expected_code_hash: str, + now: int | None = None, +) -> HighloadQueryState | None: + """Decode current Highload V3 query bitmaps from account state.""" + if not account_state.is_active: + return None + + state_init = account_state.state_init + if state_init is None or state_init.code is None or state_init.data is None: + raise RuntimeError("Active Highload V3 wallet state is missing code or data") + if state_init.code.hash.hex() != expected_code_hash: + raise RuntimeError("Unexpected code hash for Highload V3 facilitator wallet") + + data = state_init.data.begin_parse() + data.load_bytes(32) + data.load_uint(32) + old_queries = data.load_dict(13, value_deserializer=lambda item: item.load_ref()) or {} + queries = data.load_dict(13, value_deserializer=lambda item: item.load_ref()) or {} + last_clean_time = data.load_uint(64) + timeout = data.load_uint(22) + + if now is None: + now = int(time.time()) + + if last_clean_time < now - timeout: + old_queries, queries = queries, {} + if last_clean_time < now - (timeout * 2): + old_queries = {} + + return HighloadQueryState(old_queries=dict(old_queries), queries=dict(queries)) + + +def query_id_is_processed(query_state: HighloadQueryState, query_id: int) -> bool: + """Check whether a Highload V3 query id was already processed.""" + shift = query_id >> 10 + bit_number = query_id & 1023 + return _bitmap_contains(query_state.old_queries.get(shift), bit_number) or _bitmap_contains( + query_state.queries.get(shift), bit_number + ) + + +def _bitmap_contains(bitmap: Cell | None, bit_number: int) -> bool: + if bitmap is None or bit_number >= len(bitmap.bits): + return False + return bitmap.begin_parse().skip_bits(bit_number).preload_bit() != 0 diff --git a/python/x402/mechanisms/tvm/codecs/jetton.py b/python/x402/mechanisms/tvm/codecs/jetton.py new file mode 100644 index 0000000000..3e6b98f4d2 --- /dev/null +++ b/python/x402/mechanisms/tvm/codecs/jetton.py @@ -0,0 +1,98 @@ +"""Jetton-specific TVM payload encoding and decoding.""" + +from __future__ import annotations + +from collections.abc import Mapping + +from ....schemas import PaymentRequirements +from ..constants import ERR_EXACT_TVM_INVALID_JETTON_TRANSFER, JETTON_TRANSFER_OPCODE +from ..types import ParsedJettonTransfer +from .common import decode_base64_boc, normalize_address + +try: + from pytoniq_core import Address, Cell, begin_cell +except ImportError as e: + raise ImportError( + "TVM mechanism requires pytoniq packages. Install with: pip install x402[tvm]" + ) from e + + +def build_jetton_transfer_body(requirements: PaymentRequirements) -> Cell: + """Build a TEP-74 ``transfer`` body from x402 TVM payment requirements.""" + return build_jetton_transfer_body_fields( + amount=int(requirements.amount), + pay_to=requirements.pay_to, + extra=requirements.extra, + ) + + +def build_jetton_transfer_body_fields( + *, + amount: int, + pay_to: str, + extra: Mapping[str, object], +) -> Cell: + """Build a TEP-74 ``transfer`` body from normalized transfer fields.""" + forward_ton_amount = int(extra.get("forwardTonAmount", 0)) + if forward_ton_amount < 0: + raise ValueError("Forward ton amount should be >= 0") + response_destination = extra.get("responseDestination") + + transfer_body = ( + begin_cell() + .store_uint(JETTON_TRANSFER_OPCODE, 32) + .store_uint(0, 64) + .store_coins(amount) + .store_address(Address(pay_to)) + .store_address(response_destination) + .store_bit(0) + .store_coins(forward_ton_amount) + ) + encoded_forward_payload = extra.get("forwardPayload") + if encoded_forward_payload is None: + transfer_body = transfer_body.store_uint(0, 2) + else: + forward_payload = decode_base64_boc(str(encoded_forward_payload)) + transfer_body = transfer_body.store_maybe_ref(forward_payload) + return transfer_body.end_cell() + + +def parse_jetton_transfer(jetton_wallet: str, body: Cell) -> ParsedJettonTransfer: + """ + Parse a TEP-74 `transfer` body: + transfer#0f8a7ea5 query_id:uint64 amount:(VarUInteger 16) destination:MsgAddress + response_destination:MsgAddress custom_payload:(Maybe ^Cell) + forward_ton_amount:(VarUInteger 16) forward_payload:(Either Cell ^Cell) + = InternalMsgBody; + """ + body_slice = body.begin_parse() + + opcode = body_slice.load_uint(32) + if opcode != JETTON_TRANSFER_OPCODE: + raise ValueError(ERR_EXACT_TVM_INVALID_JETTON_TRANSFER) + + body_slice.load_uint(64) + amount = body_slice.load_coins() + destination = body_slice.load_address() + if destination is None: + raise ValueError(ERR_EXACT_TVM_INVALID_JETTON_TRANSFER) + + response_destination = body_slice.load_address() + + if body_slice.load_bit(): + raise ValueError(ERR_EXACT_TVM_INVALID_JETTON_TRANSFER) + forward_ton_amount = body_slice.load_coins() + forward_payload = body_slice.load_ref() if body_slice.load_bit() else body_slice.to_cell() + + return ParsedJettonTransfer( + source_wallet=jetton_wallet, + destination=normalize_address(destination), + response_destination=( + normalize_address(response_destination) if response_destination else None + ), + jetton_amount=amount, + attached_ton_amount=0, + forward_ton_amount=forward_ton_amount, + forward_payload=forward_payload, + body_hash=body.hash, + ) diff --git a/python/x402/mechanisms/tvm/codecs/w5.py b/python/x402/mechanisms/tvm/codecs/w5.py new file mode 100644 index 0000000000..c05ea49495 --- /dev/null +++ b/python/x402/mechanisms/tvm/codecs/w5.py @@ -0,0 +1,168 @@ +"""Wallet V5 R1 codecs and state decoding helpers.""" + +from __future__ import annotations + +from collections.abc import Callable + +from pytoniq_core import TransactionError + +from ..constants import ( + ALLOWED_CLIENT_CODES, + ERR_EXACT_TVM_INVALID_W5_ACTIONS, + ERR_EXACT_TVM_INVALID_W5_MESSAGE, + SEND_MODE_IGNORE_ERRORS, + SEND_MODE_PAY_FEES_SEPARATELY, + W5R1_CODE_HEX, +) +from ..types import TvmAccountState, W5InitData +from .common import get_network_global_id, normalize_address + +try: + from pytoniq_core import Address, Cell, begin_cell + from pytoniq_core.crypto.signature import verify_sign + from pytoniq_core.tlb.account import StateInit + from pytoniq_core.tlb.transaction import OutAction +except ImportError as e: + raise ImportError( + "TVM mechanism requires pytoniq packages. Install with: pip install x402[tvm]" + ) from e + + +def make_w5r1_wallet_id(network: str, workchain: int = 0, subwallet_number: int = 0) -> int: + """Build the unsigned W5R1 wallet_id for a client wallet.""" + network_global_id = get_network_global_id(network) + context = ( + begin_cell() + .store_uint(1, 1) + .store_int(workchain, 8) + .store_uint(0, 8) + .store_uint(subwallet_number, 15) + .end_cell() + .begin_parse() + .load_int(32) + ) + return ((network_global_id & 0xFFFFFFFF) ^ (context & 0xFFFFFFFF)) & 0xFFFFFFFF + + +def address_from_state_init(state_init: StateInit, workchain: int) -> str: + """Compute the contract address derived from ``state_init``.""" + return normalize_address(Address((workchain, state_init.serialize().hash))) + + +def build_w5r1_state_init(public_key: bytes, wallet_id: int) -> StateInit: + """Build a W5R1 wallet StateInit for a client wallet.""" + code = Cell.one_from_boc(bytes.fromhex(W5R1_CODE_HEX)) + + data = ( + begin_cell() + .store_uint(1, 1) + .store_uint(0, 32) + .store_uint(wallet_id, 32) + .store_bytes(public_key) + .store_bit(0) + .end_cell() + ) + return StateInit(code=code, data=data) + + +def parse_w5_init_data(state_init: StateInit) -> W5InitData: + """Extract W5 wallet fields from StateInit data.""" + if state_init.data is None: + raise ValueError(ERR_EXACT_TVM_INVALID_W5_MESSAGE) + data = state_init.data.begin_parse() + result = W5InitData( + signature_allowed=data.load_bit(), + seqno=data.load_uint(32), + wallet_id=data.load_uint(32), + public_key=data.load_bytes(32), + extensions_dict=data.load_maybe_ref(), + ) + if data.remaining_bits or data.remaining_refs: + raise ValueError(ERR_EXACT_TVM_INVALID_W5_MESSAGE) + return result + + +def parse_active_w5_account_state(account_state: TvmAccountState) -> W5InitData: + """Decode W5 state from an active account state.""" + if ( + not account_state.is_active + or account_state.state_init is None + or account_state.state_init.code is None + ): + raise RuntimeError(f"Account {account_state.address} does not have active W5 state") + if account_state.state_init.code.hash.hex() not in ALLOWED_CLIENT_CODES: + raise RuntimeError(f"Account {account_state.address} is not a W5R1 wallet") + return parse_w5_init_data(account_state.state_init) + + +def get_w5_seqno(account_state: TvmAccountState) -> int: + """Extract seqno from W5 account state, treating undeployed accounts as seqno=0.""" + if account_state.is_uninitialized: + return 0 + return parse_active_w5_account_state(account_state).seqno + + +def parse_out_list(cell: Cell) -> list[OutAction]: + """Parse a recursive OutList cell into actions.""" + cell_slice = cell.begin_parse() + out_actions = [] + while cell_slice.remaining_bits or cell_slice.remaining_refs: + n_bits = cell_slice.remaining_bits + n_refs = cell_slice.remaining_refs + if n_refs != 2 or n_bits != 32 + 8: + raise ValueError(ERR_EXACT_TVM_INVALID_W5_ACTIONS) + + prev = cell_slice.load_ref().begin_parse() + try: + out_actions.append(OutAction.deserialize(cell_slice)) + except TransactionError as exc: + raise ValueError(ERR_EXACT_TVM_INVALID_W5_ACTIONS) from exc + cell_slice = prev + + return out_actions + + +def serialize_send_msg_action( + message: Cell, mode: int = SEND_MODE_IGNORE_ERRORS + SEND_MODE_PAY_FEES_SEPARATELY +) -> Cell: + """Serialize one action_send_msg item.""" + return begin_cell().store_uint(0x0EC3C86D, 32).store_uint(mode, 8).store_ref(message).end_cell() + + +def serialize_out_list(actions: list[Cell]) -> Cell: + """Serialize a recursive OutList.""" + out_list = Cell.empty() + for action in actions: + out_list = begin_cell().store_ref(out_list).store_cell(action).end_cell() + return out_list + + +def build_w5_signed_body( + *, + out_message: Cell, + seqno: int, + valid_until: int, + sign_message: Callable[[bytes], bytes], + wallet_id: int, + opcode: int, + send_mode: int = SEND_MODE_PAY_FEES_SEPARATELY, +) -> Cell: + """Build and sign a W5 request body for a single outgoing message.""" + actions = serialize_out_list([serialize_send_msg_action(out_message, send_mode)]) + unsigned_body = ( + begin_cell() + .store_uint(opcode, 32) + .store_uint(wallet_id, 32) + .store_uint(valid_until, 32) + .store_uint(seqno, 32) + .store_maybe_ref(actions) + .store_bit(0) + .end_cell() + ) + signature = sign_message(unsigned_body.hash) + return begin_cell().store_slice(unsigned_body.begin_parse()).store_bytes(signature).end_cell() + + +def verify_w5_signature(public_key: bytes, signed_slice_hash: bytes, signature: bytes) -> bool: + """Verify a signed W5 request body.""" + return bool(verify_sign(public_key, signed_slice_hash, signature)) diff --git a/python/x402/mechanisms/tvm/constants.py b/python/x402/mechanisms/tvm/constants.py new file mode 100644 index 0000000000..7acca31327 --- /dev/null +++ b/python/x402/mechanisms/tvm/constants.py @@ -0,0 +1,96 @@ +"""TVM mechanism constants.""" + +SCHEME_EXACT = "exact" + +TVM_MAINNET = "tvm:-239" +TVM_TESTNET = "tvm:-3" +SUPPORTED_NETWORKS = {TVM_MAINNET, TVM_TESTNET} + +DEFAULT_DECIMALS = 6 +DEFAULT_MAX_TIMEOUT_SECONDS = 300 +DEFAULT_W5R1_SUBWALLET_NUMBER = 0 +DEFAULT_HIGHLOAD_SUBWALLET_ID = 0x10AD +DEFAULT_HIGHLOAD_TIMEOUT = 3600 +DEFAULT_RELAY_AMOUNT = 40_000_000 +DEFAULT_JETTON_WALLET_MESSAGE_AMOUNT = 30_000_000 +MIN_FACILITATOR_TON_BALANCE = 1_040_000_000 # 1.04 TON in nanotons +DEFAULT_TVM_INNER_GAS_BUFFER = 7_100_000 +DEFAULT_TVM_OUTER_GAS_BUFFER = 500_000 +DEFAULT_TONCENTER_TIMEOUT_SECONDS = 2.0 +DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS = 10.0 +DEFAULT_TRACE_CONFIRMATION_TIMEOUT_SECONDS = 20.0 +DEFAULT_STREAMING_CONFIRMATION_GRACE_SECONDS = 3.0 +DEFAULT_SETTLEMENT_BATCH_FLUSH_INTERVAL_SECONDS = 1.0 +DEFAULT_SETTLEMENT_BATCH_FLUSH_SIZE = 100 +DEFAULT_SETTLEMENT_CONFIRMATION_WORKERS = 4 +DEFAULT_SETTLEMENT_BATCH_MAX_SIZE = 185 + +TVM_PROVIDER_TONCENTER = "toncenter" +TVM_PROVIDER_TONAPI = "tonapi" +SUPPORTED_TVM_PROVIDERS = {TVM_PROVIDER_TONCENTER, TVM_PROVIDER_TONAPI} + +TONCENTER_MAINNET_BASE_URL = "https://toncenter.com" +TONCENTER_TESTNET_BASE_URL = "https://testnet.toncenter.com" +TONAPI_MAINNET_BASE_URL = "https://tonapi.io" +TONAPI_TESTNET_BASE_URL = "https://testnet.tonapi.io" + +# Active W5 wallet used only for relay-style fee emulation of sponsored payments. +DEFAULT_TVM_EMULATION_ADDRESS = "0:0f8110d76414005a9f0a7deb4d15938b1cd8db22df3f160ed5b48337735abb62" +DEFAULT_TVM_EMULATION_WALLET_ID = 2147483409 +DEFAULT_TVM_EMULATION_SEQNO = 1 +DEFAULT_TVM_EMULATION_RELAY_AMOUNT = 130_000_000 + +USDT_MAINNET_MINTER = "0:b113a994b5024a16719f69139328eb759596c38a25f59028b146fecdc3621dfe" +USDT_TESTNET_MINTER = "0:f418a04cf196ebc959366844a6cdf53a6fd6fff1eadafc892f05210bba31593e" + +SEND_MODE_REGULAR = 0 +SEND_MODE_PAY_FEES_SEPARATELY = 1 +SEND_MODE_IGNORE_ERRORS = 2 +SEND_MODE_BOUNCE_ON_ACTION_FAIL = 16 +SEND_MODE_DESTROY = 32 +SEND_MODE_CARRY_ALL_REMAINING_MESSAGE_VALUE = 64 +SEND_MODE_CARRY_ALL_BALANCE = 128 +SEND_MODE_ESTIMATE_FEE_ONLY = 1024 + +JETTON_TRANSFER_OPCODE = 0x0F8A7EA5 +W5_EXTERNAL_SIGNED_OPCODE = 0x7369676E +W5_INTERNAL_SIGNED_OPCODE = 0x73696E74 +# fmt: off +W5R1_CODE_HEX = "b5ee9c7241021401000281000114ff00f4a413f4bcf2c80b01020120020d020148030402dcd020d749c120915b8f6320d70b1f2082106578746ebd21821073696e74bdb0925f03e082106578746eba8eb48020d72101d074d721fa4030fa44f828fa443058bd915be0ed44d0810141d721f4058307f40e6fa1319130e18040d721707fdb3ce03120d749810280b99130e070e2100f020120050c020120060902016e07080019adce76a2684020eb90eb85ffc00019af1df6a2684010eb90eb858fc00201480a0b0017b325fb51341c75c875c2c7e00011b262fb513435c280200019be5f0f6a2684080a0eb90fa02c0102f20e011e20d70b1f82107369676ebaf2e08a7f0f01e68ef0eda2edfb218308d722028308d723208020d721d31fd31fd31fed44d0d200d31f20d31fd3ffd70a000af90140ccf9109a28945f0adb31e1f2c087df02b35007b0f2d0845125baf2e0855036baf2e086f823bbf2d0882292f800de01a47fc8ca00cb1f01cf16c9ed542092f80fde70db3cd81003f6eda2edfb02f404216e926c218e4c0221d73930709421c700b38e2d01d72820761e436c20d749c008f2e09320d74ac002f2e09320d71d06c712c2005230b0f2d089d74cd7393001a4e86c128407bbf2e093d74ac000f2e093ed55e2d20001c000915be0ebd72c08142091709601d72c081c12e25210b1e30f20d74a111213009601fa4001fa44f828fa443058baf2e091ed44d0810141d718f405049d7fc8ca0040048307f453f2e08b8e14038307f45bf2e08c22d70a00216e01b3b0f2d090e2c85003cf1612f400c9ed54007230d72c08248e2d21f2e092d200ed44d0d2005113baf2d08f54503091319c01810140d721d70a00f2e08ee2c8ca0058cf16c9ed5493f2c08de20010935bdb31e1d74cd0b4d6c35e" +# fmt: on + +W5R1_CODE_HASH = "20834b7b72b112147e1b2fb457b84e74d1a30f04f737d4f62a668e9552d2b72f" +ALLOWED_CLIENT_CODES = [W5R1_CODE_HASH] + +# fmt: off +HIGHLOAD_V3_CODE_HEX = "b5ee9c7241021001000228000114ff00f4a413f4bcf2c80b01020120020d02014803040078d020d74bc00101c060b0915be101d0d3030171b0915be0fa4030f828c705b39130e0d31f018210ae42e5a4ba9d8040d721d74cf82a01ed55fb04e030020120050a02027306070011adce76a2686b85ffc00201200809001aabb6ed44d0810122d721d70b3f0018aa3bed44d08307d721d70b1f0201200b0c001bb9a6eed44d0810162d721d70b15800e5b8bf2eda2edfb21ab09028409b0ed44d0810120d721f404f404d33fd315d1058e1bf82325a15210b99f326df82305aa0015a112b992306dde923033e2923033e25230800df40f6fa19ed021d721d70a00955f037fdb31e09130e259800df40f6fa19cd001d721d70a00937fdb31e0915be270801f6f2d48308d718d121f900ed44d0d3ffd31ff404f404d33fd315d1f82321a15220b98e12336df82324aa00a112b9926d32de58f82301de541675f910f2a106d0d31fd4d307d30cd309d33fd315d15168baf2a2515abaf2a6f8232aa15250bcf2a304f823bbf2a35304800df40f6fa199d024d721d70a00f2649130e20e01fe5309800df40f6fa18e13d05004d718d20001f264c858cf16cf8301cf168e1030c824cf40cf8384095005a1a514cf40e2f800c94039800df41704c8cbff13cb1ff40012f40012cb3f12cb15c9ed54f80f21d0d30001f265d3020171b0925f03e0fa4001d70b01c000f2a5fa4031fa0031f401fa0031fa00318060d721d300010f0020f265d2000193d431d19130e272b1fb00b585bf03" +# fmt: on +HIGHLOAD_V3_CODE_HASH = "11acad7955844090f283bf238bc1449871f783e7cc0979408d3f4859483e8525" + +ERR_EXACT_TVM_UNSUPPORTED_SCHEME = "unsupported_scheme" +ERR_EXACT_TVM_UNSUPPORTED_VERSION = "unsupported_version" +ERR_EXACT_TVM_UNSUPPORTED_NETWORK = "unsupported_network" +ERR_EXACT_TVM_NETWORK_MISMATCH = "network_mismatch" +ERR_EXACT_TVM_INVALID_PAYLOAD = "invalid_exact_tvm_payload" +ERR_EXACT_TVM_INVALID_SETTLEMENT_BOC = "invalid_exact_tvm_payload_settlement_boc" +ERR_EXACT_TVM_INVALID_W5_MESSAGE = "invalid_exact_tvm_payload_w5_internal_signed_request" +ERR_EXACT_TVM_INVALID_W5_ACTIONS = "invalid_exact_tvm_payload_w5_actions" +ERR_EXACT_TVM_INVALID_JETTON_TRANSFER = "invalid_exact_tvm_payload_jetton_transfer" +ERR_EXACT_TVM_INVALID_SIGNATURE = "invalid_exact_tvm_payload_invalid_signature" +ERR_EXACT_TVM_INVALID_CODE_HASH = "invalid_exact_tvm_payload_invalid_code_hash" +ERR_EXACT_TVM_INVALID_ASSET = "invalid_exact_tvm_payload_asset_mismatch" +ERR_EXACT_TVM_INVALID_RECIPIENT = "invalid_exact_tvm_payload_recipient_mismatch" +ERR_EXACT_TVM_INVALID_AMOUNT = "invalid_exact_tvm_payload_amount_mismatch" +ERR_EXACT_TVM_INVALID_SIGNATURE_MODE = "invalid_exact_tvm_payload_signature_mode_mismatch" +ERR_EXACT_TVM_INVALID_SEQNO = "invalid_exact_tvm_payload_seqno_mismatch" +ERR_EXACT_TVM_INVALID_WALLET_ID = "invalid_exact_tvm_payload_wallet_id_mismatch" +ERR_EXACT_TVM_INVALID_EXTENSIONS_DICT = "invalid_exact_tvm_payload_extensions_dict_mismatch" +ERR_EXACT_TVM_TON_AMOUNT_TOO_HIGH = "invalid_exact_tvm_payload_attached_ton_amount_too_high" +ERR_EXACT_TVM_ACCOUNT_FROZEN = "account_frozen" +ERR_EXACT_TVM_INVALID_UNTIL_EXPIRED = "invalid_exact_tvm_payload_valid_until_expired" +ERR_EXACT_TVM_VALID_UNTIL_TOO_FAR = "invalid_exact_tvm_payload_valid_until_too_far" +ERR_EXACT_TVM_INSUFFICIENT_BALANCE = "insufficient_balance" +ERR_EXACT_TVM_FACILITATOR_INSUFFICIENT_BALANCE = "facilitator_insufficient_balance" +ERR_EXACT_TVM_DUPLICATE_SETTLEMENT = "duplicate_settlement" +ERR_EXACT_TVM_SIMULATION_FAILED = "simulation_failed" +ERR_EXACT_TVM_TRANSACTION_FAILED = "transaction_failed" diff --git a/python/x402/mechanisms/tvm/exact/__init__.py b/python/x402/mechanisms/tvm/exact/__init__.py new file mode 100644 index 0000000000..d8631a903a --- /dev/null +++ b/python/x402/mechanisms/tvm/exact/__init__.py @@ -0,0 +1,14 @@ +"""Exact TVM payment scheme helpers.""" + +from .client import ExactTvmScheme as ExactTvmClientScheme +from .facilitator import ExactTvmScheme as ExactTvmFacilitatorScheme +from .server import ExactTvmScheme as ExactTvmServerScheme + +ExactTvmScheme = ExactTvmClientScheme + +__all__ = [ + "ExactTvmScheme", + "ExactTvmClientScheme", + "ExactTvmFacilitatorScheme", + "ExactTvmServerScheme", +] diff --git a/python/x402/mechanisms/tvm/exact/client.py b/python/x402/mechanisms/tvm/exact/client.py new file mode 100644 index 0000000000..277502fedc --- /dev/null +++ b/python/x402/mechanisms/tvm/exact/client.py @@ -0,0 +1,295 @@ +"""TVM client implementation for the Exact payment scheme (V2).""" + +from __future__ import annotations + +import base64 +import time +from typing import Any + +from ....schemas import PaymentRequirements +from ..codecs.common import normalize_address +from ..codecs.jetton import build_jetton_transfer_body +from ..codecs.w5 import build_w5_signed_body, get_w5_seqno +from ..constants import ( + DEFAULT_JETTON_WALLET_MESSAGE_AMOUNT, + DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + DEFAULT_TONCENTER_TIMEOUT_SECONDS, + DEFAULT_TVM_EMULATION_ADDRESS, + DEFAULT_TVM_EMULATION_RELAY_AMOUNT, + DEFAULT_TVM_EMULATION_SEQNO, + DEFAULT_TVM_EMULATION_WALLET_ID, + DEFAULT_TVM_INNER_GAS_BUFFER, + SCHEME_EXACT, + SEND_MODE_IGNORE_ERRORS, + SEND_MODE_PAY_FEES_SEPARATELY, + SUPPORTED_NETWORKS, + TVM_PROVIDER_TONCENTER, + W5_EXTERNAL_SIGNED_OPCODE, + W5_INTERNAL_SIGNED_OPCODE, +) +from ..provider import TvmProviderClient, create_tvm_provider_client +from ..signer import ClientTvmSigner +from ..trace_utils import ( + parse_trace_transactions, + trace_transaction_compute_fees, + trace_transaction_fwd_fees, + trace_transaction_storage_fees, + transaction_succeeded, +) +from ..types import ExactTvmPayload + +try: + from pytoniq.contract.contract import Contract + from pytoniq_core import Address, Cell +except ImportError as e: + raise ImportError( + "TVM mechanism requires pytoniq packages. Install with: pip install x402[tvm]" + ) from e + + +class ExactTvmScheme: + """TVM client implementation for the Exact payment scheme (V2).""" + + scheme = SCHEME_EXACT + + def __init__(self, signer: ClientTvmSigner) -> None: + self._signer = signer + self._clients: dict[str, TvmProviderClient] = {} + + def close(self) -> None: + """Close any cached provider clients owned by this scheme.""" + for client in self._clients.values(): + client.close() + self._clients.clear() + + def create_payment_payload( + self, + requirements: PaymentRequirements, + ) -> dict[str, Any]: + """Create a signed TON exact payment payload.""" + network = str(requirements.network) + if network not in SUPPORTED_NETWORKS: + raise ValueError(f"Unsupported TVM network: {network}") + if network != self._signer.network: + raise ValueError( + f"Signer network {self._signer.network} does not match requirements network {network}" + ) + if requirements.extra.get("areFeesSponsored") is not True: + raise ValueError("Exact TVM scheme requires extra.areFeesSponsored to be true") + + client = self._get_client(network) + payer = normalize_address(self._signer.address) + asset = normalize_address(requirements.asset) + source_wallet = client.get_jetton_wallet(asset, payer) + + account = client.get_account_state(payer) + include_state_init = not account.is_active + seqno = get_w5_seqno(account) + valid_until = int(time.time()) + ( + requirements.max_timeout_seconds - 5 + if requirements.max_timeout_seconds > 10 + else (requirements.max_timeout_seconds + 1) // 2 + ) + transfer_body = self._build_transfer_body(requirements) + required_inner = self._estimate_required_inner_value( + client=client, + source_wallet=source_wallet, + requirements=requirements, + seqno=seqno, + valid_until=valid_until, + transfer_body=transfer_body, + include_state_init=include_state_init, + ) + + signed_body = self._build_signed_body( + source_wallet=source_wallet, + transfer_body=transfer_body, + seqno=seqno, + valid_until=valid_until, + attached_amount=required_inner, + ) + settlement_boc = self._build_settlement_boc(payer, signed_body, include_state_init) + + return ExactTvmPayload( + settlement_boc=settlement_boc, + asset=asset, + ).to_dict() + + def _get_client(self, network: str) -> TvmProviderClient: + if network not in self._clients: + self._clients[network] = create_tvm_provider_client( + network, + provider=getattr(self._signer, "provider", TVM_PROVIDER_TONCENTER), + api_key=getattr(self._signer, "api_key", None), + base_url=getattr(self._signer, "provider_base_url", None), + timeout=float( + getattr( + self._signer, + "provider_timeout_seconds", + DEFAULT_TONCENTER_TIMEOUT_SECONDS, + ) + ), + ) + return self._clients[network] + + def _build_w5_signed_body( + self, + *, + out_message: Cell, + seqno: int, + valid_until: int, + opcode: int = W5_INTERNAL_SIGNED_OPCODE, + send_mode: int = SEND_MODE_PAY_FEES_SEPARATELY, + wallet_id: int | None = None, + ) -> Cell: + return build_w5_signed_body( + out_message=out_message, + seqno=seqno, + valid_until=valid_until, + sign_message=self._signer.sign_message, + wallet_id=self._signer.wallet_id if wallet_id is None else wallet_id, + opcode=opcode, + send_mode=send_mode, + ) + + def _build_signed_body( + self, + *, + source_wallet: str, + transfer_body: Cell, + seqno: int, + valid_until: int, + attached_amount: int, + opcode: int = W5_INTERNAL_SIGNED_OPCODE, + send_mode: int = SEND_MODE_PAY_FEES_SEPARATELY, + wallet_id: int | None = None, + ) -> Cell: + out_msg = Contract.create_internal_msg( + src=None, + dest=Address(source_wallet), + bounce=True, + value=attached_amount, + body=transfer_body, + ).serialize() + return self._build_w5_signed_body( + out_message=out_msg, + seqno=seqno, + valid_until=valid_until, + opcode=opcode, + send_mode=send_mode, + wallet_id=wallet_id, + ) + + def _build_settlement_boc(self, payer: str, body: Cell, include_state_init: bool) -> str: + message = Contract.create_internal_msg( + src=None, + dest=Address(payer), + bounce=True, + value=0, + state_init=self._signer.state_init if include_state_init else None, + body=body, + ) + return base64.b64encode(message.serialize().to_boc()).decode("utf-8") + + def _build_transfer_body(self, requirements: PaymentRequirements) -> Cell: + return build_jetton_transfer_body(requirements) + + def _estimate_required_inner_value( + self, + *, + client: TvmProviderClient, + source_wallet: str, + requirements: PaymentRequirements, + seqno: int, + valid_until: int, + transfer_body: Cell, + include_state_init: bool, + ) -> int: + forward_ton_amount = int(requirements.extra.get("forwardTonAmount", 0)) + provisional_value = DEFAULT_JETTON_WALLET_MESSAGE_AMOUNT + forward_ton_amount + payer_body = self._build_signed_body( + source_wallet=source_wallet, + transfer_body=transfer_body, + seqno=seqno, + valid_until=valid_until, + attached_amount=provisional_value, + ) + relay_message = Contract.create_internal_msg( + src=None, + dest=Address(self._signer.address), + bounce=True, + value=DEFAULT_TVM_EMULATION_RELAY_AMOUNT, + state_init=self._signer.state_init if include_state_init else None, + body=payer_body, + ).serialize() + external_body = self._build_w5_signed_body( + out_message=relay_message, + seqno=DEFAULT_TVM_EMULATION_SEQNO, + valid_until=valid_until, + opcode=W5_EXTERNAL_SIGNED_OPCODE, + send_mode=SEND_MODE_PAY_FEES_SEPARATELY + SEND_MODE_IGNORE_ERRORS, + wallet_id=DEFAULT_TVM_EMULATION_WALLET_ID, + ) + external_message = Contract.create_external_msg( + dest=Address(DEFAULT_TVM_EMULATION_ADDRESS), + body=external_body, + ) + trace = client.emulate_trace( + external_message.serialize().to_boc(), + ignore_chksig=True, + timeout=float( + getattr( + self._signer, + "provider_emulation_timeout_seconds", + DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + ) + ), + ) + transactions = parse_trace_transactions(trace) + + source_wallet_tx = None + for transaction in transactions: + if normalize_address(transaction["account"]) != normalize_address(source_wallet): + continue + if not transaction_succeeded(transaction): + continue + in_msg = transaction.get("in_msg") or {} + if in_msg.get("decoded_opcode") == "jetton_transfer" and normalize_address( + in_msg["source"] + ) == normalize_address(self._signer.address): + source_wallet_tx = transaction + break + if source_wallet_tx is None: + raise ValueError("Trace does not contain the expected source jetton wallet transaction") + + receiver_wallet_tx = None + for transaction in transactions: + if not transaction_succeeded(transaction): + continue + in_msg = transaction.get("in_msg") or {} + if in_msg.get("decoded_opcode") == "jetton_internal_transfer" and normalize_address( + in_msg["source"] + ) == normalize_address(source_wallet): + receiver_wallet_tx = transaction + break + if receiver_wallet_tx is None: + raise ValueError( + "Trace does not contain the expected destination jetton wallet transaction" + ) + + forward_fees = trace_transaction_fwd_fees( + source_wallet_tx, + expected_count=2 if forward_ton_amount > 0 else 1, + ) + compute_fee_source = trace_transaction_compute_fees(source_wallet_tx) + compute_fee_destination = trace_transaction_compute_fees(receiver_wallet_tx) + storage_fees_source = trace_transaction_storage_fees(source_wallet_tx) + + return ( + DEFAULT_TVM_INNER_GAS_BUFFER + + forward_fees + + compute_fee_source + + compute_fee_destination + + forward_ton_amount + + storage_fees_source + ) diff --git a/python/x402/mechanisms/tvm/exact/codec.py b/python/x402/mechanisms/tvm/exact/codec.py new file mode 100644 index 0000000000..e34a89c079 --- /dev/null +++ b/python/x402/mechanisms/tvm/exact/codec.py @@ -0,0 +1,102 @@ +"""Exact TVM settlement payload codec.""" + +from __future__ import annotations + +import base64 + +from ..codecs.common import normalize_address +from ..codecs.jetton import parse_jetton_transfer +from ..codecs.w5 import parse_out_list +from ..constants import ( + ERR_EXACT_TVM_INVALID_SETTLEMENT_BOC, + ERR_EXACT_TVM_INVALID_W5_ACTIONS, + ERR_EXACT_TVM_INVALID_W5_MESSAGE, + SEND_MODE_IGNORE_ERRORS, + SEND_MODE_PAY_FEES_SEPARATELY, + W5_INTERNAL_SIGNED_OPCODE, +) +from ..types import ParsedTvmSettlement + +try: + from pytoniq_core import Cell + from pytoniq_core.tlb.transaction import MessageAny +except ImportError as e: + raise ImportError( + "TVM mechanism requires pytoniq packages. Install with: pip install x402[tvm]" + ) from e + + +def parse_exact_tvm_payload(settlement_boc: str) -> ParsedTvmSettlement: + """Parse an exact TVM settlement payload into structured fields.""" + try: + root = Cell.one_from_boc(base64.b64decode(settlement_boc)) + message = MessageAny.deserialize(root.begin_parse()) + except Exception as exc: + raise ValueError(ERR_EXACT_TVM_INVALID_SETTLEMENT_BOC) from exc + + if not message.is_internal or message.info.dest is None: + raise ValueError(ERR_EXACT_TVM_INVALID_SETTLEMENT_BOC) + + payer = normalize_address(message.info.dest) + state_init = message.init + body = message.body + + body_slice = body.begin_parse() + opcode = body_slice.load_uint(32) + if opcode != W5_INTERNAL_SIGNED_OPCODE: + raise ValueError(ERR_EXACT_TVM_INVALID_W5_MESSAGE) + + wallet_id = body_slice.load_uint(32) + valid_until = body_slice.load_uint(32) + seqno = body_slice.load_uint(32) + + has_actions = body_slice.load_bit() + actions = parse_out_list(body_slice.load_ref()) if has_actions else [] + has_extra_actions = body_slice.load_bit() + if has_extra_actions: + raise ValueError(ERR_EXACT_TVM_INVALID_W5_ACTIONS) + + if len(actions) != 1 or actions[0].type_ != "action_send_msg": + raise ValueError(ERR_EXACT_TVM_INVALID_W5_ACTIONS) + + action = actions[0] + if ( + not action.out_msg.is_internal + or action.out_msg.info.dest is None + or not action.out_msg.info.bounce + ): + raise ValueError(ERR_EXACT_TVM_INVALID_W5_ACTIONS) + + allowed_send_modes = { + SEND_MODE_PAY_FEES_SEPARATELY, + SEND_MODE_PAY_FEES_SEPARATELY + SEND_MODE_IGNORE_ERRORS, + } + if action.mode not in allowed_send_modes: + raise ValueError(ERR_EXACT_TVM_INVALID_W5_ACTIONS) + + transfer = parse_jetton_transfer( + jetton_wallet=normalize_address(action.out_msg.info.dest), + body=action.out_msg.body, + ) + transfer.attached_ton_amount = action.out_msg.info.value_coins + + signature = body_slice.load_bytes(64) + if body_slice.remaining_bits or body_slice.remaining_refs: + raise ValueError(ERR_EXACT_TVM_INVALID_W5_MESSAGE) + + signed_slice = body.begin_parse().copy() + signed_slice.bits = signed_slice.bits[:-512] + signed_slice_hash = signed_slice.to_cell().hash + + return ParsedTvmSettlement( + payer=payer, + wallet_id=wallet_id, + valid_until=valid_until, + seqno=seqno, + settlement_hash=root.hash.hex(), + body=body, + signed_slice_hash=signed_slice_hash, + signature=signature, + state_init=state_init, + transfer=transfer, + ) diff --git a/python/x402/mechanisms/tvm/exact/facilitator.py b/python/x402/mechanisms/tvm/exact/facilitator.py new file mode 100644 index 0000000000..d88cf4fc34 --- /dev/null +++ b/python/x402/mechanisms/tvm/exact/facilitator.py @@ -0,0 +1,525 @@ +"""TVM facilitator implementation for the Exact payment scheme (V2).""" + +from __future__ import annotations + +import time +from typing import Any + +from pytoniq_core import begin_cell + +from ....schemas import ( + Network, + PaymentPayload, + PaymentRequirements, + SettleResponse, + VerifyResponse, +) +from ..codecs.common import decode_base64_boc, normalize_address +from ..codecs.w5 import ( + address_from_state_init, + parse_active_w5_account_state, + parse_w5_init_data, + verify_w5_signature, +) +from ..constants import ( + ALLOWED_CLIENT_CODES, + DEFAULT_JETTON_WALLET_MESSAGE_AMOUNT, + DEFAULT_SETTLEMENT_BATCH_FLUSH_INTERVAL_SECONDS, + DEFAULT_SETTLEMENT_BATCH_FLUSH_SIZE, + DEFAULT_SETTLEMENT_CONFIRMATION_WORKERS, + DEFAULT_TRACE_CONFIRMATION_TIMEOUT_SECONDS, + DEFAULT_TVM_OUTER_GAS_BUFFER, + ERR_EXACT_TVM_ACCOUNT_FROZEN, + ERR_EXACT_TVM_DUPLICATE_SETTLEMENT, + ERR_EXACT_TVM_FACILITATOR_INSUFFICIENT_BALANCE, + ERR_EXACT_TVM_INSUFFICIENT_BALANCE, + ERR_EXACT_TVM_INVALID_AMOUNT, + ERR_EXACT_TVM_INVALID_ASSET, + ERR_EXACT_TVM_INVALID_CODE_HASH, + ERR_EXACT_TVM_INVALID_EXTENSIONS_DICT, + ERR_EXACT_TVM_INVALID_JETTON_TRANSFER, + ERR_EXACT_TVM_INVALID_PAYLOAD, + ERR_EXACT_TVM_INVALID_RECIPIENT, + ERR_EXACT_TVM_INVALID_SEQNO, + ERR_EXACT_TVM_INVALID_SIGNATURE, + ERR_EXACT_TVM_INVALID_SIGNATURE_MODE, + ERR_EXACT_TVM_INVALID_UNTIL_EXPIRED, + ERR_EXACT_TVM_INVALID_W5_MESSAGE, + ERR_EXACT_TVM_INVALID_WALLET_ID, + ERR_EXACT_TVM_NETWORK_MISMATCH, + ERR_EXACT_TVM_SIMULATION_FAILED, + ERR_EXACT_TVM_TON_AMOUNT_TOO_HIGH, + ERR_EXACT_TVM_TRANSACTION_FAILED, + ERR_EXACT_TVM_UNSUPPORTED_NETWORK, + ERR_EXACT_TVM_UNSUPPORTED_SCHEME, + ERR_EXACT_TVM_UNSUPPORTED_VERSION, + ERR_EXACT_TVM_VALID_UNTIL_TOO_FAR, + MIN_FACILITATOR_TON_BALANCE, + SCHEME_EXACT, + SUPPORTED_NETWORKS, +) +from ..settlement_cache import SettlementCache +from ..signer import FacilitatorTvmSigner +from ..trace_utils import ( + message_body_hash_matches, + parse_trace_transactions, + trace_transaction_compute_fees, + trace_transaction_fwd_fees, + trace_transaction_hash_to_hex, + trace_transaction_storage_fees, + transaction_succeeded, +) +from ..types import ExactTvmPayload, ParsedTvmSettlement, TvmRelayRequest, W5InitData +from .codec import parse_exact_tvm_payload +from .settlement_batcher import _BatchResult, _QueuedSettlement, _SettlementBatcher + + +def _effective_response_destination(extra: dict[str, Any]) -> str | None: + response_destination = extra.get("responseDestination") + if response_destination is None: + return None + return normalize_address(response_destination) + + +def _effective_forward_ton_amount(extra: dict[str, Any]) -> int: + return int(extra.get("forwardTonAmount", 0)) + + +def _effective_forward_payload(extra: dict[str, Any]): + encoded_payload = extra.get("forwardPayload") + if encoded_payload is None: + return begin_cell().store_bit(0).end_cell() + return decode_base64_boc(encoded_payload) + + +class ExactTvmScheme: + """TVM facilitator implementation for the Exact payment scheme (V2).""" + + scheme = SCHEME_EXACT + caip_family = "tvm:*" + + def __init__( + self, + signer: FacilitatorTvmSigner, + settlement_cache: SettlementCache | None = None, + *, + batch_flush_interval_seconds: float = DEFAULT_SETTLEMENT_BATCH_FLUSH_INTERVAL_SECONDS, + batch_flush_size: int = DEFAULT_SETTLEMENT_BATCH_FLUSH_SIZE, + confirmation_workers: int = DEFAULT_SETTLEMENT_CONFIRMATION_WORKERS, + confirmation_timeout_seconds: float = DEFAULT_TRACE_CONFIRMATION_TIMEOUT_SECONDS, + ) -> None: + self._signer = signer + self._settlement_cache = settlement_cache or SettlementCache() + self._batcher = _SettlementBatcher( + signer, + self._settlement_cache, + flush_interval_seconds=batch_flush_interval_seconds, + batch_flush_size=batch_flush_size, + confirmation_workers=confirmation_workers, + confirmation_timeout_seconds=confirmation_timeout_seconds, + settlement_verifier=lambda trace_data, settlement: ( + self._verify_finalized_trace_settlement( + trace_data, + settlement=settlement, + ) + ), + ) + + def get_extra(self, network: Network) -> dict[str, Any] | None: + """Get mechanism-specific extra data.""" + if str(network) not in SUPPORTED_NETWORKS: + return None + return {"areFeesSponsored": True} + + def get_signers(self, network: Network) -> list[str]: + """Get facilitator wallet addresses.""" + return self._signer.get_addresses_for_network(str(network)) + + def verify( + self, + payload: PaymentPayload, + requirements: PaymentRequirements, + context=None, + ) -> VerifyResponse: + """Verify a TON exact payment payload.""" + try: + tvm_payload = ExactTvmPayload.from_dict(payload.payload) + except ValueError as e: + return VerifyResponse( + is_valid=False, + invalid_reason=ERR_EXACT_TVM_INVALID_PAYLOAD, + invalid_message=str(e), + payer="", + ) + + try: + settlement = parse_exact_tvm_payload(tvm_payload.settlement_boc) + verification, _ = self._verify(payload, requirements, tvm_payload, settlement) + return verification + except ValueError as e: + return VerifyResponse(is_valid=False, invalid_reason=str(e), payer="") + except Exception as e: + return VerifyResponse( + is_valid=False, + invalid_reason=ERR_EXACT_TVM_SIMULATION_FAILED, + invalid_message=str(e), + payer="", + ) + + def settle( + self, + payload: PaymentPayload, + requirements: PaymentRequirements, + context=None, + ) -> SettleResponse: + """Settle a TON exact payment payload.""" + try: + tvm_payload = ExactTvmPayload.from_dict(payload.payload) + except ValueError as e: + return SettleResponse( + success=False, + error_reason=ERR_EXACT_TVM_INVALID_PAYLOAD, + error_message=str(e), + payer="", + transaction="", + network=requirements.network, + ) + + try: + settlement = parse_exact_tvm_payload(tvm_payload.settlement_boc) + verification, relay_request = self._verify( + payload, requirements, tvm_payload, settlement + ) + except ValueError as e: + return SettleResponse( + success=False, + error_reason=str(e), + payer="", + transaction="", + network=requirements.network, + ) + except Exception as e: + return SettleResponse( + success=False, + error_reason=ERR_EXACT_TVM_SIMULATION_FAILED, + error_message=str(e), + payer="", + transaction="", + network=requirements.network, + ) + if not verification.is_valid: + return SettleResponse( + success=False, + error_reason=verification.invalid_reason, + error_message=verification.invalid_message, + payer=verification.payer, + transaction="", + network=requirements.network, + ) + + if self._settlement_cache.is_duplicate( + settlement.settlement_hash, requirements.max_timeout_seconds + ): + return SettleResponse( + success=False, + error_reason=ERR_EXACT_TVM_DUPLICATE_SETTLEMENT, + payer=settlement.payer, + transaction="", + network=requirements.network, + ) + + try: + batch_result = self._batcher.enqueue( + _QueuedSettlement( + network=str(requirements.network), + settlement_hash=settlement.settlement_hash, + settlement=settlement, + relay_request=relay_request, + ) + ) + except Exception as e: + self._settlement_cache.release(settlement.settlement_hash) + batch_result = _BatchResult( + success=False, + error_reason=ERR_EXACT_TVM_TRANSACTION_FAILED, + error_message=str(e), + ) + + return SettleResponse( + success=batch_result.success, + error_reason=batch_result.error_reason, + error_message=batch_result.error_message, + payer=settlement.payer, + transaction=batch_result.transaction, + network=requirements.network, + ) + + def _verify( + self, + payload: PaymentPayload, + requirements: PaymentRequirements, + tvm_payload: ExactTvmPayload, + settlement: ParsedTvmSettlement, + ) -> tuple[VerifyResponse, TvmRelayRequest | None]: + payer = settlement.payer + + def invalid_response(reason: str) -> tuple[VerifyResponse, TvmRelayRequest | None]: + return (VerifyResponse(is_valid=False, invalid_reason=reason, payer=payer), None) + + if payload.x402_version != 2: + return invalid_response(ERR_EXACT_TVM_UNSUPPORTED_VERSION) + + if payload.accepted.scheme != SCHEME_EXACT or requirements.scheme != SCHEME_EXACT: + return invalid_response(ERR_EXACT_TVM_UNSUPPORTED_SCHEME) + + if str(requirements.network) not in SUPPORTED_NETWORKS: + return invalid_response(ERR_EXACT_TVM_UNSUPPORTED_NETWORK) + + if str(payload.accepted.network) != str(requirements.network): + return invalid_response(ERR_EXACT_TVM_NETWORK_MISMATCH) + + facilitator_addresses = self._signer.get_addresses_for_network(str(requirements.network)) + for facilitator_address in facilitator_addresses: + facilitator_state = self._signer.get_account_state( + facilitator_address, str(requirements.network) + ) + if facilitator_state.balance < MIN_FACILITATOR_TON_BALANCE: + return ( + VerifyResponse( + is_valid=False, + invalid_reason=ERR_EXACT_TVM_FACILITATOR_INSUFFICIENT_BALANCE, + invalid_message=( + f"Facilitator wallet {facilitator_address} balance " + f"{facilitator_state.balance} nanotons is below required " + f"{MIN_FACILITATOR_TON_BALANCE} nanotons (1.1 TON)" + ), + payer=payer, + ), + None, + ) + + if int(payload.accepted.amount) != int(requirements.amount): + return invalid_response(ERR_EXACT_TVM_INVALID_AMOUNT) + + if normalize_address(payload.accepted.asset) != normalize_address(requirements.asset): + return invalid_response(ERR_EXACT_TVM_INVALID_ASSET) + + if normalize_address(payload.accepted.pay_to) != normalize_address(requirements.pay_to): + return invalid_response(ERR_EXACT_TVM_INVALID_RECIPIENT) + + if ( + payload.accepted.extra.get("areFeesSponsored") is not True + or requirements.extra.get("areFeesSponsored") is not True + ): + return invalid_response(ERR_EXACT_TVM_UNSUPPORTED_SCHEME) + + if normalize_address(tvm_payload.asset) != normalize_address(requirements.asset): + return invalid_response(ERR_EXACT_TVM_INVALID_ASSET) + + expected_response_destination = _effective_response_destination(requirements.extra) + if _effective_response_destination(payload.accepted.extra) != expected_response_destination: + return invalid_response(ERR_EXACT_TVM_INVALID_JETTON_TRANSFER) + + expected_forward_ton_amount = _effective_forward_ton_amount(requirements.extra) + if _effective_forward_ton_amount(payload.accepted.extra) != expected_forward_ton_amount: + return invalid_response(ERR_EXACT_TVM_INVALID_JETTON_TRANSFER) + + expected_forward_payload = _effective_forward_payload(requirements.extra) + if _effective_forward_payload(payload.accepted.extra).hash != expected_forward_payload.hash: + return invalid_response(ERR_EXACT_TVM_INVALID_JETTON_TRANSFER) + + # Up to this point, we've checked all fields in PaymentRequirements and PaymentPayload except for settlementBoc + + if settlement.transfer.destination != normalize_address(requirements.pay_to): + return invalid_response(ERR_EXACT_TVM_INVALID_RECIPIENT) + + if settlement.transfer.jetton_amount != int(requirements.amount): + return invalid_response(ERR_EXACT_TVM_INVALID_AMOUNT) + + if settlement.transfer.forward_ton_amount != expected_forward_ton_amount: + return invalid_response(ERR_EXACT_TVM_INVALID_JETTON_TRANSFER) + if settlement.transfer.response_destination != expected_response_destination: + return invalid_response(ERR_EXACT_TVM_INVALID_JETTON_TRANSFER) + if settlement.transfer.forward_payload.hash != expected_forward_payload.hash: + return invalid_response(ERR_EXACT_TVM_INVALID_JETTON_TRANSFER) + max_attached_ton_amount = ( + settlement.transfer.forward_ton_amount + DEFAULT_JETTON_WALLET_MESSAGE_AMOUNT + ) + if settlement.transfer.attached_ton_amount > max_attached_ton_amount: + return invalid_response(ERR_EXACT_TVM_TON_AMOUNT_TOO_HIGH) + + now = int(time.time()) + if settlement.valid_until <= now: + return invalid_response(ERR_EXACT_TVM_INVALID_UNTIL_EXPIRED) + if settlement.valid_until > now + requirements.max_timeout_seconds: + return invalid_response(ERR_EXACT_TVM_VALID_UNTIL_TOO_FAR) + + account = self._signer.get_account_state(payer, str(requirements.network)) + init_data_parsed: W5InitData + + if account.is_frozen: + return invalid_response(ERR_EXACT_TVM_ACCOUNT_FROZEN) + + if settlement.state_init is not None and account.is_uninitialized: + if ( + settlement.state_init.code is None + or settlement.state_init.code.hash.hex() not in ALLOWED_CLIENT_CODES + ): + return invalid_response(ERR_EXACT_TVM_INVALID_CODE_HASH) + payer_workchain = int(payer.split(":", 1)[0]) + if address_from_state_init(settlement.state_init, payer_workchain) != payer: + return invalid_response(ERR_EXACT_TVM_INVALID_W5_MESSAGE) + init_data_parsed = parse_w5_init_data(settlement.state_init) + if init_data_parsed.seqno != 0: + return invalid_response(ERR_EXACT_TVM_INVALID_SEQNO) + if init_data_parsed.extensions_dict: + return invalid_response(ERR_EXACT_TVM_INVALID_EXTENSIONS_DICT) + else: + try: + init_data_parsed = parse_active_w5_account_state(account) + except RuntimeError: + return invalid_response(ERR_EXACT_TVM_INVALID_CODE_HASH) + + if not init_data_parsed.signature_allowed: + return invalid_response(ERR_EXACT_TVM_INVALID_SIGNATURE_MODE) + if init_data_parsed.seqno != settlement.seqno: + return invalid_response(ERR_EXACT_TVM_INVALID_SEQNO) + if init_data_parsed.wallet_id != settlement.wallet_id: + return invalid_response(ERR_EXACT_TVM_INVALID_WALLET_ID) + + if not verify_w5_signature( + init_data_parsed.public_key, + settlement.signed_slice_hash, + settlement.signature, + ): + return invalid_response(ERR_EXACT_TVM_INVALID_SIGNATURE) + + canonical_source_wallet = normalize_address( + self._signer.get_jetton_wallet( + requirements.asset, + payer, + str(requirements.network), + ) + ) + if normalize_address(settlement.transfer.source_wallet) != canonical_source_wallet: + return invalid_response(ERR_EXACT_TVM_INVALID_JETTON_TRANSFER) + + jetton_wallet_data = self._signer.get_jetton_wallet_data( + settlement.transfer.source_wallet, + str(requirements.network), + ) + if normalize_address(jetton_wallet_data.owner) != payer: + return invalid_response(ERR_EXACT_TVM_INVALID_RECIPIENT) + if normalize_address(jetton_wallet_data.jetton_minter) != normalize_address( + requirements.asset + ): + return invalid_response(ERR_EXACT_TVM_INVALID_ASSET) + if jetton_wallet_data.balance < settlement.transfer.jetton_amount: + return invalid_response(ERR_EXACT_TVM_INSUFFICIENT_BALANCE) + + try: + provisional_relay_request = TvmRelayRequest( + destination=settlement.payer, + body=settlement.body, + state_init=settlement.state_init, + forward_ton_amount=settlement.transfer.forward_ton_amount, + ) + external_boc = self._signer.build_relay_external_boc( + requirements.network, + provisional_relay_request, + for_emulation=True, + ) + emulation = self._signer.emulate_external_message(requirements.network, external_boc) + payer_transaction = self._verify_finalized_trace_settlement( + emulation, + settlement=settlement, + return_transaction=True, + ) + actual_inner = settlement.transfer.attached_ton_amount + required_outer = ( + actual_inner + + trace_transaction_storage_fees(payer_transaction) + + trace_transaction_compute_fees(payer_transaction) + + trace_transaction_fwd_fees(payer_transaction) + + DEFAULT_TVM_OUTER_GAS_BUFFER + ) + relay_request = TvmRelayRequest( + destination=settlement.payer, + body=settlement.body, + state_init=settlement.state_init, + forward_ton_amount=settlement.transfer.forward_ton_amount, + relay_amount=required_outer, + ) + except Exception as e: + return ( + VerifyResponse( + is_valid=False, + invalid_reason=ERR_EXACT_TVM_SIMULATION_FAILED, + invalid_message=str(e), + payer=payer, + ), + None, + ) + + return (VerifyResponse(is_valid=True, payer=payer), relay_request) + + @staticmethod + def _verify_finalized_trace_settlement( + trace_data: dict[str, object], + *, + settlement: ParsedTvmSettlement, + return_transaction: bool = False, + ) -> str | dict[str, object]: + transactions = parse_trace_transactions(trace_data) + expected_source_wallet = normalize_address(settlement.transfer.source_wallet) + + payer_transaction = None + for transaction in transactions: + if normalize_address(transaction["account"]) != settlement.payer: + continue + if not transaction_succeeded(transaction): + continue + in_msg: dict = transaction.get("in_msg") + if not message_body_hash_matches(in_msg, settlement.body.hash): + continue + payer_transaction = transaction + break + if payer_transaction is None: + raise ValueError("Trace does not contain the expected payer wallet transaction") + + out_msgs: list[dict] = payer_transaction.get("out_msgs") + payer_out_hash = None + for out_msg in out_msgs: + if normalize_address(out_msg["destination"]) != expected_source_wallet: + continue + if not message_body_hash_matches(out_msg, settlement.transfer.body_hash): + continue + payer_out_hash = out_msg["hash"] + break + if payer_out_hash is None: + raise ValueError("Trace payer wallet transaction is missing out message hash") + + # According to TEP-74, it is sufficient to check the success of the transaction on the payer's jetton wallet + source_wallet_transaction = None + for transaction in transactions: + if normalize_address(transaction["account"]) != expected_source_wallet: + continue + if not transaction_succeeded(transaction): + continue + in_msg: dict = transaction.get("in_msg") + if not in_msg: + continue + if in_msg.get("hash") == payer_out_hash: + source_wallet_transaction = transaction + break + if source_wallet_transaction is None: + raise ValueError("Trace does not contain the expected source jetton wallet transaction") + + transaction_hash = payer_transaction.get("hash_norm") or payer_transaction.get("hash") + if not transaction_hash: + raise ValueError("Trace payer wallet transaction is missing transaction hash") + return ( + payer_transaction + if return_transaction + else trace_transaction_hash_to_hex(transaction_hash) + ) diff --git a/python/x402/mechanisms/tvm/exact/server.py b/python/x402/mechanisms/tvm/exact/server.py new file mode 100644 index 0000000000..df30d7552c --- /dev/null +++ b/python/x402/mechanisms/tvm/exact/server.py @@ -0,0 +1,148 @@ +"""TVM server implementation for the Exact payment scheme (V2).""" + +from __future__ import annotations + +import re +from collections.abc import Callable +from decimal import Decimal + +from ....schemas import AssetAmount, Network, PaymentRequirements, Price, SupportedKind +from ..codecs.common import ( + encode_base64_boc, + make_zero_bit_cell, + normalize_address, + parse_amount, + parse_money_to_decimal, +) +from ..constants import ( + DEFAULT_DECIMALS, + SCHEME_EXACT, + TVM_MAINNET, + TVM_TESTNET, + USDT_MAINNET_MINTER, + USDT_TESTNET_MINTER, +) + +MoneyParser = Callable[[float, str], AssetAmount | None] + + +class ExactTvmScheme: + """TVM server implementation for the Exact payment scheme (V2).""" + + scheme = SCHEME_EXACT + + def __init__(self) -> None: + self._money_parsers: list[MoneyParser] = [] + + def register_money_parser(self, parser: MoneyParser) -> ExactTvmScheme: + """Register a custom money parser.""" + self._money_parsers.append(parser) + return self + + def parse_price(self, price: Price, network: Network) -> AssetAmount: + """Parse price into a normalized AssetAmount.""" + if isinstance(price, dict) and "amount" in price: + if not price.get("asset"): + raise ValueError(f"Asset address required for AssetAmount on {network}") + return AssetAmount( + amount=price["amount"], + asset=normalize_address(price["asset"]), + extra=price.get("extra", {}), + ) + + if isinstance(price, AssetAmount): + if not price.asset: + raise ValueError(f"Asset address required for AssetAmount on {network}") + return AssetAmount( + amount=price.amount, + asset=normalize_address(price.asset), + extra=price.extra, + ) + + if isinstance(price, int): + exact_decimal_amount = Decimal(price) + elif isinstance(price, float): + exact_decimal_amount = Decimal(str(price)) + else: + clean = price.strip() + clean = clean.lstrip("$") + clean = re.sub(r"\s*(USD|USDT|usd|usdt)\s*$", "", clean) + exact_decimal_amount = Decimal(clean.strip()) + + decimal_amount = parse_money_to_decimal(price) + for parser in self._money_parsers: + result = parser(decimal_amount, str(network)) + if result is not None: + return result + + return self._default_money_conversion(exact_decimal_amount, str(network)) + + def enhance_payment_requirements( + self, + requirements: PaymentRequirements, + supported_kind: SupportedKind, + extension_keys: list[str], + ) -> PaymentRequirements: + """Add TVM-specific fields to payment requirements.""" + _ = extension_keys + + if not requirements.asset: + requirements.asset = self._get_default_asset(str(requirements.network)) + requirements.asset = normalize_address(requirements.asset) + requirements.pay_to = normalize_address(requirements.pay_to) + + if "." in requirements.amount: + requirements.amount = str( + parse_amount(requirements.amount, self._get_asset_decimals(requirements)) + ) + + if requirements.extra is None: + requirements.extra = {} + if ( + "responseDestination" in requirements.extra + and requirements.extra["responseDestination"] is not None + ): + requirements.extra["responseDestination"] = normalize_address( + requirements.extra["responseDestination"] + ) + if "areFeesSponsored" not in requirements.extra: + requirements.extra["areFeesSponsored"] = (supported_kind.extra or {}).get( + "areFeesSponsored", + True, + ) + + return requirements + + def _default_money_conversion(self, amount: Decimal, network: str) -> AssetAmount: + return AssetAmount( + amount=str(parse_amount(format(amount, "f"), DEFAULT_DECIMALS)), + asset=self._get_default_asset(network), + extra={ + "areFeesSponsored": True, + "forwardPayload": encode_base64_boc(make_zero_bit_cell()), + "forwardTonAmount": "0", + }, + ) + + def _get_default_asset(self, network: str) -> str: + if network == TVM_MAINNET: + return USDT_MAINNET_MINTER + if network == TVM_TESTNET: + return USDT_TESTNET_MINTER + raise ValueError( + f"No default stablecoin configured for network {network}; specify an explicit asset" + ) + + def _get_asset_decimals(self, requirements: PaymentRequirements) -> int: + extra = requirements.extra or {} + if "decimals" in extra: + return int(extra["decimals"]) + if normalize_address(requirements.asset) in { + USDT_MAINNET_MINTER, + USDT_TESTNET_MINTER, + }: + return DEFAULT_DECIMALS + raise ValueError( + f"Token {requirements.asset} is not a registered asset for network " + f"{requirements.network}; provide amount in atomic units or extra.decimals" + ) diff --git a/python/x402/mechanisms/tvm/exact/settlement_batcher.py b/python/x402/mechanisms/tvm/exact/settlement_batcher.py new file mode 100644 index 0000000000..ab00f4f2c8 --- /dev/null +++ b/python/x402/mechanisms/tvm/exact/settlement_batcher.py @@ -0,0 +1,222 @@ +"""Internal batching helpers for TVM exact settlement relay.""" + +from __future__ import annotations + +import queue +import threading +import time +from collections.abc import Callable +from dataclasses import dataclass, field + +from ..constants import ( + DEFAULT_SETTLEMENT_BATCH_MAX_SIZE, + DEFAULT_SETTLEMENT_CONFIRMATION_WORKERS, + ERR_EXACT_TVM_SIMULATION_FAILED, + ERR_EXACT_TVM_TRANSACTION_FAILED, +) +from ..settlement_cache import SettlementCache +from ..signer import FacilitatorTvmSigner +from ..types import ParsedTvmSettlement, TvmRelayRequest + + +@dataclass +class _BatchResult: + success: bool + transaction: str = "" + error_reason: str | None = None + error_message: str | None = None + + +@dataclass +class _QueuedSettlement: + network: str + settlement_hash: str + settlement: ParsedTvmSettlement + relay_request: TvmRelayRequest + completed: threading.Event = field(default_factory=threading.Event) + result: _BatchResult | None = None + + +@dataclass +class _PendingConfirmation: + network: str + batch: list[_QueuedSettlement] + trace_external_hash_norm: str + + +class _SettlementBatcher: + def __init__( + self, + signer: FacilitatorTvmSigner, + settlement_cache: SettlementCache, + *, + flush_interval_seconds: float, + batch_flush_size: int, + confirmation_workers: int = DEFAULT_SETTLEMENT_CONFIRMATION_WORKERS, + confirmation_timeout_seconds: float, + settlement_verifier: Callable[[dict[str, object], ParsedTvmSettlement], str], + ) -> None: + self._signer = signer + self._settlement_cache = settlement_cache + self._flush_interval_seconds = flush_interval_seconds + self._batch_flush_size = batch_flush_size + self._max_batch_size = DEFAULT_SETTLEMENT_BATCH_MAX_SIZE + self._confirmation_timeout_seconds = confirmation_timeout_seconds + self._settlement_verifier = settlement_verifier + if confirmation_workers < 1: + raise ValueError("confirmation_workers must be at least 1") + self._lock = threading.Lock() + self._condition = threading.Condition(self._lock) + self._confirmation_queue: queue.SimpleQueue[_PendingConfirmation] = queue.SimpleQueue() + self._queues: dict[str, list[_QueuedSettlement]] = {} + self._deadlines: dict[str, float] = {} + self._worker = threading.Thread( + target=self._run, name="tvm-settlement-batcher", daemon=True + ) + self._worker.start() + self._confirmation_workers = [ + threading.Thread( + target=self._run_confirmation_worker, + name=f"tvm-settlement-confirmation-{idx}", + daemon=True, + ) + for idx in range(confirmation_workers) + ] + for worker in self._confirmation_workers: + worker.start() + + def enqueue(self, queued_settlement: _QueuedSettlement) -> _BatchResult: + with self._condition: + queue = self._queues.setdefault(queued_settlement.network, []) + queue.append(queued_settlement) + if len(queue) == 1: + self._deadlines[queued_settlement.network] = ( + time.monotonic() + self._flush_interval_seconds + ) + elif len(queue) >= self._batch_flush_size: + self._deadlines[queued_settlement.network] = time.monotonic() + self._condition.notify_all() + + queued_settlement.completed.wait() + assert queued_settlement.result is not None + return queued_settlement.result + + def _run(self) -> None: + while True: + with self._condition: + network, batch = self._wait_for_ready_batch_locked() + self._flush_batch(network, batch) + + def _wait_for_ready_batch_locked(self) -> tuple[str, list[_QueuedSettlement]]: + while True: + now = time.monotonic() + for network, deadline in list(self._deadlines.items()): + queue = self._queues.get(network) + if queue and deadline <= now: + batch_size = min(len(queue), self._max_batch_size) + batch = queue[:batch_size] + del queue[:batch_size] + if queue: + self._deadlines[network] = ( + now + if len(queue) >= self._batch_flush_size + else now + self._flush_interval_seconds + ) + self._condition.notify_all() + else: + self._queues.pop(network, None) + self._deadlines.pop(network, None) + return network, batch + self._condition.wait(timeout=self._next_wait_timeout_locked()) + + def _next_wait_timeout_locked(self) -> float | None: + if not self._deadlines: + return None + return max(0.0, min(self._deadlines.values()) - time.monotonic()) + + def _flush_batch(self, network: str, batch: list[_QueuedSettlement]) -> None: + try: + external_boc = self._signer.build_relay_external_boc_batch( + network, + [queued.relay_request for queued in batch], + ) + trace_external_hash_norm = self._signer.send_external_message(network, external_boc) + except Exception as exc: + for queued in batch: + self._fail_queued_settlement( + queued, + error_reason=( + ERR_EXACT_TVM_SIMULATION_FAILED + if isinstance(exc, ValueError) + else ERR_EXACT_TVM_TRANSACTION_FAILED + ), + error_message=str(exc), + ) + return + + self._confirmation_queue.put( + _PendingConfirmation( + network=network, + batch=batch, + trace_external_hash_norm=trace_external_hash_norm, + ) + ) + + def _run_confirmation_worker(self) -> None: + while True: + pending = self._confirmation_queue.get() + try: + finalized_trace = self._signer.wait_for_trace_confirmation( + pending.network, + pending.trace_external_hash_norm, + timeout_seconds=self._confirmation_timeout_seconds, + ) + except Exception as exc: + for queued in pending.batch: + self._fail_queued_settlement( + queued, + error_reason=( + ERR_EXACT_TVM_SIMULATION_FAILED + if isinstance(exc, ValueError) + else ERR_EXACT_TVM_TRANSACTION_FAILED + ), + error_message=str(exc), + ) + continue + + for queued in pending.batch: + try: + transaction_hash = self._settlement_verifier( + finalized_trace, + queued.settlement, + ) + queued.result = _BatchResult( + success=True, + transaction=transaction_hash, + ) + except Exception as exc: + self._fail_queued_settlement( + queued, + error_reason=ERR_EXACT_TVM_TRANSACTION_FAILED, + error_message=str(exc), + ) + continue + queued.completed.set() + # On-chain seqno already advanced; further retries fail at verify + self._settlement_cache.release(queued.settlement_hash) + + def _fail_queued_settlement( + self, + queued: _QueuedSettlement, + *, + error_reason: str, + error_message: str, + ) -> None: + queued.result = _BatchResult( + success=False, + transaction="", + error_reason=error_reason, + error_message=error_message, + ) + queued.completed.set() + self._settlement_cache.release(queued.settlement_hash) diff --git a/python/x402/mechanisms/tvm/provider.py b/python/x402/mechanisms/tvm/provider.py new file mode 100644 index 0000000000..eafd54fcc7 --- /dev/null +++ b/python/x402/mechanisms/tvm/provider.py @@ -0,0 +1,813 @@ +"""TVM RPC provider clients.""" + +from __future__ import annotations + +import base64 +import binascii +import logging +import re +import time +from typing import Any, Protocol, cast +from urllib.parse import quote + +from .codecs.common import address_to_stack_item, normalize_address +from .constants import ( + DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + DEFAULT_TONCENTER_TIMEOUT_SECONDS, + JETTON_TRANSFER_OPCODE, + SUPPORTED_TVM_PROVIDERS, + TONAPI_MAINNET_BASE_URL, + TONAPI_TESTNET_BASE_URL, + TONCENTER_MAINNET_BASE_URL, + TONCENTER_TESTNET_BASE_URL, + TVM_MAINNET, + TVM_PROVIDER_TONAPI, + TVM_PROVIDER_TONCENTER, + TVM_TESTNET, + W5_EXTERNAL_SIGNED_OPCODE, + W5_INTERNAL_SIGNED_OPCODE, +) +from .types import TvmAccountState, TvmJettonWalletData + +try: + import httpx + from pytoniq_core import Address, Builder, Cell + from pytoniq_core.tlb.account import StateInit + from pytoniq_core.tlb.transaction import MessageAny +except ImportError as e: + raise ImportError( + "TVM mechanism requires pytoniq packages and httpx. Install with: pip install x402[tvm,httpx]" + ) from e + +logger = logging.getLogger(__name__) + +_MAX_LOGGED_RESPONSE_BODY_LENGTH = 512 +_JETTON_INTERNAL_TRANSFER_OPCODE = 0x178D4519 +_OPCODE_NAMES = { + JETTON_TRANSFER_OPCODE: "jetton_transfer", + _JETTON_INTERNAL_TRANSFER_OPCODE: "jetton_internal_transfer", + W5_INTERNAL_SIGNED_OPCODE: "w5_internal_signed_request", + W5_EXTERNAL_SIGNED_OPCODE: "w5_external_signed_request", +} + + +class TvmProviderClient(Protocol): + """Provider operations used by the TVM mechanism.""" + + def get_account_state(self, address: str) -> TvmAccountState: + """Get account state for a raw or user-friendly address.""" + ... + + def close(self) -> None: + """Close provider-owned resources.""" + ... + + def get_jetton_wallet(self, asset: str, owner: str) -> str: + """Resolve an owner's canonical jetton wallet.""" + ... + + def get_jetton_wallet_data(self, address: str) -> TvmJettonWalletData: + """Read TEP-74 get_wallet_data.""" + ... + + def send_message(self, boc: bytes) -> str: + """Broadcast a BOC and return the normalized external message hash.""" + ... + + def emulate_trace( + self, + boc: bytes, + *, + ignore_chksig: bool = False, + timeout: float = DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + ) -> dict[str, Any]: + """Emulate a BOC and return a Toncenter-shaped trace.""" + ... + + def get_trace_by_message_hash(self, message_hash: str) -> dict[str, Any]: + """Fetch a complete trace by normalized external message hash.""" + ... + + def run_get_method( + self, + address: str, + method: str, + stack: list[dict[str, object]], + ) -> list[dict[str, object]]: + """Run a get-method and return a Toncenter-shaped stack.""" + ... + + +def create_tvm_provider_client( + network: str, + *, + provider: str = TVM_PROVIDER_TONCENTER, + api_key: str | None = None, + base_url: str | None = None, + timeout: float = DEFAULT_TONCENTER_TIMEOUT_SECONDS, +) -> TvmProviderClient: + """Create the configured TVM provider client.""" + normalized_provider = provider.strip().lower() + if normalized_provider not in SUPPORTED_TVM_PROVIDERS: + raise ValueError(f"Unsupported TVM provider: {normalized_provider}") + if normalized_provider == TVM_PROVIDER_TONAPI: + return TonapiRestClient( + network, + api_key=api_key, + base_url=base_url, + timeout=timeout, + ) + return ToncenterRestClient( + network, + api_key=api_key, + base_url=base_url, + timeout=timeout, + ) + + +class ToncenterRestClient: + """Minimal Toncenter v3 client used by the TVM mechanism.""" + + def __init__( + self, + network: str, + *, + api_key: str | None = None, + base_url: str | None = None, + timeout: float = DEFAULT_TONCENTER_TIMEOUT_SECONDS, + ) -> None: + root_url = (base_url or _default_base_url(network)).rstrip("/") + headers = {"Accept": "application/json"} + if api_key: + headers["X-Api-Key"] = api_key + + self._client = httpx.Client(base_url=root_url, headers=headers, timeout=timeout) + + def get_account_state(self, address: str) -> TvmAccountState: + address = normalize_address(address) + response = self._request( + "GET", + "/api/v3/accountStates", + params={"address": [address], "include_boc": "true"}, + ) + accounts = response.get("accounts") or [] + if not accounts: + return _synthetic_uninitialized_account(address) + + return _account_state_from_payload( + address, accounts[0], code_key="code_boc", data_key="data_boc" + ) + + def close(self) -> None: + """Close the underlying HTTP client.""" + self._client.close() + + def get_jetton_wallet(self, asset: str, owner: str) -> str: + result = self.run_get_method( + asset, + "get_wallet_address", + [cast(dict[str, object], address_to_stack_item(owner))], + ) + return _parse_stack_address(result[0]) + + def get_jetton_wallet_data(self, address: str) -> TvmJettonWalletData: + result = self.run_get_method(address, "get_wallet_data", []) + if len(result) < 3: + raise RuntimeError("Toncenter get_wallet_data returned an incomplete stack") + + return TvmJettonWalletData( + address=normalize_address(address), + balance=_parse_stack_num(result[0]), + owner=_parse_stack_address(result[1]), + jetton_minter=_parse_stack_address(result[2]), + ) + + def send_message(self, boc: bytes) -> str: + response = self._request( + "POST", + "/api/v3/message", + json={"boc": base64.b64encode(boc).decode("utf-8")}, + ) + return str(response.get("message_hash_norm") or response["message_hash"]) + + def emulate_trace( + self, + boc: bytes, + *, + ignore_chksig: bool = False, + timeout: float = DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + ) -> dict[str, Any]: + response = self._request( + "POST", + "/api/emulate/v1/emulateTrace", + json={ + "boc": base64.b64encode(boc).decode("utf-8"), + "ignore_chksig": ignore_chksig, + "with_actions": True, + }, + timeout=timeout, + ) + if not isinstance(response, dict): + raise RuntimeError("Toncenter returned an invalid emulateTrace response") + return response + + def get_trace_by_message_hash(self, message_hash: str) -> dict[str, Any]: + response = self._request( + "GET", + "/api/v3/traces", + params={ + "msg_hash": [message_hash], + "limit": 1, + "sort": "desc", + }, + ) + traces = response.get("traces") + if not isinstance(traces, list): + raise RuntimeError("Toncenter returned an invalid traces response") + for trace in traces: + if isinstance(trace, dict): + return trace + raise RuntimeError(f"Toncenter returned no trace for message hash {message_hash}") + + def run_get_method( + self, + address: str, + method: str, + stack: list[dict[str, object]], + ) -> list[dict[str, object]]: + response = self._request( + "POST", + "/api/v3/runGetMethod", + json={ + "address": normalize_address(address), + "method": method, + "stack": stack, + }, + ) + if int(response.get("exit_code", 0)) != 0: + raise RuntimeError( + f"Toncenter get-method {method} failed with exit code {response['exit_code']}" + ) + + result = response.get("stack") + if not isinstance(result, list): + raise RuntimeError(f"Toncenter returned an invalid stack for get-method {method}") + return [item for item in result if isinstance(item, dict)] + + def _request(self, method: str, path: str, **kwargs: Any) -> dict[str, Any]: + return _request_json(self._client, "Toncenter", method, path, **kwargs) + + +class TonapiRestClient: + """Minimal TonAPI v2 client adapted to the TVM mechanism's provider contract.""" + + def __init__( + self, + network: str, + *, + api_key: str | None = None, + base_url: str | None = None, + timeout: float = DEFAULT_TONCENTER_TIMEOUT_SECONDS, + ) -> None: + root_url = (base_url or _default_base_url(network, TVM_PROVIDER_TONAPI)).rstrip("/") + headers = {"Accept": "application/json"} + if api_key: + headers["Authorization"] = f"Bearer {api_key}" + + self._client = httpx.Client(base_url=root_url, headers=headers, timeout=timeout) + + def get_account_state(self, address: str) -> TvmAccountState: + address = normalize_address(address) + try: + account = self._request("GET", f"/v2/blockchain/accounts/{address}") + except httpx.HTTPStatusError as exc: + if exc.response.status_code != 404: + raise + return _synthetic_uninitialized_account(address) + + return _account_state_from_payload(address, account, code_key="code", data_key="data") + + def close(self) -> None: + """Close the underlying HTTP client.""" + self._client.close() + + def get_jetton_wallet(self, asset: str, owner: str) -> str: + result = self.run_get_method( + asset, + "get_wallet_address", + [cast(dict[str, object], address_to_stack_item(owner))], + ) + return _parse_stack_address(result[0]) + + def get_jetton_wallet_data(self, address: str) -> TvmJettonWalletData: + result = self.run_get_method(address, "get_wallet_data", []) + if len(result) < 3: + raise RuntimeError("TonAPI get_wallet_data returned an incomplete stack") + + return TvmJettonWalletData( + address=normalize_address(address), + balance=_parse_stack_num(result[0]), + owner=_parse_stack_address(result[1]), + jetton_minter=_parse_stack_address(result[2]), + ) + + def send_message(self, boc: bytes) -> str: + self._request( + "POST", + "/v2/blockchain/message", + json={"boc": base64.b64encode(boc).decode("utf-8")}, + ) + return _normalized_external_message_hash_hex(boc) + + def emulate_trace( + self, + boc: bytes, + *, + ignore_chksig: bool = False, + timeout: float = DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + ) -> dict[str, Any]: + response = self._request( + "POST", + "/v2/traces/emulate", + params={"ignore_signature_check": ignore_chksig}, + json={"boc": base64.b64encode(boc).decode("utf-8")}, + timeout=timeout, + ) + return _tonapi_trace_to_toncenter(response) + + def get_trace_by_message_hash(self, message_hash: str) -> dict[str, Any]: + trace_id = quote(message_hash, safe="") + return _tonapi_trace_to_toncenter(self._request("GET", f"/v2/traces/{trace_id}")) + + def run_get_method( + self, + address: str, + method: str, + stack: list[dict[str, object]], + ) -> list[dict[str, object]]: + response = self._request( + "POST", + f"/v2/blockchain/accounts/{normalize_address(address)}/methods/{quote(method, safe='')}", + json={"args": [_tonapi_get_method_arg(item) for item in stack]}, + ) + if response.get("success") is False or int(response.get("exit_code", 0)) != 0: + raise RuntimeError( + f"TonAPI get-method {method} failed with exit code {response['exit_code']}" + ) + + result = response.get("stack") + if not isinstance(result, list): + raise RuntimeError(f"TonAPI returned an invalid stack for get-method {method}") + return [ + _tonapi_stack_record_to_toncenter(item) for item in result if isinstance(item, dict) + ] + + def _request(self, method: str, path: str, **kwargs: Any) -> dict[str, Any]: + return _request_json( + self._client, + "TonAPI", + method, + path, + allow_empty_response=True, + **kwargs, + ) + + +def _default_base_url(network: str, provider: str = TVM_PROVIDER_TONCENTER) -> str: + normalized_provider = provider.strip().lower() + if normalized_provider == TVM_PROVIDER_TONCENTER: + if network == TVM_MAINNET: + return TONCENTER_MAINNET_BASE_URL + if network == TVM_TESTNET: + return TONCENTER_TESTNET_BASE_URL + raise ValueError(f"Unsupported TVM network: {network}") + if normalized_provider == TVM_PROVIDER_TONAPI: + if network == TVM_MAINNET: + return TONAPI_MAINNET_BASE_URL + if network == TVM_TESTNET: + return TONAPI_TESTNET_BASE_URL + raise ValueError(f"Unsupported TVM network: {network}") + raise ValueError(f"Unsupported TVM provider: {provider}") + + +def _account_state_from_payload( + address: str, + account: dict[str, Any], + *, + code_key: str, + data_key: str, +) -> TvmAccountState: + status = str(account.get("status") or "") + state_init = None + code_boc = account.get(code_key) + data_boc = account.get(data_key) + if status == "active" and isinstance(code_boc, str) and isinstance(data_boc, str): + state_init = StateInit( + code=Cell.one_from_boc(_decode_boc_text(code_boc)), + data=Cell.one_from_boc(_decode_boc_text(data_boc)), + ) + + return TvmAccountState( + address=address, + balance=int(account.get("balance") or 0), + is_active=status == "active", + is_uninitialized=status in {"uninit", "nonexist"}, + is_frozen=status == "frozen", + state_init=state_init, + ) + + +def _synthetic_uninitialized_account(address: str) -> TvmAccountState: + return TvmAccountState( + address=address, + balance=0, + is_active=False, + is_uninitialized=True, + is_frozen=False, + state_init=None, + ) + + +def _parse_stack_address(item: dict[str, object]) -> str: + cell = _parse_stack_cell(item) + address = cell.begin_parse().load_address() + return normalize_address(address) + + +def _parse_stack_cell(item: dict[str, object]) -> Cell: + value = item.get("value") + if not value: + raise RuntimeError("Can't parse cell stack value") + return Cell.one_from_boc(base64.b64decode(str(value))) + + +def _parse_stack_num(item: dict[str, object]) -> int: + return int(str(item.get("value")), 0) + + +def _request_json( + client: httpx.Client, + provider_label: str, + method: str, + path: str, + *, + allow_empty_response: bool = False, + **kwargs: Any, +) -> dict[str, Any]: + attempts = 5 + backoff_seconds = 0.25 + last_error: Exception | None = None + for attempt in range(attempts): + try: + response = client.request(method, path, **kwargs) + _log_provider_response( + provider_label, + method, + path, + response, + attempt=attempt + 1, + attempts=attempts, + ) + response.raise_for_status() + if allow_empty_response and not response.content: + return {} + data = response.json() + if not isinstance(data, dict): + raise RuntimeError(f"{provider_label} returned a non-object response for {path}") + return data + except httpx.HTTPStatusError as exc: + last_error = exc + retryable = exc.response.status_code in {429, 500, 502, 503, 504} + logger.warning( + "%s request failed: method=%s path=%s url=%s status=%s " + "attempt=%s/%s retryable=%s body=%r", + provider_label, + method, + path, + str(exc.request.url), + exc.response.status_code, + attempt + 1, + attempts, + retryable, + _truncate_response_body(exc.response.text), + ) + if not retryable or attempt == attempts - 1: + raise + retry_after = exc.response.headers.get("Retry-After") + if retry_after: + logger.info( + "%s request backing off per Retry-After: method=%s path=%s " + "retry_after=%s attempt=%s/%s", + provider_label, + method, + path, + retry_after, + attempt + 1, + attempts, + ) + try: + time.sleep(float(retry_after)) + continue + except ValueError: + pass + except httpx.RequestError as exc: + last_error = exc + logger.warning( + "%s request transport error: method=%s path=%s attempt=%s/%s error=%r", + provider_label, + method, + path, + attempt + 1, + attempts, + exc, + ) + if attempt == attempts - 1: + raise + time.sleep(backoff_seconds * (attempt + 1)) + + if last_error is not None: + raise last_error + raise RuntimeError(f"{provider_label} request for {path} failed without an exception") + + +def _tonapi_get_method_arg(item: dict[str, object]) -> dict[str, str]: + item_type = str(item.get("type") or "") + value = item.get("value") + if value is None: + raise RuntimeError(f"TonAPI get-method stack item is missing value: {item!r}") + + if item_type == "slice": + if isinstance(value, str): + try: + cell = Cell.one_from_boc(base64.b64decode(value, validate=True)) + address = cell.begin_parse().load_address() + if address is not None: + return {"type": "slice", "value": normalize_address(address)} + except Exception: + pass + return {"type": "slice_boc_hex", "value": _decode_boc_text(value).hex()} + if item_type == "cell": + return {"type": "cell_boc_base64", "value": str(value)} + if item_type in {"num", "int"}: + return {"type": "int257", "value": str(value)} + if item_type in {"nan", "null", "tinyint", "int257", "cell_boc_base64", "slice_boc_hex"}: + return {"type": item_type, "value": str(value)} + raise RuntimeError(f"Unsupported TonAPI get-method stack item type: {item_type}") + + +def _tonapi_stack_record_to_toncenter(record: dict[str, object]) -> dict[str, object]: + record_type = str(record.get("type") or "") + tuple_value = record.get("tuple") + if record_type == "num": + return {"type": "num", "value": str(record.get("num") or "0")} + if record_type == "cell" and record.get("cell") is not None: + return {"type": "cell", "value": _cell_boc_to_base64(record["cell"])} + if record_type == "tuple" and isinstance(tuple_value, list): + return { + "type": "tuple", + "value": [ + _tonapi_stack_record_to_toncenter(item) + for item in tuple_value + if isinstance(item, dict) + ], + } + if record_type == "null": + return {"type": "null", "value": None} + if record_type == "nan": + return {"type": "nan", "value": "NaN"} + if record_type == "slice" and record.get("slice") is not None: + value = record["slice"] + if isinstance(value, str): + try: + normalized_address = normalize_address(value) + cell = Builder().store_address(Address(normalized_address)).end_cell() + return { + "type": "slice", + "value": base64.b64encode(cell.to_boc()).decode("utf-8"), + } + except Exception: + pass + return {"type": "slice", "value": _cell_boc_to_base64(value)} + raise RuntimeError(f"TonAPI returned an unsupported stack record: {record!r}") + + +def _tonapi_trace_to_toncenter(trace: dict[str, Any]) -> dict[str, Any]: + transactions: dict[str, dict[str, object]] = {} + + def walk(node: dict[str, Any]) -> dict[str, object] | None: + transaction = node.get("transaction") + converted: dict[str, object] | None = None + if isinstance(transaction, dict): + converted = _tonapi_transaction_to_toncenter(transaction) + transaction_hash = str(converted.get("hash") or len(transactions)) + transactions[transaction_hash] = converted + children = node.get("children") or [] + if isinstance(children, list): + for child in children: + if isinstance(child, dict): + child_transaction = walk(child) + if converted is not None and child_transaction is not None: + _append_child_in_msg_as_parent_out_msg(converted, child_transaction) + return converted + + walk(trace) + return { + "transactions": transactions, + "is_incomplete": False, + } + + +def _append_child_in_msg_as_parent_out_msg( + parent_transaction: dict[str, object], + child_transaction: dict[str, object], +) -> None: + """TonAPI trace trees may omit parent out_msgs; recover them from child in_msg.""" + child_in_msg = child_transaction.get("in_msg") + if not isinstance(child_in_msg, dict) or not child_in_msg: + return + + out_msgs = parent_transaction.get("out_msgs") + if not isinstance(out_msgs, list): + out_msgs = [] + parent_transaction["out_msgs"] = out_msgs + + child_hash = child_in_msg.get("hash") + if child_hash and any( + isinstance(message, dict) and message.get("hash") == child_hash for message in out_msgs + ): + return + + out_msgs.append(dict(child_in_msg)) + + +def _tonapi_transaction_to_toncenter(transaction: dict[str, Any]) -> dict[str, object]: + converted: dict[str, object] = { + "account": _tonapi_account_address(transaction.get("account")), + "hash": str(transaction.get("hash") or ""), + "hash_norm": str(transaction.get("hash") or ""), + "description": { + "aborted": transaction.get("aborted"), + "compute_ph": _tonapi_compute_phase(transaction.get("compute_phase")), + "action": _tonapi_action_phase(transaction.get("action_phase")), + "storage_ph": _tonapi_storage_phase(transaction.get("storage_phase")), + }, + "in_msg": _tonapi_message_to_toncenter(transaction.get("in_msg")), + "out_msgs": [ + _tonapi_message_to_toncenter(message) + for message in transaction.get("out_msgs") or [] + if isinstance(message, dict) + ], + } + return converted + + +def _tonapi_compute_phase(phase: object) -> dict[str, object]: + if not isinstance(phase, dict): + return {"skipped": True, "success": False} + return { + "skipped": phase.get("skipped"), + "success": phase.get("success"), + "gas_fees": phase.get("gas_fees"), + } + + +def _tonapi_action_phase(phase: object) -> dict[str, object] | None: + if not isinstance(phase, dict): + return None + return { + "success": phase.get("success"), + "total_fwd_fees": phase.get("fwd_fees"), + "fwd_fee": phase.get("fwd_fees"), + "total_fees": phase.get("total_fees"), + } + + +def _tonapi_storage_phase(phase: object) -> dict[str, object]: + if not isinstance(phase, dict): + return {} + return { + "storage_fees_collected": phase.get("fees_collected"), + "storage_fees_due": phase.get("fees_due"), + } + + +def _tonapi_message_to_toncenter(message: object) -> dict[str, object]: + if not isinstance(message, dict): + return {} + converted: dict[str, object] = { + "hash": str(message.get("hash") or ""), + "hash_norm": str(message.get("hash") or ""), + "source": _tonapi_account_address(message.get("source")), + "destination": _tonapi_account_address(message.get("destination")), + "decoded_opcode": _normalize_decoded_opcode(message), + "fwd_fee": message.get("fwd_fee"), + "value": message.get("value"), + } + message_content: dict[str, object] = {} + raw_body = message.get("raw_body") + if isinstance(raw_body, str) and raw_body: + try: + message_content["hash"] = base64.b64encode( + Cell.one_from_boc(_decode_boc_text(raw_body)).hash + ).decode("ascii") + except Exception: + pass + decoded_body = message.get("decoded_body") + if decoded_body is not None: + message_content["decoded"] = decoded_body + if message_content: + converted["message_content"] = message_content + return converted + + +def _tonapi_account_address(value: object) -> str: + if isinstance(value, dict): + address = value.get("address") + return normalize_address(address) if isinstance(address, str) and address else "" + if isinstance(value, str) and value: + return normalize_address(value) + return "" + + +def _normalize_decoded_opcode(message: dict[str, object]) -> str: + opcode_name = message.get("decoded_op_name") + if isinstance(opcode_name, str) and opcode_name: + normalized = re.sub(r"(? str: + return base64.b64encode(_decode_boc_text(str(value))).decode("utf-8") + + +def _decode_boc_text(value: str) -> bytes: + normalized = value.strip() + if not normalized: + raise ValueError("BOC value is empty") + if len(normalized) % 2 == 0 and re.fullmatch(r"[0-9a-fA-F]+", normalized): + return bytes.fromhex(normalized) + try: + return base64.b64decode(normalized, validate=True) + except (ValueError, binascii.Error) as exc: + raise ValueError("BOC value must be hex or base64") from exc + + +def _normalized_external_message_hash_hex(boc: bytes) -> str: + message = MessageAny.deserialize(Cell.one_from_boc(boc).begin_parse()) + if not message.is_external: + return str(message.body.hash.hex()) + return str( + Builder() + .store_uint(2, 2) + .store_address(None) + .store_address(message.info.dest) + .store_coins(0) + .store_bit(False) + .store_bit(True) + .store_ref(message.body) + .end_cell() + .hash.hex() + ) + + +def _truncate_response_body(body: str) -> str: + if len(body) <= _MAX_LOGGED_RESPONSE_BODY_LENGTH: + return body + return body[:_MAX_LOGGED_RESPONSE_BODY_LENGTH] + "..." + + +def _log_provider_response( + provider_label: str, + method: str, + path: str, + response: httpx.Response, + *, + attempt: int, + attempts: int, +) -> None: + if not logger.isEnabledFor(logging.DEBUG): + return + logger.debug( + "%s response: method=%s path=%s url=%s status=%s attempt=%s/%s body=%r", + provider_label, + method, + path, + str(response.request.url), + response.status_code, + attempt, + attempts, + _truncate_response_body(response.text), + ) diff --git a/python/x402/mechanisms/tvm/settlement_cache.py b/python/x402/mechanisms/tvm/settlement_cache.py new file mode 100644 index 0000000000..26c1b25851 --- /dev/null +++ b/python/x402/mechanisms/tvm/settlement_cache.py @@ -0,0 +1,45 @@ +"""Thread-safe in-memory cache for deduplicating concurrent settlement requests.""" + +from __future__ import annotations + +import threading +import time + + +class SettlementCache: + """In-memory cache for deduplicating concurrent settlement requests. + + Each entry carries its own TTL because TVM settlement validity depends on the + request-specific timeout window. + """ + + def __init__(self) -> None: + self._entries: dict[str, float] = {} + self._lock = threading.Lock() + + def is_duplicate(self, key: str, ttl_seconds: float) -> bool: + """Return ``True`` if *key* is already pending settlement (duplicate). + + When ``False`` the key is recorded as newly pending. + Callers should reject the settlement when this returns ``True``. + """ + now = time.monotonic() + expires_at = now + max(0.0, ttl_seconds) + with self._lock: + self._prune(now) + if key in self._entries: + return True + self._entries[key] = expires_at + return False + + def release(self, key: str) -> None: + """Remove *key* from the pending settlement set.""" + now = time.monotonic() + with self._lock: + self._prune(now) + self._entries.pop(key, None) + + def _prune(self, now: float) -> None: + expired = [key for key, expires_at in self._entries.items() if expires_at <= now] + for key in expired: + del self._entries[key] diff --git a/python/x402/mechanisms/tvm/signer.py b/python/x402/mechanisms/tvm/signer.py new file mode 100644 index 0000000000..7101c541bd --- /dev/null +++ b/python/x402/mechanisms/tvm/signer.py @@ -0,0 +1,102 @@ +"""TVM signer protocol definitions.""" + +from __future__ import annotations + +from typing import Protocol + +from .types import TvmAccountState, TvmJettonWalletData, TvmRelayRequest + +try: + from pytoniq_core.tlb.account import StateInit +except ImportError as e: + raise ImportError( + "TVM mechanism requires pytoniq packages. Install with: pip install x402[tvm]" + ) from e + + +class FacilitatorTvmSigner(Protocol): + """Facilitator-side TVM signer for verification and settlement.""" + + def get_addresses(self) -> list[str]: + """Get all facilitator wallet addresses.""" + ... + + def get_addresses_for_network(self, network: str) -> list[str]: + """Get facilitator wallet addresses available for one TVM network.""" + ... + + def get_account_state(self, address: str, network: str) -> TvmAccountState: + """Get account state for a wallet or jetton wallet.""" + ... + + def get_jetton_wallet(self, asset: str, owner: str, network: str) -> str: + """Resolve the canonical TEP-74 jetton wallet for an owner.""" + ... + + def build_relay_external_boc( + self, + network: str, + relay_request: TvmRelayRequest, + *, + for_emulation: bool = False, + ) -> bytes: + """Build a Highload V3 external message for relaying the pre-signed W5 message.""" + ... + + def build_relay_external_boc_batch( + self, + network: str, + relay_requests: list[TvmRelayRequest], + ) -> bytes: + """Build one Highload V3 external message that relays multiple requests.""" + ... + + def emulate_external_message(self, network: str, external_boc: bytes) -> dict[str, object]: + """Emulate a prepared external message through the configured TVM provider.""" + ... + + def send_external_message(self, network: str, external_boc: bytes) -> str: + """Broadcast a prepared external message through the configured TVM provider.""" + ... + + def wait_for_trace_confirmation( + self, + network: str, + trace_external_hash_norm: str, + *, + timeout_seconds: float, + ) -> dict[str, object]: + """Wait until a submitted trace reaches finalized and return its payload.""" + ... + + def get_jetton_wallet_data(self, address: str, network: str) -> TvmJettonWalletData: + """Read TEP-74 jetton wallet data for a wallet address.""" + ... + + +class ClientTvmSigner(Protocol): + """Client-side TVM signer for W5 exact payments.""" + + @property + def address(self) -> str: + """The signer's W5 wallet address in raw format.""" + ... + + @property + def network(self) -> str: + """The CAIP-2 TVM network this signer is configured for.""" + ... + + @property + def wallet_id(self) -> int: + """The W5 wallet_id used in signed requests.""" + ... + + @property + def state_init(self) -> StateInit: + """The wallet StateInit used for first deployment.""" + ... + + def sign_message(self, message: bytes) -> bytes: + """Sign a W5 request body hash.""" + ... diff --git a/python/x402/mechanisms/tvm/signers.py b/python/x402/mechanisms/tvm/signers.py new file mode 100644 index 0000000000..c21edfdc6b --- /dev/null +++ b/python/x402/mechanisms/tvm/signers.py @@ -0,0 +1,629 @@ +"""Concrete TVM signer implementations.""" + +from __future__ import annotations + +import base64 +import binascii +import threading +import time +from dataclasses import dataclass +from secrets import randbelow + +from .codecs.common import normalize_address +from .codecs.highload_v3 import ( + MAX_USABLE_QUERY_SEQNO, + load_highload_query_state, + query_id_is_processed, + seqno_to_query_id, + serialize_internal_transfer, +) +from .codecs.w5 import ( + address_from_state_init, + build_w5r1_state_init, + make_w5r1_wallet_id, + serialize_out_list, + serialize_send_msg_action, +) +from .constants import ( + DEFAULT_HIGHLOAD_SUBWALLET_ID, + DEFAULT_HIGHLOAD_TIMEOUT, + DEFAULT_RELAY_AMOUNT, + DEFAULT_STREAMING_CONFIRMATION_GRACE_SECONDS, + DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + DEFAULT_TONCENTER_TIMEOUT_SECONDS, + DEFAULT_W5R1_SUBWALLET_NUMBER, + HIGHLOAD_V3_CODE_HASH, + HIGHLOAD_V3_CODE_HEX, + TVM_PROVIDER_TONCENTER, +) +from .provider import ( + TvmProviderClient, + _default_base_url, + create_tvm_provider_client, +) +from .streaming import TvmStreamingSseClient, TvmStreamingWatcher +from .types import TvmAccountState, TvmJettonWalletData, TvmRelayRequest + +try: + from nacl.signing import SigningKey + from pytoniq.contract.contract import Contract + from pytoniq_core import Address, Cell, begin_cell + from pytoniq_core.crypto.keys import mnemonic_to_wallet_key, private_key_to_public_key + from pytoniq_core.crypto.signature import sign_message + from pytoniq_core.tlb.account import StateInit +except ImportError as e: + raise ImportError( + "TVM mechanism requires pytoniq packages. Install with: pip install x402[tvm]" + ) from e + + +DEFAULT_TRACE_FETCH_BACKOFF_SECONDS = 0.5 + + +def _normalize_private_key_bytes(private_key: bytes) -> bytes: + """Normalize a TVM private key to the 64-byte secret key format used by pytoniq.""" + if len(private_key) == 64: + return private_key + if len(private_key) == 32: + return private_key + SigningKey(private_key).verify_key.encode() + raise ValueError("TVM private key must be 32 bytes (seed) or 64 bytes (secret key)") + + +def _parse_private_key(private_key: str | bytes) -> bytes: + """Parse a TVM private key from raw bytes, hex, or base64 text.""" + if isinstance(private_key, bytes): + return _normalize_private_key_bytes(private_key) + + value = private_key.strip() + if value.startswith("0x"): + value = value[2:] + + try: + return _normalize_private_key_bytes(bytes.fromhex(value)) + except ValueError: + pass + + try: + return _normalize_private_key_bytes(base64.b64decode(value, validate=True)) + except (ValueError, binascii.Error) as exc: + raise ValueError("TVM private key must be valid hex or base64") from exc + + +@dataclass +class HighloadV3Config: + """Configuration for one facilitator wallet on a TVM network.""" + + secret_key: bytes + api_key: str | None = None + subwallet_id: int = DEFAULT_HIGHLOAD_SUBWALLET_ID + timeout: int = DEFAULT_HIGHLOAD_TIMEOUT + relay_amount: int = DEFAULT_RELAY_AMOUNT + provider_base_url: str | None = None + provider_timeout_seconds: float = DEFAULT_TONCENTER_TIMEOUT_SECONDS + provider_emulation_timeout_seconds: float = DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS + workchain: int = 0 + provider: str = TVM_PROVIDER_TONCENTER + + @classmethod + def from_mnemonic( + cls, + mnemonic: str | list[str], + *, + subwallet_id: int = DEFAULT_HIGHLOAD_SUBWALLET_ID, + timeout: int = DEFAULT_HIGHLOAD_TIMEOUT, + relay_amount: int = DEFAULT_RELAY_AMOUNT, + workchain: int = 0, + ) -> HighloadV3Config: + """Create config from a TON mnemonic.""" + if isinstance(mnemonic, str): + mnemonic = mnemonic.split() + _, secret_key = mnemonic_to_wallet_key(mnemonic) + return cls( + secret_key=secret_key, + subwallet_id=subwallet_id, + timeout=timeout, + relay_amount=relay_amount, + workchain=workchain, + ) + + @classmethod + def from_private_key( + cls, + private_key: str | bytes, + *, + subwallet_id: int = DEFAULT_HIGHLOAD_SUBWALLET_ID, + timeout: int = DEFAULT_HIGHLOAD_TIMEOUT, + relay_amount: int = DEFAULT_RELAY_AMOUNT, + workchain: int = 0, + ) -> HighloadV3Config: + """Create config from a TVM private key.""" + return cls( + secret_key=_parse_private_key(private_key), + subwallet_id=subwallet_id, + timeout=timeout, + relay_amount=relay_amount, + workchain=workchain, + ) + + +@dataclass +class WalletV5R1Config: + """Configuration for one client-side W5R1 wallet.""" + + network: str + secret_key: bytes + api_key: str | None = None + provider_base_url: str | None = None + subwallet_number: int = DEFAULT_W5R1_SUBWALLET_NUMBER + provider_timeout_seconds: float = DEFAULT_TONCENTER_TIMEOUT_SECONDS + provider_emulation_timeout_seconds: float = DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS + workchain: int = 0 + provider: str = TVM_PROVIDER_TONCENTER + + @classmethod + def from_mnemonic( + cls, + network: str, + mnemonic: str | list[str], + *, + subwallet_number: int = DEFAULT_W5R1_SUBWALLET_NUMBER, + workchain: int = 0, + ) -> WalletV5R1Config: + """Create config from a TON mnemonic.""" + if isinstance(mnemonic, str): + mnemonic = mnemonic.split() + _, secret_key = mnemonic_to_wallet_key(mnemonic) + return cls( + network=network, + secret_key=secret_key, + subwallet_number=subwallet_number, + workchain=workchain, + ) + + @classmethod + def from_private_key( + cls, + network: str, + private_key: str | bytes, + *, + subwallet_number: int = DEFAULT_W5R1_SUBWALLET_NUMBER, + workchain: int = 0, + ) -> WalletV5R1Config: + """Create config from a TVM private key.""" + return cls( + network=network, + secret_key=_parse_private_key(private_key), + subwallet_number=subwallet_number, + workchain=workchain, + ) + + +class WalletV5R1MnemonicSigner: + """Client signer backed by a mnemonic-derived W5R1 wallet.""" + + def __init__(self, config: WalletV5R1Config) -> None: + self._config = config + self._public_key = private_key_to_public_key(config.secret_key) + self._wallet_id = make_w5r1_wallet_id( + config.network, + workchain=config.workchain, + subwallet_number=config.subwallet_number, + ) + self._state_init = build_w5r1_state_init(self._public_key, self._wallet_id) + self._address = address_from_state_init(self._state_init, config.workchain) + + @property + def address(self) -> str: + return self._address + + @property + def network(self) -> str: + return self._config.network + + @property + def api_key(self) -> str | None: + return self._config.api_key + + @property + def provider(self) -> str: + return self._config.provider + + @property + def provider_base_url(self) -> str | None: + return self._config.provider_base_url + + @property + def provider_timeout_seconds(self) -> float: + return self._config.provider_timeout_seconds + + @property + def provider_emulation_timeout_seconds(self) -> float: + return self._config.provider_emulation_timeout_seconds + + @property + def wallet_id(self) -> int: + return self._wallet_id + + @property + def state_init(self) -> StateInit: + return self._state_init + + def sign_message(self, message: bytes) -> bytes: + return sign_message(message, self._config.secret_key) + + +class FacilitatorHighloadV3Signer: + """Facilitator signer backed by a highload-wallet-contract-v3 wallet.""" + + def __init__(self, configs: dict[str, HighloadV3Config]) -> None: + self._configs = dict(configs) + self._clients: dict[str, TvmProviderClient] = {} + self._streaming_clients: dict[str, TvmStreamingSseClient] = {} + self._streaming_watchers: dict[str, TvmStreamingWatcher] = {} + self._streaming_watcher_startups: dict[str, threading.Event] = {} + self._cached_facilitator_states: dict[str, TvmAccountState] = {} + self._facilitator_state_dirty: dict[str, bool] = {} + self._wallets: dict[str, _WalletContext] = {} + self._query_ids: dict[str, int] = {} + self._lock = threading.RLock() + + for network, config in self._configs.items(): + context = _WalletContext.from_config(config) + self._wallets[network] = context + self._query_ids[network] = randbelow(MAX_USABLE_QUERY_SEQNO + 1) + self._facilitator_state_dirty[network] = True + + def get_addresses(self) -> list[str]: + """Get all facilitator wallet addresses.""" + return [wallet.address for wallet in self._wallets.values()] + + def get_addresses_for_network(self, network: str) -> list[str]: + """Get facilitator wallet addresses for one TVM network.""" + wallet = self._wallets.get(network) + if wallet is None: + raise ValueError(f"Unsupported network: {network}") + return [wallet.address] + + def close(self) -> None: + """Close all provider clients and streaming watchers owned by this signer.""" + with self._lock: + streaming_clients = list(self._streaming_clients.values()) + provider_clients = list(self._clients.values()) + self._streaming_watchers = {} + self._streaming_clients = {} + self._clients = {} + + for streaming_client in streaming_clients: + try: + streaming_client.close() + except Exception: + pass + + for provider_client in provider_clients: + try: + provider_client.close() + except Exception: + pass + + def get_account_state(self, address: str, network: str) -> TvmAccountState: + """Get current account state.""" + normalized_address = normalize_address(address) + if normalized_address == self._wallets[network].address: + return self._get_facilitator_account_state(network) + return self._client(network).get_account_state(address) + + def get_jetton_wallet(self, asset: str, owner: str, network: str) -> str: + """Resolve the canonical TEP-74 jetton wallet for an owner.""" + return self._client(network).get_jetton_wallet(asset, owner) + + def build_relay_external_boc( + self, + network: str, + relay_request: TvmRelayRequest, + *, + for_emulation: bool = False, + ) -> bytes: + """Build a Highload V3 external message for relaying the pre-signed W5 request.""" + return self.build_relay_external_boc_batch( + network, [relay_request], for_emulation=for_emulation + ) + + def build_relay_external_boc_batch( + self, + network: str, + relay_requests: list[TvmRelayRequest], + *, + for_emulation: bool = False, + ) -> bytes: + """Build one Highload V3 external message for relaying multiple W5 requests.""" + if not relay_requests: + raise ValueError("relay_requests must not be empty") + + wallet_context = self._wallets[network] + query_id = self._select_query_id(network, for_emulation) + created_at = ( + int(time.time()) - 5 + ) # workaround because lite servers often lag behind the blockchain + external_state_init = None + forward_actions: list[Cell] = [] + + for relay_request in relay_requests: + forward_value = ( + relay_request.relay_amount + if relay_request.relay_amount is not None + else wallet_context.config.relay_amount + relay_request.forward_ton_amount + ) + forward_message = Contract.create_internal_msg( + src=None, + dest=Address(relay_request.destination), + bounce=True, + value=forward_value, + state_init=relay_request.state_init, + body=relay_request.body, + ) + forward_actions.append(serialize_send_msg_action(forward_message.serialize(), mode=3)) + + message_to_send = self._pack_actions_message(wallet_context, forward_actions, query_id) + + message_inner = ( + begin_cell() + .store_uint(wallet_context.config.subwallet_id, 32) + .store_ref(message_to_send) + .store_uint(1, 8) + .store_uint(query_id, 23) + .store_uint(created_at, 64) + .store_uint(wallet_context.config.timeout, 22) + .end_cell() + ) + + external_body = ( + begin_cell() + .store_bytes(sign_message(message_inner.hash, wallet_context.config.secret_key)) + .store_ref(message_inner) + .end_cell() + ) + + if wallet_context.deployed is not True: + facilitator_account = self.get_account_state(wallet_context.address, network) + wallet_context.deployed = facilitator_account.is_active + if facilitator_account.is_uninitialized: + external_state_init = wallet_context.state_init + + external_message = Contract.create_external_msg( + dest=Address(wallet_context.address), + state_init=external_state_init, + body=external_body, + ) + return external_message.serialize().to_boc() + + def emulate_external_message(self, network: str, external_boc: bytes) -> dict[str, object]: + """Emulate a prepared external message via the configured TVM provider.""" + return self._client(network).emulate_trace( + external_boc, + timeout=self._configs[network].provider_emulation_timeout_seconds, + ) + + def send_external_message(self, network: str, external_boc: bytes) -> str: + """Broadcast a prepared external message via the configured TVM provider.""" + self._ensure_streaming_watcher(network) + return self._client(network).send_message(external_boc) + + def wait_for_trace_confirmation( + self, + network: str, + trace_external_hash_norm: str, + *, + timeout_seconds: float, + ) -> dict[str, object]: + """Wait until the submitted trace reaches finalized.""" + deadline = time.monotonic() + timeout_seconds + + if self._ensure_streaming_watcher(network): + try: + remaining = min( + DEFAULT_STREAMING_CONFIRMATION_GRACE_SECONDS, + max(0.0, deadline - time.monotonic()), + ) + self._streaming_client(network).wait_for_trace_confirmation( + trace_external_hash_norm=trace_external_hash_norm, + timeout_seconds=remaining, + ) + except Exception: + pass + + last_error: Exception | None = None + while time.monotonic() < deadline: + try: + trace = self._client(network).get_trace_by_message_hash(trace_external_hash_norm) + if not trace.get("is_incomplete", False): + return trace + except Exception as exc: + last_error = exc + time.sleep(DEFAULT_TRACE_FETCH_BACKOFF_SECONDS) + + if last_error is not None: + raise last_error + raise RuntimeError(f"Timed out waiting for complete trace {trace_external_hash_norm}") + + def get_jetton_wallet_data(self, address: str, network: str) -> TvmJettonWalletData: + """Read TEP-74 jetton wallet data.""" + return self._client(network).get_jetton_wallet_data(address) + + def _client(self, network: str) -> TvmProviderClient: + client = self._clients.get(network) + if client is not None: + return client + + with self._lock: + client = self._clients.get(network) + if client is None: + config = self._configs[network] + client = create_tvm_provider_client( + network, + provider=config.provider, + api_key=config.api_key, + base_url=config.provider_base_url, + timeout=config.provider_timeout_seconds, + ) + self._clients[network] = client + return client + + def _streaming_client(self, network: str) -> TvmStreamingSseClient: + client = self._streaming_clients.get(network) + if client is not None: + return client + + with self._lock: + client = self._streaming_clients.get(network) + if client is None: + config = self._configs[network] + client = TvmStreamingSseClient( + base_url=( + config.provider_base_url or _default_base_url(network, config.provider) + ), + api_key=config.api_key, + provider=config.provider, + ) + self._streaming_clients[network] = client + return client + + def _get_facilitator_account_state(self, network: str) -> TvmAccountState: + """We cache the account state of the facilitator. The cache is invalidated when an event arrives from the StreamingAPI.""" + facilitator_address = self._wallets[network].address + + self._ensure_streaming_watcher(network) + with self._lock: + cached_state = self._cached_facilitator_states.get(network) + is_dirty = self._facilitator_state_dirty.get(network, True) + if cached_state is not None and not is_dirty: + return cached_state + + refreshed_state = self._client(network).get_account_state(facilitator_address) + with self._lock: + self._cached_facilitator_states[network] = refreshed_state + self._facilitator_state_dirty[network] = False + return refreshed_state + + def _ensure_streaming_watcher(self, network: str) -> bool: + startup_event: threading.Event | None = None + should_start = False + with self._lock: + existing_watcher = self._streaming_watchers.get(network) + if existing_watcher is not None and existing_watcher.is_alive(): + return True + if existing_watcher is not None: + self._streaming_watchers.pop(network, None) + startup_event = self._streaming_watcher_startups.get(network) + if startup_event is None: + startup_event = threading.Event() + self._streaming_watcher_startups[network] = startup_event + should_start = True + + if not should_start: + assert startup_event is not None + startup_event.wait() + with self._lock: + existing_watcher = self._streaming_watchers.get(network) + return existing_watcher is not None and existing_watcher.is_alive() + + watcher: TvmStreamingWatcher | None = None + try: + watcher = self._streaming_client(network).start_account_state_watcher( + address=self._wallets[network].address, + on_invalidate=lambda: self._mark_facilitator_state_dirty(network), + ) + except Exception: + watcher = None + finally: + assert startup_event is not None + with self._lock: + if watcher is not None: + self._streaming_watchers[network] = watcher + self._streaming_watcher_startups.pop(network, None) + startup_event.set() + + return watcher is not None + + def _mark_facilitator_state_dirty(self, network: str) -> None: + with self._lock: + self._facilitator_state_dirty[network] = True + + def _pack_actions_message( + self, + wallet_context: _WalletContext, + actions: list[Cell], + query_id: int, + ) -> Cell: + batch_actions = list(actions) + if len(batch_actions) > 254: + nested_message = self._pack_actions_message( + wallet_context, batch_actions[253:], query_id + ) + batch_actions = batch_actions[:253] + [ + serialize_send_msg_action(nested_message, mode=3) + ] + + return Contract.create_internal_msg( + src=None, + dest=Address(wallet_context.address), + bounce=True, + value=10**9, + body=serialize_internal_transfer(serialize_out_list(batch_actions), query_id), + ).serialize() + + def _select_query_id(self, network: str, for_emulation: bool) -> int: + """Pick a free HighloadV3 QueryID from the local monotonic seqno cursor.""" + wallet_context = self._wallets[network] + query_state = load_highload_query_state( + self.get_account_state(wallet_context.address, network), + expected_code_hash=HIGHLOAD_V3_CODE_HASH, + ) + with self._lock: + wallet_context = self._wallets[network] + wallet_context.deployed = query_state is not None + attempts = MAX_USABLE_QUERY_SEQNO + 1 + next_seqno = self._query_ids[network] + for _ in range(attempts): + seqno = next_seqno + next_seqno = (next_seqno + 1) % (MAX_USABLE_QUERY_SEQNO + 1) + query_id = seqno_to_query_id(seqno) + if query_state is None or not query_id_is_processed(query_state, query_id): + if not for_emulation: + self._query_ids[network] = next_seqno + return query_id + raise RuntimeError("No free Highload V3 query_id available") + + +@dataclass +class _WalletContext: + config: HighloadV3Config + public_key: bytes + address: str + state_init: StateInit + deployed: bool | None = None + + @classmethod + def from_config(cls, config: HighloadV3Config) -> _WalletContext: + # TON-specific: highload v3 wallet address is derived from its fixed code and data layout. + public_key = private_key_to_public_key(config.secret_key) + code = Cell.one_from_boc(bytes.fromhex(HIGHLOAD_V3_CODE_HEX)) + if code.hash.hex() != HIGHLOAD_V3_CODE_HASH: + raise ValueError("Unexpected highload-wallet-contract-v3 code hash") + + data = ( + begin_cell() + .store_bytes(public_key) + .store_uint(config.subwallet_id, 32) + .store_uint(0, 66) + .store_uint(config.timeout, 22) + .end_cell() + ) + state_init = StateInit(code=code, data=data) + address = normalize_address(Address((config.workchain, state_init.serialize().hash))) + return cls( + config=config, + public_key=public_key, + address=address, + state_init=state_init, + deployed=None, + ) diff --git a/python/x402/mechanisms/tvm/streaming.py b/python/x402/mechanisms/tvm/streaming.py new file mode 100644 index 0000000000..7d9d49be54 --- /dev/null +++ b/python/x402/mechanisms/tvm/streaming.py @@ -0,0 +1,559 @@ +"""TVM provider streaming helpers.""" + +from __future__ import annotations + +import base64 +import binascii +import json +import queue +import threading +import time +from collections.abc import Callable, Iterable, Iterator +from dataclasses import dataclass, field +from typing import Any + +from .codecs.common import normalize_address +from .constants import ( + SUPPORTED_TVM_PROVIDERS, + TVM_PROVIDER_TONAPI, + TVM_PROVIDER_TONCENTER, +) + +try: + import httpx +except ImportError as e: + raise ImportError( + "TVM mechanism requires httpx. Install with: pip install x402[tvm,httpx]" + ) from e + + +DEFAULT_STREAMING_READ_TIMEOUT_SECONDS = 20.0 +DEFAULT_STREAMING_RECONNECT_BACKOFF_SECONDS = 1.0 +DEFAULT_STREAMING_MAX_CONSECUTIVE_FAILURES = 3 +DEFAULT_RECENT_TRACE_RESULT_TTL_SECONDS = 60.0 +DEFAULT_STREAMING_START_TIMEOUT_SECONDS = 2.0 +_TONAPI_STREAMING_SSE_PATH = "/streaming/v2/sse" +_TONCENTER_STREAMING_SSE_PATH = "/api/streaming/v2/sse" + + +def _account_stream_subscription(normalized_address: str) -> dict[str, object]: + return { + "addresses": [normalized_address], + "types": ["account_state_change", "transactions"], + "min_finality": "finalized", + } + + +def _iter_sse_payloads(lines: Iterable[str]) -> Iterator[str]: + """Yield SSE event payloads from an iterable of text lines.""" + data_lines: list[str] = [] + + for line in lines: + if line == "": + if data_lines: + yield "\n".join(data_lines) + data_lines = [] + continue + if line.startswith(":"): + continue + if line.startswith("data:"): + data_lines.append(line[5:].lstrip()) + continue + if line.startswith(("event:", "id:", "retry:")): + continue + data_lines.append(line) + + +def _iter_sse_json_events(lines: Iterable[str]) -> Iterator[dict[str, Any]]: + """Parse SSE JSON object payloads from text lines.""" + for payload in _iter_sse_payloads(lines): + try: + event = json.loads(payload) + except json.JSONDecodeError as exc: + raise RuntimeError("Toncenter SSE emitted malformed JSON") from exc + if not isinstance(event, dict): + raise RuntimeError("Toncenter SSE emitted a non-object event") + yield event + + +@dataclass +class _StreamResources: + lock: threading.Lock + client: httpx.Client | None = None + response: httpx.Response | None = None + + def attach(self, client: httpx.Client, response: httpx.Response) -> None: + with self.lock: + self.client = client + self.response = response + + def detach(self, client: httpx.Client, response: httpx.Response | None) -> None: + with self.lock: + if self.response is response: + self.response = None + if self.client is client: + self.client = None + + def close(self) -> None: + with self.lock: + response = self.response + client = self.client + self.response = None + self.client = None + + if response is not None: + try: + response.close() + except Exception: + pass + if client is not None: + try: + client.close() + except Exception: + pass + + +@dataclass +class _RecentTraceResult: + completed_at: float + payload: dict[str, Any] | None + error: Exception | None + + +@dataclass +class _StartupState: + ready_event: threading.Event = field(default_factory=threading.Event) + error: Exception | None = None + + def mark_ready(self) -> None: + self.ready_event.set() + + def fail(self, exc: Exception) -> None: + self.error = exc + self.ready_event.set() + + +class TvmStreamingWatcher: + """Handle for a long-lived facilitator-account streaming watcher.""" + + def __init__( + self, + thread: threading.Thread, + stop_event: threading.Event, + close_stream: Callable[[], None], + ) -> None: + self._thread = thread + self._stop_event = stop_event + self._close_stream = close_stream + + def close(self) -> None: + self._stop_event.set() + self._close_stream() + self._thread.join(timeout=1.0) + + def is_alive(self) -> bool: + """Report whether the watcher thread is still running.""" + return self._thread.is_alive() + + def is_current_thread(self) -> bool: + """Report whether the caller runs on the watcher thread.""" + return self._thread is threading.current_thread() + + +class TvmStreamingSseClient: + """Shared SSE client for provider account streams.""" + + def __init__( + self, + *, + base_url: str, + api_key: str | None = None, + provider: str = TVM_PROVIDER_TONCENTER, + sse_path: str | None = None, + ) -> None: + self._provider = provider.strip().lower() + if self._provider not in SUPPORTED_TVM_PROVIDERS: + raise ValueError(f"Unsupported TVM streaming provider: {self._provider}") + self._provider_label = "TonAPI" if self._provider == TVM_PROVIDER_TONAPI else "Toncenter" + self._base_url = base_url.rstrip("/") + self._sse_path = sse_path or ( + _TONAPI_STREAMING_SSE_PATH + if self._provider == TVM_PROVIDER_TONAPI + else _TONCENTER_STREAMING_SSE_PATH + ) + self._headers = { + "Accept": "text/event-stream", + "Content-Type": "application/json", + } + if api_key: + if self._provider == TVM_PROVIDER_TONAPI: + self._headers["Authorization"] = f"Bearer {api_key}" + else: + self._headers["X-Api-Key"] = api_key + + self._lock = threading.Lock() + self._stream_resources = _StreamResources(lock=threading.Lock()) + self._watcher: TvmStreamingWatcher | None = None + self._watched_address: str | None = None + self._pending_trace_waiters: dict[str, list[queue.Queue[dict[str, Any] | Exception]]] = {} + self._recent_trace_results: dict[str, _RecentTraceResult] = {} + + def close(self) -> None: + """Close the watcher and any underlying stream resources.""" + with self._lock: + watcher = self._watcher + self._watcher = None + self._watched_address = None + pending_waiters = self._pending_trace_waiters + self._pending_trace_waiters = {} + self._recent_trace_results = {} + + self._stream_resources.close() + if watcher is not None: + watcher.close() + + error = RuntimeError(f"{self._provider_label} facilitator account stream closed") + for waiters in pending_waiters.values(): + self._notify_waiters(waiters, error) + + def start_account_state_watcher( + self, + *, + address: str, + on_invalidate: Callable[[], None], + ) -> TvmStreamingWatcher: + """Start one shared stream on the facilitator address.""" + normalized_address = normalize_address(address) + with self._lock: + if self._watcher is not None and not self._watcher.is_alive(): + self._watcher = None + self._watched_address = None + if self._watcher is not None: + if self._watched_address != normalized_address: + raise RuntimeError("TvmStreamingSseClient already watches a different address") + return self._watcher + + stop_event = threading.Event() + startup_state = _StartupState() + thread = threading.Thread( + target=self._run_account_stream, + args=(stop_event, normalized_address, on_invalidate, startup_state), + name=f"{self._provider}-account-stream", + daemon=True, + ) + watcher = TvmStreamingWatcher( + thread, + stop_event, + close_stream=self._stream_resources.close, + ) + self._watcher = watcher + self._watched_address = normalized_address + + thread.start() + if not startup_state.ready_event.wait(timeout=DEFAULT_STREAMING_START_TIMEOUT_SECONDS): + watcher.close() + with self._lock: + if self._watcher is watcher: + self._watcher = None + self._watched_address = None + raise RuntimeError( + f"{self._provider_label} facilitator account stream did not become ready in time" + ) + if startup_state.error is not None: + watcher.close() + with self._lock: + if self._watcher is watcher: + self._watcher = None + self._watched_address = None + raise RuntimeError( + f"{self._provider_label} facilitator account stream failed to start" + ) from startup_state.error + return watcher + + def wait_for_trace_confirmation( + self, + *, + trace_external_hash_norm: str, + timeout_seconds: float, + ) -> dict[str, Any]: + """Block until the shared account stream observes the finalized trace.""" + trace_waiter: queue.Queue[dict[str, Any] | Exception] | None = None + recent_result: _RecentTraceResult | None = None + trace_hash_aliases = _trace_hash_aliases(trace_external_hash_norm) + + with self._lock: + self._prune_recent_trace_results_locked() + if self._watcher is None: + raise RuntimeError( + f"{self._provider_label} facilitator account stream has not been started" + ) + for trace_hash_alias in trace_hash_aliases: + recent_result = self._recent_trace_results.get(trace_hash_alias) + if recent_result is not None: + break + if recent_result is None: + trace_waiter = queue.Queue(maxsize=1) + for trace_hash_alias in trace_hash_aliases: + self._pending_trace_waiters.setdefault(trace_hash_alias, []).append( + trace_waiter + ) + + if recent_result is not None: + if recent_result.error is not None: + raise recent_result.error + if recent_result.payload is None: + raise RuntimeError( + f"{self._provider_label} did not cache finalized trace payload for " + f"{trace_external_hash_norm}" + ) + return recent_result.payload + + assert trace_waiter is not None + try: + result = trace_waiter.get(timeout=timeout_seconds) + except queue.Empty as exc: + self._remove_pending_waiter(trace_external_hash_norm, trace_waiter) + raise RuntimeError( + f"Timed out waiting for finalized trace {trace_external_hash_norm}" + ) from exc + + if isinstance(result, Exception): + raise result + return result + + def _run_account_stream( + self, + stop_event: threading.Event, + normalized_address: str, + on_invalidate: Callable[[], None], + startup_state: _StartupState, + ) -> None: + consecutive_failures = 0 + + def on_subscribed() -> None: + nonlocal consecutive_failures + consecutive_failures = 0 + startup_state.mark_ready() + + try: + while not stop_event.is_set(): + try: + self._consume_stream( + subscription=_account_stream_subscription(normalized_address), + stop_event=stop_event, + on_event=lambda event: self._handle_stream_event( + event, + normalized_address=normalized_address, + on_invalidate=on_invalidate, + on_subscribed=on_subscribed, + ), + resources=self._stream_resources, + ) + except Exception as exc: + if not startup_state.ready_event.is_set(): + startup_state.fail(exc) + break + if stop_event.is_set(): + break + + on_invalidate() + consecutive_failures += 1 + if consecutive_failures >= DEFAULT_STREAMING_MAX_CONSECUTIVE_FAILURES: + self._fail_pending_waiters(exc) + break + + stop_event.wait(DEFAULT_STREAMING_RECONNECT_BACKOFF_SECONDS) + finally: + with self._lock: + if self._watcher is not None and self._watcher.is_current_thread(): + self._watcher = None + self._watched_address = None + + def _consume_stream( + self, + *, + subscription: dict[str, object], + stop_event: threading.Event, + on_event: Callable[[dict[str, Any]], None], + resources: _StreamResources | None = None, + ) -> None: + client = httpx.Client( + base_url=self._base_url, + headers=self._headers, + timeout=httpx.Timeout( + connect=DEFAULT_STREAMING_READ_TIMEOUT_SECONDS, + write=DEFAULT_STREAMING_READ_TIMEOUT_SECONDS, + pool=DEFAULT_STREAMING_READ_TIMEOUT_SECONDS, + read=DEFAULT_STREAMING_READ_TIMEOUT_SECONDS, + ), + ) + response: httpx.Response | None = None + try: + with client: + with client.stream("POST", self._sse_path, json=subscription) as response: + response.raise_for_status() + if resources is not None: + resources.attach(client, response) + + for event in _iter_sse_json_events(response.iter_lines()): + if stop_event.is_set(): + return + on_event(event) + if stop_event.is_set(): + return + + if stop_event.is_set(): + return + raise RuntimeError(f"{self._provider_label} SSE stream terminated unexpectedly") + finally: + if resources is not None: + resources.detach(client, response) + + def _handle_stream_event( + self, + event: dict[str, Any], + *, + normalized_address: str, + on_invalidate: Callable[[], None], + on_subscribed: Callable[[], None], + ) -> None: + if event.get("status") == "subscribed": + on_subscribed() + return + + if event.get("type") == "account_state_change": + account = event.get("account") + if isinstance(account, str) and normalize_address(account) == normalized_address: + on_invalidate() + return + + trace_result = self._trace_result_from_event(event) + if trace_result is None: + return + + self._publish_trace_result(*trace_result) + + def _publish_trace_result( + self, + trace_external_hash_norm: str, + payload: dict[str, Any] | None, + error: Exception | None, + ) -> None: + with self._lock: + self._prune_recent_trace_results_locked() + recent_result = _RecentTraceResult( + completed_at=time.monotonic(), payload=payload, error=error + ) + waiters_by_id: dict[int, queue.Queue[dict[str, Any] | Exception]] = {} + for trace_hash_alias in _trace_hash_aliases(trace_external_hash_norm): + self._recent_trace_results[trace_hash_alias] = recent_result + for waiter in self._pending_trace_waiters.pop(trace_hash_alias, []): + waiters_by_id[id(waiter)] = waiter + waiters = list(waiters_by_id.values()) + + self._notify_waiters(waiters, error if error is not None else payload) + + def _fail_pending_waiters(self, exc: Exception) -> None: + error = RuntimeError( + f"{self._provider_label} facilitator account stream failed before confirmation: {exc}" + ) + with self._lock: + pending_trace_waiters = self._pending_trace_waiters + self._pending_trace_waiters = {} + + for waiters in pending_trace_waiters.values(): + self._notify_waiters(waiters, error) + + def _remove_pending_waiter( + self, + trace_external_hash_norm: str, + trace_waiter: queue.Queue[dict[str, Any] | Exception], + ) -> None: + with self._lock: + for trace_hash_alias in _trace_hash_aliases(trace_external_hash_norm): + waiters = self._pending_trace_waiters.get(trace_hash_alias) + if waiters is None: + continue + self._pending_trace_waiters[trace_hash_alias] = [ + waiter for waiter in waiters if waiter is not trace_waiter + ] + if not self._pending_trace_waiters[trace_hash_alias]: + self._pending_trace_waiters.pop(trace_hash_alias, None) + + def _prune_recent_trace_results_locked(self) -> None: + cutoff = time.monotonic() - DEFAULT_RECENT_TRACE_RESULT_TTL_SECONDS + stale_hashes = [ + trace_external_hash_norm + for trace_external_hash_norm, recent_result in self._recent_trace_results.items() + if recent_result.completed_at < cutoff + ] + for trace_external_hash_norm in stale_hashes: + self._recent_trace_results.pop(trace_external_hash_norm, None) + + def _notify_waiters( + self, + waiters: Iterable[queue.Queue[dict[str, Any] | Exception]], + result: dict[str, Any] | Exception | None, + ) -> None: + for trace_waiter in waiters: + try: + if result is None: + continue + trace_waiter.put_nowait(result) + except queue.Full: + continue + + def _trace_result_from_event( + self, + event: dict[str, Any], + ) -> tuple[str, dict[str, Any] | None, Exception | None] | None: + event_type = event.get("type") + if event_type not in {"trace", "transactions"}: + return None + + trace_external_hash_norm = event.get("trace_external_hash_norm") + if not isinstance(trace_external_hash_norm, str): + return None + if event.get("finality") != "finalized": + return None + return trace_external_hash_norm, event, None + + +def _trace_hash_aliases(trace_hash: str) -> list[str]: + aliases = [trace_hash] + normalized = trace_hash.strip() + + raw_hash: bytes | None = None + if len(normalized) == 64: + try: + raw_hash = bytes.fromhex(normalized) + except ValueError: + raw_hash = None + if raw_hash is None: + padded = normalized + "=" * (-len(normalized) % 4) + for decoder in (base64.b64decode, base64.urlsafe_b64decode): + try: + candidate = decoder(padded) + except (ValueError, binascii.Error): + continue + if len(candidate) == 32: + raw_hash = candidate + break + + if raw_hash is not None: + aliases.extend( + [ + raw_hash.hex(), + base64.b64encode(raw_hash).decode("ascii"), + base64.urlsafe_b64encode(raw_hash).decode("ascii").rstrip("="), + ] + ) + + deduped: list[str] = [] + seen: set[str] = set() + for alias in aliases: + if alias in seen: + continue + seen.add(alias) + deduped.append(alias) + return deduped diff --git a/python/x402/mechanisms/tvm/trace_utils.py b/python/x402/mechanisms/tvm/trace_utils.py new file mode 100644 index 0000000000..bf7345c150 --- /dev/null +++ b/python/x402/mechanisms/tvm/trace_utils.py @@ -0,0 +1,133 @@ +"""Helpers for extracting TVM execution fees from Toncenter traces.""" + +from __future__ import annotations + +import base64 + + +def parse_trace_transactions(trace_data: dict[str, object]) -> list[dict[str, object]]: + """Return transaction objects from a Toncenter trace payload.""" + try: + transactions = trace_data["transactions"] + return list(transactions.values()) + except (KeyError, AttributeError, TypeError) as exc: + raise ValueError("Toncenter trace did not return transactions dict") from exc + + +def transaction_succeeded(transaction: dict[str, object]) -> bool: + """Return True when a traced transaction completed successfully.""" + description = _transaction_phases(transaction) + if description.get("aborted") is True: + return False + + compute_phase: dict = description["compute_ph"] + if compute_phase.get("skipped") is True or compute_phase.get("success") is not True: + return False + + action_phase = description.get("action") + if action_phase is not None and action_phase.get("success") is not True: + return False + + return True + + +def body_hash_to_base64(raw_hash: bytes) -> str: + """Encode a raw TVM cell hash to the Toncenter base64 representation.""" + return base64.b64encode(raw_hash).decode("ascii") + + +def trace_transaction_hash_to_hex(encoded_hash: str) -> str: + """Convert a provider transaction hash to lowercase hex.""" + normalized = encoded_hash.strip() + if len(normalized) == 64: + try: + bytes.fromhex(normalized) + return normalized.lower() + except ValueError: + pass + return base64.b64decode(normalized).hex() + + +def message_body_hash_matches(message: dict[str, object], expected_hash: bytes) -> bool: + """Check whether a trace message matches a known TVM body hash.""" + return message.get("message_content", {}).get("hash") == body_hash_to_base64(expected_hash) + + +def trace_transaction_fwd_fees( + transaction: dict[str, object], + *, + expected_count: int | None = None, +) -> int: + """Extract the total forward fees paid by a transaction.""" + exact_fees = [ + parsed_fee + for out_message in transaction.get("out_msgs", []) + for parsed_fee in [_parse_int(out_message.get("fwd_fee"))] + if parsed_fee is not None + ] + if exact_fees: + return sum(exact_fees) + + action_phase: dict = _transaction_phases(transaction).get("action") + if action_phase is not None: + total_fwd_fees = _parse_int(action_phase.get("total_fwd_fees")) + if total_fwd_fees is not None: + return total_fwd_fees + + fwd_fee = _parse_int(action_phase.get("fwd_fee")) + if fwd_fee is not None: + return fwd_fee * expected_count if expected_count is not None else fwd_fee + + return 0 + + +def trace_transaction_compute_fees(transaction: dict[str, object]) -> int: + """Extract compute gas fees from a transaction description.""" + compute_phase: dict = _transaction_phases(transaction)["compute_ph"] + return _parse_int(compute_phase.get("gas_fees")) or 0 + + +def trace_transaction_storage_fees(transaction: dict[str, object]) -> int: + """Extract storage fees from a transaction description.""" + storage_phase: dict = _transaction_phases(transaction)["storage_ph"] + return (_parse_int(storage_phase.get("storage_fees_collected")) or 0) + ( + _parse_int(storage_phase.get("storage_fees_due")) or 0 + ) + + +def trace_transaction_balance_before(transaction: dict[str, object]) -> int: + """Extract the account balance before transaction execution.""" + before_state: dict = transaction.get("account_state_before") + if before_state is not None: + balance = _parse_int(before_state.get("balance")) + if balance is not None: + return balance + + account_state: dict = transaction.get("account_state") + if account_state is not None: + balance = _parse_int(account_state.get("balance")) + if balance is not None: + return balance + + balance = _parse_int(transaction.get("balance")) + if balance is not None: + return balance + + raise ValueError("Trace transaction is missing account_state_before balance") + + +def _transaction_phases(transaction: dict[str, object]) -> dict[str, object]: + return transaction.get("description", transaction) + + +def _parse_int(value: object) -> int | None: + if isinstance(value, bool): + return int(value) + if isinstance(value, int): + return value + if isinstance(value, str): + try: + return int(value, 0) + except ValueError: + return None + return None diff --git a/python/x402/mechanisms/tvm/types.py b/python/x402/mechanisms/tvm/types.py new file mode 100644 index 0000000000..d8353eda58 --- /dev/null +++ b/python/x402/mechanisms/tvm/types.py @@ -0,0 +1,117 @@ +"""TVM-specific payload and parsed data types.""" + +from __future__ import annotations + +from dataclasses import dataclass +from typing import Any + +try: + from pytoniq_core import Cell + from pytoniq_core.tlb.account import StateInit +except ImportError as e: + raise ImportError( + "TVM mechanism requires pytoniq packages. Install with: pip install x402[tvm]" + ) from e + + +@dataclass +class ExactTvmPayload: + """Exact payment payload for TVM networks.""" + + settlement_boc: str + asset: str + + def to_dict(self) -> dict[str, Any]: + """Convert to dictionary for JSON serialization.""" + return { + "settlementBoc": self.settlement_boc, + "asset": self.asset, + } + + @classmethod + def from_dict(cls, data: dict[str, Any]) -> ExactTvmPayload: + """Create from dictionary.""" + settlement_boc = data.get("settlementBoc") + if not isinstance(settlement_boc, str) or not settlement_boc.strip(): + raise ValueError("Exact TVM payload field 'settlementBoc' is required") + + asset = data.get("asset") + if not isinstance(asset, str) or not asset.strip(): + raise ValueError("Exact TVM payload field 'asset' is required") + + return cls( + settlement_boc=settlement_boc, + asset=asset, + ) + + +@dataclass +class ParsedJettonTransfer: + """Jetton transfer extracted from a W5 action.""" + + source_wallet: str + destination: str + response_destination: str | None + jetton_amount: int + attached_ton_amount: int + forward_ton_amount: int + forward_payload: Cell + body_hash: bytes | None = None + + +@dataclass +class ParsedTvmSettlement: + """Parsed TON settlement payload.""" + + payer: str + wallet_id: int + valid_until: int + seqno: int + settlement_hash: str + body: Cell + signed_slice_hash: bytes + signature: bytes + state_init: StateInit | None + transfer: ParsedJettonTransfer + + +@dataclass +class TvmAccountState: + """Subset of account state needed by the facilitator.""" + + address: str + balance: int + is_active: bool + is_uninitialized: bool + is_frozen: bool + state_init: StateInit | None + + +@dataclass +class TvmJettonWalletData: + """Data returned by TEP-74 get_wallet_data().""" + + address: str + balance: int + owner: str + jetton_minter: str + + +@dataclass +class TvmRelayRequest: + """One relay request forwarded by the facilitator highload wallet.""" + + destination: str + body: Cell + state_init: StateInit | None + forward_ton_amount: int = 0 + relay_amount: int | None = None + + +@dataclass +class W5InitData: + signature_allowed: bool + seqno: int + wallet_id: int + public_key: bytes + extensions_dict: Cell | None diff --git a/python/x402/mechanisms/tvm/utils.py b/python/x402/mechanisms/tvm/utils.py new file mode 100644 index 0000000000..05f6cbc5b6 --- /dev/null +++ b/python/x402/mechanisms/tvm/utils.py @@ -0,0 +1,65 @@ +"""Backward-compatible TVM utility facade. + +This module keeps the historical import surface while the actual codec logic +is split across ``tvm.codecs`` and ``tvm.exact.codec``. +""" + +from __future__ import annotations + +try: + from pytoniq_core.crypto.signature import verify_sign +except ImportError as e: + raise ImportError( + "TVM mechanism requires pytoniq packages. Install with: pip install x402[tvm]" + ) from e + +from .codecs.common import ( + address_to_stack_item, + get_network_global_id, + normalize_address, + parse_amount, + parse_money_to_decimal, +) +from .codecs.jetton import ( + build_jetton_transfer_body, + build_jetton_transfer_body_fields, + parse_jetton_transfer, +) +from .codecs.w5 import ( + address_from_state_init, + build_w5_signed_body, + build_w5r1_state_init, + get_w5_seqno, + make_w5r1_wallet_id, + parse_active_w5_account_state, + parse_out_list, + parse_w5_init_data, + serialize_out_list, + serialize_send_msg_action, + verify_w5_signature, +) +from .exact.codec import parse_exact_tvm_payload + +__all__ = [ + "address_from_state_init", + "address_to_stack_item", + "build_jetton_transfer_body", + "build_jetton_transfer_body_fields", + "build_w5_signed_body", + "build_w5r1_state_init", + "get_network_global_id", + "get_w5_seqno", + "make_w5r1_wallet_id", + "normalize_address", + "parse_active_w5_account_state", + "parse_amount", + "parse_exact_tvm_payload", + "parse_jetton_transfer", + "parse_money_to_decimal", + "parse_out_list", + "parse_w5_init_data", + "serialize_out_list", + "serialize_send_msg_action", + "verify_sign", + "verify_w5_signature", +] diff --git a/python/x402/pyproject.toml b/python/x402/pyproject.toml index 4affe3ab24..27dcad0351 100644 --- a/python/x402/pyproject.toml +++ b/python/x402/pyproject.toml @@ -1,11 +1,11 @@ [project] name = "x402" -version = "2.5.0" +version = "2.10.0" description = "x402 Payment Protocol SDK for Python" readme = "README.md" license = { text = "MIT" } requires-python = ">=3.10" -authors = [{ name = "Coinbase" }] +authors = [{ name = "x402 Foundation" }] keywords = ["x402", "payment", "protocol", "http", "402"] classifiers = [ "Development Status :: 3 - Alpha", @@ -46,18 +46,24 @@ svm = [ "solders>=0.27.0", "solana>=0.36.0", ] +tvm = [ + "httpx>=0.28.1", + "pytoniq>=0.1.39", + "pytoniq-core>=0.1.36", + "PyNaCl>=1.5.0", +] # MCP (Model Context Protocol) integration mcp = ["mcp>=1.0.0"] # Extensions - optional functionality -extensions = ["jsonschema>=4.0.0"] +extensions = ["jsonschema>=4.0.0", "idna>=3.4"] # Convenience bundles clients = ["x402[httpx,requests]"] servers = ["x402[flask,fastapi]"] -mechanisms = ["x402[evm,svm]"] -all = ["x402[httpx,requests,flask,fastapi,evm,svm,mcp,extensions]"] +mechanisms = ["x402[evm,svm,tvm]"] +all = ["x402[httpx,requests,flask,fastapi,evm,svm,tvm,mcp,extensions]"] [dependency-groups] dev = [ @@ -82,17 +88,22 @@ dev = [ # SVM dependencies "solders>=0.27.0", "solana>=0.36.0", + # TVM dependencies + "pytoniq>=0.1.39", + "pytoniq-core>=0.1.36", + "PyNaCl>=1.5.0", # MCP dependencies "mcp>=1.26.0", "nest-asyncio>=1.6.0", # Extensions dependencies "jsonschema>=4.0.0", + "idna>=3.4", ] [project.urls] -Homepage = "https://github.com/coinbase/x402" +Homepage = "https://github.com/x402-foundation/x402" Documentation = "https://x402.org" -Repository = "https://github.com/coinbase/x402" +Repository = "https://github.com/x402-foundation/x402" [build-system] requires = ["hatchling"] @@ -103,6 +114,8 @@ include = [ "*.py", "**/*.py", "py.typed", + "mcp/CHANGELOG.md", + "mcp/README.md", ] exclude = [ "tests/", @@ -125,7 +138,17 @@ exclude = [ "http" = "x402/http" "mechanisms" = "x402/mechanisms" "extensions" = "x402/extensions" -"mcp" = "x402/mcp" +"mcp/CHANGELOG.md" = "x402/mcp/CHANGELOG.md" +"mcp/README.md" = "x402/mcp/README.md" +"mcp/__init__.py" = "x402/mcp/__init__.py" +"mcp/client.py" = "x402/mcp/client.py" +"mcp/client_async.py" = "x402/mcp/client_async.py" +"mcp/constants.py" = "x402/mcp/constants.py" +"mcp/server.py" = "x402/mcp/server.py" +"mcp/server_async.py" = "x402/mcp/server_async.py" +"mcp/server_sync.py" = "x402/mcp/server_sync.py" +"mcp/types.py" = "x402/mcp/types.py" +"mcp/utils.py" = "x402/mcp/utils.py" [tool.ruff] line-length = 100 @@ -162,7 +185,7 @@ package = "x402" filename = "CHANGELOG.md" directory = "changelog.d/" title_format = "## [{version}] - {project_date}" -issue_format = "[#{issue}](https://github.com/coinbase/x402/pull/{issue})" +issue_format = "[#{issue}](https://github.com/x402-foundation/x402/pull/{issue})" [tool.towncrier.fragment.feature] name = "Added" @@ -178,3 +201,6 @@ name = "Removals" [tool.towncrier.fragment.misc] name = "Misc" + +[tool.uv] +exclude-newer = "3 days" diff --git a/python/x402/schemas/payments.py b/python/x402/schemas/payments.py index 56d97a9c51..af5b283e75 100644 --- a/python/x402/schemas/payments.py +++ b/python/x402/schemas/payments.py @@ -14,11 +14,20 @@ class ResourceInfo(BaseX402Model): url: The URL of the resource. description: Optional human-readable description. mime_type: Optional MIME type of the resource. + service_name: Optional human-readable service name (≤ 32 chars). + tags: Optional topical tags for the service (≤ 5 entries, each ≤ 32 chars). + icon_url: Optional absolute http(s) URL to a service icon (≤ 2048 chars). + + See `specs/extensions/bazaar.md` "Service Metadata on `resource`" for + facilitator-side validation rules applied to service_name / tags / icon_url. """ url: str description: str | None = None mime_type: str | None = None + service_name: str | None = None + tags: list[str] | None = None + icon_url: str | None = None class PaymentRequirements(BaseX402Model): diff --git a/python/x402/schemas/responses.py b/python/x402/schemas/responses.py index bb5e5a7837..c176ddd5e2 100644 --- a/python/x402/schemas/responses.py +++ b/python/x402/schemas/responses.py @@ -62,6 +62,7 @@ class SettleResponse(BaseX402Model): payer: The payer's address. transaction: Transaction hash/identifier. network: Network where settlement occurred. + amount: Settled amount in atomic units. """ success: bool @@ -70,6 +71,7 @@ class SettleResponse(BaseX402Model): payer: str | None = None transaction: str network: Network + amount: str | None = None class SupportedKind(BaseX402Model): diff --git a/python/x402/tests/integrations/test_evm.py b/python/x402/tests/integrations/test_evm.py index 1fa6cc6354..70603b9ff9 100644 --- a/python/x402/tests/integrations/test_evm.py +++ b/python/x402/tests/integrations/test_evm.py @@ -18,6 +18,7 @@ from x402 import x402ClientSync, x402FacilitatorSync, x402ResourceServerSync from x402.mechanisms.evm import ( SCHEME_EXACT, + SCHEME_UPTO, TypedDataDomain, TypedDataField, ) @@ -28,6 +29,11 @@ ExactEvmServerScheme, ) from x402.mechanisms.evm.signers import EthAccountSigner, FacilitatorWeb3Signer +from x402.mechanisms.evm.upto import ( + UptoEvmClientScheme, + UptoEvmFacilitatorScheme, + UptoEvmServerScheme, +) from x402.schemas import ( PaymentPayload, PaymentRequirements, @@ -669,3 +675,161 @@ def test_facilitator_web3_signer_verify_typed_data_invalid_signer(self) -> None: signature=signature, ) assert is_valid is False + + +# ============================================================================= +# Upto Integration Tests +# ============================================================================= + + +def build_upto_payment_requirements( + pay_to: str, + amount: str, + facilitator_address: str, + network: str = "eip155:84532", +) -> PaymentRequirements: + return PaymentRequirements( + scheme=SCHEME_UPTO, + network=network, + asset=USDC_ADDRESS, + amount=amount, + pay_to=pay_to, + max_timeout_seconds=3600, + extra={ + "assetTransferMethod": "permit2", + "facilitatorAddress": facilitator_address, + }, + ) + + +class UptoEvmFacilitatorClientSync: + """Facilitator client wrapper for upto scheme.""" + + scheme = SCHEME_UPTO + network = "eip155:84532" + x402_version = 2 + + def __init__(self, facilitator: x402FacilitatorSync): + self._facilitator = facilitator + + def verify(self, payload: PaymentPayload, requirements: PaymentRequirements) -> VerifyResponse: + return self._facilitator.verify(payload, requirements) + + def settle(self, payload: PaymentPayload, requirements: PaymentRequirements) -> SettleResponse: + return self._facilitator.settle(payload, requirements) + + def get_supported(self) -> SupportedResponse: + return self._facilitator.get_supported() + + +class TestEvmUptoIntegrationV2: + """Integration tests for EVM Upto (V2) payment flow with REAL blockchain transactions.""" + + def setup_method(self) -> None: + client_account = Account.from_key(CLIENT_PRIVATE_KEY) + self.client_signer = EthAccountSigner(client_account) + self.facilitator_signer = FacilitatorWeb3Signer( + private_key=FACILITATOR_PRIVATE_KEY, + rpc_url=RPC_URL, + ) + + self.client_address = self.client_signer.address + self.facilitator_address = self.facilitator_signer.address + + # Register both exact and upto + self.client = x402ClientSync() + self.client.register("eip155:84532", UptoEvmClientScheme(self.client_signer)) + + self.facilitator = x402FacilitatorSync() + self.facilitator.register( + ["eip155:84532"], + UptoEvmFacilitatorScheme(self.facilitator_signer), + ) + + facilitator_client = UptoEvmFacilitatorClientSync(self.facilitator) + + self.server = x402ResourceServerSync(facilitator_client) + self.server.register("eip155:84532", UptoEvmServerScheme()) + self.server.initialize() + + def test_server_should_verify_and_settle_upto_payment(self) -> None: + """Full upto flow: client authorizes max, server settles actual amount.""" + recipient = self.facilitator_address + + accepts = [ + build_upto_payment_requirements( + recipient, + "1000", + self.facilitator_address, + ) + ] + resource = ResourceInfo( + url="https://api.example.com/llm/generate", + description="LLM text generation", + mime_type="application/json", + ) + payment_required = self.server.create_payment_required_response(accepts, resource) + + assert payment_required.x402_version == 2 + + payment_payload = self.client.create_payment_payload(payment_required) + + assert payment_payload.x402_version == 2 + assert payment_payload.accepted.scheme == SCHEME_UPTO + assert "permit2Authorization" in payment_payload.payload + assert "signature" in payment_payload.payload + + auth = payment_payload.payload["permit2Authorization"] + assert auth["from"].lower() == self.client_address.lower() + assert "facilitator" in auth["witness"] + + accepted = self.server.find_matching_requirements(accepts, payment_payload) + assert accepted is not None + + verify_response = self.server.verify_payment(payment_payload, accepted) + assert verify_response.is_valid is True + assert verify_response.payer.lower() == self.client_address.lower() + + # Settle for a partial amount (500 of 1000 authorized) + partial_requirements = build_upto_payment_requirements( + recipient, + "500", + self.facilitator_address, + ) + + settle_response = self.server.settle_payment(payment_payload, partial_requirements) + assert settle_response.success is True + assert settle_response.network == "eip155:84532" + assert settle_response.transaction != "" + assert settle_response.payer.lower() == self.client_address.lower() + + def test_facilitator_get_supported_includes_upto(self) -> None: + supported = self.facilitator.get_supported() + + upto_support = None + for kind in supported.kinds: + if kind.network == "eip155:84532" and kind.scheme == SCHEME_UPTO: + upto_support = kind + break + + assert upto_support is not None + assert upto_support.x402_version == 2 + assert upto_support.extra is not None + assert "facilitatorAddress" in upto_support.extra + + def test_client_creates_valid_upto_payload(self) -> None: + accepts = [ + build_upto_payment_requirements( + "0x1234567890123456789012345678901234567890", + "5000000", + self.facilitator_address, + ) + ] + payment_required = self.server.create_payment_required_response(accepts) + payload = self.client.create_payment_payload(payment_required) + + assert payload.x402_version == 2 + assert payload.accepted.scheme == SCHEME_UPTO + p2 = payload.payload["permit2Authorization"] + assert p2["permitted"]["amount"] == "5000000" + assert "facilitator" in p2["witness"] diff --git a/python/x402/tests/integrations/test_tvm.py b/python/x402/tests/integrations/test_tvm.py new file mode 100644 index 0000000000..7d3ab7ad58 --- /dev/null +++ b/python/x402/tests/integrations/test_tvm.py @@ -0,0 +1,708 @@ +"""TVM integration tests for x402ClientSync, x402ResourceServerSync, and x402FacilitatorSync. + +These tests perform REAL blockchain transactions on TON testnet using sync classes. + +Required environment variables: +- TVM_CLIENT_PRIVATE_KEY: TON private key used for the payer W5 wallet +- TVM_FACILITATOR_PRIVATE_KEY: TON private key used for the facilitator highload wallet +- TONCENTER_API_KEY: Toncenter API key for TON when TVM_PROVIDER is toncenter +- TONAPI_API_KEY: TonAPI API key when TVM_PROVIDER is tonapi + +For backward compatibility, if the split variables are not set the tests fall back to +`TVM_PRIVATE_KEY` for both roles. + +Optional environment variables: +- TVM_PROVIDER: TVM RPC provider, "toncenter" by default; set to "tonapi" for TonAPI +- TONCENTER_BASE_URL: custom Toncenter base URL +- TONAPI_BASE_URL: custom TonAPI base URL +- TVM_SECOND_CLIENT_PRIVATE_KEY: second funded W5 client used by the live batch-settlement test + +These must correspond to funded testnet wallets with TON and USDT. +""" + +from __future__ import annotations + +import os +import threading +import time +from concurrent.futures import ThreadPoolExecutor + +import pytest + +pytest.importorskip("pytoniq_core") + +from x402 import x402ClientSync, x402FacilitatorSync, x402ResourceServerSync +from x402.mechanisms.tvm import ( + SCHEME_EXACT, + TVM_PROVIDER_TONAPI, + TVM_PROVIDER_TONCENTER, + TVM_TESTNET, + USDT_TESTNET_MINTER, + ExactTvmPayload, + FacilitatorHighloadV3Signer, + HighloadV3Config, + WalletV5R1Config, + WalletV5R1MnemonicSigner, + create_tvm_provider_client, + parse_exact_tvm_payload, +) +from x402.mechanisms.tvm.constants import ( + ERR_EXACT_TVM_DUPLICATE_SETTLEMENT as ERR_DUPLICATE_SETTLEMENT, +) +from x402.mechanisms.tvm.constants import ( + ERR_EXACT_TVM_INVALID_AMOUNT, + ERR_EXACT_TVM_INVALID_RECIPIENT, +) +from x402.mechanisms.tvm.constants import ( + ERR_EXACT_TVM_INVALID_SEQNO as ERR_INVALID_SEQNO, +) +from x402.mechanisms.tvm.exact import ( + ExactTvmClientScheme, + ExactTvmFacilitatorScheme, + ExactTvmServerScheme, +) +from x402.mechanisms.tvm.provider import TvmProviderClient +from x402.schemas import ( + PaymentPayload, + PaymentRequirements, + ResourceConfig, + ResourceInfo, + SettleResponse, + SupportedResponse, + VerifyResponse, +) + +TVM_PRIVATE_KEY = os.environ.get("TVM_PRIVATE_KEY") +TVM_CLIENT_PRIVATE_KEY = os.environ.get("TVM_CLIENT_PRIVATE_KEY", TVM_PRIVATE_KEY) +TVM_SECOND_CLIENT_PRIVATE_KEY = os.environ.get("TVM_SECOND_CLIENT_PRIVATE_KEY") +TVM_FACILITATOR_PRIVATE_KEY = os.environ.get("TVM_FACILITATOR_PRIVATE_KEY", TVM_PRIVATE_KEY) +TONCENTER_API_KEY = os.environ.get("TONCENTER_API_KEY") +TONCENTER_BASE_URL = os.environ.get("TONCENTER_BASE_URL") +TONAPI_API_KEY = os.environ.get("TONAPI_API_KEY") +TONAPI_BASE_URL = os.environ.get("TONAPI_BASE_URL") +TVM_PROVIDER = os.environ.get("TVM_PROVIDER", TVM_PROVIDER_TONCENTER).lower() +TVM_PROVIDER_API_KEY = TONAPI_API_KEY if TVM_PROVIDER == TVM_PROVIDER_TONAPI else TONCENTER_API_KEY +TVM_PROVIDER_BASE_URL = ( + TONAPI_BASE_URL if TVM_PROVIDER == TVM_PROVIDER_TONAPI else TONCENTER_BASE_URL +) + +TEST_PAYMENT_AMOUNT = "1000" # 0.001 USDT with 6 decimals +MIN_FACILITATOR_TON_BALANCE = 1_000_000_000 +MIN_CLIENT_USDT_BALANCE = int(TEST_PAYMENT_AMOUNT) + +pytestmark = pytest.mark.skipif( + not TVM_CLIENT_PRIVATE_KEY + or not TVM_FACILITATOR_PRIVATE_KEY + or not TVM_PROVIDER_API_KEY + or TVM_PROVIDER not in {TVM_PROVIDER_TONCENTER, TVM_PROVIDER_TONAPI}, + reason=( + "TVM_CLIENT_PRIVATE_KEY (or TVM_PRIVATE_KEY), TVM_FACILITATOR_PRIVATE_KEY " + "(or TVM_PRIVATE_KEY), a supported TVM_PROVIDER, and the provider API key " + "(TONCENTER_API_KEY or TONAPI_API_KEY) are required for TVM integration tests" + ), +) + + +class TvmFacilitatorClientSync: + """Facilitator client wrapper for x402ResourceServerSync.""" + + scheme = SCHEME_EXACT + network = TVM_TESTNET + x402_version = 2 + + def __init__(self, facilitator: x402FacilitatorSync): + self._facilitator = facilitator + + def verify( + self, + payload: PaymentPayload, + requirements: PaymentRequirements, + ) -> VerifyResponse: + return self._facilitator.verify(payload, requirements) + + def settle( + self, + payload: PaymentPayload, + requirements: PaymentRequirements, + ) -> SettleResponse: + return self._facilitator.settle(payload, requirements) + + def get_supported(self) -> SupportedResponse: + return self._facilitator.get_supported() + + +def build_tvm_payment_requirements( + pay_to: str, + amount: str, + network: str = TVM_TESTNET, + asset: str = USDT_TESTNET_MINTER, +) -> PaymentRequirements: + """Build TVM payment requirements for testing.""" + return PaymentRequirements( + scheme=SCHEME_EXACT, + network=network, + asset=asset, + amount=amount, + pay_to=pay_to, + max_timeout_seconds=300, + extra={ + "decimals": 6, + "areFeesSponsored": True, + }, + ) + + +def _wait_for_jetton_balance_at_least( + provider: TvmProviderClient, + jetton_wallet: str, + expected_balance: int, + *, + timeout_seconds: float = 20.0, +) -> int: + """Wait until the configured provider reflects a target jetton balance.""" + deadline = time.monotonic() + timeout_seconds + last_balance = 0 + last_error: Exception | None = None + + while time.monotonic() < deadline: + try: + last_balance = provider.get_jetton_wallet_data(jetton_wallet).balance + if last_balance >= expected_balance: + return last_balance + except Exception as exc: # pragma: no cover - retry path for flaky RPC + last_error = exc + time.sleep(1.0) + + if last_error is not None: + raise AssertionError( + f"Timed out waiting for jetton balance update for {jetton_wallet}: {last_error}" + ) from last_error + raise AssertionError( + f"Timed out waiting for jetton balance {expected_balance}, last balance {last_balance}" + ) + + +def _configure_client_provider(config: WalletV5R1Config) -> None: + config.provider = TVM_PROVIDER + config.api_key = TVM_PROVIDER_API_KEY + config.provider_base_url = TVM_PROVIDER_BASE_URL + + +def _configure_facilitator_provider(config: HighloadV3Config) -> None: + config.provider = TVM_PROVIDER + config.api_key = TVM_PROVIDER_API_KEY + config.provider_base_url = TVM_PROVIDER_BASE_URL + + +class TestTvmIntegrationV2: + """Integration tests for TVM V2 payment flow with REAL blockchain transactions.""" + + def setup_method(self) -> None: + client_config = WalletV5R1Config.from_private_key(TVM_TESTNET, TVM_CLIENT_PRIVATE_KEY) + _configure_client_provider(client_config) + self.client_signer = WalletV5R1MnemonicSigner(client_config) + + facilitator_config = HighloadV3Config.from_private_key(TVM_FACILITATOR_PRIVATE_KEY) + _configure_facilitator_provider(facilitator_config) + self.facilitator_signer = FacilitatorHighloadV3Signer({TVM_TESTNET: facilitator_config}) + + self.provider = create_tvm_provider_client( + TVM_TESTNET, + provider=TVM_PROVIDER, + api_key=TVM_PROVIDER_API_KEY, + base_url=TVM_PROVIDER_BASE_URL, + ) + + self.client_address = self.client_signer.address + self.facilitator_address = self.facilitator_signer.get_addresses()[0] + self.client_jetton_wallet = self.provider.get_jetton_wallet( + USDT_TESTNET_MINTER, + self.client_address, + ) + self.facilitator_jetton_wallet = self.provider.get_jetton_wallet( + USDT_TESTNET_MINTER, + self.facilitator_address, + ) + + self.client = x402ClientSync().register( + TVM_TESTNET, + ExactTvmClientScheme(self.client_signer), + ) + self.facilitator = x402FacilitatorSync().register( + [TVM_TESTNET], + ExactTvmFacilitatorScheme( + self.facilitator_signer, + batch_flush_interval_seconds=0.05, + batch_flush_size=1, + ), + ) + + facilitator_client = TvmFacilitatorClientSync(self.facilitator) + self.server = x402ResourceServerSync(facilitator_client) + self.server.register(TVM_TESTNET, ExactTvmServerScheme()) + self.server.initialize() + + def teardown_method(self) -> None: + self.facilitator_signer.close() + self.provider.close() + + def _require_live_balances(self) -> None: + facilitator_state = self.provider.get_account_state(self.facilitator_address) + client_jetton_balance = self.provider.get_jetton_wallet_data( + self.client_jetton_wallet + ).balance + + if facilitator_state.balance < MIN_FACILITATOR_TON_BALANCE: + pytest.skip( + "Facilitator wallet " + f"{self.facilitator_address} needs at least {MIN_FACILITATOR_TON_BALANCE} nanotons" + ) + if client_jetton_balance < MIN_CLIENT_USDT_BALANCE: + pytest.skip( + f"Client jetton wallet {self.client_jetton_wallet} needs at least {MIN_CLIENT_USDT_BALANCE} USDT units" + ) + + def _require_client_balances(self, address: str, jetton_wallet: str) -> None: + client_jetton_balance = self.provider.get_jetton_wallet_data(jetton_wallet).balance + + if client_jetton_balance < MIN_CLIENT_USDT_BALANCE: + pytest.skip( + f"Client jetton wallet {jetton_wallet} needs at least {MIN_CLIENT_USDT_BALANCE} USDT units" + ) + + def test_server_should_successfully_verify_and_settle_tvm_payment_from_client( + self, + ) -> None: + """Test the complete TVM V2 payment flow with REAL blockchain transactions.""" + self._require_live_balances() + + recipient_balance_before = self.provider.get_jetton_wallet_data( + self.facilitator_jetton_wallet + ).balance + + accepts = [ + build_tvm_payment_requirements( + self.facilitator_address, + TEST_PAYMENT_AMOUNT, + ) + ] + resource = ResourceInfo( + url="https://api.example.com/premium", + description="Premium API Access", + mime_type="application/json", + ) + payment_required = self.server.create_payment_required_response(accepts, resource) + + assert payment_required.x402_version == 2 + + payment_payload = self.client.create_payment_payload(payment_required) + + assert payment_payload.x402_version == 2 + assert payment_payload.accepted.scheme == SCHEME_EXACT + assert payment_payload.accepted.network == TVM_TESTNET + assert "settlementBoc" in payment_payload.payload + assert "asset" in payment_payload.payload + + accepted = self.server.find_matching_requirements(accepts, payment_payload) + assert accepted is not None + + verify_response = self.server.verify_payment(payment_payload, accepted) + if not verify_response.is_valid: + print(f"❌ Verification failed: {verify_response.invalid_reason}") + print(f"Payer: {verify_response.payer}") + print(f"Client address: {self.client_address}") + + assert verify_response.is_valid is True + assert verify_response.payer == self.client_address + + settle_response = self.server.settle_payment(payment_payload, accepted) + if not settle_response.success: + print(f"❌ Settlement failed: {settle_response.error_reason}") + if settle_response.transaction: + print(f"📋 Trace message hash: {settle_response.transaction}") + + assert settle_response.success is True + assert settle_response.network == TVM_TESTNET + assert settle_response.transaction != "" + assert settle_response.payer == self.client_address + + recipient_balance_after = _wait_for_jetton_balance_at_least( + self.provider, + self.facilitator_jetton_wallet, + recipient_balance_before + int(TEST_PAYMENT_AMOUNT), + ) + assert recipient_balance_after >= recipient_balance_before + int(TEST_PAYMENT_AMOUNT) + + def test_server_should_batch_two_tvm_settlements_into_one_external_message(self, monkeypatch): + """Test live facilitator batching with two funded W5 clients. + + TVM W5 wallets require each signed settlement to use the wallet's current on-chain seqno. + Because of that, a live batch cannot use two distinct settlements from the same payer wallet: + the second relay would hit a seqno mismatch after the first one executes. This test uses two + funded payer wallets to exercise the facilitator's batch-relay path on TON testnet. + """ + self._require_live_balances() + if not TVM_SECOND_CLIENT_PRIVATE_KEY: + pytest.skip("TVM_SECOND_CLIENT_PRIVATE_KEY is required for the live TVM batch test") + + second_client_config = WalletV5R1Config.from_private_key( + TVM_TESTNET, + TVM_SECOND_CLIENT_PRIVATE_KEY, + ) + _configure_client_provider(second_client_config) + second_client_signer = WalletV5R1MnemonicSigner(second_client_config) + second_client = x402ClientSync().register( + TVM_TESTNET, + ExactTvmClientScheme(second_client_signer), + ) + second_client_address = second_client_signer.address + if second_client_address == self.client_address: + pytest.skip( + "TVM_SECOND_CLIENT_PRIVATE_KEY must point to a different funded W5 client wallet" + ) + second_client_jetton_wallet = self.provider.get_jetton_wallet( + USDT_TESTNET_MINTER, + second_client_address, + ) + self._require_client_balances(second_client_address, second_client_jetton_wallet) + + facilitator = x402FacilitatorSync().register( + [TVM_TESTNET], + ExactTvmFacilitatorScheme( + self.facilitator_signer, + batch_flush_interval_seconds=5.0, + batch_flush_size=2, + ), + ) + facilitator_client = TvmFacilitatorClientSync(facilitator) + server = x402ResourceServerSync(facilitator_client) + server.register(TVM_TESTNET, ExactTvmServerScheme()) + server.initialize() + + batch_build_calls: list[tuple[str, list[str], bool]] = [] + send_calls: list[str] = [] + original_build_batch = self.facilitator_signer.build_relay_external_boc_batch + original_send_message = self.facilitator_signer.send_external_message + + def build_batch_spy(network: str, relay_requests: list, *, for_emulation: bool = False): + batch_build_calls.append( + ( + network, + [relay_request.destination for relay_request in relay_requests], + for_emulation, + ) + ) + return original_build_batch( + network, + relay_requests, + for_emulation=for_emulation, + ) + + def send_message_spy(network: str, external_boc: bytes) -> str: + send_calls.append(network) + return original_send_message(network, external_boc) + + monkeypatch.setattr( + self.facilitator_signer, + "build_relay_external_boc_batch", + build_batch_spy, + ) + monkeypatch.setattr( + self.facilitator_signer, + "send_external_message", + send_message_spy, + ) + + recipient_balance_before = self.provider.get_jetton_wallet_data( + self.facilitator_jetton_wallet + ).balance + + accepts = [ + build_tvm_payment_requirements( + self.facilitator_address, + TEST_PAYMENT_AMOUNT, + ) + ] + payment_required = server.create_payment_required_response(accepts) + first_payload = self.client.create_payment_payload(payment_required) + second_payload = second_client.create_payment_payload(payment_required) + + first_accepted = server.find_matching_requirements(accepts, first_payload) + second_accepted = server.find_matching_requirements(accepts, second_payload) + assert first_accepted is not None + assert second_accepted is not None + + first_verify = server.verify_payment(first_payload, first_accepted) + second_verify = server.verify_payment(second_payload, second_accepted) + assert first_verify.is_valid is True + assert first_verify.payer == self.client_address + assert second_verify.is_valid is True + assert second_verify.payer == second_client_address + + start_barrier = threading.Barrier(2) + + def settle_payment( + payload: PaymentPayload, accepted: PaymentRequirements + ) -> SettleResponse: + start_barrier.wait(timeout=15.0) + return server.settle_payment(payload, accepted) + + with ThreadPoolExecutor(max_workers=2) as executor: + first_future = executor.submit(settle_payment, first_payload, first_accepted) + second_future = executor.submit(settle_payment, second_payload, second_accepted) + first_settle = first_future.result(timeout=180.0) + second_settle = second_future.result(timeout=180.0) + + assert first_settle.success is True + assert first_settle.transaction != "" + assert first_settle.payer == self.client_address + assert second_settle.success is True + assert second_settle.transaction != "" + assert second_settle.payer == second_client_address + + settlement_batch_build_calls = [ + (network, destinations) + for network, destinations, for_emulation in batch_build_calls + if for_emulation is False + ] + assert len(settlement_batch_build_calls) == 1 + assert settlement_batch_build_calls[0][0] == TVM_TESTNET + assert len(settlement_batch_build_calls[0][1]) == 2 + assert set(settlement_batch_build_calls[0][1]) == { + self.client_address, + second_client_address, + } + assert send_calls == [TVM_TESTNET] + + recipient_balance_after = _wait_for_jetton_balance_at_least( + self.provider, + self.facilitator_jetton_wallet, + recipient_balance_before + (2 * int(TEST_PAYMENT_AMOUNT)), + ) + assert recipient_balance_after >= recipient_balance_before + (2 * int(TEST_PAYMENT_AMOUNT)) + + def test_client_creates_valid_tvm_payment_payload(self) -> None: + """Test that client creates properly structured TVM payload.""" + self._require_live_balances() + + accepts = [ + build_tvm_payment_requirements( + self.facilitator_address, + "5000000", + ) + ] + payment_required = self.server.create_payment_required_response(accepts) + + payload = self.client.create_payment_payload(payment_required) + + assert payload.x402_version == 2 + assert payload.accepted.scheme == SCHEME_EXACT + assert payload.accepted.amount == "5000000" + assert payload.accepted.network == TVM_TESTNET + + tvm_payload = ExactTvmPayload.from_dict(payload.payload) + settlement = parse_exact_tvm_payload(tvm_payload.settlement_boc) + + assert tvm_payload.asset == USDT_TESTNET_MINTER + assert settlement.payer == self.client_address + assert settlement.state_init is None + assert settlement.transfer.destination == self.facilitator_address + assert settlement.transfer.response_destination is None + assert settlement.transfer.jetton_amount == 5_000_000 + assert settlement.transfer.forward_ton_amount == 0 + assert settlement.transfer.source_wallet == self.client_jetton_wallet + + def test_invalid_recipient_fails_verification(self) -> None: + """Test that mismatched recipient fails verification.""" + self._require_live_balances() + + accepts = [ + build_tvm_payment_requirements( + self.facilitator_address, + TEST_PAYMENT_AMOUNT, + ) + ] + payment_required = self.server.create_payment_required_response(accepts) + payload = self.client.create_payment_payload(payment_required) + + different_accepts = [ + build_tvm_payment_requirements( + self.client_address, + TEST_PAYMENT_AMOUNT, + ) + ] + + verify_response = self.server.verify_payment(payload, different_accepts[0]) + assert verify_response.is_valid is False + assert verify_response.invalid_reason == ERR_EXACT_TVM_INVALID_RECIPIENT + + def test_insufficient_amount_fails_verification(self) -> None: + """Test that insufficient amount fails verification.""" + self._require_live_balances() + + accepts = [ + build_tvm_payment_requirements( + self.facilitator_address, + TEST_PAYMENT_AMOUNT, + ) + ] + payment_required = self.server.create_payment_required_response(accepts) + payload = self.client.create_payment_payload(payment_required) + + higher_accepts = [ + build_tvm_payment_requirements( + self.facilitator_address, + "2000", + ) + ] + + verify_response = self.server.verify_payment(payload, higher_accepts[0]) + assert verify_response.is_valid is False + assert verify_response.invalid_reason == ERR_EXACT_TVM_INVALID_AMOUNT + + def test_duplicate_settlement_fails_on_second_attempt(self) -> None: + """Test that settling the same payload twice is rejected as duplicate.""" + self._require_live_balances() + + accepts = [ + build_tvm_payment_requirements( + self.facilitator_address, + TEST_PAYMENT_AMOUNT, + ) + ] + payment_required = self.server.create_payment_required_response(accepts) + payload = self.client.create_payment_payload(payment_required) + accepted = self.server.find_matching_requirements(accepts, payload) + assert accepted is not None + + first_settle = self.server.settle_payment(payload, accepted) + assert first_settle.success is True + + second_settle = self.server.settle_payment(payload, accepted) + assert second_settle.success is False + assert second_settle.error_reason in { + ERR_DUPLICATE_SETTLEMENT, + ERR_INVALID_SEQNO, + } + + def test_facilitator_get_supported(self) -> None: + """Test that facilitator returns supported kinds.""" + supported = self.facilitator.get_supported() + + tvm_support = None + for kind in supported.kinds: + if kind.network == TVM_TESTNET and kind.scheme == SCHEME_EXACT: + tvm_support = kind + break + + assert tvm_support is not None + assert tvm_support.x402_version == 2 + assert tvm_support.extra is not None + assert tvm_support.extra.get("areFeesSponsored") is True + + +class TestTvmPriceParsing: + """Tests for TVM server price parsing via resource-server integration.""" + + def setup_method(self) -> None: + facilitator_config = HighloadV3Config.from_private_key(TVM_FACILITATOR_PRIVATE_KEY) + _configure_facilitator_provider(facilitator_config) + self.facilitator_signer = FacilitatorHighloadV3Signer({TVM_TESTNET: facilitator_config}) + self.facilitator_address = self.facilitator_signer.get_addresses()[0] + + self.facilitator = x402FacilitatorSync().register( + [TVM_TESTNET], + ExactTvmFacilitatorScheme(self.facilitator_signer), + ) + + facilitator_client = TvmFacilitatorClientSync(self.facilitator) + self.server = x402ResourceServerSync(facilitator_client) + self.tvm_server = ExactTvmServerScheme() + self.server.register(TVM_TESTNET, self.tvm_server) + self.server.initialize() + + def teardown_method(self) -> None: + self.facilitator_signer.close() + + def test_parse_money_formats(self) -> None: + test_cases = [ + ("$1.00", "1000000"), + ("1.50", "1500000"), + (2.5, "2500000"), + ("$0.001", "1000"), + ] + + for input_price, expected_amount in test_cases: + config = ResourceConfig( + scheme=SCHEME_EXACT, + pay_to=self.facilitator_address, + price=input_price, + network=TVM_TESTNET, + ) + requirements = self.server.build_payment_requirements(config) + + assert len(requirements) == 1 + assert requirements[0].amount == expected_amount + assert requirements[0].asset == USDT_TESTNET_MINTER + assert requirements[0].extra.get("areFeesSponsored") is True + + def test_asset_amount_passthrough(self) -> None: + from x402.schemas import AssetAmount + + custom_asset = AssetAmount( + amount="5000000", + asset="0:" + "a" * 64, + extra={"foo": "bar"}, + ) + + config = ResourceConfig( + scheme=SCHEME_EXACT, + pay_to=self.facilitator_address, + price=custom_asset, + network=TVM_TESTNET, + ) + requirements = self.server.build_payment_requirements(config) + + assert len(requirements) == 1 + assert requirements[0].amount == "5000000" + assert requirements[0].asset == "0:" + "a" * 64 + assert requirements[0].extra == { + "foo": "bar", + "areFeesSponsored": True, + } + + def test_custom_money_parser(self) -> None: + from x402.schemas import AssetAmount + + def large_amount_parser(amount: float, network: str): + if amount > 100: + return AssetAmount( + amount=str(int(amount * 1_000_000_000)), + asset="0:" + "b" * 64, + extra={"token": "LARGE", "tier": "large"}, + ) + return None + + self.tvm_server.register_money_parser(large_amount_parser) + + large_config = ResourceConfig( + scheme=SCHEME_EXACT, + pay_to=self.facilitator_address, + price=150, + network=TVM_TESTNET, + ) + large_req = self.server.build_payment_requirements(large_config) + + assert large_req[0].asset == "0:" + "b" * 64 + assert large_req[0].extra.get("token") == "LARGE" + assert large_req[0].extra.get("tier") == "large" + + small_config = ResourceConfig( + scheme=SCHEME_EXACT, + pay_to=self.facilitator_address, + price=50, + network=TVM_TESTNET, + ) + small_req = self.server.build_payment_requirements(small_config) + + assert small_req[0].asset == USDT_TESTNET_MINTER diff --git a/python/x402/tests/unit/extensions/bazaar/test_facilitator.py b/python/x402/tests/unit/extensions/bazaar/test_facilitator.py index af79e1fa46..09111dcb47 100644 --- a/python/x402/tests/unit/extensions/bazaar/test_facilitator.py +++ b/python/x402/tests/unit/extensions/bazaar/test_facilitator.py @@ -10,7 +10,18 @@ validate_and_extract, validate_discovery_extension, ) -from x402.extensions.bazaar.facilitator import _is_valid_route_template +from x402.extensions.bazaar.facilitator import ( + _is_valid_icon_url, + _is_valid_route_template, + _is_valid_service_name, + _sanitize_resource_service_metadata, + _sanitize_tags, +) +from x402.extensions.bazaar.resource_service import ( + DeclareMcpDiscoveryConfig, + declare_mcp_discovery_extension, +) +from x402.extensions.bazaar.types import McpDiscoveryInfo class TestIsValidRouteTemplate: @@ -177,6 +188,32 @@ def test_extract_no_extensions(self) -> None: result = extract_discovery_info(payload, requirements) assert result is None + def test_extract_v2_mcp_extension_with_empty_method(self) -> None: + """MCP discovery should not depend on HTTP method being present.""" + payload = { + "x402Version": 2, + "resource": {"url": "https://api.example.com/mcp"}, + "extensions": { + BAZAAR.key: { + "info": { + "input": { + "type": "mcp", + "method": "", + "toolName": "search_tool", + "inputSchema": {"type": "object"}, + }, + }, + "schema": {}, + } + }, + "accepted": {}, + } + + result = extract_discovery_info(payload, {}, validate=False) + + assert result is not None + assert result.resource_url == "https://api.example.com/mcp" + def test_strip_query_params_from_v2_resource_url(self) -> None: """Test that query params are stripped from v2 resourceUrl.""" ext = declare_discovery_extension( @@ -382,7 +419,8 @@ def test_route_template_used_for_canonical_url(self) -> None: declaration = ext[BAZAAR.key] if hasattr(declaration, "model_dump"): declaration = declaration.model_dump(by_alias=True) - # Inject routeTemplate as if the server extension enriched it + # Inject method/routeTemplate/pathParams as the server extension would at request time + declaration["info"]["input"]["method"] = "GET" declaration["routeTemplate"] = "/users/:userId" declaration["info"]["input"]["pathParams"] = {"userId": "123"} @@ -411,6 +449,7 @@ def test_static_route_uses_concrete_url(self) -> None: declaration = ext[BAZAAR.key] if hasattr(declaration, "model_dump"): declaration = declaration.model_dump(by_alias=True) + declaration["info"]["input"]["method"] = "GET" payload = { "x402Version": 2, @@ -427,3 +466,354 @@ def test_static_route_uses_concrete_url(self) -> None: assert discovered is not None assert discovered.resource_url == "http://example.com/search" assert discovered.route_template is None + + +class TestExtractDiscoveryInfoMCP: + """Tests for MCP resource extraction via extract_discovery_info.""" + + def test_extract_v2_mcp_extension_populates_tool_name(self) -> None: + """MCP extensions should populate tool_name, not method.""" + ext = declare_mcp_discovery_extension( + DeclareMcpDiscoveryConfig( + tool_name="search_tool", + input_schema={"type": "object", "properties": {"query": {"type": "string"}}}, + ) + ) + + payload = { + "x402Version": 2, + "resource": {"url": "https://api.example.com/mcp"}, + "extensions": {BAZAAR.key: ext[BAZAAR.key]}, + "accepted": {}, + } + + result = extract_discovery_info(payload, {}, validate=False) + + assert result is not None + assert result.tool_name == "search_tool" + assert result.method == "" + assert result.resource_url == "https://api.example.com/mcp" + assert isinstance(result.discovery_info, McpDiscoveryInfo) + + def test_extract_v2_mcp_extension_with_empty_method_field(self) -> None: + """MCP payloads with an explicit empty method field should still extract correctly.""" + payload = { + "x402Version": 2, + "resource": {"url": "https://api.example.com/mcp"}, + "extensions": { + BAZAAR.key: { + "info": { + "input": { + "type": "mcp", + "method": "", + "toolName": "search_tool", + "inputSchema": {"type": "object"}, + }, + }, + "schema": {}, + } + }, + "accepted": {}, + } + + result = extract_discovery_info(payload, {}, validate=False) + + assert result is not None + assert result.tool_name == "search_tool" + assert result.method == "" + + def test_extract_v2_mcp_does_not_return_unknown_method(self) -> None: + """MCP resources must never surface method='UNKNOWN' — only empty string.""" + ext = declare_mcp_discovery_extension( + DeclareMcpDiscoveryConfig( + tool_name="my_tool", + input_schema={"type": "object"}, + ) + ) + + payload = { + "x402Version": 2, + "resource": {"url": "https://api.example.com/mcp"}, + "extensions": {BAZAAR.key: ext[BAZAAR.key]}, + "accepted": {}, + } + + result = extract_discovery_info(payload, {}, validate=False) + + assert result is not None + assert result.method != "UNKNOWN" + assert result.method == "" + + def test_http_resource_with_no_method_returns_none(self) -> None: + """HTTP resources with no method set must not silently produce a result.""" + payload = { + "x402Version": 2, + "resource": {"url": "https://api.example.com/data"}, + "extensions": { + BAZAAR.key: { + "info": { + "input": { + "type": "http", + # method intentionally absent + "queryParams": {"q": "test"}, + }, + }, + "schema": {}, + } + }, + "accepted": {}, + } + + result = extract_discovery_info(payload, {}, validate=False) + + assert result is None + + def test_http_resource_with_empty_method_string_returns_none(self) -> None: + """HTTP resources with an explicit empty method string must not silently produce a result.""" + payload = { + "x402Version": 2, + "resource": {"url": "https://api.example.com/data"}, + "extensions": { + BAZAAR.key: { + "info": { + "input": { + "type": "http", + "method": "", + }, + }, + "schema": {}, + } + }, + "accepted": {}, + } + + result = extract_discovery_info(payload, {}, validate=False) + + assert result is None + + +class TestIsValidServiceName: + """Direct unit tests for the _is_valid_service_name helper.""" + + def test_accepts_strings_up_to_32_chars(self) -> None: + assert _is_valid_service_name("Example Weather") is True + assert _is_valid_service_name("a") is True + assert _is_valid_service_name("a" * 32) is True + + def test_rejects_empty_none_and_over_cap(self) -> None: + assert _is_valid_service_name(None) is False + assert _is_valid_service_name("") is False + assert _is_valid_service_name("a" * 33) is False + + def test_rejects_non_string(self) -> None: + assert _is_valid_service_name(42) is False + assert _is_valid_service_name(["x"]) is False + + def test_rejects_non_ascii_characters(self) -> None: + # Multi-byte chars in UTF-8 — would otherwise diverge across SDKs + # (UTF-16 code units in TS, code points here, bytes in Go). + assert _is_valid_service_name("Café Service") is False + assert _is_valid_service_name("東京 Weather") is False + assert _is_valid_service_name("🚀 Service") is False + + def test_rejects_ascii_control_characters(self) -> None: + assert _is_valid_service_name("Service\x00") is False + assert _is_valid_service_name("Line\nBreak") is False + assert _is_valid_service_name("Tab\there") is False + + def test_accepts_printable_ascii_with_spaces_and_punctuation(self) -> None: + assert _is_valid_service_name("Example Weather") is True + assert _is_valid_service_name("AT&T") is True + assert _is_valid_service_name("Coinbase, Inc.") is True + assert _is_valid_service_name("Service v2.0!") is True + + +class TestSanitizeTags: + """Direct unit tests for the _sanitize_tags helper.""" + + def test_returns_none_for_non_lists(self) -> None: + assert _sanitize_tags(None) is None + assert _sanitize_tags("weather") is None + assert _sanitize_tags({"tag": "weather"}) is None + + def test_drops_invalid_entries(self) -> None: + result = _sanitize_tags(["weather", "", "a" * 33, 42, None, "forecast"]) + assert result == ["weather", "forecast"] + + def test_truncates_to_5_entries(self) -> None: + result = _sanitize_tags(["a", "b", "c", "d", "e", "f", "g"]) + assert result == ["a", "b", "c", "d", "e"] + + def test_returns_none_when_nothing_survives(self) -> None: + assert _sanitize_tags(["", "a" * 33, 7]) is None + assert _sanitize_tags([]) is None + + def test_drops_non_ascii_tags_but_keeps_ascii_siblings(self) -> None: + result = _sanitize_tags(["weather", "café", "東京", "🚀", "forecast"]) + assert result == ["weather", "forecast"] + + def test_dedupes_case_insensitively_keeping_first_occurrence(self) -> None: + result = _sanitize_tags(["Weather", "weather", "WEATHER", "forecast"]) + assert result == ["Weather", "forecast"] + + +class TestIsValidIconUrl: + """Direct unit tests for the _is_valid_icon_url helper.""" + + def test_accepts_plain_http_and_https_urls(self) -> None: + assert _is_valid_icon_url("https://api.example.com/icon.png") is True + assert _is_valid_icon_url("http://api.example.com/icon") is True + + def test_rejects_empty_none_and_over_cap(self) -> None: + assert _is_valid_icon_url(None) is False + assert _is_valid_icon_url("") is False + assert _is_valid_icon_url("https://example.com/" + "a" * 2048) is False + + def test_rejects_non_http_schemes(self) -> None: + assert _is_valid_icon_url("data:image/png;base64,iVBOR") is False + assert _is_valid_icon_url("file:///etc/passwd") is False + assert _is_valid_icon_url("javascript:alert(1)") is False + assert _is_valid_icon_url("ftp://example.com/icon.png") is False + + def test_rejects_userinfo(self) -> None: + assert _is_valid_icon_url("https://user@example.com/icon.png") is False + assert _is_valid_icon_url("https://user:pass@example.com/icon.png") is False + + def test_rejects_ip_literals(self) -> None: + assert _is_valid_icon_url("http://10.0.0.1/icon.png") is False + assert _is_valid_icon_url("http://127.0.0.1/icon.png") is False + assert _is_valid_icon_url("http://[::1]/icon.png") is False + assert _is_valid_icon_url("http://[2001:db8::1]/icon.png") is False + + def test_rejects_decimal_and_short_form_ip_hosts(self) -> None: + # 2130706433 == 127.0.0.1; 0 expands to 0.0.0.0 on Linux. + assert _is_valid_icon_url("http://2130706433/icon.png") is False + assert _is_valid_icon_url("http://0/icon.png") is False + assert _is_valid_icon_url("http://3232235521/icon.png") is False + + def test_rejects_hex_encoded_ip_hosts(self) -> None: + # 0x7f000001 == 127.0.0.1. + assert _is_valid_icon_url("http://0x7f000001/icon.png") is False + assert _is_valid_icon_url("http://0X7F000001/icon.png") is False + + def test_rejects_localhost(self) -> None: + assert _is_valid_icon_url("http://localhost/icon.png") is False + assert _is_valid_icon_url("http://LOCALHOST/icon.png") is False + + def test_rejects_loopback_aliases(self) -> None: + assert _is_valid_icon_url("http://localhost.localdomain/icon.png") is False + assert _is_valid_icon_url("http://ip6-localhost/icon.png") is False + assert _is_valid_icon_url("http://ip6-loopback/icon.png") is False + + def test_rejects_idn_full_width_localhost_confusables(self) -> None: + # Full-width Latin "localhost" normalizes to "localhost" via UTS #46. + assert _is_valid_icon_url("http://localhost/icon.png") is False + + def test_rejects_control_characters(self) -> None: + assert _is_valid_icon_url("https://example.com/\x00icon.png") is False + assert _is_valid_icon_url("https://example.com/icon\n.png") is False + assert _is_valid_icon_url("https://example.com/icon\x7f.png") is False + + def test_rejects_relative_paths(self) -> None: + assert _is_valid_icon_url("/icon.png") is False + assert _is_valid_icon_url("icon.png") is False + + +class TestSanitizeResourceServiceMetadata: + """Direct unit tests for the _sanitize_resource_service_metadata helper.""" + + def test_preserves_all_valid_fields(self) -> None: + out = _sanitize_resource_service_metadata( + { + "url": "https://api.example.com/x", + "serviceName": "Example Weather", + "tags": ["weather", "forecast"], + "iconUrl": "https://api.example.com/icon.png", + } + ) + assert out.service_name == "Example Weather" + assert out.tags == ["weather", "forecast"] + assert out.icon_url == "https://api.example.com/icon.png" + + def test_soft_drops_only_invalid_fields(self) -> None: + out = _sanitize_resource_service_metadata( + { + "serviceName": "a" * 33, + "tags": ["weather", "forecast"], + "iconUrl": "data:image/png;base64,iVBOR", + } + ) + assert out.service_name is None + assert out.tags == ["weather", "forecast"] + assert out.icon_url is None + + def test_accepts_snake_case_keys(self) -> None: + out = _sanitize_resource_service_metadata( + { + "service_name": "Example", + "icon_url": "https://api.example.com/icon.png", + } + ) + assert out.service_name == "Example" + assert out.icon_url == "https://api.example.com/icon.png" + + def test_returns_empty_for_missing_or_non_dict(self) -> None: + empty = _sanitize_resource_service_metadata(None) + assert empty.service_name is None + assert empty.tags is None + assert empty.icon_url is None + + +class TestExtractDiscoveryInfoServiceMetadata: + """End-to-end tests that service metadata round-trips through extraction.""" + + def _build_payload(self, resource: dict) -> dict: + declared = declare_discovery_extension( + input={"city": "NYC"}, + input_schema={"properties": {"city": {"type": "string"}}}, + ) + ext = declared[BAZAAR.key] + if hasattr(ext, "model_dump"): + ext = ext.model_dump(by_alias=True) + ext["info"]["input"]["method"] = "GET" + return { + "x402Version": 2, + "scheme": "exact", + "network": "eip155:8453", + "payload": {}, + "accepted": {}, + "resource": resource, + "extensions": {BAZAAR.key: ext}, + } + + def test_surfaces_sanitized_metadata(self) -> None: + payload = self._build_payload( + { + "url": "https://api.example.com/weather", + "description": "Weather API", + "mimeType": "application/json", + "serviceName": "Example Weather", + "tags": ["weather", "forecast"], + "iconUrl": "https://api.example.com/icon.png", + } + ) + discovered = extract_discovery_info(payload, {}, validate=False) + assert discovered is not None + assert discovered.service_name == "Example Weather" + assert discovered.tags == ["weather", "forecast"] + assert discovered.icon_url == "https://api.example.com/icon.png" + + def test_soft_drops_invalid_fields_independently(self) -> None: + payload = self._build_payload( + { + "url": "https://api.example.com/weather", + "serviceName": "a" * 33, + "tags": ["weather", "", "forecast"], + "iconUrl": "http://localhost/icon.png", + } + ) + discovered = extract_discovery_info(payload, {}, validate=False) + assert discovered is not None + assert discovered.service_name is None + assert discovered.tags == ["weather", "forecast"] + assert discovered.icon_url is None diff --git a/python/x402/tests/unit/extensions/bazaar/test_facilitator_client.py b/python/x402/tests/unit/extensions/bazaar/test_facilitator_client.py new file mode 100644 index 0000000000..a4d35328b1 --- /dev/null +++ b/python/x402/tests/unit/extensions/bazaar/test_facilitator_client.py @@ -0,0 +1,520 @@ +"""Unit tests for the Bazaar facilitator client (with_bazaar, list_resources, search).""" + +from __future__ import annotations + +import json +from unittest.mock import MagicMock + +import pytest + +from x402.extensions.bazaar import ( + BazaarClientExtension, + BazaarExtendedClient, + BazaarExtension, + DiscoveryResourcesResponse, + ListDiscoveryResourcesParams, + Pagination, + SearchDiscoveryResourcesParams, + SearchDiscoveryResourcesResponse, + with_bazaar, +) +from x402.extensions.bazaar.facilitator_client import ( + _parse_list_response, + _parse_search_response, +) + +# --------------------------------------------------------------------------- +# Helpers +# --------------------------------------------------------------------------- + + +def _make_client(url: str = "https://facilitator.example.com") -> MagicMock: + """Create a minimal mock HTTPFacilitatorClient.""" + client = MagicMock() + client.url = url + client._auth_provider = None + return client + + +def _make_http_response(status_code: int = 200, json_data: dict | None = None) -> MagicMock: + """Create a mock HTTP response.""" + response = MagicMock() + response.status_code = status_code + response.text = json.dumps(json_data or {}) + response.json.return_value = json_data or {} + return response + + +LIST_RESPONSE_FIXTURE = { + "x402Version": 2, + "items": [ + { + "resource": "https://api.example.com/weather", + "type": "http", + "x402Version": 2, + "accepts": [{"scheme": "exact", "network": "eip155:8453"}], + "lastUpdated": "2026-01-01T00:00:00Z", + "extensions": {"bazaar": {"category": "weather"}}, + } + ], + "pagination": {"limit": 20, "offset": 0, "total": 1}, +} + +SEARCH_RESPONSE_FIXTURE = { + "x402Version": 2, + "resources": [ + { + "resource": "https://api.example.com/weather", + "type": "http", + "x402Version": 2, + "accepts": [], + "lastUpdated": "2026-01-01T00:00:00Z", + } + ], + "partialResults": False, + "pagination": {"limit": 10, "cursor": None}, +} + + +# --------------------------------------------------------------------------- +# _parse_list_response +# --------------------------------------------------------------------------- + + +class TestParseListResponse: + def test_parses_items_and_pagination(self) -> None: + result = _parse_list_response(LIST_RESPONSE_FIXTURE) + + assert isinstance(result, DiscoveryResourcesResponse) + assert result.x402_version == 2 + assert len(result.items) == 1 + assert result.items[0].resource == "https://api.example.com/weather" + assert result.items[0].type == "http" + assert result.items[0].x402_version == 2 + assert result.items[0].last_updated == "2026-01-01T00:00:00Z" + assert result.items[0].extensions == {"bazaar": {"category": "weather"}} + assert isinstance(result.pagination, Pagination) + assert result.pagination.limit == 20 + assert result.pagination.offset == 0 + assert result.pagination.total == 1 + + def test_handles_empty_items(self) -> None: + data = { + "x402Version": 2, + "items": [], + "pagination": {"limit": 20, "offset": 0, "total": 0}, + } + result = _parse_list_response(data) + + assert result.items == [] + assert result.pagination.total == 0 + + def test_handles_missing_optional_fields(self) -> None: + data = { + "x402Version": 1, + "items": [{"resource": "https://api.example.com/data", "type": "mcp"}], + "pagination": {"limit": 10, "offset": 0, "total": 1}, + } + result = _parse_list_response(data) + + assert result.items[0].resource == "https://api.example.com/data" + assert result.items[0].extensions is None + assert result.items[0].accepts is None + assert result.items[0].x402_version == 0 + + def test_handles_missing_pagination(self) -> None: + data = {"x402Version": 2, "items": []} + result = _parse_list_response(data) + + assert result.pagination.limit == 0 + assert result.pagination.offset == 0 + assert result.pagination.total == 0 + + +# --------------------------------------------------------------------------- +# _parse_search_response +# --------------------------------------------------------------------------- + + +class TestParseSearchResponse: + def test_parses_items_and_search_meta(self) -> None: + result = _parse_search_response(SEARCH_RESPONSE_FIXTURE) + + assert isinstance(result, SearchDiscoveryResourcesResponse) + assert result.x402_version == 2 + assert len(result.resources) == 1 + assert result.resources[0].resource == "https://api.example.com/weather" + assert result.partial_results is False + assert result.pagination is not None + assert result.pagination.limit == 10 + assert result.pagination.cursor is None + + def test_parses_pagination_object_with_cursor(self) -> None: + data = { + "x402Version": 2, + "resources": [], + "pagination": {"limit": 10, "cursor": "eyJwYWdlIjoyfQ=="}, + } + result = _parse_search_response(data) + + assert result.pagination is not None + assert result.pagination.limit == 10 + assert result.pagination.cursor == "eyJwYWdlIjoyfQ==" + + def test_handles_null_cursor_in_pagination(self) -> None: + data = { + "x402Version": 2, + "resources": [], + "pagination": {"limit": 5, "cursor": None}, + } + result = _parse_search_response(data) + + assert result.pagination is not None + assert result.pagination.cursor is None + + def test_handles_missing_pagination(self) -> None: + data = {"x402Version": 2, "resources": []} + result = _parse_search_response(data) + + assert result.pagination is None + + +# --------------------------------------------------------------------------- +# with_bazaar +# --------------------------------------------------------------------------- + + +class TestWithBazaar: + def test_returns_extended_client(self) -> None: + client = _make_client() + extended = with_bazaar(client) + + assert isinstance(extended, BazaarExtendedClient) + + def test_extensions_bazaar_is_present(self) -> None: + client = _make_client() + extended = with_bazaar(client) + + assert isinstance(extended.extensions, BazaarClientExtension) + assert isinstance(extended.extensions.bazaar, BazaarExtension) + + def test_delegates_attribute_access_to_wrapped_client(self) -> None: + client = _make_client() + client.url = "https://example.com/facilitator" + extended = with_bazaar(client) + + assert extended.url == "https://example.com/facilitator" + + def test_context_manager_delegates_to_client(self) -> None: + client = _make_client() + client.__enter__ = MagicMock(return_value=client) + client.__exit__ = MagicMock(return_value=None) + extended = with_bazaar(client) + + with extended as ctx: + assert ctx is extended + + client.__enter__.assert_called_once() + client.__exit__.assert_called_once() + + +# --------------------------------------------------------------------------- +# BazaarExtension.list_resources +# --------------------------------------------------------------------------- + + +class TestListResources: + def _make_extended(self, response: MagicMock) -> BazaarExtendedClient: + client = _make_client() + http_client = MagicMock() + http_client.get.return_value = response + client._get_client.return_value = http_client + return with_bazaar(client) + + def test_calls_correct_endpoint(self) -> None: + response = _make_http_response(200, LIST_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.list_resources() + + http_client = extended._client._get_client() + call_args = http_client.get.call_args + assert call_args[0][0] == "https://facilitator.example.com/discovery/resources" + + def test_passes_type_param(self) -> None: + response = _make_http_response(200, LIST_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.list_resources(ListDiscoveryResourcesParams(type="http")) + + http_client = extended._client._get_client() + call_kwargs = http_client.get.call_args[1] + assert call_kwargs["params"]["type"] == "http" + + def test_passes_limit_and_offset(self) -> None: + response = _make_http_response(200, LIST_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.list_resources(ListDiscoveryResourcesParams(limit=10, offset=5)) + + http_client = extended._client._get_client() + call_kwargs = http_client.get.call_args[1] + assert call_kwargs["params"]["limit"] == "10" + assert call_kwargs["params"]["offset"] == "5" + + def test_passes_additional_filters(self) -> None: + response = _make_http_response(200, LIST_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.list_resources( + ListDiscoveryResourcesParams( + pay_to="0x1234567890123456789012345678901234567890", + scheme="exact", + network="eip155:8453", + extensions="bazaar", + ) + ) + + http_client = extended._client._get_client() + call_kwargs = http_client.get.call_args[1] + assert call_kwargs["params"]["payTo"] == "0x1234567890123456789012345678901234567890" + assert call_kwargs["params"]["scheme"] == "exact" + assert call_kwargs["params"]["network"] == "eip155:8453" + assert call_kwargs["params"]["extensions"] == "bazaar" + + def test_omits_params_when_none(self) -> None: + response = _make_http_response(200, LIST_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.list_resources() + + http_client = extended._client._get_client() + call_kwargs = http_client.get.call_args[1] + assert call_kwargs.get("params") is None + + def test_returns_parsed_response(self) -> None: + response = _make_http_response(200, LIST_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + result = extended.extensions.bazaar.list_resources() + + assert isinstance(result, DiscoveryResourcesResponse) + assert len(result.items) == 1 + assert result.items[0].resource == "https://api.example.com/weather" + assert result.pagination.total == 1 + + def test_raises_on_error_response(self) -> None: + response = _make_http_response(500, {}) + response.text = "internal server error" + extended = self._make_extended(response) + + with pytest.raises(ValueError, match="listDiscoveryResources failed \\(500\\)"): + extended.extensions.bazaar.list_resources() + + def test_raises_on_404(self) -> None: + response = _make_http_response(404, {}) + response.text = "not found" + extended = self._make_extended(response) + + with pytest.raises(ValueError, match="listDiscoveryResources failed \\(404\\)"): + extended.extensions.bazaar.list_resources() + + def test_sends_bazaar_auth_headers_when_provider_present(self) -> None: + response = _make_http_response(200, LIST_RESPONSE_FIXTURE) + client = _make_client() + http_client = MagicMock() + http_client.get.return_value = response + client._get_client.return_value = http_client + + auth_provider = MagicMock() + auth_headers = MagicMock() + auth_headers.bazaar = {"Authorization": "Bearer test-token"} + auth_provider.get_auth_headers.return_value = auth_headers + client._auth_provider = auth_provider + + extended = with_bazaar(client) + extended.extensions.bazaar.list_resources() + + call_kwargs = http_client.get.call_args[1] + assert call_kwargs["headers"]["Authorization"] == "Bearer test-token" + + def test_no_auth_headers_when_no_provider(self) -> None: + response = _make_http_response(200, LIST_RESPONSE_FIXTURE) + client = _make_client() + http_client = MagicMock() + http_client.get.return_value = response + client._get_client.return_value = http_client + client._auth_provider = None + + extended = with_bazaar(client) + extended.extensions.bazaar.list_resources() + + call_kwargs = http_client.get.call_args[1] + assert "Authorization" not in call_kwargs["headers"] + + +# --------------------------------------------------------------------------- +# BazaarExtension.search +# --------------------------------------------------------------------------- + + +class TestSearch: + def _make_extended(self, response: MagicMock) -> BazaarExtendedClient: + client = _make_client() + http_client = MagicMock() + http_client.get.return_value = response + client._get_client.return_value = http_client + return with_bazaar(client) + + def test_calls_correct_search_endpoint(self) -> None: + response = _make_http_response(200, SEARCH_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.search(SearchDiscoveryResourcesParams(query="weather")) + + http_client = extended._client._get_client() + call_args = http_client.get.call_args + assert "/discovery/search" in call_args[0][0] + + def test_passes_query_param(self) -> None: + response = _make_http_response(200, SEARCH_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.search(SearchDiscoveryResourcesParams(query="weather APIs")) + + http_client = extended._client._get_client() + call_kwargs = http_client.get.call_args[1] + assert call_kwargs["params"]["query"] == "weather APIs" + + def test_passes_optional_type_param(self) -> None: + response = _make_http_response(200, SEARCH_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.search( + SearchDiscoveryResourcesParams(query="weather", type="http") + ) + + http_client = extended._client._get_client() + call_kwargs = http_client.get.call_args[1] + assert call_kwargs["params"]["type"] == "http" + + def test_passes_limit_and_cursor(self) -> None: + response = _make_http_response(200, SEARCH_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.search( + SearchDiscoveryResourcesParams(query="test", limit=5, cursor="abc123") + ) + + http_client = extended._client._get_client() + call_kwargs = http_client.get.call_args[1] + assert call_kwargs["params"]["limit"] == "5" + assert call_kwargs["params"]["cursor"] == "abc123" + + def test_passes_additional_filters(self) -> None: + response = _make_http_response(200, SEARCH_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.search( + SearchDiscoveryResourcesParams( + query="test", + pay_to="0x1234567890123456789012345678901234567890", + scheme="exact", + network="eip155:8453", + extensions="bazaar", + ) + ) + + http_client = extended._client._get_client() + call_kwargs = http_client.get.call_args[1] + assert call_kwargs["params"]["payTo"] == "0x1234567890123456789012345678901234567890" + assert call_kwargs["params"]["scheme"] == "exact" + assert call_kwargs["params"]["network"] == "eip155:8453" + assert call_kwargs["params"]["extensions"] == "bazaar" + + def test_returns_parsed_search_response(self) -> None: + response = _make_http_response(200, SEARCH_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + result = extended.extensions.bazaar.search( + SearchDiscoveryResourcesParams(query="weather APIs") + ) + + assert isinstance(result, SearchDiscoveryResourcesResponse) + assert len(result.resources) == 1 + assert result.resources[0].resource == "https://api.example.com/weather" + assert result.pagination is not None + assert result.pagination.limit == 10 + assert result.pagination.cursor is None + + def test_raises_on_empty_query(self) -> None: + client = _make_client() + extended = with_bazaar(client) + + with pytest.raises(ValueError, match="search query is required"): + extended.extensions.bazaar.search(SearchDiscoveryResourcesParams(query="")) + + def test_raises_on_error_response(self) -> None: + response = _make_http_response(500, {}) + response.text = "search failed" + extended = self._make_extended(response) + + with pytest.raises(ValueError, match="searchDiscoveryResources failed \\(500\\)"): + extended.extensions.bazaar.search(SearchDiscoveryResourcesParams(query="test")) + + def test_sends_bazaar_auth_headers(self) -> None: + response = _make_http_response(200, SEARCH_RESPONSE_FIXTURE) + client = _make_client() + http_client = MagicMock() + http_client.get.return_value = response + client._get_client.return_value = http_client + + auth_provider = MagicMock() + auth_headers = MagicMock() + auth_headers.bazaar = {"X-Api-Key": "secret"} + auth_provider.get_auth_headers.return_value = auth_headers + client._auth_provider = auth_provider + + extended = with_bazaar(client) + extended.extensions.bazaar.search(SearchDiscoveryResourcesParams(query="test")) + + call_kwargs = http_client.get.call_args[1] + assert call_kwargs["headers"]["X-Api-Key"] == "secret" + + def test_search_without_type_omits_type_from_params(self) -> None: + response = _make_http_response(200, SEARCH_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.search(SearchDiscoveryResourcesParams(query="weather")) + + http_client = extended._client._get_client() + call_kwargs = http_client.get.call_args[1] + assert "type" not in call_kwargs["params"] + + def test_search_without_cursor_omits_cursor(self) -> None: + response = _make_http_response(200, SEARCH_RESPONSE_FIXTURE) + extended = self._make_extended(response) + + extended.extensions.bazaar.search(SearchDiscoveryResourcesParams(query="weather")) + + http_client = extended._client._get_client() + call_kwargs = http_client.get.call_args[1] + assert "cursor" not in call_kwargs["params"] + + def test_returns_pagination_object_with_cursor(self) -> None: + cursor = "eyJwYWdlIjoyfQ==" + data = { + "x402Version": 2, + "resources": [], + "pagination": {"limit": 10, "cursor": cursor}, + } + response = _make_http_response(200, data) + extended = self._make_extended(response) + + result = extended.extensions.bazaar.search( + SearchDiscoveryResourcesParams(query="financial") + ) + + assert result.pagination is not None + assert result.pagination.limit == 10 + assert result.pagination.cursor == cursor diff --git a/python/x402/tests/unit/extensions/test_erc20_approval_gas_sponsoring.py b/python/x402/tests/unit/extensions/test_erc20_approval_gas_sponsoring.py index 82ce5eaf1a..21273d6345 100644 --- a/python/x402/tests/unit/extensions/test_erc20_approval_gas_sponsoring.py +++ b/python/x402/tests/unit/extensions/test_erc20_approval_gas_sponsoring.py @@ -11,7 +11,14 @@ extract_erc20_approval_gas_sponsoring_info, validate_erc20_approval_gas_sponsoring_info, ) -from x402.mechanisms.evm.constants import PERMIT2_ADDRESS +from x402.extensions.erc20_approval_gas_sponsoring.client import ( + sign_erc20_approval_transaction, +) +from x402.mechanisms.evm.constants import ( + DEFAULT_MAX_FEE_PER_GAS, + DEFAULT_MAX_PRIORITY_FEE_PER_GAS, + PERMIT2_ADDRESS, +) from x402.schemas import PaymentPayload, PaymentRequirements, ResourceInfo TOKEN_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" @@ -109,3 +116,56 @@ def test_invalid_address(self): def test_invalid_signed_transaction(self): info = _make_info(signed_transaction="not-hex") assert validate_erc20_approval_gas_sponsoring_info(info) is False + + +class _StubSigner: + """Minimal signer that records the transaction it was asked to sign.""" + + def __init__(self, fees: tuple[int, int] | None = None, raise_on_estimate: bool = False): + self.address = PAYER + self._fees = fees + self._raise = raise_on_estimate + self.signed_tx: dict[str, Any] | None = None + if fees is not None or raise_on_estimate: + + def estimate_fees_per_gas() -> tuple[int, int]: + if self._raise: + raise RuntimeError("rpc unavailable") + assert self._fees is not None + return self._fees + + self.estimate_fees_per_gas = estimate_fees_per_gas + + def get_transaction_count(self, address: str) -> int: + return 0 + + def sign_transaction(self, tx: dict[str, Any]) -> str: + self.signed_tx = tx + return "0x" + "ab" * 100 + + +class TestGasFeeFallback: + def test_constants_exported_with_expected_values(self): + assert DEFAULT_MAX_FEE_PER_GAS == 1_000_000_000 + assert DEFAULT_MAX_PRIORITY_FEE_PER_GAS == 100_000_000 + + def test_uses_defaults_when_signer_has_no_estimator(self): + signer = _StubSigner() + sign_erc20_approval_transaction(signer, TOKEN_ADDRESS, chain_id=84532) + assert signer.signed_tx is not None + assert signer.signed_tx["maxFeePerGas"] == DEFAULT_MAX_FEE_PER_GAS + assert signer.signed_tx["maxPriorityFeePerGas"] == DEFAULT_MAX_PRIORITY_FEE_PER_GAS + + def test_uses_defaults_when_estimator_raises(self): + signer = _StubSigner(raise_on_estimate=True) + sign_erc20_approval_transaction(signer, TOKEN_ADDRESS, chain_id=84532) + assert signer.signed_tx is not None + assert signer.signed_tx["maxFeePerGas"] == DEFAULT_MAX_FEE_PER_GAS + assert signer.signed_tx["maxPriorityFeePerGas"] == DEFAULT_MAX_PRIORITY_FEE_PER_GAS + + def test_uses_estimated_fees_when_available(self): + signer = _StubSigner(fees=(5_000_000_000, 250_000_000)) + sign_erc20_approval_transaction(signer, TOKEN_ADDRESS, chain_id=84532) + assert signer.signed_tx is not None + assert signer.signed_tx["maxFeePerGas"] == 5_000_000_000 + assert signer.signed_tx["maxPriorityFeePerGas"] == 250_000_000 diff --git a/python/x402/tests/unit/mcp/test_server_wrappers.py b/python/x402/tests/unit/mcp/test_server_wrappers.py new file mode 100644 index 0000000000..e99827b8af --- /dev/null +++ b/python/x402/tests/unit/mcp/test_server_wrappers.py @@ -0,0 +1,170 @@ +"""Regression tests for MCP server wrapper payment-required responses.""" + +from __future__ import annotations + +import pytest + +from x402.mcp.constants import MCP_PAYMENT_RESPONSE_META_KEY +from x402.mcp.server import _create_settlement_failed_result +from x402.mcp.server_async import ( + PaymentWrapperConfig, + _create_settlement_failed_result_async, +) +from x402.mcp.server_sync import _create_settlement_failed_result_sync +from x402.mcp.types import SyncPaymentWrapperConfig +from x402.schemas import PaymentRequirements, ResourceInfo + + +def make_payment_requirements() -> PaymentRequirements: + """Helper to create valid payment requirements.""" + return PaymentRequirements( + scheme="exact", + network="eip155:8453", + asset="0x0000000000000000000000000000000000000000", + amount="1000000", + pay_to="0x1234567890123456789012345678901234567890", + max_timeout_seconds=300, + ) + + +class MockAsyncResourceServer: + """Minimal async resource server for settlement failure helper tests.""" + + def __init__(self): + self.last_extensions = None + + async def create_payment_required_response( # noqa: PLR0913 + self, + accepts, + resource, + error_message, + extensions=None, + ): + self.last_extensions = extensions + return { + "x402Version": 2, + "accepts": [req.model_dump(by_alias=True) for req in accepts], + "error": error_message, + "resource": resource.model_dump(by_alias=True), + "extensions": extensions, + } + + +class MockSyncResourceServer: + """Minimal sync resource server for settlement failure helper tests.""" + + def __init__(self): + self.last_extensions = None + + def create_payment_required_response( # noqa: PLR0913 + self, + accepts, + resource, + error_message, + extensions=None, + ): + self.last_extensions = extensions + return { + "x402Version": 2, + "accepts": [req.model_dump(by_alias=True) for req in accepts], + "error": error_message, + "resource": resource.model_dump(by_alias=True), + "extensions": extensions, + } + + +@pytest.mark.asyncio +async def test_async_settlement_failure_preserves_extensions() -> None: + """Settlement failure 402 keeps extensions in async wrapper path.""" + server = MockAsyncResourceServer() + extensions = { + "bazaar": { + "info": { + "input": { + "type": "mcp", + "toolName": "get_weather", + "inputSchema": {"type": "object"}, + } + }, + "schema": {"type": "object"}, + } + } + config = PaymentWrapperConfig( + accepts=[make_payment_requirements()], + extensions=extensions, + ) + + result = await _create_settlement_failed_result_async( + server, + "get_weather", + config, + "settle exploded", + ) + + assert server.last_extensions == extensions + assert result.structured_content is not None + assert result.structured_content["extensions"] == extensions + assert result.structured_content[MCP_PAYMENT_RESPONSE_META_KEY]["success"] is False + + +def test_sync_settlement_failure_preserves_extensions() -> None: + """Settlement failure 402 keeps extensions in sync wrapper path.""" + server = MockSyncResourceServer() + extensions = { + "bazaar": { + "info": { + "input": { + "type": "mcp", + "toolName": "get_weather", + "inputSchema": {"type": "object"}, + } + }, + "schema": {"type": "object"}, + } + } + config = SyncPaymentWrapperConfig( + accepts=[make_payment_requirements()], + extensions=extensions, + ) + + result = _create_settlement_failed_result_sync( + server, + "get_weather", + config, + "settle exploded", + ) + + assert server.last_extensions == extensions + assert result.structured_content is not None + assert result.structured_content["extensions"] == extensions + assert result.structured_content[MCP_PAYMENT_RESPONSE_META_KEY]["success"] is False + + +def test_fastmcp_settlement_failure_preserves_extensions() -> None: + """Settlement failure 402 keeps extensions in FastMCP wrapper path.""" + extensions = { + "bazaar": { + "info": { + "input": { + "type": "mcp", + "toolName": "get_weather", + "inputSchema": {"type": "object"}, + } + }, + "schema": {"type": "object"}, + } + } + result = _create_settlement_failed_result( + accepts=[make_payment_requirements()], + resource=ResourceInfo( + url="mcp://tool/get_weather", + description="Tool: get_weather", + mime_type="application/json", + ), + error_message="settle exploded", + extensions=extensions, + ) + + assert result.structuredContent is not None + assert result.structuredContent["extensions"] == extensions + assert result.structuredContent[MCP_PAYMENT_RESPONSE_META_KEY]["success"] is False diff --git a/python/x402/tests/unit/mechanisms/evm/test_upto_client.py b/python/x402/tests/unit/mechanisms/evm/test_upto_client.py new file mode 100644 index 0000000000..afd4da4456 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/evm/test_upto_client.py @@ -0,0 +1,147 @@ +"""Tests for UptoEvmScheme client.""" + +try: + from eth_account import Account + from eth_account.signers.local import LocalAccount +except ImportError: + import pytest + + pytest.skip("EVM client requires eth_account", allow_module_level=True) + +from x402.mechanisms.evm.constants import X402_UPTO_PERMIT2_PROXY_ADDRESS +from x402.mechanisms.evm.signers import EthAccountSigner +from x402.mechanisms.evm.upto import UptoEvmClientScheme +from x402.schemas import PaymentRequirements + +FACILITATOR = "0x1111111111111111111111111111111111111111" + + +def make_upto_requirements( + *, + network: str = "eip155:8453", + amount: str = "500000", + facilitator_address: str = FACILITATOR, +) -> PaymentRequirements: + return PaymentRequirements( + scheme="upto", + network=network, + asset="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + amount=amount, + pay_to="0x0987654321098765432109876543210987654321", + max_timeout_seconds=3600, + extra={ + "assetTransferMethod": "permit2", + "facilitatorAddress": facilitator_address, + }, + ) + + +class TestUptoEvmSchemeConstructor: + def test_should_create_instance_with_correct_scheme(self): + account = Account.create() + signer = EthAccountSigner(account) + client = UptoEvmClientScheme(signer) + assert client.scheme == "upto" + + def test_should_store_signer_reference(self): + account = Account.create() + signer = EthAccountSigner(account) + client = UptoEvmClientScheme(signer) + assert client._signer is signer + + +class TestCreatePaymentPayload: + def test_should_create_permit2_payload_with_facilitator(self): + account = Account.create() + signer = EthAccountSigner(account) + client = UptoEvmClientScheme(signer) + + requirements = make_upto_requirements() + payload = client.create_payment_payload(requirements) + + assert isinstance(payload, dict) + assert "permit2Authorization" in payload + assert "signature" in payload + assert payload["signature"].startswith("0x") + + p2 = payload["permit2Authorization"] + assert p2["from"] == account.address + assert p2["spender"] == X402_UPTO_PERMIT2_PROXY_ADDRESS + assert "facilitator" in p2["witness"] + assert p2["witness"]["facilitator"].lower() == FACILITATOR.lower() + + def test_should_reject_missing_facilitator_address(self): + account = Account.create() + client = UptoEvmClientScheme(signer=account) + + requirements = PaymentRequirements( + scheme="upto", + network="eip155:8453", + asset="0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + amount="500000", + pay_to="0x0987654321098765432109876543210987654321", + max_timeout_seconds=3600, + extra={"assetTransferMethod": "permit2"}, + ) + + import pytest + + with pytest.raises(ValueError, match="facilitatorAddress"): + client.create_payment_payload(requirements) + + def test_permit2_payload_has_correct_witness_structure(self): + account = Account.create() + client = UptoEvmClientScheme(signer=account) + + requirements = make_upto_requirements() + payload = client.create_payment_payload(requirements) + + witness = payload["permit2Authorization"]["witness"] + assert "to" in witness + assert "facilitator" in witness + assert "validAfter" in witness + + def test_rejects_non_positive_timeout_window(self): + import pytest + + account = Account.create() + signer = EthAccountSigner(account) + client = UptoEvmClientScheme(signer) + + requirements = make_upto_requirements() + requirements.max_timeout_seconds = -1000 + + with pytest.raises(ValueError, match="Invalid time window"): + client.create_payment_payload(requirements) + + +class TestLocalAccountAutoWrap: + def test_should_auto_wrap_local_account(self): + account = Account.create() + assert isinstance(account, LocalAccount) + client = UptoEvmClientScheme(signer=account) + assert isinstance(client._signer, EthAccountSigner) + + def test_auto_wrapped_signer_has_correct_address(self): + account = Account.create() + client = UptoEvmClientScheme(signer=account) + assert client._signer.address == account.address + + def test_pre_wrapped_signer_is_not_double_wrapped(self): + account = Account.create() + signer = EthAccountSigner(account) + client = UptoEvmClientScheme(signer=signer) + assert client._signer is signer + + def test_raw_local_account_can_sign_payload(self): + account = Account.create() + client = UptoEvmClientScheme(signer=account) + requirements = make_upto_requirements() + + payload = client.create_payment_payload(requirements) + + assert isinstance(payload, dict) + assert "permit2Authorization" in payload + assert "signature" in payload + assert payload["signature"].startswith("0x") + assert len(payload["signature"]) > 2 diff --git a/python/x402/tests/unit/mechanisms/evm/test_upto_facilitator.py b/python/x402/tests/unit/mechanisms/evm/test_upto_facilitator.py new file mode 100644 index 0000000000..9b480ca02d --- /dev/null +++ b/python/x402/tests/unit/mechanisms/evm/test_upto_facilitator.py @@ -0,0 +1,642 @@ +"""Tests for the upto EVM facilitator.""" + +from __future__ import annotations + +import time +from typing import Any + +from x402.mechanisms.evm import get_network_config +from x402.mechanisms.evm.constants import ( + ERR_PERMIT2_AMOUNT_MISMATCH, + ERR_PERMIT2_DEADLINE_EXPIRED, + ERR_PERMIT2_INSUFFICIENT_BALANCE, + ERR_PERMIT2_INVALID_SPENDER, + ERR_PERMIT2_NOT_YET_VALID, + ERR_PERMIT2_RECIPIENT_MISMATCH, + ERR_PERMIT2_TOKEN_MISMATCH, + ERR_UPTO_FACILITATOR_MISMATCH, + ERR_UPTO_INVALID_SCHEME, + ERR_UPTO_NETWORK_MISMATCH, + ERR_UPTO_SETTLEMENT_EXCEEDS_AMOUNT, + ERR_UPTO_TRANSACTION_FAILED, + X402_UPTO_PERMIT2_PROXY_ADDRESS, +) +from x402.mechanisms.evm.types import ( + ExactPermit2TokenPermissions, + TransactionReceipt, + UptoPermit2Authorization, + UptoPermit2Payload, + UptoPermit2Witness, +) +from x402.mechanisms.evm.upto import UptoEvmFacilitatorScheme, UptoEvmSchemeConfig +from x402.schemas import PaymentPayload, PaymentRequirements, ResourceInfo + +NETWORK = "eip155:8453" +TOKEN_ADDRESS = get_network_config(NETWORK)["default_asset"]["address"] +PAYER = "0x1234567890123456789012345678901234567890" +RECIPIENT = "0x0987654321098765432109876543210987654321" +FACILITATOR = "0x1111111111111111111111111111111111111111" +AMOUNT = "1000" + + +def make_upto_permit2_authorization( + *, + from_address: str = PAYER, + token: str = TOKEN_ADDRESS, + amount: str = AMOUNT, + spender: str = X402_UPTO_PERMIT2_PROXY_ADDRESS, + nonce: str = "12345678901234567890", + deadline_offset: int = 3600, + valid_after_offset: int = -600, + witness_to: str = RECIPIENT, + facilitator: str = FACILITATOR, +) -> UptoPermit2Authorization: + now = int(time.time()) + return UptoPermit2Authorization( + from_address=from_address, + permitted=ExactPermit2TokenPermissions(token=token, amount=amount), + spender=spender, + nonce=nonce, + deadline=str(now + deadline_offset), + witness=UptoPermit2Witness( + to=witness_to, + facilitator=facilitator, + valid_after=str(now + valid_after_offset), + ), + ) + + +def make_upto_payload_dict( + auth: UptoPermit2Authorization | None = None, + signature: str = "0x" + "aa" * 65, +) -> dict[str, Any]: + if auth is None: + auth = make_upto_permit2_authorization() + payload = UptoPermit2Payload(permit2_authorization=auth, signature=signature) + return payload.to_dict() + + +def make_payment_payload( + *, + payload_dict: dict[str, Any] | None = None, + accepted_scheme: str = "upto", + accepted_network: str = NETWORK, + pay_to: str = RECIPIENT, + amount: str = AMOUNT, +) -> PaymentPayload: + if payload_dict is None: + payload_dict = make_upto_payload_dict() + return PaymentPayload( + x402_version=2, + resource=ResourceInfo( + url="http://example.com/upto-test", + description="Upto test resource", + mime_type="application/json", + ), + accepted=PaymentRequirements( + scheme=accepted_scheme, + network=accepted_network, + asset=TOKEN_ADDRESS, + amount=amount, + pay_to=pay_to, + max_timeout_seconds=3600, + extra={"assetTransferMethod": "permit2", "facilitatorAddress": FACILITATOR}, + ), + payload=payload_dict, + ) + + +def make_requirements( + *, + scheme: str = "upto", + network: str = NETWORK, + amount: str = AMOUNT, + pay_to: str = RECIPIENT, +) -> PaymentRequirements: + return PaymentRequirements( + scheme=scheme, + network=network, + asset=TOKEN_ADDRESS, + amount=amount, + pay_to=pay_to, + max_timeout_seconds=3600, + extra={"assetTransferMethod": "permit2", "facilitatorAddress": FACILITATOR}, + ) + + +class MockFacilitatorSigner: + def __init__( + self, + *, + addresses: list[str] | None = None, + sig_valid: bool = True, + allowance: int = int(AMOUNT) * 2, + balance: int = int(AMOUNT) * 10, + tx_success: bool = True, + simulate_ok: bool = True, + code: bytes = b"", + ): + self._addresses = addresses or [FACILITATOR] + self._sig_valid = sig_valid + self._allowance = allowance + self._balance = balance + self._tx_success = tx_success + self._simulate_ok = simulate_ok + self._code = code + self.write_calls: list[tuple] = [] + + def get_addresses(self) -> list[str]: + return self._addresses + + def read_contract(self, address: str, abi: list[dict], function_name: str, *args) -> Any: + if function_name == "allowance": + return self._allowance + if function_name == "balanceOf": + return self._balance + if function_name in {"settle", "settleWithPermit"}: + if self._simulate_ok: + return None + raise RuntimeError("simulation failed") + raise AssertionError(f"unexpected read_contract: {function_name}") + + def verify_typed_data(self, *args: Any, **kwargs: Any) -> bool: + return self._sig_valid + + def write_contract(self, address: str, abi: list[dict], function_name: str, *args) -> str: + self.write_calls.append((address, function_name, args)) + return "0x" + "ab" * 32 + + def send_transaction(self, to: str, data: bytes) -> str: + return "0x" + "cd" * 32 + + def wait_for_transaction_receipt(self, tx_hash: str) -> TransactionReceipt: + status = 1 if self._tx_success else 0 + return TransactionReceipt(status=status, block_number=1, tx_hash=tx_hash) + + def get_balance(self, address: str, token_address: str) -> int: + return self._balance + + def get_chain_id(self) -> int: + return 8453 + + def get_code(self, address: str) -> bytes: + return self._code + + +class TestUptoEvmSchemeConstructor: + def test_creates_instance_with_correct_scheme(self): + signer = MockFacilitatorSigner() + facilitator = UptoEvmFacilitatorScheme(signer) + assert facilitator.scheme == "upto" + assert facilitator.caip_family == "eip155:*" + + +class TestGetExtra: + def test_returns_facilitator_address(self): + signer = MockFacilitatorSigner(addresses=[FACILITATOR]) + facilitator = UptoEvmFacilitatorScheme(signer) + extra = facilitator.get_extra(NETWORK) + assert extra is not None + assert extra["facilitatorAddress"] == FACILITATOR + + def test_returns_none_when_no_addresses(self): + signer = MockFacilitatorSigner() + signer._addresses = [] + facilitator = UptoEvmFacilitatorScheme(signer) + assert facilitator.get_extra(NETWORK) is None + + def test_returns_one_of_multiple_addresses(self): + """get_extra picks randomly from multiple addresses (matches Go/TS behavior).""" + addr2 = "0x2222222222222222222222222222222222222222" + addresses = [FACILITATOR, addr2] + signer = MockFacilitatorSigner(addresses=addresses) + facilitator = UptoEvmFacilitatorScheme(signer) + seen = set() + for _ in range(50): + extra = facilitator.get_extra(NETWORK) + assert extra is not None + seen.add(extra["facilitatorAddress"]) + assert seen == set(addresses), "get_extra should select from all addresses" + + +class TestGetSigners: + def test_returns_signer_addresses(self): + addresses = [FACILITATOR, "0x2222222222222222222222222222222222222222"] + signer = MockFacilitatorSigner(addresses=addresses) + facilitator = UptoEvmFacilitatorScheme(signer) + assert facilitator.get_signers(NETWORK) == addresses + + +class TestVerify: + def _make_facilitator(self, **kwargs) -> UptoEvmFacilitatorScheme: + signer = MockFacilitatorSigner(**kwargs) + return UptoEvmFacilitatorScheme(signer) + + def test_rejects_wrong_scheme(self): + facilitator = self._make_facilitator() + result = facilitator.verify( + make_payment_payload(accepted_scheme="exact"), + make_requirements(), + ) + assert result.is_valid is False + assert result.invalid_reason == ERR_UPTO_INVALID_SCHEME + + def test_rejects_wrong_network(self): + facilitator = self._make_facilitator() + result = facilitator.verify( + make_payment_payload(accepted_network="eip155:1"), + make_requirements(), + ) + assert result.is_valid is False + assert result.invalid_reason == ERR_UPTO_NETWORK_MISMATCH + + def test_rejects_invalid_spender(self): + facilitator = self._make_facilitator() + auth = make_upto_permit2_authorization(spender="0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") + payload = make_payment_payload(payload_dict=make_upto_payload_dict(auth)) + result = facilitator.verify(payload, make_requirements()) + assert result.is_valid is False + assert result.invalid_reason == ERR_PERMIT2_INVALID_SPENDER + + def test_rejects_recipient_mismatch(self): + facilitator = self._make_facilitator() + auth = make_upto_permit2_authorization( + witness_to="0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + ) + payload = make_payment_payload(payload_dict=make_upto_payload_dict(auth)) + result = facilitator.verify(payload, make_requirements()) + assert result.is_valid is False + assert result.invalid_reason == ERR_PERMIT2_RECIPIENT_MISMATCH + + def test_rejects_facilitator_mismatch(self): + facilitator = self._make_facilitator() + auth = make_upto_permit2_authorization( + facilitator="0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef" + ) + payload = make_payment_payload(payload_dict=make_upto_payload_dict(auth)) + result = facilitator.verify(payload, make_requirements()) + assert result.is_valid is False + assert result.invalid_reason == ERR_UPTO_FACILITATOR_MISMATCH + + def test_rejects_expired_deadline(self): + facilitator = self._make_facilitator() + auth = make_upto_permit2_authorization(deadline_offset=-100) + payload = make_payment_payload(payload_dict=make_upto_payload_dict(auth)) + result = facilitator.verify(payload, make_requirements()) + assert result.is_valid is False + assert result.invalid_reason == ERR_PERMIT2_DEADLINE_EXPIRED + + def test_rejects_valid_after_in_future(self): + facilitator = self._make_facilitator() + auth = make_upto_permit2_authorization(valid_after_offset=3600) + payload = make_payment_payload(payload_dict=make_upto_payload_dict(auth)) + result = facilitator.verify(payload, make_requirements()) + assert result.is_valid is False + assert result.invalid_reason == ERR_PERMIT2_NOT_YET_VALID + + def test_rejects_amount_mismatch(self): + facilitator = self._make_facilitator() + auth = make_upto_permit2_authorization(amount="999") + payload = make_payment_payload(payload_dict=make_upto_payload_dict(auth)) + result = facilitator.verify(payload, make_requirements(amount=AMOUNT)) + assert result.is_valid is False + assert result.invalid_reason == ERR_PERMIT2_AMOUNT_MISMATCH + + def test_rejects_token_mismatch(self): + facilitator = self._make_facilitator() + auth = make_upto_permit2_authorization(token="0xdeadbeefdeadbeefdeadbeefdeadbeefdeadbeef") + payload = make_payment_payload(payload_dict=make_upto_payload_dict(auth)) + result = facilitator.verify(payload, make_requirements()) + assert result.is_valid is False + assert result.invalid_reason == ERR_PERMIT2_TOKEN_MISMATCH + + def test_accepts_valid_upto_payload(self): + from unittest.mock import patch + + facilitator = self._make_facilitator(sig_valid=True) + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.verify(make_payment_payload(), make_requirements()) + assert result.is_valid is True + assert result.payer == PAYER + + def test_verify_skips_allowance_and_simulation_when_simulate_false(self): + """simulate=False must return valid after signature check, matching Go/TS behavior.""" + from unittest.mock import patch + + from x402.mechanisms.evm.upto.permit2_utils import verify_upto_permit2 + + signer = MockFacilitatorSigner(sig_valid=True, allowance=0, balance=0, simulate_ok=False) + payload = make_payment_payload() + requirements = make_requirements() + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = verify_upto_permit2(signer, payload, requirements, simulate=False) + assert result.is_valid is True + + def test_rejects_unsupported_payload_type(self): + facilitator = self._make_facilitator() + payload = PaymentPayload( + x402_version=2, + resource=ResourceInfo( + url="http://test", description="test", mime_type="application/json" + ), + accepted=PaymentRequirements( + scheme="upto", + network=NETWORK, + asset=TOKEN_ADDRESS, + amount=AMOUNT, + pay_to=RECIPIENT, + max_timeout_seconds=3600, + extra={}, + ), + payload={"authorization": {"from": PAYER}, "signature": "0x"}, + ) + result = facilitator.verify(payload, make_requirements()) + assert result.is_valid is False + assert result.invalid_reason == "unsupported_payload_type" + + +class TestSettle: + def _make_facilitator(self, **kwargs) -> UptoEvmFacilitatorScheme: + signer = MockFacilitatorSigner(**kwargs) + return UptoEvmFacilitatorScheme(signer) + + def test_settle_calls_upto_proxy_contract(self): + from unittest.mock import patch + + signer = MockFacilitatorSigner(sig_valid=True) + facilitator = UptoEvmFacilitatorScheme(signer) + + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.settle(make_payment_payload(), make_requirements()) + + assert result.success is True + assert len(signer.write_calls) == 1 + address, function_name, _ = signer.write_calls[0] + assert address == X402_UPTO_PERMIT2_PROXY_ADDRESS + assert function_name == "settle" + + def test_settle_returns_amount_in_response(self): + from unittest.mock import patch + + signer = MockFacilitatorSigner(sig_valid=True) + facilitator = UptoEvmFacilitatorScheme(signer) + + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.settle(make_payment_payload(), make_requirements()) + + assert result.success is True + assert result.amount == AMOUNT + + def test_zero_settlement_returns_success_without_tx(self): + from unittest.mock import patch + + signer = MockFacilitatorSigner(sig_valid=True) + facilitator = UptoEvmFacilitatorScheme(signer) + + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.settle(make_payment_payload(), make_requirements(amount="0")) + + assert result.success is True + assert result.transaction == "" + assert result.amount == "0" + assert len(signer.write_calls) == 0 + + def test_settlement_exceeding_amount_fails(self): + from unittest.mock import patch + + signer = MockFacilitatorSigner(sig_valid=True) + facilitator = UptoEvmFacilitatorScheme(signer) + + # authorized max is AMOUNT (1000), try to settle for 2000 + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.settle(make_payment_payload(), make_requirements(amount="2000")) + + assert result.success is False + assert result.error_reason == ERR_UPTO_SETTLEMENT_EXCEEDS_AMOUNT + + def test_settle_fails_if_verify_fails(self): + # Use an invalid signature with no deployed contract code so that + # verify always rejects (signature check runs regardless of simulate mode). + facilitator = self._make_facilitator(sig_valid=False) + result = facilitator.settle(make_payment_payload(), make_requirements()) + assert result.success is False + + def test_settle_fails_on_transaction_failure(self): + from unittest.mock import patch + + signer = MockFacilitatorSigner(tx_success=False) + facilitator = UptoEvmFacilitatorScheme(signer) + + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.settle(make_payment_payload(), make_requirements()) + + assert result.success is False + + def test_partial_settlement_below_max(self): + """Settle for 500 when max authorized is 1000.""" + from unittest.mock import patch + + signer = MockFacilitatorSigner(sig_valid=True) + facilitator = UptoEvmFacilitatorScheme(signer) + + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.settle(make_payment_payload(), make_requirements(amount="500")) + + assert result.success is True + assert result.amount == "500" + assert len(signer.write_calls) == 1 + + def test_settle_for_exact_max_amount(self): + """Settle for exactly the max authorized amount (boundary).""" + from unittest.mock import patch + + signer = MockFacilitatorSigner(sig_valid=True) + facilitator = UptoEvmFacilitatorScheme(signer) + + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.settle(make_payment_payload(), make_requirements(amount=AMOUNT)) + + assert result.success is True + assert result.amount == AMOUNT + + def test_settle_respects_simulate_in_settle_config(self): + from unittest.mock import patch + + signer = MockFacilitatorSigner(sig_valid=True, simulate_ok=False) + facilitator = UptoEvmFacilitatorScheme( + signer, config=UptoEvmSchemeConfig(simulate_in_settle=True) + ) + + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.settle(make_payment_payload(), make_requirements()) + + assert result.success is False + assert result.error_reason == ERR_UPTO_TRANSACTION_FAILED + + +class TestVerifyEdgeCases: + def _make_facilitator(self, **kwargs) -> UptoEvmFacilitatorScheme: + signer = MockFacilitatorSigner(**kwargs) + return UptoEvmFacilitatorScheme(signer) + + def test_rejects_missing_signature(self): + facilitator = self._make_facilitator() + auth = make_upto_permit2_authorization() + payload_dict = UptoPermit2Payload(permit2_authorization=auth, signature=None).to_dict() + payload = make_payment_payload(payload_dict=payload_dict) + result = facilitator.verify(payload, make_requirements()) + assert result.is_valid is False + assert "signature" in result.invalid_reason + + def test_rejects_invalid_signature(self): + from unittest.mock import patch + + facilitator = self._make_facilitator() + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=False, + ): + result = facilitator.verify(make_payment_payload(), make_requirements()) + assert result.is_valid is False + assert "signature" in result.invalid_reason + + def test_rejects_insufficient_balance(self): + from unittest.mock import patch + + facilitator = self._make_facilitator(balance=0) + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.verify(make_payment_payload(), make_requirements()) + assert result.is_valid is False + assert result.invalid_reason == ERR_PERMIT2_INSUFFICIENT_BALANCE + + def test_rejects_insufficient_allowance(self): + from unittest.mock import patch + + facilitator = self._make_facilitator(allowance=0) + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.verify(make_payment_payload(), make_requirements()) + assert result.is_valid is False + assert result.invalid_reason == "permit2_allowance_required" + + def test_rejects_requirements_scheme_mismatch(self): + """TS checks both payload.accepted.scheme and requirements.scheme.""" + facilitator = self._make_facilitator() + result = facilitator.verify( + make_payment_payload(), + make_requirements(scheme="exact"), + ) + assert result.is_valid is False + assert result.invalid_reason == ERR_UPTO_INVALID_SCHEME + + def test_accepts_contract_wallet_when_simulation_succeeds(self): + from unittest.mock import patch + + facilitator = self._make_facilitator(sig_valid=False, code=b"\x01", simulate_ok=True) + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=False, + ): + result = facilitator.verify(make_payment_payload(), make_requirements()) + + assert result.is_valid is True + + def test_rejects_when_upto_settle_simulation_fails(self): + from unittest.mock import patch + + facilitator = self._make_facilitator(sig_valid=True, simulate_ok=False) + with patch( + "x402.mechanisms.evm.upto.permit2_utils._verify_upto_permit2_signature", + return_value=True, + ): + result = facilitator.verify(make_payment_payload(), make_requirements()) + + assert result.is_valid is False + assert result.invalid_reason == ERR_UPTO_TRANSACTION_FAILED + + +class TestMapUptoSettleError: + """Verify _map_upto_settle_error produces canonical Go/TS-parity error codes.""" + + def _call(self, msg: str) -> str: + from x402.mechanisms.evm.upto.permit2_utils import _map_upto_settle_error + + resp = _map_upto_settle_error(RuntimeError(msg), "eip155:8453", PAYER) + return resp.error_reason + + def test_amount_exceeds_permitted(self): + assert ( + self._call("execution reverted: AmountExceedsPermitted") + == "upto_amount_exceeds_permitted" + ) + + def test_unauthorized_facilitator(self): + assert ( + self._call("execution reverted: UnauthorizedFacilitator") + == "upto_unauthorized_facilitator" + ) + + def test_invalid_destination(self): + assert self._call("execution reverted: InvalidDestination") == "permit2_invalid_destination" + + def test_invalid_owner(self): + assert self._call("execution reverted: InvalidOwner") == "permit2_invalid_owner" + + def test_payment_too_early(self): + assert self._call("execution reverted: PaymentTooEarly") == "permit2_payment_too_early" + + def test_invalid_signature(self): + assert self._call("execution reverted: InvalidSignature") == "invalid_permit2_signature" + + def test_signature_expired(self): + assert self._call("execution reverted: SignatureExpired") == "invalid_permit2_signature" + + def test_invalid_nonce(self): + assert self._call("execution reverted: InvalidNonce") == "permit2_invalid_nonce" + + def test_permit2612_amount_mismatch(self): + assert ( + self._call("execution reverted: Permit2612AmountMismatch") + == "permit2_2612_amount_mismatch" + ) + + def test_erc20_approval_broadcast_failed(self): + assert self._call("erc20_approval_tx_failed: 0xabc") == "erc20_approval_broadcast_failed" + + def test_default_maps_to_upto_transaction_failed(self): + assert self._call("some unknown revert") == "invalid_upto_evm_transaction_failed" diff --git a/python/x402/tests/unit/mechanisms/evm/test_upto_permit2.py b/python/x402/tests/unit/mechanisms/evm/test_upto_permit2.py new file mode 100644 index 0000000000..e41d5ae003 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/evm/test_upto_permit2.py @@ -0,0 +1,115 @@ +"""Tests for the upto Permit2 payment types and type guards.""" + +from __future__ import annotations + +import time + +from x402.mechanisms.evm.constants import X402_UPTO_PERMIT2_PROXY_ADDRESS +from x402.mechanisms.evm.types import ( + ExactPermit2TokenPermissions, + UptoPermit2Authorization, + UptoPermit2Payload, + UptoPermit2Witness, + is_permit2_payload, + is_upto_permit2_payload, +) + +PAYER = "0x1234567890123456789012345678901234567890" +RECIPIENT = "0x0987654321098765432109876543210987654321" +FACILITATOR = "0x1111111111111111111111111111111111111111" +TOKEN_ADDRESS = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" +AMOUNT = "1000" + + +def make_upto_authorization( + *, + from_address: str = PAYER, + token: str = TOKEN_ADDRESS, + amount: str = AMOUNT, +) -> UptoPermit2Authorization: + now = int(time.time()) + return UptoPermit2Authorization( + from_address=from_address, + permitted=ExactPermit2TokenPermissions(token=token, amount=amount), + spender=X402_UPTO_PERMIT2_PROXY_ADDRESS, + nonce="12345678901234567890", + deadline=str(now + 3600), + witness=UptoPermit2Witness( + to=RECIPIENT, + facilitator=FACILITATOR, + valid_after=str(now - 600), + ), + ) + + +class TestUptoPermit2PayloadSerialization: + def test_to_dict_and_from_dict_roundtrip(self): + auth = make_upto_authorization() + original = UptoPermit2Payload(permit2_authorization=auth, signature="0x" + "ff" * 65) + + d = original.to_dict() + restored = UptoPermit2Payload.from_dict(d) + + assert restored.permit2_authorization.from_address == auth.from_address + assert restored.permit2_authorization.spender == auth.spender + assert restored.permit2_authorization.nonce == auth.nonce + assert restored.permit2_authorization.deadline == auth.deadline + assert restored.permit2_authorization.permitted.token == auth.permitted.token + assert restored.permit2_authorization.permitted.amount == auth.permitted.amount + assert restored.permit2_authorization.witness.to == auth.witness.to + assert restored.permit2_authorization.witness.facilitator == auth.witness.facilitator + assert restored.permit2_authorization.witness.valid_after == auth.witness.valid_after + assert restored.signature == original.signature + + def test_to_dict_keys_are_camel_case(self): + auth = make_upto_authorization() + payload = UptoPermit2Payload(permit2_authorization=auth, signature="0xsig") + d = payload.to_dict() + + assert "permit2Authorization" in d + p2 = d["permit2Authorization"] + assert "from" in p2 + assert "permitted" in p2 + assert "spender" in p2 + assert "nonce" in p2 + assert "deadline" in p2 + assert "witness" in p2 + assert "to" in p2["witness"] + assert "facilitator" in p2["witness"] + assert "validAfter" in p2["witness"] + + def test_to_dict_omits_signature_when_none(self): + auth = make_upto_authorization() + payload = UptoPermit2Payload(permit2_authorization=auth, signature=None) + d = payload.to_dict() + assert "signature" not in d + + +class TestIsUptoPermit2Payload: + def test_detects_upto_permit2_payload(self): + auth = make_upto_authorization() + payload = UptoPermit2Payload(permit2_authorization=auth, signature="0x").to_dict() + assert is_upto_permit2_payload(payload) is True + + def test_rejects_exact_permit2_payload(self): + payload = { + "permit2Authorization": { + "from": PAYER, + "witness": {"to": RECIPIENT, "validAfter": "123"}, + }, + "signature": "0x", + } + assert is_upto_permit2_payload(payload) is False + + def test_rejects_eip3009_payload(self): + payload = {"authorization": {"from": PAYER}, "signature": "0x"} + assert is_upto_permit2_payload(payload) is False + + def test_rejects_empty_dict(self): + assert is_upto_permit2_payload({}) is False + + def test_exact_is_permit2_payload_also_detects_upto(self): + """is_permit2_payload (exact) returns True for upto payloads too (both have permit2Authorization).""" + auth = make_upto_authorization() + payload = UptoPermit2Payload(permit2_authorization=auth, signature="0x").to_dict() + assert is_permit2_payload(payload) is True diff --git a/python/x402/tests/unit/mechanisms/evm/test_upto_server.py b/python/x402/tests/unit/mechanisms/evm/test_upto_server.py new file mode 100644 index 0000000000..1f8a80bdf9 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/evm/test_upto_server.py @@ -0,0 +1,206 @@ +"""Tests for UptoEvmScheme server.""" + +import pytest + +from x402.mechanisms.evm import get_network_config +from x402.mechanisms.evm.upto import UptoEvmServerScheme +from x402.schemas import AssetAmount, PaymentRequirements, SupportedKind + +FACILITATOR = "0x1111111111111111111111111111111111111111" + + +class TestParsePrice: + class TestBaseMainnetNetwork: + def test_should_parse_dollar_string_prices(self): + server = UptoEvmServerScheme() + network = "eip155:8453" + result = server.parse_price("$0.10", network) + assert result.amount == "100000" + assert result.asset == get_network_config(network)["default_asset"]["address"] + + def test_should_parse_number_prices(self): + server = UptoEvmServerScheme() + network = "eip155:8453" + result = server.parse_price(0.1, network) + assert result.amount == "100000" + + def test_default_conversion_includes_permit2(self): + server = UptoEvmServerScheme() + network = "eip155:8453" + result = server.parse_price("$1.00", network) + assert result.extra.get("assetTransferMethod") == "permit2" + + class TestPreParsedPriceObjects: + def test_should_handle_pre_parsed_price_objects_with_asset(self): + server = UptoEvmServerScheme() + network = "eip155:8453" + result = server.parse_price( + {"amount": "123456", "asset": "0x1234567890123456789012345678901234567890"}, + network, + ) + assert result.amount == "123456" + + def test_should_raise_for_price_objects_without_asset(self): + server = UptoEvmServerScheme() + network = "eip155:8453" + with pytest.raises(ValueError, match="Asset address required"): + server.parse_price({"amount": "123456"}, network) + + +class TestEnhancePaymentRequirements: + def test_should_always_set_permit2_and_facilitator_address(self): + server = UptoEvmServerScheme() + network = "eip155:8453" + + requirements = PaymentRequirements( + scheme="upto", + network=network, + asset=get_network_config(network)["default_asset"]["address"], + amount="100000", + pay_to="0x1234567890123456789012345678901234567890", + max_timeout_seconds=3600, + extra={}, + ) + + supported_kind = SupportedKind( + x402_version=2, + scheme="upto", + network=network, + extra={"facilitatorAddress": FACILITATOR}, + ) + + result = server.enhance_payment_requirements(requirements, supported_kind, []) + + assert result.extra is not None + assert result.extra["assetTransferMethod"] == "permit2" + assert result.extra["facilitatorAddress"] == FACILITATOR + assert result.extra["name"] + assert result.extra["version"] + + def test_should_convert_decimal_amounts_to_smallest_unit(self): + server = UptoEvmServerScheme() + network = "eip155:8453" + + requirements = PaymentRequirements( + scheme="upto", + network=network, + asset=get_network_config(network)["default_asset"]["address"], + amount="1.5", + pay_to="0x1234567890123456789012345678901234567890", + max_timeout_seconds=3600, + extra={}, + ) + + supported_kind = SupportedKind( + x402_version=2, + scheme="upto", + network=network, + extra={"facilitatorAddress": FACILITATOR}, + ) + + result = server.enhance_payment_requirements(requirements, supported_kind, []) + assert result.amount == "1500000" + + def test_should_set_default_asset_if_not_specified(self): + server = UptoEvmServerScheme() + network = "eip155:8453" + + requirements = PaymentRequirements( + scheme="upto", + network=network, + asset="", + amount="100000", + pay_to="0x1234567890123456789012345678901234567890", + max_timeout_seconds=3600, + extra={}, + ) + + supported_kind = SupportedKind( + x402_version=2, + scheme="upto", + network=network, + extra={"facilitatorAddress": FACILITATOR}, + ) + + result = server.enhance_payment_requirements(requirements, supported_kind, []) + + config = get_network_config(network) + assert result.asset == config["default_asset"]["address"] + + def test_should_copy_extension_keys_from_supported_kind_extra(self): + server = UptoEvmServerScheme() + network = "eip155:8453" + requirements = PaymentRequirements( + scheme="upto", + network=network, + asset=get_network_config(network)["default_asset"]["address"], + amount="100000", + pay_to="0x1234567890123456789012345678901234567890", + max_timeout_seconds=3600, + extra={}, + ) + supported_kind = SupportedKind( + x402_version=2, + scheme="upto", + network=network, + extra={ + "facilitatorAddress": FACILITATOR, + "erc20ApprovalGasSponsoring": {"version": "1"}, + }, + ) + + result = server.enhance_payment_requirements( + requirements, supported_kind, ["erc20ApprovalGasSponsoring"] + ) + assert result.extra is not None + assert result.extra["erc20ApprovalGasSponsoring"] == {"version": "1"} + + def test_should_fail_without_facilitator_address(self): + server = UptoEvmServerScheme() + network = "eip155:8453" + requirements = PaymentRequirements( + scheme="upto", + network=network, + asset=get_network_config(network)["default_asset"]["address"], + amount="100000", + pay_to="0x1234567890123456789012345678901234567890", + max_timeout_seconds=3600, + extra={}, + ) + supported_kind = SupportedKind( + x402_version=2, + scheme="upto", + network=network, + extra={}, + ) + + with pytest.raises(ValueError, match="facilitatorAddress"): + server.enhance_payment_requirements(requirements, supported_kind, []) + + +class TestRegisterMoneyParser: + def test_should_use_custom_parser_for_money_values(self): + server = UptoEvmServerScheme() + network = "eip155:8453" + + def custom_parser(amount: float, network: str) -> AssetAmount | None: + if amount > 100: + return AssetAmount( + amount=str(int(amount * 1e9)), + asset="0xCustomToken123456789012345678901234567890", + extra={"token": "CUSTOM"}, + ) + return None + + server.register_money_parser(custom_parser) + + result = server.parse_price(150, network) + assert result.asset == "0xCustomToken123456789012345678901234567890" + + result2 = server.parse_price(50, network) + assert result2.asset == get_network_config(network)["default_asset"]["address"] + + def test_should_return_self_for_chaining(self): + server = UptoEvmServerScheme() + result = server.register_money_parser(lambda a, n: None) + assert result is server diff --git a/python/x402/tests/unit/mechanisms/svm/test_duplicate_tx.py b/python/x402/tests/unit/mechanisms/svm/test_duplicate_tx.py index cad477379d..1012c8a821 100644 --- a/python/x402/tests/unit/mechanisms/svm/test_duplicate_tx.py +++ b/python/x402/tests/unit/mechanisms/svm/test_duplicate_tx.py @@ -327,3 +327,137 @@ def test_memo_has_empty_accounts(self, mock_rpc_client, test_keypair, test_requi memo_ix = tx.message.instructions[3] assert str(tx.message.account_keys[memo_ix.program_id_index]) == MEMO_PROGRAM_ADDRESS assert len(memo_ix.accounts) == 0, "memo must have no accounts" + + +class TestSellerMemo: + """Tests for optional extra.memo seller-defined memo support.""" + + @pytest.fixture + def mock_rpc_client(self): + mock_client = MagicMock() + mock_blockhash_resp = MagicMock() + mock_blockhash_resp.value.blockhash = Hash.from_string(FIXED_BLOCKHASH) + mock_client.get_latest_blockhash.return_value = mock_blockhash_resp + + mock_account_info = MagicMock() + mock_account_info.value = MagicMock() + mock_account_info.value.owner = Pubkey.from_string(TOKEN_PROGRAM_ADDRESS) + mock_account_info.value.data = bytes(44) + bytes([6]) + bytes(37) + mock_client.get_account_info.return_value = mock_account_info + return mock_client + + @pytest.fixture + def test_keypair(self): + return Keypair.from_seed(bytes([1] * 32)) + + def test_uses_extra_memo_as_memo_data(self, mock_rpc_client, test_keypair): + """When extra.memo is provided, client uses it as memo instruction data.""" + seller_memo = "pi_3abc123def456" + fee_payer = Keypair.from_seed(bytes([2] * 32)) + pay_to = Keypair.from_seed(bytes([3] * 32)) + + requirements = PaymentRequirements( + scheme="exact", + network=SOLANA_DEVNET_CAIP2, + asset=USDC_DEVNET_ADDRESS, + amount="100000", + pay_to=str(pay_to.pubkey()), + max_timeout_seconds=3600, + extra={"feePayer": str(fee_payer.pubkey()), "memo": seller_memo}, + ) + + client = ExactSvmClientScheme(KeypairSigner(test_keypair)) + with patch.object(client, "_get_client", return_value=mock_rpc_client): + payload = client.create_payment_payload(requirements) + + tx = decode_transaction_from_payload(ExactSvmPayload(transaction=payload["transaction"])) + assert len(tx.message.instructions) >= 4 + + memo_ix = tx.message.instructions[3] + assert str(tx.message.account_keys[memo_ix.program_id_index]) == MEMO_PROGRAM_ADDRESS + + memo_data = bytes(memo_ix.data).decode("utf-8") + assert memo_data == seller_memo + + def test_produces_identical_memo_with_extra_memo(self, mock_rpc_client, test_keypair): + """With extra.memo, memo data is deterministic across calls.""" + seller_memo = "order_12345" + fee_payer = Keypair.from_seed(bytes([2] * 32)) + pay_to = Keypair.from_seed(bytes([3] * 32)) + + requirements = PaymentRequirements( + scheme="exact", + network=SOLANA_DEVNET_CAIP2, + asset=USDC_DEVNET_ADDRESS, + amount="100000", + pay_to=str(pay_to.pubkey()), + max_timeout_seconds=3600, + extra={"feePayer": str(fee_payer.pubkey()), "memo": seller_memo}, + ) + + client = ExactSvmClientScheme(KeypairSigner(test_keypair)) + with patch.object(client, "_get_client", return_value=mock_rpc_client): + payload1 = client.create_payment_payload(requirements) + payload2 = client.create_payment_payload(requirements) + + tx1 = decode_transaction_from_payload(ExactSvmPayload(transaction=payload1["transaction"])) + tx2 = decode_transaction_from_payload(ExactSvmPayload(transaction=payload2["transaction"])) + + memo1 = bytes(tx1.message.instructions[3].data).decode("utf-8") + memo2 = bytes(tx2.message.instructions[3].data).decode("utf-8") + + assert memo1 == seller_memo + assert memo2 == seller_memo + assert memo1 == memo2 + + def test_falls_back_to_random_nonce_without_memo(self, mock_rpc_client, test_keypair): + """Without extra.memo, falls back to random hex nonce.""" + fee_payer = Keypair.from_seed(bytes([2] * 32)) + pay_to = Keypair.from_seed(bytes([3] * 32)) + + requirements = PaymentRequirements( + scheme="exact", + network=SOLANA_DEVNET_CAIP2, + asset=USDC_DEVNET_ADDRESS, + amount="100000", + pay_to=str(pay_to.pubkey()), + max_timeout_seconds=3600, + extra={"feePayer": str(fee_payer.pubkey())}, + ) + + client = ExactSvmClientScheme(KeypairSigner(test_keypair)) + with patch.object(client, "_get_client", return_value=mock_rpc_client): + payload1 = client.create_payment_payload(requirements) + payload2 = client.create_payment_payload(requirements) + + tx1 = decode_transaction_from_payload(ExactSvmPayload(transaction=payload1["transaction"])) + tx2 = decode_transaction_from_payload(ExactSvmPayload(transaction=payload2["transaction"])) + + memo1 = bytes(tx1.message.instructions[3].data).decode("utf-8") + memo2 = bytes(tx2.message.instructions[3].data).decode("utf-8") + + import re + + assert memo1 != memo2, "Random nonces should differ between calls" + assert re.match(r"^[0-9a-f]{32}$", memo1), "Nonce should be 32 hex chars" + assert re.match(r"^[0-9a-f]{32}$", memo2), "Nonce should be 32 hex chars" + + def test_rejects_memo_exceeding_256_bytes(self, mock_rpc_client, test_keypair): + """Client should reject extra.memo exceeding 256 bytes.""" + fee_payer = Keypair.from_seed(bytes([2] * 32)) + pay_to = Keypair.from_seed(bytes([3] * 32)) + + requirements = PaymentRequirements( + scheme="exact", + network=SOLANA_DEVNET_CAIP2, + asset=USDC_DEVNET_ADDRESS, + amount="100000", + pay_to=str(pay_to.pubkey()), + max_timeout_seconds=3600, + extra={"feePayer": str(fee_payer.pubkey()), "memo": "x" * 257}, + ) + + client = ExactSvmClientScheme(KeypairSigner(test_keypair)) + with patch.object(client, "_get_client", return_value=mock_rpc_client): + with pytest.raises(ValueError, match="extra.memo exceeds maximum 256 bytes"): + client.create_payment_payload(requirements) diff --git a/python/x402/tests/unit/mechanisms/tvm/__init__.py b/python/x402/tests/unit/mechanisms/tvm/__init__.py new file mode 100644 index 0000000000..d1e5a3000b --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/__init__.py @@ -0,0 +1 @@ +"""Unit tests for the TVM mechanism.""" diff --git a/python/x402/tests/unit/mechanisms/tvm/builders.py b/python/x402/tests/unit/mechanisms/tvm/builders.py new file mode 100644 index 0000000000..d8f1078957 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/builders.py @@ -0,0 +1,128 @@ +"""Test data builders for TVM mechanism unit tests.""" + +from __future__ import annotations + +import base64 +import time +from dataclasses import dataclass + +from pytoniq_core import begin_cell +from pytoniq_core.crypto.keys import mnemonic_to_wallet_key + +from x402.mechanisms.tvm import TVM_TESTNET, ParsedJettonTransfer, ParsedTvmSettlement +from x402.schemas import PaymentPayload, PaymentRequirements, ResourceInfo + +PAYER = "0:" + "1" * 64 +MERCHANT = "0:" + "2" * 64 +ASSET = "0:" + "3" * 64 +SOURCE_WALLET = "0:" + "4" * 64 +RECEIVER_WALLET = "0:" + "5" * 64 +RESPONSE_DESTINATION = "0:" + "6" * 64 +FACILITATOR = "0:" + "f" * 64 + +TEST_MNEMONIC = ( + "abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon abandon about" +) + +EMPTY_FORWARD_PAYLOAD = begin_cell().store_bit(0).end_cell() +EMPTY_FORWARD_PAYLOAD_B64 = base64.b64encode(EMPTY_FORWARD_PAYLOAD.to_boc()).decode("ascii") +SPONSORED_FORWARDING_EXTRA = { + "areFeesSponsored": True, + "forwardPayload": EMPTY_FORWARD_PAYLOAD_B64, + "forwardTonAmount": "0", +} +SPONSORED_EXTRA = { + "areFeesSponsored": True, + "forwardTonAmount": "0", +} + + +def derive_test_secret_key() -> bytes: + """Return a deterministic secret key used across signer tests.""" + _, secret_key = mnemonic_to_wallet_key(TEST_MNEMONIC.split()) + return secret_key + + +def make_tvm_requirements( + *, + default_extra: dict[str, object] | None = None, + extra: dict[str, object] | None = None, + **overrides: object, +) -> PaymentRequirements: + merged_extra = dict(default_extra or {}) + merged_extra.update(extra or {}) + return PaymentRequirements( + scheme="exact", + network=overrides.pop("network", TVM_TESTNET), + asset=overrides.pop("asset", ASSET), + amount=overrides.pop("amount", "100"), + pay_to=overrides.pop("pay_to", MERCHANT), + max_timeout_seconds=overrides.pop("max_timeout_seconds", 300), + extra=merged_extra, + **overrides, + ) + + +def make_tvm_payload( + *, + default_accepted_extra: dict[str, object] | None = None, + accepted_extra: dict[str, object] | None = None, + payload: dict[str, object] | None = None, + **overrides: object, +) -> PaymentPayload: + merged_extra = dict(default_accepted_extra or {}) + merged_extra.update(accepted_extra or {}) + resolved_payload = payload or { + "settlementBoc": overrides.pop("settlement_boc", "base64-boc=="), + "asset": overrides.pop("payload_asset", ASSET), + } + return PaymentPayload( + x402_version=overrides.pop("x402_version", 2), + resource=ResourceInfo( + url="http://example.com/protected", + description="Test resource", + mime_type="application/json", + ), + accepted=PaymentRequirements( + scheme=overrides.pop("accepted_scheme", "exact"), + network=overrides.pop("accepted_network", TVM_TESTNET), + asset=overrides.pop("accepted_asset", ASSET), + amount=overrides.pop("accepted_amount", "100"), + pay_to=overrides.pop("accepted_pay_to", MERCHANT), + max_timeout_seconds=overrides.pop("accepted_max_timeout_seconds", 300), + extra=merged_extra, + ), + payload=resolved_payload, + **overrides, + ) + + +@dataclass +class FakeCell: + hash: bytes + + +def make_tvm_settlement(**overrides: object) -> ParsedTvmSettlement: + transfer = ParsedJettonTransfer( + source_wallet=overrides.pop("source_wallet", SOURCE_WALLET), + destination=overrides.pop("destination", MERCHANT), + response_destination=overrides.pop("response_destination", None), + jetton_amount=overrides.pop("jetton_amount", 100), + attached_ton_amount=overrides.pop("attached_ton_amount", 500_000), + forward_ton_amount=overrides.pop("forward_ton_amount", 0), + forward_payload=overrides.pop("forward_payload", EMPTY_FORWARD_PAYLOAD), + body_hash=overrides.pop("body_hash", b"transfer-body-hash"), + ) + return ParsedTvmSettlement( + payer=overrides.pop("payer", PAYER), + wallet_id=overrides.pop("wallet_id", 777), + valid_until=overrides.pop("valid_until", int(time.time()) + 120), + seqno=overrides.pop("seqno", 12), + settlement_hash=overrides.pop("settlement_hash", "settlement-hash-1"), + body=overrides.pop("body", FakeCell(b"body-hash")), + signed_slice_hash=overrides.pop("signed_slice_hash", b"signed-slice"), + signature=overrides.pop("signature", b"signature"), + state_init=overrides.pop("state_init", None), + transfer=transfer, + **overrides, + ) diff --git a/python/x402/tests/unit/mechanisms/tvm/fakes.py b/python/x402/tests/unit/mechanisms/tvm/fakes.py new file mode 100644 index 0000000000..f2f44b879a --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/fakes.py @@ -0,0 +1,285 @@ +"""Test doubles for TVM mechanism unit tests.""" + +from __future__ import annotations + +from typing import Any + +from x402.mechanisms.tvm import ( + TVM_TESTNET, + TvmAccountState, + TvmJettonWalletData, + TvmRelayRequest, + address_from_state_init, + build_w5r1_state_init, +) +from x402.mechanisms.tvm.constants import ( + DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + DEFAULT_TVM_EMULATION_ADDRESS, +) + +from .builders import ASSET, FACILITATOR, PAYER, RECEIVER_WALLET, SOURCE_WALLET + + +class ClientSignerStub: + def __init__(self) -> None: + self._wallet_id = 7 + self._state_init = build_w5r1_state_init(b"\x11" * 32, self._wallet_id) + self._address = address_from_state_init(self._state_init, 0) + + @property + def address(self) -> str: + return self._address + + @property + def network(self) -> str: + return TVM_TESTNET + + @property + def wallet_id(self) -> int: + return self._wallet_id + + @property + def state_init(self): + return self._state_init + + @property + def provider_emulation_timeout_seconds(self) -> float: + return DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS + + def sign_message(self, message: bytes) -> bytes: + assert message + return b"\x00" * 64 + + +class ToncenterClientStub: + def __init__( + self, + *, + is_active: bool = False, + source_wallet_balance: int = 0, + source_wallet_fwd_fees: list[int] | None = None, + source_wallet_compute_fee: int = 0, + receiver_wallet_compute_fee: int = 0, + source_wallet_storage_fee: int = 0, + omit_receiver_tx: bool = False, + source_action_total_fwd_fees: int | None = None, + signer: ClientSignerStub | None = None, + ) -> None: + self._is_active = is_active + self._source_wallet_balance = source_wallet_balance + self._source_wallet_fwd_fees = source_wallet_fwd_fees or [0] + self._source_wallet_compute_fee = source_wallet_compute_fee + self._receiver_wallet_compute_fee = receiver_wallet_compute_fee + self._source_wallet_storage_fee = source_wallet_storage_fee + self._omit_receiver_tx = omit_receiver_tx + self._source_action_total_fwd_fees = source_action_total_fwd_fees + self._signer = signer or ClientSignerStub() + self.get_account_state_calls = 0 + self.get_jetton_wallet_calls: list[tuple[str, str]] = [] + self.emulate_trace_calls: list[dict[str, object]] = [] + self.close_calls = 0 + + def get_account_state(self, address: str) -> TvmAccountState: + self.get_account_state_calls += 1 + return TvmAccountState( + address=address, + balance=0, + is_active=self._is_active, + is_uninitialized=not self._is_active, + is_frozen=False, + state_init=self._signer.state_init if self._is_active else None, + ) + + def get_jetton_wallet(self, asset: str, owner: str) -> str: + self.get_jetton_wallet_calls.append((asset, owner)) + if owner == self._signer.address: + return SOURCE_WALLET + return RECEIVER_WALLET + + def emulate_trace( + self, + boc: bytes, + *, + ignore_chksig: bool = False, + timeout: float = DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + ) -> dict[str, object]: + _ = boc + self.emulate_trace_calls.append({"ignore_chksig": ignore_chksig, "timeout": timeout}) + payer = self._signer.address + emulation_address = DEFAULT_TVM_EMULATION_ADDRESS + relay_out_hash = "relay-out-hash" + payer_out_hash = "payer-out-hash" + source_out_hash = "source-out-hash" + transactions: dict[str, Any] = { + "payer": { + "account": payer, + "description": { + "aborted": False, + "action": {"success": True}, + "compute_ph": {"success": True, "skipped": False}, + }, + "in_msg": ( + { + "hash": relay_out_hash, + "hash_norm": relay_out_hash, + "source": emulation_address, + "destination": payer, + "decoded_opcode": "w5_internal_signed_request", + } + if ignore_chksig + else {"decoded_opcode": "w5_external_signed_request"} + ), + "out_msgs": [{"hash": payer_out_hash, "hash_norm": payer_out_hash}], + }, + "source": { + "account": SOURCE_WALLET, + "account_state_before": {"balance": str(self._source_wallet_balance)}, + "description": { + "aborted": False, + "action": { + "success": True, + **( + {"total_fwd_fees": str(self._source_action_total_fwd_fees)} + if self._source_action_total_fwd_fees is not None + else {} + ), + }, + "compute_ph": { + "success": True, + "skipped": False, + "gas_fees": str(self._source_wallet_compute_fee), + }, + "storage_ph": {"storage_fees_collected": str(self._source_wallet_storage_fee)}, + }, + "in_msg": { + "hash": payer_out_hash, + "hash_norm": payer_out_hash, + "source": payer, + "destination": SOURCE_WALLET, + "decoded_opcode": "jetton_transfer", + }, + "out_msgs": [ + { + "hash": source_out_hash, + "hash_norm": source_out_hash, + "source": SOURCE_WALLET, + "destination": RECEIVER_WALLET, + "decoded_opcode": "jetton_internal_transfer", + "message_content": { + "decoded": { + "@type": "jetton_internal_transfer", + } + }, + **({"fwd_fee": str(fee)} if fee is not None else {}), + } + for fee in self._source_wallet_fwd_fees + ], + }, + } + if not self._omit_receiver_tx: + transactions["receiver"] = { + "account": RECEIVER_WALLET, + "description": { + "aborted": False, + "action": {"success": True}, + "compute_ph": { + "success": True, + "skipped": False, + "gas_fees": str(self._receiver_wallet_compute_fee), + }, + }, + "in_msg": { + "hash": source_out_hash, + "hash_norm": source_out_hash, + "source": SOURCE_WALLET, + "destination": RECEIVER_WALLET, + "decoded_opcode": "jetton_internal_transfer", + }, + } + if ignore_chksig: + transactions["emulation"] = { + "account": emulation_address, + "description": { + "aborted": False, + "action": {"success": True}, + "compute_ph": {"success": True, "skipped": False}, + }, + "in_msg": {"decoded_opcode": "w5_external_signed_request"}, + "out_msgs": [ + { + "hash": relay_out_hash, + "hash_norm": relay_out_hash, + "source": emulation_address, + "destination": payer, + } + ], + } + return {"transactions": transactions} + + def close(self) -> None: + self.close_calls += 1 + + +class FacilitatorSignerStub: + def __init__(self) -> None: + self.account_state = TvmAccountState( + address=PAYER, + balance=0, + is_active=True, + is_frozen=False, + is_uninitialized=False, + state_init=None, + ) + self.facilitator_account_state = TvmAccountState( + address=FACILITATOR, + balance=10_000_000_000, + is_active=True, + is_frozen=False, + is_uninitialized=False, + state_init=None, + ) + self.jetton_wallet_data = TvmJettonWalletData( + address=SOURCE_WALLET, + balance=1_000_000, + owner=PAYER, + jetton_minter=ASSET, + ) + self.last_relay_request: TvmRelayRequest | None = None + + def get_addresses(self) -> list[str]: + return [FACILITATOR] + + def get_addresses_for_network(self, network: str) -> list[str]: + assert network == TVM_TESTNET + return [FACILITATOR] + + def get_account_state(self, address: str, network: str) -> TvmAccountState: + assert network == TVM_TESTNET + if address == FACILITATOR: + return self.facilitator_account_state + assert address == PAYER + return self.account_state + + def get_jetton_wallet(self, asset: str, owner: str, network: str) -> str: + assert asset == ASSET + assert owner == PAYER + assert network == TVM_TESTNET + return SOURCE_WALLET + + def get_jetton_wallet_data(self, address: str, network: str) -> TvmJettonWalletData: + assert address == SOURCE_WALLET + assert network == TVM_TESTNET + return self.jetton_wallet_data + + def build_relay_external_boc( + self, network: str, relay_request: TvmRelayRequest, *, for_emulation: bool = False + ) -> bytes: + assert network == TVM_TESTNET + assert for_emulation is True + self.last_relay_request = relay_request + return b"external-boc" + + def emulate_external_message(self, network: str, external_boc: bytes) -> dict[str, object]: + assert network == TVM_TESTNET + assert external_boc == b"external-boc" + return {"transactions": {}} diff --git a/python/x402/tests/unit/mechanisms/tvm/helpers.py b/python/x402/tests/unit/mechanisms/tvm/helpers.py new file mode 100644 index 0000000000..d4b7de0533 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/helpers.py @@ -0,0 +1,45 @@ +"""Generic test helpers for TVM mechanism unit tests.""" + +from __future__ import annotations + +import threading +from dataclasses import dataclass + + +@dataclass +class ThreadCapture: + thread: threading.Thread + holder: dict[str, object] + + def join(self, timeout: float = 1.0) -> None: + self.thread.join(timeout=timeout) + assert self.thread.is_alive() is False + + @property + def result(self) -> object: + if "error" in self.holder: + raise AssertionError(f"Thread raised unexpectedly: {self.holder['error']!r}") + return self.holder["result"] + + @property + def error(self) -> BaseException: + error = self.holder.get("error") + assert isinstance(error, BaseException) + return error + + +def start_captured_thread(target, *, timeout: float | None = None) -> ThreadCapture: + """Start a thread and capture either its return value or its terminal exception.""" + holder: dict[str, object] = {} + + def runner() -> None: + try: + holder["result"] = target() + except BaseException as exc: # pragma: no cover - exercised via tests + holder["error"] = exc + + thread = threading.Thread(target=runner) + thread.start() + if timeout is not None: + thread.join(timeout=timeout) + return ThreadCapture(thread=thread, holder=holder) diff --git a/python/x402/tests/unit/mechanisms/tvm/test_client.py b/python/x402/tests/unit/mechanisms/tvm/test_client.py new file mode 100644 index 0000000000..d1cdae95a4 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_client.py @@ -0,0 +1,304 @@ +"""Tests for the exact TVM client scheme.""" + +from __future__ import annotations + +import base64 + +import pytest + +pytest.importorskip("pytoniq_core") + +from pytoniq.contract.contract import Contract +from pytoniq_core import Address, begin_cell + +from x402.mechanisms.tvm import ( + TVM_TESTNET, +) +from x402.mechanisms.tvm.constants import ( + DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + DEFAULT_TVM_INNER_GAS_BUFFER, +) +from x402.mechanisms.tvm.exact import ExactTvmClientScheme +from x402.mechanisms.tvm.exact.codec import parse_exact_tvm_payload + +from .builders import ( + ASSET, + MERCHANT, + RESPONSE_DESTINATION, + SOURCE_WALLET, + SPONSORED_EXTRA, + make_tvm_requirements, +) +from .fakes import ClientSignerStub, ToncenterClientStub + + +def _make_requirements(**overrides): + return make_tvm_requirements(default_extra=SPONSORED_EXTRA, **overrides) + + +class TestExactTvmClientSchemeConstructor: + def test_should_create_instance_with_correct_scheme(self): + signer = ClientSignerStub() + + client = ExactTvmClientScheme(signer) + + assert client.scheme == "exact" + + def test_should_store_signer_reference(self): + signer = ClientSignerStub() + + client = ExactTvmClientScheme(signer) + + assert client._signer is signer + + def test_close_should_close_cached_toncenter_clients(self): + client = ExactTvmClientScheme(ClientSignerStub()) + testnet_client = ToncenterClientStub() + mainnet_client = ToncenterClientStub() + client._clients = { + TVM_TESTNET: testnet_client, + "tvm:-239": mainnet_client, + } + + client.close() + + assert testnet_client.close_calls == 1 + assert mainnet_client.close_calls == 1 + assert client._clients == {} + + def test_close_should_be_idempotent(self): + client = ExactTvmClientScheme(ClientSignerStub()) + + client.close() + client.close() + + +class TestCreatePaymentPayload: + def test_should_have_create_payment_payload_method(self): + client = ExactTvmClientScheme(ClientSignerStub()) + + assert hasattr(client, "create_payment_payload") + assert callable(client.create_payment_payload) + + def test_should_reject_unsupported_network(self): + client = ExactTvmClientScheme(ClientSignerStub()) + + with pytest.raises(ValueError, match="Unsupported TVM network"): + client.create_payment_payload(_make_requirements(network="tvm:999")) + + def test_should_reject_requirements_for_different_signer_network(self): + client = ExactTvmClientScheme(ClientSignerStub()) + + with pytest.raises(ValueError, match="Signer network .* does not match requirements"): + client.create_payment_payload(_make_requirements(network="tvm:-239")) + + def test_should_require_fee_sponsorship(self): + client = ExactTvmClientScheme(ClientSignerStub()) + + with pytest.raises(ValueError, match="requires extra.areFeesSponsored to be true"): + client.create_payment_payload(_make_requirements(extra={"areFeesSponsored": False})) + + def test_should_create_payload_with_forward_defaults(self, monkeypatch): + signer = ClientSignerStub() + client = ExactTvmClientScheme(signer) + toncenter = ToncenterClientStub( + is_active=True, + source_wallet_balance=1_000_000, + source_wallet_fwd_fees=[200_000], + source_wallet_compute_fee=300_000, + receiver_wallet_compute_fee=400_000, + source_wallet_storage_fee=500_000, + signer=signer, + ) + monkeypatch.setattr(client, "_get_client", lambda network: toncenter) + + payload = client.create_payment_payload(_make_requirements()) + settlement = parse_exact_tvm_payload(payload["settlementBoc"]) + + assert payload["asset"] == ASSET + assert settlement.transfer.destination == MERCHANT + assert settlement.transfer.source_wallet == SOURCE_WALLET + assert settlement.transfer.response_destination is None + assert settlement.transfer.forward_ton_amount == 0 + assert settlement.transfer.forward_payload.hash == begin_cell().store_bit(0).end_cell().hash + assert settlement.transfer.attached_ton_amount == ( + 200_000 + 300_000 + 400_000 + 500_000 + DEFAULT_TVM_INNER_GAS_BUFFER + ) + assert toncenter.get_account_state_calls == 1 + assert toncenter.get_jetton_wallet_calls == [(ASSET, signer.address)] + assert toncenter.emulate_trace_calls == [ + { + "ignore_chksig": True, + "timeout": DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + } + ] + + def test_should_use_default_emulation_wallet_to_relay_into_undeployed_payer(self, monkeypatch): + signer = ClientSignerStub() + client = ExactTvmClientScheme(signer) + toncenter = ToncenterClientStub( + is_active=False, + source_wallet_balance=1_000_000, + source_wallet_fwd_fees=[200_000], + source_wallet_compute_fee=300_000, + receiver_wallet_compute_fee=400_000, + source_wallet_storage_fee=500_000, + signer=signer, + ) + monkeypatch.setattr(client, "_get_client", lambda network: toncenter) + + payload = client.create_payment_payload(_make_requirements()) + settlement = parse_exact_tvm_payload(payload["settlementBoc"]) + + assert settlement.transfer.source_wallet == SOURCE_WALLET + assert toncenter.get_account_state_calls == 1 + assert toncenter.get_jetton_wallet_calls == [(ASSET, signer.address)] + assert toncenter.emulate_trace_calls == [ + { + "ignore_chksig": True, + "timeout": DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + } + ] + + def test_should_use_signer_emulation_timeout_override(self, monkeypatch): + class _CustomTimeoutSigner(ClientSignerStub): + @property + def provider_emulation_timeout_seconds(self) -> float: + return 14.0 + + client = ExactTvmClientScheme(_CustomTimeoutSigner()) + toncenter = ToncenterClientStub( + is_active=True, + source_wallet_balance=1_000_000, + source_wallet_fwd_fees=[200_000], + source_wallet_compute_fee=300_000, + receiver_wallet_compute_fee=400_000, + source_wallet_storage_fee=500_000, + signer=client._signer, + ) + monkeypatch.setattr(client, "_get_client", lambda network: toncenter) + + client.create_payment_payload(_make_requirements()) + + assert toncenter.emulate_trace_calls == [{"ignore_chksig": True, "timeout": 14.0}] + + def test_should_create_payload_with_custom_forward_settings(self, monkeypatch): + signer = ClientSignerStub() + client = ExactTvmClientScheme(signer) + toncenter = ToncenterClientStub( + is_active=True, + source_wallet_balance=1_000_000, + source_wallet_fwd_fees=[200_000, 250_000], + source_wallet_compute_fee=300_000, + receiver_wallet_compute_fee=400_000, + source_wallet_storage_fee=500_000, + signer=signer, + ) + monkeypatch.setattr(client, "_get_client", lambda network: toncenter) + forward_payload = begin_cell().store_uint(0xABCD, 16).end_cell() + + payload = client.create_payment_payload( + _make_requirements( + extra={ + "areFeesSponsored": True, + "responseDestination": RESPONSE_DESTINATION, + "forwardTonAmount": "50000000", + "forwardPayload": base64.b64encode(forward_payload.to_boc()).decode("ascii"), + } + ) + ) + settlement = parse_exact_tvm_payload(payload["settlementBoc"]) + + assert settlement.transfer.response_destination == RESPONSE_DESTINATION + assert settlement.transfer.forward_ton_amount == 50_000_000 + assert settlement.transfer.forward_payload.hash == forward_payload.hash + assert settlement.transfer.attached_ton_amount == 58_750_000 + + def test_should_raise_when_trace_does_not_include_destination_wallet_transfer( + self, monkeypatch + ): + signer = ClientSignerStub() + client = ExactTvmClientScheme(signer) + monkeypatch.setattr( + client, + "_get_client", + lambda network: ToncenterClientStub( + is_active=True, + source_wallet_balance=1_000_000, + source_wallet_fwd_fees=[200_000], + source_wallet_compute_fee=300_000, + receiver_wallet_compute_fee=400_000, + source_wallet_storage_fee=500_000, + omit_receiver_tx=True, + signer=signer, + ), + ) + + with pytest.raises( + ValueError, + match="Trace does not contain the expected destination jetton wallet transaction", + ): + client.create_payment_payload(_make_requirements()) + + def test_build_transfer_body_should_reject_negative_forward_ton_amount(self): + client = ExactTvmClientScheme(ClientSignerStub()) + + with pytest.raises(ValueError, match="Forward ton amount should be >= 0"): + client._build_transfer_body(_make_requirements(extra={"forwardTonAmount": "-1"})) + + def test_build_transfer_body_should_store_explicit_forward_payload(self): + client = ExactTvmClientScheme(ClientSignerStub()) + forward_payload = begin_cell().store_uint(0xABCD, 16).end_cell() + + transfer_body = client._build_transfer_body( + _make_requirements( + extra={ + "forwardTonAmount": "777", + "forwardPayload": base64.b64encode(forward_payload.to_boc()).decode("ascii"), + } + ) + ) + transfer = parse_exact_tvm_payload( + base64.b64encode( + Contract.create_internal_msg( + src=None, + dest=Address(ClientSignerStub().address), + bounce=True, + value=0, + body=client._build_signed_body( + source_wallet=SOURCE_WALLET, + transfer_body=transfer_body, + seqno=1, + valid_until=2, + attached_amount=3, + ), + ) + .serialize() + .to_boc() + ).decode("ascii") + ) + + assert transfer.transfer.forward_ton_amount == 777 + assert transfer.transfer.forward_payload.hash == forward_payload.hash + + def test_estimate_required_inner_value_should_fallback_to_action_phase_fees(self, monkeypatch): + signer = ClientSignerStub() + client = ExactTvmClientScheme(signer) + toncenter = ToncenterClientStub( + is_active=True, + source_wallet_balance=1_000_000, + source_wallet_fwd_fees=[None], + source_wallet_compute_fee=300_000, + receiver_wallet_compute_fee=400_000, + source_wallet_storage_fee=500_000, + source_action_total_fwd_fees=200_000, + signer=signer, + ) + monkeypatch.setattr(client, "_get_client", lambda network: toncenter) + + payload = client.create_payment_payload(_make_requirements()) + settlement = parse_exact_tvm_payload(payload["settlementBoc"]) + + assert settlement.transfer.attached_ton_amount == ( + 200_000 + 300_000 + 400_000 + 500_000 + DEFAULT_TVM_INNER_GAS_BUFFER + ) diff --git a/python/x402/tests/unit/mechanisms/tvm/test_codec.py b/python/x402/tests/unit/mechanisms/tvm/test_codec.py new file mode 100644 index 0000000000..1d3d83e13e --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_codec.py @@ -0,0 +1,213 @@ +"""Focused tests for the exact TVM settlement payload codec.""" + +from __future__ import annotations + +import base64 + +import pytest + +pytest.importorskip("pytoniq_core") + +from pytoniq.contract.contract import Contract +from pytoniq_core import Address, Cell, begin_cell + +from x402.mechanisms.tvm.codecs.w5 import serialize_out_list, serialize_send_msg_action +from x402.mechanisms.tvm.constants import ( + ERR_EXACT_TVM_INVALID_SETTLEMENT_BOC, + ERR_EXACT_TVM_INVALID_W5_ACTIONS, + ERR_EXACT_TVM_INVALID_W5_MESSAGE, + JETTON_TRANSFER_OPCODE, + SEND_MODE_IGNORE_ERRORS, + SEND_MODE_PAY_FEES_SEPARATELY, + W5_INTERNAL_SIGNED_OPCODE, +) +from x402.mechanisms.tvm.exact.codec import parse_exact_tvm_payload + +PAYER = "0:" + "1" * 64 +SOURCE_WALLET = "0:" + "2" * 64 +DESTINATION = "0:" + "3" * 64 +RESPONSE_DESTINATION = "0:" + "4" * 64 + + +def _make_transfer_body( + *, + destination: str = DESTINATION, + response_destination: str | None = RESPONSE_DESTINATION, + amount: int = 123, + forward_ton_amount: int = 456, + forward_payload: Cell | None = None, +) -> Cell: + builder = ( + begin_cell() + .store_uint(JETTON_TRANSFER_OPCODE, 32) + .store_uint(0, 64) + .store_coins(amount) + .store_address(Address(destination)) + .store_address(Address(response_destination) if response_destination else None) + .store_bit(0) + .store_coins(forward_ton_amount) + ) + if forward_payload is None: + builder = builder.store_bit(0) + else: + builder = builder.store_bit(1).store_ref(forward_payload) + return builder.end_cell() + + +def _make_signed_body( + *, + action_cell: Cell | None = None, + opcode: int = W5_INTERNAL_SIGNED_OPCODE, + wallet_id: int = 7, + valid_until: int = 111, + seqno: int = 9, + has_actions: bool = True, + has_extra_actions: bool = False, + signature: bytes = b"\xaa" * 64, + trailing_bit: bool = False, +) -> Cell: + if action_cell is None: + out_msg = Contract.create_internal_msg( + src=None, + dest=Address(SOURCE_WALLET), + bounce=True, + value=999, + body=_make_transfer_body(forward_payload=begin_cell().store_uint(0xAB, 8).end_cell()), + ).serialize() + action_cell = serialize_send_msg_action(out_msg, SEND_MODE_PAY_FEES_SEPARATELY) + + builder = ( + begin_cell() + .store_uint(opcode, 32) + .store_uint(wallet_id, 32) + .store_uint(valid_until, 32) + .store_uint(seqno, 32) + ) + if has_actions: + builder = builder.store_bit(1).store_ref(serialize_out_list([action_cell])) + else: + builder = builder.store_bit(0) + builder = builder.store_bit(1 if has_extra_actions else 0).store_bytes(signature) + if trailing_bit: + builder = builder.store_bit(1) + return builder.end_cell() + + +def _make_settlement_boc( + *, + body: Cell | None = None, + bounce: bool = True, + internal: bool = True, +) -> str: + body = body or _make_signed_body() + if internal: + message = Contract.create_internal_msg( + src=None, + dest=Address(PAYER), + bounce=bounce, + value=0, + body=body, + ) + else: + message = Contract.create_external_msg( + dest=Address(PAYER), + body=body, + ) + return base64.b64encode(message.serialize().to_boc()).decode("ascii") + + +class TestParseExactTvmPayload: + def test_should_reject_malformed_boc(self): + with pytest.raises(ValueError, match=ERR_EXACT_TVM_INVALID_SETTLEMENT_BOC): + parse_exact_tvm_payload("not-base64") + + def test_should_reject_non_internal_message(self): + with pytest.raises(ValueError, match=ERR_EXACT_TVM_INVALID_SETTLEMENT_BOC): + parse_exact_tvm_payload(_make_settlement_boc(internal=False)) + + def test_should_accept_non_bounceable_settlement_wrapper(self): + payload = parse_exact_tvm_payload(_make_settlement_boc(bounce=False)) + + assert payload.payer == PAYER + assert payload.transfer.source_wallet == SOURCE_WALLET + + def test_should_reject_wrong_w5_opcode(self): + with pytest.raises(ValueError, match=ERR_EXACT_TVM_INVALID_W5_MESSAGE): + parse_exact_tvm_payload(_make_settlement_boc(body=_make_signed_body(opcode=0xDEADBEEF))) + + def test_should_reject_extra_actions_flag(self): + with pytest.raises(ValueError, match=ERR_EXACT_TVM_INVALID_W5_ACTIONS): + parse_exact_tvm_payload( + _make_settlement_boc(body=_make_signed_body(has_extra_actions=True)) + ) + + def test_should_reject_wrong_action_count(self): + with pytest.raises(ValueError, match=ERR_EXACT_TVM_INVALID_W5_ACTIONS): + parse_exact_tvm_payload(_make_settlement_boc(body=_make_signed_body(has_actions=False))) + + def test_should_reject_invalid_action_type(self): + invalid_action = ( + begin_cell() + .store_uint(0xDEADBEEF, 32) + .store_uint(0, 8) + .store_ref(Cell.empty()) + .end_cell() + ) + + with pytest.raises(ValueError, match=ERR_EXACT_TVM_INVALID_W5_ACTIONS): + parse_exact_tvm_payload( + _make_settlement_boc(body=_make_signed_body(action_cell=invalid_action)) + ) + + def test_should_reject_wrong_send_mode(self): + out_msg = Contract.create_internal_msg( + src=None, + dest=Address(SOURCE_WALLET), + bounce=True, + value=999, + body=_make_transfer_body(), + ).serialize() + wrong_mode_action = serialize_send_msg_action(out_msg, SEND_MODE_PAY_FEES_SEPARATELY + 1) + + with pytest.raises(ValueError, match=ERR_EXACT_TVM_INVALID_W5_ACTIONS): + parse_exact_tvm_payload( + _make_settlement_boc(body=_make_signed_body(action_cell=wrong_mode_action)) + ) + + def test_should_accept_ignore_errors_send_mode(self): + out_msg = Contract.create_internal_msg( + src=None, + dest=Address(SOURCE_WALLET), + bounce=True, + value=999, + body=_make_transfer_body(), + ).serialize() + acceptable_action = serialize_send_msg_action( + out_msg, + SEND_MODE_PAY_FEES_SEPARATELY + SEND_MODE_IGNORE_ERRORS, + ) + + payload = parse_exact_tvm_payload( + _make_settlement_boc(body=_make_signed_body(action_cell=acceptable_action)) + ) + + assert payload.transfer.source_wallet == SOURCE_WALLET + + def test_should_reject_trailing_bits_after_signature(self): + with pytest.raises(ValueError, match=ERR_EXACT_TVM_INVALID_W5_MESSAGE): + parse_exact_tvm_payload(_make_settlement_boc(body=_make_signed_body(trailing_bit=True))) + + def test_should_parse_valid_settlement_boc(self): + payload = parse_exact_tvm_payload(_make_settlement_boc()) + + assert payload.payer == PAYER + assert payload.wallet_id == 7 + assert payload.valid_until == 111 + assert payload.seqno == 9 + assert payload.transfer.source_wallet == SOURCE_WALLET + assert payload.transfer.destination == DESTINATION + assert payload.transfer.response_destination == RESPONSE_DESTINATION + assert payload.transfer.jetton_amount == 123 + assert payload.transfer.attached_ton_amount == 999 + assert payload.transfer.forward_ton_amount == 456 + assert payload.signature == b"\xaa" * 64 diff --git a/python/x402/tests/unit/mechanisms/tvm/test_constants.py b/python/x402/tests/unit/mechanisms/tvm/test_constants.py new file mode 100644 index 0000000000..4090ef8e05 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_constants.py @@ -0,0 +1,73 @@ +"""Tests for TVM error constant exports.""" + +from __future__ import annotations + +from x402.mechanisms.tvm import ( + ERR_EXACT_TVM_ACCOUNT_FROZEN, + ERR_EXACT_TVM_DUPLICATE_SETTLEMENT, + ERR_EXACT_TVM_FACILITATOR_INSUFFICIENT_BALANCE, + ERR_EXACT_TVM_INSUFFICIENT_BALANCE, + ERR_EXACT_TVM_INVALID_AMOUNT, + ERR_EXACT_TVM_INVALID_ASSET, + ERR_EXACT_TVM_INVALID_CODE_HASH, + ERR_EXACT_TVM_INVALID_EXTENSIONS_DICT, + ERR_EXACT_TVM_INVALID_JETTON_TRANSFER, + ERR_EXACT_TVM_INVALID_PAYLOAD, + ERR_EXACT_TVM_INVALID_RECIPIENT, + ERR_EXACT_TVM_INVALID_SEQNO, + ERR_EXACT_TVM_INVALID_SETTLEMENT_BOC, + ERR_EXACT_TVM_INVALID_SIGNATURE, + ERR_EXACT_TVM_INVALID_SIGNATURE_MODE, + ERR_EXACT_TVM_INVALID_UNTIL_EXPIRED, + ERR_EXACT_TVM_INVALID_W5_ACTIONS, + ERR_EXACT_TVM_INVALID_W5_MESSAGE, + ERR_EXACT_TVM_INVALID_WALLET_ID, + ERR_EXACT_TVM_NETWORK_MISMATCH, + ERR_EXACT_TVM_SIMULATION_FAILED, + ERR_EXACT_TVM_TON_AMOUNT_TOO_HIGH, + ERR_EXACT_TVM_TRANSACTION_FAILED, + ERR_EXACT_TVM_UNSUPPORTED_NETWORK, + ERR_EXACT_TVM_UNSUPPORTED_SCHEME, + ERR_EXACT_TVM_UNSUPPORTED_VERSION, + ERR_EXACT_TVM_VALID_UNTIL_TOO_FAR, +) + + +def test_should_export_canonical_tvm_error_constants() -> None: + assert ERR_EXACT_TVM_UNSUPPORTED_SCHEME == "unsupported_scheme" + assert ERR_EXACT_TVM_UNSUPPORTED_VERSION == "unsupported_version" + assert ERR_EXACT_TVM_UNSUPPORTED_NETWORK == "unsupported_network" + assert ERR_EXACT_TVM_NETWORK_MISMATCH == "network_mismatch" + assert ERR_EXACT_TVM_INVALID_PAYLOAD == "invalid_exact_tvm_payload" + assert ERR_EXACT_TVM_INVALID_SETTLEMENT_BOC == "invalid_exact_tvm_payload_settlement_boc" + assert ( + ERR_EXACT_TVM_INVALID_W5_MESSAGE == "invalid_exact_tvm_payload_w5_internal_signed_request" + ) + assert ERR_EXACT_TVM_INVALID_W5_ACTIONS == "invalid_exact_tvm_payload_w5_actions" + assert ERR_EXACT_TVM_INVALID_JETTON_TRANSFER == "invalid_exact_tvm_payload_jetton_transfer" + assert ERR_EXACT_TVM_INVALID_SIGNATURE == "invalid_exact_tvm_payload_invalid_signature" + assert ERR_EXACT_TVM_INVALID_CODE_HASH == "invalid_exact_tvm_payload_invalid_code_hash" + assert ERR_EXACT_TVM_INVALID_ASSET == "invalid_exact_tvm_payload_asset_mismatch" + assert ERR_EXACT_TVM_INVALID_RECIPIENT == "invalid_exact_tvm_payload_recipient_mismatch" + assert ERR_EXACT_TVM_INVALID_AMOUNT == "invalid_exact_tvm_payload_amount_mismatch" + assert ( + ERR_EXACT_TVM_INVALID_SIGNATURE_MODE == "invalid_exact_tvm_payload_signature_mode_mismatch" + ) + assert ERR_EXACT_TVM_INVALID_SEQNO == "invalid_exact_tvm_payload_seqno_mismatch" + assert ERR_EXACT_TVM_INVALID_WALLET_ID == "invalid_exact_tvm_payload_wallet_id_mismatch" + assert ( + ERR_EXACT_TVM_INVALID_EXTENSIONS_DICT + == "invalid_exact_tvm_payload_extensions_dict_mismatch" + ) + assert ( + ERR_EXACT_TVM_TON_AMOUNT_TOO_HIGH + == "invalid_exact_tvm_payload_attached_ton_amount_too_high" + ) + assert ERR_EXACT_TVM_ACCOUNT_FROZEN == "account_frozen" + assert ERR_EXACT_TVM_INVALID_UNTIL_EXPIRED == "invalid_exact_tvm_payload_valid_until_expired" + assert ERR_EXACT_TVM_VALID_UNTIL_TOO_FAR == "invalid_exact_tvm_payload_valid_until_too_far" + assert ERR_EXACT_TVM_INSUFFICIENT_BALANCE == "insufficient_balance" + assert ERR_EXACT_TVM_FACILITATOR_INSUFFICIENT_BALANCE == "facilitator_insufficient_balance" + assert ERR_EXACT_TVM_DUPLICATE_SETTLEMENT == "duplicate_settlement" + assert ERR_EXACT_TVM_SIMULATION_FAILED == "simulation_failed" + assert ERR_EXACT_TVM_TRANSACTION_FAILED == "transaction_failed" diff --git a/python/x402/tests/unit/mechanisms/tvm/test_facilitator.py b/python/x402/tests/unit/mechanisms/tvm/test_facilitator.py new file mode 100644 index 0000000000..2fc90f305f --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_facilitator.py @@ -0,0 +1,660 @@ +"""Tests for the exact TVM facilitator scheme.""" + +from __future__ import annotations + +import time +from dataclasses import dataclass + +import pytest + +pytest.importorskip("pytoniq_core") + +from pytoniq_core import begin_cell + +import x402.mechanisms.tvm.exact.facilitator as facilitator_module +from x402.mechanisms.tvm import ( + DEFAULT_SETTLEMENT_CONFIRMATION_WORKERS, + TVM_TESTNET, + SettlementCache, + TvmAccountState, +) +from x402.mechanisms.tvm.constants import ( + DEFAULT_JETTON_WALLET_MESSAGE_AMOUNT, + DEFAULT_TVM_OUTER_GAS_BUFFER, + ERR_EXACT_TVM_ACCOUNT_FROZEN, + ERR_EXACT_TVM_DUPLICATE_SETTLEMENT, + ERR_EXACT_TVM_FACILITATOR_INSUFFICIENT_BALANCE, + ERR_EXACT_TVM_INVALID_AMOUNT, + ERR_EXACT_TVM_INVALID_ASSET, + ERR_EXACT_TVM_INVALID_JETTON_TRANSFER, + ERR_EXACT_TVM_INVALID_PAYLOAD, + ERR_EXACT_TVM_INVALID_RECIPIENT, + ERR_EXACT_TVM_INVALID_SIGNATURE, + ERR_EXACT_TVM_INVALID_UNTIL_EXPIRED, + ERR_EXACT_TVM_NETWORK_MISMATCH, + ERR_EXACT_TVM_SIMULATION_FAILED, + ERR_EXACT_TVM_TON_AMOUNT_TOO_HIGH, + ERR_EXACT_TVM_TRANSACTION_FAILED, + ERR_EXACT_TVM_UNSUPPORTED_NETWORK, + ERR_EXACT_TVM_UNSUPPORTED_SCHEME, + ERR_EXACT_TVM_UNSUPPORTED_VERSION, + ERR_EXACT_TVM_VALID_UNTIL_TOO_FAR, +) +from x402.mechanisms.tvm.exact import ExactTvmFacilitatorScheme +from x402.mechanisms.tvm.trace_utils import body_hash_to_base64 + +from .builders import ( + ASSET, + FACILITATOR, + PAYER, + SOURCE_WALLET, + SPONSORED_FORWARDING_EXTRA, + make_tvm_payload, + make_tvm_requirements, + make_tvm_settlement, +) +from .fakes import FacilitatorSignerStub + + +class _FakeBatcher: + def __init__( + self, + signer, + settlement_cache, + *, + flush_interval_seconds: float, + batch_flush_size: int, + confirmation_workers: int, + confirmation_timeout_seconds: float, + settlement_verifier, + ) -> None: + _ = signer, settlement_cache, flush_interval_seconds, batch_flush_size + _ = confirmation_timeout_seconds, settlement_verifier + self.confirmation_workers = confirmation_workers + self.enqueued: list[object] = [] + self.result = facilitator_module._BatchResult(success=True, transaction="trace-tx-hash") + self.error: Exception | None = None + + def enqueue(self, queued_settlement): + self.enqueued.append(queued_settlement) + if self.error is not None: + raise self.error + return self.result + + +def _assert_invalid_verify(result, reason: str, *, message: str | None = None) -> None: + assert result.is_valid is False + assert result.invalid_reason == reason + if message is not None: + assert result.invalid_message == message + + +def _assert_failed_settlement(result, reason: str, *, message: str | None = None) -> None: + assert result.success is False + assert result.error_reason == reason + assert result.transaction == "" + assert result.network == TVM_TESTNET + if message is not None: + assert result.error_message == message + + +def _make_requirements(**overrides): + return make_tvm_requirements(default_extra=SPONSORED_FORWARDING_EXTRA, **overrides) + + +def _make_payload(**overrides): + return make_tvm_payload(default_accepted_extra=SPONSORED_FORWARDING_EXTRA, **overrides) + + +@dataclass +class _FacilitatorEnv: + facilitator: ExactTvmFacilitatorScheme + signer: FacilitatorSignerStub + settlement: object + batchers: list[_FakeBatcher] + + def batcher(self) -> _FakeBatcher: + return self.batchers[-1] + + +@pytest.fixture +def facilitator_env(monkeypatch): + batchers: list[_FakeBatcher] = [] + + def _batcher_factory(*args, **kwargs): + batcher = _FakeBatcher(*args, **kwargs) + batchers.append(batcher) + return batcher + + signer = FacilitatorSignerStub() + settlement = make_tvm_settlement() + monkeypatch.setattr(facilitator_module, "_SettlementBatcher", _batcher_factory) + monkeypatch.setattr(facilitator_module, "parse_exact_tvm_payload", lambda boc: settlement) + monkeypatch.setattr( + facilitator_module, + "parse_active_w5_account_state", + lambda account: facilitator_module.W5InitData( + signature_allowed=True, + seqno=settlement.seqno, + wallet_id=settlement.wallet_id, + public_key=b"\x01" * 32, + extensions_dict=None, + ), + ) + monkeypatch.setattr(facilitator_module, "verify_w5_signature", lambda *args: True) + monkeypatch.setattr( + facilitator_module, + "trace_transaction_storage_fees", + lambda tx: 10_000, + ) + monkeypatch.setattr( + facilitator_module, + "trace_transaction_compute_fees", + lambda tx: 20_000, + ) + monkeypatch.setattr( + facilitator_module, + "trace_transaction_fwd_fees", + lambda tx, **kwargs: 30_000, + ) + monkeypatch.setattr( + ExactTvmFacilitatorScheme, + "_verify_finalized_trace_settlement", + staticmethod(lambda *args, **kwargs: {"hash": "payer-tx"}), + ) + + facilitator = ExactTvmFacilitatorScheme(signer, SettlementCache()) + return _FacilitatorEnv( + facilitator=facilitator, + signer=signer, + settlement=settlement, + batchers=batchers, + ) + + +class TestExactTvmFacilitatorSchemeConstructor: + def test_should_create_instance_with_correct_scheme(self, facilitator_env): + facilitator = facilitator_env.facilitator + + assert facilitator.scheme == "exact" + assert facilitator.caip_family == "tvm:*" + + def test_should_return_supported_extra_and_signers(self, facilitator_env): + facilitator = facilitator_env.facilitator + + assert facilitator.get_extra(TVM_TESTNET) == {"areFeesSponsored": True} + assert facilitator.get_extra("tvm:123") is None + assert facilitator.get_signers(TVM_TESTNET) == [FACILITATOR] + + def test_should_use_default_confirmation_worker_count(self, facilitator_env): + batcher = facilitator_env.batcher() + + assert batcher.confirmation_workers == DEFAULT_SETTLEMENT_CONFIRMATION_WORKERS + + +class TestVerify: + @pytest.mark.parametrize( + ("payload_overrides", "requirements_overrides", "expected_reason"), + [ + pytest.param( + {"x402_version": 1}, + {}, + ERR_EXACT_TVM_UNSUPPORTED_VERSION, + id="unsupported-x402-version", + ), + pytest.param( + {"accepted_scheme": "wrong"}, + {}, + ERR_EXACT_TVM_UNSUPPORTED_SCHEME, + id="wrong-scheme", + ), + pytest.param( + {"accepted_network": "tvm:123"}, + {"network": "tvm:123"}, + ERR_EXACT_TVM_UNSUPPORTED_NETWORK, + id="unsupported-network", + ), + pytest.param( + {"accepted_network": "tvm:-239"}, + {"network": TVM_TESTNET}, + ERR_EXACT_TVM_NETWORK_MISMATCH, + id="network-mismatch", + ), + pytest.param( + {"accepted_amount": "101"}, + {"amount": "100"}, + ERR_EXACT_TVM_INVALID_AMOUNT, + id="amount-mismatch", + ), + pytest.param( + {"payload_asset": "0:" + "9" * 64}, + {}, + ERR_EXACT_TVM_INVALID_ASSET, + id="asset-mismatch", + ), + pytest.param( + {"accepted_pay_to": "0:" + "8" * 64}, + {}, + ERR_EXACT_TVM_INVALID_RECIPIENT, + id="payee-mismatch", + ), + pytest.param( + {"accepted_extra": {"forwardTonAmount": "1"}}, + {}, + ERR_EXACT_TVM_INVALID_JETTON_TRANSFER, + id="forward-amount-mismatch", + ), + ], + ) + def test_should_reject_invalid_payment_metadata( + self, + facilitator_env, + payload_overrides, + requirements_overrides, + expected_reason, + ): + facilitator = facilitator_env.facilitator + + result = facilitator.verify( + _make_payload(**payload_overrides), + _make_requirements(**requirements_overrides), + ) + + _assert_invalid_verify(result, expected_reason) + + def test_should_reject_forward_payload_mismatch(self, facilitator_env, monkeypatch): + facilitator = facilitator_env.facilitator + monkeypatch.setattr( + facilitator_module, + "parse_exact_tvm_payload", + lambda boc: make_tvm_settlement( + forward_payload=begin_cell().store_uint(0xABCD, 16).end_cell() + ), + ) + + result = facilitator.verify(_make_payload(), _make_requirements()) + + _assert_invalid_verify(result, ERR_EXACT_TVM_INVALID_JETTON_TRANSFER) + + def test_should_reject_attached_ton_amount_above_reasonable_cap( + self, facilitator_env, monkeypatch + ): + facilitator = facilitator_env.facilitator + monkeypatch.setattr( + facilitator_module, + "parse_exact_tvm_payload", + lambda boc: make_tvm_settlement( + attached_ton_amount=DEFAULT_JETTON_WALLET_MESSAGE_AMOUNT + 1, + ), + ) + + result = facilitator.verify(_make_payload(), _make_requirements()) + + _assert_invalid_verify(result, ERR_EXACT_TVM_TON_AMOUNT_TOO_HIGH) + + def test_should_reject_payload_missing_settlement_boc(self, facilitator_env): + facilitator = facilitator_env.facilitator + + result = facilitator.verify( + _make_payload(payload={"asset": ASSET}), + _make_requirements(), + ) + + _assert_invalid_verify( + result, + ERR_EXACT_TVM_INVALID_PAYLOAD, + message="Exact TVM payload field 'settlementBoc' is required", + ) + + def test_should_reject_expired_settlement(self, facilitator_env, monkeypatch): + facilitator = facilitator_env.facilitator + settlement = facilitator_env.settlement + monkeypatch.setattr( + facilitator_module, + "parse_exact_tvm_payload", + lambda boc: make_tvm_settlement( + valid_until=int(time.time()) - 1, + seqno=settlement.seqno, + ), + ) + + result = facilitator.verify(_make_payload(), _make_requirements()) + + _assert_invalid_verify(result, ERR_EXACT_TVM_INVALID_UNTIL_EXPIRED) + + def test_should_reject_valid_until_beyond_timeout(self, facilitator_env, monkeypatch): + facilitator = facilitator_env.facilitator + monkeypatch.setattr( + facilitator_module, + "parse_exact_tvm_payload", + lambda boc: make_tvm_settlement(valid_until=int(time.time()) + 600), + ) + + result = facilitator.verify(_make_payload(), _make_requirements(max_timeout_seconds=300)) + + _assert_invalid_verify(result, ERR_EXACT_TVM_VALID_UNTIL_TOO_FAR) + + def test_should_reject_invalid_signature(self, facilitator_env, monkeypatch): + facilitator = facilitator_env.facilitator + monkeypatch.setattr(facilitator_module, "verify_w5_signature", lambda *args: False) + + result = facilitator.verify(_make_payload(), _make_requirements()) + + _assert_invalid_verify(result, ERR_EXACT_TVM_INVALID_SIGNATURE) + + def test_should_reject_frozen_account_state(self, facilitator_env): + facilitator = facilitator_env.facilitator + signer = facilitator_env.signer + signer.account_state = TvmAccountState( + address=PAYER, + balance=0, + is_active=False, + is_frozen=True, + is_uninitialized=False, + state_init=None, + ) + + result = facilitator.verify(_make_payload(), _make_requirements()) + + _assert_invalid_verify(result, ERR_EXACT_TVM_ACCOUNT_FROZEN) + + def test_should_reject_facilitator_with_insufficient_ton_balance(self, facilitator_env): + facilitator = facilitator_env.facilitator + signer = facilitator_env.signer + signer.facilitator_account_state = TvmAccountState( + address=signer.facilitator_account_state.address, + balance=1_000_000_000, + is_active=True, + is_frozen=False, + is_uninitialized=False, + state_init=None, + ) + + result = facilitator.verify(_make_payload(), _make_requirements()) + + _assert_invalid_verify(result, ERR_EXACT_TVM_FACILITATOR_INSUFFICIENT_BALANCE) + + def test_should_ignore_settlement_state_init_for_active_account( + self, facilitator_env, monkeypatch + ): + facilitator = facilitator_env.facilitator + signer = facilitator_env.signer + parse_active_calls: list[TvmAccountState] = [] + + def _parse_active(account: TvmAccountState) -> facilitator_module.W5InitData: + parse_active_calls.append(account) + return facilitator_module.W5InitData( + signature_allowed=True, + seqno=12, + wallet_id=777, + public_key=b"\x01" * 32, + extensions_dict=None, + ) + + monkeypatch.setattr(facilitator_module, "parse_active_w5_account_state", _parse_active) + monkeypatch.setattr( + facilitator_module, + "parse_w5_init_data", + lambda state_init: pytest.fail("active accounts should use on-chain state"), + ) + monkeypatch.setattr( + facilitator_module, + "parse_exact_tvm_payload", + lambda boc: make_tvm_settlement(state_init=object()), + ) + + result = facilitator.verify(_make_payload(), _make_requirements()) + + assert result.is_valid is True + assert parse_active_calls == [signer.account_state] + + def test_should_return_valid_response_for_matching_payload(self, facilitator_env): + facilitator = facilitator_env.facilitator + + result = facilitator.verify(_make_payload(), _make_requirements()) + + assert result.is_valid is True + assert result.payer == PAYER + + +class TestSettle: + @pytest.mark.parametrize( + ("payload_overrides", "requirements_overrides", "expected_reason"), + [ + pytest.param( + {"x402_version": 1}, + {}, + ERR_EXACT_TVM_UNSUPPORTED_VERSION, + id="unsupported-x402-version", + ), + pytest.param( + {"accepted_scheme": "wrong"}, + {}, + ERR_EXACT_TVM_UNSUPPORTED_SCHEME, + id="verification-fails", + ), + ], + ) + def test_should_fail_settlement_for_invalid_payment_metadata( + self, + facilitator_env, + payload_overrides, + requirements_overrides, + expected_reason, + ): + facilitator = facilitator_env.facilitator + + result = facilitator.settle( + _make_payload(**payload_overrides), + _make_requirements(**requirements_overrides), + ) + + _assert_failed_settlement(result, expected_reason) + + def test_should_fail_settlement_when_payload_is_missing_required_field(self, facilitator_env): + facilitator = facilitator_env.facilitator + + result = facilitator.settle( + _make_payload(payload={"settlementBoc": "base64-boc=="}), + _make_requirements(), + ) + + _assert_failed_settlement( + result, + ERR_EXACT_TVM_INVALID_PAYLOAD, + message="Exact TVM payload field 'asset' is required", + ) + + def test_should_reject_duplicate_settlement(self, facilitator_env): + facilitator = facilitator_env.facilitator + + first = facilitator.settle(_make_payload(), _make_requirements()) + second = facilitator.settle(_make_payload(), _make_requirements()) + + assert first.success is True + _assert_failed_settlement(second, ERR_EXACT_TVM_DUPLICATE_SETTLEMENT) + assert second.payer == PAYER + + def test_should_return_successful_settlement_response(self, facilitator_env): + facilitator = facilitator_env.facilitator + batcher = facilitator_env.batcher() + + result = facilitator.settle(_make_payload(), _make_requirements()) + + assert result.success is True + assert result.transaction == "trace-tx-hash" + assert result.payer == PAYER + assert result.network == TVM_TESTNET + assert len(batcher.enqueued) == 1 + queued = batcher.enqueued[0] + assert queued.network == TVM_TESTNET + assert queued.settlement_hash == "settlement-hash-1" + assert queued.relay_request.destination == PAYER + assert queued.relay_request.relay_amount == ( + 500_000 + 10_000 + 20_000 + 30_000 + DEFAULT_TVM_OUTER_GAS_BUFFER + ) + + def test_should_convert_batcher_exceptions_into_transaction_failed(self, facilitator_env): + facilitator = facilitator_env.facilitator + batcher = facilitator_env.batcher() + batcher.error = RuntimeError("boom") + + result = facilitator.settle(_make_payload(), _make_requirements()) + + _assert_failed_settlement(result, ERR_EXACT_TVM_TRANSACTION_FAILED, message="boom") + + def test_should_map_unexpected_verification_exception_to_simulation_failed( + self, facilitator_env, monkeypatch + ): + facilitator = facilitator_env.facilitator + monkeypatch.setattr( + facilitator_module, + "parse_exact_tvm_payload", + lambda boc: (_ for _ in ()).throw(RuntimeError("decode crashed")), + ) + + result = facilitator.settle(_make_payload(), _make_requirements()) + + _assert_failed_settlement( + result, + ERR_EXACT_TVM_SIMULATION_FAILED, + message="decode crashed", + ) + + +def _make_trace( + *, + include_payer_tx: bool = True, + payer_tx_success: bool = True, + include_matching_payer_out_msg: bool = True, + include_source_wallet_tx: bool = True, + payer_hash: str | None = "q6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6s=", + payer_hash_norm: str | None = "payer-tx-hash-norm", +): + settlement = make_tvm_settlement() + transactions: dict[str, object] = {} + if include_payer_tx: + transactions["payer"] = { + "hash": payer_hash, + **({"hash_norm": payer_hash_norm} if payer_hash_norm is not None else {}), + "account": PAYER, + "description": { + "aborted": not payer_tx_success, + "compute_ph": {"success": payer_tx_success, "skipped": False}, + "action": {"success": payer_tx_success}, + }, + "in_msg": { + "message_content": {"hash": body_hash_to_base64(settlement.body.hash)}, + }, + "out_msgs": ( + [ + { + "hash": "payer-out-hash", + "destination": SOURCE_WALLET, + "message_content": { + "hash": body_hash_to_base64(settlement.transfer.body_hash or b""), + }, + } + ] + if include_matching_payer_out_msg + else [] + ), + } + if include_source_wallet_tx: + transactions["source"] = { + "hash": "source-tx-hash", + "account": SOURCE_WALLET, + "description": { + "aborted": False, + "compute_ph": {"success": True, "skipped": False}, + "action": {"success": True}, + }, + "in_msg": { + "hash": "payer-out-hash", + }, + } + return settlement, {"transactions": transactions} + + +class TestVerifyFinalizedTraceSettlement: + def test_should_fail_when_trace_has_no_matching_payer_wallet_transaction(self): + settlement, trace = _make_trace(include_payer_tx=False) + + with pytest.raises(ValueError, match="expected payer wallet transaction"): + ExactTvmFacilitatorScheme._verify_finalized_trace_settlement( + trace, + settlement=settlement, + ) + + def test_should_ignore_failed_payer_wallet_transactions(self): + settlement, trace = _make_trace(payer_tx_success=False) + + with pytest.raises(ValueError, match="expected payer wallet transaction"): + ExactTvmFacilitatorScheme._verify_finalized_trace_settlement( + trace, + settlement=settlement, + ) + + def test_should_fail_when_payer_wallet_transaction_has_no_matching_out_message(self): + settlement, trace = _make_trace(include_matching_payer_out_msg=False) + + with pytest.raises(ValueError, match="missing out message hash"): + ExactTvmFacilitatorScheme._verify_finalized_trace_settlement( + trace, + settlement=settlement, + ) + + def test_should_fail_when_trace_has_no_matching_source_wallet_transaction(self): + settlement, trace = _make_trace(include_source_wallet_tx=False) + + with pytest.raises(ValueError, match="expected source jetton wallet transaction"): + ExactTvmFacilitatorScheme._verify_finalized_trace_settlement( + trace, + settlement=settlement, + ) + + def test_should_fail_when_payer_wallet_transaction_has_no_hash(self): + settlement, trace = _make_trace(payer_hash="", payer_hash_norm="") + + with pytest.raises(ValueError, match="missing transaction hash"): + ExactTvmFacilitatorScheme._verify_finalized_trace_settlement( + trace, + settlement=settlement, + ) + + def test_should_return_payer_transaction_hash_for_valid_trace(self): + settlement, trace = _make_trace( + payer_hash="q6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6s=", + payer_hash_norm="q6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6s=", + ) + + result = ExactTvmFacilitatorScheme._verify_finalized_trace_settlement( + trace, + settlement=settlement, + ) + + assert result == "ab" * 32 + + def test_should_prefer_normalized_payer_transaction_hash_when_present(self): + settlement, trace = _make_trace( + payer_hash="q6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6s=", + payer_hash_norm="zMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMw=", + ) + + result = ExactTvmFacilitatorScheme._verify_finalized_trace_settlement( + trace, + settlement=settlement, + ) + + assert result == "cc" * 32 + + def test_should_return_payer_transaction_object_when_requested(self): + settlement, trace = _make_trace(payer_hash_norm=None) + + result = ExactTvmFacilitatorScheme._verify_finalized_trace_settlement( + trace, + settlement=settlement, + return_transaction=True, + ) + + assert result["hash"] == "q6urq6urq6urq6urq6urq6urq6urq6urq6urq6urq6s=" diff --git a/python/x402/tests/unit/mechanisms/tvm/test_highload_v3.py b/python/x402/tests/unit/mechanisms/tvm/test_highload_v3.py new file mode 100644 index 0000000000..17ebb8a78d --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_highload_v3.py @@ -0,0 +1,17 @@ +"""Focused tests for Highload V3 codecs.""" + +from __future__ import annotations + +import pytest + +pytest.importorskip("pytoniq_core") + +from pytoniq_core import begin_cell + +from x402.mechanisms.tvm.codecs.highload_v3 import _bitmap_contains + + +def test_bitmap_contains_should_return_false_for_out_of_range_bit_number(): + bitmap = begin_cell().store_uint(0b101, 3).end_cell() + + assert _bitmap_contains(bitmap, 3) is False diff --git a/python/x402/tests/unit/mechanisms/tvm/test_index.py b/python/x402/tests/unit/mechanisms/tvm/test_index.py new file mode 100644 index 0000000000..fddee13dea --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_index.py @@ -0,0 +1,128 @@ +"""Tests for TVM mechanism exports.""" + +from __future__ import annotations + +import pytest + +pytest.importorskip("pytoniq_core") + +import x402.mechanisms.tvm as tvm_module +import x402.mechanisms.tvm.constants as constants_module +from x402.mechanisms.tvm import ( + DEFAULT_JETTON_WALLET_MESSAGE_AMOUNT, + DEFAULT_SETTLEMENT_BATCH_MAX_SIZE, + DEFAULT_STREAMING_CONFIRMATION_GRACE_SECONDS, + DEFAULT_TVM_EMULATION_ADDRESS, + DEFAULT_TVM_EMULATION_RELAY_AMOUNT, + DEFAULT_TVM_EMULATION_SEQNO, + DEFAULT_TVM_EMULATION_WALLET_ID, + DEFAULT_TVM_INNER_GAS_BUFFER, + DEFAULT_TVM_OUTER_GAS_BUFFER, + HIGHLOAD_V3_CODE_HEX, + MIN_FACILITATOR_TON_BALANCE, + SCHEME_EXACT, + SEND_MODE_IGNORE_ERRORS, + SEND_MODE_PAY_FEES_SEPARATELY, + SUPPORTED_NETWORKS, + TVM_MAINNET, + TVM_PROVIDER_TONAPI, + TVM_PROVIDER_TONCENTER, + TVM_TESTNET, + W5_EXTERNAL_SIGNED_OPCODE, + W5R1_CODE_HASH, + ClientTvmSigner, + ExactTvmPayload, + FacilitatorHighloadV3Signer, + FacilitatorTvmSigner, + SettlementCache, + TonapiRestClient, + ToncenterRestClient, + WalletV5R1MnemonicSigner, + create_tvm_provider_client, + get_network_global_id, + normalize_address, + parse_amount, + parse_money_to_decimal, +) +from x402.mechanisms.tvm.exact import ( + ExactTvmClientScheme, + ExactTvmFacilitatorScheme, + ExactTvmScheme, + ExactTvmServerScheme, +) + + +class TestExports: + def test_should_export_main_classes(self): + assert ExactTvmScheme is ExactTvmClientScheme + assert ExactTvmClientScheme is not None + assert ExactTvmServerScheme is not None + assert ExactTvmFacilitatorScheme is not None + + def test_should_export_signer_protocols_and_implementations(self): + assert ClientTvmSigner is not None + assert FacilitatorTvmSigner is not None + assert WalletV5R1MnemonicSigner is not None + assert FacilitatorHighloadV3Signer is not None + + def test_should_export_provider_and_payload_types(self): + assert ToncenterRestClient is not None + assert TonapiRestClient is not None + assert create_tvm_provider_client is not None + assert TVM_PROVIDER_TONCENTER == "toncenter" + assert TVM_PROVIDER_TONAPI == "tonapi" + assert ExactTvmPayload is not None + assert SettlementCache is not None + + def test_should_export_tvm_runtime_constants(self): + assert DEFAULT_JETTON_WALLET_MESSAGE_AMOUNT == 30_000_000 + assert MIN_FACILITATOR_TON_BALANCE == 1_040_000_000 + assert DEFAULT_TVM_INNER_GAS_BUFFER == 7_100_000 + assert DEFAULT_TVM_OUTER_GAS_BUFFER == 500_000 + assert DEFAULT_STREAMING_CONFIRMATION_GRACE_SECONDS == 3.0 + assert DEFAULT_SETTLEMENT_BATCH_MAX_SIZE == 185 + assert DEFAULT_TVM_EMULATION_ADDRESS.startswith("0:") + assert DEFAULT_TVM_EMULATION_WALLET_ID == 2147483409 + assert DEFAULT_TVM_EMULATION_SEQNO == 1 + assert DEFAULT_TVM_EMULATION_RELAY_AMOUNT == 130_000_000 + + def test_should_export_tvm_opcode_and_send_mode_constants(self): + assert SEND_MODE_PAY_FEES_SEPARATELY + SEND_MODE_IGNORE_ERRORS == 3 + assert W5_EXTERNAL_SIGNED_OPCODE == 0x7369676E + assert len(W5R1_CODE_HASH) == 64 + assert HIGHLOAD_V3_CODE_HEX.startswith("b5ee9c") + + def test_should_reexport_public_constants_module_surface(self): + missing = [ + name + for name in dir(constants_module) + if name.isupper() and not hasattr(tvm_module, name) + ] + assert missing == [] + + +class TestNetworkUtilities: + def test_should_export_supported_networks(self): + assert SUPPORTED_NETWORKS == {TVM_MAINNET, TVM_TESTNET} + + def test_should_extract_global_id_from_caip2_network(self): + assert get_network_global_id(TVM_MAINNET) == -239 + assert get_network_global_id(TVM_TESTNET) == -3 + + def test_should_export_scheme_exact(self): + assert SCHEME_EXACT == "exact" + + +class TestAmountUtilities: + def test_should_parse_amount_using_decimals(self): + assert parse_amount("0.001", 6) == 1000 + assert parse_amount("1", 6) == 1000000 + + def test_should_parse_money_strings_without_currency_noise(self): + assert parse_money_to_decimal("$0.10") == 0.1 + assert parse_money_to_decimal("2.5 USDT") == 2.5 + + def test_should_normalize_raw_addresses(self): + raw = "0:" + "1" * 64 + + assert normalize_address(raw) == raw diff --git a/python/x402/tests/unit/mechanisms/tvm/test_provider.py b/python/x402/tests/unit/mechanisms/tvm/test_provider.py new file mode 100644 index 0000000000..3ebbd60658 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_provider.py @@ -0,0 +1,641 @@ +"""Focused tests for the Toncenter TVM provider client.""" + +from __future__ import annotations + +import base64 +import json +import logging + +import httpx +import pytest + +pytest.importorskip("pytoniq_core") + +from pytoniq.contract.contract import Contract +from pytoniq_core import Address, begin_cell + +import x402.mechanisms.tvm.provider as provider_module +from x402.mechanisms.tvm import ( + DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, + TONAPI_MAINNET_BASE_URL, + TONAPI_TESTNET_BASE_URL, + TVM_MAINNET, + TVM_PROVIDER_TONAPI, + TVM_TESTNET, +) +from x402.mechanisms.tvm.provider import ( + TonapiRestClient, + ToncenterRestClient, + _default_base_url, + create_tvm_provider_client, +) + + +def _cell_b64(value: int) -> str: + return base64.b64encode(begin_cell().store_uint(value, 8).end_cell().to_boc()).decode("ascii") + + +def _cell_hex(value: int) -> str: + return begin_cell().store_uint(value, 8).end_cell().to_boc().hex() + + +def _address_cell_b64(address: str) -> str: + return base64.b64encode( + begin_cell().store_address(Address(address)).end_cell().to_boc() + ).decode("ascii") + + +def _address_cell_hex(address: str) -> str: + return begin_cell().store_address(Address(address)).end_cell().to_boc().hex() + + +class _FakeHttpClient: + def __init__(self, responses): + self.responses = list(responses) + self.calls: list[tuple[str, str, object]] = [] + self.closed = False + + def request(self, method: str, path: str, **kwargs): + self.calls.append((method, path, kwargs)) + response = self.responses.pop(0) + if isinstance(response, Exception): + raise response + return response + + def close(self): + self.closed = True + + +def _json_response( + status_code: int, + data, + *, + path: str = "/api/test", + headers: dict[str, str] | None = None, +): + request = httpx.Request("GET", f"https://toncenter.example{path}") + return httpx.Response( + status_code, + content=json.dumps(data).encode("utf-8"), + request=request, + headers={"Content-Type": "application/json", **(headers or {})}, + ) + + +class TestDefaultBaseUrl: + def test_should_select_default_base_url_for_supported_networks(self): + assert _default_base_url(TVM_MAINNET) == "https://toncenter.com" + assert _default_base_url(TVM_TESTNET) == "https://testnet.toncenter.com" + assert _default_base_url(TVM_MAINNET, TVM_PROVIDER_TONAPI) == TONAPI_MAINNET_BASE_URL + assert _default_base_url(TVM_TESTNET, TVM_PROVIDER_TONAPI) == TONAPI_TESTNET_BASE_URL + assert _default_base_url(TVM_TESTNET, " TonAPI ") == TONAPI_TESTNET_BASE_URL + + def test_should_reject_unsupported_network(self): + with pytest.raises(ValueError, match="Unsupported TVM network"): + _default_base_url("tvm:123") + + def test_should_reject_unsupported_provider(self): + with pytest.raises(ValueError, match="Unsupported TVM provider"): + _default_base_url(TVM_TESTNET, "unknown") + + +class TestProviderFactory: + def test_should_create_toncenter_client_by_default(self): + client = create_tvm_provider_client(TVM_TESTNET) + + try: + assert isinstance(client, ToncenterRestClient) + finally: + client.close() + + def test_should_create_tonapi_client_when_selected(self): + client = create_tvm_provider_client(TVM_TESTNET, provider=" TonAPI ") + + try: + assert isinstance(client, TonapiRestClient) + finally: + client.close() + + +class TestToncenterRestClientParsing: + def test_emulate_trace_should_forward_ignore_chksig_flag(self): + client = ToncenterRestClient(TVM_TESTNET) + fake_http = _FakeHttpClient( + [_json_response(200, {"transactions": {}}, path="/api/emulate/v1/emulateTrace")] + ) + client._client = fake_http + + client.emulate_trace(b"boc-bytes", ignore_chksig=True) + + assert len(fake_http.calls) == 1 + method, path, kwargs = fake_http.calls[0] + assert method == "POST" + assert path == "/api/emulate/v1/emulateTrace" + assert kwargs["json"]["ignore_chksig"] is True + assert kwargs["json"]["with_actions"] is True + assert kwargs["timeout"] == DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS + + def test_emulate_trace_should_allow_custom_timeout(self): + client = ToncenterRestClient(TVM_TESTNET) + fake_http = _FakeHttpClient( + [_json_response(200, {"transactions": {}}, path="/api/emulate/v1/emulateTrace")] + ) + client._client = fake_http + + client.emulate_trace(b"boc-bytes", timeout=9.5) + + assert len(fake_http.calls) == 1 + _, _, kwargs = fake_http.calls[0] + assert kwargs["timeout"] == 9.5 + + def test_get_account_state_should_decode_active_state_init(self): + client = ToncenterRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [ + _json_response( + 200, + { + "accounts": [ + { + "address": "EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c", + "balance": "123", + "status": "active", + "code_boc": _cell_b64(1), + "data_boc": _cell_b64(2), + } + ] + }, + path="/api/v3/accountStates", + ) + ] + ) + + account = client.get_account_state("0:" + "0" * 64) + + assert account.address == "0:" + "0" * 64 + assert account.balance == 123 + assert account.is_active is True + assert account.is_uninitialized is False + assert account.state_init is not None + + def test_get_account_state_should_decode_uninitialized_account_without_state_init(self): + client = ToncenterRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [ + _json_response( + 200, + { + "accounts": [ + { + "address": "0:" + "1" * 64, + "balance": "0", + "status": "uninit", + } + ] + }, + path="/api/v3/accountStates", + ) + ] + ) + + account = client.get_account_state("0:" + "1" * 64) + + assert account.is_active is False + assert account.is_uninitialized is True + assert account.state_init is None + + def test_get_account_state_should_return_synthetic_uninitialized_state_for_empty_accounts(self): + client = ToncenterRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [ + _json_response( + 200, + {"accounts": []}, + path="/api/v3/accountStates", + ) + ] + ) + + account = client.get_account_state("0:" + "2" * 64) + + assert account.address == "0:" + "2" * 64 + assert account.balance == 0 + assert account.is_active is False + assert account.is_uninitialized is True + assert account.is_frozen is False + assert account.state_init is None + + def test_run_get_method_should_reject_non_zero_exit_code(self): + client = ToncenterRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [_json_response(200, {"exit_code": 1, "stack": []}, path="/api/v3/runGetMethod")] + ) + + with pytest.raises(RuntimeError, match="failed with exit code 1"): + client.run_get_method("0:" + "1" * 64, "method", []) + + def test_run_get_method_should_reject_non_list_stack(self): + client = ToncenterRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [_json_response(200, {"exit_code": 0, "stack": {}}, path="/api/v3/runGetMethod")] + ) + + with pytest.raises(RuntimeError, match="invalid stack"): + client.run_get_method("0:" + "1" * 64, "method", []) + + def test_should_parse_stack_helpers_and_jetton_wallet_data(self): + owner = "0:" + "2" * 64 + minter = "0:" + "3" * 64 + client = ToncenterRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [ + _json_response( + 200, + { + "exit_code": 0, + "stack": [ + {"value": "123"}, + {"value": _address_cell_b64(owner)}, + {"value": _address_cell_b64(minter)}, + ], + }, + path="/api/v3/runGetMethod", + ) + ] + ) + + data = client.get_jetton_wallet_data("0:" + "4" * 64) + + assert data.balance == 123 + assert data.owner == owner + assert data.jetton_minter == minter + + def test_get_trace_by_message_hash_should_reject_malformed_response(self): + client = ToncenterRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [_json_response(200, {"traces": {}}, path="/api/v3/traces")] + ) + + with pytest.raises(RuntimeError, match="invalid traces response"): + client.get_trace_by_message_hash("hash-1") + + def test_get_trace_by_message_hash_should_reject_empty_traces(self): + client = ToncenterRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [_json_response(200, {"traces": []}, path="/api/v3/traces")] + ) + + with pytest.raises(RuntimeError, match="returned no trace"): + client.get_trace_by_message_hash("hash-1") + + +class TestToncenterRequestRetries: + def test_should_debug_log_successful_provider_responses(self, caplog): + client = ToncenterRestClient(TVM_TESTNET) + client._client = _FakeHttpClient([_json_response(200, {"ok": True}, path="/api/test")]) + + with caplog.at_level(logging.DEBUG, logger=provider_module.logger.name): + result = client._request("GET", "/api/test") + + assert result == {"ok": True} + assert "Toncenter response: method=GET path=/api/test" in caplog.text + assert "status=200" in caplog.text + assert """body='{"ok": true}'""" in caplog.text + + def test_should_retry_retryable_http_statuses(self, monkeypatch): + client = ToncenterRestClient(TVM_TESTNET) + fake_client = _FakeHttpClient( + [ + _json_response(500, {"error": "boom"}, path="/api/test"), + _json_response(200, {"ok": True}, path="/api/test"), + ] + ) + client._client = fake_client + sleeps: list[float] = [] + monkeypatch.setattr(provider_module.time, "sleep", lambda seconds: sleeps.append(seconds)) + + result = client._request("GET", "/api/test") + + assert result == {"ok": True} + assert len(fake_client.calls) == 2 + assert sleeps == [0.25] + + def test_should_honor_retry_after_header(self, monkeypatch): + client = ToncenterRestClient(TVM_TESTNET) + fake_client = _FakeHttpClient( + [ + _json_response( + 429, + {"error": "busy"}, + path="/api/test", + headers={"Retry-After": "1.5"}, + ), + _json_response(200, {"ok": True}, path="/api/test"), + ] + ) + client._client = fake_client + sleeps: list[float] = [] + monkeypatch.setattr(provider_module.time, "sleep", lambda seconds: sleeps.append(seconds)) + + result = client._request("GET", "/api/test") + + assert result == {"ok": True} + assert sleeps == [1.5] + + def test_should_not_retry_non_retryable_http_statuses(self): + client = ToncenterRestClient(TVM_TESTNET) + fake_client = _FakeHttpClient([_json_response(400, {"error": "bad"}, path="/api/test")]) + client._client = fake_client + + with pytest.raises(httpx.HTTPStatusError): + client._request("GET", "/api/test") + + assert len(fake_client.calls) == 1 + + def test_should_retry_transport_errors_then_raise_last_error(self, monkeypatch): + client = ToncenterRestClient(TVM_TESTNET) + fake_client = _FakeHttpClient( + [ + httpx.RequestError( + "boom", request=httpx.Request("GET", "https://toncenter.example/api/test") + ) + ] + * 5 + ) + client._client = fake_client + monkeypatch.setattr(provider_module.time, "sleep", lambda seconds: None) + + with pytest.raises(httpx.RequestError, match="boom"): + client._request("GET", "/api/test") + + assert len(fake_client.calls) == 5 + + def test_should_reject_non_object_json_payloads(self): + client = ToncenterRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [_json_response(200, ["not", "an", "object"], path="/api/test")] + ) + + with pytest.raises(RuntimeError, match="non-object response"): + client._request("GET", "/api/test") + + +class TestTonapiRestClient: + def test_should_use_bearer_authentication_header(self): + client = TonapiRestClient(TVM_TESTNET, api_key="tonapi-key") + + try: + assert client._client.headers["authorization"] == "Bearer tonapi-key" + finally: + client.close() + + def test_get_account_state_should_decode_raw_account_state(self): + address = "0:" + "1" * 64 + client = TonapiRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [ + _json_response( + 200, + { + "address": address, + "balance": 123, + "status": "active", + "code": _cell_hex(1), + "data": _cell_hex(2), + "last_transaction_lt": 1, + "storage": {}, + }, + path=f"/v2/blockchain/accounts/{address}", + ) + ] + ) + + account = client.get_account_state(address) + + assert account.address == address + assert account.balance == 123 + assert account.is_active is True + assert account.state_init is not None + + def test_get_account_state_should_return_uninitialized_for_404(self): + address = "0:" + "2" * 64 + client = TonapiRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [_json_response(404, {"error": "not found"}, path=f"/v2/blockchain/accounts/{address}")] + ) + + account = client.get_account_state(address) + + assert account.address == address + assert account.is_uninitialized is True + assert account.balance == 0 + + def test_run_get_method_should_convert_arguments_and_stack_records(self): + asset = "0:" + "3" * 64 + owner = "0:" + "4" * 64 + wallet = "0:" + "5" * 64 + client = TonapiRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [ + _json_response( + 200, + { + "success": True, + "exit_code": 0, + "stack": [ + { + "type": "cell", + "cell": _address_cell_hex(wallet), + } + ], + }, + path=f"/v2/blockchain/accounts/{asset}/methods/get_wallet_address", + ) + ] + ) + + resolved_wallet = client.get_jetton_wallet(asset, owner) + + assert resolved_wallet == wallet + method, path, kwargs = client._client.calls[0] + assert method == "POST" + assert path == f"/v2/blockchain/accounts/{asset}/methods/get_wallet_address" + assert kwargs["json"]["args"] == [{"type": "slice", "value": owner}] + + def test_get_jetton_wallet_data_should_parse_tonapi_stack(self): + owner = "0:" + "2" * 64 + minter = "0:" + "3" * 64 + address = "0:" + "4" * 64 + client = TonapiRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [ + _json_response( + 200, + { + "success": True, + "exit_code": 0, + "stack": [ + {"type": "num", "num": "123"}, + {"type": "cell", "cell": _address_cell_hex(owner)}, + {"type": "cell", "cell": _address_cell_hex(minter)}, + ], + }, + path=f"/v2/blockchain/accounts/{address}/methods/get_wallet_data", + ) + ] + ) + + data = client.get_jetton_wallet_data(address) + + assert data.balance == 123 + assert data.owner == owner + assert data.jetton_minter == minter + + def test_send_message_should_return_normalized_external_message_hash(self): + destination = "0:" + "6" * 64 + body = begin_cell().store_uint(1, 8).end_cell() + external_message = Contract.create_external_msg(dest=Address(destination), body=body) + client = TonapiRestClient(TVM_TESTNET) + client._client = _FakeHttpClient([_json_response(200, {}, path="/v2/blockchain/message")]) + + message_hash = client.send_message(external_message.serialize().to_boc()) + + assert len(message_hash) == 64 + assert bytes.fromhex(message_hash) + method, path, kwargs = client._client.calls[0] + assert method == "POST" + assert path == "/v2/blockchain/message" + assert kwargs["json"]["boc"] + + def test_emulate_trace_should_adapt_tonapi_trace_shape(self): + account = "0:" + "7" * 64 + raw_body = begin_cell().store_uint(0x0F8A7EA5, 32).end_cell() + client = TonapiRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [ + _json_response( + 200, + { + "transaction": { + "hash": "a" * 64, + "account": { + "address": account, + "is_scam": False, + "is_wallet": True, + }, + "end_balance": 1000, + "aborted": False, + "compute_phase": { + "skipped": False, + "success": True, + "gas_fees": 100, + }, + "action_phase": { + "success": True, + "fwd_fees": 20, + "total_fees": 30, + }, + "storage_phase": { + "fees_collected": 5, + "status_change": "unchanged", + }, + "in_msg": { + "hash": "b" * 64, + "source": { + "address": account, + "is_scam": False, + "is_wallet": True, + }, + "destination": { + "address": account, + "is_scam": False, + "is_wallet": True, + }, + "decoded_op_name": "JettonTransfer", + "raw_body": raw_body.to_boc().hex(), + "fwd_fee": 10, + }, + "out_msgs": [], + }, + "interfaces": [], + }, + path="/v2/traces/emulate", + ) + ] + ) + + trace = client.emulate_trace(b"boc-bytes", ignore_chksig=True, timeout=7.5) + + transaction = trace["transactions"]["a" * 64] + assert transaction["account"] == account + assert "balance" not in transaction + assert transaction["description"]["compute_ph"]["gas_fees"] == 100 + assert transaction["description"]["action"]["total_fwd_fees"] == 20 + assert transaction["in_msg"]["decoded_opcode"] == "jetton_transfer" + assert transaction["in_msg"]["message_content"]["hash"] == base64.b64encode( + raw_body.hash + ).decode("ascii") + method, path, kwargs = client._client.calls[0] + assert method == "POST" + assert path == "/v2/traces/emulate" + assert kwargs["params"] == {"ignore_signature_check": True} + assert kwargs["timeout"] == 7.5 + + def test_emulate_trace_should_recover_parent_out_msgs_from_child_transactions(self): + parent_account = "0:" + "7" * 64 + child_account = "0:" + "8" * 64 + child_in_body = begin_cell().store_uint(0x0F8A7EA5, 32).end_cell() + child_message_hash = "c" * 64 + client = TonapiRestClient(TVM_TESTNET) + client._client = _FakeHttpClient( + [ + _json_response( + 200, + { + "transaction": { + "hash": "a" * 64, + "account": {"address": parent_account}, + "aborted": False, + "compute_phase": {"skipped": False, "success": True}, + "action_phase": {"success": True}, + "storage_phase": {}, + "in_msg": {"hash": "b" * 64, "destination": parent_account}, + "out_msgs": [], + }, + "children": [ + { + "transaction": { + "hash": "d" * 64, + "account": {"address": child_account}, + "aborted": False, + "compute_phase": {"skipped": False, "success": True}, + "action_phase": {"success": True}, + "storage_phase": {}, + "in_msg": { + "hash": child_message_hash, + "source": {"address": parent_account}, + "destination": {"address": child_account}, + "decoded_op_name": "JettonTransfer", + "raw_body": child_in_body.to_boc().hex(), + }, + "out_msgs": [], + }, + "children": [], + } + ], + }, + path="/v2/traces/emulate", + ) + ] + ) + + trace = client.emulate_trace(b"boc-bytes") + + parent = trace["transactions"]["a" * 64] + child = trace["transactions"]["d" * 64] + assert parent["out_msgs"] == [child["in_msg"]] + assert parent["out_msgs"][0]["hash"] == child_message_hash + assert parent["out_msgs"][0]["destination"] == child_account + assert parent["out_msgs"][0]["message_content"]["hash"] == base64.b64encode( + child_in_body.hash + ).decode("ascii") diff --git a/python/x402/tests/unit/mechanisms/tvm/test_server.py b/python/x402/tests/unit/mechanisms/tvm/test_server.py new file mode 100644 index 0000000000..f47d78c6f6 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_server.py @@ -0,0 +1,258 @@ +"""Tests for the exact TVM server scheme.""" + +from __future__ import annotations + +import pytest + +pytest.importorskip("pytoniq_core") + +from x402.mechanisms.tvm import ( + TVM_MAINNET, + TVM_TESTNET, + USDT_MAINNET_MINTER, + USDT_TESTNET_MINTER, +) +from x402.mechanisms.tvm.exact import ExactTvmServerScheme +from x402.schemas import AssetAmount, SupportedKind + +from .builders import EMPTY_FORWARD_PAYLOAD_B64, make_tvm_requirements + +ZERO_BIT_PAYLOAD_B64 = EMPTY_FORWARD_PAYLOAD_B64 + + +def _make_requirements(**overrides): + return make_tvm_requirements( + asset=overrides.pop("asset", USDT_TESTNET_MINTER), + pay_to=overrides.pop("pay_to", USDT_TESTNET_MINTER), + **overrides, + ) + + +class TestParsePrice: + """Test parse_price.""" + + class TestMainnetNetwork: + @pytest.mark.parametrize( + ("price", "amount"), + [ + pytest.param("$0.10", "100000", id="dollar-string"), + pytest.param("0.10", "100000", id="plain-string"), + pytest.param(0.1, "100000", id="float"), + pytest.param(1, "1000000", id="int"), + ], + ) + def test_should_parse_prices_against_default_mainnet_usdt(self, price, amount): + server = ExactTvmServerScheme() + result = server.parse_price(price, TVM_MAINNET) + + assert result.amount == amount + assert result.asset == USDT_MAINNET_MINTER + assert result.extra == { + "areFeesSponsored": True, + "forwardPayload": ZERO_BIT_PAYLOAD_B64, + "forwardTonAmount": "0", + } + + class TestTestnetNetwork: + def test_should_use_testnet_default_asset(self): + server = ExactTvmServerScheme() + + result = server.parse_price("$0.001", TVM_TESTNET) + + assert result.amount == "1000" + assert result.asset == USDT_TESTNET_MINTER + + class TestPreParsedPriceObjects: + def test_should_preserve_preparsed_dict_price(self): + server = ExactTvmServerScheme() + + result = server.parse_price( + { + "amount": "123456", + "asset": "0:" + "1" * 64, + "extra": {"foo": "bar"}, + }, + TVM_MAINNET, + ) + + assert result.amount == "123456" + assert result.asset == "0:" + "1" * 64 + assert result.extra == {"foo": "bar"} + + def test_should_preserve_asset_amount_instance(self): + server = ExactTvmServerScheme() + + result = server.parse_price( + AssetAmount( + amount="42", + asset="0:" + "2" * 64, + extra={"token": "CUSTOM"}, + ), + TVM_TESTNET, + ) + + assert result.amount == "42" + assert result.asset == "0:" + "2" * 64 + assert result.extra == {"token": "CUSTOM"} + + @pytest.mark.parametrize("price", [{"amount": "1"}, AssetAmount(amount="1", asset="")]) + def test_should_reject_passthrough_price_without_asset(self, price): + server = ExactTvmServerScheme() + + with pytest.raises(ValueError, match="Asset address required"): + server.parse_price(price, TVM_MAINNET) + + class TestCustomMoneyParsers: + def test_should_use_custom_money_parser_before_default_conversion(self): + server = ExactTvmServerScheme() + + def custom_parser(amount: float, network: str) -> AssetAmount | None: + assert network == TVM_MAINNET + if amount >= 100: + return AssetAmount( + amount="999", + asset="0:" + "9" * 64, + extra={"tier": "large"}, + ) + return None + + server.register_money_parser(custom_parser) + + large = server.parse_price(100, TVM_MAINNET) + small = server.parse_price(1, TVM_MAINNET) + + assert large.amount == "999" + assert large.asset == "0:" + "9" * 64 + assert large.extra == {"tier": "large"} + assert small.asset == USDT_MAINNET_MINTER + assert small.amount == "1000000" + + def test_should_not_call_custom_parser_for_passthrough_price_objects(self): + server = ExactTvmServerScheme() + parser_called = False + + def tracking_parser(amount: float, network: str) -> AssetAmount | None: + nonlocal parser_called + parser_called = True + return None + + server.register_money_parser(tracking_parser) + + server.parse_price( + AssetAmount(amount="123", asset="0:" + "4" * 64), + TVM_MAINNET, + ) + + assert parser_called is False + + class TestErrorCases: + def test_should_raise_when_network_has_no_default_asset(self): + server = ExactTvmServerScheme() + + with pytest.raises(ValueError, match="No default stablecoin configured"): + server.parse_price("1.00", "tvm:123") + + +class TestEnhancePaymentRequirements: + """Test enhance_payment_requirements.""" + + class TestDefaultAssetNormalization: + def test_should_set_default_asset_and_normalize_decimal_amount(self): + server = ExactTvmServerScheme() + + result = server.enhance_payment_requirements( + _make_requirements( + asset="", + amount="1.5", + pay_to="EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c", + extra={}, + ), + SupportedKind( + x402_version=2, + scheme="exact", + network=TVM_TESTNET, + extra={"areFeesSponsored": False}, + ), + [], + ) + + assert result.asset == USDT_TESTNET_MINTER + assert result.amount == "1500000" + assert result.pay_to == "0:" + "0" * 64 + assert result.extra == {"areFeesSponsored": False} + + def test_should_preserve_existing_extra_fields_and_normalize_response_destination(self): + server = ExactTvmServerScheme() + + result = server.enhance_payment_requirements( + _make_requirements( + extra={ + "custom": "value", + "areFeesSponsored": True, + "responseDestination": "EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAM9c", + } + ), + SupportedKind(x402_version=2, scheme="exact", network=TVM_TESTNET), + [], + ) + + assert result.extra == { + "custom": "value", + "areFeesSponsored": True, + "responseDestination": "0:" + "0" * 64, + } + + class TestCustomAssets: + def test_should_raise_when_custom_asset_decimal_amount_has_no_decimals_metadata(self): + server = ExactTvmServerScheme() + + with pytest.raises( + ValueError, match="provide amount in atomic units or extra.decimals" + ): + server.enhance_payment_requirements( + _make_requirements( + asset="0:" + "8" * 64, + amount="1.25", + extra={}, + ), + SupportedKind(x402_version=2, scheme="exact", network=TVM_TESTNET), + [], + ) + + def test_should_use_extra_decimals_for_custom_assets(self): + server = ExactTvmServerScheme() + + result = server.enhance_payment_requirements( + _make_requirements( + asset="0:" + "8" * 64, + amount="1.25", + extra={"decimals": 9}, + ), + SupportedKind(x402_version=2, scheme="exact", network=TVM_TESTNET), + [], + ) + + assert result.amount == "1250000000" + + class TestInternalHelpers: + def test_get_default_asset_should_raise_for_unknown_network(self): + server = ExactTvmServerScheme() + + with pytest.raises(ValueError, match="No default stablecoin configured"): + server._get_default_asset("tvm:123") + + def test_get_asset_decimals_should_return_default_for_usdt(self): + server = ExactTvmServerScheme() + + assert server._get_asset_decimals(_make_requirements(network=TVM_TESTNET)) == 6 + + +class TestRegisterMoneyParser: + """Test register_money_parser.""" + + def test_should_return_self_for_chaining(self): + server = ExactTvmServerScheme() + + result = server.register_money_parser(lambda amount, network: None) + + assert result is server diff --git a/python/x402/tests/unit/mechanisms/tvm/test_settlement_batcher.py b/python/x402/tests/unit/mechanisms/tvm/test_settlement_batcher.py new file mode 100644 index 0000000000..9a354d9bcb --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_settlement_batcher.py @@ -0,0 +1,239 @@ +"""Tests for TVM settlement batching failure paths.""" + +from __future__ import annotations + +import pytest + +from x402.mechanisms.tvm.constants import ( + ERR_EXACT_TVM_SIMULATION_FAILED, + ERR_EXACT_TVM_TRANSACTION_FAILED, +) +from x402.mechanisms.tvm.exact.settlement_batcher import ( + _PendingConfirmation, + _QueuedSettlement, + _SettlementBatcher, +) + +TVM_TESTNET = "tvm:-3" + + +class _StopWorker(Exception): + pass + + +class _ReleaseSpyCache: + def __init__(self) -> None: + self._queued_by_key: dict[str, _QueuedSettlement] = {} + self.release_checks: list[dict[str, object]] = [] + + def register(self, queued: _QueuedSettlement) -> None: + self._queued_by_key[queued.settlement_hash] = queued + + def release(self, key: str) -> None: + queued = self._queued_by_key[key] + self.release_checks.append( + { + "key": key, + "completed": queued.completed.is_set(), + "error_reason": None if queued.result is None else queued.result.error_reason, + "success": None if queued.result is None else queued.result.success, + } + ) + + +class _SinglePendingQueue: + def __init__(self, pending: _PendingConfirmation) -> None: + self._pending = pending + self._consumed = False + + def get(self) -> _PendingConfirmation: + if self._consumed: + raise _StopWorker() + self._consumed = True + return self._pending + + +class _BuildFailureSigner: + def __init__(self, exc: Exception) -> None: + self._exc = exc + + def build_relay_external_boc_batch(self, network: str, requests: list[object]) -> bytes: + _ = network, requests + raise self._exc + + +class _ConfirmationFailureSigner: + def __init__(self, exc: Exception) -> None: + self._exc = exc + + def wait_for_trace_confirmation( + self, + network: str, + trace_external_hash_norm: str, + *, + timeout_seconds: float, + ) -> dict[str, object]: + _ = network, trace_external_hash_norm, timeout_seconds + raise self._exc + + +class _ConfirmedSigner: + def wait_for_trace_confirmation( + self, + network: str, + trace_external_hash_norm: str, + *, + timeout_seconds: float, + ) -> dict[str, object]: + _ = network, trace_external_hash_norm, timeout_seconds + return {"transactions": {}} + + +def _make_batcher( + *, + signer: object, + settlement_cache: _ReleaseSpyCache, + settlement_verifier, +) -> _SettlementBatcher: + batcher = object.__new__(_SettlementBatcher) + batcher._signer = signer + batcher._settlement_cache = settlement_cache + batcher._confirmation_timeout_seconds = 30.0 + batcher._settlement_verifier = settlement_verifier + return batcher + + +def _make_queued_settlement(settlement_hash: str = "settlement-hash") -> _QueuedSettlement: + return _QueuedSettlement( + network=TVM_TESTNET, + settlement_hash=settlement_hash, + settlement=object(), + relay_request=object(), + ) + + +def test_flush_batch_releases_only_after_result_and_completion_on_send_failure(): + queued = _make_queued_settlement() + cache = _ReleaseSpyCache() + cache.register(queued) + batcher = _make_batcher( + signer=_BuildFailureSigner(RuntimeError("send failed")), + settlement_cache=cache, + settlement_verifier=lambda trace_data, settlement: "unused", + ) + + batcher._flush_batch(TVM_TESTNET, [queued]) + + assert queued.completed.is_set() is True + assert queued.result is not None + assert queued.result.error_reason == ERR_EXACT_TVM_TRANSACTION_FAILED + assert cache.release_checks == [ + { + "key": queued.settlement_hash, + "completed": True, + "error_reason": ERR_EXACT_TVM_TRANSACTION_FAILED, + "success": False, + } + ] + + +def test_confirmation_worker_releases_only_after_result_and_completion_on_wait_failure(): + queued = _make_queued_settlement() + cache = _ReleaseSpyCache() + cache.register(queued) + batcher = _make_batcher( + signer=_ConfirmationFailureSigner(ValueError("trace wait failed")), + settlement_cache=cache, + settlement_verifier=lambda trace_data, settlement: "unused", + ) + batcher._confirmation_queue = _SinglePendingQueue( + _PendingConfirmation( + network=TVM_TESTNET, + batch=[queued], + trace_external_hash_norm="trace-hash", + ) + ) + + with pytest.raises(_StopWorker): + batcher._run_confirmation_worker() + + assert queued.completed.is_set() is True + assert queued.result is not None + assert queued.result.error_reason == ERR_EXACT_TVM_SIMULATION_FAILED + assert cache.release_checks == [ + { + "key": queued.settlement_hash, + "completed": True, + "error_reason": ERR_EXACT_TVM_SIMULATION_FAILED, + "success": False, + } + ] + + +def test_confirmation_worker_releases_after_completion_on_success(): + queued = _make_queued_settlement() + cache = _ReleaseSpyCache() + cache.register(queued) + batcher = _make_batcher( + signer=_ConfirmedSigner(), + settlement_cache=cache, + settlement_verifier=lambda trace_data, settlement: "tx-hash", + ) + batcher._confirmation_queue = _SinglePendingQueue( + _PendingConfirmation( + network=TVM_TESTNET, + batch=[queued], + trace_external_hash_norm="trace-hash", + ) + ) + + with pytest.raises(_StopWorker): + batcher._run_confirmation_worker() + + assert queued.completed.is_set() is True + assert queued.result is not None + assert queued.result.success is True + assert queued.result.transaction == "tx-hash" + assert cache.release_checks == [ + { + "key": queued.settlement_hash, + "completed": True, + "error_reason": None, + "success": True, + } + ] + + +def test_confirmation_worker_releases_only_after_result_and_completion_on_verify_failure(): + queued = _make_queued_settlement() + cache = _ReleaseSpyCache() + cache.register(queued) + batcher = _make_batcher( + signer=_ConfirmedSigner(), + settlement_cache=cache, + settlement_verifier=lambda trace_data, settlement: (_ for _ in ()).throw( + RuntimeError("verification failed") + ), + ) + batcher._confirmation_queue = _SinglePendingQueue( + _PendingConfirmation( + network=TVM_TESTNET, + batch=[queued], + trace_external_hash_norm="trace-hash", + ) + ) + + with pytest.raises(_StopWorker): + batcher._run_confirmation_worker() + + assert queued.completed.is_set() is True + assert queued.result is not None + assert queued.result.error_reason == ERR_EXACT_TVM_TRANSACTION_FAILED + assert cache.release_checks == [ + { + "key": queued.settlement_hash, + "completed": True, + "error_reason": ERR_EXACT_TVM_TRANSACTION_FAILED, + "success": False, + } + ] diff --git a/python/x402/tests/unit/mechanisms/tvm/test_settlement_cache.py b/python/x402/tests/unit/mechanisms/tvm/test_settlement_cache.py new file mode 100644 index 0000000000..f6ba5c307e --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_settlement_cache.py @@ -0,0 +1,41 @@ +"""Tests for the TVM settlement cache.""" + +import pytest + +pytest.importorskip("pytoniq_core") + +from x402.mechanisms.tvm.settlement_cache import SettlementCache + + +def test_is_duplicate_rejects_duplicate_until_released() -> None: + cache = SettlementCache() + + assert cache.is_duplicate("settlement-1", 300.0) is False + assert cache.is_duplicate("settlement-1", 300.0) is True + + cache.release("settlement-1") + + assert cache.is_duplicate("settlement-1", 300.0) is False + + +def test_is_duplicate_prunes_expired_entries() -> None: + cache = SettlementCache() + + assert cache.is_duplicate("settlement-1", 300.0) is False + cache._entries["settlement-1"] -= 301.0 + + assert cache.is_duplicate("settlement-1", 300.0) is False + + +def test_release_prunes_expired_entries_when_cache_is_otherwise_idle() -> None: + cache = SettlementCache() + + assert cache.is_duplicate("expired-settlement", 300.0) is False + assert cache.is_duplicate("active-settlement", 300.0) is False + + cache._entries["expired-settlement"] -= 301.0 + + cache.release("missing-settlement") + + assert "expired-settlement" not in cache._entries + assert "active-settlement" in cache._entries diff --git a/python/x402/tests/unit/mechanisms/tvm/test_signers.py b/python/x402/tests/unit/mechanisms/tvm/test_signers.py new file mode 100644 index 0000000000..c5fa20c667 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_signers.py @@ -0,0 +1,403 @@ +"""Tests for TVM signer implementations.""" + +from __future__ import annotations + +import base64 +import threading + +import pytest + +pytest.importorskip("pytoniq_core") + +from x402.mechanisms.tvm import ( + TVM_MAINNET, + TVM_PROVIDER_TONAPI, + TVM_TESTNET, + TonapiRestClient, +) +from x402.mechanisms.tvm.constants import ( + DEFAULT_STREAMING_CONFIRMATION_GRACE_SECONDS, + DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS, +) +from x402.mechanisms.tvm.signers import ( + FacilitatorHighloadV3Signer, + HighloadV3Config, + WalletV5R1Config, + WalletV5R1MnemonicSigner, +) +from x402.mechanisms.tvm.types import TvmAccountState + +from .builders import TEST_MNEMONIC, derive_test_secret_key +from .helpers import start_captured_thread + + +class TestWalletV5R1Config: + @pytest.mark.parametrize( + ("private_key", "factory"), + [ + pytest.param( + lambda secret_key, seed: secret_key.hex(), + lambda private_key: WalletV5R1Config.from_private_key(TVM_TESTNET, private_key), + id="hex-64", + ), + pytest.param( + lambda secret_key, seed: seed.hex(), + lambda private_key: WalletV5R1Config.from_private_key(TVM_TESTNET, private_key), + id="hex-32", + ), + pytest.param( + lambda secret_key, seed: base64.b64encode(secret_key).decode(), + lambda private_key: WalletV5R1Config.from_private_key(TVM_TESTNET, private_key), + id="base64-64", + ), + pytest.param( + lambda secret_key, seed: base64.b64encode(seed).decode(), + lambda private_key: WalletV5R1Config.from_private_key(TVM_TESTNET, private_key), + id="base64-32", + ), + ], + ) + def test_from_private_key_should_accept_hex_and_base64_seed_or_secret_key( + self, private_key, factory + ): + secret_key = derive_test_secret_key() + seed = secret_key[:32] + + config = factory(private_key(secret_key, seed)) + + assert config.secret_key == secret_key + assert config.network == TVM_TESTNET + + def test_from_private_key_should_reject_invalid_input(self): + with pytest.raises(ValueError, match="valid hex or base64"): + WalletV5R1Config.from_private_key(TVM_TESTNET, "not-a-key") + + +class TestWalletV5R1MnemonicSigner: + def test_should_expose_network_wallet_id_state_init_and_address(self): + config = WalletV5R1Config.from_mnemonic(TVM_TESTNET, TEST_MNEMONIC) + config.provider = TVM_PROVIDER_TONAPI + config.provider_base_url = "https://tonapi.local" + + signer = WalletV5R1MnemonicSigner(config) + + assert signer.network == TVM_TESTNET + assert signer.provider == TVM_PROVIDER_TONAPI + assert signer.provider_base_url == "https://tonapi.local" + assert signer.wallet_id > 0 + assert signer.state_init is not None + assert signer.address.startswith("0:") + assert len(signer.address) == 66 + + def test_sign_message_should_return_ed25519_signature(self): + config = WalletV5R1Config.from_mnemonic(TVM_TESTNET, TEST_MNEMONIC) + signer = WalletV5R1MnemonicSigner(config) + + signature = signer.sign_message(b"message-hash") + + assert isinstance(signature, bytes) + assert len(signature) == 64 + + +class TestHighloadV3Config: + @pytest.mark.parametrize( + ("private_key", "factory"), + [ + pytest.param( + lambda secret_key, seed: secret_key.hex(), + lambda private_key: HighloadV3Config.from_private_key(private_key), + id="hex-64", + ), + pytest.param( + lambda secret_key, seed: seed.hex(), + lambda private_key: HighloadV3Config.from_private_key(private_key), + id="hex-32", + ), + ], + ) + def test_from_private_key_should_accept_hex_seed_or_secret_key(self, private_key, factory): + secret_key = derive_test_secret_key() + seed = secret_key[:32] + + config = factory(private_key(secret_key, seed)) + + assert config.secret_key == secret_key + + +class TestFacilitatorHighloadV3Signer: + def test_get_addresses_for_network_should_return_only_requested_wallet(self): + secret_key = derive_test_secret_key() + signer = FacilitatorHighloadV3Signer( + { + TVM_TESTNET: HighloadV3Config(secret_key=secret_key, subwallet_id=1), + TVM_MAINNET: HighloadV3Config(secret_key=secret_key, subwallet_id=2), + } + ) + + testnet_addresses = signer.get_addresses_for_network(TVM_TESTNET) + mainnet_addresses = signer.get_addresses_for_network(TVM_MAINNET) + + assert len(testnet_addresses) == 1 + assert len(mainnet_addresses) == 1 + assert testnet_addresses != mainnet_addresses + assert signer.get_addresses() == testnet_addresses + mainnet_addresses + + def test_wait_for_trace_confirmation_fetches_full_trace_after_stream_signal(self, monkeypatch): + secret_key = derive_test_secret_key() + signer = FacilitatorHighloadV3Signer( + { + TVM_TESTNET: HighloadV3Config( + secret_key=secret_key, + ) + } + ) + stream_calls: list[tuple[str, float]] = [] + trace_calls: list[str] = [] + expected_trace = { + "trace_id": "trace-id-1", + "transactions": { + "tx-1": { + "account": "0:" + "1" * 64, + } + }, + } + + class _FakeStreamingClient: + def wait_for_trace_confirmation( + self, *, trace_external_hash_norm: str, timeout_seconds: float + ): + stream_calls.append((trace_external_hash_norm, timeout_seconds)) + return { + "type": "transactions", + "finality": "finalized", + "trace_external_hash_norm": trace_external_hash_norm, + } + + class _FakeProviderClient: + def get_trace_by_message_hash(self, trace_external_hash_norm: str): + trace_calls.append(trace_external_hash_norm) + return expected_trace + + monkeypatch.setattr(signer, "_ensure_streaming_watcher", lambda network: True) + monkeypatch.setattr(signer, "_streaming_client", lambda network: _FakeStreamingClient()) + monkeypatch.setattr(signer, "_client", lambda network: _FakeProviderClient()) + + result = signer.wait_for_trace_confirmation( + TVM_TESTNET, + "trace-hash-1", + timeout_seconds=12.5, + ) + + assert len(stream_calls) == 1 + assert stream_calls[0][0] == "trace-hash-1" + assert stream_calls[0][1] == pytest.approx( + DEFAULT_STREAMING_CONFIRMATION_GRACE_SECONDS, abs=0.1 + ) + assert trace_calls == ["trace-hash-1"] + assert result == expected_trace + + def test_wait_for_trace_confirmation_uses_remaining_budget_for_rest_after_stream_timeout( + self, monkeypatch + ): + secret_key = derive_test_secret_key() + signer = FacilitatorHighloadV3Signer( + { + TVM_TESTNET: HighloadV3Config( + secret_key=secret_key, + ) + } + ) + stream_calls: list[tuple[str, float]] = [] + trace_calls: list[str] = [] + fake_now = 100.0 + expected_trace = { + "trace_id": "trace-id-1", + "transactions": { + "tx-1": { + "account": "0:" + "1" * 64, + } + }, + } + + class _FakeStreamingClient: + def wait_for_trace_confirmation( + self, *, trace_external_hash_norm: str, timeout_seconds: float + ): + nonlocal fake_now + stream_calls.append((trace_external_hash_norm, timeout_seconds)) + fake_now += timeout_seconds + raise RuntimeError("stream timeout") + + class _FakeProviderClient: + def get_trace_by_message_hash(self, trace_external_hash_norm: str): + trace_calls.append(trace_external_hash_norm) + return expected_trace + + monkeypatch.setattr(signer, "_ensure_streaming_watcher", lambda network: True) + monkeypatch.setattr(signer, "_streaming_client", lambda network: _FakeStreamingClient()) + monkeypatch.setattr(signer, "_client", lambda network: _FakeProviderClient()) + monkeypatch.setattr("x402.mechanisms.tvm.signers.time.monotonic", lambda: fake_now) + monkeypatch.setattr("x402.mechanisms.tvm.signers.time.sleep", lambda seconds: None) + + result = signer.wait_for_trace_confirmation( + TVM_TESTNET, + "trace-hash-1", + timeout_seconds=12.5, + ) + + assert len(stream_calls) == 1 + assert stream_calls[0][0] == "trace-hash-1" + assert stream_calls[0][1] == pytest.approx( + DEFAULT_STREAMING_CONFIRMATION_GRACE_SECONDS, abs=0.1 + ) + assert fake_now == pytest.approx( + 100.0 + DEFAULT_STREAMING_CONFIRMATION_GRACE_SECONDS, abs=0.1 + ) + assert trace_calls == ["trace-hash-1"] + assert result == expected_trace + + def test_emulate_external_message_uses_emulation_timeout(self, monkeypatch): + secret_key = derive_test_secret_key() + signer = FacilitatorHighloadV3Signer( + { + TVM_TESTNET: HighloadV3Config( + secret_key=secret_key, + provider_emulation_timeout_seconds=17.5, + ) + } + ) + emulate_calls: list[tuple[bytes, float]] = [] + + class _FakeProviderClient: + def emulate_trace(self, boc: bytes, *, ignore_chksig: bool = False, timeout: float): + assert ignore_chksig is False + emulate_calls.append((boc, timeout)) + return {"transactions": {}} + + monkeypatch.setattr(signer, "_client", lambda network: _FakeProviderClient()) + + result = signer.emulate_external_message(TVM_TESTNET, b"external-boc") + + assert result == {"transactions": {}} + assert emulate_calls == [(b"external-boc", 17.5)] + + def test_wallet_config_defaults_emulation_timeout(self): + config = WalletV5R1Config.from_mnemonic(TVM_TESTNET, TEST_MNEMONIC) + + assert config.provider_emulation_timeout_seconds == ( + DEFAULT_TONCENTER_EMULATION_TIMEOUT_SECONDS + ) + + def test_client_and_streaming_client_should_use_tonapi_provider(self): + secret_key = derive_test_secret_key() + signer = FacilitatorHighloadV3Signer( + { + TVM_TESTNET: HighloadV3Config( + secret_key=secret_key, + provider=" TonAPI ", + provider_base_url="https://tonapi.local", + ) + } + ) + + try: + provider_client = signer._client(TVM_TESTNET) + streaming_client = signer._streaming_client(TVM_TESTNET) + + assert isinstance(provider_client, TonapiRestClient) + assert str(provider_client._client.base_url).rstrip("/") == "https://tonapi.local" + assert streaming_client._base_url == "https://tonapi.local" + assert streaming_client._sse_path == "/streaming/v2/sse" + finally: + signer.close() + + def test_select_query_id_fetches_account_state_outside_lock(self, monkeypatch): + secret_key = derive_test_secret_key() + signer = FacilitatorHighloadV3Signer( + { + TVM_TESTNET: HighloadV3Config( + secret_key=secret_key, + ) + } + ) + + class _TrackingLock: + def __init__(self) -> None: + self._lock = threading.RLock() + self.depth = 0 + + def __enter__(self): + self._lock.acquire() + self.depth += 1 + return self + + def __exit__(self, exc_type, exc, tb): + self.depth -= 1 + self._lock.release() + + tracking_lock = _TrackingLock() + signer._lock = tracking_lock + account_state_lock_depths: list[int] = [] + + def _get_account_state(address: str, network: str) -> TvmAccountState: + account_state_lock_depths.append(tracking_lock.depth) + return TvmAccountState( + address=address, + balance=0, + is_active=False, + is_uninitialized=True, + is_frozen=False, + state_init=None, + ) + + monkeypatch.setattr(signer, "get_account_state", _get_account_state) + + query_id = signer._select_query_id(TVM_TESTNET, for_emulation=False) + + assert account_state_lock_depths == [0] + assert query_id >= 0 + + def test_ensure_streaming_watcher_starts_only_one_sse_connection(self, monkeypatch): + secret_key = derive_test_secret_key() + signer = FacilitatorHighloadV3Signer( + { + TVM_TESTNET: HighloadV3Config( + secret_key=secret_key, + ) + } + ) + start_entered = threading.Event() + allow_finish = threading.Event() + start_calls = 0 + results: list[bool] = [] + + class _FakeWatcher: + def is_alive(self) -> bool: + return True + + class _FakeStreamingClient: + def start_account_state_watcher(self, *, address: str, on_invalidate): + nonlocal start_calls + _ = on_invalidate + assert address == signer.get_addresses_for_network(TVM_TESTNET)[0] + start_calls += 1 + start_entered.set() + assert allow_finish.wait(timeout=1.0) + return _FakeWatcher() + + monkeypatch.setattr(signer, "_streaming_client", lambda network: _FakeStreamingClient()) + + first = start_captured_thread( + lambda: results.append(signer._ensure_streaming_watcher(TVM_TESTNET)) + ) + assert start_entered.wait(timeout=1.0) + second = start_captured_thread( + lambda: results.append(signer._ensure_streaming_watcher(TVM_TESTNET)) + ) + allow_finish.set() + + first.join() + second.join() + + assert start_calls == 1 + assert results == [True, True] diff --git a/python/x402/tests/unit/mechanisms/tvm/test_streaming.py b/python/x402/tests/unit/mechanisms/tvm/test_streaming.py new file mode 100644 index 0000000000..8836aa0454 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_streaming.py @@ -0,0 +1,337 @@ +"""Tests for TVM streaming trace confirmation.""" + +from __future__ import annotations + +import base64 +import queue +import threading +import time +from dataclasses import dataclass + +import pytest + +pytest.importorskip("pytoniq_core") + +import x402.mechanisms.tvm as tvm_module +import x402.mechanisms.tvm.streaming as streaming_module +from x402.mechanisms.tvm import TVM_PROVIDER_TONAPI +from x402.mechanisms.tvm.streaming import ( + TvmStreamingSseClient, + TvmStreamingWatcher, + _account_stream_subscription, + _iter_sse_json_events, + _iter_sse_payloads, +) + +from .helpers import start_captured_thread + +TRACE_HASH = "trace-hash-1" +FACILITATOR_ADDRESS = "0:" + "1" * 64 + + +@dataclass(frozen=True) +class _ConsumePlan: + events: tuple[dict[str, object], ...] = () + error: Exception | None = None + wait_on: threading.Event | None = None + sleep_seconds: float = 0.0 + set_stop: bool = False + + +def _subscribed_event() -> dict[str, str]: + return {"status": "subscribed"} + + +def _finalized_trace_event(trace_hash: str = TRACE_HASH) -> dict[str, object]: + return { + "type": "transactions", + "finality": "finalized", + "trace_external_hash_norm": trace_hash, + "transactions": [], + } + + +def _start_trace_waiter( + client: TvmStreamingSseClient, + *, + trace_hash: str = TRACE_HASH, + timeout_seconds: float = 1.0, +): + return start_captured_thread( + lambda: client.wait_for_trace_confirmation( + trace_external_hash_norm=trace_hash, + timeout_seconds=timeout_seconds, + ) + ) + + +def _planned_consumer(state: dict[str, int], plans: list[_ConsumePlan]): + def fake_consume_stream(*, subscription, stop_event, on_event, resources=None): + _ = subscription, resources + state["calls"] += 1 + plan = plans[state["calls"] - 1] + for event in plan.events: + on_event(event) + if plan.wait_on is not None: + plan.wait_on.wait(timeout=1.0) + if plan.sleep_seconds: + time.sleep(plan.sleep_seconds) + if plan.set_stop: + stop_event.set() + if plan.error is not None: + raise plan.error + + return fake_consume_stream + + +def test_account_stream_subscription_uses_transactions_and_account_state_change(): + assert _account_stream_subscription(FACILITATOR_ADDRESS) == { + "addresses": [FACILITATOR_ADDRESS], + "types": ["account_state_change", "transactions"], + "min_finality": "finalized", + } + + +def test_iter_sse_payloads_ignores_trailing_partial_event_without_blank_line(): + lines = [ + 'data: {"status":"subscribed"}', + "", + 'data: {"type":"transactions"', + ] + + assert list(_iter_sse_payloads(lines)) == ['{"status":"subscribed"}'] + + +def test_iter_sse_json_events_ignores_trailing_partial_event_without_blank_line(): + lines = [ + 'data: {"status":"subscribed"}', + "", + 'data: {"type":"transactions"', + ] + + assert list(_iter_sse_json_events(lines)) == [{"status": "subscribed"}] + + +def test_streaming_watcher_reports_whether_the_caller_is_the_watcher_thread(): + watcher = TvmStreamingWatcher( + threading.current_thread(), + threading.Event(), + close_stream=lambda: None, + ) + + assert watcher.is_current_thread() is True + + result_holder: dict[str, bool] = {} + + def check_from_other_thread() -> None: + result_holder["is_current_thread"] = watcher.is_current_thread() + + other_thread = start_captured_thread(check_from_other_thread) + other_thread.join() + assert result_holder["is_current_thread"] is False + + +def test_tonapi_streaming_client_uses_compatible_sse_route_and_bearer_auth(): + client = TvmStreamingSseClient( + base_url="https://tonapi.io", + api_key="tonapi-key", + provider=" TonAPI ", + ) + + assert client._sse_path == "/streaming/v2/sse" + assert client._headers["Authorization"] == "Bearer tonapi-key" + + +def test_streaming_sse_routes_are_internal_provider_details(): + tvm_client = TvmStreamingSseClient(base_url="https://toncenter.example") + tonapi_client = TvmStreamingSseClient( + base_url="https://tonapi.io", + provider=TVM_PROVIDER_TONAPI, + ) + + assert tvm_client._sse_path == "/api/streaming/v2/sse" + assert tonapi_client._sse_path == "/streaming/v2/sse" + assert not hasattr(tvm_module, "TONAPI_STREAMING_SSE_PATH") + assert not hasattr(tvm_module, "TONCENTER_STREAMING_SSE_PATH") + + +def test_trace_confirmation_should_match_hex_and_base64_hash_aliases(): + client = TvmStreamingSseClient(base_url="https://tonapi.io", provider=TVM_PROVIDER_TONAPI) + client._watcher = object() # type: ignore[assignment] + raw_hash = b"\x11" * 32 + trace_hash_hex = raw_hash.hex() + trace_hash_base64 = base64.b64encode(raw_hash).decode("ascii") + payload = { + "type": "transactions", + "finality": "finalized", + "trace_external_hash_norm": trace_hash_base64, + } + + client._publish_trace_result(trace_hash_base64, payload, None) + + assert ( + client.wait_for_trace_confirmation( + trace_external_hash_norm=trace_hash_hex, + timeout_seconds=0.01, + ) + == payload + ) + + +def test_wait_for_trace_confirmation_returns_finalized_trace_payload_from_transactions_event( + monkeypatch, +): + client = TvmStreamingSseClient(base_url="https://toncenter.example") + client._watcher = object() # type: ignore[assignment] + + waiter = start_captured_thread( + lambda: client.wait_for_trace_confirmation( + trace_external_hash_norm=TRACE_HASH, + timeout_seconds=1.0, + ) + ) + client._handle_stream_event( + _finalized_trace_event(), + normalized_address=FACILITATOR_ADDRESS, + on_invalidate=lambda: None, + on_subscribed=lambda: None, + ) + waiter.join() + + assert waiter.result == _finalized_trace_event() + + +def test_start_account_state_watcher_retries_after_failed_start(monkeypatch): + client = TvmStreamingSseClient(base_url="https://toncenter.example") + state = {"calls": 0} + + def fake_consume_stream(*, subscription, stop_event, on_event, resources=None): + _ = subscription, resources + state["calls"] += 1 + if state["calls"] == 1: + raise RuntimeError("boom") + on_event(_subscribed_event()) + while not stop_event.wait(0.01): + pass + + monkeypatch.setattr(client, "_consume_stream", fake_consume_stream) + + with pytest.raises(RuntimeError, match="failed to start"): + client.start_account_state_watcher( + address=FACILITATOR_ADDRESS, + on_invalidate=lambda: None, + ) + + watcher = client.start_account_state_watcher( + address=FACILITATOR_ADDRESS, + on_invalidate=lambda: None, + ) + try: + assert watcher.is_alive() is True + assert state["calls"] == 2 + finally: + watcher.close() + + +def test_wait_for_trace_confirmation_survives_stream_reconnect(monkeypatch): + client = TvmStreamingSseClient(base_url="https://toncenter.example") + state = {"calls": 0} + monkeypatch.setattr(streaming_module, "DEFAULT_STREAMING_RECONNECT_BACKOFF_SECONDS", 0.01) + monkeypatch.setattr( + client, + "_consume_stream", + _planned_consumer( + state, + [ + _ConsumePlan( + events=(_subscribed_event(),), + sleep_seconds=0.05, + error=RuntimeError("disconnect"), + ), + _ConsumePlan( + events=(_subscribed_event(), _finalized_trace_event()), + set_stop=True, + ), + ], + ), + ) + watcher = client.start_account_state_watcher( + address=FACILITATOR_ADDRESS, + on_invalidate=lambda: None, + ) + try: + waiter = _start_trace_waiter(client) + waiter.join() + + assert waiter.result == _finalized_trace_event() + assert state["calls"] >= 2 + finally: + watcher.close() + + +def test_wait_for_trace_confirmation_fails_after_max_consecutive_stream_failures(monkeypatch): + client = TvmStreamingSseClient(base_url="https://toncenter.example") + state = {"calls": 0, "invalidations": 0} + release_first_failure = threading.Event() + + monkeypatch.setattr(streaming_module, "DEFAULT_STREAMING_RECONNECT_BACKOFF_SECONDS", 0.01) + monkeypatch.setattr(streaming_module, "DEFAULT_STREAMING_MAX_CONSECUTIVE_FAILURES", 2) + + monkeypatch.setattr( + client, + "_consume_stream", + _planned_consumer( + state, + [ + _ConsumePlan( + events=(_subscribed_event(),), + wait_on=release_first_failure, + error=RuntimeError("disconnect-1"), + ), + _ConsumePlan(error=RuntimeError("disconnect-2")), + ], + ), + ) + watcher = client.start_account_state_watcher( + address=FACILITATOR_ADDRESS, + on_invalidate=lambda: state.__setitem__("invalidations", state["invalidations"] + 1), + ) + try: + waiter = _start_trace_waiter(client) + release_first_failure.set() + waiter.join(timeout=0.5) + error = waiter.error + assert isinstance(error, RuntimeError) + assert str(error) == ( + "Toncenter facilitator account stream failed before confirmation: disconnect-2" + ) + assert state["calls"] == 2 + assert state["invalidations"] == 2 + finally: + watcher.close() + + +def test_close_stops_watcher_and_fails_pending_waiters(): + client = TvmStreamingSseClient(base_url="https://toncenter.example") + waiter: queue.Queue[dict[str, object] | Exception] = queue.Queue(maxsize=1) + close_calls: list[str] = [] + + class _Watcher: + def close(self) -> None: + close_calls.append("closed") + + def is_alive(self) -> bool: + return True + + client._watcher = _Watcher() # type: ignore[assignment] + client._watched_address = FACILITATOR_ADDRESS + client._pending_trace_waiters[TRACE_HASH] = [waiter] + + client.close() + + result = waiter.get_nowait() + assert isinstance(result, RuntimeError) + assert str(result) == "Toncenter facilitator account stream closed" + assert close_calls == ["closed"] + assert client._watcher is None + assert client._watched_address is None diff --git a/python/x402/tests/unit/mechanisms/tvm/test_trace_utils.py b/python/x402/tests/unit/mechanisms/tvm/test_trace_utils.py new file mode 100644 index 0000000000..b01fcca162 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_trace_utils.py @@ -0,0 +1,183 @@ +"""Focused tests for TVM trace utility helpers.""" + +from __future__ import annotations + +import base64 + +import pytest + +from x402.mechanisms.tvm.trace_utils import ( + body_hash_to_base64, + message_body_hash_matches, + parse_trace_transactions, + trace_transaction_balance_before, + trace_transaction_compute_fees, + trace_transaction_fwd_fees, + trace_transaction_hash_to_hex, + trace_transaction_storage_fees, + transaction_succeeded, +) + + +class TestParseTraceTransactions: + def test_should_return_transactions_values(self): + transactions = parse_trace_transactions( + {"transactions": {"a": {"hash": "1"}, "b": {"hash": "2"}}} + ) + + assert transactions == [{"hash": "1"}, {"hash": "2"}] + + def test_should_reject_malformed_trace_payload(self): + with pytest.raises(ValueError, match="transactions dict"): + parse_trace_transactions({}) + + +class TestTransactionSucceeded: + def test_should_return_true_for_successful_transaction(self): + assert transaction_succeeded( + { + "description": { + "aborted": False, + "compute_ph": {"success": True, "skipped": False}, + "action": {"success": True}, + } + } + ) + + @pytest.mark.parametrize( + "transaction", + [ + pytest.param( + { + "description": { + "aborted": True, + "compute_ph": {"success": True, "skipped": False}, + } + }, + id="aborted", + ), + pytest.param( + { + "description": { + "aborted": False, + "compute_ph": {"success": False, "skipped": False}, + } + }, + id="compute-failed", + ), + pytest.param( + { + "description": { + "aborted": False, + "compute_ph": {"success": True, "skipped": True}, + } + }, + id="compute-skipped", + ), + pytest.param( + { + "description": { + "aborted": False, + "compute_ph": {"success": True, "skipped": False}, + "action": {"success": False}, + } + }, + id="action-failed", + ), + ], + ) + def test_should_return_false_for_failed_transaction(self, transaction): + assert transaction_succeeded(transaction) is False + + +class TestBodyHashes: + def test_should_encode_raw_hash_to_base64(self): + raw_hash = b"\x01\x02\x03" + + assert body_hash_to_base64(raw_hash) == base64.b64encode(raw_hash).decode("ascii") + + def test_should_convert_toncenter_transaction_hash_to_hex(self): + raw_hash = bytes(range(32)) + + assert ( + trace_transaction_hash_to_hex(base64.b64encode(raw_hash).decode("ascii")) + == raw_hash.hex() + ) + + def test_should_match_message_content_hash(self): + raw_hash = b"\x05" * 32 + message = {"message_content": {"hash": body_hash_to_base64(raw_hash)}} + + assert message_body_hash_matches(message, raw_hash) is True + assert message_body_hash_matches(message, b"\x06" * 32) is False + + +class TestForwardFees: + def test_should_sum_forward_fees_from_out_messages(self): + assert ( + trace_transaction_fwd_fees( + {"out_msgs": [{"fwd_fee": "10"}, {"fwd_fee": "0x20"}, {"fwd_fee": "bad"}]} + ) + == 42 + ) + + def test_should_fallback_to_total_fwd_fees_from_action_phase(self): + assert ( + trace_transaction_fwd_fees({"description": {"action": {"total_fwd_fees": "55"}}}) == 55 + ) + + def test_should_fallback_to_fwd_fee_times_expected_count(self): + assert ( + trace_transaction_fwd_fees( + {"description": {"action": {"fwd_fee": "7"}}}, + expected_count=3, + ) + == 21 + ) + + def test_should_return_zero_when_fees_are_missing(self): + assert trace_transaction_fwd_fees({"description": {}}) == 0 + + +class TestOtherFeeExtraction: + def test_should_extract_compute_fees(self): + assert ( + trace_transaction_compute_fees({"description": {"compute_ph": {"gas_fees": "33"}}}) + == 33 + ) + + def test_should_extract_storage_fees_collected_then_due(self): + assert ( + trace_transaction_storage_fees( + {"description": {"storage_ph": {"storage_fees_collected": "44"}}} + ) + == 44 + ) + assert ( + trace_transaction_storage_fees( + {"description": {"storage_ph": {"storage_fees_due": "55"}}} + ) + == 55 + ) + + +class TestBalanceBefore: + def test_should_prefer_account_state_before_balance(self): + assert ( + trace_transaction_balance_before( + { + "account_state_before": {"balance": "10"}, + "account_state": {"balance": "20"}, + "balance": "30", + } + ) + == 10 + ) + + def test_should_fallback_to_account_state_then_transaction_balance(self): + assert trace_transaction_balance_before({"account_state": {"balance": "20"}}) == 20 + assert trace_transaction_balance_before({"balance": "30"}) == 30 + + def test_should_fail_when_balance_is_missing(self): + with pytest.raises(ValueError, match="missing account_state_before balance"): + trace_transaction_balance_before({}) diff --git a/python/x402/tests/unit/mechanisms/tvm/test_types.py b/python/x402/tests/unit/mechanisms/tvm/test_types.py new file mode 100644 index 0000000000..ee5781da79 --- /dev/null +++ b/python/x402/tests/unit/mechanisms/tvm/test_types.py @@ -0,0 +1,137 @@ +"""Tests for TVM payload and parsed data types.""" + +import pytest + +pytest.importorskip("pytoniq_core") + +from pytoniq_core import begin_cell + +from x402.mechanisms.tvm import ( + ExactTvmPayload, + ParsedJettonTransfer, + ParsedTvmSettlement, + TvmAccountState, + TvmJettonWalletData, + TvmRelayRequest, +) + + +class TestExactTvmPayload: + """Test ExactTvmPayload serialization helpers.""" + + def test_to_dict_should_return_expected_shape(self): + """to_dict should use public JSON field names.""" + payload = ExactTvmPayload( + settlement_boc="base64-boc==", + asset="0:" + "1" * 64, + ) + + assert payload.to_dict() == { + "settlementBoc": "base64-boc==", + "asset": "0:" + "1" * 64, + } + + def test_from_dict_should_create_payload_from_dict(self): + """from_dict should hydrate the dataclass from JSON field names.""" + payload = ExactTvmPayload.from_dict( + { + "settlementBoc": "base64-boc==", + "asset": "0:" + "2" * 64, + } + ) + + assert payload.settlement_boc == "base64-boc==" + assert payload.asset == "0:" + "2" * 64 + + def test_round_trip_serialization(self): + """Should preserve data through serialization round-trip.""" + original = ExactTvmPayload( + settlement_boc="payload==", + asset="0:" + "3" * 64, + ) + + restored = ExactTvmPayload.from_dict(original.to_dict()) + + assert restored == original + + def test_from_dict_should_reject_missing_settlement_boc(self): + """from_dict should reject payloads without settlementBoc.""" + with pytest.raises(ValueError, match="settlementBoc.*required"): + ExactTvmPayload.from_dict({"asset": "0:" + "2" * 64}) + + def test_from_dict_should_reject_empty_asset(self): + """from_dict should reject payloads with an empty asset.""" + with pytest.raises(ValueError, match="asset.*required"): + ExactTvmPayload.from_dict( + { + "settlementBoc": "base64-boc==", + "asset": " ", + } + ) + + +class TestParsedTypes: + """Test TVM parsed settlement dataclasses.""" + + def test_should_store_account_state_data(self): + """Account state dataclass should retain provided fields.""" + state = TvmAccountState( + address="0:" + "4" * 64, + balance=123, + is_active=True, + is_frozen=False, + is_uninitialized=False, + state_init=None, + ) + + assert state.address == "0:" + "4" * 64 + assert state.balance == 123 + assert state.is_active is True + + def test_should_store_jetton_wallet_data(self): + """Jetton wallet dataclass should retain provided fields.""" + wallet = TvmJettonWalletData( + address="0:" + "5" * 64, + balance=456, + owner="0:" + "6" * 64, + jetton_minter="0:" + "7" * 64, + ) + + assert wallet.balance == 456 + assert wallet.owner == "0:" + "6" * 64 + + def test_should_store_relay_request_and_parsed_settlement(self): + """Parsed transfer/settlement dataclasses should accept cell payloads.""" + cell = begin_cell().store_uint(1, 1).end_cell() + relay_request = TvmRelayRequest( + destination="0:" + "8" * 64, + body=cell, + state_init=None, + ) + transfer = ParsedJettonTransfer( + source_wallet="0:" + "9" * 64, + destination="0:" + "a" * 64, + response_destination=None, + jetton_amount=1000, + attached_ton_amount=2000, + forward_ton_amount=1, + forward_payload=cell, + body_hash=b"hash", + ) + settlement = ParsedTvmSettlement( + payer="0:" + "c" * 64, + wallet_id=1, + valid_until=2, + seqno=3, + settlement_hash="hash-1", + body=cell, + signed_slice_hash=b"slice", + signature=b"sig", + state_init=None, + transfer=transfer, + ) + + assert relay_request.body == cell + assert settlement.transfer.attached_ton_amount == 2000 + assert settlement.transfer.jetton_amount == 1000 + assert settlement.signature == b"sig" diff --git a/python/x402/uv.lock b/python/x402/uv.lock index d9b2c5ceb9..4ba512290a 100644 --- a/python/x402/uv.lock +++ b/python/x402/uv.lock @@ -1,7 +1,11 @@ version = 1 -revision = 2 +revision = 3 requires-python = ">=3.10" +[options] +exclude-newer = "0001-01-01T00:00:00Z" # This has no effect and is included for backwards compatibility when using relative exclude-newer values. +exclude-newer-span = "P3D" + [[package]] name = "aiohappyeyeballs" version = "2.6.1" @@ -2138,6 +2142,41 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/d1/92/2eadd1341abd2989cce2e2740b4423608ee2014acb8110438244ee97d7ff/pycryptodome-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:45c69ad715ca1a94f778215a11e66b7ff989d792a4d63b68dc586a1da1392ff5", size = 1803005, upload-time = "2025-05-17T17:21:31.37Z" }, ] +[[package]] +name = "pycryptodomex" +version = "3.23.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c9/85/e24bf90972a30b0fcd16c73009add1d7d7cd9140c2498a68252028899e41/pycryptodomex-3.23.0.tar.gz", hash = "sha256:71909758f010c82bc99b0abf4ea12012c98962fbf0583c2164f8b84533c2e4da", size = 4922157, upload-time = "2025-05-17T17:23:41.434Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/00/10edb04777069a42490a38c137099d4b17ba6e36a4e6e28bdc7470e9e853/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:7b37e08e3871efe2187bc1fd9320cc81d87caf19816c648f24443483005ff886", size = 2498764, upload-time = "2025-05-17T17:22:21.453Z" }, + { url = "https://files.pythonhosted.org/packages/6b/3f/2872a9c2d3a27eac094f9ceaa5a8a483b774ae69018040ea3240d5b11154/pycryptodomex-3.23.0-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:91979028227543010d7b2ba2471cf1d1e398b3f183cb105ac584df0c36dac28d", size = 1643012, upload-time = "2025-05-17T17:22:23.702Z" }, + { url = "https://files.pythonhosted.org/packages/70/af/774c2e2b4f6570fbf6a4972161adbb183aeeaa1863bde31e8706f123bf92/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6b8962204c47464d5c1c4038abeadd4514a133b28748bcd9fa5b6d62e3cec6fa", size = 2187643, upload-time = "2025-05-17T17:22:26.37Z" }, + { url = "https://files.pythonhosted.org/packages/de/a3/71065b24cb889d537954cedc3ae5466af00a2cabcff8e29b73be047e9a19/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a33986a0066860f7fcf7c7bd2bc804fa90e434183645595ae7b33d01f3c91ed8", size = 2273762, upload-time = "2025-05-17T17:22:28.313Z" }, + { url = "https://files.pythonhosted.org/packages/c9/0b/ff6f43b7fbef4d302c8b981fe58467b8871902cdc3eb28896b52421422cc/pycryptodomex-3.23.0-cp313-cp313t-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c7947ab8d589e3178da3d7cdeabe14f841b391e17046954f2fbcd941705762b5", size = 2313012, upload-time = "2025-05-17T17:22:30.57Z" }, + { url = "https://files.pythonhosted.org/packages/02/de/9d4772c0506ab6da10b41159493657105d3f8bb5c53615d19452afc6b315/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c25e30a20e1b426e1f0fa00131c516f16e474204eee1139d1603e132acffc314", size = 2186856, upload-time = "2025-05-17T17:22:32.819Z" }, + { url = "https://files.pythonhosted.org/packages/28/ad/8b30efcd6341707a234e5eba5493700a17852ca1ac7a75daa7945fcf6427/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_i686.whl", hash = "sha256:da4fa650cef02db88c2b98acc5434461e027dce0ae8c22dd5a69013eaf510006", size = 2347523, upload-time = "2025-05-17T17:22:35.386Z" }, + { url = "https://files.pythonhosted.org/packages/0f/02/16868e9f655b7670dbb0ac4f2844145cbc42251f916fc35c414ad2359849/pycryptodomex-3.23.0-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:58b851b9effd0d072d4ca2e4542bf2a4abcf13c82a29fd2c93ce27ee2a2e9462", size = 2272825, upload-time = "2025-05-17T17:22:37.632Z" }, + { url = "https://files.pythonhosted.org/packages/ca/18/4ca89ac737230b52ac8ffaca42f9c6f1fd07c81a6cd821e91af79db60632/pycryptodomex-3.23.0-cp313-cp313t-win32.whl", hash = "sha256:a9d446e844f08299236780f2efa9898c818fe7e02f17263866b8550c7d5fb328", size = 1772078, upload-time = "2025-05-17T17:22:40Z" }, + { url = "https://files.pythonhosted.org/packages/73/34/13e01c322db027682e00986873eca803f11c56ade9ba5bbf3225841ea2d4/pycryptodomex-3.23.0-cp313-cp313t-win_amd64.whl", hash = "sha256:bc65bdd9fc8de7a35a74cab1c898cab391a4add33a8fe740bda00f5976ca4708", size = 1803656, upload-time = "2025-05-17T17:22:42.139Z" }, + { url = "https://files.pythonhosted.org/packages/54/68/9504c8796b1805d58f4425002bcca20f12880e6fa4dc2fc9a668705c7a08/pycryptodomex-3.23.0-cp313-cp313t-win_arm64.whl", hash = "sha256:c885da45e70139464f082018ac527fdaad26f1657a99ee13eecdce0f0ca24ab4", size = 1707172, upload-time = "2025-05-17T17:22:44.704Z" }, + { url = "https://files.pythonhosted.org/packages/dd/9c/1a8f35daa39784ed8adf93a694e7e5dc15c23c741bbda06e1d45f8979e9e/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_universal2.whl", hash = "sha256:06698f957fe1ab229a99ba2defeeae1c09af185baa909a31a5d1f9d42b1aaed6", size = 2499240, upload-time = "2025-05-17T17:22:46.953Z" }, + { url = "https://files.pythonhosted.org/packages/7a/62/f5221a191a97157d240cf6643747558759126c76ee92f29a3f4aee3197a5/pycryptodomex-3.23.0-cp37-abi3-macosx_10_9_x86_64.whl", hash = "sha256:b2c2537863eccef2d41061e82a881dcabb04944c5c06c5aa7110b577cc487545", size = 1644042, upload-time = "2025-05-17T17:22:49.098Z" }, + { url = "https://files.pythonhosted.org/packages/8c/fd/5a054543c8988d4ed7b612721d7e78a4b9bf36bc3c5ad45ef45c22d0060e/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:43c446e2ba8df8889e0e16f02211c25b4934898384c1ec1ec04d7889c0333587", size = 2186227, upload-time = "2025-05-17T17:22:51.139Z" }, + { url = "https://files.pythonhosted.org/packages/c8/a9/8862616a85cf450d2822dbd4fff1fcaba90877907a6ff5bc2672cafe42f8/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f489c4765093fb60e2edafdf223397bc716491b2b69fe74367b70d6999257a5c", size = 2272578, upload-time = "2025-05-17T17:22:53.676Z" }, + { url = "https://files.pythonhosted.org/packages/46/9f/bda9c49a7c1842820de674ab36c79f4fbeeee03f8ff0e4f3546c3889076b/pycryptodomex-3.23.0-cp37-abi3-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:bdc69d0d3d989a1029df0eed67cc5e8e5d968f3724f4519bd03e0ec68df7543c", size = 2312166, upload-time = "2025-05-17T17:22:56.585Z" }, + { url = "https://files.pythonhosted.org/packages/03/cc/870b9bf8ca92866ca0186534801cf8d20554ad2a76ca959538041b7a7cf4/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:6bbcb1dd0f646484939e142462d9e532482bc74475cecf9c4903d4e1cd21f003", size = 2185467, upload-time = "2025-05-17T17:22:59.237Z" }, + { url = "https://files.pythonhosted.org/packages/96/e3/ce9348236d8e669fea5dd82a90e86be48b9c341210f44e25443162aba187/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_i686.whl", hash = "sha256:8a4fcd42ccb04c31268d1efeecfccfd1249612b4de6374205376b8f280321744", size = 2346104, upload-time = "2025-05-17T17:23:02.112Z" }, + { url = "https://files.pythonhosted.org/packages/a5/e9/e869bcee87beb89040263c416a8a50204f7f7a83ac11897646c9e71e0daf/pycryptodomex-3.23.0-cp37-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:55ccbe27f049743a4caf4f4221b166560d3438d0b1e5ab929e07ae1702a4d6fd", size = 2271038, upload-time = "2025-05-17T17:23:04.872Z" }, + { url = "https://files.pythonhosted.org/packages/8d/67/09ee8500dd22614af5fbaa51a4aee6e342b5fa8aecf0a6cb9cbf52fa6d45/pycryptodomex-3.23.0-cp37-abi3-win32.whl", hash = "sha256:189afbc87f0b9f158386bf051f720e20fa6145975f1e76369303d0f31d1a8d7c", size = 1771969, upload-time = "2025-05-17T17:23:07.115Z" }, + { url = "https://files.pythonhosted.org/packages/69/96/11f36f71a865dd6df03716d33bd07a67e9d20f6b8d39820470b766af323c/pycryptodomex-3.23.0-cp37-abi3-win_amd64.whl", hash = "sha256:52e5ca58c3a0b0bd5e100a9fbc8015059b05cffc6c66ce9d98b4b45e023443b9", size = 1803124, upload-time = "2025-05-17T17:23:09.267Z" }, + { url = "https://files.pythonhosted.org/packages/f9/93/45c1cdcbeb182ccd2e144c693eaa097763b08b38cded279f0053ed53c553/pycryptodomex-3.23.0-cp37-abi3-win_arm64.whl", hash = "sha256:02d87b80778c171445d67e23d1caef279bf4b25c3597050ccd2e13970b57fd51", size = 1707161, upload-time = "2025-05-17T17:23:11.414Z" }, + { url = "https://files.pythonhosted.org/packages/f3/b8/3e76d948c3c4ac71335bbe75dac53e154b40b0f8f1f022dfa295257a0c96/pycryptodomex-3.23.0-pp310-pypy310_pp73-macosx_10_15_x86_64.whl", hash = "sha256:ebfff755c360d674306e5891c564a274a47953562b42fb74a5c25b8fc1fb1cb5", size = 1627695, upload-time = "2025-05-17T17:23:17.38Z" }, + { url = "https://files.pythonhosted.org/packages/6a/cf/80f4297a4820dfdfd1c88cf6c4666a200f204b3488103d027b5edd9176ec/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eca54f4bb349d45afc17e3011ed4264ef1cc9e266699874cdd1349c504e64798", size = 1675772, upload-time = "2025-05-17T17:23:19.202Z" }, + { url = "https://files.pythonhosted.org/packages/d1/42/1e969ee0ad19fe3134b0e1b856c39bd0b70d47a4d0e81c2a8b05727394c9/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2596e643d4365e14d0879dc5aafe6355616c61c2176009270f3048f6d9a61f", size = 1668083, upload-time = "2025-05-17T17:23:21.867Z" }, + { url = "https://files.pythonhosted.org/packages/6e/c3/1de4f7631fea8a992a44ba632aa40e0008764c0fb9bf2854b0acf78c2cf2/pycryptodomex-3.23.0-pp310-pypy310_pp73-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fdfac7cda115bca3a5abb2f9e43bc2fb66c2b65ab074913643803ca7083a79ea", size = 1706056, upload-time = "2025-05-17T17:23:24.031Z" }, + { url = "https://files.pythonhosted.org/packages/f2/5f/af7da8e6f1e42b52f44a24d08b8e4c726207434e2593732d39e7af5e7256/pycryptodomex-3.23.0-pp310-pypy310_pp73-win_amd64.whl", hash = "sha256:14c37aaece158d0ace436f76a7bb19093db3b4deade9797abfc39ec6cd6cc2fe", size = 1806478, upload-time = "2025-05-17T17:23:26.066Z" }, +] + [[package]] name = "pydantic" version = "2.12.5" @@ -2326,6 +2365,41 @@ crypto = [ { name = "cryptography" }, ] +[[package]] +name = "pynacl" +version = "1.6.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "cffi", marker = "platform_python_implementation != 'PyPy'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/d9/9a/4019b524b03a13438637b11538c82781a5eda427394380381af8f04f467a/pynacl-1.6.2.tar.gz", hash = "sha256:018494d6d696ae03c7e656e5e74cdfd8ea1326962cc401bcf018f1ed8436811c", size = 3511692, upload-time = "2026-01-01T17:48:10.851Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/79/0e3c34dc3c4671f67d251c07aa8eb100916f250ee470df230b0ab89551b4/pynacl-1.6.2-cp314-cp314t-macosx_10_10_universal2.whl", hash = "sha256:622d7b07cc5c02c666795792931b50c91f3ce3c2649762efb1ef0d5684c81594", size = 390064, upload-time = "2026-01-01T17:31:57.264Z" }, + { url = "https://files.pythonhosted.org/packages/eb/1c/23a26e931736e13b16483795c8a6b2f641bf6a3d5238c22b070a5112722c/pynacl-1.6.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:d071c6a9a4c94d79eb665db4ce5cedc537faf74f2355e4d502591d850d3913c0", size = 809370, upload-time = "2026-01-01T17:31:59.198Z" }, + { url = "https://files.pythonhosted.org/packages/87/74/8d4b718f8a22aea9e8dcc8b95deb76d4aae380e2f5b570cc70b5fd0a852d/pynacl-1.6.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:fe9847ca47d287af41e82be1dd5e23023d3c31a951da134121ab02e42ac218c9", size = 1408304, upload-time = "2026-01-01T17:32:01.162Z" }, + { url = "https://files.pythonhosted.org/packages/fd/73/be4fdd3a6a87fe8a4553380c2b47fbd1f7f58292eb820902f5c8ac7de7b0/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:04316d1fc625d860b6c162fff704eb8426b1a8bcd3abacea11142cbd99a6b574", size = 844871, upload-time = "2026-01-01T17:32:02.824Z" }, + { url = "https://files.pythonhosted.org/packages/55/ad/6efc57ab75ee4422e96b5f2697d51bbcf6cdcc091e66310df91fbdc144a8/pynacl-1.6.2-cp314-cp314t-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:44081faff368d6c5553ccf55322ef2819abb40e25afaec7e740f159f74813634", size = 1446356, upload-time = "2026-01-01T17:32:04.452Z" }, + { url = "https://files.pythonhosted.org/packages/78/b7/928ee9c4779caa0a915844311ab9fb5f99585621c5d6e4574538a17dca07/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_aarch64.whl", hash = "sha256:a9f9932d8d2811ce1a8ffa79dcbdf3970e7355b5c8eb0c1a881a57e7f7d96e88", size = 826814, upload-time = "2026-01-01T17:32:06.078Z" }, + { url = "https://files.pythonhosted.org/packages/f7/a9/1bdba746a2be20f8809fee75c10e3159d75864ef69c6b0dd168fc60e485d/pynacl-1.6.2-cp314-cp314t-manylinux_2_34_x86_64.whl", hash = "sha256:bc4a36b28dd72fb4845e5d8f9760610588a96d5a51f01d84d8c6ff9849968c14", size = 1411742, upload-time = "2026-01-01T17:32:07.651Z" }, + { url = "https://files.pythonhosted.org/packages/f3/2f/5e7ea8d85f9f3ea5b6b87db1d8388daa3587eed181bdeb0306816fdbbe79/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:3bffb6d0f6becacb6526f8f42adfb5efb26337056ee0831fb9a7044d1a964444", size = 801714, upload-time = "2026-01-01T17:32:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/06/ea/43fe2f7eab5f200e40fb10d305bf6f87ea31b3bbc83443eac37cd34a9e1e/pynacl-1.6.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:2fef529ef3ee487ad8113d287a593fa26f48ee3620d92ecc6f1d09ea38e0709b", size = 1372257, upload-time = "2026-01-01T17:32:11.026Z" }, + { url = "https://files.pythonhosted.org/packages/4d/54/c9ea116412788629b1347e415f72195c25eb2f3809b2d3e7b25f5c79f13a/pynacl-1.6.2-cp314-cp314t-win32.whl", hash = "sha256:a84bf1c20339d06dc0c85d9aea9637a24f718f375d861b2668b2f9f96fa51145", size = 231319, upload-time = "2026-01-01T17:32:12.46Z" }, + { url = "https://files.pythonhosted.org/packages/ce/04/64e9d76646abac2dccf904fccba352a86e7d172647557f35b9fe2a5ee4a1/pynacl-1.6.2-cp314-cp314t-win_amd64.whl", hash = "sha256:320ef68a41c87547c91a8b58903c9caa641ab01e8512ce291085b5fe2fcb7590", size = 244044, upload-time = "2026-01-01T17:32:13.781Z" }, + { url = "https://files.pythonhosted.org/packages/33/33/7873dc161c6a06f43cda13dec67b6fe152cb2f982581151956fa5e5cdb47/pynacl-1.6.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d29bfe37e20e015a7d8b23cfc8bd6aa7909c92a1b8f41ee416bbb3e79ef182b2", size = 188740, upload-time = "2026-01-01T17:32:15.083Z" }, + { url = "https://files.pythonhosted.org/packages/be/7b/4845bbf88e94586ec47a432da4e9107e3fc3ce37eb412b1398630a37f7dd/pynacl-1.6.2-cp38-abi3-macosx_10_10_universal2.whl", hash = "sha256:c949ea47e4206af7c8f604b8278093b674f7c79ed0d4719cc836902bf4517465", size = 388458, upload-time = "2026-01-01T17:32:16.829Z" }, + { url = "https://files.pythonhosted.org/packages/1e/b4/e927e0653ba63b02a4ca5b4d852a8d1d678afbf69b3dbf9c4d0785ac905c/pynacl-1.6.2-cp38-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:8845c0631c0be43abdd865511c41eab235e0be69c81dc66a50911594198679b0", size = 800020, upload-time = "2026-01-01T17:32:18.34Z" }, + { url = "https://files.pythonhosted.org/packages/7f/81/d60984052df5c97b1d24365bc1e30024379b42c4edcd79d2436b1b9806f2/pynacl-1.6.2-cp38-abi3-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:22de65bb9010a725b0dac248f353bb072969c94fa8d6b1f34b87d7953cf7bbe4", size = 1399174, upload-time = "2026-01-01T17:32:20.239Z" }, + { url = "https://files.pythonhosted.org/packages/68/f7/322f2f9915c4ef27d140101dd0ed26b479f7e6f5f183590fd32dfc48c4d3/pynacl-1.6.2-cp38-abi3-manylinux_2_26_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:46065496ab748469cdd999246d17e301b2c24ae2fdf739132e580a0e94c94a87", size = 835085, upload-time = "2026-01-01T17:32:22.24Z" }, + { url = "https://files.pythonhosted.org/packages/3e/d0/f301f83ac8dbe53442c5a43f6a39016f94f754d7a9815a875b65e218a307/pynacl-1.6.2-cp38-abi3-manylinux_2_26_x86_64.manylinux_2_28_x86_64.whl", hash = "sha256:8a66d6fb6ae7661c58995f9c6435bda2b1e68b54b598a6a10247bfcdadac996c", size = 1437614, upload-time = "2026-01-01T17:32:23.766Z" }, + { url = "https://files.pythonhosted.org/packages/c4/58/fc6e649762b029315325ace1a8c6be66125e42f67416d3dbd47b69563d61/pynacl-1.6.2-cp38-abi3-manylinux_2_34_aarch64.whl", hash = "sha256:26bfcd00dcf2cf160f122186af731ae30ab120c18e8375684ec2670dccd28130", size = 818251, upload-time = "2026-01-01T17:32:25.69Z" }, + { url = "https://files.pythonhosted.org/packages/c9/a8/b917096b1accc9acd878819a49d3d84875731a41eb665f6ebc826b1af99e/pynacl-1.6.2-cp38-abi3-manylinux_2_34_x86_64.whl", hash = "sha256:c8a231e36ec2cab018c4ad4358c386e36eede0319a0c41fed24f840b1dac59f6", size = 1402859, upload-time = "2026-01-01T17:32:27.215Z" }, + { url = "https://files.pythonhosted.org/packages/85/42/fe60b5f4473e12c72f977548e4028156f4d340b884c635ec6b063fe7e9a5/pynacl-1.6.2-cp38-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:68be3a09455743ff9505491220b64440ced8973fe930f270c8e07ccfa25b1f9e", size = 791926, upload-time = "2026-01-01T17:32:29.314Z" }, + { url = "https://files.pythonhosted.org/packages/fa/f9/e40e318c604259301cc091a2a63f237d9e7b424c4851cafaea4ea7c4834e/pynacl-1.6.2-cp38-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:8b097553b380236d51ed11356c953bf8ce36a29a3e596e934ecabe76c985a577", size = 1363101, upload-time = "2026-01-01T17:32:31.263Z" }, + { url = "https://files.pythonhosted.org/packages/48/47/e761c254f410c023a469284a9bc210933e18588ca87706ae93002c05114c/pynacl-1.6.2-cp38-abi3-win32.whl", hash = "sha256:5811c72b473b2f38f7e2a3dc4f8642e3a3e9b5e7317266e4ced1fba85cae41aa", size = 227421, upload-time = "2026-01-01T17:32:33.076Z" }, + { url = "https://files.pythonhosted.org/packages/41/ad/334600e8cacc7d86587fe5f565480fde569dfb487389c8e1be56ac21d8ac/pynacl-1.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:62985f233210dee6548c223301b6c25440852e13d59a8b81490203c3227c5ba0", size = 239754, upload-time = "2026-01-01T17:32:34.557Z" }, + { url = "https://files.pythonhosted.org/packages/29/7d/5945b5af29534641820d3bd7b00962abbbdfee84ec7e19f0d5b3175f9a31/pynacl-1.6.2-cp38-abi3-win_arm64.whl", hash = "sha256:834a43af110f743a754448463e8fd61259cd4ab5bbedcf70f9dabad1d28a394c", size = 184801, upload-time = "2026-01-01T17:32:36.309Z" }, +] + [[package]] name = "pytest" version = "9.0.2" @@ -2385,6 +2459,37 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/84/25/d9db8be44e205a124f6c98bc0324b2bb149b7431c53877fc6d1038dddaf5/pytokens-0.3.0-py3-none-any.whl", hash = "sha256:95b2b5eaf832e469d141a378872480ede3f251a5a5041b8ec6e581d3ac71bbf3", size = 12195, upload-time = "2025-11-05T13:36:33.183Z" }, ] +[[package]] +name = "pytoniq" +version = "0.1.43" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pytoniq-core" }, + { name = "requests" }, + { name = "setuptools" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/37/b2/9991a953e4b766918a142fe111f71f12803c6acf65eb30f36eb85ed08f31/pytoniq-0.1.43.tar.gz", hash = "sha256:b4b1c8fed2f9d2f1b6f0ab4b3f1fc5503a0088630d8081f817807ff31e608606", size = 50463, upload-time = "2025-11-30T12:30:41.102Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cd/c1/b6e5c739839e0e12bde4563438acd55d39552ea63f6de123724b4b91ac64/pytoniq-0.1.43-py3-none-any.whl", hash = "sha256:922c1721124bf7214e0b7044fba2a439e006367778611c0ce813cbe5b00079d3", size = 56118, upload-time = "2025-11-30T12:30:39.65Z" }, +] + +[[package]] +name = "pytoniq-core" +version = "0.1.46" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "bitarray" }, + { name = "pycryptodomex" }, + { name = "pynacl" }, + { name = "requests" }, + { name = "setuptools" }, + { name = "x25519" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/a3/2c/7afbb9003a3aa72ccfe69711433fe36d2493db2c4acf66dde32f7b55799b/pytoniq_core-0.1.46.tar.gz", hash = "sha256:c8e3cf9ccb1852780a725cd51ba7a66a28122eb39c8b9bb97dcdc5bd02c24734", size = 101236, upload-time = "2025-11-28T10:23:21.887Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/7b/0e/e27cf7ce1bebb47fb95e1d6deae5c91c6ffcb7851f156990e57079cbe8db/pytoniq_core-0.1.46-py3-none-any.whl", hash = "sha256:0a284c8b68f9fed9d54e4dad871238d844339183bf985a614796360e36e1b95e", size = 91400, upload-time = "2025-11-28T10:23:20.95Z" }, +] + [[package]] name = "pyunormalize" version = "17.0.0" @@ -2937,6 +3042,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/4d/19/8d77f9992e5cbfcaa9133c3bf63b4fbbb051248802e1e803fed5c552fbb2/sentry_sdk-2.48.0-py2.py3-none-any.whl", hash = "sha256:6b12ac256769d41825d9b7518444e57fa35b5642df4c7c5e322af4d2c8721172", size = 414555, upload-time = "2025-12-16T14:55:40.152Z" }, ] +[[package]] +name = "setuptools" +version = "82.0.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/4f/db/cfac1baf10650ab4d1c111714410d2fbb77ac5a616db26775db562c8fab2/setuptools-82.0.1.tar.gz", hash = "sha256:7d872682c5d01cfde07da7bccc7b65469d3dca203318515ada1de5eda35efbf9", size = 1152316, upload-time = "2026-03-09T12:47:17.221Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/9d/76/f789f7a86709c6b087c5a2f52f911838cad707cc613162401badc665acfe/setuptools-82.0.1-py3-none-any.whl", hash = "sha256:a59e362652f08dcd477c78bb6e7bd9d80a7995bc73ce773050228a348ce2e5bb", size = 1006223, upload-time = "2026-03-09T12:47:15.026Z" }, +] + [[package]] name = "shellingham" version = "1.5.4" @@ -3405,9 +3519,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2f/f9/9e082990c2585c744734f85bec79b5dae5df9c974ffee58fe421652c8e91/werkzeug-3.1.4-py3-none-any.whl", hash = "sha256:2ad50fb9ed09cc3af22c54698351027ace879a0b60a3b5edf5730b2f7d876905", size = 224960, upload-time = "2025-11-29T02:15:21.13Z" }, ] +[[package]] +name = "x25519" +version = "0.0.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/c7/b6/fca895aff0800cdf941f856df0685a5513094163664b904576e3e3ef1460/x25519-0.0.2.tar.gz", hash = "sha256:ed91d0aba7f4f4959ed8b37118c11d94f56d36c38bb6f2e6c20d0438d75b1556", size = 4833, upload-time = "2021-10-24T15:18:38.051Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/f2/d1/66c637eb8e7a9601675bf7f04bb9a3015358a0f49e4c31d29a2b9a9d72d9/x25519-0.0.2-py3-none-any.whl", hash = "sha256:5c0833260a548bea9137a5a1b5c30334b751a59d148a62832df0c9e7b919ce99", size = 4907, upload-time = "2021-10-24T15:18:36.727Z" }, +] + [[package]] name = "x402" -version = "2.5.0" +version = "2.10.0" source = { editable = "." } dependencies = [ { name = "nest-asyncio" }, @@ -3424,8 +3547,12 @@ all = [ { name = "fastapi", extra = ["standard"] }, { name = "flask" }, { name = "httpx" }, + { name = "idna" }, { name = "jsonschema" }, { name = "mcp" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, { name = "requests" }, { name = "solana" }, { name = "solders" }, @@ -3444,6 +3571,7 @@ evm = [ { name = "web3" }, ] extensions = [ + { name = "idna" }, { name = "jsonschema" }, ] fastapi = [ @@ -3464,6 +3592,10 @@ mechanisms = [ { name = "eth-account" }, { name = "eth-keys" }, { name = "eth-utils" }, + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, { name = "solana" }, { name = "solders" }, { name = "web3" }, @@ -3480,6 +3612,12 @@ svm = [ { name = "solana" }, { name = "solders" }, ] +tvm = [ + { name = "httpx" }, + { name = "pynacl" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, +] [package.dev-dependencies] dev = [ @@ -3491,12 +3629,16 @@ dev = [ { name = "fastapi", extra = ["standard"] }, { name = "flask" }, { name = "httpx" }, + { name = "idna" }, { name = "jsonschema" }, { name = "mcp" }, { name = "mypy" }, { name = "nest-asyncio" }, + { name = "pynacl" }, { name = "pytest" }, { name = "pytest-asyncio" }, + { name = "pytoniq" }, + { name = "pytoniq-core" }, { name = "requests" }, { name = "ruff" }, { name = "solana" }, @@ -3515,22 +3657,27 @@ requires-dist = [ { name = "fastapi", extras = ["standard"], marker = "extra == 'fastapi'", specifier = ">=0.115.0" }, { name = "flask", marker = "extra == 'flask'", specifier = ">=3.0.0" }, { name = "httpx", marker = "extra == 'httpx'", specifier = ">=0.28.1" }, + { name = "httpx", marker = "extra == 'tvm'", specifier = ">=0.28.1" }, + { name = "idna", marker = "extra == 'extensions'", specifier = ">=3.4" }, { name = "jsonschema", marker = "extra == 'extensions'", specifier = ">=4.0.0" }, { name = "mcp", marker = "extra == 'mcp'", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, { name = "pydantic", specifier = ">=2.0.0" }, + { name = "pynacl", marker = "extra == 'tvm'", specifier = ">=1.5.0" }, + { name = "pytoniq", marker = "extra == 'tvm'", specifier = ">=0.1.39" }, + { name = "pytoniq-core", marker = "extra == 'tvm'", specifier = ">=0.1.36" }, { name = "requests", marker = "extra == 'requests'", specifier = ">=2.31.0" }, { name = "solana", marker = "extra == 'svm'", specifier = ">=0.36.0" }, { name = "solders", marker = "extra == 'svm'", specifier = ">=0.27.0" }, { name = "starlette", marker = "extra == 'fastapi'", specifier = ">=0.27.0" }, { name = "typing-extensions", specifier = ">=4.0.0" }, { name = "web3", marker = "extra == 'evm'", specifier = ">=7.0.0" }, - { name = "x402", extras = ["evm", "svm"], marker = "extra == 'mechanisms'" }, + { name = "x402", extras = ["evm", "svm", "tvm"], marker = "extra == 'mechanisms'" }, { name = "x402", extras = ["flask", "fastapi"], marker = "extra == 'servers'" }, { name = "x402", extras = ["httpx", "requests"], marker = "extra == 'clients'" }, - { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions"], marker = "extra == 'all'" }, + { name = "x402", extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions"], marker = "extra == 'all'" }, ] -provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] +provides-extras = ["httpx", "requests", "flask", "fastapi", "evm", "svm", "tvm", "mcp", "extensions", "clients", "servers", "mechanisms", "all"] [package.metadata.requires-dev] dev = [ @@ -3542,12 +3689,16 @@ dev = [ { name = "fastapi", extras = ["standard"], specifier = ">=0.115.0" }, { name = "flask", specifier = ">=3.0.0" }, { name = "httpx", specifier = ">=0.28.1" }, + { name = "idna", specifier = ">=3.4" }, { name = "jsonschema", specifier = ">=4.0.0" }, { name = "mcp", specifier = ">=1.26.0" }, { name = "mypy", specifier = ">=1.0.0" }, { name = "nest-asyncio", specifier = ">=1.6.0" }, + { name = "pynacl", specifier = ">=1.5.0" }, { name = "pytest", specifier = ">=7.0.0" }, { name = "pytest-asyncio", specifier = ">=0.21.0" }, + { name = "pytoniq", specifier = ">=0.1.39" }, + { name = "pytoniq-core", specifier = ">=0.1.36" }, { name = "requests", specifier = ">=2.31.0" }, { name = "ruff", specifier = ">=0.1.0" }, { name = "solana", specifier = ">=0.36.0" }, diff --git a/specs/extensions/bazaar.md b/specs/extensions/bazaar.md index 96324b16ed..cc5b3e95ba 100644 --- a/specs/extensions/bazaar.md +++ b/specs/extensions/bazaar.md @@ -27,7 +27,10 @@ The `info.input` object uses a discriminated union type, distinguished by the `t "resource": { "url": "https://api.example.com/weather", "description": "Weather data endpoint", - "mimeType": "application/json" + "mimeType": "application/json", + "serviceName": "Example Weather", + "tags": ["weather", "forecast"], + "iconUrl": "https://api.example.com/icon.png" }, "accepts": [ ... ], "extensions": { @@ -181,7 +184,7 @@ The `info.input` object uses a discriminated union type, distinguished by the `t "info": { "input": { "type": "mcp", - "tool": "financial_analysis", + "toolName": "financial_analysis", "description": "Advanced AI-powered financial analysis", "inputSchema": { "type": "object", @@ -212,13 +215,13 @@ The `info.input` object uses a discriminated union type, distinguished by the `t "type": "object", "properties": { "type": { "type": "string", "const": "mcp" }, - "tool": { "type": "string" }, + "toolName": { "type": "string" }, "description": { "type": "string" }, "transport": { "type": "string", "enum": ["streamable-http", "sse"] }, "inputSchema": { "type": "object" }, "example": { "type": "object" } }, - "required": ["type", "tool", "inputSchema"], + "required": ["type", "toolName", "inputSchema"], "additionalProperties": false }, "output": { @@ -270,13 +273,13 @@ The `info.input` object describes how to call the endpoint or tool. | Field | Type | Required | Description | |-------|------|----------|-------------| | `type` | string | Yes | Always `"mcp"` | -| `tool` | string | Yes | MCP tool name (matches what's passed to `tools/call`) | +| `toolName` | string | Yes | MCP tool name (matches what's passed to `tools/call`) | | `description` | string | No | Human-readable description of the tool | | `inputSchema` | object | Yes | JSON Schema for the tool's `arguments`, following the MCP [`Tool.inputSchema`](https://spec.modelcontextprotocol.io/) format (a JSON Schema subset with `type: "object"`, `properties`, and `required`). Servers should reuse the same schema their MCP tool already declares. | | `transport` | string | No | MCP transport protocol. One of `"streamable-http"` or `"sse"`. Defaults to `"streamable-http"` if omitted. | | `example` | object | No | Example `arguments` object | -> **Note:** For MCP tools, the unique resource identifier is the tuple (`resource.url`, `input.tool`). Since MCP multiplexes multiple tools over a single server endpoint, `resource.url` alone may not be unique. Facilitators **must** use both fields when cataloging MCP tools. +> **Note:** For MCP tools, the unique resource identifier is the tuple (`resource.url`, `input.toolName`). Since MCP multiplexes multiple tools over a single server endpoint, `resource.url` alone may not be unique. Facilitators **must** use both fields when cataloging MCP tools. ### Output Types @@ -314,7 +317,7 @@ The `schema` field contains a JSON Schema (Draft 2020-12) that validates the str - May define an `output` property (optional) - Must validate that `input.type` equals `"http"` (for HTTP endpoints) or `"mcp"` (for MCP tools) - For HTTP endpoints: Must validate the appropriate `method` enum based on operation type -- For MCP tools: Must require `tool` and `inputSchema` fields +- For MCP tools: Must require `toolName` and `inputSchema` fields Facilitators **must** validate `info` against `schema` before cataloging. @@ -329,13 +332,13 @@ Facilitators **must** validate `info` against `schema` before cataloging. "type": "object", "properties": { "type": { "type": "string", "const": "mcp" }, - "tool": { "type": "string" }, + "toolName": { "type": "string" }, "description": { "type": "string" }, "transport": { "type": "string", "enum": ["streamable-http", "sse"] }, "inputSchema": { "type": "object" }, "example": { "type": "object" } }, - "required": ["type", "tool", "inputSchema"], + "required": ["type", "toolName", "inputSchema"], "additionalProperties": false }, "output": { @@ -353,6 +356,68 @@ Facilitators **must** validate `info` against `schema` before cataloging. --- +## Service Metadata on `resource` + +Resource servers MAY publish provider-level metadata describing the service that +hosts the resource. Facilitators use these fields to enrich Bazaar search results +with a human-readable name, topical tags, and an icon, without any out-of-band +admin step. The fields live on the **top-level `resource` object** of the +`PaymentRequired` response (alongside `url`, `description`, `mimeType`) and are +echoed by clients in the `PaymentPayload.resource` exactly like `description` +and `mimeType`. + +All fields are optional and purely additive. Servers that omit them produce +byte-identical 402 bodies; clients that don't recognize them ignore them. + +| Field | Type | Required | Description | +|---------------|-----------------|----------|----------------------------------------------------------------------------------------------| +| `serviceName` | string | No | Human-readable name for the service (the authority that hosts the resource). | +| `tags` | array of string | No | Short topical tags describing the service. Used for facilitator-side filtering and search. | +| `iconUrl` | string | No | Absolute `https`/`http` URL to an icon image representing the service. | + +### Validation Rules + +The facilitator is a trust boundary: clients echo the `resource` block from +`PaymentRequired` into `PaymentPayload`, so a malicious client could submit +hostile metadata to poison the catalog. SDKs and facilitators MUST apply the +following soft-drop rules during extraction. A field that fails its rule is +discarded; the surrounding metadata is preserved. + +| Field | Rule | On violation | +|---------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------| +| `serviceName` | Non-empty string of printable ASCII (U+0020–U+007E), length ≤ 32 characters; contains no Unicode control characters (category Cc). | Drop the field. | +| `tags` | Array of strings; at most 5 entries; each entry non-empty, printable ASCII (U+0020–U+007E), length ≤ 32 characters, no Unicode control characters; entries deduplicated case-insensitively (first occurrence wins). | Truncate to the first 5 valid entries; drop individual invalid entries. | +| `iconUrl` | String of length ≤ 2048; parses as an absolute `http://` or `https://` URL; no `data:` / `file:` / other non-http schemes; no userinfo (`user@`); host is IDN-normalized (UTS #46) before checks; not an IP literal (v4 or v6), not in the loopback set (`localhost`, `localhost.localdomain`, `ip6-localhost`, `ip6-loopback`), not an all-digit hostname (decimal IP encodings like `2130706433`), and not a hex literal (`0x7f000001`); contains no control characters. | Drop the field. | + +Implementations MUST percent-decode the iconUrl host before applying the IP / +`localhost` checks (parallel to how `routeTemplate` is decoded before its `..` +and `://` checks). + +The `serviceName` and `tags` ASCII restriction follows the same convention as +`paymentidentifier.id`: bounding the character set to printable ASCII keeps +length checks identical across all three SDKs (where `len()` semantics +otherwise diverge — UTF-16 code units in TypeScript, code points in Python, +bytes in Go) and avoids non-ASCII display ambiguity in catalog UIs. Providers +that need to display localized names should rely on the consuming UI for +internationalization rather than encoding non-ASCII characters in this field. + +All SDK implementations expose helpers that apply these rules identically: +`isValidServiceName`, `sanitizeTags`, `isValidIconUrl`, and a combined +`sanitizeResourceServiceMetadata` (TypeScript, Go) or `_is_valid_service_name`, +`_sanitize_tags`, `_is_valid_icon_url`, `_sanitize_resource_service_metadata` +(Python). **All three copies must stay in sync.** + +> **SDK implementers:** If you add a fourth SDK, copy these validation rules +> exactly, including the percent-decoding step before the IP / `localhost` +> checks for `iconUrl`. + +Hard rejection only happens at the JSON envelope level (handled by existing +extraction error paths). Image content-type, size, and dimension validation +are out of scope for the SDK helpers and remain the facilitator's +responsibility (e.g. via Cloudinary at serve time). + +--- + ## Facilitator Behavior When a facilitator receives a `PaymentPayload` containing the `bazaar` extension, it should: @@ -362,9 +427,51 @@ When a facilitator receives a `PaymentPayload` containing the `bazaar` extension How a facilitator stores, indexes, and exposes discovered resources is an implementation detail. Facilitators may choose to catalog resources in a database, expose them via a discovery API, or process them in any manner they see fit. -### Settlement Response Header +### Optional Discovery Endpoints + +Facilitators that implement Bazaar discovery may expose discovery APIs to let clients browse and search cataloged resources. + +#### `GET /discovery/resources` + +Lists discoverable x402 resources. + +| Parameter | Type | Required | Description | +| --------- | -------- | -------- | ------------------------------------------- | +| `type` | `string` | Optional | Filter by resource type (for example, `http` or `mcp`) | +| `payTo` | `string` | Optional | Filter by payment recipient address | +| `scheme` | `string` | Optional | Filter by payment scheme (for example, `exact`) | +| `network` | `string` | Optional | Filter by payment network (for example, `eip155:8453`) | +| `extensions` | `string` | Optional | Filter by extension key present on each resource (for example, `bazaar`) | +| `limit` | `number` | Optional | Maximum number of results to return | +| `offset` | `number` | Optional | Number of results to skip for pagination | + +#### `GET /discovery/search` + +Searches discoverable x402 resources using a natural-language query. Response shape mirrors the list endpoint with a `resources` array and optional `pagination`. + +| Parameter | Type | Required | Description | +| --------- | -------- | -------- | ------------------------------------------- | +| `query` | `string` | Yes | Natural-language search query | +| `type` | `string` | Optional | Filter by resource type (for example, `http` or `mcp`) | +| `payTo` | `string` | Optional | Filter by payment recipient address | +| `scheme` | `string` | Optional | Filter by payment scheme (for example, `exact`) | +| `network` | `string` | Optional | Filter by payment network (for example, `eip155:8453`) | +| `extensions` | `string` | Optional | Filter by extension key present on each resource (for example, `bazaar`) | +| `limit` | `number` | Optional | Advisory maximum number of results; facilitator may return fewer or ignore | +| `cursor` | `string` | Optional | Advisory continuation cursor from a previous page | + +Search responses may include: + +| Field | Type | Required | Description | +| ----- | ---- | -------- | ----------- | +| `partialResults` | `boolean` | No | `true` when additional matches were truncated | +| `pagination` | `object` or `null` | No | Pagination details for a paginated response | +| `pagination.limit` | `number` | Yes (when `pagination` is an object) | Number of results in this page | +| `pagination.cursor` | `string` or `null` | Yes (when `pagination` is an object) | Cursor for the next page, or `null` if unavailable | + +### Verify and Settlement Response Header -After processing a `PaymentPayload`, a facilitator **MAY** append an `EXTENSION-RESPONSES` HTTP header to the settlement response to communicate extension-specific outcomes to the client. +After processing a `PaymentPayload`, a facilitator **MAY** append an `EXTENSION-RESPONSES` HTTP header to the verify or settlement response to communicate extension-specific outcomes to the client. **Header name:** `EXTENSION-RESPONSES` diff --git a/specs/extensions/builder_code.md b/specs/extensions/builder_code.md new file mode 100644 index 0000000000..05c55d4e40 --- /dev/null +++ b/specs/extensions/builder_code.md @@ -0,0 +1,272 @@ +# Extension: `builder-code` + +## Summary + +The `builder-code` extension enables **on-chain attribution tracking** for x402 payments by appending [ERC-8021](https://eip.tools/eip/8021) Schema 2 builder codes to settlement transaction calldata. It attributes which application exposed the paid endpoint and which facilitator settled the payment. + +This extension implements **Schema 2** (CBOR-encoded) of ERC-8021. The `m` (custom metadata) and `r` (custom registries) fields are not supported. + +--- + +## ERC-8021 Schema 2 Overview + +ERC-8021 defines a structured data suffix appended to transaction calldata for entity attribution. Schema 2 uses CBOR encoding for extensibility. + +### Suffix Format + +The complete suffix appended to calldata is (ordered end of calldata backwards): + +| Component | Size | Description | +| ------------ | -------- | ------------------------------------------------------- | +| `ercMarker` | 16 bytes | Constant identifier: `80218021802180218021802180218021` | +| `schemaId` | 1 byte | `0x02` for Schema 2 | +| `cborLength` | 2 bytes | Length of CBOR data (big-endian) | +| `cborData` | variable | CBOR-encoded map of attribution fields | + +Wire order: `[cborData][cborLength (2B)][schemaId (1B)][ercMarker (16B)]` + +### CBOR Map Fields + +| Key | Type | Description | +| --- | --------------- | --------------------------------------------------------------- | +| `a` | string | App code — the application that exposed the paid endpoint | +| `w` | string | Wallet code — the facilitator that settled the payment on-chain | +| `s` | array of string | Service codes — clients and intermediaries that participated | + +All fields are optional. + +### Builder Code Format + +Codes must match the pattern `^[a-z0-9_]{1,32}$`: + +- **Length**: 1-32 characters +- **Characters**: lowercase alphanumeric and underscores only + +--- + +## `PaymentRequired` + +The application declares its builder code per-route in the payment middleware configuration. + +```json +{ + "x402Version": 2, + "error": "Payment required", + "accepts": [ ... ], + "extensions": { + "builder-code": { + "info": { + "a": "my_app" + }, + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "a": { + "type": "string", + "pattern": "^[a-z0-9_]{1,32}$", + "description": "App builder code" + }, + "w": { + "type": "string", + "pattern": "^[a-z0-9_]{1,32}$", + "description": "Wallet builder code" + }, + "s": { + "type": "array", + "items": { + "type": "string", + "pattern": "^[a-z0-9_]{1,32}$" + }, + "description": "Service builder codes" + } + }, + "additionalProperties": false + } + } + } +} +``` + +--- + +## `PaymentPayload` + +The client echoes the builder code extension from `PaymentRequired` into its `PaymentPayload`, and may append its own code(s) to the `s` array. + +```json +{ + "extensions": { + "builder-code": { + "a": "my_app", + "s": ["my_client"] + } + } +} +``` + +The `w` (wallet) field is **not** set by the client. It is added by the facilitator at settlement time. + +--- + +## Builder Code Fields + +| Field | Set by | When | Description | +| ----- | ----------- | ---------------------------------- | -------------------------------------------------------- | +| `a` | Application | Per-route middleware configuration | Identifies the application exposing the paid endpoint | +| `w` | Facilitator | Settlement | Identifies the facilitator settling the payment on-chain | +| `s` | Client | Payment payload construction | Identifies the client(s) and intermediaries that participated | + +--- + +## Facilitator Behavior + +When a facilitator settles a payment containing the `builder-code` extension, it: + +1. Verifies that `PaymentPayload.extensions["builder-code"].a` matches `PaymentRequired.extensions["builder-code"].info.a` +2. Reads `a` (app code) and `s` (service codes) from the payment payload extensions +3. Adds its own builder code as the `w` (wallet) field +4. Encodes the combined data as an ERC-8021 Schema 2 CBOR suffix +5. Appends the suffix to the settlement transaction calldata + +The facilitator's builder code is configured at initialization and validated against the same `^[a-z0-9_]{1,32}$` pattern. + +### Calldata Suffix Construction + +The facilitator builds the suffix as follows: + +1. CBOR-encode a map containing all present fields (`a`, `s`, `w`) +2. Compute `cborLength` as the byte length of the CBOR data (2 bytes, big-endian) +3. Append: `[cborData][cborLength][0x02][80218021802180218021802180218021]` +4. Return the hex-encoded result for the settlement mechanism to append to calldata + +--- + +## Protocol Flow + +``` +Client (App) Resource Server Facilitator + | | | + 1. |--- request ----------------->| | + | | | + 2. |<-- 402 PaymentRequired ------| | + | extensions.builder-code: | | + | { a: "my_app" } | | + | | | + 3. | (sign payment, echo extensions) | + | | | + 4. |--- request + payment ------->| | + | extensions.builder-code: | | + | { a: "my_app", | | + | s: ["my_client"] } | | + | | | + 5. | |--- verify/settle ----------->| + | | extensions.builder-code: | + | | { a: "my_app", | + | | s: ["my_client"] } | + | | | + 6. | | Facilitator adds w, | + | | encodes CBOR suffix, | + | | appends to calldata: | + | | [cbor({a:"my_app", | + | | s:["my_client"], | + | | w:"my_fac"})] | + | | [cborLen][0x02][mark] | + | | | + 7. |<-- 200 OK + resource data ---| | + | | | +``` + +--- + +## Examples + +### Single App Attribution + +Application declares its builder code: + +```json +{ + "extensions": { + "builder-code": { + "info": { + "a": "bc_myapp" + }, + "schema": { ... } + } + } +} +``` + +Settlement calldata suffix (hex): + +``` +{original_calldata} a161616862635f6d79617070 000c 02 80218021802180218021802180218021 +``` + +Decoded: + +- CBOR: `{"a": "bc_myapp"}` +- cborLength: `0x000c` (12 bytes) +- schemaId: `0x02` +- marker: `80218021802180218021802180218021` + +### App + Facilitator Attribution + +After facilitator adds its `w` code at settlement: + +``` +{original_calldata} a261616862635f6d7961707061777062635f6d79666163696c697461746f72 001f 02 80218021802180218021802180218021 +``` + +Decoded: + +- CBOR: `{"a": "bc_myapp", "w": "bc_myfacilitator"}` +- cborLength: `0x001f` (31 bytes) +- schemaId: `0x02` +- marker: `80218021802180218021802180218021` + +--- + +## Validation + +### Builder Code Validation + +All builder codes (`a`, `w`, and each entry in `s`) must: + +- Match `^[a-z0-9_]{1,32}$` +- Be 1-32 characters long +- Contain only lowercase letters, digits, and underscores + +Invalid codes must be rejected at declaration time (application) and at construction time (facilitator). The facilitator validates each entry in `s` for format only — `s` is client self-reported and cannot be verified against any authoritative source. + +### App Code Echo Validation + +The facilitator MUST verify that the `a` field echoed by the client in `PaymentPayload.extensions["builder-code"]` exactly matches the `a` field declared by the application in `PaymentRequired.extensions["builder-code"].info`. A mismatch indicates the client tampered with the attribution and the payment MUST be rejected. + +### Schema Validation + +The `schema` field uses JSON Schema Draft 2020-12. Facilitators should validate `info` against the provided schema. + +--- + +## Parsing + +Off-chain parsers can extract builder code attribution from settlement calldata using the ERC-8021 parsing algorithm: + +1. Extract the last 16 bytes and verify they match the ERC-8021 marker (`80218021...`) +2. Extract the preceding byte as `schemaId` and verify it equals `0x02` +3. Extract the preceding 2 bytes as `cborLength` (big-endian) +4. Extract the preceding `cborLength` bytes as `cborData` +5. Decode `cborData` as a CBOR map +6. Read `a` (app code), `w` (wallet code), and `s` (service codes array) from the map + +--- + +## Responsibilities + +| Role | Responsibility | +| --------------- | ----------------------------------------------------------------------------------------------------------- | +| **Application** | Declares `a` (app code) per-route in the payment middleware configuration | +| **Client** | Echoes `a` from `PaymentRequired`; optionally populates `s` with its own service code(s) in `PaymentPayload` | +| **Facilitator** | Adds `w` (wallet code) at settlement, encodes the full CBOR suffix (`a`, `s`, `w`), appends to calldata | diff --git a/specs/extensions/extension-auth-hints.md b/specs/extensions/extension-auth-hints.md new file mode 100644 index 0000000000..fae215dea4 --- /dev/null +++ b/specs/extensions/extension-auth-hints.md @@ -0,0 +1,370 @@ +# Extension: `auth-hints` + +## Summary + +The `auth-hints` extension provides authentication hints for specific payment requirements within x402. It enables clients to discover which `accepts[]` entries require authentication and complete registration and token acquisition *before* submitting a payment payload, avoiding an unnecessary round trip. + +This extension addresses a specific gap: when a `402 Payment Required` response includes multiple payment requirements and only some of them require authentication, the client needs a way to know which entries require auth and how to obtain credentials — before committing to a payment method. + +This is a **Server ↔ Client** extension. The Facilitator is not involved in authentication. + +--- + +## Interaction with `WWW-Authenticate` + +On an HTTP transport, the `WWW-Authenticate` header (RFC 9110) is the standard mechanism for authentication challenges. x402 is fully compatible with this header. The following table describes how `WWW-Authenticate` and the `auth-hints` extension interact: + +| Scenario | `WWW-Authenticate` | `auth-hints` extension | Meaning | +|------------------------|--------------------|------------------------|-------------------------------------------------------------------------------------------------------------| +| Resource requires auth | Present | Absent | Auth is mandatory for all payment requirements. Standard HTTP flow. | +| Entry requires auth | Absent | Present | Auth is required only for specific `accepts[]` entries. Client uses extension hints. | +| Both | Present | Present | Auth is mandatory for the resource AND the extension provides entry-specific hints (e.g. different scopes). | +| Neither | Absent | Absent | No authentication required. | + +--- + +## Authentication Without Hints + +x402 is fully compatible with existing authentication mechanisms without this extension. Authentication and payment are parallel concerns- authentication identifies the client, payment authorizes the transfer of value. + +When a resource server requires authentication, the client can discover this through standard HTTP challenge mechanisms: + +1. The server returns a `402 Payment Required` response. If authentication is required for the resource, the server includes a `WWW-Authenticate` header on this response. +2. If the client submits a `PaymentPayload` without credentials, the server responds with `401 Unauthorized` and a `WWW-Authenticate` header. +3. The client discovers the authorization server via `WWW-Authenticate` parameters or RFC 8414 (OAuth 2.0 Authorization Server Metadata). +4. The client registers via RFC 7591 (Dynamic Client Registration) if needed, obtains a token from the token endpoint, and retries with both authentication credentials and the payment payload. + +On an HTTP transport, the retry includes both the `Authorization` header and the x402 `PAYMENT-SIGNATURE` header. For example, with DPoP: + +``` +GET /premium-data HTTP/1.1 +Host: api.example.com +Authorization: DPoP +DPoP: +PAYMENT-SIGNATURE: +``` + +Authorization without hints works but requires an extra round trip when the client doesn't know upfront that a payment requirement requires authentication. The `auth-hints` extension eliminates this by providing the authentication metadata in the `402` response. + +On non-HTTP transports (MCP, A2A, etc.), the mechanism for discovering authentication requirements and presenting credentials is transport-specific. This specification defines behavior for HTTP. Other transports will define their own mechanisms in the future (see PaymentPayload below). + +--- + +## Authentication With Hints + +Some payment requirements require authentication even when the resource itself does not. For example, a `deferred` payment requirement uses off-chain vouchers against an escrow deposit, so the server needs to verify the client's identity to match vouchers to the correct escrow account and track accumulated value. Without this extension, the client has no way to know which `accepts[]` entries require authentication until it tries and gets rejected. The `auth-hints` extension solves this by including authentication metadata in the `402` response, mapped to specific `accepts[]` entries. + +### PaymentRequired + +A resource server advertises auth requirements by including the `auth-hints` extension in the `extensions` object of the `402 Payment Required` response. + +The extension uses `authRequirements` to map `accepts[]` entries to their authentication requirements. + +```json +{ + "x402Version": 2, + "error": "Payment required", + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepts": [ + { + "scheme": "exact", + "network": "eip155:8453", + "amount": "10000", + "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C", + "maxTimeoutSeconds": 60 + }, + { + "scheme": "deferred", + "network": "eip155:8453", + "amount": "10000", + "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C", + "maxTimeoutSeconds": 60 + } + ], + "extensions": { + "auth-hints": { + "info": { + "authRequirements": [ + { + "acceptIndexes": [1], + "methods": [ + { + "type": "oauth2", + "tokenType": "DPoP", + "authorizationServer": "https://as.example.com", + "tokenEndpoint": "https://as.example.com/token", + "registrationEndpoint": "https://as.example.com/register" + } + ] + } + ] + }, + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "authRequirements": { + "type": "array", + "items": { + "type": "object", + "properties": { + "acceptIndexes": { + "type": "array", + "items": { "type": "integer" }, + "description": "Indexes into the accepts[] array" + }, + "methods": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "Authentication method type" + } + }, + "required": ["type"] + } + } + }, + "required": ["acceptIndexes", "methods"] + } + } + }, + "required": ["authRequirements"] + } + } + } +} +``` + +In this example, `accepts[0]` (exact) requires no authentication. `accepts[1]` (deferred) requires OAuth 2.0 with DPoP. + +#### `acceptIndexes` Matching + +Each `authRequirements` entry identifies which `accepts[]` entries it applies to via the `acceptIndexes` array. The array contains one or more integer indexes into the top-level `accepts[]` array. + +When resolving which auth requirements apply to a chosen `accepts[]` entry, clients check whether the chosen entry's index appears in any `authRequirements` entry's `acceptIndexes` array. Clients MUST silently ignore any index in `acceptIndexes` that is out of range for the `accepts[]` array. + +#### Server-Declared PaymentRequired Fields + +##### `authRequirements[]` + +| Field | Type | Required | Description | +|------------------|-----------|----------|----------------------------------------------------------------------------------------------| +| `acceptIndexes` | integer[] | Yes | Indexes into the `accepts[]` array identifying which payment requirements require auth | +| `methods` | array | Yes | Supported authentication methods for these payment requirements. Client picks one. | + +If an `acceptIndexes` value applies to an `accepts[]` entry, authentication is REQUIRED for use of that payment requirement. The hints are not advisory- they indicate a mandatory authentication step. + +##### Authentication Method Types + +The `methods` array contains one or more authentication methods. Each method has a `type` field that determines the remaining fields. The following types are currently defined. + +###### Type: `oauth2` + +OAuth 2.0 authentication. The client obtains an access token from the authorization server and presents it in the request to the resource server. In HTTP, the token is sent in the `Authorization` header on the same request that carries the x402 payment. + +| Field | Type | Required | Description | +|-----------------------|--------|----------|--------------------------------------------------------------------------------------| +| `type` | string | Yes | `"oauth2"` | +| `tokenType` | string | Yes | Token type for presentation: `"Bearer"` or `"DPoP"` | +| `authorizationServer` | string | Yes | Base URL of the authorization server | +| `tokenEndpoint` | string | Yes | URL of the token endpoint for obtaining access tokens | +| `registrationEndpoint`| string | No | URL of the DCR endpoint (RFC 7591). If present, dynamic client registration is available. If absent, the client must already have a `client_id`. | + +The `tokenEndpoint` and `registrationEndpoint` serve different purposes. The registration endpoint (RFC 7591) is called once to register the client and obtain a `client_id`. The token endpoint is called for each session to obtain a time-limited access token using that `client_id`. Registration is optional and one-time; token acquisition is required and recurring. + +###### Type: `sign-in-with-x` + +Wallet-based authentication via the `sign-in-with-x` extension (CAIP-122). The client proves wallet ownership by signing a challenge. + +| Field | Type | Required | Description | +|--------|--------|----------|---------------------| +| `type` | string | Yes | `"sign-in-with-x"` | + +When a client encounters this method type, it MUST look at the `sign-in-with-x` extension on the same `PaymentRequired` response for the full challenge parameters, supported chains, and schema. The auth-hint serves only as a pointer- all SIWX metadata is defined by the `sign-in-with-x` extension. + +#### Client Behavior + +When a client receives a `402` response containing the `auth-hints` extension: + +1. The client evaluates all available payment requirements in `accepts[]`, including their authentication requirements from `authRequirements`. +2. The client selects a payment requirement based on its capabilities, preferences, and the authentication burden of each option. +3. If the chosen entry has a matching `authRequirements` entry, the client completes the authentication flow before submitting the payment: + - For `oauth2`: register if needed and obtain an access token + - For `sign-in-with-x`: sign the SIWX challenge per the `sign-in-with-x` extension specification +4. The client submits the payment with both the authentication credentials and the x402 payment payload. + +If no `acceptIndexes` value exists for the chosen `accepts[]` entry, no authentication is needed. + +### PaymentPayload + +How the client presents authentication credentials alongside the payment payload depends on the transport. + +#### HTTP + +On HTTP transports, authentication credentials are sent as standard HTTP headers alongside the x402 `PAYMENT-SIGNATURE` header. The credentials do not travel inside the x402 `PaymentPayload`. + +OAuth 2.0 — Bearer: + +``` +Authorization: Bearer +PAYMENT-SIGNATURE: +``` + +OAuth 2.0 — DPoP: + +``` +Authorization: DPoP +DPoP: +PAYMENT-SIGNATURE: +``` + +Sign-In With X: + +``` +SIGN-IN-WITH-X: +PAYMENT-SIGNATURE: +``` + +#### Other Transports + +Credential presentation for non-HTTP transports (MCP, A2A, etc.) is defined by the respective transport specifications. The `auth-hints` extension provides discovery metadata only; it does not define transport-specific presentation mechanisms. + +### Server Verification + +When the resource server receives a request with both authentication credentials and a payment payload, it validates both independently: + +1. **Validate authentication:** + - For `oauth2`: validate the access token (signature, audience, expiry, DPoP binding if applicable) + - For `sign-in-with-x`: verify the SIWX proof per the `sign-in-with-x` extension specification (signature, nonce, domain, expiration) +2. **Validate payment:** forward the `PaymentPayload` to the facilitator (or verify locally) for payment verification and settlement +3. If both succeed, fulfill the request + +The facilitator is not involved in authentication validation. + +Authentication identity and payment identity are independent. The authenticated client MAY use one or more payer wallets, subject to server policy. This extension does not require the authentication identity to equal the payer address in the payment. + +--- + +### Example Flow: OAuth 2.0 with DCR and DPoP + +This example walks through the complete flow on an HTTP transport when a client encounters a `deferred` payment requirement that requires OAuth 2.0 authentication with DPoP. + +#### Step 1 — Client Requests Resource + +``` +GET /premium-data HTTP/1.1 +Host: api.example.com +``` + +#### Step 2 — Server Responds with 402 + +The server returns payment requirements. The `auth-hints` extension indicates that `accepts[1]` (deferred) requires OAuth 2.0 with DPoP. + +``` +HTTP/1.1 402 Payment Required +Content-Type: application/json + +{ + "x402Version": 2, + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepts": [ + { + "scheme": "exact", + "network": "eip155:8453", + "amount": "10000", + "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C", + "maxTimeoutSeconds": 60 + }, + { + "scheme": "deferred", + "network": "eip155:8453", + "amount": "10000", + "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "payTo": "0x209693Bc6afc0C5328bA36FaF03C514EF312287C", + "maxTimeoutSeconds": 60 + } + ], + "extensions": { + "auth-hints": { + "info": { + "authRequirements": [ + { + "acceptIndexes": [1], + "methods": [ + { + "type": "oauth2", + "tokenType": "DPoP", + "authorizationServer": "https://as.example.com", + "tokenEndpoint": "https://as.example.com/token", + "registrationEndpoint": "https://as.example.com/register" + } + ] + } + ] + }, + "schema": { "..." : "..." } + } + } +} +``` + +#### Step 3 — Client Registers via DCR + +The client chooses `accepts[1]` (deferred), sees the auth requirement, and registers with the authorization server via Dynamic Client Registration (RFC 7591). This is a one-time step — the client reuses the `client_id` for subsequent token requests. See RFC 7591 for the registration request and response format. + +#### Step 4 — Client Obtains DPoP-Bound Access Token + +Using the `client_id` from registration, the client requests an access token from the token endpoint (RFC 6749 §4.4). The client generates a DPoP key pair and includes a DPoP proof JWT per RFC 9449. See the respective RFCs for the token request and response format. + +#### Step 5 — Client Submits Payment with Authentication + +The client retries the original request with both the DPoP-bound access token and the x402 payment payload: + +``` +GET /premium-data HTTP/1.1 +Host: api.example.com +Authorization: DPoP eyJ... +DPoP: +PAYMENT-SIGNATURE: +``` + +#### Step 6 — Server Validates and Fulfills + +The resource server validates the DPoP-bound access token, verifies the x402 payment (via facilitator or locally), and returns the requested resource. + +--- + +## Security Considerations + +- Use sender-constrained tokens (DPoP) when possible to prevent token theft and replay +- Validate token audience (`aud`) to ensure the token was issued for the correct resource server +- Validate token expiry to limit the window of use +- Protect token endpoints with TLS +- Authorization servers SHOULD implement replay protection for DPoP proofs (RFC 9449) +- For `sign-in-with-x`, servers MUST validate nonce uniqueness to prevent replay attacks + +--- + +## References + +- [RFC 9110: HTTP Semantics](https://www.rfc-editor.org/rfc/rfc9110) — `WWW-Authenticate` header semantics +- [RFC 8414: OAuth 2.0 Authorization Server Metadata](https://www.rfc-editor.org/rfc/rfc8414) — Authorization server discovery +- [RFC 7591: OAuth 2.0 Dynamic Client Registration](https://www.rfc-editor.org/rfc/rfc7591) — DCR protocol +- [RFC 9449: OAuth 2.0 Demonstrating Proof of Possession (DPoP)](https://www.rfc-editor.org/rfc/rfc9449) — Sender-constrained tokens +- [CAIP-122: Sign-In With X](https://github.com/ChainAgnostic/CAIPs/blob/main/CAIPs/caip-122.md) — Wallet-based authentication +- [Extension: `sign-in-with-x`](sign-in-with-x.md) — x402 SIWX extension specification +- [Core x402 Specification](../x402-specification-v2.md) diff --git a/specs/extensions/http-message-signatures.md b/specs/extensions/http-message-signatures.md new file mode 100644 index 0000000000..cf4e41aed5 --- /dev/null +++ b/specs/extensions/http-message-signatures.md @@ -0,0 +1,128 @@ +# Extension: `http-message-signatures` + +## Summary + +The `http-message-signatures` extension establishes the **identity** of the paying agent through cryptographic signatures (RFC 9421). This extension is used by network implementations that authenticate payment commitments using HTTP Message Signatures. + +## Purpose + +Establishes the cryptographic identity of the paying agent and provides information on how to associate that identity with the network for billing. + +## Extension Definition + +```json +{ + "http-message-signatures": { + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "registrationUrl": { + "type": "string", + "format": "uri", + "description": "URL to the network's setup endpoint and documentation" + }, + "signatureSchemes": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Supported cryptographic signature algorithms" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + }, + "description": "Supported signature tags for validation" + } + }, + "required": ["registrationUrl", "signatureSchemes"] + }, + "info": { + "registrationUrl": "https://network.example.com/signature-agents", + "signatureSchemes": ["ed25519", "ecdsa-p256-sha256", "rsa-pss-sha512"], + "tags": ["web-bot-auth", "agent-browser-auth"] + } + } +} +``` + +## Fields + +- **`registrationUrl`** (required): URL to the network's documentation and setup endpoint where signature agents can associate their identity with a billing identity +- **`signatureSchemes`** (required): Array of supported cryptographic algorithms (e.g., `["ed25519", "ecdsa-p256-sha256", "rsa-pss-sha512"]`) +- **`tags`** (required): Array of supported signature tags that identify the purpose (e.g., `["web-bot-auth"]`) + +**Schema Omission**: The `schema` field is optional and may be omitted from responses to reduce header size. When omitted, clients should reference this specification for field definitions. + +## Usage + +Networks that use HTTP Message Signatures for authentication include this extension in the `PaymentRequired` response to inform clients: + +1. Where to register their signature agent with the network (`registrationUrl`) +2. Which cryptographic algorithms are supported (`signatureSchemes`) +3. Which signature tags are accepted for validation (`tags`) + +The client must: + +1. Host their public keys at `/.well-known/http-message-signatures-directory` (per draft-meunier-http-message-signatures-directory) +2. Register their signature agent URL with the network via the `registrationUrl` +3. Sign HTTP requests using HTTP Message Signatures (RFC 9421) with the appropriate tag + +## Server-Signed Responses + +Servers can sign responses per RFC 9421 Section 3.1 to provide integrity for payment data. This enables clients to verify that `PAYMENT-REQUIRED` and `PAYMENT-RESPONSE` headers have not been modified, and to pin a specific version of terms to a transaction. + +### Covered Components + +Per RFC 9421 Section 2.2.9, responses can include `@status` in the signature. Per Section 2.4, servers can bind response signatures to request components using the `req` flag. For x402, servers signing responses should include: + +- `@status`: HTTP status code +- `payment-required` or `payment-response`: The x402 header +- Request binding: `"@authority";req`, `"@path";req` + +### Example + +```http +HTTP/2 200 OK +Content-Type: text/html +PAYMENT-RESPONSE: eyJhbW91bnQiOiI1IiwiYXNzZXQiOiJVU0QiLCJleHRlbnNpb25zIjp7InRlcm1zIjp7ImluZm8iOnsiZm9ybWF0IjoidXJpIiwidGVybXMiOiJodHRwczovL2V4YW1wbGUuY29tL3Rlcm1zLXYyLjAubWQifX19fQ== +Signature-Input: resp=("@status" "payment-response" "@authority";req "@path";req);created=1700000000;keyid="server-key";tag="x402-response" +Signature: resp=:abc123...==: +``` + +Servers publishing response signatures should host their public keys at `/.well-known/http-message-signatures-directory`. + +## Example Networks + +- **Cloudflare** (`cloudflare:402`): Uses this extension with `ed25519` signatures and `web-bot-auth` tag + +## Example + +```json +{ + "extensions": { + "http-message-signatures": { + "schema": { + "$schema": "https://json-schema.org/draft/2020-12/schema", + "type": "object", + "properties": { + "registrationUrl": { "type": "string", "format": "uri" }, + "signatureSchemes": { + "type": "array", + "items": { "type": "string" } + }, + "tags": { "type": "array", "items": { "type": "string" } } + }, + "required": ["registrationUrl", "signatureSchemes"] + }, + "info": { + "registrationUrl": "https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/verify-ai-crawler/", + "signatureSchemes": ["ed25519"], + "tags": ["web-bot-auth"] + } + } + } +} +``` diff --git a/specs/extensions/payment_identifier.md b/specs/extensions/payment_identifier.md index 592ea0465a..e85f0d5310 100644 --- a/specs/extensions/payment_identifier.md +++ b/specs/extensions/payment_identifier.md @@ -86,6 +86,30 @@ Client echoes the extension and appends an `id`: | Same `id`, different payload | Return 409 Conflict | | `required: true`, no `id` provided | Return 400 Bad Request | +### Request Binding + +Resource servers and facilitators should bind each `id` to a normalized request +fingerprint before returning a cached result. The fingerprint should cover the +parts of the request that make the paid operation unique, such as: + +- `scheme` +- `network` +- `asset` +- `amount` +- `payTo` +- resource path and method +- application-level operation or order identifier + +Implementations should store the first observed fingerprint with the `id`. +Later requests with the same `id` and the same fingerprint can return the +cached response. Later requests with the same `id` and a different fingerprint +should fail with `409 Conflict` instead of reusing the cached response or +executing a second operation. + +Servers should avoid using `id` alone as the storage key for authorization +decisions when the same backend handles multiple paid resources. Scope the key +by tenant, merchant, route, or facilitator account when those boundaries exist. + --- ## Responsibilities diff --git a/specs/schemes/authCapture/scheme_authCapture.md b/specs/schemes/authCapture/scheme_authCapture.md new file mode 100644 index 0000000000..836a4cc947 --- /dev/null +++ b/specs/schemes/authCapture/scheme_authCapture.md @@ -0,0 +1,85 @@ +# Scheme: `authCapture` + +## Summary + +`authCapture` is a payment scheme where funds can be held and settled later. The client authorizes a maximum amount, and the facilitator submits it — either locking funds in escrow for later settlement (two-phase) or sending them directly to the receiver with refund capability (single-shot). + +The **captureAuthorizer** is the entity authorized to authorize, capture, void, refund, or charge a payment. In a facilitator-submits flow, that's either the facilitator itself or any smart contract that ends up calling the underlying escrow. + +Unlike `exact`, which has no built-in mechanism for returning funds, `authCapture` supports returning funds to the client through void, refund, and reclaim. + +## Example Use Cases + +- Refundable payments with buyer protection +- Delayed delivery where the client needs recourse if the service is unsatisfactory +- Subscription or session billing with periodic captures against a single authorization + +## Settlement Paths + +The scheme supports two settlement paths, selected via `extra.autoCapture`: + +| `autoCapture` | Behavior | +| :---------------- | :--------------------------------------------------------------------------------------------------------------------------- | +| `false` (default) | Two-phase. Funds held in escrow. CaptureAuthorizer can capture, void, refund. Client can reclaim if capture deadline passes. | +| `true` | Single-shot. Funds sent directly to receiver. CaptureAuthorizer can refund post-settlement. | + +### Two-phase (`autoCapture: false`, default) + +``` +AUTHORIZE → RESOURCE DELIVERED → CAPTURE / VOID → (REFUND) +``` + +1. **Authorize**: Client authorization is submitted — funds locked in escrow. +2. **Resource delivered**: Server returns the resource (HTTP 200). +3. **Capture or void**: The captureAuthorizer can capture (finalize funds to the receiver) or void (release escrowed funds back to client). +4. **Reclaim**: If the capture deadline passes without action, the client can reclaim directly. +5. **Refund**: After capture, the captureAuthorizer can refund within the refund window. + +### Single-shot (`autoCapture: true`) + +``` +CHARGE → RESOURCE DELIVERED → (REFUND) +``` + +1. **Charge**: Client authorization is submitted — funds sent directly to receiver. +2. **Resource delivered**: Server returns the resource (HTTP 200). +3. **Refund**: The captureAuthorizer can refund within the refund window. + +No capture, void, or reclaim — funds are never held in escrow. + +## Core Properties + +### Fund Safety + +- Cannot overcharge — settlement amount is capped by the client-signed maximum. +- Two-phase path: client can reclaim escrowed funds after the capture deadline if no action is taken. +- Fee bounds are client-signed and enforced at settlement. + +### Replay Prevention + +- Each payment has a unique nonce derived from the payment parameters and a fresh client-generated salt. +- Nonce is consumed on-chain at settlement, preventing double-spend. + +### Expiry Enforcement + +Two absolute-timestamp deadlines govern the payment lifecycle (network-specific implementations may add a derived pre-approval expiry from `maxTimeoutSeconds`): + +- **Capture deadline** (`captureDeadline`): Last moment to capture escrowed funds (two-phase); after this, the client can reclaim. +- **Refund deadline** (`refundDeadline`): Last moment to issue a refund on captured or charged payments. + +## Relationship to `exact` + +| Aspect | `exact` | `authCapture` | +| :--------- | :----------------- | :-------------------------------------------------------------------- | +| Settlement | Immediate transfer | Via escrow (two-phase) or direct with refund capability (single-shot) | +| Refundable | No | Yes (both paths) | +| Fee system | None | Configurable (min/max bounds, client-signed) | + +## Appendix + +Network-specific implementation details (contracts, signature formats, verification logic) are in per-network documents: `scheme_authCapture_evm.md` (EVM). + +### References + +- [Escrow Scheme Proposal — Agentokratia (Issue #834)](https://github.com/coinbase/x402/issues/834) +- [Escrow Scheme Proposal — x402r (Issue #1011)](https://github.com/coinbase/x402/issues/1011) diff --git a/specs/schemes/authCapture/scheme_authCapture_evm.md b/specs/schemes/authCapture/scheme_authCapture_evm.md new file mode 100644 index 0000000000..888e086ba8 --- /dev/null +++ b/specs/schemes/authCapture/scheme_authCapture_evm.md @@ -0,0 +1,297 @@ +# Scheme: `authCapture` on `EVM` + +## Summary + +The `authCapture` scheme on EVM uses the [base/commerce-payments](https://github.com/base/commerce-payments) contract stack: + +- **AuthCaptureEscrow**: Singleton — locks funds, enforces expiries, distributes on capture/refund. Universal canonical address (same address on every supported chain). +- **Token Collectors**: Universal canonical addresses, one per `assetTransferMethod`: + - `EIP3009_TOKEN_COLLECTOR_ADDRESS` — collects funds via `receiveWithAuthorization` signatures (USDC, EURC, etc.) + - `PERMIT2_TOKEN_COLLECTOR_ADDRESS` — collects funds via Uniswap Permit2 `permitTransferFrom` (any ERC-20) +- **`captureAuthorizer`**: Address authorized to authorize, capture, void, refund, or charge a payment. The escrow contract gates those operations on `msg.sender` matching this address. In x402's facilitator-submits flow that means either **the facilitator's EOA**, or **any smart contract** that ends up calling the escrow (e.g., an arbiter contract with dispute logic, a multisig, etc.). + +The client signs a single signature (ERC-3009 or Permit2). The facilitator calls `AuthCaptureEscrow.authorize()` (two-phase) or `AuthCaptureEscrow.charge()` (single-shot via `autoCapture: true`), either directly or through a smart contract set as the captureAuthorizer. + +## PaymentRequirements + +AuthCapture-accepting servers advertise with scheme `authCapture`: + +```json +{ + "x402Version": 2, + "accepts": [ + { + "scheme": "authCapture", + "network": "eip155:8453", + "amount": "1000000", + "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "payTo": "0xReceiverAddress", + "maxTimeoutSeconds": 60, + "extra": { + "name": "USDC", + "version": "2", + "captureAuthorizer": "0xCaptureAuthorizerAddress", + "captureDeadline": 1740758554, + "refundDeadline": 1741276954, + "minFeeBps": 0, + "maxFeeBps": 1000, + "feeRecipient": "0xFeeRecipientAddress", + "autoCapture": false, + "assetTransferMethod": "eip3009" + } + } + ] +} +``` + +### `extra` Fields + +| Field | Required | Type | Description | +| :-------------------- | :------- | :----------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| `name` | Yes | `string` | EIP-712 token-domain name (e.g., `"USDC"`). Used for ERC-3009 signing only. | +| `version` | Yes | `string` | EIP-712 token-domain version (e.g., `"2"`). | +| `captureAuthorizer` | Yes | `address` | Address authorized to authorize/capture/void/refund/charge. Committed on-chain as `PaymentInfo.operator`. | +| `captureDeadline` | Yes | `uint48` | Absolute Unix seconds — capture must occur before this. Encoded as `authorizationExpiry`. | +| `refundDeadline` | Yes | `uint48` | Absolute Unix seconds — refunds allowed until this. Encoded as `refundExpiry`. | +| `feeRecipient` | Yes | `address` | Fee recipient (committed on-chain as `PaymentInfo.feeReceiver`). Set to `address(0)` to let the captureAuthorizer specify any non-zero recipient at capture/charge time. | +| `minFeeBps` | Yes | `uint16` | Minimum fee in basis points (the fee floor the captureAuthorizer must take). `0` = no minimum. | +| `maxFeeBps` | Yes | `uint16` | Maximum fee in basis points (the cap on the captureAuthorizer's fee). | +| `autoCapture` | No | `bool` | `true` → facilitator calls `charge()` (atomic). `false` → `authorize()` (two-phase). Default: `false`. | +| `assetTransferMethod` | No | `"eip3009" \| "permit2"` | Which token collector to use. Default: `"eip3009"`. A server MAY list multiple `accepts[]` entries with different `assetTransferMethod` values so clients can pick the method matching their token approvals. | + +### Spec → on-chain field name mapping + +The wire-format extra uses spec-level field names. The on-chain `PaymentInfo` struct keeps canonical Solidity names so the EIP-712 typehash matches the AuthCaptureEscrow contract byte-for-byte. + +| Wire (`extra`) | On-chain (`PaymentInfo`) | +| :----------------------------------- | :----------------------- | +| `captureAuthorizer` | `operator` | +| `captureDeadline` | `authorizationExpiry` | +| `refundDeadline` | `refundExpiry` | +| `feeRecipient` | `feeReceiver` | +| (derived: `now + maxTimeoutSeconds`) | `preApprovalExpiry` | + +## PaymentPayload + +The payload carries the signature and the client-generated `salt`. The facilitator reconstructs the full `PaymentInfo` from `extra` + `salt` + payer + top-level requirements (`payTo`, `asset`, `amount`). + +### EIP-3009 (default) + +```json +{ + "x402Version": 2, + "resource": { "url": "https://api.example.com/resource", "method": "GET" }, + "accepted": { "scheme": "authCapture", "...": "..." }, + "payload": { + "authorization": { + "from": "0xPayerAddress", + "to": "0xEIP3009TokenCollectorAddress", + "value": "1000000", + "validAfter": "0", + "validBefore": "1740675754", + "nonce": "0xf374...3480" + }, + "signature": "0x2d6a...571c", + "salt": "0x0000000000000000000000000000000000000000000000000000000000000abc" + } +} +``` + +**Field derivation (EIP-3009):** + +| Payload field | Derived from | +| :-------------------------- | :---------------------------------------------------------------------------------------------------------- | +| `authorization.from` | Client's own address | +| `authorization.to` | `EIP3009_TOKEN_COLLECTOR_ADDRESS` (universal constant) | +| `authorization.value` | `requirements.amount` | +| `authorization.validAfter` | `0` (the token collector hardcodes the lower bound) | +| `authorization.validBefore` | `now + requirements.maxTimeoutSeconds` (also used as `preApprovalExpiry` when reconstructing `PaymentInfo`) | +| `authorization.nonce` | Payer-agnostic `PaymentInfo` hash — see [Nonce Derivation](#nonce-derivation-both-methods) | +| `salt` | Fresh `bytes32` generated client-side per signing call | +| EIP-712 domain | `{ name, version }` from `extra`; `chainId` from `network`; `verifyingContract = requirements.asset` | + +### Permit2 + +```json +{ + "x402Version": 2, + "resource": { "url": "https://api.example.com/resource", "method": "GET" }, + "accepted": { "scheme": "authCapture", "...": "..." }, + "payload": { + "permit2Authorization": { + "from": "0xPayerAddress", + "permitted": { + "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "amount": "1000000" + }, + "spender": "0xPermit2TokenCollectorAddress", + "nonce": "110210486920734568342928534950928740912034856789012345678901234567890123456789", + "deadline": "1740675754" + }, + "signature": "0x2d6a...571c", + "salt": "0x0000000000000000000000000000000000000000000000000000000000000abc" + } +} +``` + +**Field derivation (Permit2):** + +| Payload field | Derived from | +| :-------------------------------------- | :---------------------------------------------------------------------------------------------------------- | +| `permit2Authorization.from` | Client's own address | +| `permit2Authorization.permitted.token` | `requirements.asset` | +| `permit2Authorization.permitted.amount` | `requirements.amount` | +| `permit2Authorization.spender` | `PERMIT2_TOKEN_COLLECTOR_ADDRESS` (universal constant) | +| `permit2Authorization.nonce` | `uint256(payerAgnosticPaymentInfoHash)` — see [Nonce Derivation](#nonce-derivation-both-methods) | +| `permit2Authorization.deadline` | `now + requirements.maxTimeoutSeconds` (also used as `preApprovalExpiry` when reconstructing `PaymentInfo`) | +| `salt` | Fresh `bytes32` generated client-side per signing call | +| EIP-712 domain | Canonical Permit2 contract; `chainId` from `network` | + +**No witness** — the merchant address is bound through the deterministic nonce, not a separate witness struct. + +### Nonce Derivation (both methods) + +The signature nonce is the payer-agnostic `PaymentInfo` hash. Payer is zeroed; everything else is the values that will appear on-chain. + +``` +paymentInfoHash = keccak256(abi.encode(PAYMENT_INFO_TYPEHASH, paymentInfoWithZeroPayer)) +nonce = keccak256(abi.encode(chainId, AUTH_CAPTURE_ESCROW_ADDRESS, paymentInfoHash)) +``` + +Freshness is enforced by `salt`: each signing call generates a fresh `bytes32` salt, so two payers signing concurrently produce distinct nonces with no collision risk. + +## Verification Logic + +The facilitator performs these checks in order: + +1. **Type guard**: Verify payload matches one of `Eip3009Payload` or `Permit2Payload` (must include `signature` and `salt`). +2. **Scheme match**: `requirements.scheme === "authCapture"` and `payload.accepted.scheme === "authCapture"`. +3. **Network match**: `payload.accepted.network === requirements.network` and format is `eip155:`. +4. **Extra validation**: `requirements.extra` contains all required fields (`captureAuthorizer`, `captureDeadline`, `refundDeadline`, `feeRecipient`, `minFeeBps`, `maxFeeBps`, `name`, `version`). +5. **Method routing**: `extra.assetTransferMethod` (default `"eip3009"`) matches the payload shape. +6. **Deadline ordering**: `refundDeadline >= captureDeadline`, `captureDeadline > now + 6s`, and `payload.validBefore` (EIP-3009) / `payload.deadline` (Permit2) `<= captureDeadline`. +7. **Time window**: `payload.deadline / validBefore > now + 6s` (not expired) and `validAfter <= now` (active, EIP-3009 only). +8. **Spender / collector match**: `payload.to === EIP3009_TOKEN_COLLECTOR_ADDRESS` (EIP-3009) or `payload.spender === PERMIT2_TOKEN_COLLECTOR_ADDRESS` (Permit2). +9. **Token match**: `payload.permitted.token === requirements.asset` (Permit2 only — EIP-3009 binds via signing domain). +10. **Signature verify**: Recover signer from EIP-712 (`ReceiveWithAuthorization` or `PermitTransferFrom`); must match `payer`. +11. **Amount**: `authorization.value` (EIP-3009) or `permit2Authorization.permitted.amount` (Permit2) matches `requirements.amount`. +12. **Nonce match**: Reconstruct `PaymentInfo` from extra + payload.salt + payer + requirements; recompute payer-agnostic hash; assert it matches the wire nonce. This transitively enforces equality on every field encoded in `PaymentInfo` (receiver, token, deadlines, fee bounds, feeRecipient), so individual field-by-field checks for those values are unnecessary. +13. **Simulate** `AUTH_CAPTURE_ESCROW.authorize(...)` or `.charge(...)` to ensure success. + +### EIP-6492 Support + +For smart wallet clients, the signature may be EIP-6492 wrapped (containing deployment bytecode). The facilitator extracts the inner ECDSA signature for verification. The on-chain `ERC6492SignatureHandler` in the token collector handles wallet deployment during settlement. + +## Settlement Logic + +1. **Re-verify** the payload (catches expired/invalid payloads before spending gas). +2. **Determine function**: `extra.autoCapture === true ? "charge" : "authorize"`. +3. **Resolve collector**: `EIP3009_TOKEN_COLLECTOR_ADDRESS` or `PERMIT2_TOKEN_COLLECTOR_ADDRESS` (per `assetTransferMethod`). +4. **Encode `collectorData`**: raw ERC-3009 signature, or ABI-encoded Permit2 signature. +5. **Call escrow**: `AUTH_CAPTURE_ESCROW.(paymentInfo, amount, tokenCollector, collectorData)`. +6. **Wait for receipt**: 60s timeout. +7. **Return result**: tx hash, network, payer. + +## Error Codes + +The authCapture scheme uses the standard x402 error codes plus these scheme-specific codes: + +### Verification Errors + +| Error Code | Description | +| :---------------------------------- | :-------------------------------------------------------------------------------- | +| `invalid_payload_format` | Payload doesn't match `Eip3009Payload` or `Permit2Payload`. | +| `unsupported_scheme` | Scheme is not `authCapture`. | +| `network_mismatch` | Payload network doesn't match requirements. | +| `invalid_network` | Network format is not `eip155:`. | +| `invalid_authCapture_extra` | Extra is missing required fields. | +| `unsupported_asset_transfer_method` | `assetTransferMethod` is not `"eip3009"` or `"permit2"`. | +| `payload_method_mismatch` | Payload shape doesn't match `assetTransferMethod`. | +| `capture_deadline_expired` | `captureDeadline <= now + 6s`. | +| `invalid_deadline_ordering` | Deadlines violate `now + maxTimeoutSeconds <= captureDeadline <= refundDeadline`. | +| `authorization_expired` | EIP-3009 `validBefore` (or Permit2 `deadline`) `<= now + 6s`. | +| `authorization_not_yet_valid` | EIP-3009 `validAfter > now`. | +| `invalid_authCapture_signature` | Signature verification failed. | +| `amount_mismatch` | Authorization value doesn't match `requirements.amount`. | +| `token_collector_mismatch` | `to` / `spender` doesn't match the canonical collector for the method. | +| `token_mismatch` | Permit2 `permitted.token` doesn't match `requirements.asset`. | +| `nonce_mismatch` | Wire nonce doesn't match the recomputed payer-agnostic PaymentInfo hash. | +| `insufficient_balance` | Payer balance is less than required amount. | +| `simulation_failed` | Settlement simulation reverted with an unmapped error. | + +### Typed simulation reverts + +If the simulate call reverts with an `AuthCaptureEscrow` custom error declared in the call's ABI, the facilitator decodes it via `BaseError.walk()` + `ContractFunctionRevertedError` and surfaces a stable reason instead of the opaque `simulation_failed` fallback: + +| Custom error | `invalidReason` | +| :------------------------------ | :------------------------------------ | +| `AfterPreApprovalExpiry` | `authorization_expired` | +| `InvalidExpiries` | `invalid_deadline_ordering` | +| `ExceedsMaxAmount` | `amount_mismatch` | +| `PaymentAlreadyCollected` | `payment_already_collected` | +| `TokenCollectionFailed` | `token_collection_failed` | +| `InvalidCollectorForOperation` | `invalid_collector` | +| `InvalidSender` | `invalid_capture_authorizer` | +| `ZeroAmount` / `AmountOverflow` | `amount_mismatch` / `amount_overflow` | +| `FeeBpsOverflow` | `invalid_fee_bps` | +| `InvalidFeeBpsRange` | `invalid_fee_bps_range` | +| `FeeBpsOutOfRange` | `fee_bps_out_of_range` | +| `ZeroFeeReceiver` | `zero_fee_receiver` | +| `InvalidFeeReceiver` | `invalid_fee_receiver` | +| `AfterAuthorizationExpiry` | `capture_deadline_expired` | +| `InsufficientAuthorization` | `insufficient_authorization` | +| `ZeroAuthorization` | `zero_authorization` | + +### Settlement Errors + +| Error Code | Description | +| :--------------------- | :------------------------------------------------ | +| `verification_failed` | Re-verification before settlement failed. | +| `transaction_reverted` | On-chain transaction reverted after confirmation. | + +## Appendix + +### PaymentInfo Struct (canonical Solidity — wire-level field names map per the table above) + +```solidity +struct PaymentInfo { + address operator; // = extra.captureAuthorizer + address payer; // payload-derived + address receiver; // = requirements.payTo + address token; // = requirements.asset + uint120 maxAmount; // = requirements.amount + uint48 preApprovalExpiry; // = now + maxTimeoutSeconds (client-derived) + uint48 authorizationExpiry; // = extra.captureDeadline + uint48 refundExpiry; // = extra.refundDeadline + uint16 minFeeBps; + uint16 maxFeeBps; + address feeReceiver; // = extra.feeRecipient + uint256 salt; // = payload.salt (client-generated, fresh per request) +} +``` + +### Expiry Ordering + +The contract enforces: `preApprovalExpiry <= authorizationExpiry <= refundExpiry`. + +| Expiry | Wire field | Enforced at | Effect | +| :-------------------- | :---------------- | :------------------------- | :---------------------------------- | +| `preApprovalExpiry` | derived | `authorize()` / `charge()` | Blocks settlement after this time | +| `authorizationExpiry` | `captureDeadline` | `capture()` | Blocks capture; enables `reclaim()` | +| `refundExpiry` | `refundDeadline` | `refund()` | Blocks refund requests | + +### Fee System + +Fees are enforced on-chain by the escrow contract: + +- `minFeeBps` and `maxFeeBps` set by the client in `PaymentInfo` (0–10,000 bps) +- `feeBps` at capture/charge must fall within `[minFeeBps, maxFeeBps]` +- If `feeReceiver` (`extra.feeRecipient`) is set in `PaymentInfo`, actual `feeReceiver` at capture/charge must match +- If `feeReceiver` is `address(0)`, the caller can specify any non-zero address +- Fee distribution: `feeAmount = amount * feeBps / 10000`, remainder goes to receiver + +### Canonical Addresses + +The `AUTH_CAPTURE_ESCROW_ADDRESS`, `EIP3009_TOKEN_COLLECTOR_ADDRESS`, and `PERMIT2_TOKEN_COLLECTOR_ADDRESS` constants resolve to the canonical [Base Commerce-Payments contracts](https://github.com/base/commerce-payments/releases/tag/v1.0.0). + +The `PERMIT2_ADDRESS` constant resolves to the canonical [Uniswap Permit2 contract](https://docs.uniswap.org/contracts/v4/deployments). diff --git a/specs/schemes/batch-settlement/scheme_batch_settlement.md b/specs/schemes/batch-settlement/scheme_batch_settlement.md new file mode 100644 index 0000000000..c7c127bb86 --- /dev/null +++ b/specs/schemes/batch-settlement/scheme_batch_settlement.md @@ -0,0 +1,77 @@ +# Scheme: `batch-settlement` + +## Summary + +`batch-settlement` is a payment scheme in which the client provides a cryptographic payment commitment at request time, but the transfer of value is not executed synchronously during that request. The commitment is accepted, access is granted immediately, and financial settlement occurs later through a process defined by the network binding. + +Per-request onchain settlement may not be ideal for some real-world use cases. `batch-settlement` exists to serve situations where gas fees exceed the value of individual requests, block confirmation time is incompatible with HTTP response latency, request volume requires batched settlement, or settlement happens through infrastructure that operates asynchronously from HTTP (payment channels, fiat billing systems, stablecoin invoices). + +The model of how a commitment is formed, what backs it, and how it is eventually redeemed,is defined entirely by the network binding. + +The `batch-settlement` scheme supports **dynamic pricing**: the client commits up to the maximum per-request price (`PaymentRequirements.amount`), but the server may charge a lower actual price after executing the request. The actual charge is communicated via the `PAYMENT-RESPONSE`. + +## Protocol behavior + +For `exact` and `upto`, verification and settlement happen in a single pass: the commitment is validated, a transaction is broadcast, and value has moved. The settlement result contains an onchain transaction hash. + +For `batch-settlement`, verification confirms the commitment is valid, but settlement stores it rather than executing a transfer. The settlement result contains a commitment identifier, but value moves later, through the network binding's redemption process. + +### Commitment identifier + +The settlement result MUST include a non-empty commitment identifier on success. This identifier is meaningful to the network binding; a token, a voucher ID, channel receipt hash, account ledger reference, or equivalent. + +## Commitment models + +Network bindings may choose one of two trust models for backing the client's commitment. + +### Capital-backed + +The client's commitment is backed by onchain capital committed before or during the session such as pre-funded escrow, a payment channel, or a delegated authorization against a wallet balance. The trust anchor is the client's own funds. No network intermediary is required to underwrite access. + +### Credit-backed + +The client's commitment is backed by a verified identity associated with a billing account managed by a trusted network intermediary. No onchain capital is required from the client. The network authenticates the identity, underwrites the access obligation, and settles with the resource server through off-chain infrastructure on a defined schedule. + +## Use cases + +**Escrow-backed micropayments.** An AI agent pre-funds an onchain escrow at session start. Each sub-cent API call produces a signed voucher drawn against that balance. The provider accumulates vouchers and redeems them in a single onchain transaction at session end, keeping per-request gas cost to zero. + +**Payment channel streaming.** A client and provider open a payment channel once. Each request increments a signed running total (a receipt). The provider closes the channel periodically, collecting accumulated value in one settlement regardless of how many individual requests were made. + +**Delegated authorization.** A client delegates spending authority to an operator against their wallet balance. The operator signs commitments per request on the client's behalf. The provider collects authorizations and settles them through the delegation contract. + +**Credit-backed content licensing.** A content publisher monetizes AI crawler access. Crawlers authenticate via a network-registered identity backed by a billing account. The network verifies each request, accumulates usage, and invoices the crawler operator on a billing cycle with no wallet or onchain interaction required from the client. + +## Settlement lifecycle + +All `batch-settlement` network bindings share this abstract lifecycle. The network binding defines the specifics of each phase. + +1. **Commit.** The client produces a cryptographic payment commitment and attaches it to the request. The commitment is validated and stored. The resource is served immediately. + +2. **Accumulate.** The network retains the commitment in a voucher store, channel state, account ledger, or billing system. The network binding defines who stores commitments, where, and for how long. + +3. **Redeem.** Value is transferred out of band through an onchain contract call, a channel close, a fiat batch invoice, or any rail the network defines. The trigger, timing, and mechanism are network-defined. + +## Appendix + +### Network requirements + +Every `batch-settlement` network binding MUST specify: + +1. **Commitment format** — the structure and encoding of the payment payload, including all fields required for verification and redemption. +2. **Verification rules** — how the commitment is validated: signature scheme, balance or credit check, replay prevention, expiry. +3. **Storage behavior** — what constitutes a stored commitment for this network, and what the commitment identifier contains on success. +4. **Double-spend prevention** — how the network ensures the same commitment cannot be accepted or redeemed more than once. +5. **Commitment expiry** — when commitments become invalid and what happens to unaccepted commitments after expiry. +6. **Redemption** — who triggers redemption, when, and through what rail. +7. **Trust model** — whether the trust anchor is the client's onchain capital (capital-backed) or a network intermediary (credit-backed), and what guarantee the seller has of eventual settlement. + +### Extensions + +Network bindings may use optional extensions to communicate additional requirements in the `PaymentRequired` response. See the [extensions directory](../../extensions/) for available specifications. + +### Related schemes + +[`exact`](../exact/scheme_exact.md) — value is transferred immediately per request. + +[`upto`](../upto/scheme_upto.md) — value is transferred immediately, variable amount up to a client-authorized maximum. \ No newline at end of file diff --git a/specs/schemes/batch-settlement/scheme_batch_settlement_cloudflare.md b/specs/schemes/batch-settlement/scheme_batch_settlement_cloudflare.md new file mode 100644 index 0000000000..38a79eb064 --- /dev/null +++ b/specs/schemes/batch-settlement/scheme_batch_settlement_cloudflare.md @@ -0,0 +1,396 @@ +# Scheme: `batch-settlement` `cloudflare:402` + +## Summary + +The `batch-settlement` scheme on the Cloudflare network `cloudflare:402` enables access to resources through cryptographically signed payment commitments that are settled later through the network's infrastructure. + +**Network Identifier**: `cloudflare:402` +**Trust Model**: Credit-backed (see [batch_settlement.md](./batch_settlement.md#credit-backed)) + +**Authentication Method**: This implementation uses **HTTP Message Signatures (RFC 9421)** to authenticate payment commitments. The network acts as a trusted intermediary to provide immediate resource access while settlement is batched and handled later. + +## Protocol Flow + +The protocol flow for `batch-settlement` on the network (Cloudflare) includes an initial setup step, followed by client-driven payment with optional pre-authorization: + +### First-time Setup (Client) + +1. Host public keys at a `.well-known` endpoint (e.g., `https://mycrawler.com/.well-known/http-message-signatures-directory`) +2. Submit signature agent URL to the `registrationUrl` from the `http-message-signatures` extension (e.g., `https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/verify-ai-crawler/`) +3. The network (Cloudflare) associates signature agent URL with a billing identity for settlement + +### Payment Flow (Per Request) + +1. Makes an HTTP request to a **Resource Server**. +2. **Resource Server** responds with a `402 Payment Required` status. The response includes a PAYMENT-REQUIRED header (base64-encoded JSON) containing payment requirements with the `batch-settlement` scheme and `cloudflare:402` network with `payTo` set to `merchant`. The response also includes the `http-message-signatures` extension indicating where to find documentation on associating the HTTP message signature agent with the network. +3. **Client** constructs a payment payload containing the payment commitment (amount, asset) and signs the HTTP request using **HTTP Message Signatures (RFC 9421)**. The client includes `Signature-Agent`, `Signature-Input`, and `Signature` headers along with the PAYMENT-SIGNATURE header. +4. **Client** sends a new HTTP request with the PAYMENT-SIGNATURE header (base64-encoded JSON) and HTTP Message Signature headers. +5. **Resource Server** verifies the signature agent is recognized by the network (Cloudflare) and fetches the public key. +6. **Resource Server** verifies the HTTP Message Signature is valid using the fetched public key. +7. **Resource Server** validates the payment amount and asset match the requirements. +8. **Resource Server**, upon successful verification, grants the **Client** access to the resource and includes a PAYMENT-RESPONSE header (base64-encoded JSON) confirming the payment commitment. +9. The network (Cloudflare) acts as Merchant of Record, handling batched settlement and billing the identity associated with the signature agent. + +**Pre-Authorized Flow**: Clients with pre-authorized payment agreements can include the PAYMENT-SIGNATURE header and HTTP Message Signature headers in their initial request (step 1), bypassing the 402 response and proceeding directly to verification and access. + +**Note on HTTP Message Signatures**: All requests are signed using HTTP Message Signatures (RFC 9421). The signature agent's `.well-known/http-message-signatures-directory` URL must be known to the network (Cloudflare) and associated with a billing identity for settlement. This conforms to [draft-meunier-http-message-signatures-directory-04](https://datatracker.ietf.org/doc/html/draft-meunier-http-message-signatures-directory-04). + +## PaymentRequired for batch-settlement + +The `batch-settlement` scheme on the Cloudflare network uses the standard x402 `PaymentRequired` fields. The Cloudflare implementation includes the `http-message-signatures` extension to communicate authentication requirements. + +> **Note on Price Availability**: The `amount` field in `accepts` may not be available in all responses. Price information is only guaranteed when the HTTP Message Signature extension is correctly parsed and the signature agent is recognized. When price is not available, clients should retry with authentication. + +### Header Size Constraints + +HTTP intermediaries may reject headers larger than 2KB. To minimize header size, the `cloudflare:402` network: + +- Omits `schema` from extensions (schemas are documented in the extension specifications) +- May omit optional `resource` fields (`description`, `website`) when not available + +**Required fields:** + +- `x402Version` +- `accepts[].scheme`, `accepts[].network`, `accepts[].amount`, `accepts[].asset`, `accepts[].payTo` +- `accepts[].extra.version`: Network implementation version (semver format) +- `extensions.http-message-signatures.info.registrationUrl`, `extensions.http-message-signatures.info.signatureSchemes`, `extensions.http-message-signatures.info.tags` + +```http +HTTP/2 402 Payment Required +Content-Type: text/html +PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6IDIsICJlcnJvciI6ICJObyBQQVlNRU5ULVNJR05BVFVSRSBoZWFkZXIgcHJvdmlkZWQiLCAicmVzb3VyY2UiOiB7InVybCI6ICJodHRwczovL2V4YW1wbGUuY29tL2FydGljbGUiLCAiZGVzY3JpcHRpb24iOiAiUHJlbWl1bSBhcnRpY2xlIGNvbnRlbnQiLCAibWltZVR5cGUiOiAidGV4dC9odG1sIn0sICJhY2NlcHRzIjogWy4uLl19 + + + + Payment Required + This content requires payment. + +``` + +**Decoded PAYMENT-REQUIRED header:** + +```json +{ + "x402Version": 2, + "error": "No PAYMENT-SIGNATURE header provided", + "resource": { + "url": "https://example.com/article", + "mimeType": "text/html" + }, + "accepts": [ + { + "scheme": "batch-settlement", + "network": "cloudflare:402", + "amount": "1", + "asset": "USD", + "payTo": "merchant", + "extra": { + "version": "1.0.0" + } + } + ], + "extensions": { + "http-message-signatures": { + "info": { + "registrationUrl": "https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/verify-ai-crawler/", + "signatureSchemes": ["ed25519"], + "tags": ["web-bot-auth"] + } + } + } +} +``` + +**PaymentRequirements fields:** + +- `scheme`: Must be `"batch-settlement"` +- `network`: Must be `"cloudflare:402"` (CAIP-2 format) +- `asset`: The asset identifier (e.g., `"USD"` for fiat currency - ISO 4217 format) +- `payTo`: Must be `"merchant"` (constant indicating the network handles settlement) +- `amount`: Payment amount in smallest unit of the asset (e.g., cents for USD) +- `maxTimeoutSeconds`: Maximum time allowed for payment completion (optional, see note below) +- `extra.version`: Network implementation version in semver format (see [Network Version](#network-version)) + +> **Note on Timeouts**: When the `maxTimeoutSeconds` is omitted or set to `0`, the network makes no timing guarantees on price validity. Clients should not cache pricing information across requests when timeout is zero or absent. + +**Extensions:** + +The Cloudflare implementation uses the `http-message-signatures` extension to communicate authentication requirements: + +- `extensions.http-message-signatures`: Communicates Cloudflare's authentication requirements + - `info.registrationUrl`: URL to the network's setup documentation (`https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/verify-ai-crawler/`) - this is intended for human-driven setup; a programmatic API endpoint may be provided in future versions + - `info.signatureSchemes`: Supported algorithms (`["ed25519"]`) + - `info.tags`: Supported signature tags (`["web-bot-auth"]`) + +Note: `payTo` is set to `"merchant"` as the network handles settlement. + +## PAYMENT-SIGNATURE Header Payload + +The client sends a PAYMENT-SIGNATURE header containing base64-encoded JSON with the payment payload. + +```http +GET /article HTTP/2 +Host: example.com +Signature-Agent: mycrawler.com +Signature-Input: sig=("@authority" "signature-agent" "payment-signature"); created=1700000000; expires=1700011111; keyid="ba3e64=="; tag="web-bot-auth" +Signature: sig=:abc123...==: +PAYMENT-SIGNATURE: eyJ4NDAyVmVyc2lvbiI6MiwicGF5bG9hZCI6eyJhbW91bnQiOiI1IiwiYXNzZXQiOiJVU0QifSwiYWNjZXB0ZWQiOnsic2NoZW1lIjoiYmF0Y2gtc2V0dGxlbWVudCIsIm5ldHdvcmsiOiJjbG91ZGZsYXJlOjQwMiIsImFtb3VudCI6IjUiLCJhc3NldCI6IlVTRCIsInBheVRvIjoibWVyY2hhbnQiLCJtYXhUaW1lb3V0U2Vjb25kcyI6MzB9fQ== +``` + +**Decoded PAYMENT-SIGNATURE header:** + +```json +{ + "x402Version": 2, + "payload": { + "amount": "5", + "asset": "USD" + }, + "accepted": { + "scheme": "batch-settlement", + "network": "cloudflare:402", + "amount": "5", + "asset": "USD", + "payTo": "merchant", + "maxTimeoutSeconds": 30 + } +} +``` + +The `payload` field contains: + +- `amount`: Payment amount in smallest unit of the asset (e.g., cents for USD) +- `asset`: Asset identifier (e.g., `"USD"`) + +**Note**: The `signatureAgent` and `signature` are NOT in the payment payload. They come from the HTTP Message Signature headers (`Signature-Agent` and `Signature` headers) as defined in RFC 9421. + +The `accepted` field contains the full `PaymentRequirements` object that this payment fulfills (without extensions, as those are at the top level). + +**Note on Extensions**: According to v2 spec, clients must echo the extensions from the `PaymentRequired` response. However, extensions are not part of the `accepted` field since `accepted` contains only the specific `PaymentRequirements` object from the `accepts` array. Extensions would be echoed at the top level of the payment payload if the client needs to respond to them. + +## Verification + +Steps to verify a payment for the `batch-settlement` scheme, the network (Cloudflare) implements: + +1. **Verify HTTP Message Signature is valid**: Validate the HTTP Message Signature (RFC 9421) from the `Signature` header using the public key fetched from the `Signature-Agent` header URL +2. **Verify signature agent is recognized by the network**: Confirm the signature agent URL (from `Signature-Agent` header) is known to the network (Cloudflare) and associated with a billing identity +3. **Verify amount and asset are sufficient**: Ensure the payment amount and asset meet the requirements +4. **Verify timestamp freshness**: Ensure the payment is not expired (typically within 30 seconds) +5. **Verify accepted field matches**: Verify the `accepted` field matches one of the offered `PaymentRequirements` + +### Verification Pseudocode + +```javascript +function verifyBatchSettlementPayment(paymentPayload, signatureAgentHeader, httpSignature) { + // 1. Verify signature agent is recognized by the network and get billing info + const agentInfo = await verifySignatureAgentWithNetwork(signatureAgentHeader); + + if (!agentInfo.isRecognized) { + return { valid: false, reason: "signature_agent_unknown" }; + } + + // 2. Fetch public key from signature agent's .well-known/http-message-signatures-directory endpoint + const publicKey = await fetchPublicKey(signatureAgentHeader, agentInfo.keyId); + + if (!publicKey) { + return { valid: false, reason: "server_error" }; + } + + // 3. Verify HTTP Message Signature using the public key + const isSignatureValid = verifyHttpMessageSignature( + httpSignature, + publicKey, + buildCanonicalString(paymentPayload) + ); + + if (!isSignatureValid) { + return { valid: false, reason: "invalid_signature" }; + } + + // 4. Verify payment signature header is correctly structured + if (!isValidPaymentSignature(paymentPayload)) { + return { valid: false, reason: "invalid_payment" }; + } + + // 5. Verify amount/asset are sufficient for the resource + const isSufficientPayment = checkPaymentSufficiency( + paymentPayload.accepted.amount, + paymentPayload.accepted.asset, + ); + + if (!isSufficientPayment) { + return { valid: false, reason: "invalid_payment" }; + } + + // billingIdentifier is an arbitrary network identifier (e.g., account ID) + // used by the network to rollup and bill charges for this signature agent + return { valid: true, reason: null, billingIdentifier: agentInfo.billingIdentifier }; +} +``` + +## Settlement + +The network (Cloudflare) acts as Merchant of Record, aggregating payment commitments, billing the identity associated with each signature agent, and distributing revenue to content owners on a periodic basis through traditional off-chain financial rails. + +## PAYMENT-RESPONSE Header + +Upon successful verification, the server includes a PAYMENT-RESPONSE header (base64-encoded JSON) in the 200 OK response. + +```http +HTTP/2 200 OK +Content-Type: text/html +PAYMENT-RESPONSE: eyJzdWNjZXNzIjp0cnVlLCJ0cmFuc2FjdGlvbiI6IiIsIm5ldHdvcmsiOiJjbG91ZGZsYXJlOjQwMiIsInBheWVyIjoibXljcmF3bGVyLmNvbSIsImFtb3VudCI6IjUiLCJhc3NldCI6IlVTRCIsImV4dHJhIjp7InRpbWVzdGFtcCI6MTczMDg3Mjk2OH19 + + + + Premium Article +
Premium content...
+ +``` + +**Decoded PAYMENT-RESPONSE header:** + +```json +{ + "success": true, + "transaction": "", + "network": "cloudflare:402", + "payer": "mycrawler.com", + "amount": "5", + "asset": "USD", + "extra": { + "timestamp": 1730872968 + } +} +``` + +## Appendix + +### Network-Specific Implementation + +The network (Cloudflare) implements the `batch-settlement` scheme with the following details: + +**Registration URL**: `https://developers.cloudflare.com/ai-crawl-control/features/pay-per-crawl/use-pay-per-crawl-as-ai-owner/verify-ai-crawler/` + +> **Note**: This URL is intended for human-driven setup and documentation. It provides instructions for the onboarding process including Web Bot Auth setup, verified bot policy compliance, and verification request submission. A programmatic API endpoint for automated registration may be provided in future versions. + +This URL provides: + +1. **Setup instructions**: How to submit your signature agent's `.well-known/http-message-signatures-directory` URL to the network +2. **Billing identity association**: How to associate your signature agent with a billing identity for settlement +3. **Public key requirements**: What public key formats and algorithms are supported +4. **Verification process**: How the network verifies HTTP Message Signatures + +**Supported Tags**: `["web-bot-auth", "agent-browser-auth"]` + +**Setup Process**: + +1. Client hosts their public keys at a `.well-known/http-message-signatures-directory` endpoint (e.g., `https://mycrawler.com/.well-known/http-message-signatures-directory`) +2. Client submits this URL to the network via the network URL endpoint +3. The network associates the signature agent URL with a billing identity +4. Client can now sign requests using HTTP Message Signatures, with the `Signature-Agent` header pointing to their `.well-known/http-message-signatures-directory` URL +5. Resource servers verify signatures by fetching public keys from the `Signature-Agent` URL and validating the signature agent is known to the network + +### Network Registration Terms + +The following operational details are established during registration with the network (via `registrationUrl`) and are not part of the x402 protocol itself: + +- **Settlement periods**: Frequency of billing cycles (e.g., daily, weekly) +- **Payment failure handling**: What happens if batched payments cannot be settled +- **Rate limits and quotas**: Usage restrictions per billing period +- **Dispute resolution**: Process for handling billing disputes + +These terms may vary by account and are subject to the network's terms of service. + +**Note**: For the full extension definition, see [`http-message-signatures`](../../extensions/http-message-signatures.md). + +**Example HTTP Request with Message Signatures**: + +```http +GET /article HTTP/2 +Host: example.com +User-Agent: Mozilla/5.0 Chrome/113.0.0 MyCrawler/1.0 +Signature-Agent: mycrawler.com +Signature-Input: sig=("@authority" "signature-agent" "payment-signature"); created=1700000000; expires=1700011111; keyid="ba3e64=="; tag="web-bot-auth" +Signature: sig=:abc123...==: + +Payment-Signature: eyJ4NDAyVmVyc2lvbiI6IDIsIC4uLn0= +``` + +The `Signature-Agent` header indicates where to find the client's public keys (e.g., `mycrawler.com`). This URL must be known to the network (Cloudflare) and associated with a billing identity. The `registrationUrl` in the extension points to the network's documentation on how to associate your signature agent. + +### Security Considerations + +**HTTP Message Signature Verification**: + +- All requests must be signed using HTTP Message Signatures (RFC 9421) +- The signature **MUST** include the following components: + - `@authority`: The target server authority + - `signature-agent`: The signature agent header value + - `payment-signature`: The PAYMENT-SIGNATURE header (lowercase per RFC 9421) +- This ensures the payment commitment is cryptographically bound to the HTTP request +- Servers verify signatures by: + 1. Fetching the public key from the URL in the `Signature-Agent` header + 2. Validating the signature using the fetched public key + 3. Confirming the signature agent URL is known to the network (Cloudflare) + +**Billing Identity Association**: + +- The signature agent URL (from `Signature-Agent` HTTP header) must be known to the network (Cloudflare) +- The network maintains the association between signature agent URLs and billing identities with account IDs +- The signature agent is identified by the `Signature-Agent` header + +**Stateless Verification**: + +- Servers do not need to maintain payment state or track attempts +- All verification can be performed stateless by validating the signature and billing identity association +- No database lookups or session management required + +### Error Codes + +Error codes for batch-settlement payment failures on the Cloudflare network: + +- `blocked`: Payment required to access resource +- `price_not_acceptable`: Payment amount does not match requirements +- `payment_failed`: Signature agent not associated with valid billing identity +- `invalid_signature`: Invalid or missing `Signature-Input` or `Signature` headers +- `signature_agent_unknown`: Signature agent not recognized by network (Cloudflare) +- `invalid_payment_signature`: Invalid or malformed `PAYMENT-SIGNATURE` header +- `origin_error`: Server error during payment processing +- `unknown`: Unknown error + +### Pre-Authorized Access + +Clients with pre-authorized payment agreements can include the PAYMENT-SIGNATURE header in their initial request, bypassing the 402 response: + +```http +GET /article HTTP/2 +Host: example.com +Signature-Agent: mycrawler.com +Signature-Input: sig=("@authority" "signature-agent" "payment-signature"); created=1700000000; expires=1700011111; keyid="ba3e64=="; tag="web-bot-auth" +Signature: sig=:abc123...==: + +Payment-Signature: eyJ4NDAyVmVyc2lvbiI6MiwicGF5bG9hZCI6eyJhbW91bnQiOiIxMDAwMCIsImFzc2V0IjoiVVNEIn0sImFjY2VwdGVkIjp7Ii4uLiJ9fQ== +``` + +If the payment is valid, the server responds directly with `200 OK` and the requested content, skipping the 402 negotiation phase. + +### Comparison with Exact Scheme + +| Feature | Exact + EVM/SVM | Batch-Settlement + Cloudflare | +| ---------------- | -------------------------------- | --------------------------------------- | +| Settlement | Immediate blockchain transaction | Batched off-chain settlement | +| Transaction Fees | Gas fees required | No transaction fees | +| Currency | Cryptocurrency (USDC, etc.) | Fiat (USD, etc.) | +| Infrastructure | Blockchain wallet required | Cloudflare account required | +| Trust Model | Trustless blockchain | Trusted Merchant of Record (Cloudflare) | + +### Network Version + +The `extra.version` field uses semantic versioning (semver) to signal changes in network behavior. Clients should check this field to detect breaking changes. + +**Changelog:** + +| Version | Date | Changes | +| ------- | ------- | --------------- | +| `1.0.0` | 2026-01 | Initial release | \ No newline at end of file diff --git a/specs/schemes/batch-settlement/scheme_batch_settlement_evm.md b/specs/schemes/batch-settlement/scheme_batch_settlement_evm.md new file mode 100644 index 0000000000..79d8e47650 --- /dev/null +++ b/specs/schemes/batch-settlement/scheme_batch_settlement_evm.md @@ -0,0 +1,681 @@ +# Scheme: `batch-settlement` on `EVM` + +## Summary + +The `batch-settlement` scheme on EVM is a **capital-backed** network binding using stateless unidirectional payment channels for high-throughput, low-cost payments. Clients deposit funds into onchain channels once and sign off-chain **cumulative vouchers** per request. Servers verify vouchers with fast signature checks and claim them onchain periodically in batches, reducing both latency and gas costs drastically. A single claim transaction can cover many channels at once and only updates onchain accounting; claimed funds are later transferred to the receiver via a separate settle operation that sweeps many claims into one token transfer. + +The scheme supports **dynamic pricing**: the client authorizes a maximum per-request, and the server charges the actual cost within that ceiling. + +--- + +## Channel Lifecycle + +### Channel creation and deposits + +A channel is created implicitly on the first deposit. The client deposits funds from the `payer` address into an onchain escrow via one of two asset transfer methods: `eip3009` for tokens that support `receiveWithAuthorization` (e.g. USDC) or `permit2` as a universal fallback for any ERC-20. Deposits are sponsored by the facilitator (gasless for the client). + +Channel identity is derived from an immutable config struct: +```solidity +struct ChannelConfig { + address payer; // Client wallet (EOA or smart wallet) + address payerAuthorizer; // EOA for voucher signing, or address(0) for EIP-1271 via payer + address receiver; // Server's payment destination (EOA or routing contract) + address receiverAuthorizer; // Authorizes claims and refunds via EIP-712 signatures + address token; // ERC-20 payment token + uint40 withdrawDelay; // Seconds before timed withdrawal completes (15 min – 30 days) + bytes32 salt; // Differentiates channels with identical parameters +} +``` +with `channelId = EIP712Hash(ChannelConfig)` under the `x402 Batch Settlement` domain. The hash binds the immutable config to the EVM `chainId` and deployed `x402BatchSettlement` address, so the same config produces different IDs across chains or deployments. + +### Requests and vouchers + +The channel tracks two values: `balance` (total deposited minus withdrawals and refunds) and `totalClaimed` (cumulative amount claimed by the server). Each voucher the client signs carries a cumulative ceiling (`maxClaimableAmount`). The server can claim up to that ceiling. Because vouchers are monotonically increasing, old vouchers with lower ceilings are naturally superseded. + +The server tracks a running total of actual charges per channel (`chargedCumulativeAmount`). For each subsequent request, the client sets the voucher's `maxClaimableAmount` to `chargedCumulativeAmount + amount`, where `amount` is the per-request maximum. + +### Claim and settle + +The server claims the latest voucher per channel onchain at its discretion. `claimWithSignature(claims, signature)` allows aggregating claims from multiple channels in one call. Claiming updates `totalClaimed` per channel; no token transfer occurs. + +`settle` sweeps all claimed-but-unsettled funds to the `receiver` in one transfer. + +### Refund and withdrawal + +**Cooperative refund**: the receiver side can return up to `balance - totalClaimed` to the payer via two paths: +- `refund(config, amount)`: direct call by `receiver` or `receiverAuthorizer`, no signature required. +- `refundWithSignature(config, amount, nonce, sig)`: relay-friendly; anyone submits an EIP-712 `Refund` signature from `receiverAuthorizer`. + +Both paths share the same internal execution: `refundNonce` is incremented **first** (before the amount cap is applied and before any token transfer), so a no-op refund (`amount > 0` but no unclaimed escrow available) still advances the nonce without emitting `Refunded` or moving tokens. A direct `refund` call therefore invalidates any pre-signed `refundWithSignature` digest for the previous nonce. If a timed withdrawal is pending, a cooperative refund **reduces** its recorded amount proportionally; it is only cancelled entirely when the refund amount meets or exceeds the pending withdrawal amount. + +**Timed withdrawal** (escape hatch): the `payer` or `payerAuthorizer` calls `initiateWithdraw(config, amount)` to start a grace period. The requested `amount` must not exceed `balance - totalClaimed` at initiation time; the call reverts otherwise. During the grace period the server can claim outstanding vouchers. After the withdrawal delay elapses, `finalizeWithdraw` (also callable by `payerAuthorizer`) completes the withdrawal, capping the transferred amount to whatever unclaimed escrow remains at that point. + +### Authorizer roles + +**Payer authorizer** (`payerAuthorizer`): if set to a non-zero address (an EOA), vouchers are verified via ECDSA recovery against that committed key ( fast, no RPC required). If set to zero, vouchers are verified against the payer address, supporting EIP-1271 smart wallets at the cost of an RPC call. + +**Receiver authorizer** (`receiverAuthorizer`): authorizes claim and refund operations via EIP-712 signatures. The server chooses this address: a server-owned EOA or smart contract (eg for key rotation), or a facilitator-provided address when the server delegates authorization. Must not be zero. Anyone can relay a `claimWithSignature` or `refundWithSignature` transaction with a valid authorization signature from the `receiverAuthorizer`. + +### Channel lifecycle events + +The contract emits `ChannelCreated(channelId, config)` on the first deposit into a channel (when `balance` transitions from zero with `totalClaimed == 0`). It emits `ChannelClosed(channelId, config)` when unclaimed escrow returns to zero with `totalClaimed == 0` — triggered by either a full cooperative refund or a timed withdrawal that drains all escrow. Indexers must handle `ChannelCreated` firing more than once on the same `channelId` if the channel is re-funded after being fully drained. + +### Channel reuse and parameter changes + +Channels are long-lived. After a refund, the client can top up and reuse the same channel. However, the channel config is immutable. If any parameter needs to change, a new channel is required. If delegating `receiverAuthorizer` to a facilitator, the server should claim all outstanding vouchers and refund remaining balances on old channels before switching to another facilitator. + +--- + +## 402 Response (PaymentRequirements) + +The 402 response contains pricing terms and the server's channel parameters. The client maps `payTo` → `ChannelConfig.receiver`, `extra.receiverAuthorizer` → `ChannelConfig.receiverAuthorizer`, `asset` → `ChannelConfig.token`, and `extra.withdrawDelay` → `ChannelConfig.withdrawDelay`, then fills in its own `payer`, `payerAuthorizer`, and `salt` to construct the full config. + +```json +{ + "scheme": "batch-settlement", + "network": "eip155:8453", + "amount": "100000", + "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "payTo": "0xServerReceiverAddress", + "maxTimeoutSeconds": 3600, + "extra": { + "receiverAuthorizer": "0xReceiverAuthorizerAddress", + "withdrawDelay": 900, + "name": "USDC", + "version": "2" + } +} +``` + +| Field | Type | Required | Description | +| --------------------------- | -------- | -------- | ------------------------------------------------------ | +| `extra.receiverAuthorizer` | `string` | yes | Address that will authorize claims/refunds | +| `extra.withdrawDelay` | `number` | yes | Withdrawal delay in seconds (15 min – 30 days) | +| `extra.assetTransferMethod` | `string` | optional | `"eip3009"` (default) or `"permit2"` | +| `extra.name` | `string` | yes | EIP-712 domain name of the token contract | +| `extra.version` | `string` | yes | EIP-712 domain version of the token contract | +| `extra.channelState` | `object` | optional | Corrective-only server channel snapshot for cumulative amount resynchronization | +| `extra.voucherState` | `object` | optional | Corrective-only signed voucher proof for cumulative amount resynchronization | + +--- + +## Client: Payment Construction + +The client constructs a payment payload whose type depends on channel state: + +- `deposit`: No channel exists or balance is exhausted — client signs a token authorization and voucher +- `voucher`: Channel has sufficient balance — client signs a new cumulative voucher +- `refund`: Client requests a cooperative refund — client signs a zero-charge voucher and optionally includes a refund amount + +### Deposit Payload + +The `deposit.authorization` field contains the token transfer authorization — exactly one of `erc3009Authorization` or `permit2Authorization` must be present. + +```json +{ + "x402Version": 2, + "accepted": { + "scheme": "batch-settlement", + "network": "eip155:8453", + "amount": "1000", + "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "payTo": "0xServerReceiverAddress", + "maxTimeoutSeconds": 3600, + "extra": { + "receiverAuthorizer": "0xReceiverAuthorizerAddress", + "withdrawDelay": 900, + "name": "USDC", + "version": "2" + } + }, + "payload": { + "type": "deposit", + "channelConfig": { + "payer": "0xClientAddress", + "payerAuthorizer": "0xClientPayerAuthorizerEOA", + "receiver": "0xServerReceiverAddress", + "receiverAuthorizer": "0xReceiverAuthorizerAddress", + "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "withdrawDelay": 900, + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "voucher": { + "channelId": "0xabc123...channelId", + "maxClaimableAmount": "1000", + "signature": "0x...EIP-712 voucher signature" + }, + "deposit": { + "amount": "100000", + "authorization": { + "erc3009Authorization": { + "validAfter": "0", + "validBefore": "1770000000", + "salt": "0x...authorization salt", + "signature": "0x...ERC-3009 signature" + } + } + } + } +} +``` + +### Voucher Payload + +```json +{ + "x402Version": 2, + "accepted": { "..." : "..." }, + "payload": { + "type": "voucher", + "channelConfig": { + "payer": "0xClientAddress", + "payerAuthorizer": "0xClientPayerAuthorizerEOA", + "receiver": "0xServerReceiverAddress", + "receiverAuthorizer": "0xReceiverAuthorizerAddress", + "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "withdrawDelay": 900, + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "voucher": { + "channelId": "0xabc123...channelId", + "maxClaimableAmount": "5000", + "signature": "0x...EIP-712 voucher signature" + } + } +} +``` + +### Refund Payload + +The optional `amount` requests a partial refund; omit it for a full refund. The voucher is zero-charge: `voucher.maxClaimableAmount` MUST equal the channel's current `chargedCumulativeAmount`. Before settlement, the server completes the payload with the refund nonce, claim data, and any receiver-authorizer signatures it is responsible for. + +```json +{ + "x402Version": 2, + "accepted": { "..." : "..." }, + "payload": { + "type": "refund", + "channelConfig": { + "payer": "0xClientAddress", + "payerAuthorizer": "0xClientPayerAuthorizerEOA", + "receiver": "0xServerReceiverAddress", + "receiverAuthorizer": "0xReceiverAuthorizerAddress", + "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + "withdrawDelay": 900, + "salt": "0x0000000000000000000000000000000000000000000000000000000000000000" + }, + "voucher": { + "channelId": "0xabc123...channelId", + "maxClaimableAmount": "3200", + "signature": "0x...EIP-712 zero-charge voucher signature" + }, + "amount": "1500" + } +} +``` + +--- + +## Server: State & Forwarding + +The server is the sole owner of per-channel state. + +### Per-Channel State + +The server must maintain per-channel state, keyed by channel ID: + +| State Field | Type | Description | +| ------------------------- | --------------- | ------------------------------------------------------------------------------------------ | +| `channelConfig` | `ChannelConfig` | Full channel configuration object | +| `chargedCumulativeAmount` | `uint128` | Actual accumulated cost for this channel | +| `signedMaxClaimable` | `uint128` | `maxClaimableAmount` from the latest client-signed voucher | +| `signature` | `bytes` | Client's voucher signature for the latest `signedMaxClaimable` | +| `balance` | `uint128` | Current channel balance (mirrored from onchain) | +| `totalClaimed` | `uint128` | Total claimed onchain (mirrored from onchain) | +| `withdrawRequestedAt` | `uint64` | Unix timestamp when timed withdrawal was initiated, or 0 if none (mirrored from onchain) | +| `refundNonce` | `uint256` | Next nonce required for `refundWithSignature` (mirrored from onchain) | +| `onchainSyncedAt` | `uint64` | Local timestamp when mirrored onchain fields were refreshed | +| `lastRequestTimestamp` | `uint64` | Timestamp of the last paid request | + +### Request Processing + +The server must serialize request processing per channel and must not update voucher state until the resource handler has succeeded. + +1. **Verify**: + - For `voucher` and `deposit` payloads, check that `payload.voucher.maxClaimableAmount == chargedCumulativeAmount + paymentRequirements.amount`. If this fails, reject with `invalid_batch_settlement_evm_cumulative_amount_mismatch` and return a corrective 402. + - For refund payloads, check that `payload.voucher.maxClaimableAmount == chargedCumulativeAmount` and skip the resource handler after facilitator verification. + - Always call facilitator `/verify` for `deposit` and `refund` payloads, as well as `voucher` payloads with EIP-1271 vouchers. + - A plain EOA-authorized `voucher` may be verified locally when the server's mirrored onchain state is fresh. +2. **Execute**: Run the resource handler +3. **On success** — commit state: + - `chargedCumulativeAmount += actualPrice` (where `actualPrice <= PaymentRequirements.amount`) + - Mirror `balance`, `totalClaimed`, `withdrawRequestedAt`, and `refundNonce` from the facilitator response +4. **On failure**: State unchanged, client can retry the same voucher. + +### Payment Response Contract + +Successful paid responses distinguish onchain transfers from offchain charges: + +- Voucher-only response: `transaction` is `""`, top-level `amount` is `""`, `extra.chargedAmount` is the request charge, and `extra.channelState` carries the channel snapshot. +- Deposit response: `transaction` is the deposit transaction hash, top-level `amount` is the deposited amount, `extra.chargedAmount` is the request charge, and `extra.channelState` carries the channel snapshot. +- Refund response: `transaction` is the refund transaction hash, top-level `amount` is the refunded amount, `extra.channelState` carries the post-refund channel snapshot and `extra.chargedAmount` is omitted. + +```json +{ + "success": true, + "transaction": "", + "network": "eip155:8453", + "payer": "0xClientAddress", + "amount": "", + "extra": { + "chargedAmount": "700", + "channelState": { + "channelId": "0xabc123...channelId", + "balance": "100000", + "totalClaimed": "3200", + "withdrawRequestedAt": 0, + "refundNonce": "1", + "chargedCumulativeAmount": "3900" + } + } +} +``` + +### Cooperative refund flow + +When the server receives a `type: "refund"` payload: + +1. **Verify (zero-charge)**: enforce `payload.voucher.maxClaimableAmount == chargedCumulativeAmount` (no increment from `paymentRequirements.amount`). If local state is stale, emit a corrective 402 so the client can recover and retry. +2. **Bypass the protected resource.** Refund payloads are payment operations, not paid requests; the application route is not invoked. +3. **Complete the settlement payload**: resolve omitted `amount` to a full refund, validate any partial `amount`, add `refundNonce`, build `claims`, and add receiver-authorizer signatures when the server owns that key. +4. **Submit onchain**: `claimWithSignature(claims, claimSig)` (no-op when `maxClaimableAmount == totalClaimed`) followed by `refundWithSignature(config, amount, nonce, refundSig)`. The contract increments `refundNonce` before applying the amount cap; even if no tokens move (zero available escrow), the nonce advances. +5. **Update channel state**: + - **Full refund** (refunded amount equals the remainder): delete the channel record. + - **Partial refund**: keep the channel record, mirror the returned `balance`, `totalClaimed`, `withdrawRequestedAt`, and `refundNonce`. If a timed withdrawal was pending, its recorded amount is reduced proportionally (or cancelled if the refund covers it entirely). +6. Return the settle response in the standard `PAYMENT-RESPONSE` header. + +After the server completes the refund payload, the facilitator receives: + +```json +{ + "type": "refund", + "channelConfig": { "..." : "..." }, + "voucher": { + "channelId": "0xabc123...channelId", + "maxClaimableAmount": "3200", + "signature": "0x...EIP-712 zero-charge voucher signature" + }, + "amount": "1500", + "refundNonce": "1", + "claims": [ + { + "voucher": { + "channel": { "..." : "..." }, + "maxClaimableAmount": "3200" + }, + "signature": "0x...EIP-712 zero-charge voucher signature", + "totalClaimed": "3200" + } + ], + "refundAuthorizerSignature": "0x...refund authorization", + "claimAuthorizerSignature": "0x...claim authorization" +} +``` + +`refundAuthorizerSignature` and `claimAuthorizerSignature` are included when the server owns the receiver-authorizer key. If the channel delegates receiver authorization to the facilitator, the server omits them and the facilitator signs before submitting the transaction. + +--- + +## Facilitator Interface + +Uses the standard x402 facilitator interface (`/verify`, `/settle`, `/supported`). + +### POST /verify + +Verifies a deposit, voucher, or refund payment payload. Returns the onchain channel snapshot: + +```json +{ + "isValid": true, + "payer": "0xPayerAddress", + "extra": { + "channelId": "0xabc123...", + "balance": "1000000", + "totalClaimed": "500000", + "withdrawRequestedAt": 0, + "refundNonce": "0" + } +} +``` + +### POST /settle + +| `payload.type` | When Used | Onchain Effect | +| -------------- | ----------------------------- | ----------------------------------------------------- | +| `"deposit"` | First request or top-up | Deposit via the canonical ERC-3009 or Permit2 collector | +| `"claim"` | Server batches voucher claims | Validate vouchers, update accounting (no transfer) | +| `"settle"` | Server transfers earned funds | Transfer unsettled amount to receiver | +| `"refund"` | Cooperative refund | Return specified amount to payer, increment refund nonce | + +Server-authored claim and settle payloads use the same `type` discriminator: + +```json +{ + "type": "claim", + "claims": [ + { + "voucher": { + "channel": { "..." : "..." }, + "maxClaimableAmount": "5000" + }, + "signature": "0x...voucher signature", + "totalClaimed": "5000" + } + ], + "claimAuthorizerSignature": "0x...claim authorization" +} +``` + +`claimAuthorizerSignature` is included when the server owns the receiver-authorizer key. If receiver authorization is delegated to the facilitator, the server omits it and the facilitator signs before submitting the transaction. + +```json +{ + "type": "settle", + "receiver": "0xServerReceiverAddress", + "token": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913" +} +``` + +Example facilitator response for a claim: + +```json +{ + "success": true, + "transaction": "0x...transactionHash", + "network": "eip155:8453", + "amount": "" +} +``` + +`amount` is empty because claim only updates accounting; no funds move. + +Example facilitator response for a settle: + +```json +{ + "success": true, + "transaction": "0x...transactionHash", + "network": "eip155:8453", + "amount": "5000" +} +``` + +`amount` is the amount transferred to the receiver; if settlement is a no-op, it is `"0"`. + +Example facilitator response for a deposit: + +```json +{ + "success": true, + "transaction": "0x...transactionHash", + "network": "eip155:8453", + "payer": "0xPayerAddress", + "amount": "100000", + "asset": "0xAssetAddress", + "extra": { + "channelState": { + "channelId": "0xabc123...", + "balance": "100000", + "totalClaimed": "3200", + "withdrawRequestedAt": 0, + "refundNonce": "1" + } + } +} +``` + +Example facilitator response for a refund: + +```json +{ + "success": true, + "transaction": "0x...transactionHash", + "network": "eip155:8453", + "payer": "0xPayerAddress", + "amount": "1500", + "extra": { + "channelState": { + "channelId": "0xabc123...", + "balance": "98500", + "totalClaimed": "3200", + "withdrawRequestedAt": 0, + "refundNonce": "2" + } + } +} +``` + +`amount` is the amount returned to the payer. + +### GET /supported + +The facilitator declares a receiver authorizer whose role is to produce EIP-712 signatures for claims and refunds. The server may delegate to this address as its channel's `receiverAuthorizer`, or supply its own. Any address in `signers` may relay the resulting transactions. + +```json +{ + "kinds": [ + { + "x402Version": 2, + "scheme": "batch-settlement", + "network": "eip155:8453", + "extra": { + "receiverAuthorizer": "0xReceiverAuthorizerAddress" + } + } + ], + "extensions": [], + "signers": { + "eip155:*": [ + "0xSignerAddress1", + "0xSignerAddress2" + ] + } +} +``` + +### Verification Rules + +A facilitator must enforce: + +1. **Channel config consistency** (deposit, voucher, and refund): the config's chain-bound EIP-712 hash must equal the claimed channel ID. +2. **Token match**: the channel token must match the payment requirements asset. +3. **Receiver match**: the channel receiver must equal the payment requirements `payTo`. +4. **Receiver authorizer match**: the channel receiver authorizer must equal `extra.receiverAuthorizer`. +5. **Withdraw delay match**: the channel withdraw delay must equal `extra.withdrawDelay`. +6. **Signature validity**: recover the signer from the EIP-712 voucher digest. If the payer authorizer is set, the signer must match it (ECDSA only). If the payer authorizer is zero, validate via `SignatureChecker` against the payer. +7. **Channel existence**: the channel must have a positive balance. +8. **Balance check** (deposit only): the client must have sufficient token balance. +9. **Deposit sufficiency**: `maxClaimableAmount` must be at most `balance` (or `balance + depositAmount` for deposit payloads). +10. **Not below claimed**: `maxClaimableAmount` must exceed onchain `totalClaimed`. For refund payloads (`payload.type == "refund"`), this rule is relaxed to `maxClaimableAmount >= totalClaimed`, since refund vouchers are zero-charge and may match the already-claimed total exactly. +11. **Signed refunds**: the refund nonce must equal the onchain `refundNonce` at the time of submission; the EIP-712 `Refund` digest (`Refund(bytes32 channelId,uint256 nonce,uint128 amount)`) must bind the same `amount` submitted in the transaction. The contract increments the nonce before computing the capped transfer amount, so the nonce advances even when no tokens move. + +The facilitator must return the channel snapshot (`balance`, `totalClaimed`, `withdrawRequestedAt`, `refundNonce`) in every `/verify` response `extra` field and in every `/settle` response under `extra.channelState`. If `withdrawRequestedAt` is non-zero, the server should claim outstanding vouchers promptly before the withdraw delay elapses. + +--- + +## Claim & Settlement Strategy + +`claim(voucherClaims)` validates payer voucher signatures and updates accounting for multiple channels; `msg.sender` must be `receiver` or `receiverAuthorizer` for every row. `claimWithSignature(claims, signature)` is the relay-friendly variant: anyone can submit it with a valid EIP-712 `ClaimBatch` signature from `receiverAuthorizer` covering all rows (all rows must share the same `receiverAuthorizer`). No token transfer occurs in either path. + +`settle(receiver, token)` transfers all claimed-but-unsettled funds for a receiver+token pair to the receiver in one transfer. Permissionless. + +| Strategy | Description | Trade-off | +| ----------------- | ---------------------------------------------- | -------------------------------- | +| **Periodic** | Claim + settle every N minutes | Predictable gas costs | +| **Threshold** | Claim + settle when unclaimed amount exceeds T | Bounds server's risk exposure | +| **On withdrawal** | Claim + settle when withdrawal is initiated | Minimum gas, maximum risk window | + +The server must claim all outstanding vouchers before the withdraw delay elapses. Unclaimed vouchers become unclaimable after `finalizeWithdraw()` reduces the channel balance. + +--- + +## Client Verification Rules + +### Steady State + +Before signing the next voucher, the client must verify from the payment response: + +1. `extra.chargedAmount <= PaymentRequirements.amount` +2. `extra.channelState.chargedCumulativeAmount == previous + extra.chargedAmount` +3. `extra.channelState.balance` is consistent with the client's expectation +4. `extra.channelState.channelId` matches + +If any check fails, the client must not sign further vouchers and should initiate withdrawal. + +### Recovery After State Loss + +Channel identity is deterministic. The client can recompute `channelId` from the 402 response plus its own channel parameters (`payer`, `payerAuthorizer`, `salt`), then read `channels(channelId)` to recover the onchain `balance` and `totalClaimed`. + +The recovery baseline is: + +- Use onchain `totalClaimed` when no trusted offchain state is available. +- Use server-provided `chargedCumulativeAmount` only when the server also returns the last signed voucher (`signedMaxClaimable` and `signature`) and the client verifies that signature against its own voucher signer. + +**Client cold start.** When the client has no local channel record, it reads onchain state and sets `chargedCumulativeAmount = totalClaimed`. If the next request would exceed the recovered `balance`, the client sends a deposit/top-up payload. Otherwise it signs a voucher for `totalClaimed + amount`. + +**Server state loss.** If the server has no local channel record, it sets `chargedCumulativeAmount = totalClaimed` as the baseline. If the server lost unclaimed vouchers, those unclaimed charges are forfeited by the server. + +**Corrective 402.** If the server has local channel state and rejects a paid payload (`deposit` or `voucher`) because the client's cumulative amount does not match the server's channel state, it returns `invalid_batch_settlement_evm_cumulative_amount_mismatch` with `accepts[].extra.channelState` containing the channel snapshot and `accepts[].extra.voucherState` containing `signedMaxClaimable` and `signature`. The client verifies the voucher signature before adopting `chargedCumulativeAmount` and retrying. + +```json +{ + "x402Version": 2, + "error": "invalid_batch_settlement_evm_cumulative_amount_mismatch", + "accepts": [ + { + "scheme": "batch-settlement", + "extra": { + "receiverAuthorizer": "0xReceiverAuthorizerAddress", + "withdrawDelay": 900, + "name": "USDC", + "version": "2", + "channelState": { + "channelId": "0xabc123...channelId", + "balance": "100000", + "totalClaimed": "500", + "withdrawRequestedAt": 0, + "refundNonce": "1", + "chargedCumulativeAmount": "3200" + }, + "voucherState": { + "signedMaxClaimable": "3200", + "signature": "0x...last voucher signature" + } + } + } + ] +} +``` + +--- + +## Error Codes + +| Error Code | Description | +| ------------------------------------------------------------------------ | ---------------------------------------------------------------------------- | +| `invalid_batch_settlement_evm_authorizer_address_mismatch` | Authorizer address does not match the expected receiver authorizer | +| `invalid_batch_settlement_evm_channel_busy` | Another request holds the per-channel lock; client should retry shortly | +| `invalid_batch_settlement_evm_channel_id_mismatch` | Channel config does not hash to the claimed channel ID | +| `invalid_batch_settlement_evm_channel_not_found` | No channel with positive balance for the given channel ID | +| `invalid_batch_settlement_evm_channel_state_read_failed` | Facilitator failed to read onchain channel state | +| `invalid_batch_settlement_evm_charge_exceeds_signed_cumulative` | Committing the charge would exceed the voucher's signed `maxClaimableAmount` | +| `invalid_batch_settlement_evm_claim_payload` | Claim payload is malformed | +| `invalid_batch_settlement_evm_claim_simulation_failed` | Claim simulation failed | +| `invalid_batch_settlement_evm_claim_transaction_failed` | Onchain claim transaction failed | +| `invalid_batch_settlement_evm_cumulative_amount_mismatch` | Corrective 402: client's cumulative voucher ceiling does not match the server's tracked `chargedCumulativeAmount` | +| `invalid_batch_settlement_evm_cumulative_below_claimed` | Voucher `maxClaimableAmount` violates monotonicity vs onchain `totalClaimed` (non-refund: must be greater than `totalClaimed`; refund: must not be strictly below `totalClaimed`; deposit verify: must not be strictly below `totalClaimed`) | +| `invalid_batch_settlement_evm_cumulative_exceeds_balance` | Voucher `maxClaimableAmount` exceeds effective onchain balance | +| `invalid_batch_settlement_evm_deposit_payload` | Deposit payload is malformed | +| `invalid_batch_settlement_evm_deposit_simulation_failed` | Deposit simulation failed | +| `invalid_batch_settlement_evm_deposit_transaction_failed` | Onchain deposit transaction failed | +| `invalid_batch_settlement_evm_eip2612_amount_mismatch` | EIP-2612 permit amount does not match the requested authorization | +| `invalid_batch_settlement_evm_eip2612_asset_mismatch` | EIP-2612 permit asset does not match the payment asset | +| `invalid_batch_settlement_evm_eip2612_deadline_expired` | EIP-2612 permit deadline has expired | +| `invalid_batch_settlement_evm_eip2612_invalid_format` | EIP-2612 permit segment is malformed | +| `invalid_batch_settlement_evm_eip2612_invalid_signature` | EIP-2612 permit signature is invalid | +| `invalid_batch_settlement_evm_eip2612_owner_mismatch` | EIP-2612 permit owner does not match the payer | +| `invalid_batch_settlement_evm_eip2612_spender_mismatch` | EIP-2612 permit spender does not match the expected spender | +| `invalid_batch_settlement_evm_erc20_approval_asset_mismatch` | ERC-20 approval asset does not match the payment asset | +| `invalid_batch_settlement_evm_erc20_approval_broadcast_failed` | Facilitator failed to broadcast the pre-signed ERC-20 approval transaction | +| `invalid_batch_settlement_evm_erc20_approval_from_mismatch` | ERC-20 approval signer does not match the payer | +| `invalid_batch_settlement_evm_erc20_approval_invalid_format` | ERC-20 approval segment is malformed | +| `invalid_batch_settlement_evm_erc20_approval_unavailable` | ERC-20 approval gas sponsorship is unavailable | +| `invalid_batch_settlement_evm_erc20_approval_wrong_spender` | ERC-20 approval spender is not Permit2 | +| `invalid_batch_settlement_evm_erc3009_authorization_required` | Deposit payload is missing the required `erc3009Authorization` | +| `invalid_batch_settlement_evm_insufficient_balance` | Client token balance is insufficient for the deposit | +| `invalid_batch_settlement_evm_missing_channel` | Resource server has no channel session for the payload's channel ID | +| `invalid_batch_settlement_evm_missing_eip712_domain` | Token EIP-712 domain (`name`, `version`) is missing from payment requirements | +| `invalid_batch_settlement_evm_network_mismatch` | Payment payload `accepted.network` does not match `paymentRequirements.network` on the verify request | +| `invalid_batch_settlement_evm_payload_authorization_valid_after` | ERC-3009 authorization `validAfter` is still in the future | +| `invalid_batch_settlement_evm_payload_authorization_valid_before` | ERC-3009 authorization `validBefore` has already passed | +| `invalid_batch_settlement_evm_payload_type` | Payload `type` is not valid for the current verify/settle operation | +| `invalid_batch_settlement_evm_permit2_allowance_required` | Permit2 allowance is required before deposit | +| `invalid_batch_settlement_evm_permit2_amount_mismatch` | Permit2 authorization amount does not match the requested deposit amount | +| `invalid_batch_settlement_evm_permit2_authorization_required` | Deposit payload is missing the required Permit2 authorization | +| `invalid_batch_settlement_evm_permit2_deadline_expired` | Permit2 authorization deadline has expired | +| `invalid_batch_settlement_evm_permit2_invalid_signature` | Permit2 authorization signature is invalid | +| `invalid_batch_settlement_evm_permit2_invalid_spender` | Permit2 authorization spender is not the expected spender | +| `invalid_batch_settlement_evm_receive_authorization_signature` | ERC-3009 `receiveWithAuthorization` signature is invalid | +| `invalid_batch_settlement_evm_receiver_authorizer_mismatch` | Channel receiver authorizer does not match `extra.receiverAuthorizer` | +| `invalid_batch_settlement_evm_receiver_mismatch` | Channel receiver does not match `payTo` | | +| `invalid_batch_settlement_evm_refund_amount_invalid` | Refund `amount` is non-numeric or non-positive | +| `invalid_batch_settlement_evm_refund_no_balance` | Cooperative refund requested but no refundable balance remains | +| `invalid_batch_settlement_evm_refund_payload` | Refund payload is malformed | +| `invalid_batch_settlement_evm_refund_simulation_failed` | Refund simulation failed | +| `invalid_batch_settlement_evm_refund_transaction_failed` | Onchain refund transaction failed | +| `invalid_batch_settlement_evm_rpc_read_failed` | Facilitator failed to read required onchain data | +| `invalid_batch_settlement_evm_scheme` | `scheme` is not `batch-settlement` | +| `invalid_batch_settlement_evm_settle_payload` | Settle payload is malformed | +| `invalid_batch_settlement_evm_settle_simulation_failed` | Settle simulation failed | +| `invalid_batch_settlement_evm_settle_transaction_failed` | Onchain settle transaction failed | +| `invalid_batch_settlement_evm_token_mismatch` | Channel token does not match the payment requirements asset | +| `invalid_batch_settlement_evm_transaction_reverted` | Submitted transaction reverted | +| `invalid_batch_settlement_evm_unknown_settle_action` | Settle payload requested an unknown action | +| `invalid_batch_settlement_evm_voucher_payload` | Voucher payload is malformed | +| `invalid_batch_settlement_evm_voucher_signature` | EIP-712 voucher signature does not recover to the expected signer | +| `invalid_batch_settlement_evm_wait_for_receipt_failed` | Facilitator failed while waiting for the transaction receipt | +| `invalid_batch_settlement_evm_withdraw_delay_mismatch` | Channel withdraw delay does not match `extra.withdrawDelay` | +| `invalid_batch_settlement_evm_withdraw_delay_out_of_range` | Withdraw delay is outside the 15 min - 30 day bounds | + +--- + +## Security and Trust + +1. **Capital risk and cumulative replay protection**: Clients bear risk up to the signed `maxClaimableAmount`; the receiver authorizer determines actual `totalClaimed` onchain within that bound. Over-claiming is a trust violation, not a protocol violation. The cumulative model makes nonces unnecessary. As `totalClaimed` only increases, and old vouchers are naturally superseded. + +2. **Withdrawal delay as escape hatch**: The 15 min – 30 day bounds prevent a server from indefinitely trapping client funds while giving the server a fair window to claim outstanding vouchers. Cooperative refund returns unclaimed balance immediately when the server cooperates; timed withdrawal is the unilateral fallback. Servers bear the risk of vouchers left unclaimed when `finalizeWithdraw` completes. + +3. **Cross-function replay prevention**: `Voucher`, `Refund`, and `ClaimBatch` use distinct EIP-712 type hashes so a signature for one cannot be replayed as another. Refunds additionally carry a per-channel nonce. + +4. **Voucher expiry via escrow depletion**: Vouchers carry no expiry field. A voucher remains claimable as long as `balance - totalClaimed > 0`; `finalizeWithdraw` and `refundWithSignature` close the claim window by draining available escrow. The ERC-3009 `validBefore`/`validAfter` fields bound only the deposit authorization, not the voucher. + +--- + +## Reference Implementation: `x402BatchSettlement` + +The `batch-settlement` scheme is implemented by the `x402BatchSettlement` contract alongside the `ERC3009DepositCollector` and `Permit2DepositCollector` deposit collector contracts. Each contract is deployed to a deterministic address across all supported EVM chains via CREATE2. + +| Contract | Canonical Address | +| -------- | ------- | +| `x402BatchSettlement` | `0x4020074e9dF2ce1deE5A9C1b5c3f541D02a10003` | +| `ERC3009DepositCollector` | `0x4020806089470a89826cB9fB1f4059150b550004` | +| `Permit2DepositCollector` | `0x4020425FAf3B746C082C2f942b4E5159887B0005` | + +The `x402BatchSettlement` contract uses `ReentrancyGuardTransient` (EIP-1153 transient storage) and must only be deployed on chains where that opcode is supported. +--- + +## Version History + +| Version | Date | Changes | Authors | +| ------- | ---------- | ------------- | ----------------------- | +| v1.0 | 2025-04-28 | Initial draft | @phdargen @CarsonRoscoen @ilikesymmetry | \ No newline at end of file diff --git a/specs/schemes/exact/scheme_exact.md b/specs/schemes/exact/scheme_exact.md index 96268e1f39..707ed277ca 100644 --- a/specs/schemes/exact/scheme_exact.md +++ b/specs/schemes/exact/scheme_exact.md @@ -30,4 +30,12 @@ While implementation details vary by network, facilitators MUST enforce security - Transfer correctness: `to` MUST equal `payTo` and `amount` MUST equal `requirements.amount` exactly. - Simulation verification: MUST emit events showing only the expected balance changes (recipient increase, payer decrease) for `requirements.amount`—no other balance changes allowed. -Network-specific rules are in per-network documents: `scheme_exact_svm.md` (Solana), `scheme_exact_stellar.md` (Stellar), `scheme_exact_evm.md` (EVM), `scheme_exact_sui.md` (SUI). +### TON + +- Transfer correctness: exactly 1 `jetton_transfer` with destination equal to `payTo` and amount equal to `requirements.amount` exactly. +- Signature validity: Ed25519 signature MUST verify against a public key derived from the BoC's `stateInit` (seqno == 0) or from the on-chain `get_public_key` getter (seqno > 0). Only `internal_signed` (0x73696e74) opcode is supported in the current gasless flow. +- Wallet code validity: contract code MUST match a known W5 wallet contract, using `stateInit` for `nonexist`/`uninit` wallets and on-chain code for `active` wallets. +- Replay protection: seqno MUST be strictly equal to on-chain value; duplicate `settlementBoc` submissions rejected via BoC hash dedup. +- Simulation verification: SHOULD simulate via emulation during `/verify` to confirm expected balance changes. + +Network-specific rules are in per-network documents: `scheme_exact_svm.md` (Solana), `scheme_exact_stellar.md` (Stellar), `scheme_exact_evm.md` (EVM), `scheme_exact_sui.md` (SUI), `scheme_exact_ton.md` (TON). diff --git a/specs/schemes/exact/scheme_exact_algo.md b/specs/schemes/exact/scheme_exact_algo.md index 53b2763f99..5551cf14d9 100644 --- a/specs/schemes/exact/scheme_exact_algo.md +++ b/specs/schemes/exact/scheme_exact_algo.md @@ -72,7 +72,7 @@ Full `paymentRequirements` Example: "maxTimeoutSeconds": 60, "asset": "31566704", "extra": { - "feePayer": "FACILITATORADDRESSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALQCXBZE", + "feePayer": "FACILITATORADDRESSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALQCXBZE" } } ``` @@ -111,7 +111,7 @@ Example of a USDC asset transfer with an abstracted fee (i.e paid by the facilit "x402Version": 2, "scheme": "exact", "network": "algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=", - "resource": { + "resource": { "url": "https://example.net/signup", "description": "$5 registration payment", "mimeType": "text/html" @@ -124,7 +124,7 @@ Example of a USDC asset transfer with an abstracted fee (i.e paid by the facilit "maxTimeoutSeconds": 60, "asset": "31566704", "extra": { - "feePayer": "FACILITATORADDRESSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALQCXBZE", + "feePayer": "FACILITATORADDRESSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAALQCXBZE" } }, "extensions": {}, @@ -141,11 +141,12 @@ Example of a USDC asset transfer with an abstracted fee (i.e paid by the facilit ## `PAYMENT-RESPONSE` Header -Upon a successful settlement, the `PAYMENT-RESPONSE` **MUST** return the transaction ID of the `paymentGroup[paymentIndex]` transaction. This identifies the specific asset transfer transaction to the `payTo` address for the `maxAmountRequired`, and can be used to identify the transaction on the network. +Upon a successful settlement, the `PAYMENT-RESPONSE` **MUST** return the transaction ID of the `paymentGroup[paymentIndex]` transaction. This identifies the specific asset transfer transaction to the `payTo` address for the `amount`, and can be used to identify the transaction on the network. Should the settlement fail, the transaction ID **SHOULD** be returned, but since failed transactions are not committed to the network, it might not be visible on the chain. ### Full `PAYMENT-RESPONSE` header example: + ```json { "success": true, @@ -160,17 +161,21 @@ Should the settlement fail, the transaction ID **SHOULD** be returned, but since Steps to verify a payment for the `exact` scheme on Algorand: -1. Check the `paymentGroup` contains 16 or fewer elements. -2. Decode all transactions from the `paymentGroup`. -3. Locate the `paymentGroup[paymentIndex]` transaction from the `Payment Payload`. - 1. Check the `aamt` (asset amount) matches `maxAmountRequired` from the `Payment Requirements`. - 2. Check the `arcv` (asset receiver) matches `payTo` from the `Payment Requirements`. -4. Locate all transactions where for `snd` (sender) is the `Facilitator`s Algorand address. - 1. Check the `type` (transaction type) is `pay`. - 2. Check the following fields are omitted: `close`, `rekey`, `amt`. - 3. Check the `fee` (Fee) is a reasonable amount. - 4. Sign the transaction. -5. Evaluate the payment group against an Algorand node's `simulate` endpoint to ensure the transactions would succeed. +1. Validate `x402Version` is a supported version (currently `2`). +2. Validate `scheme` is `"exact"` in both the `PAYMENT-SIGNATURE` payload `accepted` field and the `paymentRequirements`. +3. Validate `network` matches between the `PAYMENT-SIGNATURE` payload `accepted` field and the `paymentRequirements`. +4. Check the `paymentGroup` contains 16 or fewer elements. +5. Decode all transactions from the `paymentGroup`. +6. Locate the `paymentGroup[paymentIndex]` transaction from the `Payment Payload`. + 1. Check the `aamt` (asset amount) matches `amount` from the `Payment Requirements`. + 2. Check the `arcv` (asset receiver) matches `payTo` from the `Payment Requirements`. + 3. Check the `xaid` (asset ID) matches `asset` from the `Payment Requirements`. +7. Locate all transactions where `snd` (sender) is the `Facilitator`s Algorand address. + 1. Check the `type` (transaction type) is `pay`. + 2. Check the following fields are omitted: `close`, `rekey`, `amt`. + 3. Check the `fee` (Fee) is a reasonable amount. + 4. Sign the transaction. +8. Evaluate the payment group against an Algorand node's `simulate` endpoint to ensure the transactions would succeed. ## Settlement diff --git a/specs/schemes/exact/scheme_exact_cardano.md b/specs/schemes/exact/scheme_exact_cardano.md new file mode 100644 index 0000000000..77ca60e997 --- /dev/null +++ b/specs/schemes/exact/scheme_exact_cardano.md @@ -0,0 +1,363 @@ +# Scheme: exact on Cardano + +## Summary + +This document specifies the `exact` payment scheme for the x402 protocol on Cardano. This scheme facilitates payments of Cardano Native Tokens. + +It offers different assetTransferMethods to do x402 interactions: + +1. Doing **Address-To-Address** Payments, similar to the regular x402 specifications on other chains. + +2. Using the **Masumi Smart Protocol**, which offers additional refund mechanics & decision logging mechanisms in a decentralised way. + +3. Performing payments to scripts using parameters that can be applied to scripts while transaction building. +## Protocol Flow + +```mermaid +sequenceDiagram + participant Client as Client/Agent + participant Server as Server + participant Facilitator as Facilitator + participant Cardano as Cardano Blockchain + + %% Initial Request + Client->>Server: 1. HTTP GET /api + + %% Payment Required Response + Server->>Client: 2. HTTP 402 and Payment Details + + %% Client Prepares Payment + Note over Client: 3. Client selects payment option,
creates and
signs a Transaction + + %% Request with Payment + Client->>Server: 4. HTTP GET /api
Header: PAYMENT-SIGNATURE (signed transaction) + Note right of Client: Retries with payment header + + %% Server Verification + alt Server Verification + Server->>Server: 5. Verify transaction locally + else Remote Verification (via Facilitator) + Server->>Facilitator: 5. POST /verify
(Payment Payload + Requirements) + Note right of Facilitator: Facilitator validates:
- Payment amount
- Correct recipient
- Nonce in Transaction + end + + %% Server Verification + alt Server Submission + Server->>Cardano: 6a. Submit signed transaction + Note right of Cardano: Transaction included in mempool or block + Cardano-->>Server: 6b. Transaction hash + confirmation + else Remote Submission (via Facilitator) + Server->>Facilitator: 6a. POST /settle
(Payment details) + Facilitator->>Cardano: 6b. Submit signed transaction + Note right of Cardano: Transaction included in mempool or block + Cardano-->>Facilitator: 6c. Transaction hash + confirmation + Facilitator->>Server: 6d. Settlement Response
(txHash, status) + end + + Note right of Server: 7. Receives transaction hash and status + + %% Final Response + Server->>Client: 8. HTTP 200 OK + Resource
Header: PAYMENT-RESPONSE + Note left of Server: Returns requested resource
with transaction confirmation:
- transaction: "2f9a7b3c..."
- network: "cardano:mainnet"
- success: true +``` + +The protocol flow for `exact` on Cardano is client-driven. + +1. **Client** makes an HTTP request to a **Resource Server**. + +2. **Resource Server** responds with a `402 Payment Required` status, detailing the payment information: + - If using the Masumi Protocol, the `extra` field will contain additional information required to build a Masumi Smart Contract interaction. + - If using Address-To-Address payments, the `payTo` field will contain the address to which the payment must be sent. + - If using Script payments, the `extra` field will contain parameters to be applied to scripts during transaction building. + +3. **Client** constructs the transaction body, signs it, and returns it to the **Resource Server** via the `PAYMENT-SIGNATURE` header. + +4. **Resource Server** verifies the transaction is valid: + - **Local verification**: The server validates the transaction structure, amount, and recipient address directly. + - **Remote verification**: The server forwards the `PAYMENT-SIGNATURE` header and `paymentRequirements` to a **Facilitator's** `/verify` endpoint to check if the transaction is valid. + +5. After successful verification, the signed transaction is submitted to the Cardano blockchain: + - **Server submission**: The **Resource Server** submits the transaction directly to the Cardano blockchain. + - **Facilitator submission**: The **Resource Server** sends the transaction to the **Facilitator's** `/settle` endpoint, which then submits it to the blockchain. + +6. The Cardano blockchain includes the transaction in the mempool or a block and returns the transaction hash and confirmation status. + +7. **Resource Server** receives the transaction hash and status: + - If submitted via the **Facilitator**, it receives a settlement response containing the `txHash` and `status`. + - Cardano uses Ouroboros Praos, which has probabilistic finality. A transaction that appears in the mempool or even in a recent block can be rolled back. Granting access upon mempool inclusion (`status: "mempool"`) is therefore **strongly discouraged** and SHOULD NOT be used for any resource with real economic value. Servers that choose to accept mempool status MUST document this risk and accept full liability for rolled-back transactions. + +8. **Resource Server** grants the **Client** access to the requested resource, returning an HTTP 200 OK response with an `PAYMENT-RESPONSE` header containing: + - `txHash`: The Cardano transaction hash + - `network`: The Cardano network (e.g., `cardano:mainnet`) + - `status`: The transaction status (e.g., `confirmed` or `mempool`) + +### `PaymentRequirementsResponse` + +#### Default Schema + +When the Resource Server responds with a `402 Payment Required`, the body of the response contains the payment requirements in the following schema: + +```js +{ + "x402Version": 2, + "error": "PAYMENT-SIGNATURE header is required", + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepts": [ + { + "scheme": "exact", + "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets + "amount": "10000", // 1 USDM = 1000000000 + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' + "payTo": "addr1...", + "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed + "extra": { + // In case of default address-to-address payments, this may be empty or contain additional metadata + } + } + ] +} +``` + +#### Masumi assetTransferMethod Schema + +When the Resource Server requires payment via the Masumi Smart Protocol, the `extra` field in the `PaymentRequirementsResponse` contains additional fields required for Masumi interactions. + +```js +{ + "x402Version": 2, + "error": "PAYMENT-SIGNATURE header is required", + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepts": [ + { + "scheme": "exact", + "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets + "amount": "10000", // 1 USDM = 1000000000 + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' + "payTo": "addr1...", + "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed + "extra": { + "assetTransferMethod": "masumi", // optional, can be "default" | "masumi" | "script" + // If the masumi assetTransferMethod is used, make sure to include all masumi related fields + "identifierFromPurchaser": "aabbaabb11221122aabb", + "sellerVkey": "sdasdqweqwewewewqe", + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260", + "agentIdentifier": "agent_identifier", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" + // Additional fields for masumi or script assetTransferMethods can be added here + } + } + ] +} +``` + +#### Script assetTransferMethod Schema + +When the Resource Server requires payment to a script, the `extra` field in the `PaymentRequirementsResponse` contains additional fields required for script interactions. + +```js +{ + "x402Version": 2, + "error": "PAYMENT-SIGNATURE header is required", + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepts": [ + { + "scheme": "exact", + "network": "cardano:mainnet", // cardano:preprod or cardano:preview for public testnets + "amount": "10000", // 1 USDM = 1000000000 + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", // ${policyId}.${assetName} The policy id in this example is the USDM policy id on Cardano Mainnet - use 16a55b2a349361ff88c03788f93e1e966e5d689605d044fef722ddde for USDM on Preprod. The asset name is the hex representation of '(333) USDM' + "payTo": "addr1...", // In case of script payments, this is the script address (the address should match the script provided in extra after applying parameters. In case of additional parameters provided, the client needs to pass the additional parameters to the server in the PAYMENT-SIGNATURE header, so that the server can reconstruct the script address and verify the payment) + "maxTimeoutSeconds": 600, // Has to be set to a higher amount of time because of the Cardano Network speed + "extra": { + "assetTransferMethod": "script", // optional, can be "default" | "masumi" | "script" + // If the script assetTransferMethod is used, make sure to include all script related fields + "scriptHash": "script_hash_here", // If the script is already on-chain, provide its hash and the client can resolve the full script + "script": { + // Optional full script object if not on-chain yet + "type": "plutusV3", + "code": "", + }, + "parameters": { + "param1": {"value": "Hello World", "type": "bytes"}, + "param2": {"value": 42, "type": "bigint"} + // Script-specific parameters required for transaction building + } + // Additional fields for script assetTransferMethods can be added here + } + } + ] +} +``` + +### `PAYMENT-SIGNATURE` Header Payload + +The PAYMENT-SIGNATURE header is base64-encoded and sent in the client's request to the resource server when paying for a resource. + +The payload field of the PAYMENT-SIGNATURE header must contain the following fields: + +transaction: The signed Cardano transaction (Base64 encoded). +Example: + +```js +{ + "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" +} +``` + +Full PAYMENT-SIGNATURE header: + +```js +{ + "x402Version": 2, + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepted": { + "scheme": "exact", + "network": "cardano:mainnet", + "amount": "10000", + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", + "payTo": "addr1...", + "maxTimeoutSeconds": 600, + "extra": { + // In case of default address-to-address payments, this may be empty or contain additional metadata + } + }, + "payload": { + "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" + "nonce": "662cbf645fcd8914eb89115b83970a950493dd2fbaf39dea3b96e8cbdc132939#0" + } +} +``` + +Expanded Schema based on assetTransferMethods: + +#### Masumi assetTransferMethod + +```js +{ + "x402Version": 2, + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepted": { + "scheme": "exact", + "network": "cardano:mainnet", + "amount": "10000", + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", + "payTo": "addr1...", + "maxTimeoutSeconds": 600, + "extra": { + "assetTransferMethod": "masumi", + "identifierFromPurchaser": "aabbaabb11221122aabb", + "sellerVkey": "sdasdqweqwewewewqe", + "paymentType": "Web3CardanoV1", + "blockchainIdentifier": "blockchain_identifier", + "payByTime": "1713626260", + "submitResultTime": "1713636260", + "unlockTime": "1713636260", + "externalDisputeUnlockTime": "1713636260", + "agentIdentifier": "agent_identifier", + "inputHash": "9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08" + } + }, + "payload": { + "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" + "nonce": "662cbf645fcd8914eb89115b83970a950493dd2fbaf39dea3b96e8cbdc132939#0" + } +} +``` + +#### Script assetTransferMethod + +```js +{ + "x402Version": 2, + "resource": { + "url": "https://api.example.com/premium-data", + "description": "Access to premium market data", + "mimeType": "application/json" + }, + "accepted": { + "scheme": "exact", + "network": "cardano:mainnet", + "amount": "10000", + "asset": "c48cbb3d5e57ed56e276bc45f99ab39abe94e6cd7ac39fb402da47ad.0014df105553444d", + "payTo": "addr1...", // script address + "maxTimeoutSeconds": 600, + "extra": { + "assetTransferMethod": "script", + "scriptHash": "script_hash_here", + "script": { + "type": "plutusV3", + "code": "" + }, + "parameters": { + "param1": {"value": "Hello World", "type": "bytes"}, + "param2": {"value": 42, "type": "bigint"} + } + } + }, + "payload": { + "transaction": "AAAIAQDi1HwjSnS6M+WGvD73iEyUY2FRKNj0MlRp7+3SHZM3xCvMdB0AAAAAIFRgPKOstGBLCnbcyGoOXugUYAWwVzNrpMjPCzXK4KQWAQCMoE29VLGwftex8rhIlOuFLFNfxLIJlHqGXoXA8hx6l+LMdB0AAAAAIHbPucTRIEWgO6lzqukswPZ6i72IHEKK5LyM1l9HJNZNAQBthSeHDVK8Xr5/zp3JMZPLtG5uAoVgedTA4pEnp+h8qUlUzRwAAAAAIACH0swYW/QfGCFczGnjAVPHPqZrQE5vfvJr36i6KVEFAQAC7W4K5vCwB+nprjxcNlLiOQ7SIIfyCZjmj2qSis2iTsCuzBwAAAAAIAkSUkXOoeq52GNdhwpbs+jZqqrqPdmiN3oPw5EzDIanAQAIyFNGWD6OxiFIyXSxrNEcFG0npm+nImk6InUssXb1EZgx1hwAAAAAILhsjmMKyM0n75Cd7z6ufH2LNhOMibFOGhNlLgV5RFuEAQC+Mh4kGkLwrw/11729oUQnt3xOmOreE6PcnuN6M68ZBcCuzBwAAAAAIO2PQhSSqSAawCbRr005lfjBgFOqIHo4zb2GcQ/WCxAlAAgA+QKVAAAAAAAgjiAHD0X4HNSdVPpJtf2E6W2uRc8kbvCHYkgEQ1B+w1MDAwEAAAUBAQABAgABAwABBAABBQACAQAAAQEGAAEBAgEAAQcAHrfFfj8r0Pxsudz/0UPqlX5NmPgFw1hzP3be4GZ/4LEB5XXrONxGw0qOUsq3yNKeUhOCOgCIwaa4pswKaer66EKqPGwdAAAAACBrOIN4poutFUmHfB6FbFJu8GgXoPPTGQWREqFpPfvO1B63xX4/K9D8bLnc/9FD6pV+TZj4BcNYcz923uBmf+Cx7gIAAAAAAABg4xYAAAAAAAA=" + "nonce": "662cbf645fcd8914eb89115b83970a950493dd2fbaf39dea3b96e8cbdc132939#0" + } +} +``` + +### Facilitator Verification Rules + +A facilitator MUST enforce all of the following rules before accepting a payment as valid. Any failure MUST result in a rejection. + +1. **Network Validation**: The transaction MUST be destined for the correct Cardano network (mainnet, preprod, or preview) as declared in `PaymentRequirements.network`. The facilitator MUST reject transactions built for a different network. + +2. **Recipient Verification**: At least one transaction output MUST send funds to the address specified in `PaymentRequirements.payTo`. The facilitator MUST NOT accept transactions where the recipient address differs from `payTo`. + +3. **Amount Verification**: The output sent to `payTo` MUST contain a value greater than or equal to the amount declared in `PaymentRequirements.amount` for the asset identified by `PaymentRequirements.asset`. The facilitator MUST verify both the policy ID and the asset name match exactly. + +4. **Asset Verification**: The asset unit in the transaction MUST exactly match `PaymentRequirements.asset` (format: `${policyId}.${assetNameHex}`). The facilitator MUST NOT accept a different asset, even one of equal market value. + +5. **Nonce / Replay Prevention**: The `payload.nonce` MUST be a valid UTXO reference (`txHash#index`) that is included as an input in the transaction. The facilitator MUST verify that this UTXO exists in the current on-chain UTXO set and has not been spent. This ensures uniqueness and prevents replay attacks. + +6. **TTL / Expiry Check**: The transaction's TTL (time-to-live slot) MUST not have already passed at the time of verification. The facilitator MUST reject transactions whose TTL is in the past. The TTL SHOULD be consistent with `PaymentRequirements.maxTimeoutSeconds`. + +### `PAYMENT-RESPONSE` Header Payload + +The `PAYMENT-RESPONSE` header is base64-encoded and returned to the client by the resource server. + +Once decoded, the `PAYMENT-RESPONSE` is a JSON string with the following properties: + +Schema: + +```js +{ + "success": true, // true or false + "network": "cardano:mainnet", + "transaction": "2f9a7b3c..." // Transaction hash of the payment if successful + "extensions": { + "status": "confirmed", // "confirmed" is the recommended value; "mempool" is permitted but strongly discouraged — see settlement warning above + } + // Optional error field in case of failure + "errorReason": "Utxo not found in utxo set" // Example error reason +} +``` diff --git a/specs/schemes/exact/scheme_exact_keeta.md b/specs/schemes/exact/scheme_exact_keeta.md new file mode 100644 index 0000000000..ff7eaaa286 --- /dev/null +++ b/specs/schemes/exact/scheme_exact_keeta.md @@ -0,0 +1,197 @@ +# Scheme: `exact` on `keeta` + +## Summary + +The `exact` scheme on Keeta transfers a specific amount of a token (such as USDC) on the Keeta network from the payer to the resource server. +The payer constructs a signed block containing a `SEND` operation to fulfill the `paymentRequirements`. +The facilitator sponsors network fees and cannot alter the signed block to redirect funds to any other address. + +**Version Support:** This specification supports x402 v2 protocol only. + +> [!NOTE] +> Non-sponsored fee flows (where the client pays network fees) are currently not supported. See [Non-Sponsored Fee Flows](#non-sponsored-fee-flows) for details. + +## Protocol + +```mermaid +sequenceDiagram + participant Client; + participant Server; + participant Facilitator; + participant Blockchain; + + Client->>Server: GET /api + Server-->>Client: 402 - Payment Required
with extra + Client->>Client: Create & sign block + Client->>Server: GET /api
with PaymentPayload + Server->>Facilitator: POST /verify + Facilitator->>Facilitator: Parse block,
verify signature,
verify requirements + Facilitator-->>Server: VerifyResponse + Server->>Facilitator: POST /settle + Facilitator->>Facilitator: Create & sign fee block + Facilitator->>Blockchain: Collect votes and
submit vote staple + Blockchain-->>Facilitator: Confirmation + Facilitator-->>Server: SettlementResponse with
Block Hash + Server-->>Client: Requested Content +``` + +1. **Client** makes a request to a **Resource Server**. +2. **Resource Server** responds with a payment required signal containing `PaymentRequired`. +3. **Client** creates and signs a block with a `SEND` operation to transfer the specified amount of the token to the recipient. If the `extra.external` field is set, the client sets the `external` field to the specified value in the `SEND` operation. The block is **not** published to the network. +4. **Client** serializes the signed block into its ASN.1 DER representation and encodes it as a Base64 string. +5. **Client** sends a new request to the **Resource Server** with the `PaymentPayload` containing the Base64-encoded signed block. +6. **Resource Server** receives the request and forwards the `PaymentPayload` and `PaymentRequirements` to a **Facilitator's** `/verify` endpoint. +7. **Facilitator** decodes and parses the signed block and verifies the block according to the [verification rules](#verification). +8. **Facilitator** returns a `VerifyResponse` to the **Resource Server**. +9. **Resource Server**, upon successful verification, forwards the payload to the facilitator's `/settle` endpoint. +10. **Facilitator** verifies the block according to the [settlement rules](#settlement). It computes and signs a fee block, requests votes for the blocks from the network's representatives and publishes the combined vote staple to the network. +11. Upon successful on-chain settlement, the **Facilitator** responds with a `SettlementResponse` including the hash of the client's payment block to the **Resource Server**. +12. **Resource Server** grants the **Client** access to the resource in its response. + +## Payment header payload + +### `PaymentRequirements` for `exact` + +In addition to the standard x402 `PaymentRequirements` fields, the `exact` scheme on Keeta supports an optional `extra` field: + +```json +{ + "scheme": "exact", + "network": "keeta:21378", + "amount": "1000000", + "asset": "keeta_amnkge74xitii5dsobstldatv3irmyimujfjotftx7plaaaseam4bntb7wnna", + "payTo": "keeta_aabcdefghijklmnopqrstuvwxyz234567abcdefghijklmnopqrstuvwxyz2345", + "maxTimeoutSeconds": 60, + "extra": { + "external": "0123456789abcdef0123456789abcdef" + } +} +``` + +**Field Descriptions:** + +- `scheme`: Always `"exact"` for this scheme +- `network`: CAIP-2 network identifier, e.g. `keeta:21378` (mainnet) or `keeta:1413829460` (testnet) +- `amount`: The exact amount to transfer in atomic units (e.g., `"1000000"` = 1 USDC, since USDC has 6 decimals) +- `asset`: The Base32-encoded identifier public key of the token (e.g., USDC on Keeta mainnet: `keeta_amnkge74xitii5dsobstldatv3irmyimujfjotftx7plaaaseam4bntb7wnna`) +- `payTo`: The Base32-encoded public key of the recipient account +- `maxTimeoutSeconds`: Maximum time in seconds before the payment expires +- `extra.external`: **Optional**. `external` reference the client should set in the `SEND` operation to the `payTo` address (see [Keeta docs](https://static.network.keeta.com/docs/classes/KeetaNetSDK.Referenced.BlockOperationSEND.html#external)). This is especially useful for resource servers to automatically off-ramp received payments to a bank account or bridge them to a different chain via asset movement anchors. + +### PaymentPayload `payload` Field + +The `payload` field of the `PaymentPayload` must contain the following field: + +- `block`: Base64 encoded ASN.1 DER-serialized signed block which contains a `SEND` operation to pay the requested amount of a token. + +Example `payload`: + +```json +{ + "block":"MIH6AgEAAgRURVNUBQAYEzIwMjYwMTIzMjIyNjUwLjczMFoEIgAC2Ynov21UzUtAf00BzdTbpJCJl1DuLlX4mAiKHx57uQAFAAQgmArjQZymslS0VvBMCNyicKkDyDUqoMQIfU8nl82JcvAwTqBMMEoEIgADEFUSmawYqevhKALRFALRYRGGrXR20+JHvI/5oE8qz00CAQEEIQNwgpeV3wC60ZR4DMHh0sDJDXFi4Mhesi9jMHvtPqp1SgRAdoNTNrjabm2gJBT2yAtVniYlpU4AzWZxb6b7rfMSw/d+C09d5qI6NmS1U2o+cOt+yJLEYE2qCEsKBYdHrgkwNA==" +} +``` + +Full `PaymentPayload` object: + +```json +{ + "x402Version": 2, + "resource": { + "url": "https://example.com/weather", + "description": "Access to protected content", + "mimeType": "application/json" + }, + "accepted": { + "scheme": "exact", + "network": "keeta:1413829460", + "amount": "1000000000", + "asset": "keeta_anyiff4v34alvumupagmdyosydeq24lc4def5mrpmmyhx3j6vj2uucckeqn52", + "payTo": "keeta_aabravistgwbrkpl4euafuiualiwcemgvv2hnu7ci66i76naj4vm6tmeahmzria", + "maxTimeoutSeconds": 60 + }, + "payload": { + "block":"MIH6AgEAAgRURVNUBQAYEzIwMjYwMTIzMjIyNjUwLjczMFoEIgAC2Ynov21UzUtAf00BzdTbpJCJl1DuLlX4mAiKHx57uQAFAAQgmArjQZymslS0VvBMCNyicKkDyDUqoMQIfU8nl82JcvAwTqBMMEoEIgADEFUSmawYqevhKALRFALRYRGGrXR20+JHvI/5oE8qz00CAQEEIQNwgpeV3wC60ZR4DMHh0sDJDXFi4Mhesi9jMHvtPqp1SgRAdoNTNrjabm2gJBT2yAtVniYlpU4AzWZxb6b7rfMSw/d+C09d5qI6NmS1U2o+cOt+yJLEYE2qCEsKBYdHrgkwNA==" + } +} +``` + +## Verification + +Steps to verify a payment for the `exact` scheme on Keeta: + +1. Verify `x402Version` is `2`. +2. Verify the `scheme` is `exact`. +3. Verify the network matches the agreed upon chain (CAIP-2 format: `keeta:`). +4. Decode and deserialize the Base64 and ASN.1 DER-encoded `payload.block` and: + 1. Verify that the signature is valid. + 2. Verify that the `network` matches the agreed upon Keeta `network_id`. + 3. Verify that the block contains exactly one operation. + 4. Verify that the operation is a `SEND` operation to pay the server for which: + 1. The `token` matches the `requirements.asset`. + 2. The `amount` matches the `requirements.amount`. + 3. The `to` matches the `requirements.payTo`. + 4. The `external` matches the `extra.external` if set. + 5. Simulate the transaction by verifying that: + 1. The `block.account` balance of `requirements.asset` is at least `requirements.amount`. + 2. The head block hash of the `block.account` equals the `block.previous` hash. + 3. The `block.signer` is allowed to send on behalf of the `block.account`, e.g. because `block.signer` is the same or has the permission such as `OWNER` or `SEND_ON_BEHALF`. + +## Settlement + +Settlement is performed through the facilitator: + +1. **Facilitator** receives the `block`. +2. **Facilitator** computes and signs a fee block. +3. **Facilitator** transmits the blocks to the network by requesting the votes from the representatives and publishing the combined vote staple to the network. +4. **Facilitator** sends the `SettlementResponse` to the **Resource Server**. + +### `SettlementResponse` + +The `SettlementResponse` for the exact scheme on Keeta: + +```json +{ + "success": true, + "transaction": "426C2D7401BB49D78F1C1EA84BF4AD7EBE294C4758037507AADD12CC0AB62910", + "network": "keeta:1413829460", + "payer": "keeta_aabntcpix5wvjtklib7u2aon2tn2jeejs5io4lsv7cmarcq7dz53sahhsuapica" +} +``` + +**Field Descriptions:** + +- `transaction`: The hash of the client's block which contains the payment to the server. +- `network`: CAIP-2 network identifier, e.g. `keeta:21378` (mainnet) or `keeta:1413829460` (testnet) +- `payer`: The Base32-encoded public key of the account that paid the server + +## Appendix + +### Transaction Serialization + +The primary data structure in Keeta is a directed acyclic graph where each account basically has their own blockchain (see [Data Structure](https://docs.keeta.com/architecture/data-structure) for more information). +Since the facilitator handles the fee payment, they have to serialize the transactions they settle on the chain to avoid any locks from trying to submit multiple vote staples at the same time. + +### Multiple Facilitator Accounts + +To avoid congestion from [Transaction Serialization](#transaction-serialization) on a single account of the facilitator they may use multiple fee payer accounts to settle transactions. +The facilitator may load-balance on a per-request basis to decide which account to use to settle each transaction. + +### Non-Sponsored Fee Flows + +Non-sponsored fee flows, where the client pays network fees rather than the facilitator, are currently not supported. +The following challenges make this difficult to implement in practice: + +- **Variable fee tokens**: Network representatives may each independently require a different token for their fees, making it unclear in what token the client should pay the fees to the facilitator. Since the facilitator may also use a different set of representatives than what the client would use, the client can also not request vote quotes from the representatives to determine the required fees before sending their block (unless they would include their vote quotes which could run into payload size limitations, see below). +- **Variable fee amounts**: The fees required by representatives are not necessarily static (and may depend on the specific block the client sends) and thus cannot simply be determined at startup or propagated via the facilitator's `/supported` endpoint. + +We have found various possible solutions to these challenges, but each of them has its disadvantages, which is why we have rejected them for now: + +- **Additional fee-quote endpoint**: The client could query the facilitator on an additional endpoint (e.g., `/fee-quote`) to obtain exactly the fees the facilitator currently requires. However, this would require the client to trust the facilitator to not charge overly high fees and introduces a non-standard, additional facilitator endpoint beyond what x402 currently specifies. +- **Send vote quotes**: Alternatively, clients could request vote quotes for their blocks directly from the network representatives and include their block, fee block, and vote quotes in the `PaymentPayload`. However, as more representatives are added to the network, the required number of vote quotes grows, and the combined payload could exceed the 8 KB HTTP header size limit commonly enforced by default by reverse proxies such as nginx. + +### Future Improvements + +As the Keeta network develops and supports more features in the future, this specification should be improved to support these natively, including: + +- **Temporary approvals**: It may become possible for clients to sign temporary / one-time spending approvals. Then, instead of sending a specific payment block, they could send the approval instead to allow resource servers / facilitators to redeem these, similar to how the `eip3009` asset transfer in the EVM scheme uses the `transferWithAuthorization` function. This may then also include the payment for the network fees and enable non-sponsored fee flows. diff --git a/specs/schemes/exact/scheme_exact_ton.md b/specs/schemes/exact/scheme_exact_ton.md new file mode 100644 index 0000000000..73b8a5e2f9 --- /dev/null +++ b/specs/schemes/exact/scheme_exact_ton.md @@ -0,0 +1,292 @@ +# Scheme: `exact` on `TON` + +## Versions supported + +- ❌ `v1` +- ✅ `v2` + +## Supported Networks + +This spec uses [CAIP-2](https://namespaces.chainagnostic.org/tvm/caip2) identifiers from the TVM namespace: + +- `tvm:-239` — TON mainnet +- `tvm:-3` — TON testnet + +> [!NOTE] +> **Scope:** This spec covers [TEP-74](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md)-compliant Jetton transfers using **W5 wallets** (v5r1) with gasless relay (`areFeesSponsored: true`). Non-gasless flows (`external_signed`, native TON transfers) are planned for a follow-up spec extension. +> +> For clients, only W5 wallets in account states `active` and `uninit`/`nonexist` are supported. `frozen` accounts are not supported. In practice this is not expected to constrain implementations because `frozen` W5 accounts are not expected to appear in the next 5 years. + +## Summary + +The `exact` scheme on TON transfers a specific amount of a [TEP-74](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md) Jetton from the client to the resource server using a W5 (v5r1) wallet signed message. + +The facilitator IS the relay. It sponsors gas (~0.013 TON per transaction) by wrapping the client-signed message in an internal TON message from its own funded wallet. The client resolves signing data (seqno, Jetton wallet address) via a TON RPC endpoint, signs locally, and sends the result. The facilitator cannot modify the destination or amount; the client controls payment intent through Ed25519 signature. The facilitator also attaches enough TON to the relay message to cover payer-wallet execution of the relayed message and to fund the client-signed inner transfer. + +There is no relay commission. The facilitator absorbs gas costs as the cost of operating the payment network, analogous to how EVM facilitators pay gas for `transferWithAuthorization`. + +## Protocol Flow + +1. **Client** requests a protected resource from the **Resource Server**. +2. **Resource Server** responds with HTTP 402 and `PaymentRequired` data. The `accepts` array includes a TON payment option. +3. **Client** queries a TON RPC endpoint to resolve its Jetton wallet address (`get_wallet_address` on the Jetton master contract) and fetches its current wallet seqno. +4. **Client** constructs a `jetton_transfer` body ([TEP-74](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md)) and wraps it in a W5 `internal_signed` message with [sending mode 1 (`PAY_FEES_SEPARATELY`) or mode 3 (`PAY_FEES_SEPARATELY | IGNORE_ERRORS`)](https://docs.ton.org/foundations/messages/modes). The outbound internal message sent by the client's W5 wallet to the source Jetton wallet MUST be bounceable. +5. **Client** signs the message with their Ed25519 private key. +6. **Client** wraps the signed body in an internal message BoC (dest = client wallet, value = 0, with `stateInit` if the wallet account is not yet deployed, i.e. [`nonexist` or `uninit`](https://docs.ton.org/foundations/status)) and base64-encodes it. +7. **Client** sends a second request to the **Resource Server** with the `PaymentPayload`. +8. **Resource Server** forwards the payload and requirements to the **Facilitator's** `/verify` endpoint. +9. **Facilitator** deserializes the internal message BoC, derives the sender address and public key, verifies the Ed25519 signature, validates payment intent (amount, destination, asset), and checks replay protection (seqno, validUntil, BoC hash). +10. **Facilitator** returns a `VerifyResponse`. Verification is **REQUIRED** — it protects the resource server from doing unnecessary work for invalid payloads. +11. **Resource Server** calls the **Facilitator's** `/settle` endpoint. The facilitator MUST perform full verification independently and MUST NOT assume prior `/verify` results. +12. **Facilitator** settles the payment: it extracts the signed body from the internal message BoC, wraps it in a new internal message from its own wallet, attaching TON for gas (estimated via emulation), then signs and broadcasts it. The user's W5 wallet verifies the signature and executes the Jetton transfer. +13. **Resource Server** returns the final response to the **Client**. + +## `PaymentRequirements` for `exact` + +In addition to standard x402 fields, TON `exact` uses `extra` fields: + +```json +{ + "scheme": "exact", + "network": "tvm:-239", + "amount": "10000", + "asset": "0:b113a994b5024a16719f69139328eb759596c38a25f59028b146fecdc3621dfe", + "payTo": "0:92433a576cbe56c4dcc86d94b497a2cf18a9baa9c8283fea28ea43eb3c25cfed", + "maxTimeoutSeconds": 300, + "extra": { + "forwardPayload": "te6cckEBAgEAkwABnYgBFpKiX...", + "forwardTonAmount": "50000000", + "responseDestination": "0:92433a576cbe56c4dcc86d94b497a2cf18a9baa9c8283fea28ea43eb3c25cfed", + "areFeesSponsored": true + } +} +``` + +**Field Definitions:** + +- `asset`: [TEP-74](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md) Jetton master contract address (raw format `workchain:hex`). +- `payTo`: Recipient TON address (raw format). +- `amount`: Atomic token amount (6 decimals for USDT, so `10000` = $0.01). Decimals can be queried via `get_jetton_data` on the Jetton master contract. +- `extra.responseDestination` (optional): TON address used as `response_destination` in the `jetton_transfer` body. If omitted, the effective value is `addr_none` (i.e. 2 zero bits). +- `extra.forwardPayload` (optional): Base64-encoded cell used as the jetton transfer forward payload (see [TEP-74](https://github.com/ton-blockchain/TEPs/blob/63fc78718dd9930f3e106954ebec743c3ad07993/text/0074-jettons-standard.md?plain=1#L68)). If omitted, the effective value is a zero-bit cell. +- `extra.forwardTonAmount` (optional): the amount of nanotons to be attached to the jetton transfer (see [TEP-74](https://github.com/ton-blockchain/TEPs/blob/63fc78718dd9930f3e106954ebec743c3ad07993/text/0074-jettons-standard.md?plain=1#L68)). If omitted, the effective value is `"0"`. +- `extra.areFeesSponsored`: Whether the facilitator sponsors gas fees. Currently always `true`; a non-sponsored flow will be added in a follow-up spec. + +These `extra` fields exist for TON-specific payment semantics: `forwardPayload` lets the payment carry application-level metadata (for example an invoice ID, analogous to a memo in other networks), `forwardTonAmount` enables the recipient to route the payment into custom contracts that require TON to execute logic on receipt, and `responseDestination` specifies where unused TON is returned as Jetton-transfer `excesses` as the exact network fee cannot be known in advance. + +## PaymentPayload `payload` Field + +The payload contains only the signed settlement BoC and the asset identifier. All other fields (sender address, amount, destination, public key, `responseDestination`, `forwardPayload`, and `forwardTonAmount`) are derived from the BoC by the facilitator: + +```json +{ + "settlementBoc": "te6cckEBAgEAkwABnYgBFpKiX...", + "asset": "0:b113a994b5024a16719f69139328eb759596c38a25f59028b146fecdc3621dfe" +} +``` + +Full `PaymentPayload` object: + +```json +{ + "x402Version": 2, + "resource": { + "url": "https://api.example.com/wallet-analytics", + "description": "TON wallet analytics", + "mimeType": "application/json" + }, + "accepted": { + "scheme": "exact", + "network": "tvm:-239", + "amount": "10000", + "asset": "0:b113a994b5024a16719f69139328eb759596c38a25f59028b146fecdc3621dfe", + "payTo": "0:92433a576cbe56c4dcc86d94b497a2cf18a9baa9c8283fea28ea43eb3c25cfed", + "maxTimeoutSeconds": 300, + "extra": { + "forwardPayload": "te6cckEBAgEAkwABnYgBFpKiX...", + "forwardTonAmount": "50000000", + "responseDestination": "0:92433a576cbe56c4dcc86d94b497a2cf18a9baa9c8283fea28ea43eb3c25cfed", + "areFeesSponsored": true + } + }, + "payload": { + "settlementBoc": "te6cckEBAgEAkwABnYgBFpKiX...", + "asset": "0:b113a994b5024a16719f69139328eb759596c38a25f59028b146fecdc3621dfe" + } +} +``` + +**Field Definitions:** + +- `settlementBoc`: Base64-encoded TON internal message BoC. The internal message carries the signed W5 body as the `body` field, the client's wallet as `dest`, and optionally a `stateInit` for first-time wallet deployment. The `settlementBoc` wrapper itself does not need to be bounceable. The outbound internal message sent by the client's W5 wallet to the source Jetton wallet MUST be bounceable. +- `asset`: Jetton master contract address in raw format. Kept as an explicit field for future multi-asset protocol extensions. + +The facilitator derives the following from the BoC: + +- **Sender address**: the `dest` field of the internal message (the client's wallet). +- **Public key**: from the `stateInit` data cell (if present) or via the on-chain `get_public_key` getter. +- **walletId, amount, destination, responseDestination, validUntil, seqno, forwardTonAmount, and forwardPayload**: from the W5 signed body and its actions. If `responseDestination`, `forwardTonAmount`, or `forwardPayload` are omitted from `accepted.extra`, the facilitator compares against the effective defaults (`addr_none`, `"0"`, and zero-bit payload, respectively). + +## `SettlementResponse` + +```json +{ + "success": true, + "transaction": "ba96f62d4ea651a21da4282809f2541ea42481ca35018129f29b406ef3fe36c0", + "network": "tvm:-239", + "payer": "0:1da21a6e33ef22840029ae77900f61ba820b94e813a3b7bef4e3ea471007645f" +} +``` + +- `transaction`: Transaction hash (64-character hex string). +- `payer`: The address of the client who signed the payment (not the facilitator). + +## Facilitator Verification Rules (MUST) + +A facilitator verifying `exact` on TON MUST enforce all of the following checks before sponsoring and relaying the transaction: + +### 1. Protocol and requirement consistency + +- `x402Version` MUST be `2`. +- `payload.accepted.scheme` and `requirements.scheme` MUST both equal `"exact"`. +- `payload.accepted.network` MUST equal `requirements.network` and MUST be a supported TVM network. +- `payload.accepted.asset` MUST equal `requirements.asset`. +- `payload.accepted.payTo` MUST equal `requirements.payTo`. +- `payload.accepted.amount` MUST equal `requirements.amount` exactly. +- The effective values of `responseDestination`, `forwardPayload`, and `forwardTonAmount` in `payload.accepted.extra` MUST match the corresponding effective values in `requirements.extra`. + +### 2. Message and signature verification + +- `payload.settlementBoc` MUST decode as a valid TON internal message. +- The `dest` field of the internal message is the client's wallet address (the sender/payer). +- The message body MUST contain a valid W5 (v5r1) signed transfer with opcode `0x73696e74` (`internal_signed`). +- The client's wallet account state MUST be either [`active`, `nonexist`, or `uninit`](https://docs.ton.org/foundations/status). `frozen` accounts are out of scope and MUST be rejected. +- The Ed25519 public key MUST be derived from the BoC's `stateInit` data cell (when `stateInit` is present, i.e. the wallet account is [`nonexist` or `uninit`](https://docs.ton.org/foundations/status)) or via the on-chain `get_public_key` getter on the client's wallet contract (when the account is `active`). The public key is NOT passed as a separate payload field. +- The Ed25519 signature MUST verify against the derived public key. The signature is located at the TAIL of the W5 message body (after `walletId`, `validUntil`, `seqno`, and actions). +- The facilitator MUST verify the client's wallet contract code matches a known W5 wallet contract. For [`nonexist` or `uninit`](https://docs.ton.org/foundations/status) accounts, the code MUST be taken from the `stateInit` included in `payload.settlementBoc`. For `active` accounts, the code MUST be fetched from the blockchain for the client's wallet address. The canonical code hash for W5R1 is `20834b7b72b112147e1b2fb457b84e74d1a30f04f737d4f62a668e9552d2b72f`. Implementations SHOULD maintain an allowlist of accepted wallet code hashes. Currently the allowlist contains one entry (W5R1). Wallet versions ship very rarely on TON (years apart), so this list is near-static. + +### 3. Payment intent + +- The W5 message MUST contain exactly **1** `jetton_transfer` (opcode `0xf8a7ea5`) internal message with [sending mode 1 (`PAY_FEES_SEPARATELY`) or mode 3 (`PAY_FEES_SEPARATELY | IGNORE_ERRORS`)](https://docs.ton.org/foundations/messages/modes). No additional actions are permitted. +- The transfer amount MUST be equal to `requirements.amount`. +- The Jetton master address (`payload.asset`) MUST equal `requirements.asset`. Note: [TEP-74](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md) `jetton_transfer` does not carry the master contract address in its body, so the on-chain asset binding is verified in the next check. +- The source Jetton wallet (the destination of the W5 internal message in the BoC) MUST match the Jetton wallet address returned by `get_wallet_address(sender)` on the Jetton master contract (`requirements.asset`). This binds the BoC to the correct asset on-chain and prevents a malicious BoC from using a substitute Jetton wallet. +- The `destination`, `response_destination`, `forward_payload`, and `forward_ton_amount` parameters inside the `jetton_transfer` body MUST match the effective parameters in `requirements`: `requirements.payTo`, `requirements.extra.responseDestination ?? addr_none`, `requirements.extra.forwardPayload ?? zero-bit payload`, and `requirements.extra.forwardTonAmount ?? "0"`. +- The TON value carried by the user's signed internal message MUST be sufficient to cover execution starting from the payer wallet's outgoing message to the source Jetton wallet, including the effective `forward_ton_amount` (`requirements.extra.forwardTonAmount ?? "0"`) and downstream Jetton-wallet execution costs. Fees for delivering and executing the outer relay message on the payer wallet itself are sponsored separately by the facilitator and therefore do NOT need to be covered by the user's signed internal message. Facilitators SHOULD satisfy this check via emulation. +- The client MUST have sufficient balance of the payment asset. + +### 4. Replay protection + +- The `validUntil` timestamp in the W5 body MUST NOT be expired and MUST NOT be more than `maxTimeoutSeconds` in the future. +- The wallet's on-chain seqno MUST be checked: the seqno in the BoC MUST be strictly equal to the current on-chain seqno. +- Duplicate `settlementBoc` submissions MUST be rejected via BoC hash dedup (see [Duplicate Settlement Mitigation](#duplicate-settlement-mitigation-recommended)). + +> **Note:** Seqno, balance, and expiry checks MAY be satisfied implicitly via transaction simulation (section 5). The spec declares them as explicit requirements so that implementations that do not simulate still enforce these checks. + +### 5. Transaction simulation (recommended) + +- Facilitator SHOULD simulate message execution via emulation during `/verify`. Simulation traces the full [TEP-74 Jetton transfer chain](https://docs.ton.org/standard/tokens/jettons/how-it-works#token-transfer) (transfer -> internal_transfer) and confirms the transfer reaches the recipient's Jetton wallet. This protects the resource server from doing unnecessary work for invalid payloads. +- Verification SHOULD fail if simulation indicates: insufficient Jetton balance, expired message, invalid seqno, or incomplete transfer chain. +- Simulation CAN replace the checks in section 3, but the checks from sections 1, 2, and 4 remain mandatory. + +## Settlement Logic + +1. Re-run all verification checks (do not trust prior `/verify` result). +2. Extract the signed body and optional `stateInit` from the internal message BoC. +3. Estimate gas via emulation: build a trial relay message, emulate the trace, and sum all fees across the trace. +4. Build the relay message: wrap the user's signed body in a bounceable internal message from the facilitator's wallet to the user's wallet, attaching sufficient TON to cover both (a) the outer relay delivery and payer-wallet execution fees and (b) the value expected by the client's signed internal message. If the client's BoC contains a `stateInit` segment (indicating the wallet is [`nonexist` or `uninit`](https://docs.ton.org/foundations/status)), include it in the relay message to enable wallet deployment. +5. Sign and broadcast the facilitator's external message. +6. Wait for transaction confirmation. +7. Return x402 `SettlementResponse` with `success`, `transaction`, `network`, and `payer`. + +## Duplicate Settlement Mitigation (RECOMMENDED) + +### Vulnerability + +A race condition exists in the settlement flow: if the same payment BoC is submitted to the facilitator's `/settle` endpoint multiple times before the first submission is confirmed on-chain, each call may attempt broadcast. Although TON's seqno-based replay protection ensures the transfer only executes once on-chain, a malicious client can exploit the timing window to obtain access to multiple resources while only paying once. + +### Recommended Mitigation + +Facilitators SHOULD maintain a short-term, in-memory cache of BoC hashes that have been verified and/or settled. Before proceeding with settlement, the facilitator checks whether the BoC has already been seen: + +1. After verification succeeds, compute a hash of the `settlementBoc`. +2. If the hash is already present in the cache, reject the settlement with a `"duplicate_settlement"` error. +3. If the hash is not present, insert it into the cache and proceed with signing and submission. +4. Evict entries older than `maxTimeoutSeconds` (default 300s). After this window, the signed message's `validUntil` will have passed and it cannot land on-chain regardless. This is analogous to SVM's fixed 120-second eviction window (tied to blockhash lifetime). + +This approach requires no external storage or long-lived state — only an in-process set with time-based eviction. It preserves the facilitator's otherwise stateless design while closing the duplicate settlement attack vector. + +## Reference Implementations + +- **POC**: [ArkadiyStena/ton-x402-demo](https://github.com/ArkadiyStena/ton-x402-demo) +- **SDK**: [x402-foundation/x402#1944](https://github.com/x402-foundation/x402/pull/1944) + +## Appendix + +### W5 Wallet and Self-Relay Architecture + +The W5 wallet contract (v5, deployed since Aug 2024) introduced `internal_signed` messages — the key primitive for gasless transfers on TON: + +1. **Client resolves signing data** via a TON RPC endpoint: wallet seqno and Jetton wallet address. +2. **Client constructs and signs** the message offline with their Ed25519 key. Standard RPC calls only (same as SVM/Stellar/Aptos). +3. **Signed message is wrapped** in an internal message BoC and sent to the resource server as an x402 payment payload. +4. **Facilitator extracts** the signed body and wraps it in a new internal message from its own funded wallet (carrying TON for gas) and submits to the user's W5 wallet contract. +5. **W5 contract verifies** the Ed25519 signature and executes the Jetton transfer. + +The facilitator IS the relay — no third-party relay service is needed. Gas cost (~0.013 TON per transaction) is absorbed by the facilitator. + +This is architecturally equivalent to x402's facilitator model on other chains: + + +| x402 Concept | TON Equivalent | EVM Equivalent | +| ------------------------ | ----------------------------------------------- | --------------------------------------------- | +| Facilitator sponsors gas | Facilitator sends internal message carrying TON | Facilitator calls `transferWithAuthorization` | +| Client signs offline | W5 `internal_signed` message | EIP-3009 authorization signature | +| Client RPC calls | seqno + `get_wallet_address` (2 calls) | nonce lookup (1 call, permit2 extension only) | +| Settlement | Facilitator wraps + broadcasts | Facilitator submits tx | + + +### Client RPC Requirements + +The client requires access to a TON RPC endpoint to prepare the payment. Two read-only calls are needed: + +1. **Wallet seqno**: call the `seqno` getter on the client's W5 wallet contract. +2. **Jetton wallet address**: call `get_wallet_address` on the Jetton master contract with the sender's address to resolve the sender's Jetton wallet. + +This is the same pattern as other x402 networks: SVM clients fetch the recent blockhash, Stellar clients simulate the transaction, and Aptos clients query sequence numbers — all via standard RPC calls. + +Implementations SHOULD allow configuring a custom RPC endpoint and optional API key for higher rate limits. + +### TON Address Formats + +- **Raw**: `workchain:hex` (e.g., `0:b113a994...`) — used in this protocol. +- **Friendly non-bounceable**: `UQ...` — used in user-facing UIs. +- **Friendly bounceable**: `EQ...` — used for smart contracts. + +Implementations MUST use raw format in protocol messages and MAY display friendly format in UIs. + +### TEP-74 Jetton Standard + +TON uses the [TEP-74 Jetton standard](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md) for fungible tokens: + +- Transfer opcode: `0xf8a7ea5` (`jetton_transfer`). +- Each holder has a separate Jetton wallet contract. +- The Jetton master contract resolves wallet addresses via `get_wallet_address` getter. + +### Default Assets + + +| Network | Asset | Symbol | Decimals | Address | +| ---------- | ----- | ------ | -------- | -------------------------------------------------------------------- | +| `tvm:-239` | USDT | USD₮ | 6 | `0:b113a994b5024a16719f69139328eb759596c38a25f59028b146fecdc3621dfe` | + + +### References + +- [x402 v2 core specification](../../x402-specification-v2.md) +- [TEP-74 Jetton Standard](https://github.com/ton-blockchain/TEPs/blob/master/text/0074-jettons-standard.md) +- [W5 Wallet Contract](https://github.com/ton-blockchain/wallet-contract-v5) +- [W5 Gasless Transactions](https://docs.ton.org/standard/wallets/v5#gasless-transactions) +- [TVM CAIP-2 Namespace](https://namespaces.chainagnostic.org/tvm/caip2) +- [Facilitator](https://github.com/ohld/x402-ton-facilitator) +- [POC](https://github.com/ohld/x402-ton-poc) diff --git a/specs/x402-specification-v1.md b/specs/x402-specification-v1.md index 32191136ab..0940e3abf1 100644 --- a/specs/x402-specification-v1.md +++ b/specs/x402-specification-v1.md @@ -31,7 +31,7 @@ x402 is made up of three core components: x402 is an open payment standard that enables clients to pay for external resources. The protocol defines standardized message formats and payment flows that can be implemented over various transport layers, providing a standardized mechanism for payments across different payment schemes, networks and transport layers. -This specification is based on the x402 protocol implementation and documentation available in the [Coinbase x402 repository](https://github.com/coinbase/x402). It aims to provide a comprehensive and implementation-agnostic specification for the x402 protocol. +This specification is based on the x402 protocol implementation and documentation available in the [Coinbase x402 repository](https://github.com/x402-foundation/x402). It aims to provide a comprehensive and implementation-agnostic specification for the x402 protocol. **2. Core Payment Flow** diff --git a/specs/x402-specification-v2.md b/specs/x402-specification-v2.md index bde67e2584..470bb9a9ca 100644 --- a/specs/x402-specification-v2.md +++ b/specs/x402-specification-v2.md @@ -8,7 +8,7 @@ This specification defines the core x402 protocol for internet-native payments. - **Protocol fundamentals**: Payment requirements format, payment payload structure, and core message schemas - **Facilitator interface**: Standard APIs for payment verification and settlement -- **Payment schemes**: Extensible payment methods (currently supporting the "exact" scheme) +- **Payment schemes**: Extensible payment methods (including `exact`, `upto`, and `batch-settlement`; see `specs/schemes/`) - **Security considerations**: Replay attack prevention and trust minimization **Out of Scope**: This specification does not include: @@ -24,14 +24,14 @@ This specification defines the core x402 protocol for internet-native payments. x402 is made up of three core components: 1. **Types**: Core data structures (e.g., `PaymentRequirements`, `PaymentPayload`, `SettlementResponse`) that are independent of both transport mechanism and payment scheme -2. **Logic**: Payment formation and verification logic that depends on the payment scheme (e.g., exact, deferred) and network (e.g., evm, solana, etc.) +2. **Logic**: Payment formation and verification logic that depends on the payment scheme (e.g., exact, upto, batch-settlement) and network (e.g., evm, solana, etc.) 3. **Representation**: How payment data is transmitted and signaled, which depends on the transport mechanism (e.g., HTTP, MCP, A2A) **1. Overview** x402 is an open payment standard that enables clients to pay for external resources. The protocol defines standardized message formats and payment flows that can be implemented over various transport layers, providing a standardized mechanism for payments across different payment schemes, networks and transport layers. -This specification is based on the x402 protocol implementation and documentation available in the [Coinbase x402 repository](https://github.com/coinbase/x402). It aims to provide a comprehensive and implementation-agnostic specification for the x402 protocol. +This specification is based on the x402 protocol implementation and documentation available in the [Coinbase x402 repository](https://github.com/x402-foundation/x402). It aims to provide a comprehensive and implementation-agnostic specification for the x402 protocol. **2. Core Payment Flow** @@ -78,7 +78,10 @@ When a resource server requires payment, it responds with a payment required sig "resource": { "url": "https://api.example.com/premium-data", "description": "Access to premium market data", - "mimeType": "application/json" + "mimeType": "application/json", + "serviceName": "Example Market Data", + "tags": ["market-data", "finance"], + "iconUrl": "https://api.example.com/icon.png" }, "accepts": [ { @@ -124,11 +127,14 @@ Each `PaymentRequirements` object in the `accepts` array contains: The `ResourceInfo` object contains: -| Field Name | Type | Required | Description | -| ------------- | -------- | -------- | ------------------------------------------ | -| `url` | `string` | Required | URL of the protected resource | -| `description` | `string` | Optional | Human-readable description of the resource | -| `mimeType` | `string` | Optional | MIME type of the expected response | +| Field Name | Type | Required | Description | +| --------------- | --------------- | -------- | -------------------------------------------------------------------------------------------------------------------- | +| `url` | `string` | Required | URL of the protected resource | +| `description` | `string` | Optional | Human-readable description of the resource | +| `mimeType` | `string` | Optional | MIME type of the expected response | +| `serviceName` | `string` | Optional | Human-readable name of the service hosting the resource. Printable ASCII, max 32 characters. | +| `tags` | `array[string]` | Optional | Topical tags for the service, used for discovery filtering. Max 5 entries; each printable ASCII, max 32 characters. | +| `iconUrl` | `string` | Optional | Absolute `https`/`http` URL to an icon representing the service. Max 2048 characters. | The `Extensions` object is a key-value map where each key is an extension identifier and each value follows a standardized structure: @@ -154,7 +160,7 @@ The client includes payment authorization as JSON in the payment payload field: "mimeType": "application/json" }, "accepted": { - "scheme": "exact", + "scheme": "exact", "network": "eip155:84532", "amount": "10000", "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", @@ -253,6 +259,7 @@ The `VerifyResponse` schema contains the following fields: | `isValid` | `boolean` | Required | Indicates whether the payment authorization is valid | | `invalidReason` | `string` | Optional | Reason for invalidity (omitted if valid) | | `payer` | `string` | Optional | Address of the payer's wallet | +| `extra` | `object` | Optional | Scheme-specific additional data | **6. Payment Schemes (The Logic)** @@ -347,7 +354,7 @@ Example with actual data: "mimeType": "application/json" }, "accepted": { - "scheme": "exact", + "scheme": "exact", "network": "eip155:84532", "amount": "10000", "asset": "0x036CbD53842c5426634e7929541eC2318f3dCF7e", @@ -505,6 +512,10 @@ List discoverable x402 resources from the Bazaar. | Parameter | Type | Required | Description | Default | | --------- | -------- | -------- | ------------------------------------------- | ------- | | `type` | `string` | Optional | Filter by resource type (e.g., "http") | - | +| `payTo` | `string` | Optional | Filter by payment recipient address | - | +| `scheme` | `string` | Optional | Filter by payment scheme (e.g., "exact") | - | +| `network` | `string` | Optional | Filter by payment network (e.g., "eip155:8453") | - | +| `extensions` | `string` | Optional | Filter by extension key present on each resource | - | | `limit` | `number` | Optional | Maximum number of results to return (1-100) | 20 | | `offset` | `number` | Optional | Number of results to skip for pagination | 0 | @@ -547,7 +558,12 @@ List discoverable x402 resources from the Bazaar. } ``` -**8.2 Discovered Resource Fields** +**8.2 GET /discovery/search** + +Search semantics and response shape are defined in the Bazaar extension specification at +`specs/extensions/bazaar.md`, since this endpoint is extension-specific behavior. + +**8.3 Discovered Resource Fields** | Field Name | Type | Required | Description | | ------------- | -------- | -------- | --------------------------------------------------------------- | @@ -556,9 +572,9 @@ List discoverable x402 resources from the Bazaar. | `x402Version` | `number` | Required | Protocol version supported by the resource | | `accepts` | `array` | Required | Array of PaymentRequirements objects specifying payment methods | | `lastUpdated` | `number` | Required | Unix timestamp of when the resource was last updated | -| `metadata` | `object` | Optional | Additional metadata (category, provider, etc.) | +| `extensions` | `object` | Optional | Additional extension payloads associated with this discovered resource | -**8.3 Bazaar Concept** +**8.4 Bazaar Concept** The Bazaar is a marketplace ecosystem where x402-enabled resources can be discovered and accessed. Key features: @@ -567,14 +583,17 @@ The Bazaar is a marketplace ecosystem where x402-enabled resources can be discov - **Provider Information**: Learn about service providers and their offerings - **Dynamic Updates**: Resources can be added, updated, or removed dynamically -**8.4 Example Usage** +**8.5 Example Usage** ```bash -# Discover financial data APIs +# List financial data APIs GET /discovery/resources?type=http&limit=10 -# Search for specific provider -GET /discovery/resources?metadata[provider]=Coinbase +# Search for weather APIs +GET /discovery/search?query=weather+APIs&type=http&limit=5 + +# Continue a paginated search (when server supports it) +GET /discovery/search?query=financial+data&limit=10&cursor=eyJwYWdlIjoyfQ== ``` **9. Error Handling** diff --git a/typescript/.changeset/add-arbitrum-one-and-arbitrum-sepolia-default-stablecoin.md b/typescript/.changeset/add-arbitrum-one-and-arbitrum-sepolia-default-stablecoin.md deleted file mode 100644 index f668d66039..0000000000 --- a/typescript/.changeset/add-arbitrum-one-and-arbitrum-sepolia-default-stablecoin.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@x402/evm": patch ---- - -Add Arbitrum One (chain ID 42161) and Arbitrum Sepolid (chain ID 421614) support with USDC as the default stablecoin \ No newline at end of file diff --git a/typescript/.changeset/add-fastify-adapter.md b/typescript/.changeset/add-fastify-adapter.md deleted file mode 100644 index 3742b2ec99..0000000000 --- a/typescript/.changeset/add-fastify-adapter.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@x402/fastify": minor ---- - -Added Fastify framework adapter for x402 payment middleware diff --git a/typescript/.changeset/add-mezo-testnet-default-asset.md b/typescript/.changeset/add-mezo-testnet-default-asset.md deleted file mode 100644 index 68f95c4bdf..0000000000 --- a/typescript/.changeset/add-mezo-testnet-default-asset.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@x402/evm": patch ---- - -Add Mezo Testnet (chain ID 31611) support with mUSD as the default stablecoin diff --git a/typescript/.changeset/add-polygon-support.md b/typescript/.changeset/add-polygon-support.md deleted file mode 100644 index c25ea927a4..0000000000 --- a/typescript/.changeset/add-polygon-support.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@x402/evm": minor ---- - -Add Polygon mainnet (chain ID 137) support with USDC as the default stablecoin diff --git a/typescript/.changeset/add-stable-support.md b/typescript/.changeset/add-stable-support.md deleted file mode 100644 index cafc97c9d8..0000000000 --- a/typescript/.changeset/add-stable-support.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@x402/evm": minor ---- - -Add Stable mainnet (chain ID 988) support with USDT0 as the default stablecoin diff --git a/typescript/.changeset/add-stable-testnet-support.md b/typescript/.changeset/add-stable-testnet-support.md deleted file mode 100644 index abad1a4804..0000000000 --- a/typescript/.changeset/add-stable-testnet-support.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@x402/evm": minor ---- - -Add Stable testnet (chain ID 2201) support with USDT0 as the default stablecoin diff --git a/typescript/.changeset/config.json b/typescript/.changeset/config.json index 83c6b62309..0edc7e9bac 100644 --- a/typescript/.changeset/config.json +++ b/typescript/.changeset/config.json @@ -2,16 +2,18 @@ "$schema": "https://unpkg.com/@changesets/config@3.1.1/schema.json", "changelog": "@changesets/cli/changelog", "commit": false, - "fixed": [], - "linked": [ + "linked": [], + "fixed": [ [ "@x402/core", "@x402/extensions", "@x402/evm", + "@x402/avm", "@x402/aptos", "@x402/stellar", "@x402/svm", "@x402/express", + "@x402/fastify", "@x402/hono", "@x402/next", "@x402/paywall", diff --git a/typescript/.changeset/export-hook-types.md b/typescript/.changeset/export-hook-types.md deleted file mode 100644 index ddaaeacf3c..0000000000 --- a/typescript/.changeset/export-hook-types.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@x402/core': patch ---- - -Export all hook types and hook context interfaces from the server entry point diff --git a/typescript/.changeset/fix-facilitator-redirect.md b/typescript/.changeset/fix-facilitator-redirect.md deleted file mode 100644 index 39b9902c64..0000000000 --- a/typescript/.changeset/fix-facilitator-redirect.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@x402/core': patch ---- - -Fixed HTTPFacilitatorClient not following 308 redirects from facilitator endpoints. Normalized base URL to strip trailing slashes and explicitly set `redirect: "follow"` on all fetch calls for cross-runtime compatibility. diff --git a/typescript/.changeset/settlement-overrides.md b/typescript/.changeset/settlement-overrides.md deleted file mode 100644 index 2d90176e25..0000000000 --- a/typescript/.changeset/settlement-overrides.md +++ /dev/null @@ -1,7 +0,0 @@ ---- -'@x402/core': minor -'@x402/express': minor -'@x402/hono': minor ---- - -Add SettlementOverrides support for partial settlement (upto scheme). Route handlers can call setSettlementOverrides() to settle less than the authorized maximum, enabling usage-based billing. diff --git a/typescript/.changeset/tall-windows-rescue.md b/typescript/.changeset/tall-windows-rescue.md deleted file mode 100644 index 4fc919c649..0000000000 --- a/typescript/.changeset/tall-windows-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@x402/fastify': patch ---- - -Applied monkey-patch on reply.raw write operations and buffered response to prevent content leak from direct raw writes bypassing Fastify's onSend lifecycle diff --git a/typescript/.changeset/upto-client-sdk.md b/typescript/.changeset/upto-client-sdk.md deleted file mode 100644 index 2c5d911156..0000000000 --- a/typescript/.changeset/upto-client-sdk.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@x402/evm': minor ---- - -Add upto payment scheme TypeScript SDK with client, facilitator, and server support for permit2-based "up to" payments on EVM chains. diff --git a/typescript/.changeset/yummy-readers-cut.md b/typescript/.changeset/yummy-readers-cut.md deleted file mode 100644 index bcadc37c36..0000000000 --- a/typescript/.changeset/yummy-readers-cut.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -"@x402/evm": patch ---- - -Updated x402UptoPermit2Proxy canonical address to 0x4020A4f3b7b90ccA423B9fabCc0CE57C6C240002, deployed with deterministic bytecode for reproducible cross-chain CREATE2 addresses diff --git a/typescript/README.md b/typescript/README.md new file mode 100644 index 0000000000..07b813e06f --- /dev/null +++ b/typescript/README.md @@ -0,0 +1,32 @@ +# x402 Typescript SDK + +This folder contains Typescript packages to help developers implement the x402 protocol in their front-end and back-end applications. + +| Package | Description | Latest version | +| --- | --- | --- | +| [`@x402/core`](./packages/core) | Transport-agnostic client, server, and facilitator components. | [![npm version](https://img.shields.io/npm/v/%40x402%2Fcore.svg)](https://www.npmjs.com/package/@x402/core) | +| [`@x402/extensions`](./packages/extensions) | Additional functionality built on top of x402 (Bazaar, Sign-in-with-x). | [![npm version](https://img.shields.io/npm/v/%40x402%2Fextensions.svg)](https://www.npmjs.com/package/@x402/extensions) | +| [`@x402/mcp`](./packages/mcp) | MCP server integration for x402. | [![npm version](https://img.shields.io/npm/v/%40x402%2Fmcp.svg)](https://www.npmjs.com/package/@x402/mcp) | + +## HTTP integrations + +| Package | Description | Latest version | +| --- | --- | --- | +| [`@x402/axios`](./packages/http/axios) | Axios interceptor for x402 payment flows. | [![npm version](https://img.shields.io/npm/v/%40x402%2Faxios.svg)](https://www.npmjs.com/package/@x402/axios) | +| [`@x402/express`](./packages/http/express) | Express middleware for x402-protected routes. | [![npm version](https://img.shields.io/npm/v/%40x402%2Fexpress.svg)](https://www.npmjs.com/package/@x402/express) | +| [`@x402/fastify`](./packages/http/fastify) | Fastify middleware for x402-protected routes. | [![npm version](https://img.shields.io/npm/v/%40x402%2Ffastify.svg)](https://www.npmjs.com/package/@x402/fastify) | +| [`@x402/fetch`](./packages/http/fetch) | Fetch wrapper for x402 payment handling. | [![npm version](https://img.shields.io/npm/v/%40x402%2Ffetch.svg)](https://www.npmjs.com/package/@x402/fetch) | +| [`@x402/hono`](./packages/http/hono) | Hono middleware for x402 integrations. | [![npm version](https://img.shields.io/npm/v/%40x402%2Fhono.svg)](https://www.npmjs.com/package/@x402/hono) | +| [`@x402/next`](./packages/http/next) | Next.js integration for x402. | [![npm version](https://img.shields.io/npm/v/%40x402%2Fnext.svg)](https://www.npmjs.com/package/@x402/next) | +| [`@x402/paywall`](./packages/http/paywall) | Browser paywall UI for x402-enabled apps. | [![npm version](https://img.shields.io/npm/v/%40x402%2Fpaywall.svg)](https://www.npmjs.com/package/@x402/paywall) | + +## Chains implementations + +| Package | Description | Latest version | +| --- | --- | --- | +| **EVM** - [`@x402/evm`](./packages/mechanisms/evm) | EVM implementation of x402 using the Exact payment scheme. | [![npm version](https://img.shields.io/npm/v/%40x402%2Fevm.svg)](https://www.npmjs.com/package/@x402/evm) | +| **Algorand** - [`@x402/avm`](./packages/mechanisms/avm) | AVM implementation of x402 using ASA transfers. | [![npm version](https://img.shields.io/npm/v/%40x402%2Favm.svg)](https://www.npmjs.com/package/@x402/avm) | +| **Aptos** - [`@x402/aptos`](./packages/mechanisms/aptos) | Aptos implementation of the x402 payment protocol. | [![npm version](https://img.shields.io/npm/v/%40x402%2Faptos.svg)](https://www.npmjs.com/package/@x402/aptos) | +| **Stellar** - [`@x402/stellar`](./packages/mechanisms/stellar) | Stellar implementation of x402 using Soroban token transfers. | [![npm version](https://img.shields.io/npm/v/%40x402%2Fstellar.svg)](https://www.npmjs.com/package/@x402/stellar) | +| **Solana** - [`@x402/svm`](./packages/mechanisms/svm) | SVM implementation of x402 using SPL token transfers. | [![npm version](https://img.shields.io/npm/v/%40x402%2Fsvm.svg)](https://www.npmjs.com/package/@x402/svm) | + diff --git a/typescript/package.json b/typescript/package.json index 8612926dc2..452ed9097c 100644 --- a/typescript/package.json +++ b/typescript/package.json @@ -1,37 +1,34 @@ { "name": "x402_monorepo", "engines": { - "node": ">=18.0.0", - "pnpm": ">=10.7.0" + "node": ">=22.0.0", + "pnpm": ">=11.1.1" }, - "packageManager": "pnpm@10.7.0", + "packageManager": "pnpm@11.1.1", "private": "true", "version": "0.0.2", "description": "x402 Payment Protocol Monorepo", "main": "index.js", - "pnpm": { - "overrides": { - "cssstyle": "5.3.6" - } - }, "scripts": { "build": "turbo run build", + "build:paywall-deps": "turbo run build --filter='@x402/paywall^...'", "lint": "turbo run lint", "format": "turbo run format", "lint:check": "turbo run lint:check", "format:check": "turbo run format:check", "test": "turbo run test", - "test:integration": "pnpm --filter @x402/core --filter @x402/evm --filter @x402/svm --filter @x402/aptos --filter @x402/stellar test:integration", + "test:integration": "pnpm --filter @x402/core --filter @x402/evm --filter @x402/svm --filter @x402/avm --filter @x402/aptos --filter @x402/hedera --filter @x402/stellar test:integration", "test:all": "pnpm test && pnpm test:integration" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { + "tsx": "^4.21.0", "tsup": "^8.4.0", "turbo": "^2.5.0", - "typescript": "^5.8.3", + "typescript": "^5.7.3", "@changesets/cli": "^2.28.1", "@changesets/changelog-github": "^0.5.1" } -} \ No newline at end of file +} diff --git a/typescript/packages/core/CHANGELOG.md b/typescript/packages/core/CHANGELOG.md index 0367e55735..330f4bc7a8 100644 --- a/typescript/packages/core/CHANGELOG.md +++ b/typescript/packages/core/CHANGELOG.md @@ -1,5 +1,41 @@ # @x402/core Changelog +## 2.12.0 + +### Minor Changes + +- 608034f: Added Bazaar service metadata fields (`serviceName`, `tags`, `iconUrl`) on `ResourceInfo`, plus `isValidServiceName` / `sanitizeTags` / `isValidIconUrl` / `sanitizeResourceServiceMetadata` helpers in `@x402/extensions/bazaar` that `extractDiscoveryInfo` now applies with soft-drop semantics. Fields are optional and additive — providers that omit them produce byte-identical 402 bodies. +- 45d7d19: - Extended scheme surface with optional schemeHooks + - Added skip primitives to verify/route/settle for custom flows + - Added VerifyResponse / SettleResponse extra + - Added onPaymentResponse client hook and processPaymentResult utility +- d235050: Log the `EXTENSION-RESPONSES` header from facilitator verify/settle responses. The HTTP facilitator client decodes the header and logs allowlisted fields (`status`, `rejectedReason`, `reason`, `code`) without attaching data to `VerifyResponse` or `SettleResponse`. + +## 2.11.0 + +### Minor Changes + +- a051f48: Enables `ResourceServerExtension` to register resource-server verify/settle hooks, and enforces extension mutation policy: `enrichPaymentRequiredResponse` may only change `payTo` / `amount` / `asset` when those baseline values are vacant; `scheme` / `network` / `maxTimeoutSeconds` and baseline `extra` entries are immutable. `enrichSettlementResponse` may not rewrite facilitator core fields (`success`, `transaction`, `network`, etc.). Lifecycle hook contexts are typed as read-only for core protocol fields. +- dc04108: Fixed a bug affecting USD prices with 7+ decimal places of precision (e.g. `$0.0000001` or smaller). + +## 2.10.0 + +### Minor Changes + +- Bumped to align version with dependent packages + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization +- d352574: Add SettlementOverrides support for partial settlement (upto scheme). Route handlers can call setSettlementOverrides() to settle less than the authorized maximum, enabling usage-based billing. + +### Patch Changes + +- 8cf3fca: Export all hook types and hook context interfaces from the server entry point +- c0e3969: Fixed HTTPFacilitatorClient not following 308 redirects from facilitator endpoints. Normalized base URL to strip trailing slashes and explicitly set `redirect: "follow"` on all fetch calls for cross-runtime compatibility. + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/core/README.md b/typescript/packages/core/README.md index c2c92188bf..bef8d90128 100644 --- a/typescript/packages/core/README.md +++ b/typescript/packages/core/README.md @@ -1,4 +1,4 @@ -# @x402/core +# `@x402/core` • [![npm version](https://img.shields.io/npm/v/%40x402%2Fcore.svg)](https://www.npmjs.com/package/@x402/core) Core implementation of the x402 payment protocol for TypeScript/JavaScript applications. Provides transport-agnostic client, server and facilitator components. @@ -283,11 +283,12 @@ For blockchain-specific implementations: - `@x402/evm` - Ethereum and EVM-compatible chains - `@x402/svm` - Solana blockchain +- `@x402/avm` - Algorand blockchain ## Examples -See the [examples directory](https://github.com/coinbase/x402/tree/main/examples/typescript) for complete examples. +See the [examples directory](https://github.com/x402-foundation/x402/tree/main/examples/typescript) for complete examples. ## Contributing -Contributions welcome! See [Contributing Guide](https://github.com/coinbase/x402/blob/main/CONTRIBUTING.md). +Contributions welcome! See [Contributing Guide](https://github.com/x402-foundation/x402/blob/main/CONTRIBUTING.md). diff --git a/typescript/packages/core/package.json b/typescript/packages/core/package.json index e1467004bf..b3cf3df14b 100644 --- a/typescript/packages/core/package.json +++ b/typescript/packages/core/package.json @@ -1,6 +1,6 @@ { "name": "@x402/core", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/cjs/index.d.ts", @@ -18,8 +18,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@eslint/js": "^9.24.0", @@ -32,7 +32,7 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", diff --git a/typescript/packages/core/src/client/x402Client.ts b/typescript/packages/core/src/client/x402Client.ts index 544aaa1c7c..bfb0c671ea 100644 --- a/typescript/packages/core/src/client/x402Client.ts +++ b/typescript/packages/core/src/client/x402Client.ts @@ -1,7 +1,7 @@ import { x402Version } from ".."; import { SchemeNetworkClient } from "../types/mechanisms"; import { PaymentPayload, PaymentRequirements } from "../types/payments"; -import { Network, PaymentRequired } from "../types"; +import { Network, PaymentRequired, SettleResponse } from "../types"; import { findByNetworkAndScheme, findSchemesByNetwork } from "../utils"; /** @@ -35,8 +35,42 @@ export type OnPaymentCreationFailureHook = ( context: PaymentCreationFailureContext, ) => Promise; +/** + * Context provided to payment response hooks after the paid request completes. + * + * Discriminate by what's present: + * - `settleResponse` with `success: true` → settle succeeded + * - `settleResponse` with `success: false` → settle failed + * - `paymentRequired` (no `settleResponse`) → verify failed + * - `error` → transport or parse error + */ +export interface PaymentResponseContext { + paymentPayload: PaymentPayload; + requirements: PaymentRequirements; + settleResponse?: SettleResponse; + paymentRequired?: PaymentRequired; + error?: Error; +} + +/** + * Hook fired after a paid request completes. + * Return `{ recovered: true }` to signal the transport should retry with a fresh payload. + */ +export type OnPaymentResponseHook = ( + ctx: PaymentResponseContext, +) => Promise; + export type SelectPaymentRequirements = (x402Version: number, paymentRequirements: PaymentRequirements[]) => PaymentRequirements; +type ClientHookAdapterHandles = { + beforePaymentCreation?: BeforePaymentCreationHook; + afterPaymentCreation?: AfterPaymentCreationHook; + onPaymentCreationFailure?: OnPaymentCreationFailureHook; + onPaymentResponse?: OnPaymentResponseHook; +}; + +type ClientHookPhase = keyof ClientHookAdapterHandles; + /** * Extension that can enrich payment payloads on the client side. * @@ -129,12 +163,14 @@ export interface x402ClientConfig { export class x402Client { private readonly paymentRequirementsSelector: SelectPaymentRequirements; private readonly registeredClientSchemes: Map>> = new Map(); + private readonly schemeClientHookAdapters: Map>> = new Map(); private readonly policies: PaymentPolicy[] = []; private readonly registeredExtensions: Map = new Map(); private beforePaymentCreationHooks: BeforePaymentCreationHook[] = []; private afterPaymentCreationHooks: AfterPaymentCreationHook[] = []; private onPaymentCreationFailureHooks: OnPaymentCreationFailureHook[] = []; + private paymentResponseHooks: OnPaymentResponseHook[] = []; /** * Creates a new x402Client instance. @@ -266,6 +302,41 @@ export class x402Client { return this; } + /** + * Register a hook to execute after a paid request completes. + * Can signal recovery by returning { recovered: true }, causing the transport to retry. + * + * @param hook - The hook function to register + * @returns The x402Client instance for chaining + */ + onPaymentResponse(hook: OnPaymentResponseHook): x402Client { + this.paymentResponseHooks.push(hook); + return this; + } + + /** + * Fires all registered payment response hooks in order. + * Returns `{ recovered: true }` if any hook signals recovery (first wins). + * + * @param ctx - The payment response context + * @returns Recovery signal or undefined + */ + async handlePaymentResponse( + ctx: PaymentResponseContext, + ): Promise<{ recovered: true } | undefined> { + for (const hook of this.getLabeledHooks( + "onPaymentResponse", + ctx.paymentPayload.x402Version, + ctx.requirements, + )) { + const result = await hook(ctx); + if (result && "recovered" in result && result.recovered) { + return { recovered: true }; + } + } + return undefined; + } + /** * Creates a payment payload based on a PaymentRequired response. * @@ -290,8 +361,11 @@ export class x402Client { selectedRequirements: requirements, }; - // Execute beforePaymentCreation hooks - for (const hook of this.beforePaymentCreationHooks) { + for (const hook of this.getLabeledHooks( + "beforePaymentCreation", + paymentRequired.x402Version, + requirements, + )) { const result = await hook(context); if (result && "abort" in result && result.abort) { throw new Error(`Payment creation aborted: ${result.reason}`); @@ -333,13 +407,16 @@ export class x402Client { // Enrich payload via registered client extensions (for non-scheme extensions) paymentPayload = await this.enrichPaymentPayloadWithExtensions(paymentPayload, paymentRequired); - // Execute afterPaymentCreation hooks const createdContext: PaymentCreatedContext = { ...context, paymentPayload, }; - for (const hook of this.afterPaymentCreationHooks) { + for (const hook of this.getLabeledHooks( + "afterPaymentCreation", + paymentRequired.x402Version, + requirements, + )) { await hook(createdContext); } @@ -350,8 +427,11 @@ export class x402Client { error: error as Error, }; - // Execute onPaymentCreationFailure hooks - for (const hook of this.onPaymentCreationFailureHooks) { + for (const hook of this.getLabeledHooks( + "onPaymentCreationFailure", + paymentRequired.x402Version, + requirements, + )) { const result = await hook(failureContext); if (result && "recovered" in result && result.recovered) { return result.payload; @@ -495,10 +575,90 @@ export class x402Client { } const clientByScheme = clientSchemesByNetwork.get(network)!; - if (!clientByScheme.has(client.scheme)) { - clientByScheme.set(client.scheme, client); + clientByScheme.set(client.scheme, client); + + if (!this.schemeClientHookAdapters.has(x402Version)) { + this.schemeClientHookAdapters.set(x402Version, new Map()); + } + const adaptersByNetwork = this.schemeClientHookAdapters.get(x402Version)!; + if (!adaptersByNetwork.has(network)) { + adaptersByNetwork.set(network, new Map()); + } + + const adaptersByScheme = adaptersByNetwork.get(network)!; + const hooks = client.schemeHooks; + if (!hooks) { + adaptersByScheme.delete(client.scheme); + return this; + } + + const handles: ClientHookAdapterHandles = {}; + if (hooks.onBeforePaymentCreation) { + handles.beforePaymentCreation = hooks.onBeforePaymentCreation; + } + if (hooks.onAfterPaymentCreation) { + handles.afterPaymentCreation = hooks.onAfterPaymentCreation; + } + if (hooks.onPaymentCreationFailure) { + handles.onPaymentCreationFailure = hooks.onPaymentCreationFailure; + } + if (hooks.onPaymentResponse) { + handles.onPaymentResponse = hooks.onPaymentResponse; + } + + if (Object.keys(handles).length > 0) { + adaptersByScheme.set(client.scheme, handles); + } else { + adaptersByScheme.delete(client.scheme); } return this; } + + /** + * Returns manual hooks followed by the hook for the selected scheme, if present. + * + * @param phase - Hook slot to collect + * @param x402Version - Protocol version for the selected requirement + * @param requirements - Selected payment requirement + * @returns Hooks in invocation order + */ + private getLabeledHooks

( + phase: P, + x402Version: number, + requirements: PaymentRequirements, + ): Array> { + let manual: Array>; + switch (phase) { + case "beforePaymentCreation": + manual = this.beforePaymentCreationHooks as Array< + NonNullable + >; + break; + case "afterPaymentCreation": + manual = this.afterPaymentCreationHooks as Array< + NonNullable + >; + break; + case "onPaymentCreationFailure": + manual = this.onPaymentCreationFailureHooks as Array< + NonNullable + >; + break; + case "onPaymentResponse": + manual = this.paymentResponseHooks as Array>; + break; + } + + const out: Array> = [...manual]; + const adaptersByNetwork = this.schemeClientHookAdapters.get(x402Version); + const schemeAdapter = adaptersByNetwork + ? findByNetworkAndScheme(adaptersByNetwork, requirements.scheme, requirements.network) + : undefined; + const hook = schemeAdapter?.[phase]; + if (hook !== undefined) { + out.push(hook); + } + return out; + } } diff --git a/typescript/packages/core/src/http/httpFacilitatorClient.ts b/typescript/packages/core/src/http/httpFacilitatorClient.ts index 37bd2a0674..e233b7b135 100644 --- a/typescript/packages/core/src/http/httpFacilitatorClient.ts +++ b/typescript/packages/core/src/http/httpFacilitatorClient.ts @@ -8,6 +8,7 @@ import { FacilitatorResponseError, } from "../types/facilitator"; import { z } from "../schemas"; +import { safeBase64Decode } from "../utils"; const DEFAULT_FACILITATOR_URL = "https://x402.org/facilitator"; @@ -17,6 +18,7 @@ export interface FacilitatorConfig { verify: Record; settle: Record; supported: Record; + bazaar?: Record; }>; } @@ -80,6 +82,10 @@ const verifyResponseSchema: z.ZodType = z .record(z.string(), z.unknown()) .nullish() .transform(v => v ?? undefined), + extra: z + .record(z.string(), z.unknown()) + .nullish() + .transform(v => v ?? undefined), }); const settleResponseSchema: z.ZodType = z.object({ @@ -98,10 +104,18 @@ const settleResponseSchema: z.ZodType = z .transform(v => v ?? undefined), transaction: z.string(), network: z.custom(value => typeof value === "string"), + amount: z + .string() + .nullish() + .transform(v => v ?? undefined), extensions: z .record(z.string(), z.unknown()) .nullish() .transform(v => v ?? undefined), + extra: z + .record(z.string(), z.unknown()) + .nullish() + .transform(v => v ?? undefined), }); const supportedKindSchema: z.ZodType = @@ -143,6 +157,40 @@ function responseExcerpt(text: string, limit: number = 200): string { return `${compact.slice(0, limit - 3)}...`; } +const EXTENSION_RESPONSE_LOG_FIELD_ALLOWLIST = ["status", "rejectedReason", "reason", "code"]; + +/** + * Reads the `EXTENSION-RESPONSES` header from a facilitator HTTP response and logs + * allowlisted fields. Silently ignores malformed headers. + * + * @param response - The HTTP response from the facilitator + */ +function logExtensionResponsesHeader(response: Response): void { + const header = response.headers.get("EXTENSION-RESPONSES"); + if (!header) return; + try { + const decoded = JSON.parse(safeBase64Decode(header)); + if (!decoded || typeof decoded !== "object" || Array.isArray(decoded)) return; + const sanitized: Record> = {}; + for (const [extensionKey, payload] of Object.entries(decoded as Record)) { + const source = + payload && typeof payload === "object" && !Array.isArray(payload) + ? (payload as Record) + : {}; + const filtered: Record = {}; + for (const key of EXTENSION_RESPONSE_LOG_FIELD_ALLOWLIST) { + if (source[key] !== undefined) { + filtered[key] = source[key]; + } + } + sanitized[extensionKey] = filtered; + } + console.log(`[x402] extension responses: ${JSON.stringify(sanitized)}`); + } catch { + // Ignore malformed header + } +} + /** * Parses and validates a successful facilitator response body. * @@ -246,7 +294,9 @@ export class HTTPFacilitatorClient implements FacilitatorClient { ); } - return parseSuccessResponse(response, verifyResponseSchema, "verify"); + const verifyResult = await parseSuccessResponse(response, verifyResponseSchema, "verify"); + logExtensionResponsesHeader(response); + return verifyResult; } /** @@ -298,7 +348,9 @@ export class HTTPFacilitatorClient implements FacilitatorClient { ); } - return parseSuccessResponse(response, settleResponseSchema, "settle"); + const settleResult = await parseSuccessResponse(response, settleResponseSchema, "settle"); + logExtensionResponsesHeader(response); + return settleResult; } /** diff --git a/typescript/packages/core/src/http/x402HTTPClient.ts b/typescript/packages/core/src/http/x402HTTPClient.ts index 2a300ee179..78ed37f1bc 100644 --- a/typescript/packages/core/src/http/x402HTTPClient.ts +++ b/typescript/packages/core/src/http/x402HTTPClient.ts @@ -5,7 +5,7 @@ import { } from "."; import { SettleResponse } from "../types"; import { PaymentPayload, PaymentRequired } from "../types/payments"; -import { x402Client } from "../client/x402Client"; +import { x402Client, type PaymentResponseContext } from "../client/x402Client"; /** * Context provided to onPaymentRequired hooks. @@ -153,4 +153,104 @@ export class x402HTTPClient { async createPaymentPayload(paymentRequired: PaymentRequired): Promise { return this.client.createPaymentPayload(paymentRequired); } + + /** + * Parses response headers into protocol types, fires payment response hooks, + * and returns whether a hook signaled recovery. + * + * Called by transport wrappers (fetch, axios) after the paid request completes. + * + * @param paymentPayload - The payload that was sent with the request + * @param getHeader - Function to retrieve a response header by name + * @param status - The HTTP status code of the response + * @returns Whether a hook recovered and the parsed settle response (if any) + */ + async processPaymentResult( + paymentPayload: PaymentPayload, + getHeader: (name: string) => string | null | undefined, + status: number, + ): Promise<{ recovered: boolean; settleResponse?: SettleResponse }> { + const requirements = paymentPayload.accepted; + + let settleResponse: SettleResponse | undefined; + try { + settleResponse = this.getPaymentSettleResponse(getHeader); + } catch { + /* no header */ + } + + let paymentRequired: PaymentRequired | undefined; + if (!settleResponse && status === 402) { + try { + paymentRequired = this.getPaymentRequiredResponse(getHeader); + } catch { + /* no header */ + } + } + + const ctx: PaymentResponseContext = { + paymentPayload, + requirements: requirements!, + ...(settleResponse ? { settleResponse } : {}), + ...(paymentRequired ? { paymentRequired } : {}), + }; + + const result = await this.client.handlePaymentResponse(ctx); + return { recovered: result?.recovered === true, settleResponse }; + } + + /** + * Parses a fetch Response into a discriminated `x402PaymentResult` for app-level convenience. + * + * @param response - The fetch Response to process + * @returns A discriminated union describing the payment outcome + */ + async processResponse(response: Response): Promise { + const getHeader = (name: string) => response.headers.get(name); + + let settleResponse: SettleResponse | undefined; + try { + settleResponse = this.getPaymentSettleResponse(getHeader); + } catch { + /* no header */ + } + + const contentType = response.headers.get("content-type") ?? ""; + const body = contentType.includes("application/json") + ? await response.json() + : await response.text(); + + if (settleResponse && settleResponse.success) { + return { kind: "success", response, body, settleResponse }; + } + + if (settleResponse && !settleResponse.success) { + return { kind: "settle_failed", response, body, settleResponse }; + } + + if (response.status === 402) { + try { + const paymentRequired = this.getPaymentRequiredResponse(getHeader, body); + return { kind: "payment_required", response, paymentRequired }; + } catch { + /* no payment-required header */ + } + } + + if (response.ok) { + return { kind: "passthrough", response, body }; + } + + return { kind: "error", response, status: response.status, body }; + } } + +/** + * Discriminated union describing the outcome of a payment-enabled request. + */ +export type x402PaymentResult = + | { kind: "success"; response: Response; body: unknown; settleResponse: SettleResponse } + | { kind: "settle_failed"; response: Response; body: unknown; settleResponse: SettleResponse } + | { kind: "payment_required"; response: Response; paymentRequired: PaymentRequired } + | { kind: "error"; response: Response; status: number; body: unknown } + | { kind: "passthrough"; response: Response; body: unknown }; diff --git a/typescript/packages/core/src/http/x402HTTPResourceServer.ts b/typescript/packages/core/src/http/x402HTTPResourceServer.ts index 7f621a8572..360f232f94 100644 --- a/typescript/packages/core/src/http/x402HTTPResourceServer.ts +++ b/typescript/packages/core/src/http/x402HTTPResourceServer.ts @@ -1,4 +1,9 @@ -import { x402ResourceServer, SettlementOverrides } from "../server"; +import { + x402ResourceServer, + SettlementOverrides, + SkipHandlerDirective, + PaymentCancellationDispatcher, +} from "../server"; import { decodePaymentSignatureHeader, encodePaymentRequiredHeader, @@ -177,6 +182,22 @@ export interface RouteConfig { */ export type RoutesConfig = Record | RouteConfig; +/** + * Check if any routes in the configuration declare bazaar extensions. + * + * @param routes - Route configuration + * @returns True if any route has extensions.bazaar defined + */ +export function checkIfBazaarNeeded(routes: RoutesConfig): boolean { + if ("accepts" in routes) { + return !!(routes.extensions && "bazaar" in routes.extensions); + } + + return Object.values(routes).some(routeConfig => { + return !!(routeConfig.extensions && "bazaar" in routeConfig.extensions); + }); +} + /** * Hook that runs on every request to a protected route, before payment processing. * Can grant access without payment, deny the request, or continue to payment flow. @@ -241,6 +262,7 @@ export type HTTPProcessResult = | { type: "no-payment-required" } | { type: "payment-verified"; + cancellationDispatcher: PaymentCancellationDispatcher; paymentPayload: PaymentPayload; paymentRequirements: PaymentRequirements; declaredExtensions?: Record; @@ -518,7 +540,7 @@ export class x402HTTPResourceServer { requirements, resourceInfo, "No matching payment requirements", - routeConfig.extensions, + extensions ?? {}, transportContext, ); return { @@ -530,6 +552,8 @@ export class x402HTTPResourceServer { const verifyResult = await this.ResourceServer.verifyPayment( paymentPayload, matchingRequirements, + extensions ?? {}, + transportContext, ); if (!verifyResult.isValid) { @@ -537,8 +561,9 @@ export class x402HTTPResourceServer { requirements, resourceInfo, verifyResult.invalidReason, - routeConfig.extensions, + extensions ?? {}, transportContext, + paymentPayload, ); return { type: "payment-error", @@ -546,12 +571,31 @@ export class x402HTTPResourceServer { }; } + // Bypass the resource handler + if (verifyResult.skipHandler) { + return await this.processSkipHandlerSettlement( + paymentPayload, + matchingRequirements, + extensions ?? {}, + transportContext, + verifyResult.skipHandler, + ); + } + + const cancellationDispatcher = this.ResourceServer.createPaymentCancellationDispatcher( + paymentPayload, + matchingRequirements, + extensions ?? {}, + transportContext, + ); + // Payment is valid, return data needed for settlement return { type: "payment-verified", + cancellationDispatcher, paymentPayload, paymentRequirements: matchingRequirements, - declaredExtensions: routeConfig.extensions, + declaredExtensions: extensions ?? {}, }; } catch (error) { if (error instanceof FacilitatorResponseError) { @@ -561,7 +605,7 @@ export class x402HTTPResourceServer { requirements, resourceInfo, error instanceof Error ? error.message : "Payment verification failed", - routeConfig.extensions, + extensions ?? {}, transportContext, ); return { @@ -600,13 +644,17 @@ export class x402HTTPResourceServer { try { // Resolve overrides: explicit param takes precedence, fall back to response header let resolvedOverrides = settlementOverrides; - if (!resolvedOverrides && transportContext?.responseHeaders?.[SETTLEMENT_OVERRIDES_HEADER]) { - try { - resolvedOverrides = JSON.parse( - transportContext.responseHeaders[SETTLEMENT_OVERRIDES_HEADER], - ); - } catch { - // Ignore malformed header + if (!resolvedOverrides && transportContext?.responseHeaders) { + const overridesKey = SETTLEMENT_OVERRIDES_HEADER.toLowerCase(); + const rawValue = Object.entries(transportContext.responseHeaders).find( + ([key]) => key.toLowerCase() === overridesKey, + )?.[1]; + if (rawValue) { + try { + resolvedOverrides = JSON.parse(rawValue); + } catch { + // Ignore malformed header + } } } @@ -690,6 +738,56 @@ export class x402HTTPResourceServer { return this.getRouteConfig(context.path, method) !== undefined; } + /** + * Settle a verified payment that requested `skipHandler`, packaging the + * result as a `payment-error` HTTPProcessResult so framework adapters can + * write the response without invoking the route handler. + * + * - On success: status 200 + PAYMENT-RESPONSE header + configured body. + * - On failure: the standard 402 settlement-failure response. + * + * @param paymentPayload - Verified payment payload. + * @param requirements - Matched payment requirements. + * @param declaredExtensions - Optional declared extensions for the route. + * @param transportContext - Optional HTTP transport context. + * @param skipHandlerResponse - Optional content type + body to return on success. + * @returns A `payment-error` HTTPProcessResult carrying the final response. + */ + private async processSkipHandlerSettlement( + paymentPayload: PaymentPayload, + requirements: PaymentRequirements, + declaredExtensions: Record | undefined, + transportContext: HTTPTransportContext, + skipHandlerResponse: SkipHandlerDirective | undefined, + ): Promise { + const settleResult = await this.processSettlement( + paymentPayload, + requirements, + declaredExtensions, + transportContext, + ); + + if (!settleResult.success) { + return { type: "payment-error", response: settleResult.response }; + } + + const contentType = skipHandlerResponse?.contentType ?? "application/json"; + const body = skipHandlerResponse?.body ?? {}; + + return { + type: "payment-error", + response: { + status: 200, + headers: { + "Content-Type": contentType, + ...settleResult.headers, + }, + body, + isHtml: contentType.includes("text/html"), + }, + }; + } + /** * Build HTTPResponseInstructions for settlement failure. * Uses settlementFailedResponseBody hook if configured, otherwise defaults to empty body. @@ -1027,6 +1125,19 @@ export class x402HTTPResourceServer { // Fallback: Basic HTML paywall const resource = paymentRequired.resource; const displayAmount = this.getDisplayAmount(paymentRequired); + const firstAccept = paymentRequired.accepts?.[0]; + const decimals = + firstAccept && "amount" in firstAccept + ? this.ResourceServer.getAssetDecimalsForRequirements(firstAccept) + : 6; + const safeDecimals = Math.min(Math.max(decimals, 0), 100); + const displayAmountText = parseFloat(displayAmount.toFixed(safeDecimals)).toString(); + const assetLabel = + typeof firstAccept?.extra?.name === "string" + ? firstAccept.extra.name + : firstAccept?.asset + ? `...${firstAccept.asset.slice(-6)}` + : "Token"; return ` @@ -1041,7 +1152,7 @@ export class x402HTTPResourceServer { ${paywallConfig?.appLogo ? `${paywallConfig.appName || ` : ""}

Payment Required

${resource ? `

Resource: ${resource.description || resource.url}

` : ""} -

Amount: $${displayAmount.toFixed(2)} USDC

+

Amount: ${displayAmountText} ${assetLabel}

0) { const firstReq = accepts[0]; if ("amount" in firstReq) { - // V2 format - return parseFloat(firstReq.amount) / 1000000; // Assuming USDC with 6 decimals + const decimals = this.ResourceServer.getAssetDecimalsForRequirements(firstReq); + return parseFloat(firstReq.amount) / 10 ** decimals; } } return 0; diff --git a/typescript/packages/core/src/schemas/index.ts b/typescript/packages/core/src/schemas/index.ts index b66dbe4eda..b21d34696d 100644 --- a/typescript/packages/core/src/schemas/index.ts +++ b/typescript/packages/core/src/schemas/index.ts @@ -61,10 +61,19 @@ export type Network = z.infer; /** * ResourceInfo schema for V2 - describes the protected resource. */ +// Printable ASCII (U+0020–U+007E) — matches the bazaar-facilitator +// `isValidServiceName` / `sanitizeTags` regex. Constraining to ASCII keeps +// the length cap consistent across TS / Python / Go (where String.length / +// len() / len() otherwise diverge for multi-byte input). +const PRINTABLE_ASCII_REGEX = /^[\x20-\x7e]+$/; + export const ResourceInfoSchema = z.object({ url: NonEmptyString, description: z.string().optional(), mimeType: z.string().optional(), + serviceName: z.string().min(1).max(32).regex(PRINTABLE_ASCII_REGEX).optional(), + tags: z.array(z.string().min(1).max(32).regex(PRINTABLE_ASCII_REGEX)).max(5).optional(), + iconUrl: z.string().max(2048).optional(), }); export type ResourceInfo = z.infer; diff --git a/typescript/packages/core/src/server/hookPolicy.ts b/typescript/packages/core/src/server/hookPolicy.ts new file mode 100644 index 0000000000..ffe216d87e --- /dev/null +++ b/typescript/packages/core/src/server/hookPolicy.ts @@ -0,0 +1,326 @@ +import type { SettleResponse } from "../types/facilitator"; +import type { PaymentRequirements } from "../types/payments"; +import { deepEqual } from "../utils"; + +/** + * True when a string field is treated as unset and may be filled by `enrichPaymentRequiredResponse`. + * + * @param value - Candidate string from `PaymentRequirements` (e.g. `payTo`, `amount`, `asset`) + * @returns Whether the field counts as vacant (empty or whitespace-only) + */ +export function isVacantStringField(value: string): boolean { + return value.trim() === ""; +} + +/** + * Deep snapshot of `accepts` entries before any `enrichPaymentRequiredResponse` runs. + * + * @param requirements - Payment requirement rows to clone + * @returns Cloned requirements suitable as an immutable baseline for policy checks + */ +export function snapshotPaymentRequirementsList( + requirements: PaymentRequirements[], +): PaymentRequirements[] { + return requirements.map(req => ({ + ...req, + extra: structuredClone(req.extra), + })); +} + +/** + * After extension enrichment, each `accepts[i]` must still match the baseline except that + * **`payTo`**, **`amount`**, and **`asset`** may change only when the baseline value is vacant + * (whitespace-only string). **`scheme`**, **`network`**, and **`maxTimeoutSeconds`** are never + * writable by extensions. **`extra`** may gain new keys; values for keys present in the baseline + * must be unchanged (deep-equal). + * + * @param baseline - Snapshot taken before any enrich hooks for this response + * @param current - Live `accepts` entries after an extension enrich step + * @param extensionKey - Registered extension key (for error messages) + * @returns Nothing; throws if the policy is violated + */ +export function assertAcceptsAllowlistedAfterExtensionEnrich( + baseline: PaymentRequirements[], + current: PaymentRequirements[], + extensionKey: string, +): void { + if (baseline.length !== current.length) { + throw new Error( + `[x402] extension "${extensionKey}" violated accepts mutation policy: accepts length changed (${baseline.length} → ${current.length})`, + ); + } + + for (let i = 0; i < baseline.length; i++) { + const b = baseline[i]; + const c = current[i]; + + if (b.scheme !== c.scheme || b.network !== c.network) { + throw new Error( + `[x402] extension "${extensionKey}" violated accepts mutation policy: scheme/network are immutable (index ${i})`, + ); + } + if (b.maxTimeoutSeconds !== c.maxTimeoutSeconds) { + throw new Error( + `[x402] extension "${extensionKey}" violated accepts mutation policy: maxTimeoutSeconds is immutable (index ${i})`, + ); + } + + for (const field of ["payTo", "amount", "asset"] as const) { + const bv = b[field]; + const cv = c[field]; + if (!isVacantStringField(bv) && cv !== bv) { + throw new Error( + `[x402] extension "${extensionKey}" violated accepts mutation policy: "${field}" may only be set when the resource left it vacant (""); non-vacant values are immutable (index ${i})`, + ); + } + } + + for (const key of Object.keys(b.extra)) { + if (!Object.prototype.hasOwnProperty.call(c.extra, key)) { + throw new Error( + `[x402] extension "${extensionKey}" violated accepts mutation policy: extra["${key}"] was removed (index ${i})`, + ); + } + if (!deepEqual(c.extra[key], b.extra[key])) { + throw new Error( + `[x402] extension "${extensionKey}" violated accepts mutation policy: extra["${key}"] may not be changed (index ${i})`, + ); + } + } + } +} + +/** + * Ensures scheme 402 enrichment only adds `extra` keys to matching accepts. + * + * @param baseline - Snapshot before the scheme enrich step + * @param current - Live `accepts` entries after scheme enrichment + * @param scheme - Scheme whose hook was invoked + * @param network - Network whose hook was invoked + */ +export function assertAcceptsAdditiveExtraAfterSchemeEnrich( + baseline: PaymentRequirements[], + current: PaymentRequirements[], + scheme: string, + network: string, +): void { + if (baseline.length !== current.length) { + throw new Error( + `[x402] scheme "${scheme}" violated accepts mutation policy: accepts length changed (${baseline.length} → ${current.length})`, + ); + } + + for (let i = 0; i < baseline.length; i++) { + const b = baseline[i]; + const c = current[i]; + const isMatchingAccept = b.scheme === scheme && b.network === network; + + if (b.scheme !== c.scheme || b.network !== c.network) { + throw new Error( + `[x402] scheme "${scheme}" violated accepts mutation policy: scheme/network are immutable (index ${i})`, + ); + } + if ( + b.maxTimeoutSeconds !== c.maxTimeoutSeconds || + b.payTo !== c.payTo || + b.amount !== c.amount || + b.asset !== c.asset + ) { + throw new Error( + `[x402] scheme "${scheme}" violated accepts mutation policy: payment terms are immutable (index ${i})`, + ); + } + + for (const key of Object.keys(b.extra)) { + if (!Object.prototype.hasOwnProperty.call(c.extra, key)) { + throw new Error( + `[x402] scheme "${scheme}" violated accepts mutation policy: extra["${key}"] was removed (index ${i})`, + ); + } + if (!deepEqual(c.extra[key], b.extra[key])) { + throw new Error( + `[x402] scheme "${scheme}" violated accepts mutation policy: extra["${key}"] may not be changed (index ${i})`, + ); + } + } + + if (!isMatchingAccept && Object.keys(c.extra).length !== Object.keys(b.extra).length) { + throw new Error( + `[x402] scheme "${scheme}" violated accepts mutation policy: only matching accepts may receive new extra fields (index ${i})`, + ); + } + } +} + +/** + * Immutable subset of {@link SettleResponse} compared across settlement extension enrich. + */ +export type SettleResponseCoreSnapshot = Pick< + SettleResponse, + "success" | "transaction" | "network" | "amount" | "payer" | "errorReason" | "errorMessage" +>; + +/** + * Captures facilitator-settled fields that extensions must not rewrite. + * + * @param result - Settlement response from the facilitator + * @returns Plain snapshot of core fields for later comparison + */ +export function snapshotSettleResponseCore(result: SettleResponse): SettleResponseCoreSnapshot { + return { + success: result.success, + transaction: result.transaction, + network: result.network, + amount: result.amount, + payer: result.payer, + errorReason: result.errorReason, + errorMessage: result.errorMessage, + }; +} + +/** + * Ensures `enrichSettlementResponse` did not rewrite facilitator outcome fields; only + * `extensions` may be populated via the merger (in addition to in-place adds on `extensions`). + * + * @param before - Snapshot taken before extension settlement enrich + * @param after - Live settlement result after an extension enrich step + * @param extensionKey - Registered extension key (for error messages) + * @returns Nothing; throws if a core field changed + */ +export function assertSettleResponseCoreUnchanged( + before: SettleResponseCoreSnapshot, + after: SettleResponse, + extensionKey: string, +): void { + const keys: (keyof SettleResponseCoreSnapshot)[] = [ + "success", + "transaction", + "network", + "amount", + "payer", + "errorReason", + "errorMessage", + ]; + for (const k of keys) { + if (!deepEqual(after[k], before[k])) { + throw new Error( + `[x402] extension "${extensionKey}" violated settlement mutation policy: field "${String(k)}" is immutable after facilitator settle`, + ); + } + } +} + +/** + * Ensures scheme settlement-payload enrichment only adds server-owned fields. + * + * @param payload - Existing scheme payload before enrichment + * @param enrichment - Fields returned by the scheme enrichment hook + * @param callerLabel - Hook source label used in policy error messages + */ +export function assertAdditivePayloadEnrichment( + payload: Record, + enrichment: Record, + callerLabel: string, +): void { + for (const key of Object.keys(enrichment)) { + if (!Object.prototype.hasOwnProperty.call(payload, key)) continue; + + throw new Error( + `[x402] ${callerLabel} violated settlement payload enrichment policy: "${key}" already exists on the client payload`, + ); + } +} + +/** + * Whether `value` is a plain object record (not null or an array). + * + * @param value - Value to inspect + * @returns True when `value` is a non-null object and not an array + */ +function isPlainRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null && !Array.isArray(value); +} + +/** + * Ensures scheme response enrichment only adds new `extra` fields, including nested fields + * below existing objects. + * + * @param extra - Existing settlement extra fields + * @param enrichment - Fields returned by the scheme response enrichment hook + * @param callerLabel - Hook label used in policy error messages + */ +export function assertAdditiveSettlementExtra( + extra: Record, + enrichment: Record, + callerLabel: string, +): void { + assertAdditiveRecord(extra, enrichment, callerLabel, "extra"); +} + +/** + * Merges server-owned settlement response fields after additive policy validation. + * + * @param extra - Existing settlement extra fields + * @param enrichment - Additive fields returned by the scheme response enrichment hook + * @returns A merged extra object + */ +export function mergeAdditiveSettlementExtra( + extra: Record, + enrichment: Record, +): Record { + return mergeAdditiveRecord(extra, enrichment); +} + +/** + * Throws if enrichment would overwrite or collide with keys already present on `target`, + * recursively for nested plain objects. + * + * @param target - Existing record fields before enrichment + * @param enrichment - Fields proposed by the hook to merge into `target` + * @param callerLabel - Hook label used in policy error messages + * @param path - Dot-style path segment for nested keys (for error messages) + */ +function assertAdditiveRecord( + target: Record, + enrichment: Record, + callerLabel: string, + path: string, +): void { + for (const [key, enrichmentValue] of Object.entries(enrichment)) { + const nextPath = `${path}["${key}"]`; + if (!Object.prototype.hasOwnProperty.call(target, key)) continue; + + const targetValue = target[key]; + if (isPlainRecord(targetValue) && isPlainRecord(enrichmentValue)) { + assertAdditiveRecord(targetValue, enrichmentValue, callerLabel, nextPath); + continue; + } + + throw new Error( + `[x402] ${callerLabel} violated settlement response enrichment policy: ${nextPath} already exists on the settlement result`, + ); + } +} + +/** + * Deep-merges `enrichment` into `target`, recursively merging nested plain objects. + * + * @param target - Base record to merge into + * @param enrichment - Additive fields to merge (caller must enforce additive policy first) + * @returns Shallow copy of `target` with `enrichment` applied + */ +function mergeAdditiveRecord( + target: Record, + enrichment: Record, +): Record { + const merged = { ...target }; + for (const [key, enrichmentValue] of Object.entries(enrichment)) { + const targetValue = merged[key]; + if (isPlainRecord(targetValue) && isPlainRecord(enrichmentValue)) { + merged[key] = mergeAdditiveRecord(targetValue, enrichmentValue); + continue; + } + merged[key] = enrichmentValue; + } + return merged; +} diff --git a/typescript/packages/core/src/server/index.ts b/typescript/packages/core/src/server/index.ts index 086e4325a9..8b1a80d139 100644 --- a/typescript/packages/core/src/server/index.ts +++ b/typescript/packages/core/src/server/index.ts @@ -8,14 +8,39 @@ export type { SettleContext, SettleResultContext, SettleFailureContext, + VerifiedPaymentCanceledContext, + VerifiedPaymentCancellationReason, + VerifiedPaymentCancelOptions, + PaymentCancellationDispatcher, SettlementOverrides, + SkipHandlerDirective, + ResourceVerifyRespone, BeforeVerifyHook, AfterVerifyHook, OnVerifyFailureHook, BeforeSettleHook, AfterSettleHook, OnSettleFailureHook, + OnVerifiedPaymentCanceledHook, } from "./x402ResourceServer"; +export type { + SchemeEnrichPaymentRequiredResponseHook, + SchemePaymentRequiredContext, + SchemeEnrichSettlementPayloadHook, + SchemeEnrichSettlementResponseHook, +} from "../types/mechanisms"; + +export { + assertAdditivePayloadEnrichment, + assertAdditiveSettlementExtra, + assertAcceptsAdditiveExtraAfterSchemeEnrich, + assertAcceptsAllowlistedAfterExtensionEnrich, + assertSettleResponseCoreUnchanged, + isVacantStringField, + snapshotPaymentRequirementsList, + snapshotSettleResponseCore, +} from "./hookPolicy"; +export type { SettleResponseCoreSnapshot } from "./hookPolicy"; export { HTTPFacilitatorClient } from "../http/httpFacilitatorClient"; export type { FacilitatorClient, FacilitatorConfig } from "../http/httpFacilitatorClient"; @@ -25,6 +50,7 @@ export { x402HTTPResourceServer, RouteConfigurationError, SETTLEMENT_OVERRIDES_HEADER, + checkIfBazaarNeeded, } from "../http/x402HTTPResourceServer"; export type { HTTPRequestContext, diff --git a/typescript/packages/core/src/server/x402ResourceServer.ts b/typescript/packages/core/src/server/x402ResourceServer.ts index 14f8aab79e..01965382a1 100644 --- a/typescript/packages/core/src/server/x402ResourceServer.ts +++ b/typescript/packages/core/src/server/x402ResourceServer.ts @@ -11,9 +11,20 @@ import { PaymentRequired, ResourceInfo, } from "../types/payments"; -import { SchemeNetworkServer } from "../types/mechanisms"; -import { Price, Network, ResourceServerExtension, VerifyError } from "../types"; +import { SchemeNetworkServer, SchemePaymentRequiredContext } from "../types/mechanisms"; +import { Price, Network, ResourceServerExtension, ResourceServerExtensionHooks } from "../types"; +import type { DeepReadonly } from "../types/readonly"; import { deepEqual, findByNetworkAndScheme } from "../utils"; +import { + assertAcceptsAllowlistedAfterExtensionEnrich, + assertAcceptsAdditiveExtraAfterSchemeEnrich, + assertAdditivePayloadEnrichment, + assertAdditiveSettlementExtra, + assertSettleResponseCoreUnchanged, + mergeAdditiveSettlementExtra, + snapshotPaymentRequirementsList, + snapshotSettleResponseCore, +} from "./hookPolicy"; import { FacilitatorClient, HTTPFacilitatorClient } from "../http/httpFacilitatorClient"; import { x402Version } from ".."; @@ -23,7 +34,12 @@ import { x402Version } from ".."; */ export interface ResourceConfig { scheme: string; - payTo: string; // Payment recipient address + /** + * Payment recipient. Use a **vacant** value (`""` or whitespace-only) when an extension must + * fill `payTo` during `enrichPaymentRequiredResponse`; non-vacant values are **immutable** there + * so extensions cannot redirect funds to an arbitrary address. + */ + payTo: string; price: Price; network: Network; maxTimeoutSeconds?: number; @@ -31,9 +47,12 @@ export interface ResourceConfig { } /** - * Lifecycle Hook Context Interfaces + * Context for `enrichPaymentRequiredResponse`. Extensions may merge extension payload via the + * return value. In-place edits to `paymentRequiredResponse.accepts` are **allowlisted** only + * (see {@link assertAcceptsAllowlistedAfterExtensionEnrich}): `scheme`, `network`, and + * `maxTimeoutSeconds` are immutable; `payTo`, `amount`, and `asset` may change only when the + * baseline value was vacant; `extra` may add keys but must not change or remove baseline keys. */ - export interface PaymentRequiredContext { requirements: PaymentRequirements[]; resourceInfo: ResourceInfo; @@ -42,42 +61,81 @@ export interface PaymentRequiredContext { transportContext?: unknown; } +/** + * Verify / settle lifecycle hook context: treat as **read-only** for core protocol fields. + * Control flow uses **abort** / **recover** return values only, not in-place mutation. + */ export interface VerifyContext { - paymentPayload: PaymentPayload; - requirements: PaymentRequirements; + paymentPayload: DeepReadonly; + requirements: DeepReadonly; + declaredExtensions: DeepReadonly>; + transportContext?: unknown; } export interface VerifyResultContext extends VerifyContext { - result: VerifyResponse; + result: DeepReadonly; } +/** + * Optional acknowledgement body returned to the caller when an `AfterVerifyHook` + * requests that the resource handler be skipped for a self-contained operation + * (e.g. cooperative refund). Travels in-process only — never on the facilitator wire. + */ +export interface SkipHandlerDirective { + contentType?: string; + body?: unknown; +} + +export type ResourceVerifyRespone = VerifyResponse & { + skipHandler?: SkipHandlerDirective; +}; + export interface VerifyFailureContext extends VerifyContext { error: Error; } export interface SettleContext { - paymentPayload: PaymentPayload; - requirements: PaymentRequirements; + paymentPayload: DeepReadonly; + requirements: DeepReadonly; + declaredExtensions: DeepReadonly>; + transportContext?: unknown; } export interface SettleResultContext extends SettleContext { - result: SettleResponse; - transportContext?: unknown; + result: DeepReadonly; } export interface SettleFailureContext extends SettleContext { error: Error; } -/** - * Lifecycle Hook Type Definitions - */ +export type VerifiedPaymentCancellationReason = "handler_threw" | "handler_failed"; + +export interface VerifiedPaymentCanceledContext extends SettleContext { + reason: VerifiedPaymentCancellationReason; + error?: unknown; + responseStatus?: number; +} + +export interface VerifiedPaymentCancelOptions { + reason: VerifiedPaymentCancellationReason; + error?: unknown; + responseStatus?: number; +} + +export interface PaymentCancellationDispatcher { + cancel(options: VerifiedPaymentCancelOptions): Promise; +} export type BeforeVerifyHook = ( context: VerifyContext, -) => Promise; +) => Promise< + void | { abort: true; reason: string; message?: string } | { skip: true; result: VerifyResponse } +>; -export type AfterVerifyHook = (context: VerifyResultContext) => Promise; +export type AfterVerifyHook = ( + context: VerifyResultContext, +) => Promise; export type OnVerifyFailureHook = ( context: VerifyFailureContext, @@ -85,7 +143,9 @@ export type OnVerifyFailureHook = ( export type BeforeSettleHook = ( context: SettleContext, -) => Promise; +) => Promise< + void | { abort: true; reason: string; message?: string } | { skip: true; result: SettleResponse } +>; export type AfterSettleHook = (context: SettleResultContext) => Promise; @@ -93,6 +153,10 @@ export type OnSettleFailureHook = ( context: SettleFailureContext, ) => Promise; +export type OnVerifiedPaymentCanceledHook = ( + context: VerifiedPaymentCanceledContext, +) => Promise; + /** * Optional overrides for settlement parameters. * Used to support partial settlement (e.g., upto scheme billing by actual usage). @@ -161,6 +225,24 @@ export function resolveSettlementOverrideAmount( return rawAmount; } +type HookAdapterHandles = { + beforeVerify?: BeforeVerifyHook; + afterVerify?: AfterVerifyHook; + onVerifyFailure?: OnVerifyFailureHook; + beforeSettle?: BeforeSettleHook; + afterSettle?: AfterSettleHook; + onSettleFailure?: OnSettleFailureHook; + onVerifiedPaymentCanceled?: OnVerifiedPaymentCanceledHook; +}; + +type ExtensionAdapterHandles = HookAdapterHandles; +type SchemeAdapterHandles = HookAdapterHandles; + +/** Keys shared by adapter handles and manual `*Hooks` arrays on the server. */ +type ResourceServerHookPhase = keyof HookAdapterHandles; + +type ResourceServerManualHookArrayKey = `${ResourceServerHookPhase}Hooks`; + /** * Core x402 protocol server for resource protection * Transport-agnostic implementation of the x402 payment protocol @@ -168,11 +250,13 @@ export function resolveSettlementOverrideAmount( export class x402ResourceServer { private facilitatorClients: FacilitatorClient[]; private registeredServerSchemes: Map> = new Map(); + private schemeHookAdapters: Map> = new Map(); private supportedResponsesMap: Map>> = new Map(); private facilitatorClientsMap: Map>> = new Map(); private registeredExtensions: Map = new Map(); + private extensionHookAdapters = new Map(); private beforeVerifyHooks: BeforeVerifyHook[] = []; private afterVerifyHooks: AfterVerifyHook[] = []; @@ -180,6 +264,7 @@ export class x402ResourceServer { private beforeSettleHooks: BeforeSettleHook[] = []; private afterSettleHooks: AfterSettleHook[] = []; private onSettleFailureHooks: OnSettleFailureHook[] = []; + private onVerifiedPaymentCanceledHooks: OnVerifiedPaymentCanceledHook[] = []; /** * Creates a new x402ResourceServer instance. @@ -214,8 +299,34 @@ export class x402ResourceServer { } const serverByScheme = this.registeredServerSchemes.get(network)!; - if (!serverByScheme.has(server.scheme)) { - serverByScheme.set(server.scheme, server); + serverByScheme.set(server.scheme, server); + + if (!this.schemeHookAdapters.has(network)) { + this.schemeHookAdapters.set(network, new Map()); + } + + const hooksByScheme = this.schemeHookAdapters.get(network)!; + const hooks = server.schemeHooks; + if (!hooks) { + hooksByScheme.delete(server.scheme); + return this; + } + + const handles: SchemeAdapterHandles = {}; + if (hooks.onBeforeVerify) handles.beforeVerify = hooks.onBeforeVerify; + if (hooks.onAfterVerify) handles.afterVerify = hooks.onAfterVerify; + if (hooks.onVerifyFailure) handles.onVerifyFailure = hooks.onVerifyFailure; + if (hooks.onBeforeSettle) handles.beforeSettle = hooks.onBeforeSettle; + if (hooks.onAfterSettle) handles.afterSettle = hooks.onAfterSettle; + if (hooks.onSettleFailure) handles.onSettleFailure = hooks.onSettleFailure; + if (hooks.onVerifiedPaymentCanceled) { + handles.onVerifiedPaymentCanceled = hooks.onVerifiedPaymentCanceled; + } + + if (Object.keys(handles).length > 0) { + hooksByScheme.set(server.scheme, handles); + } else { + hooksByScheme.delete(server.scheme); } return this; @@ -233,13 +344,75 @@ export class x402ResourceServer { } /** - * Registers a resource service extension that can enrich extension declarations. + * Returns the decimal precision for the asset specified in the given payment requirements. + * Looks up the registered scheme for the network and delegates to its getAssetDecimals + * method if available. Falls back to 6 (standard for USDC stablecoins) when the scheme + * does not implement getAssetDecimals or is not registered. * - * @param extension - The extension to register - * @returns The x402ResourceServer instance for chaining + * @param requirements - The payment requirements containing scheme, network, and asset + * @returns The number of decimal places for the asset + */ + getAssetDecimalsForRequirements(requirements: PaymentRequirements): number { + const scheme = findByNetworkAndScheme( + this.registeredServerSchemes, + requirements.scheme, + requirements.network as Network, + ); + return ( + scheme?.getAssetDecimals?.(requirements.asset ?? "", requirements.network as Network) ?? 6 + ); + } + + /** + * Registers a resource server extension (enrichment and optional verify/settle hooks). + * Re-registering the same key overwrites; omitting `hooks` removes adapter handles for that key. + * + * @param extension - Extension definition including `key` and optional `hooks` + * @returns This server instance for chaining */ registerExtension(extension: ResourceServerExtension): this { this.registeredExtensions.set(extension.key, extension); + const extensionKey = extension.key; + const extensionHooks = extension.hooks; + if (!extensionHooks) { + this.extensionHookAdapters.delete(extensionKey); + return this; + } + const handles: ExtensionAdapterHandles = {}; + + const bindExtensionHookAdapter = < + ExtKey extends keyof ResourceServerExtensionHooks, + Phase extends ResourceServerHookPhase, + >( + extensionHookKey: ExtKey, + adapterPhase: Phase, + ): void => { + const impl = extensionHooks[extensionHookKey]; + if (!impl) return; + + type AdapterContext = Parameters>[0]; + + handles[adapterPhase] = (async (ctx: AdapterContext) => { + if (ctx.declaredExtensions[extensionKey] === undefined) return; + return (impl as (declaration: unknown, context: AdapterContext) => Promise)( + ctx.declaredExtensions[extensionKey], + ctx, + ); + }) as ExtensionAdapterHandles[Phase]; + }; + + bindExtensionHookAdapter("onBeforeVerify", "beforeVerify"); + bindExtensionHookAdapter("onAfterVerify", "afterVerify"); + bindExtensionHookAdapter("onVerifyFailure", "onVerifyFailure"); + bindExtensionHookAdapter("onBeforeSettle", "beforeSettle"); + bindExtensionHookAdapter("onAfterSettle", "afterSettle"); + bindExtensionHookAdapter("onSettleFailure", "onSettleFailure"); + bindExtensionHookAdapter("onVerifiedPaymentCanceled", "onVerifiedPaymentCanceled"); + if (Object.keys(handles).length > 0) { + this.extensionHookAdapters.set(extensionKey, handles); + } else { + this.extensionHookAdapters.delete(extensionKey); + } return this; } @@ -279,7 +452,12 @@ export class x402ResourceServer { const extension = this.registeredExtensions.get(key); if (extension?.enrichDeclaration) { - enriched[key] = extension.enrichDeclaration(declaration, transportContext); + try { + enriched[key] = extension.enrichDeclaration(declaration, transportContext); + } catch (error) { + this.warnExtensionHookFailure(key, "enrichDeclaration", error); + enriched[key] = declaration; + } } else { enriched[key] = declaration; } @@ -358,6 +536,17 @@ export class x402ResourceServer { return this; } + /** + * Register a hook to execute when verified payment work is canceled before settlement. + * + * @param hook - The hook function to register + * @returns The x402ResourceServer instance for chaining + */ + onVerifiedPaymentCanceled(hook: OnVerifiedPaymentCanceledHook): x402ResourceServer { + this.onVerifiedPaymentCanceledHooks.push(hook); + return this; + } + /** * Initialize by fetching supported kinds from all facilitators * Creates mappings for supported responses and facilitator clients @@ -540,13 +729,9 @@ export class x402ResourceServer { }; // Delegate to the implementation for scheme-specific enhancements - // Note: enhancePaymentRequirements expects x402Version in the kind, so we add it back const requirement = await SchemeNetworkServer.enhancePaymentRequirements( baseRequirements, - { - ...supportedKind, - x402Version, - }, + supportedKind, facilitatorExtensions, ); @@ -607,6 +792,7 @@ export class x402ResourceServer { * @param error - Error message * @param extensions - Optional declared extensions (for per-key enrichment) * @param transportContext - Optional transport-specific context (e.g., HTTP request, MCP tool context) + * @param paymentPayload - Optional failed payment payload for response-time scheme enrichment * @returns Payment required response object */ async createPaymentRequiredResponse( @@ -615,13 +801,21 @@ export class x402ResourceServer { error?: string, extensions?: Record, transportContext?: unknown, + paymentPayload?: PaymentPayload, ): Promise { + const acceptsClone = requirements.map(req => ({ + ...req, + extra: structuredClone(req.extra), + })); + let workingAccepts = acceptsClone; + let baselineAccepts = snapshotPaymentRequirementsList(workingAccepts); + // V2 response with resource at top level let response: PaymentRequired = { x402Version: 2, error, resource: resourceInfo, - accepts: requirements as PaymentRequirements[], + accepts: workingAccepts, }; // Add extensions if provided @@ -629,6 +823,39 @@ export class x402ResourceServer { response.extensions = extensions; } + for (let i = 0; i < workingAccepts.length; i++) { + const accept = workingAccepts[i]; + const scheme = findByNetworkAndScheme( + this.registeredServerSchemes, + accept.scheme, + accept.network as Network, + ); + if (!scheme?.enrichPaymentRequiredResponse) { + continue; + } + + const context: SchemePaymentRequiredContext = { + requirements: workingAccepts, + paymentPayload, + resourceInfo, + error, + paymentRequiredResponse: response, + transportContext, + }; + const enrichedAccepts = await scheme.enrichPaymentRequiredResponse(context); + if (enrichedAccepts !== undefined) { + workingAccepts = enrichedAccepts; + response.accepts = workingAccepts; + } + assertAcceptsAdditiveExtraAfterSchemeEnrich( + baselineAccepts, + response.accepts, + accept.scheme, + accept.network, + ); + baselineAccepts = snapshotPaymentRequirementsList(response.accepts); + } + // Let declared extensions add data to PaymentRequired response if (extensions) { for (const [key, declaration] of Object.entries(extensions)) { @@ -636,7 +863,7 @@ export class x402ResourceServer { if (extension?.enrichPaymentRequiredResponse) { try { const context: PaymentRequiredContext = { - requirements, + requirements: workingAccepts, resourceInfo, error, paymentRequiredResponse: response, @@ -653,11 +880,10 @@ export class x402ResourceServer { response.extensions[key] = extensionData; } } catch (error) { - console.error( - `Error in enrichPaymentRequiredResponse hook for extension ${key}:`, - error, - ); + this.warnExtensionHookFailure(key, "enrichPaymentRequiredResponse", error); } + assertAcceptsAllowlistedAfterExtensionEnrich(baselineAccepts, workingAccepts, key); + baselineAccepts = snapshotPaymentRequirementsList(workingAccepts); } } } @@ -666,23 +892,40 @@ export class x402ResourceServer { } /** - * Verify a payment against requirements + * Verifies a payment against requirements, running manual and in-use extension hooks. * - * @param paymentPayload - The payment payload to verify - * @param requirements - The payment requirements - * @returns Verification response + * @param paymentPayload - Signed payment payload from the client + * @param requirements - Requirements matched to the payload + * @param declaredExtensions - Optional per-extension declarations for the request + * @param transportContext - Optional transport-specific context (e.g. HTTP, MCP) + * @returns Facilitator verify outcome (optionally carrying a `skipHandler` directive), + * or abort/recovery as driven by hooks */ async verifyPayment( paymentPayload: PaymentPayload, requirements: PaymentRequirements, - ): Promise { + declaredExtensions?: Record, + transportContext?: unknown, + ): Promise { + const resolvedDeclaredExtensions = declaredExtensions ?? {}; + const extensionKeysInUse = Object.keys(resolvedDeclaredExtensions); + const matchedScheme = { + network: requirements.network as Network, + scheme: requirements.scheme, + }; + const context: VerifyContext = { paymentPayload, requirements, + declaredExtensions: resolvedDeclaredExtensions, + transportContext, }; - // Execute beforeVerify hooks - for (const hook of this.beforeVerifyHooks) { + for (const { label, hook } of this.getLabeledHooks( + "beforeVerify", + extensionKeysInUse, + matchedScheme, + )) { try { const result = await hook(context); if (result && "abort" in result && result.abort) { @@ -692,12 +935,16 @@ export class x402ResourceServer { invalidMessage: result.message, }; } + if (result && "skip" in result && result.skip) { + return this.runAfterVerifyHooks( + result.result, + context, + extensionKeysInUse, + matchedScheme, + ); + } } catch (error) { - throw new VerifyError(400, { - isValid: false, - invalidReason: "before_verify_hook_error", - invalidMessage: error instanceof Error ? error.message : "", - }); + this.warnResourceServerHookFailure("beforeVerify", label, error); } } @@ -737,28 +984,25 @@ export class x402ResourceServer { verifyResult = await facilitatorClient.verify(paymentPayload, requirements); } - // Execute afterVerify hooks - const resultContext: VerifyResultContext = { - ...context, - result: verifyResult, - }; - - for (const hook of this.afterVerifyHooks) { - await hook(resultContext); - } - - return verifyResult; + return this.runAfterVerifyHooks(verifyResult, context, extensionKeysInUse, matchedScheme); } catch (error) { const failureContext: VerifyFailureContext = { ...context, error: error as Error, }; - // Execute onVerifyFailure hooks - for (const hook of this.onVerifyFailureHooks) { - const result = await hook(failureContext); - if (result && "recovered" in result && result.recovered) { - return result.result; + for (const { label, hook } of this.getLabeledHooks( + "onVerifyFailure", + extensionKeysInUse, + matchedScheme, + )) { + try { + const result = await hook(failureContext); + if (result && "recovered" in result && result.recovered) { + return result.result; + } + } catch (error) { + this.warnResourceServerHookFailure("onVerifyFailure", label, error); } } @@ -766,6 +1010,40 @@ export class x402ResourceServer { } } + /** + * Create cancellation controls for a verified payment attempt. + * + * @param paymentPayload - Signed payment payload from the client + * @param requirements - Requirements matched to the payload + * @param declaredExtensions - Optional per-extension declarations for the request + * @param transportContext - Optional transport-specific context + * @returns Cancellation controls for the verified payment attempt + */ + createPaymentCancellationDispatcher( + paymentPayload: PaymentPayload, + requirements: PaymentRequirements, + declaredExtensions?: Record, + transportContext?: unknown, + ): PaymentCancellationDispatcher { + const resolvedDeclaredExtensions = declaredExtensions ?? {}; + let cancelPromise: Promise | undefined; + + return { + cancel: (options: VerifiedPaymentCancelOptions) => { + if (!cancelPromise) { + cancelPromise = this.dispatchVerifiedPaymentCanceled( + paymentPayload, + requirements, + resolvedDeclaredExtensions, + options, + transportContext, + ); + } + return cancelPromise; + }, + }; + } + /** * Settle a verified payment * @@ -783,6 +1061,9 @@ export class x402ResourceServer { transportContext?: unknown, settlementOverrides?: SettlementOverrides, ): Promise { + const resolvedDeclaredExtensions = declaredExtensions ?? {}; + const extensionKeysInUse = Object.keys(resolvedDeclaredExtensions); + // Apply settlement overrides (e.g., partial settlement for upto scheme) let effectiveRequirements = requirements; if (settlementOverrides?.amount !== undefined) { @@ -802,10 +1083,19 @@ export class x402ResourceServer { const context: SettleContext = { paymentPayload, requirements: effectiveRequirements, + declaredExtensions: resolvedDeclaredExtensions, + transportContext, + }; + const matchedScheme = { + network: effectiveRequirements.network as Network, + scheme: effectiveRequirements.scheme, }; - // Execute beforeSettle hooks - for (const hook of this.beforeSettleHooks) { + for (const { label, hook } of this.getLabeledHooks( + "beforeSettle", + extensionKeysInUse, + matchedScheme, + )) { try { const result = await hook(context); if (result && "abort" in result && result.abort) { @@ -817,21 +1107,56 @@ export class x402ResourceServer { network: requirements.network, }); } + if (result && "skip" in result && result.skip) { + const settleResult = result.result; + const skipResultContext: SettleResultContext = { + ...context, + result: settleResult, + transportContext, + }; + for (const { label, hook } of this.getLabeledHooks( + "afterSettle", + extensionKeysInUse, + matchedScheme, + )) { + try { + await hook(skipResultContext); + } catch (error) { + this.warnResourceServerHookFailure("afterSettle", label, error); + } + } + await this.enrichSettlementResponse( + settleResult, + skipResultContext, + resolvedDeclaredExtensions, + matchedScheme, + ); + return settleResult; + } } catch (error) { if (error instanceof SettleError) { throw error; } - throw new SettleError(400, { - success: false, - errorReason: "before_settle_hook_error", - errorMessage: error instanceof Error ? error.message : "", - transaction: "", - network: requirements.network, - }); + this.warnResourceServerHookFailure("beforeSettle", label, error); } } try { + const scheme = findByNetworkAndScheme( + this.registeredServerSchemes, + matchedScheme.scheme, + matchedScheme.network, + ); + const payloadEnrichmentHook = scheme?.enrichSettlementPayload; + if (payloadEnrichmentHook) { + const label = `scheme "${matchedScheme.scheme}" enrichSettlementPayload`; + const enrichment = await payloadEnrichmentHook(context); + if (enrichment !== undefined) { + assertAdditivePayloadEnrichment(paymentPayload.payload, enrichment, label); + paymentPayload.payload = { ...paymentPayload.payload, ...enrichment }; + } + } + // Find the facilitator that supports this payment type const facilitatorClient = this.getFacilitatorClient( paymentPayload.x402Version, @@ -871,36 +1196,27 @@ export class x402ResourceServer { const resultContext: SettleResultContext = { ...context, result: settleResult, - transportContext, }; - for (const hook of this.afterSettleHooks) { - await hook(resultContext); - } - - // Let declared extensions add data to settlement response - if (declaredExtensions) { - for (const [key, declaration] of Object.entries(declaredExtensions)) { - const extension = this.registeredExtensions.get(key); - if (extension?.enrichSettlementResponse) { - try { - const extensionData = await extension.enrichSettlementResponse( - declaration, - resultContext, - ); - if (extensionData !== undefined) { - if (!settleResult.extensions) { - settleResult.extensions = {}; - } - settleResult.extensions[key] = extensionData; - } - } catch (error) { - console.error(`Error in enrichSettlementResponse hook for extension ${key}:`, error); - } - } + for (const { label, hook } of this.getLabeledHooks( + "afterSettle", + extensionKeysInUse, + matchedScheme, + )) { + try { + await hook(resultContext); + } catch (error) { + this.warnResourceServerHookFailure("afterSettle", label, error); } } + await this.enrichSettlementResponse( + settleResult, + resultContext, + resolvedDeclaredExtensions, + matchedScheme, + ); + return settleResult; } catch (error) { const failureContext: SettleFailureContext = { @@ -908,11 +1224,18 @@ export class x402ResourceServer { error: error as Error, }; - // Execute onSettleFailure hooks - for (const hook of this.onSettleFailureHooks) { - const result = await hook(failureContext); - if (result && "recovered" in result && result.recovered) { - return result.result; + for (const { label, hook } of this.getLabeledHooks( + "onSettleFailure", + extensionKeysInUse, + matchedScheme, + )) { + try { + const result = await hook(failureContext); + if (result && "recovered" in result && result.recovered) { + return result.result; + } + } catch (error) { + this.warnResourceServerHookFailure("onSettleFailure", label, error); } } @@ -952,69 +1275,224 @@ export class x402ResourceServer { } /** - * Process a payment request + * Logs a warning when a manual or extension adapter lifecycle hook throws. * - * @param paymentPayload - Optional payment payload if provided - * @param resourceConfig - Configuration for the protected resource - * @param resourceInfo - Information about the resource being accessed - * @param extensions - Optional extensions to include in the response - * @returns Processing result + * @param phase - Lifecycle phase name (e.g. `beforeVerify`) + * @param label - Hook source label from {@link getLabeledHooks} (manual index or extension key) + * @param error - Thrown value or rejection reason */ - async processPaymentRequest( - paymentPayload: PaymentPayload | null, - resourceConfig: ResourceConfig, - resourceInfo: ResourceInfo, - extensions?: Record, - ): Promise<{ - success: boolean; - requiresPayment?: PaymentRequired; - verificationResult?: VerifyResponse; - settlementResult?: SettleResponse; - error?: string; - }> { - const requirements = await this.buildPaymentRequirements(resourceConfig); - - if (!paymentPayload) { - return { - success: false, - requiresPayment: await this.createPaymentRequiredResponse( - requirements, - resourceInfo, - "Payment required", - extensions, - ), - }; + private warnResourceServerHookFailure(phase: string, label: string, error: unknown): void { + const detail = error instanceof Error ? error.message : String(error); + console.warn(`[x402] Resource server ${phase} hook threw (${label}): ${detail}`); + } + + /** + * Logs a warning when a registered extension enrichment hook throws. + * + * @param extensionKey - Registered extension identifier + * @param hookName - Hook method name (e.g. `enrichDeclaration`) + * @param error - Thrown value or rejection reason + */ + private warnExtensionHookFailure(extensionKey: string, hookName: string, error: unknown): void { + const detail = error instanceof Error ? error.message : String(error); + console.warn(`[x402] extension "${extensionKey}" ${hookName} threw: ${detail}`); + } + + /** + * Executes after-verify hooks for facilitator and hook-provided verify results. + * + * @param verifyResult - Verify response passed to after-verify hooks. + * @param context - Verify context shared with before-verify hooks. + * @param extensionKeysInUse - Declared extension keys for this request. + * @param matchedScheme - Scheme/network selected for this payment. + * @param matchedScheme.network - Matched payment network. + * @param matchedScheme.scheme - Matched payment scheme. + * @returns Verify response with any in-process skip handler directive. + */ + private async runAfterVerifyHooks( + verifyResult: VerifyResponse, + context: VerifyContext, + extensionKeysInUse: readonly string[], + matchedScheme: { network: Network; scheme: string }, + ): Promise { + const resultContext: VerifyResultContext = { + ...context, + result: verifyResult, + }; + + let skipHandler: SkipHandlerDirective | undefined; + for (const { label, hook } of this.getLabeledHooks( + "afterVerify", + extensionKeysInUse, + matchedScheme, + )) { + try { + const directive = await hook(resultContext); + if (directive && "skipHandler" in directive && directive.skipHandler) { + skipHandler = directive.response ?? {}; + } + } catch (error) { + this.warnResourceServerHookFailure("afterVerify", label, error); + } } - // Find matching requirements - const matchingRequirements = this.findMatchingRequirements(requirements, paymentPayload); - if (!matchingRequirements) { - return { - success: false, - requiresPayment: await this.createPaymentRequiredResponse( - requirements, - resourceInfo, - "No matching payment requirements found", - extensions, - ), - }; + return skipHandler ? { ...verifyResult, skipHandler } : verifyResult; + } + + /** + * Runs response enrichment after settlement lifecycle hooks complete. + * + * @param settleResult - Mutable settlement result being returned to the caller + * @param context - Read-only hook context for enrichment callbacks + * @param declaredExtensions - Extension declarations present on this payment + * @param matchedScheme - Scheme/network selected for this settlement + * @param matchedScheme.network - Matched payment network + * @param matchedScheme.scheme - Matched payment scheme + */ + private async enrichSettlementResponse( + settleResult: SettleResponse, + context: SettleResultContext, + declaredExtensions: Record, + matchedScheme: { network: Network; scheme: string }, + ): Promise { + if (Object.keys(declaredExtensions).length > 0) { + const settleCoreSnapshot = snapshotSettleResponseCore(settleResult); + for (const [key, declaration] of Object.entries(declaredExtensions)) { + const extension = this.registeredExtensions.get(key); + if (!extension?.enrichSettlementResponse) continue; + + try { + const extensionData = await extension.enrichSettlementResponse(declaration, context); + if (extensionData !== undefined) { + if (!settleResult.extensions) { + settleResult.extensions = {}; + } + settleResult.extensions[key] = extensionData; + } + } catch (error) { + this.warnExtensionHookFailure(key, "enrichSettlementResponse", error); + } + assertSettleResponseCoreUnchanged(settleCoreSnapshot, settleResult, key); + } } - // Verify payment - const verificationResult = await this.verifyPayment(paymentPayload, matchingRequirements); - if (!verificationResult.isValid) { - return { - success: false, - error: verificationResult.invalidReason, - verificationResult, - }; + const scheme = findByNetworkAndScheme( + this.registeredServerSchemes, + matchedScheme.scheme, + matchedScheme.network, + ); + const hook = scheme?.enrichSettlementResponse; + if (!hook) return; + + const label = `scheme "${matchedScheme.scheme}" enrichSettlementResponse`; + try { + const enrichment = await hook(context); + if (enrichment === undefined) return; + + assertAdditiveSettlementExtra(settleResult.extra ?? {}, enrichment, label); + settleResult.extra = mergeAdditiveSettlementExtra(settleResult.extra ?? {}, enrichment); + } catch (error) { + this.warnResourceServerHookFailure("enrichSettlementResponse", label, error); } + } - // Payment verified, ready for settlement - return { - success: true, - verificationResult, + /** + * Notify hooks that verified work ended before settlement. + * + * @param paymentPayload - Signed payment payload from the client + * @param requirements - Requirements matched to the payload + * @param declaredExtensions - Optional per-extension declarations for the request + * @param options - Cancellation reason and optional diagnostics + * @param fallbackTransportContext - Optional transport-specific context + */ + private async dispatchVerifiedPaymentCanceled( + paymentPayload: PaymentPayload, + requirements: PaymentRequirements, + declaredExtensions: Record, + options: VerifiedPaymentCancelOptions, + fallbackTransportContext?: unknown, + ): Promise { + const extensionKeysInUse = Object.keys(declaredExtensions); + const matchedScheme = { + network: requirements.network as Network, + scheme: requirements.scheme, }; + const context: VerifiedPaymentCanceledContext = { + paymentPayload, + requirements, + declaredExtensions, + transportContext: fallbackTransportContext, + reason: options.reason, + error: options.error, + responseStatus: options.responseStatus, + }; + + for (const { label, hook } of this.getLabeledHooks( + "onVerifiedPaymentCanceled", + extensionKeysInUse, + matchedScheme, + )) { + try { + await hook(context); + } catch (error) { + this.warnResourceServerHookFailure("onVerifiedPaymentCanceled", label, error); + } + } + } + + /** + * Manual hooks first, then the matched scheme adapter, then extension adapters for keys in use. + * Each entry carries a stable label for logging when a hook throws. + * + * @param phase - Hook slot (e.g. `beforeVerify`) + * @param extensionKeysInUse - Declared extension keys for this request + * @param matchedScheme - Scheme/network selected for this payment + * @param matchedScheme.network - Matched payment network + * @param matchedScheme.scheme - Matched payment scheme + * @returns Hooks in invocation order with source labels + */ + private getLabeledHooks

( + phase: P, + extensionKeysInUse: readonly string[], + matchedScheme?: { network: Network; scheme: string }, + ): Array<{ + label: string; + hook: NonNullable; + }> { + type HookFn = NonNullable; + const manualKey = `${phase}Hooks` as ResourceServerManualHookArrayKey; + const manual = (this as Record)[manualKey]; + + const out: Array<{ label: string; hook: HookFn }> = []; + manual.forEach((hook, index) => { + out.push({ label: `manual ${phase} hook #${index}`, hook }); + }); + + if (matchedScheme) { + const schemeHandles = findByNetworkAndScheme( + this.schemeHookAdapters, + matchedScheme.scheme, + matchedScheme.network, + ); + const hook = schemeHandles?.[phase]; + if (hook !== undefined) { + out.push({ + label: `scheme "${matchedScheme.scheme}" ${phase}`, + hook, + }); + } + } + + const inUse = new Set(extensionKeysInUse); + for (const [extensionKey, adapterHandles] of this.extensionHookAdapters.entries()) { + if (!inUse.has(extensionKey)) continue; + const hook = adapterHandles[phase]; + if (hook !== undefined) { + out.push({ label: `extension "${extensionKey}" ${phase}`, hook }); + } + } + + return out; } /** diff --git a/typescript/packages/core/src/types/extensions.ts b/typescript/packages/core/src/types/extensions.ts index c1e5b0992c..006bdef9a3 100644 --- a/typescript/packages/core/src/types/extensions.ts +++ b/typescript/packages/core/src/types/extensions.ts @@ -1,56 +1,88 @@ -import type { PaymentRequiredContext, SettleResultContext } from "../server/x402ResourceServer"; +import type { VerifyResponse, SettleResponse } from "./facilitator"; +import type { + PaymentRequiredContext, + SettleResultContext, + VerifyContext, + VerifyResultContext, + VerifyFailureContext, + SettleContext, + SettleFailureContext, + VerifiedPaymentCanceledContext, +} from "../server/x402ResourceServer"; -// Re-export context types from x402ResourceServer for convenience -export type { PaymentRequiredContext, SettleResultContext }; +export type { + PaymentRequiredContext, + SettleResultContext, + VerifyContext, + VerifyResultContext, + VerifyFailureContext, + SettleContext, + SettleFailureContext, + VerifiedPaymentCanceledContext, +}; -/** - * Base interface for facilitator extensions. - * Extensions registered with x402Facilitator are stored by key and made - * available to mechanism implementations via FacilitatorContext. - * - * Specific extensions extend this with additional capabilities: - * - * @example - * interface Erc20GasSponsoringExtension extends FacilitatorExtension { - * batchSigner: SmartWalletBatchSigner; - * } - */ export interface FacilitatorExtension { key: string; } +/** + * Per-extension verify/settle hooks. Contexts are **read-only** for core protocol fields; use + * **abort** / **recover** return values instead of mutating `paymentPayload`, `requirements`, etc. + */ +export interface ResourceServerExtensionHooks { + onBeforeVerify?: ( + declaration: unknown, + context: VerifyContext, + ) => Promise< + | void + | { abort: true; reason: string; message?: string } + | { skip: true; result: VerifyResponse } + >; + onAfterVerify?: (declaration: unknown, context: VerifyResultContext) => Promise; + onVerifyFailure?: ( + declaration: unknown, + context: VerifyFailureContext, + ) => Promise; + onBeforeSettle?: ( + declaration: unknown, + context: SettleContext, + ) => Promise< + | void + | { abort: true; reason: string; message?: string } + | { skip: true; result: SettleResponse } + >; + onAfterSettle?: (declaration: unknown, context: SettleResultContext) => Promise; + onSettleFailure?: ( + declaration: unknown, + context: SettleFailureContext, + ) => Promise; + onVerifiedPaymentCanceled?: ( + declaration: unknown, + context: VerifiedPaymentCanceledContext, + ) => Promise; +} + export interface ResourceServerExtension { key: string; - /** - * Enrich extension declaration with extension-specific data. - * - * @param declaration - Extension declaration from route config - * @param transportContext - Transport-specific context (HTTP, A2A, MCP, etc.) - * @returns Enriched extension declaration - */ enrichDeclaration?: (declaration: unknown, transportContext: unknown) => unknown; /** - * Called when generating a 402 PaymentRequired response. - * Return extension data to add to extensions[key], or undefined to skip. - * - * @param declaration - Extension declaration from route config - * @param context - PaymentRequired context containing response, requirements, and optional transportContext - * @returns Extension data to add to response.extensions[key] + * Return value merges into `extensions[key]`. In-place edits to `accepts` are allowlisted only + * (see server `assertAcceptsAllowlistedAfterExtensionEnrich`): vacant `payTo` / `amount` / `asset` + * may be filled; locked values and `scheme` / `network` / `maxTimeoutSeconds` / baseline `extra` + * entries are immutable. */ enrichPaymentRequiredResponse?: ( declaration: unknown, context: PaymentRequiredContext, ) => Promise; /** - * Called after successful payment settlement. - * Return extension data to add to response.extensions[key], or undefined to skip. - * - * @param declaration - Extension declaration from route config - * @param context - Settlement result context containing payment payload, requirements, result and optional transportContext - * @returns Extension data to add to response.extensions[key] + * Return value merges into `settleResult.extensions[key]`. Facilitator fields (`success`, + * `transaction`, `network`, etc.) must not be changed; only `extensions` is merged from the hook. */ enrichSettlementResponse?: ( declaration: unknown, context: SettleResultContext, ) => Promise; + /** Installed on `registerExtension`; runs only when `declaredExtensions[key]` is defined. */ + hooks?: ResourceServerExtensionHooks; } diff --git a/typescript/packages/core/src/types/facilitator.ts b/typescript/packages/core/src/types/facilitator.ts index e330967f03..f1d937051e 100644 --- a/typescript/packages/core/src/types/facilitator.ts +++ b/typescript/packages/core/src/types/facilitator.ts @@ -13,6 +13,7 @@ export type VerifyResponse = { invalidMessage?: string; payer?: string; extensions?: Record; + extra?: Record; }; export type SettleRequest = { @@ -31,6 +32,7 @@ export type SettleResponse = { /** Actual amount settled in atomic token units. Present for schemes like `upto` where settlement amount may differ from the authorized maximum. */ amount?: string; extensions?: Record; + extra?: Record; }; export type SupportedKind = { @@ -59,7 +61,7 @@ export class VerifyError extends Error { * Creates a VerifyError from a failed verification response. * * @param statusCode - HTTP status code from the facilitator - * @param response - The verify response containing error details + * @param response - The verify response containing failure details */ constructor(statusCode: number, response: VerifyResponse) { const reason = response.invalidReason || "unknown reason"; diff --git a/typescript/packages/core/src/types/index.ts b/typescript/packages/core/src/types/index.ts index 6ef8e7fe37..87d7949533 100644 --- a/typescript/packages/core/src/types/index.ts +++ b/typescript/packages/core/src/types/index.ts @@ -4,6 +4,7 @@ export type { SettleRequest, SettleResponse, SupportedResponse, + SupportedKind, } from "./facilitator"; export { VerifyError, @@ -19,21 +20,34 @@ export type { } from "./payments"; export type { SchemeNetworkClient, + SchemeClientHooks, SchemeNetworkFacilitator, SchemeNetworkServer, + SchemeServerHooks, MoneyParser, PaymentPayloadResult, PaymentPayloadContext, FacilitatorContext, + SchemePaymentRequiredContext, + SchemeEnrichPaymentRequiredResponseHook, } from "./mechanisms"; export type { PaymentRequirementsV1, PaymentRequiredV1, PaymentPayloadV1 } from "./v1"; export type { FacilitatorExtension, ResourceServerExtension, + ResourceServerExtensionHooks, PaymentRequiredContext, SettleResultContext, + VerifyContext, + VerifyResultContext, + VerifyFailureContext, + SettleContext, + SettleFailureContext, + VerifiedPaymentCanceledContext, } from "./extensions"; +export type { DeepReadonly } from "./readonly"; + export type Network = `${string}:${string}`; export type Money = string | number; diff --git a/typescript/packages/core/src/types/mechanisms.ts b/typescript/packages/core/src/types/mechanisms.ts index fb3fa46a92..2a0cc691b5 100644 --- a/typescript/packages/core/src/types/mechanisms.ts +++ b/typescript/packages/core/src/types/mechanisms.ts @@ -1,8 +1,25 @@ -import { SettleResponse, VerifyResponse } from "./facilitator"; -import { PaymentRequirements } from "./payments"; -import { PaymentPayload } from "./payments"; +import { SettleResponse, SupportedKind, VerifyResponse } from "./facilitator"; +import { PaymentPayload, PaymentRequired, PaymentRequirements, ResourceInfo } from "./payments"; import { Price, Network, AssetAmount } from "."; import { FacilitatorExtension } from "./extensions"; +import type { DeepReadonly } from "./readonly"; +import type { + BeforeVerifyHook, + AfterVerifyHook, + BeforeSettleHook, + AfterSettleHook, + OnVerifyFailureHook, + OnSettleFailureHook, + OnVerifiedPaymentCanceledHook, + SettleContext, + SettleResultContext, +} from "../server/x402ResourceServer"; +import type { + BeforePaymentCreationHook, + AfterPaymentCreationHook, + OnPaymentCreationFailureHook, + OnPaymentResponseHook, +} from "../client/x402Client"; /** * Money parser function that converts a numeric amount to an AssetAmount @@ -35,8 +52,16 @@ export interface PaymentPayloadContext { extensions?: Record; } +export interface SchemeClientHooks { + onBeforePaymentCreation?: BeforePaymentCreationHook; + onAfterPaymentCreation?: AfterPaymentCreationHook; + onPaymentCreationFailure?: OnPaymentCreationFailureHook; + onPaymentResponse?: OnPaymentResponseHook; +} + export interface SchemeNetworkClient { readonly scheme: string; + readonly schemeHooks?: SchemeClientHooks; createPaymentPayload( x402Version: number, @@ -128,8 +153,43 @@ export interface SchemeNetworkFacilitator { ): Promise; } +export interface SchemeServerHooks { + onBeforeVerify?: BeforeVerifyHook; + onAfterVerify?: AfterVerifyHook; + onBeforeSettle?: BeforeSettleHook; + onAfterSettle?: AfterSettleHook; + onVerifyFailure?: OnVerifyFailureHook; + onSettleFailure?: OnSettleFailureHook; + onVerifiedPaymentCanceled?: OnVerifiedPaymentCanceledHook; +} + +export type SchemeEnrichSettlementPayloadHook = ( + ctx: SettleContext, +) => Promise | void>; + +export type SchemeEnrichSettlementResponseHook = ( + ctx: SettleResultContext, +) => Promise | void>; + +export interface SchemePaymentRequiredContext { + requirements: PaymentRequirements[]; + paymentPayload?: DeepReadonly; + resourceInfo: ResourceInfo; + error?: string; + paymentRequiredResponse: PaymentRequired; + transportContext?: unknown; +} + +export type SchemeEnrichPaymentRequiredResponseHook = ( + ctx: SchemePaymentRequiredContext, +) => Promise; + export interface SchemeNetworkServer { readonly scheme: string; + readonly schemeHooks?: SchemeServerHooks; + enrichPaymentRequiredResponse?: SchemeEnrichPaymentRequiredResponseHook; + enrichSettlementPayload?: SchemeEnrichSettlementPayloadHook; + enrichSettlementResponse?: SchemeEnrichSettlementResponseHook; /** * Convert a user-friendly price to the scheme's specific amount and asset format @@ -173,12 +233,7 @@ export interface SchemeNetworkServer { */ enhancePaymentRequirements( paymentRequirements: PaymentRequirements, - supportedKind: { - x402Version: number; - scheme: string; - network: Network; - extra?: Record; - }, + supportedKind: SupportedKind, facilitatorExtensions: string[], ): Promise; } diff --git a/typescript/packages/core/src/types/payments.ts b/typescript/packages/core/src/types/payments.ts index 129d136d69..be4f6d9d10 100644 --- a/typescript/packages/core/src/types/payments.ts +++ b/typescript/packages/core/src/types/payments.ts @@ -4,6 +4,9 @@ export interface ResourceInfo { url: string; description?: string; mimeType?: string; + serviceName?: string; + tags?: string[]; + iconUrl?: string; } export type PaymentRequirements = { diff --git a/typescript/packages/core/src/types/readonly.ts b/typescript/packages/core/src/types/readonly.ts new file mode 100644 index 0000000000..bfaaf9460d --- /dev/null +++ b/typescript/packages/core/src/types/readonly.ts @@ -0,0 +1,9 @@ +/** + * Recursive readonly for hook contexts so accidental in-place mutation is visible at compile time. + * (Runtime mutation is still possible via other references; see extension enrich validation.) + */ +export type DeepReadonly = T extends (infer U)[] + ? ReadonlyArray> + : T extends object + ? { readonly [K in keyof T]: DeepReadonly } + : T; diff --git a/typescript/packages/core/src/utils/index.ts b/typescript/packages/core/src/utils/index.ts index 9cfbce43f4..5ba2e1ae09 100644 --- a/typescript/packages/core/src/utils/index.ts +++ b/typescript/packages/core/src/utils/index.ts @@ -1,5 +1,66 @@ import { Network } from "../types"; +/** + * Converts a JavaScript number to a plain decimal string, expanding scientific notation + * via string manipulation rather than parseFloat round-tripping. + * + * e.g. 1e-7 → "0.0000001", 4.02 → "4.02" + * + * @param n - The number to convert + * @returns A plain decimal string representation with no scientific notation + */ +export function numberToDecimalString(n: number): string { + const str = n.toString(); + if (!/[eE]/.test(str)) return str; + + const [significand, exponentStr] = str.split(/[eE]/); + const exp = parseInt(exponentStr, 10); + const negative = significand.startsWith("-"); + const abs = negative ? significand.slice(1) : significand; + const [intDigits, fracDigits = ""] = abs.split("."); + const allDigits = intDigits + fracDigits; + const decimalPos = intDigits.length + exp; + + let result: string; + if (decimalPos <= 0) { + result = "0." + "0".repeat(-decimalPos) + allDigits; + } else if (decimalPos >= allDigits.length) { + result = allDigits + "0".repeat(decimalPos - allDigits.length); + } else { + result = allDigits.slice(0, decimalPos) + "." + allDigits.slice(decimalPos); + } + return (negative ? "-" : "") + result; +} + +/** + * Convert a decimal amount to token smallest units. + * Accepts only plain decimal strings — scientific notation is not allowed. + * Throws if the amount is non-zero but too small to represent with the given decimal precision. + * + * @param decimalAmount - The decimal amount as a plain string (e.g., "0.10") + * @param decimals - The number of decimals for the token (e.g., 6 for USDC) + * @returns The amount in smallest units as a string + */ +export function convertToTokenAmount(decimalAmount: string, decimals: number): string { + if (/[eE]/.test(decimalAmount)) { + throw new Error( + `Invalid amount: ${decimalAmount} — use decimal notation, not scientific notation`, + ); + } + if (!/^-?\d+\.?\d*$/.test(decimalAmount)) { + throw new Error(`Invalid amount: ${decimalAmount}`); + } + const [intPart, decPart = ""] = decimalAmount.split("."); + const paddedDec = decPart.padEnd(decimals, "0").slice(0, decimals); + const tokenAmount = (intPart + paddedDec).replace(/^0+/, "") || "0"; + if (tokenAmount === "0" && /[1-9]/.test(decimalAmount)) { + throw new Error( + `Amount ${decimalAmount} is too small to represent with ${decimals} decimal places`, + ); + } + return tokenAmount; +} + /** * Scheme data structure for facilitator storage */ diff --git a/typescript/packages/core/test/mocks/generic/MockSchemeClient.ts b/typescript/packages/core/test/mocks/generic/MockSchemeClient.ts index 96c59889ba..e1e8619c28 100644 --- a/typescript/packages/core/test/mocks/generic/MockSchemeClient.ts +++ b/typescript/packages/core/test/mocks/generic/MockSchemeClient.ts @@ -1,4 +1,4 @@ -import { SchemeNetworkClient } from "../../../src/types/mechanisms"; +import { SchemeClientHooks, SchemeNetworkClient } from "../../../src/types/mechanisms"; import { PaymentPayload, PaymentRequirements } from "../../../src/types/payments"; /** @@ -6,6 +6,7 @@ import { PaymentPayload, PaymentRequirements } from "../../../src/types/payments */ export class MockSchemeNetworkClient implements SchemeNetworkClient { public readonly scheme: string; + public readonly schemeHooks?: SchemeClientHooks; private payloadResult: Pick | Error; // Call tracking @@ -22,12 +23,14 @@ export class MockSchemeNetworkClient implements SchemeNetworkClient { constructor( scheme: string, payloadResult?: Pick | Error, + schemeHooks?: SchemeClientHooks, ) { this.scheme = scheme; this.payloadResult = payloadResult || { x402Version: 2, payload: { signature: "mock_signature", from: "mock_address" }, }; + this.schemeHooks = schemeHooks; } /** diff --git a/typescript/packages/core/test/mocks/generic/MockSchemeServer.ts b/typescript/packages/core/test/mocks/generic/MockSchemeServer.ts index 803124b1d4..ddbce1c93a 100644 --- a/typescript/packages/core/test/mocks/generic/MockSchemeServer.ts +++ b/typescript/packages/core/test/mocks/generic/MockSchemeServer.ts @@ -1,19 +1,22 @@ -import { SchemeNetworkServer } from "../../../src/types/mechanisms"; +import { SchemeNetworkServer, SchemeServerHooks } from "../../../src/types/mechanisms"; import { AssetAmount, Network, Price } from "../../../src/types"; import { PaymentRequirements } from "../../../src/types/payments"; +import type { SupportedKind } from "../../../src/types/facilitator"; /** * Mock scheme network server for testing. */ export class MockSchemeNetworkServer implements SchemeNetworkServer { public readonly scheme: string; + public readonly schemeHooks?: SchemeServerHooks; private parsePriceResult: AssetAmount | Error; private enhanceResult: PaymentRequirements | Error | null = null; private assetDecimalsResult: number | null = null; // Call tracking public parsePriceCalls: Array<{ price: Price; network: Network }> = []; - public enhanceCalls: Array<{ requirements: PaymentRequirements }> = []; + public enhanceCalls: Array<{ requirements: PaymentRequirements; supportedKind: SupportedKind }> = + []; /** * @@ -23,9 +26,11 @@ export class MockSchemeNetworkServer implements SchemeNetworkServer { constructor( scheme: string, parsePriceResult: AssetAmount = { amount: "1000000", asset: "USDC", extra: {} }, + schemeHooks?: SchemeServerHooks, ) { this.scheme = scheme; this.parsePriceResult = parsePriceResult; + this.schemeHooks = schemeHooks; } /** @@ -54,15 +59,10 @@ export class MockSchemeNetworkServer implements SchemeNetworkServer { */ async enhancePaymentRequirements( paymentRequirements: PaymentRequirements, - _supportedKind: { - x402Version: number; - scheme: string; - network: Network; - extra?: Record; - }, + _supportedKind: SupportedKind, _facilitatorExtensions: string[], ): Promise { - this.enhanceCalls.push({ requirements: paymentRequirements }); + this.enhanceCalls.push({ requirements: paymentRequirements, supportedKind: _supportedKind }); if (this.enhanceResult instanceof Error) { throw this.enhanceResult; diff --git a/typescript/packages/core/test/unit/client/x402Client.test.ts b/typescript/packages/core/test/unit/client/x402Client.test.ts index b9401ca689..b6e9dcd458 100644 --- a/typescript/packages/core/test/unit/client/x402Client.test.ts +++ b/typescript/packages/core/test/unit/client/x402Client.test.ts @@ -213,6 +213,69 @@ describe("x402Client", () => { expect(evmClient.createPaymentPayloadCalls.length).toBe(1); }); + + it("runs scheme hooks only for the selected network pattern and scheme", async () => { + const client = new x402Client(); + const order: string[] = []; + + client.onBeforePaymentCreation(async () => { + order.push("manual"); + }); + client.register( + "eip155:*" as Network, + new MockSchemeNetworkClient("exact", undefined, { + onBeforePaymentCreation: async () => { + order.push("scheme"); + }, + }), + ); + client.register( + "eip155:*" as Network, + new MockSchemeNetworkClient("other", undefined, { + onBeforePaymentCreation: async () => { + order.push("other-scheme"); + }, + }), + ); + client.register( + "solana:*" as Network, + new MockSchemeNetworkClient("exact", undefined, { + onBeforePaymentCreation: async () => { + order.push("other-network"); + }, + }), + ); + + await client.createPaymentPayload( + buildPaymentRequired({ + accepts: [ + buildPaymentRequirements({ scheme: "exact", network: "eip155:8453" as Network }), + ], + }), + ); + + expect(order).toEqual(["manual", "scheme"]); + }); + + it("removes scheme client hook adapters when a scheme is re-registered without hooks", async () => { + const client = new x402Client(); + let calls = 0; + + client.register( + "test:network" as Network, + new MockSchemeNetworkClient("test-scheme", undefined, { + onBeforePaymentCreation: async () => { + calls++; + }, + }), + ); + await client.createPaymentPayload(buildPaymentRequired()); + expect(calls).toBe(1); + + client.register("test:network" as Network, new MockSchemeNetworkClient("test-scheme")); + await client.createPaymentPayload(buildPaymentRequired()); + expect(calls).toBe(1); + }); }); describe("registerV1", () => { diff --git a/typescript/packages/core/test/unit/http/x402HTTPResourceServer.hooks.test.ts b/typescript/packages/core/test/unit/http/x402HTTPResourceServer.hooks.test.ts index 3de9e6abb1..5382aca8f2 100644 --- a/typescript/packages/core/test/unit/http/x402HTTPResourceServer.hooks.test.ts +++ b/typescript/packages/core/test/unit/http/x402HTTPResourceServer.hooks.test.ts @@ -6,7 +6,7 @@ import { RouteConfig, ProtectedRequestHook, } from "../../../src/http/x402HTTPResourceServer"; -import { x402ResourceServer } from "../../../src/server/x402ResourceServer"; +import { x402ResourceServer, type VerifyContext } from "../../../src/server/x402ResourceServer"; import { MockFacilitatorClient, MockSchemeNetworkServer, @@ -329,6 +329,60 @@ describe("x402HTTPResourceServer Hooks", () => { expect(receivedContext?.transportContext).toEqual(transportContext); }); + it("should merge nested scheme settlement response enrichment", async () => { + const schemeWithEnrichment = extensionMockScheme as MockSchemeNetworkServer & { + enrichSettlementResponse: () => Promise>; + }; + schemeWithEnrichment.enrichSettlementResponse = async () => ({ + chargedAmount: "1000", + channelState: { + chargedCumulativeAmount: "1000", + }, + }); + + const routes = { + "/api/test": { + accepts: { + scheme: "exact", + payTo: "0xabc", + price: "$1.00" as Price, + network: "eip155:8453" as Network, + }, + }, + }; + const httpServer = new x402HTTPResourceServer(extensionResourceServer, routes); + const payload = buildPaymentPayload(); + const requirements = buildPaymentRequirements({ + scheme: "exact", + network: "eip155:8453" as Network, + }); + + extensionMockFacilitator.setSettleResponse( + buildSettleResponse({ + success: true, + network: "eip155:8453" as Network, + extra: { + channelState: { + channelId: "0xchannel", + balance: "10000", + }, + }, + }), + ); + + const result = await httpServer.processSettlement(payload, requirements); + + expect(result.success).toBe(true); + expect(result.extra).toEqual({ + chargedAmount: "1000", + channelState: { + channelId: "0xchannel", + balance: "10000", + chargedCumulativeAmount: "1000", + }, + }); + }); + it("should have undefined transportContext when not provided", async () => { let receivedContext: SettleResultContext | undefined; @@ -574,6 +628,63 @@ describe("x402HTTPResourceServer Hooks", () => { }); }); + describe("verifyPayment declaredExtensions from HTTP", () => { + it("passes route extensions map to manual onBeforeVerify", async () => { + extensionMockFacilitator.setVerifyResponse(buildVerifyResponse({ isValid: true })); + + let verifyCtx: VerifyContext | undefined; + extensionResourceServer.onBeforeVerify(async ctx => { + verifyCtx = ctx; + }); + + const routes: Record = { + "/api/test": { + accepts: { + scheme: "exact", + payTo: "0xabc", + price: "$1.00" as Price, + network: "eip155:8453" as Network, + }, + extensions: { + bazaar: { tool: "x" }, + }, + }, + }; + + const httpServer = new x402HTTPResourceServer(extensionResourceServer, routes); + + const paymentRequired = await extensionResourceServer.createPaymentRequiredResponse( + await extensionResourceServer.buildPaymentRequirements({ + scheme: "exact", + payTo: "0xabc", + price: "$1.00" as Price, + network: "eip155:8453" as Network, + }), + { url: "/api/test", description: "", mimeType: "" }, + undefined, + routes["/api/test"].extensions, + ); + + const payload = buildPaymentPayload({ + accepted: paymentRequired.accepts[0], + resource: paymentRequired.resource, + }); + const paymentHeader = encodePaymentSignatureHeader(payload); + const adapter = new MockHTTPAdapter({ "payment-signature": paymentHeader }); + const context: HTTPRequestContext = { + adapter, + path: "/api/test", + method: "GET", + }; + + const result = await httpServer.processHTTPRequest(context); + expect(result.type).toBe("payment-verified"); + expect(verifyCtx).toBeDefined(); + expect(verifyCtx!.declaredExtensions).toEqual({ bazaar: { tool: "x" } }); + expect(verifyCtx!.transportContext).toBeDefined(); + }); + }); + describe("Integration: All hooks together", () => { it("should apply all extension hooks in sequence", async () => { const allHooksExtension: ResourceServerExtension = { diff --git a/typescript/packages/core/test/unit/http/x402HTTPResourceService.test.ts b/typescript/packages/core/test/unit/http/x402HTTPResourceService.test.ts index 2dda52f143..15754a7127 100644 --- a/typescript/packages/core/test/unit/http/x402HTTPResourceService.test.ts +++ b/typescript/packages/core/test/unit/http/x402HTTPResourceService.test.ts @@ -197,7 +197,7 @@ describe("x402HTTPResourceServer", () => { const result = await httpServer.processHTTPRequest(context); expect(contextReceived).toBeDefined(); - expect(contextReceived?.path).toBe("/api/dynamic"); + expect((contextReceived as HTTPRequestContext | null)?.path).toBe("/api/dynamic"); expect(result.type).toBe("payment-error"); // No payment provided }); @@ -289,7 +289,7 @@ describe("x402HTTPResourceServer", () => { await httpServer.processHTTPRequest(context); expect(contextReceived).toBeDefined(); - expect(contextReceived?.path).toBe("/api/dynamic"); + expect((contextReceived as HTTPRequestContext | null)?.path).toBe("/api/dynamic"); }); it("should use static payTo if not a function", async () => { @@ -726,6 +726,68 @@ describe("x402HTTPResourceServer", () => { } }); + it("threads the failed payment payload into 402 response enrichment", async () => { + mockFacilitator.setVerifyResponse( + buildVerifyResponse({ isValid: false, invalidReason: "stale_state" }), + ); + const scheme = mockScheme as MockSchemeNetworkServer & { + enrichPaymentRequiredResponse: NonNullable< + import("../../../src/types").SchemeNetworkServer["enrichPaymentRequiredResponse"] + >; + }; + let sawFailedPayload = false; + scheme.enrichPaymentRequiredResponse = async ctx => { + if (ctx.error !== "stale_state") { + return; + } + sawFailedPayload = ctx.paymentPayload?.payload.signature === "test_signature"; + ctx.requirements[0].extra.ChannelState = { channelId: "0x123" }; + }; + + const routes = { + "/api/test": { + accepts: { + scheme: "exact", + payTo: "0xabc", + price: "$1.00" as Price, + network: "eip155:8453" as Network, + }, + }, + }; + const httpServer = new x402HTTPResourceServer(ResourceServer, routes); + const matchingRequirements = buildPaymentRequirements({ + scheme: "exact", + network: "eip155:8453" as Network, + payTo: "0xabc", + amount: "1000000", + asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + maxTimeoutSeconds: 300, + extra: {}, + }); + const payload = buildPaymentPayload({ accepted: matchingRequirements }); + const { decodePaymentRequiredHeader, encodePaymentSignatureHeader } = await import( + "../../../src/http" + ); + const adapter = new MockHTTPAdapter({ + "payment-signature": encodePaymentSignatureHeader(payload), + }); + + const result = await httpServer.processHTTPRequest({ + adapter, + path: "/api/test", + method: "GET", + }); + + expect(result.type).toBe("payment-error"); + if (result.type === "payment-error") { + const paymentRequired = decodePaymentRequiredHeader( + result.response.headers["PAYMENT-REQUIRED"], + ); + expect(sawFailedPayload).toBe(true); + expect(paymentRequired.accepts[0].extra.ChannelState).toEqual({ channelId: "0x123" }); + } + }); + it("should delegate verification to resource service", async () => { const routes = { "/api/test": { @@ -1022,6 +1084,66 @@ describe("x402HTTPResourceServer", () => { } }); + it("should bypass the resource handler when an AfterVerifyHook returns skipHandler", async () => { + mockFacilitator.setVerifyResponse({ + isValid: true, + payer: "0xpayer", + }); + + ResourceServer.onAfterVerify(async () => ({ + skipHandler: true, + response: { + contentType: "application/json", + body: { message: "Refund acknowledged" }, + }, + })); + + const routes = { + "/api/refund": { + accepts: { + scheme: "exact", + payTo: "0xabc", + price: "$1.00" as Price, + network: "eip155:8453" as Network, + }, + }, + }; + + const httpServer = new x402HTTPResourceServer(ResourceServer, routes); + + const matchingRequirements = buildPaymentRequirements({ + scheme: "exact", + network: "eip155:8453" as Network, + payTo: "0xabc", + amount: "1000000", + asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + maxTimeoutSeconds: 300, + extra: {}, + }); + const payload = buildPaymentPayload({ accepted: matchingRequirements }); + const { encodePaymentSignatureHeader } = await import("../../../src/http"); + const paymentHeader = encodePaymentSignatureHeader(payload); + + const adapter = new MockHTTPAdapter({ "payment-signature": paymentHeader }); + const context: HTTPRequestContext = { + adapter, + path: "/api/refund", + method: "GET", + }; + + const result = await httpServer.processHTTPRequest(context); + + expect(mockFacilitator.verifyCalls.length).toBe(1); + expect(mockFacilitator.settleCalls.length).toBe(1); + + expect(result.type).toBe("payment-error"); + if (result.type === "payment-error") { + expect(result.response.status).toBe(200); + expect(result.response.headers["PAYMENT-RESPONSE"]).toBeDefined(); + expect(result.response.body).toEqual({ message: "Refund acknowledged" }); + } + }); + it("should not treat API clients as browsers", async () => { const routes = { "/api/test": { diff --git a/typescript/packages/core/test/unit/server/hookPolicy.test.ts b/typescript/packages/core/test/unit/server/hookPolicy.test.ts new file mode 100644 index 0000000000..d9d43b05cb --- /dev/null +++ b/typescript/packages/core/test/unit/server/hookPolicy.test.ts @@ -0,0 +1,239 @@ +import { describe, it, expect } from "vitest"; +import { + assertAcceptsAllowlistedAfterExtensionEnrich, + assertAdditivePayloadEnrichment, + assertAdditiveSettlementExtra, + assertSettleResponseCoreUnchanged, + isVacantStringField, + mergeAdditiveSettlementExtra, + snapshotPaymentRequirementsList, + snapshotSettleResponseCore, +} from "../../../src/server/hookPolicy"; +import { buildPaymentRequirements, buildSettleResponse } from "../../mocks"; +import type { Network } from "../../../src/types"; + +describe("hookPolicy", () => { + describe("isVacantStringField", () => { + it("treats empty and whitespace-only strings as vacant", () => { + expect(isVacantStringField("")).toBe(true); + expect(isVacantStringField(" ")).toBe(true); + expect(isVacantStringField("0xabc")).toBe(false); + }); + }); + + describe("assertAcceptsAllowlistedAfterExtensionEnrich", () => { + it("allows filling vacant payTo, amount, and asset", () => { + const baseline = snapshotPaymentRequirementsList([ + buildPaymentRequirements({ + payTo: "", + amount: "", + asset: "", + }), + ]); + const current = snapshotPaymentRequirementsList(baseline); + current[0].payTo = "0xnew"; + current[0].amount = "1"; + current[0].asset = "USDC"; + expect(() => + assertAcceptsAllowlistedAfterExtensionEnrich(baseline, current, "ext"), + ).not.toThrow(); + }); + + it("rejects changing scheme", () => { + const baseline = snapshotPaymentRequirementsList([buildPaymentRequirements()]); + const current = snapshotPaymentRequirementsList(baseline); + current[0].scheme = "other"; + expect(() => assertAcceptsAllowlistedAfterExtensionEnrich(baseline, current, "ext")).toThrow( + /scheme\/network/, + ); + }); + + it("rejects changing amount when baseline amount was set", () => { + const baseline = snapshotPaymentRequirementsList([ + buildPaymentRequirements({ amount: "1000" }), + ]); + const current = snapshotPaymentRequirementsList(baseline); + current[0].amount = "999"; + expect(() => assertAcceptsAllowlistedAfterExtensionEnrich(baseline, current, "ext")).toThrow( + /amount.*vacant/, + ); + }); + + it("rejects removing an extra key from baseline", () => { + const baseline = snapshotPaymentRequirementsList([ + buildPaymentRequirements({ extra: { k: 1 } }), + ]); + const current = snapshotPaymentRequirementsList(baseline); + current[0].extra = {}; + expect(() => assertAcceptsAllowlistedAfterExtensionEnrich(baseline, current, "ext")).toThrow( + /extra\["k"\]/, + ); + }); + + it("rejects changing an extra value from baseline", () => { + const baseline = snapshotPaymentRequirementsList([ + buildPaymentRequirements({ extra: { k: 1 } }), + ]); + const current = snapshotPaymentRequirementsList(baseline); + current[0].extra = { ...current[0].extra, k: 2 }; + expect(() => assertAcceptsAllowlistedAfterExtensionEnrich(baseline, current, "ext")).toThrow( + /extra\["k"\]/, + ); + }); + + it("allows adding new extra keys", () => { + const baseline = snapshotPaymentRequirementsList([ + buildPaymentRequirements({ extra: { k: 1 } }), + ]); + const current = snapshotPaymentRequirementsList(baseline); + current[0].extra = { ...current[0].extra, k: 1, newKey: true }; + expect(() => + assertAcceptsAllowlistedAfterExtensionEnrich(baseline, current, "ext"), + ).not.toThrow(); + }); + + it("detects in-place mutation of nested extra values (deep snapshot)", () => { + const baseline = snapshotPaymentRequirementsList([ + buildPaymentRequirements({ extra: { nested: { b: "c" } } }), + ]); + const current = snapshotPaymentRequirementsList(baseline); + (current[0].extra as { nested: { b: string } }).nested.b = "mutated"; + expect(() => assertAcceptsAllowlistedAfterExtensionEnrich(baseline, current, "ext")).toThrow( + /extra\["nested"\]/, + ); + }); + }); + + describe("assertSettleResponseCoreUnchanged", () => { + it("passes when only extensions change", () => { + const base = buildSettleResponse({ + success: true, + transaction: "0xtx", + network: "eip155:8453" as Network, + }); + const snap = snapshotSettleResponseCore(base); + base.extensions = { a: 1 }; + expect(() => assertSettleResponseCoreUnchanged(snap, base, "ext")).not.toThrow(); + }); + + it("throws when transaction changes", () => { + const base = buildSettleResponse({ + success: true, + transaction: "0xtx", + network: "eip155:8453" as Network, + }); + const snap = snapshotSettleResponseCore(base); + base.transaction = "0xother"; + expect(() => assertSettleResponseCoreUnchanged(snap, base, "ext")).toThrow(/transaction/); + }); + }); + + describe("assertAdditivePayloadEnrichment", () => { + it("allows adding new payload fields", () => { + expect(() => + assertAdditivePayloadEnrichment( + { clientField: "client" }, + { serverField: "server" }, + "scheme test", + ), + ).not.toThrow(); + }); + + it("rejects overwriting payload fields", () => { + expect(() => + assertAdditivePayloadEnrichment( + { clientField: "client" }, + { clientField: "server" }, + "scheme test", + ), + ).toThrow(/clientField/); + }); + }); + + describe("assertAdditiveSettlementExtra", () => { + it("allows adding new settlement extra fields", () => { + expect(() => + assertAdditiveSettlementExtra( + { facilitatorField: "facilitator" }, + { schemeField: "scheme" }, + "scheme test", + ), + ).not.toThrow(); + }); + + it("allows adding nested settlement extra fields", () => { + expect(() => + assertAdditiveSettlementExtra( + { + channelState: { + channelId: "0xchannel", + balance: "1000", + }, + }, + { + channelState: { + chargedCumulativeAmount: "200", + }, + }, + "scheme test", + ), + ).not.toThrow(); + }); + + it("rejects overwriting settlement extra fields", () => { + expect(() => + assertAdditiveSettlementExtra( + { facilitatorField: "facilitator" }, + { facilitatorField: "scheme" }, + "scheme test", + ), + ).toThrow(/facilitatorField/); + }); + + it("rejects overwriting nested settlement extra fields", () => { + expect(() => + assertAdditiveSettlementExtra( + { + channelState: { + balance: "1000", + }, + }, + { + channelState: { + balance: "2000", + }, + }, + "scheme test", + ), + ).toThrow(/channelState.*balance/); + }); + }); + + describe("mergeAdditiveSettlementExtra", () => { + it("merges nested settlement extra fields", () => { + expect( + mergeAdditiveSettlementExtra( + { + channelState: { + channelId: "0xchannel", + balance: "1000", + }, + }, + { + chargedAmount: "100", + channelState: { + chargedCumulativeAmount: "200", + }, + }, + ), + ).toEqual({ + chargedAmount: "100", + channelState: { + channelId: "0xchannel", + balance: "1000", + chargedCumulativeAmount: "200", + }, + }); + }); + }); +}); diff --git a/typescript/packages/core/test/unit/server/x402ResourceServer.test.ts b/typescript/packages/core/test/unit/server/x402ResourceServer.test.ts index 1966efa662..24a1e9c60e 100644 --- a/typescript/packages/core/test/unit/server/x402ResourceServer.test.ts +++ b/typescript/packages/core/test/unit/server/x402ResourceServer.test.ts @@ -1,4 +1,4 @@ -import { describe, it, expect, beforeEach } from "vitest"; +import { describe, it, expect, beforeEach, vi } from "vitest"; import { x402ResourceServer, resolveSettlementOverrideAmount, @@ -13,6 +13,7 @@ import { buildSettleResponse, } from "../../mocks"; import { Network } from "../../../src/types"; +import type { SettleResponse } from "../../../src/types/facilitator"; describe("x402ResourceServer", () => { describe("Construction", () => { @@ -99,6 +100,83 @@ describe("x402ResourceServer", () => { // This is verified implicitly - both registrations succeed without error expect(server).toBeDefined(); }); + + it("runs scheme hooks only for the matched network pattern and scheme", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + ); + const server = new x402ResourceServer(mockClient); + const order: string[] = []; + + server.onBeforeVerify(async () => { + order.push("manual"); + }); + server.register( + "eip155:*" as Network, + new MockSchemeNetworkServer("batch", undefined, { + onBeforeVerify: async () => { + order.push("scheme"); + }, + }), + ); + server.register( + "eip155:*" as Network, + new MockSchemeNetworkServer("other", undefined, { + onBeforeVerify: async () => { + order.push("other-scheme"); + }, + }), + ); + server.register( + "solana:*" as Network, + new MockSchemeNetworkServer("batch", undefined, { + onBeforeVerify: async () => { + order.push("other-network"); + }, + }), + ); + server.registerExtension({ + key: "ext", + hooks: { + onBeforeVerify: async () => { + order.push("extension"); + }, + }, + }); + + await server.verifyPayment( + buildPaymentPayload(), + buildPaymentRequirements({ scheme: "batch", network: "eip155:8453" as Network }), + { ext: {} }, + ); + + expect(order).toEqual(["manual", "scheme", "extension"]); + }); + + it("overwrites scheme hook adapters when a scheme is re-registered", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + ); + const server = new x402ResourceServer(mockClient); + let calls = 0; + + server.register( + "test:network" as Network, + new MockSchemeNetworkServer("test-scheme", undefined, { + onBeforeVerify: async () => { + calls++; + }, + }), + ); + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements()); + expect(calls).toBe(1); + + server.register("test:network" as Network, new MockSchemeNetworkServer("test-scheme")); + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements()); + expect(calls).toBe(1); + }); }); describe("initialize", () => { @@ -316,6 +394,11 @@ describe("x402ResourceServer", () => { }); expect(mockScheme.enhanceCalls.length).toBe(1); + expect(mockScheme.enhanceCalls[0].supportedKind).toEqual({ + x402Version: 2, + scheme: "test-scheme", + network: "test:network", + }); }); it("should use default maxTimeoutSeconds of 300", async () => { @@ -425,6 +508,7 @@ describe("x402ResourceServer", () => { hookExecuted = true; expect(context.paymentPayload).toBeDefined(); expect(context.requirements).toBeDefined(); + expect(context.declaredExtensions).toEqual({}); }); const payload = buildPaymentPayload(); @@ -450,6 +534,72 @@ describe("x402ResourceServer", () => { expect(mockClient.verifyCalls.length).toBe(0); // Facilitator not called }); + it("should abort verification with the hook reason", async () => { + server.onBeforeVerify(async () => { + return { + abort: true, + reason: "stale_state", + }; + }); + + const result = await server.verifyPayment( + buildPaymentPayload(), + buildPaymentRequirements(), + ); + + expect(result).toMatchObject({ + isValid: false, + invalidReason: "stale_state", + }); + }); + + it("should skip facilitator verification when a beforeVerify hook returns a result", async () => { + server.onBeforeVerify(async () => { + return { + skip: true, + result: buildVerifyResponse({ + isValid: true, + payer: "0xlocal", + extra: { source: "local" }, + }), + }; + }); + + const result = await server.verifyPayment( + buildPaymentPayload(), + buildPaymentRequirements(), + ); + + expect(mockClient.verifyCalls.length).toBe(0); + expect(result).toMatchObject({ + isValid: true, + payer: "0xlocal", + extra: { source: "local" }, + }); + }); + + it("should run afterVerify hooks when beforeVerify skips facilitator verification", async () => { + const executionOrder: string[] = []; + + server + .onBeforeVerify(async () => { + executionOrder.push("before"); + return { + skip: true, + result: buildVerifyResponse({ isValid: true, payer: "0xlocal" }), + }; + }) + .onAfterVerify(async context => { + executionOrder.push("after"); + expect(context.result.payer).toBe("0xlocal"); + }); + + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements()); + + expect(mockClient.verifyCalls.length).toBe(0); + expect(executionOrder).toEqual(["before", "after"]); + }); + it("should execute multiple hooks in order", async () => { const executionOrder: number[] = []; @@ -488,6 +638,25 @@ describe("x402ResourceServer", () => { expect(executionOrder).toEqual([1, 2]); // Third hook not executed }); + + it("should warn and continue verification when a beforeVerify hook throws", async () => { + const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); + + server.onBeforeVerify(async () => { + throw new Error("Hook boom"); + }); + + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements()); + + expect(mockClient.verifyCalls.length).toBe(1); + expect(warnSpy).toHaveBeenCalledWith( + expect.stringMatching( + /\[x402\] Resource server beforeVerify hook threw \(manual beforeVerify hook #0\): Hook boom/, + ), + ); + + warnSpy.mockRestore(); + }); }); describe("onAfterVerify", () => { @@ -528,6 +697,31 @@ describe("x402ResourceServer", () => { expect(executionOrder).toEqual([1, 2, 3]); }); + it("should warn and run later afterVerify hooks when an earlier hook throws", async () => { + const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); + const executionOrder: number[] = []; + + server + .onAfterVerify(async () => { + executionOrder.push(1); + throw new Error("after fail"); + }) + .onAfterVerify(async () => { + executionOrder.push(2); + }); + + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements()); + + expect(executionOrder).toEqual([1, 2]); + expect(warnSpy).toHaveBeenCalledWith( + expect.stringMatching( + /\[x402\] Resource server afterVerify hook threw \(manual afterVerify hook #0\): after fail/, + ), + ); + + warnSpy.mockRestore(); + }); + it("should not execute afterVerify if verification aborted", async () => { let afterVerifyCalled = false; @@ -608,6 +802,39 @@ describe("x402ResourceServer", () => { expect(executionOrder).toEqual([1, 2]); // Stops after recovery }); + it("should warn and continue onVerifyFailure hooks when a hook throws", async () => { + const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); + const executionOrder: number[] = []; + + mockClient.setVerifyResponse(new Error("Failure")); + + server + .onVerifyFailure(async () => { + executionOrder.push(1); + throw new Error("failure-hook boom"); + }) + .onVerifyFailure(async () => { + executionOrder.push(2); + return { recovered: true, result: { isValid: true, payer: "0xok" } }; + }); + + const result = await server.verifyPayment( + buildPaymentPayload(), + buildPaymentRequirements(), + ); + + expect(result.isValid).toBe(true); + expect(result.payer).toBe("0xok"); + expect(executionOrder).toEqual([1, 2]); + expect(warnSpy).toHaveBeenCalledWith( + expect.stringMatching( + /\[x402\] Resource server onVerifyFailure hook threw \(manual onVerifyFailure hook #0\): failure-hook boom/, + ), + ); + + warnSpy.mockRestore(); + }); + it("should re-throw if no recovery", async () => { mockClient.setVerifyResponse(new Error("Fatal error")); @@ -663,19 +890,27 @@ describe("x402ResourceServer", () => { } }); - it("should wrap unexpected hook errors as before_settle_hook_error", async () => { + it("should warn and continue settlement when a beforeSettle hook throws", async () => { + const warnSpy = vi.spyOn(console, "warn").mockImplementation(() => {}); + server.onBeforeSettle(async () => { throw new Error("Unexpected failure"); }); - try { - await server.settlePayment(buildPaymentPayload(), buildPaymentRequirements()); - expect.unreachable("Should have thrown"); - } catch (error: any) { - expect(error.name).toBe("SettleError"); - expect(error.errorReason).toBe("before_settle_hook_error"); - expect(error.errorMessage).toBe("Unexpected failure"); - } + const result = await server.settlePayment( + buildPaymentPayload(), + buildPaymentRequirements(), + ); + + expect(result.success).toBe(true); + expect(mockClient.settleCalls.length).toBe(1); + expect(warnSpy).toHaveBeenCalledWith( + expect.stringMatching( + /\[x402\] Resource server beforeSettle hook threw \(manual beforeSettle hook #0\): Unexpected failure/, + ), + ); + + warnSpy.mockRestore(); }); it("should execute multiple hooks in order", async () => { @@ -756,6 +991,50 @@ describe("x402ResourceServer", () => { expect(result.transaction).toBe("0xRecoveredTx"); }); }); + + describe("onVerifiedPaymentCanceled", () => { + it("executes manual, scheme, and extension hooks once", async () => { + const server = new x402ResourceServer(mockClient); + const calls: string[] = []; + + server.onVerifiedPaymentCanceled(async context => { + calls.push(`manual:${context.reason}:${context.responseStatus}`); + }); + server.register( + "eip155:*" as Network, + new MockSchemeNetworkServer("exact", undefined, { + onVerifiedPaymentCanceled: async context => { + calls.push(`scheme:${context.reason}`); + }, + }), + ); + server.registerExtension({ + key: "ext", + hooks: { + onVerifiedPaymentCanceled: async (_declaration, context) => { + calls.push(`extension:${context.reason}`); + }, + }, + }); + + const transportContext = { requestId: "req-1" }; + const cancellation = server.createPaymentCancellationDispatcher( + buildPaymentPayload(), + buildPaymentRequirements({ scheme: "exact", network: "eip155:8453" as Network }), + { ext: {} }, + transportContext, + ); + + await cancellation.cancel({ reason: "handler_failed", responseStatus: 500 }); + await cancellation.cancel({ reason: "handler_failed", responseStatus: 500 }); + + expect(calls).toEqual([ + "manual:handler_failed:500", + "scheme:handler_failed", + "extension:handler_failed", + ]); + }); + }); }); describe("verifyPayment", () => { @@ -1059,6 +1338,200 @@ describe("x402ResourceServer", () => { expect(hookAmount).toBe("300000"); }); + + it("runs labeled afterSettle hooks when beforeSettle returns a skip result", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + buildSettleResponse({ success: true }), + ); + const server = new x402ResourceServer(mockClient); + const order: string[] = []; + + server.onBeforeSettle(async () => ({ + skip: true, + result: buildSettleResponse({ success: true }), + })); + server.onAfterSettle(async () => { + order.push("manual"); + }); + server.register( + "test:network" as Network, + new MockSchemeNetworkServer("test-scheme", undefined, { + onAfterSettle: async () => { + order.push("scheme"); + }, + }), + ); + server.registerExtension({ + key: "ext", + hooks: { + onAfterSettle: async () => { + order.push("extension"); + }, + }, + }); + + const result = await server.settlePayment(buildPaymentPayload(), buildPaymentRequirements(), { + ext: {}, + }); + + expect(result.success).toBe(true); + expect(mockClient.settleCalls.length).toBe(0); + expect(order).toEqual(["manual", "scheme", "extension"]); + }); + + it("applies scheme payload enrichment before facilitator settlement", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + buildSettleResponse({ success: true }), + ); + const server = new x402ResourceServer(mockClient); + const order: string[] = []; + + server.register( + "test:network", + Object.assign(new MockSchemeNetworkServer("test-scheme"), { + enrichSettlementPayload: async () => { + order.push("payload"); + return { serverField: "server" }; + }, + }), + ); + + await server.settlePayment( + buildPaymentPayload({ payload: { clientField: "client" } }), + buildPaymentRequirements(), + ); + + expect(order).toEqual(["payload"]); + expect(mockClient.settleCalls[0].payload.payload).toEqual({ + clientField: "client", + serverField: "server", + }); + }); + + it("rejects payload enrichment that overwrites client payload fields", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + buildSettleResponse({ success: true }), + ); + const server = new x402ResourceServer(mockClient); + + server.register( + "test:network", + Object.assign(new MockSchemeNetworkServer("test-scheme"), { + enrichSettlementPayload: async () => ({ clientField: "server" }), + }), + ); + + await expect( + server.settlePayment( + buildPaymentPayload({ payload: { clientField: "client" } }), + buildPaymentRequirements(), + ), + ).rejects.toThrow(/clientField/); + expect(mockClient.settleCalls.length).toBe(0); + }); + + it("runs settlement response enrichment after afterSettle and extension enrichment", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + buildSettleResponse({ success: true, extra: { facilitatorField: "facilitator" } }), + ); + const server = new x402ResourceServer(mockClient); + const order: string[] = []; + + server.onAfterSettle(async () => { + order.push("afterSettle"); + }); + server.registerExtension({ + key: "ext", + enrichSettlementResponse: async () => { + order.push("extension"); + return { extensionField: "extension" }; + }, + }); + server.register( + "test:network", + Object.assign(new MockSchemeNetworkServer("test-scheme"), { + enrichSettlementResponse: async () => { + order.push("scheme"); + return { schemeField: "scheme" }; + }, + }), + ); + + const result = await server.settlePayment(buildPaymentPayload(), buildPaymentRequirements(), { + ext: {}, + }); + + expect(order).toEqual(["afterSettle", "extension", "scheme"]); + expect(result.extensions).toEqual({ ext: { extensionField: "extension" } }); + expect(result.extra).toEqual({ + facilitatorField: "facilitator", + schemeField: "scheme", + }); + }); + + it("skips payload enrichment and still runs response enrichment for skip results", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + buildSettleResponse({ success: true }), + ); + const server = new x402ResourceServer(mockClient); + const enrichSettlementPayload = vi.fn(async () => ({ serverField: "server" })); + + server.onBeforeSettle(async () => ({ + skip: true, + result: buildSettleResponse({ success: true, extra: { skipField: "skip" } }), + })); + server.register( + "test:network", + Object.assign(new MockSchemeNetworkServer("test-scheme"), { + enrichSettlementPayload, + enrichSettlementResponse: async () => ({ schemeField: "scheme" }), + }), + ); + + const result = await server.settlePayment(buildPaymentPayload(), buildPaymentRequirements()); + + expect(enrichSettlementPayload).not.toHaveBeenCalled(); + expect(mockClient.settleCalls.length).toBe(0); + expect(result.extra).toEqual({ + skipField: "skip", + schemeField: "scheme", + }); + }); + + it("rejects enrichSettlementResponse that mutates facilitator core fields", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + buildSettleResponse({ + success: true, + transaction: "0xfacilitator_tx", + network: "test:network" as Network, + }), + ); + const server = new x402ResourceServer(mockClient); + server.registerExtension({ + key: "badSettle", + enrichSettlementResponse: async (_d, ctx) => { + // Simulate a misbehaving extension: context is typed read-only, but runtime objects are still mutable. + (ctx.result as SettleResponse).transaction = "0x_attacker_tx"; + return { leaked: true }; + }, + }); + + await expect( + server.settlePayment(buildPaymentPayload(), buildPaymentRequirements(), { badSettle: {} }), + ).rejects.toThrow(/transaction/); + }); }); describe("findMatchingRequirements", () => { @@ -1212,6 +1685,434 @@ describe("x402ResourceServer", () => { expect(result.extensions).toBeUndefined(); }); + + it("should clone accepts so the caller requirements array is not mutated by reference", async () => { + const server = new x402ResourceServer(); + const requirements = [buildPaymentRequirements({ payTo: "0x_original" })]; + const resourceInfo = { + url: "https://example.com", + description: "Test resource", + mimeType: "application/json", + }; + + const result = await server.createPaymentRequiredResponse(requirements, resourceInfo); + + expect(result.accepts).not.toBe(requirements); + expect(result.accepts[0]).not.toBe(requirements[0]); + expect(requirements[0].payTo).toBe("0x_original"); + }); + + it("allows enrichPaymentRequiredResponse to set payTo only when baseline payTo is vacant", async () => { + const server = new x402ResourceServer(); + server.registerExtension({ + key: "mut", + enrichPaymentRequiredResponse: async (_d, ctx) => { + ctx.paymentRequiredResponse.accepts[0]!.payTo = "0x_mutated"; + return { ok: true }; + }, + }); + const requirements = [buildPaymentRequirements({ payTo: "" })]; + const result = await server.createPaymentRequiredResponse( + requirements, + { url: "https://example.com", description: "", mimeType: "" }, + undefined, + { mut: {} }, + ); + + expect(result.accepts[0].payTo).toBe("0x_mutated"); + expect(requirements[0].payTo).toBe(""); + expect((result.extensions as Record).mut).toEqual({ ok: true }); + }); + + it("serializes accepts mutations made by enrichPaymentRequiredResponse on the cloned list", async () => { + const server = new x402ResourceServer(); + server.registerExtension({ + key: "mut", + enrichPaymentRequiredResponse: async (_d, ctx) => { + ctx.paymentRequiredResponse.accepts[0]!.extra.corrective = "x"; + return undefined; + }, + }); + const requirements = [buildPaymentRequirements({ extra: {} })]; + + const result = await server.createPaymentRequiredResponse( + requirements, + { url: "https://example.com", description: "", mimeType: "" }, + undefined, + { mut: {} }, + ); + + expect(result.accepts[0].extra.corrective).toBe("x"); + expect(requirements[0].extra.corrective).toBeUndefined(); + }); + + it("lets a scheme enrich matching accepts with additive extra fields", async () => { + const server = new x402ResourceServer(); + const scheme = new MockSchemeNetworkServer("test-scheme") as MockSchemeNetworkServer & { + enrichPaymentRequiredResponse: NonNullable< + import("../../../src/types").SchemeNetworkServer["enrichPaymentRequiredResponse"] + >; + }; + const paymentPayload = buildPaymentPayload(); + const enrich = vi.fn(async ctx => { + expect(ctx.paymentPayload).toBe(paymentPayload); + ctx.requirements[0].extra.ChannelState = { channelId: "0x123" }; + }); + scheme.enrichPaymentRequiredResponse = enrich; + server.register("test:network" as Network, scheme); + + const result = await server.createPaymentRequiredResponse( + [buildPaymentRequirements()], + { url: "https://example.com", description: "", mimeType: "" }, + "stale_state", + undefined, + undefined, + paymentPayload, + ); + + expect(enrich).toHaveBeenCalledTimes(1); + expect(result.accepts[0].extra.ChannelState).toEqual({ channelId: "0x123" }); + }); + + it("rejects scheme response enrichment that overwrites baseline terms", async () => { + const server = new x402ResourceServer(); + const scheme = new MockSchemeNetworkServer("test-scheme") as MockSchemeNetworkServer & { + enrichPaymentRequiredResponse: NonNullable< + import("../../../src/types").SchemeNetworkServer["enrichPaymentRequiredResponse"] + >; + }; + scheme.enrichPaymentRequiredResponse = async ctx => { + ctx.requirements[0].extra = { ChannelState: { channelId: "0x123" } }; + }; + server.register("test:network" as Network, scheme); + + await expect( + server.createPaymentRequiredResponse( + [buildPaymentRequirements({ extra: { name: "USDC" } })], + { url: "https://example.com", description: "", mimeType: "" }, + "stale_state", + ), + ).rejects.toThrow(/extra\["name"\] was removed/); + }); + + it("rejects enrichPaymentRequiredResponse that overwrites a non-vacant payTo", async () => { + const server = new x402ResourceServer(); + server.registerExtension({ + key: "bad", + enrichPaymentRequiredResponse: async (_d, ctx) => { + ctx.paymentRequiredResponse.accepts[0]!.payTo = "0x_attacker"; + return {}; + }, + }); + const requirements = [buildPaymentRequirements({ payTo: "0x_merchant" })]; + + await expect( + server.createPaymentRequiredResponse( + requirements, + { url: "https://example.com", description: "", mimeType: "" }, + undefined, + { bad: {} }, + ), + ).rejects.toThrow(/payTo.*vacant/); + }); + }); + + describe("registerExtension lifecycle hooks", () => { + it("runs extension onBeforeVerify only when extension key is in declaredExtensions", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + ); + const server = new x402ResourceServer(mockClient); + let extCalls = 0; + server.registerExtension({ + key: "extA", + hooks: { + onBeforeVerify: async () => { + extCalls++; + }, + }, + }); + + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements()); + expect(extCalls).toBe(0); + + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements(), { extA: {} }); + expect(extCalls).toBe(1); + }); + + it("registerExtension with the same key overwrites extension hook adapters", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + ); + const server = new x402ResourceServer(mockClient); + let extCalls = 0; + server.registerExtension({ + key: "extB", + hooks: { + onBeforeVerify: async () => { + extCalls++; + }, + }, + }); + server.registerExtension({ + key: "extB", + hooks: { + onBeforeVerify: async () => { + extCalls++; + }, + }, + }); + + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements(), { extB: {} }); + expect(extCalls).toBe(1); + }); + + it("runs manual onBeforeVerify hooks before extension onBeforeVerify", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + ); + const server = new x402ResourceServer(mockClient); + const order: string[] = []; + server.onBeforeVerify(async () => { + order.push("manual"); + }); + server.registerExtension({ + key: "extC", + hooks: { + onBeforeVerify: async () => { + order.push("ext"); + }, + }, + }); + + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements(), { extC: {} }); + expect(order).toEqual(["manual", "ext"]); + }); + + it("runs extension onBeforeVerify only for keys present in declaredExtensions (not all registered)", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + ); + const server = new x402ResourceServer(mockClient); + let callsA = 0; + let callsB = 0; + server.registerExtension({ + key: "extA", + hooks: { + onBeforeVerify: async () => { + callsA++; + }, + }, + }); + server.registerExtension({ + key: "extB", + hooks: { + onBeforeVerify: async () => { + callsB++; + }, + }, + }); + + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements(), { extB: {} }); + expect(callsA).toBe(0); + expect(callsB).toBe(1); + }); + + it("runs extension onAfterVerify only when extension key is declared", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + ); + const server = new x402ResourceServer(mockClient); + let afterCalls = 0; + server.registerExtension({ + key: "afterExt", + hooks: { + onAfterVerify: async () => { + afterCalls++; + }, + }, + }); + + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements()); + expect(afterCalls).toBe(0); + + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements(), { + afterExt: {}, + }); + expect(afterCalls).toBe(1); + }); + + it("runs extension onVerifyFailure only when extension key is declared", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + ); + const server = new x402ResourceServer(mockClient); + mockClient.setVerifyResponse(new Error("verify boom")); + let failCalls = 0; + server.registerExtension({ + key: "failExt", + hooks: { + onVerifyFailure: async () => { + failCalls++; + }, + }, + }); + + await expect( + server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements()), + ).rejects.toThrow("verify boom"); + expect(failCalls).toBe(0); + + await expect( + server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements(), { failExt: {} }), + ).rejects.toThrow("verify boom"); + expect(failCalls).toBe(1); + }); + + it("runs extension onBeforeSettle and onAfterSettle only when extension key is declared", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + buildSettleResponse({ success: true }), + ); + const server = new x402ResourceServer(mockClient); + let beforeCalls = 0; + let afterCalls = 0; + server.registerExtension({ + key: "settleExt", + hooks: { + onBeforeSettle: async () => { + beforeCalls++; + }, + onAfterSettle: async () => { + afterCalls++; + }, + }, + }); + + await server.settlePayment(buildPaymentPayload(), buildPaymentRequirements()); + expect(beforeCalls).toBe(0); + expect(afterCalls).toBe(0); + + await server.settlePayment(buildPaymentPayload(), buildPaymentRequirements(), { + settleExt: {}, + }); + expect(beforeCalls).toBe(1); + expect(afterCalls).toBe(1); + }); + + it("runs extension onSettleFailure only when extension key is declared", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + buildSettleResponse({ success: true }), + ); + const server = new x402ResourceServer(mockClient); + mockClient.setSettleResponse(new Error("settle boom")); + let failCalls = 0; + server.registerExtension({ + key: "settleFailExt", + hooks: { + onSettleFailure: async () => { + failCalls++; + }, + }, + }); + + await expect( + server.settlePayment(buildPaymentPayload(), buildPaymentRequirements()), + ).rejects.toThrow("settle boom"); + expect(failCalls).toBe(0); + + await expect( + server.settlePayment(buildPaymentPayload(), buildPaymentRequirements(), { + settleFailExt: {}, + }), + ).rejects.toThrow("settle boom"); + expect(failCalls).toBe(1); + }); + + it("still runs manual onVerifyFailure when declaredExtensions is empty", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + ); + const server = new x402ResourceServer(mockClient); + mockClient.setVerifyResponse(new Error("verify boom")); + let manualCalls = 0; + server.onVerifyFailure(async () => { + manualCalls++; + }); + server.registerExtension({ + key: "onlyRegistered", + hooks: { + onVerifyFailure: async () => { + manualCalls += 100; + }, + }, + }); + + await expect( + server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements()), + ).rejects.toThrow("verify boom"); + expect(manualCalls).toBe(1); + }); + + it("removes extension lifecycle adapters when re-registering with hooks: {}", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + ); + const server = new x402ResourceServer(mockClient); + let calls = 0; + server.registerExtension({ + key: "reReg", + hooks: { + onBeforeVerify: async () => { + calls++; + }, + }, + }); + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements(), { reReg: {} }); + expect(calls).toBe(1); + + server.registerExtension({ key: "reReg", hooks: {} }); + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements(), { reReg: {} }); + expect(calls).toBe(1); + }); + + it("removes extension lifecycle adapters when re-registering without hooks", async () => { + const mockClient = new MockFacilitatorClient( + buildSupportedResponse(), + buildVerifyResponse({ isValid: true }), + ); + const server = new x402ResourceServer(mockClient); + let calls = 0; + server.registerExtension({ + key: "noHooks", + hooks: { + onBeforeVerify: async () => { + calls++; + }, + }, + }); + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements(), { + noHooks: {}, + }); + expect(calls).toBe(1); + + server.registerExtension({ key: "noHooks" }); + await server.verifyPayment(buildPaymentPayload(), buildPaymentRequirements(), { + noHooks: {}, + }); + expect(calls).toBe(1); + }); }); describe("getSupportedKind and getFacilitatorExtensions", () => { diff --git a/typescript/packages/core/test/unit/utils/utils.test.ts b/typescript/packages/core/test/unit/utils/utils.test.ts index 4ac1dcac4f..3b268cafb6 100644 --- a/typescript/packages/core/test/unit/utils/utils.test.ts +++ b/typescript/packages/core/test/unit/utils/utils.test.ts @@ -5,6 +5,8 @@ import { deepEqual, safeBase64Encode, safeBase64Decode, + numberToDecimalString, + convertToTokenAmount, } from "../../../src/utils"; import { Network } from "../../../src/types"; @@ -291,6 +293,136 @@ describe("Utils", () => { }); }); + describe("numberToDecimalString", () => { + it("should pass through plain integers", () => { + expect(numberToDecimalString(0)).toBe("0"); + expect(numberToDecimalString(1)).toBe("1"); + expect(numberToDecimalString(42)).toBe("42"); + expect(numberToDecimalString(-5)).toBe("-5"); + }); + + it("should pass through plain decimals", () => { + expect(numberToDecimalString(1.5)).toBe("1.5"); + expect(numberToDecimalString(4.02)).toBe("4.02"); + expect(numberToDecimalString(0.123)).toBe("0.123"); + expect(numberToDecimalString(-3.14)).toBe("-3.14"); + }); + + it("should expand small negative exponents", () => { + expect(numberToDecimalString(1e-7)).toBe("0.0000001"); + expect(numberToDecimalString(1e-8)).toBe("0.00000001"); + expect(numberToDecimalString(1.5e-6)).toBe("0.0000015"); + expect(numberToDecimalString(1e-18)).toBe("0.000000000000000001"); + }); + + it("should expand negative numbers with negative exponents", () => { + expect(numberToDecimalString(-1e-7)).toBe("-0.0000001"); + expect(numberToDecimalString(-2.5e-10)).toBe("-0.00000000025"); + }); + + it("should expand large positive exponents", () => { + expect(numberToDecimalString(1e20)).toBe("100000000000000000000"); + expect(numberToDecimalString(1.5e10)).toBe("15000000000"); + }); + }); + + describe("convertToTokenAmount", () => { + describe("basic conversions", () => { + it("should convert decimal amounts to token units", () => { + expect(convertToTokenAmount("4.02", 6)).toBe("4020000"); + expect(convertToTokenAmount("0.10", 6)).toBe("100000"); + expect(convertToTokenAmount("1.00", 6)).toBe("1000000"); + expect(convertToTokenAmount("0.01", 6)).toBe("10000"); + expect(convertToTokenAmount("123.456789", 6)).toBe("123456789"); + }); + + it("should handle whole numbers", () => { + expect(convertToTokenAmount("1", 6)).toBe("1000000"); + expect(convertToTokenAmount("100", 6)).toBe("100000000"); + expect(convertToTokenAmount("0", 6)).toBe("0"); + }); + + it("should handle different decimal precisions", () => { + expect(convertToTokenAmount("1", 0)).toBe("1"); + expect(convertToTokenAmount("1", 2)).toBe("100"); + expect(convertToTokenAmount("1", 7)).toBe("10000000"); + expect(convertToTokenAmount("1", 9)).toBe("1000000000"); + expect(convertToTokenAmount("1.0", 18)).toBe("1000000000000000000"); + }); + + it("should truncate excess decimal places", () => { + expect(convertToTokenAmount("1.12345678", 7)).toBe("11234567"); + expect(convertToTokenAmount("1.5", 0)).toBe("1"); + expect(convertToTokenAmount("2.9", 0)).toBe("2"); + }); + + it("should handle trailing zeros", () => { + expect(convertToTokenAmount("1.0", 6)).toBe("1000000"); + expect(convertToTokenAmount("0.1000000", 7)).toBe("1000000"); + }); + + it("should handle negative numbers", () => { + expect(convertToTokenAmount("-1.5", 6)).toBe("-1500000"); + }); + + it("should handle very large numbers", () => { + expect(convertToTokenAmount("999999999.9999999", 7)).toBe("9999999999999999"); + }); + }); + + describe("small amounts with sufficient precision", () => { + it("should convert tiny amounts when token has enough decimals", () => { + // 0.0000001 with 9 decimals = 100 atomic units + expect(convertToTokenAmount("0.0000001", 9)).toBe("100"); + // 0.000000001 with 9 decimals = 1 atomic unit + expect(convertToTokenAmount("0.000000001", 9)).toBe("1"); + // 0.0000015 with 9 decimals = 1500 atomic units + expect(convertToTokenAmount("0.0000015", 9)).toBe("1500"); + }); + + it("should handle the smallest representable amount", () => { + expect(convertToTokenAmount("0.0000001", 7)).toBe("1"); + expect(convertToTokenAmount("0.000001", 6)).toBe("1"); + expect(convertToTokenAmount("0.000000000000000001", 18)).toBe("1"); + }); + }); + + describe("too-small errors", () => { + it("should throw when a non-zero amount rounds down to 0", () => { + // 0.0000001 with 6 decimals: truncates to 0 atomic units + expect(() => convertToTokenAmount("0.0000001", 6)).toThrow("too small"); + // 0.00000001 with 7 decimals: truncates to 0 + expect(() => convertToTokenAmount("0.00000001", 7)).toThrow("too small"); + // 0.0000000001 with 6 decimals: also too small + expect(() => convertToTokenAmount("0.0000000001", 6)).toThrow("too small"); + }); + + it("should not throw for zero itself", () => { + expect(convertToTokenAmount("0", 6)).toBe("0"); + expect(convertToTokenAmount("0.0", 6)).toBe("0"); + expect(convertToTokenAmount("0.000000", 6)).toBe("0"); + }); + }); + + describe("scientific notation rejection", () => { + it("should throw for scientific notation input", () => { + expect(() => convertToTokenAmount("1e-7", 9)).toThrow("scientific notation"); + expect(() => convertToTokenAmount("1e-6", 6)).toThrow("scientific notation"); + expect(() => convertToTokenAmount("1.5e-6", 9)).toThrow("scientific notation"); + expect(() => convertToTokenAmount("1E10", 6)).toThrow("scientific notation"); + }); + }); + + describe("invalid input", () => { + it("should throw for non-numeric strings", () => { + expect(() => convertToTokenAmount("invalid", 6)).toThrow("Invalid amount"); + expect(() => convertToTokenAmount("abc", 6)).toThrow("Invalid amount"); + expect(() => convertToTokenAmount("", 6)).toThrow("Invalid amount"); + expect(() => convertToTokenAmount("NaN", 6)).toThrow("Invalid amount"); + }); + }); + }); + describe("Base64 encoding", () => { const unicodeOriginal = "USD₮0 🤖 中文 ありがとう नमस्ते Привет مرحبا بالعالم שלום Γειά σου สวัสดี"; diff --git a/typescript/packages/extensions/CHANGELOG.md b/typescript/packages/extensions/CHANGELOG.md index 085352cfbe..5b91a920f3 100644 --- a/typescript/packages/extensions/CHANGELOG.md +++ b/typescript/packages/extensions/CHANGELOG.md @@ -1,5 +1,52 @@ # @x402/extensions Changelog +## 2.12.0 + +### Minor Changes + +- 608034f: Added Bazaar service metadata fields (`serviceName`, `tags`, `iconUrl`) on `ResourceInfo`, plus `isValidServiceName` / `sanitizeTags` / `isValidIconUrl` / `sanitizeResourceServiceMetadata` helpers in `@x402/extensions/bazaar` that `extractDiscoveryInfo` now applies with soft-drop semantics. Fields are optional and additive — providers that omit them produce byte-identical 402 bodies. +- ee7c156: chore: tighten viem dependency floor to ^2.48.11 + + Raises the viem floor in every `@x402/*` package.json that lists viem as a direct dep so future `pnpm install` re-resolutions cannot regress below this version. Fixes the incomplete tightening from #2013. + +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] + - @x402/core@2.12.0 + +## 2.11.0 + +### Minor Changes + +- Updated dependencies [a051f48] +- Updated dependencies [dc04108] + - @x402/core@2.11.0 + +## 2.10.0 + +### Minor Changes + +- 9424291: chore: bump viem lockfile to 2.47.12 + + Updates the resolved viem version across all direct dependencies, adding chain definitions for Mezo Testnet, MegaETH, Stable, and Stable Testnet that were missing from previously locked versions. + +- a4e4911: Migrate SIWE dependency from `siwe` (Spruce) to `@signinwithethereum/siwe` (Ethereum Identity Foundation). The new package is the official successor, supports viem natively as a peer dependency, and maintains the same `SiweMessage` API. + - @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization + +### Patch Changes + +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/extensions/README.md b/typescript/packages/extensions/README.md index f937322d0a..1301a903c5 100644 --- a/typescript/packages/extensions/README.md +++ b/typescript/packages/extensions/README.md @@ -1,4 +1,4 @@ -# @x402/extensions +# `@x402/extensions` • [![npm version](https://img.shields.io/npm/v/%40x402%2Fextensions.svg)](https://www.npmjs.com/package/@x402/extensions) x402 Payment Protocol Extensions. This package provides optional extensions that enhance the x402 payment protocol with additional functionality. diff --git a/typescript/packages/extensions/package.json b/typescript/packages/extensions/package.json index abc827908f..634def85a1 100644 --- a/typescript/packages/extensions/package.json +++ b/typescript/packages/extensions/package.json @@ -1,6 +1,6 @@ { "name": "@x402/extensions", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/cjs/index.d.ts", @@ -22,8 +22,8 @@ "extensions" ], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol Extensions", "devDependencies": { "@eslint/js": "^9.24.0", @@ -36,7 +36,7 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", @@ -48,9 +48,9 @@ "@x402/core": "workspace:~", "ajv": "^8.17.1", "jose": "^5.9.6", - "siwe": "^2.3.2", + "@signinwithethereum/siwe": "^4.1.0", "tweetnacl": "^1.0.3", - "viem": "^2.43.5", + "viem": "^2.48.11", "zod": "^3.24.2" }, "exports": { diff --git a/typescript/packages/extensions/src/bazaar/facilitator.ts b/typescript/packages/extensions/src/bazaar/facilitator.ts index 201489a868..f7b8dd0daa 100644 --- a/typescript/packages/extensions/src/bazaar/facilitator.ts +++ b/typescript/packages/extensions/src/bazaar/facilitator.ts @@ -7,8 +7,14 @@ * Supports both v2 (extensions in PaymentRequired) and v1 (outputSchema in PaymentRequirements). */ +import { domainToASCII } from "node:url"; import Ajv from "ajv/dist/2020.js"; -import type { PaymentPayload, PaymentRequirements, PaymentRequirementsV1 } from "@x402/core/types"; +import type { + PaymentPayload, + PaymentRequirements, + PaymentRequirementsV1, + ResourceInfo, +} from "@x402/core/types"; import type { DiscoveryExtension, DiscoveryInfo } from "./types"; import type { McpDiscoveryInfo } from "./mcp/types"; import type { DiscoveredHTTPResource } from "./http/types"; @@ -70,6 +76,212 @@ export function validateRouteTemplate(value: string | undefined): string | undef return isValidRouteTemplate(value) ? value : undefined; } +/** + * Maximum lengths for resource service metadata fields. Spec: see + * `specs/extensions/bazaar.md` "Service Metadata on `resource`". + */ +const MAX_SERVICE_NAME_LEN = 32; +const MAX_TAG_LEN = 32; +const MAX_TAGS = 5; +const MAX_ICON_URL_LEN = 2048; +// Matches ASCII control characters (C0 + DEL). +const CONTROL_CHAR_REGEX = /[\x00-\x1f\x7f]/; +// Printable ASCII range (U+0020–U+007E). `serviceName` and `tags` are +// constrained to this range so that String.length (UTF-16 code units), +// len() in Python (code points), and len() in Go (UTF-8 bytes) all agree +// on the character count. Same convention as paymentidentifier.id. +const PRINTABLE_ASCII_REGEX = /^[\x20-\x7e]+$/; +// Unicode control characters (category Cc). Defense-in-depth: the printable +// ASCII regex already rejects every control character, but this explicit +// check documents intent and would survive any future relaxation of the +// ASCII restriction. Mirrors `unicode.IsControl` (Go). +const UNICODE_CONTROL_REGEX = /\p{Cc}/u; + +// Loopback hostnames that must be rejected for SSRF defense. Includes the +// common /etc/hosts aliases on Linux/macOS (`localhost.localdomain`, +// `ip6-localhost`, `ip6-loopback`) — without these, a hostile provider could +// route the facilitator's image fetcher to its own loopback interface. +const LOOPBACK_HOSTNAMES = new Set([ + "localhost", + "localhost.localdomain", + "ip6-localhost", + "ip6-loopback", +]); +// Matches a bare IPv4 dotted-quad. IPv6 literals are detected via hostname brackets. +const IPV4_REGEX = /^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$/; +// SSRF defense: any all-digit hostname is suspect because no legitimate DNS name +// is purely numeric. Catches decimal-encoded IPs (`http://2130706433/` → 127.0.0.1) +// and short-form IPs (`http://0/` → 0.0.0.0, treated as loopback on Linux). +const ALL_DIGITS_REGEX = /^\d+$/; +// SSRF defense: hex-encoded IPs (`http://0x7f000001/` → 127.0.0.1) — same family +// of bypasses as the decimal form above. +const HEX_LITERAL_REGEX = /^0x[0-9a-f]+$/i; + +/** + * Checks whether a serviceName value is structurally valid for the bazaar + * `resource.serviceName` field. Non-empty string of printable ASCII + * (U+0020–U+007E), length ≤ 32. + * + * The ASCII restriction matches the `paymentidentifier.id` convention and + * keeps `len()` semantics identical across TS / Python / Go. + * + * Mirrors `_is_valid_service_name` (Python) and `isValidServiceName` (Go). + * All three implementations must stay in sync. + * + * @param value - The raw serviceName string from the resource object + * @returns true if the value is a valid serviceName, false otherwise + * + * @internal Exported for facilitator use. + */ +export function isValidServiceName(value: string | undefined): value is string { + if (typeof value !== "string") return false; + if (value.length === 0 || value.length > MAX_SERVICE_NAME_LEN) return false; + if (UNICODE_CONTROL_REGEX.test(value)) return false; + if (!PRINTABLE_ASCII_REGEX.test(value)) return false; + return true; +} + +/** + * Sanitizes a tags array for the bazaar `resource.tags` field. Drops entries + * that are not non-empty printable-ASCII strings of at most 32 characters, + * then truncates to the first 5 valid entries. Returns undefined when no + * entries survive (so the field can be omitted from the catalog). + * + * The ASCII restriction matches the `paymentidentifier.id` convention and + * keeps `len()` semantics identical across TS / Python / Go. + * + * Mirrors `_sanitize_tags` (Python) and `sanitizeTags` (Go). + * All three implementations must stay in sync. + * + * @param value - The raw tags value from the resource object (typed as unknown + * because callers pass it directly from a parsed JSON payload) + * @returns The sanitized tags array, or undefined if no entries survive + * + * @internal Exported for facilitator use. + */ +export function sanitizeTags(value: unknown): string[] | undefined { + if (!Array.isArray(value)) return undefined; + const out: string[] = []; + // Case-insensitive dedup: keeps the first occurrence's casing. + // Prevents catalog noise like ["Weather", "weather", "WEATHER"]. + const seen = new Set(); + for (const entry of value) { + if (typeof entry !== "string") continue; + if (entry.length === 0 || entry.length > MAX_TAG_LEN) continue; + if (UNICODE_CONTROL_REGEX.test(entry)) continue; + if (!PRINTABLE_ASCII_REGEX.test(entry)) continue; + const key = entry.toLowerCase(); + if (seen.has(key)) continue; + seen.add(key); + out.push(entry); + if (out.length === MAX_TAGS) break; + } + return out.length > 0 ? out : undefined; +} + +/** + * Checks whether an iconUrl value is structurally safe for the bazaar + * `resource.iconUrl` field. + * + * Rules (see `specs/extensions/bazaar.md` "Service Metadata on `resource`"): + * - String of length ≤ 2048 + * - No ASCII control characters + * - Parses as an absolute http:// or https:// URL + * - No userinfo (user@host) + * - Host is IDN-normalized (UTS #46) before checks, so confusable + * full-width / Unicode forms (e.g. `localhost`) collapse to their + * ASCII canonical and get caught by the loopback check + * - Host is not an IP literal (v4 or v6), not in the loopback set + * (`localhost`, `localhost.localdomain`, `ip6-localhost`, `ip6-loopback`) + * - Host is not a decimal IP encoding (e.g. `2130706433` → 127.0.0.1) or + * hex literal (e.g. `0x7f000001`) — common SSRF bypass forms + * + * Percent-decoding is applied to the hostname before IDN normalization, and + * IDN normalization runs before the IP / loopback checks (parallel to the + * routeTemplate decoder). + * + * Mirrors `_is_valid_icon_url` (Python) and `isValidIconUrl` (Go). + * All three implementations must stay in sync. + * + * @param value - The raw iconUrl string from the resource object + * @returns true if the value is a structurally safe iconUrl, false otherwise + * + * @internal Exported for facilitator use. + */ +export function isValidIconUrl(value: string | undefined): value is string { + if (typeof value !== "string") return false; + if (value.length === 0 || value.length > MAX_ICON_URL_LEN) return false; + if (CONTROL_CHAR_REGEX.test(value)) return false; + let parsed: URL; + try { + parsed = new URL(value); + } catch { + return false; + } + if (parsed.protocol !== "http:" && parsed.protocol !== "https:") return false; + if (parsed.username !== "" || parsed.password !== "") return false; + // URL.hostname strips IPv6 brackets, so detect IPv6 from the bracketed host instead. + if (parsed.host.startsWith("[")) return false; + let hostname: string; + try { + hostname = decodeURIComponent(parsed.hostname); + } catch { + return false; + } + // IDN/full-width normalization: e.g. "localhost" (full-width Latin) + // → "localhost". Without this the loopback alias check would miss + // confusable Unicode hostnames. domainToASCII applies the same WHATWG / + // UTS #46 mapping that idna.Lookup.ToASCII (Go) and idna.encode (Python) + // use; returns "" on failure. + const asciiHost = domainToASCII(hostname); + if (asciiHost === "") return false; + hostname = asciiHost.toLowerCase(); + if (hostname === "") return false; + if (LOOPBACK_HOSTNAMES.has(hostname)) return false; + if (IPV4_REGEX.test(hostname)) return false; + if (ALL_DIGITS_REGEX.test(hostname)) return false; + if (HEX_LITERAL_REGEX.test(hostname)) return false; + return true; +} + +/** + * Sanitized service metadata extracted from a `resource` object. + */ +export interface SanitizedResourceServiceMetadata { + serviceName?: string; + tags?: string[]; + iconUrl?: string; +} + +/** + * Applies the bazaar service-metadata validation rules to a `resource` object + * and returns only the fields that survive. Missing or invalid fields are + * dropped silently (soft-drop semantics — see spec). + * + * @param resource - The raw `resource` object from a PaymentRequired or + * PaymentPayload, or undefined. + * @returns An object containing only the valid serviceName / tags / iconUrl. + * + * @internal Exported for facilitator use. + */ +export function sanitizeResourceServiceMetadata( + resource: ResourceInfo | undefined | null, +): SanitizedResourceServiceMetadata { + if (!resource) return {}; + const out: SanitizedResourceServiceMetadata = {}; + if (isValidServiceName(resource.serviceName)) { + out.serviceName = resource.serviceName; + } + const tags = sanitizeTags(resource.tags); + if (tags) { + out.tags = tags; + } + if (isValidIconUrl(resource.iconUrl)) { + out.iconUrl = resource.iconUrl; + } + return out; +} + /** * Validation result for discovery extensions */ @@ -238,10 +450,13 @@ export function extractDiscoveryInfo( // Extract description and mimeType from resource info (v2) or requirements (v1) let description: string | undefined; let mimeType: string | undefined; + let serviceMetadata: SanitizedResourceServiceMetadata = {}; if (paymentPayload.x402Version === 2) { description = paymentPayload.resource?.description; mimeType = paymentPayload.resource?.mimeType; + // Service metadata only exists in v2; v1 had no equivalent. + serviceMetadata = sanitizeResourceServiceMetadata(paymentPayload.resource); } else if (paymentPayload.x402Version === 1) { const requirementsV1 = paymentRequirements as PaymentRequirementsV1; description = requirementsV1.description; @@ -252,6 +467,7 @@ export function extractDiscoveryInfo( resourceUrl: canonicalUrl, description, mimeType, + ...serviceMetadata, x402Version: paymentPayload.x402Version, discoveryInfo, }; diff --git a/typescript/packages/extensions/src/bazaar/facilitatorClient.ts b/typescript/packages/extensions/src/bazaar/facilitatorClient.ts index 8e62ba0d13..6e8c7e509b 100644 --- a/typescript/packages/extensions/src/bazaar/facilitatorClient.ts +++ b/typescript/packages/extensions/src/bazaar/facilitatorClient.ts @@ -16,6 +16,26 @@ export interface ListDiscoveryResourcesParams { */ type?: string; + /** + * Filter by payment recipient address. + */ + payTo?: string; + + /** + * Filter by payment scheme (e.g., "exact"). + */ + scheme?: string; + + /** + * Filter by payment network (e.g., "eip155:8453"). + */ + network?: string; + + /** + * Filter by extension key present on the discovered resource. + */ + extensions?: string; + /** * The number of discovered x402 resources to return per page. */ @@ -27,6 +47,51 @@ export interface ListDiscoveryResourcesParams { offset?: number; } +/** + * Parameters for searching discovery resources. + */ +export interface SearchDiscoveryResourcesParams { + /** + * Natural-language search query. + */ + query: string; + + /** + * Filter by protocol type (e.g., "http", "mcp"). + */ + type?: string; + + /** + * Filter by payment recipient address. + */ + payTo?: string; + + /** + * Filter by payment scheme (e.g., "exact"). + */ + scheme?: string; + + /** + * Filter by payment network (e.g., "eip155:8453"). + */ + network?: string; + + /** + * Filter by extension key present on the discovered resource. + */ + extensions?: string; + + /** + * Advisory maximum number of results. The server may return fewer or ignore this. + */ + limit?: number; + + /** + * Advisory continuation cursor from a previous response. The server may ignore this. + */ + cursor?: string; +} + /** * A discovered x402 resource from the bazaar. */ @@ -41,8 +106,8 @@ export interface DiscoveryResource { accepts: PaymentRequirements[]; /** ISO 8601 timestamp of when the resource was last updated */ lastUpdated: string; - /** Additional metadata about the resource */ - metadata?: Record; + /** Additional extension payloads attached to this discovered resource */ + extensions?: Record; } /** @@ -64,11 +129,30 @@ export interface DiscoveryResourcesResponse { }; } +/** + * Response from searching discovery resources. + */ +export interface SearchDiscoveryResourcesResponse { + /** The x402 protocol version of this response */ + x402Version: number; + /** The list of matching discovered resources */ + resources: DiscoveryResource[]; + /** Whether additional matches were truncated by facilitator */ + partialResults?: boolean; + /** Optional pagination details when a paginated response is returned */ + pagination?: { + /** Number of results in this page */ + limit: number; + /** Continuation cursor for the next page; may be null */ + cursor: string | null; + } | null; +} + /** * Bazaar client extension interface providing discovery query functionality. */ export interface BazaarClientExtension { - discovery: { + bazaar: { /** * List x402 discovery resources from the bazaar. * @@ -76,6 +160,17 @@ export interface BazaarClientExtension { * @returns A promise resolving to the discovery resources response */ listResources(params?: ListDiscoveryResourcesParams): Promise; + + /** + * Search x402 discovery resources from the bazaar using a natural-language query. + * + * Pagination is optional: facilitators may ignore `limit` and `cursor`, or include + * `response.pagination` when pagination is used. + * + * @param params - Search parameters including the required query string + * @returns A promise resolving to the search response + */ + search(params: SearchDiscoveryResourcesParams): Promise; }; } @@ -90,12 +185,15 @@ export interface BazaarClientExtension { * ```ts * // Basic usage * const client = withBazaar(new HTTPFacilitatorClient()); - * const resources = await client.extensions.discovery.listResources({ type: "http" }); + * const resources = await client.extensions.bazaar.listResources({ type: "http" }); + * + * // Search + * const results = await client.extensions.bazaar.search({ query: "weather APIs" }); * * // Chaining with other extensions * const client = withBazaar(withOtherExtension(new HTTPFacilitatorClient())); * await client.extensions.other.someMethod(); - * await client.extensions.discovery.listResources(); + * await client.extensions.bazaar.listResources(); * ``` */ export function withBazaar( @@ -109,7 +207,7 @@ export function withBazaar( extended.extensions = { ...existingExtensions, - discovery: { + bazaar: { async listResources( params?: ListDiscoveryResourcesParams, ): Promise { @@ -117,13 +215,25 @@ export function withBazaar( "Content-Type": "application/json", }; - const authHeaders = await client.createAuthHeaders("discovery"); + const authHeaders = await client.createAuthHeaders("bazaar"); headers = { ...headers, ...authHeaders.headers }; const queryParams = new URLSearchParams(); if (params?.type !== undefined) { queryParams.set("type", params.type); } + if (params?.payTo !== undefined) { + queryParams.set("payTo", params.payTo); + } + if (params?.scheme !== undefined) { + queryParams.set("scheme", params.scheme); + } + if (params?.network !== undefined) { + queryParams.set("network", params.network); + } + if (params?.extensions !== undefined) { + queryParams.set("extensions", params.extensions); + } if (params?.limit !== undefined) { queryParams.set("limit", params.limit.toString()); } @@ -148,6 +258,57 @@ export function withBazaar( return (await response.json()) as DiscoveryResourcesResponse; }, + + async search( + params: SearchDiscoveryResourcesParams, + ): Promise { + let headers: Record = { + "Content-Type": "application/json", + }; + + const authHeaders = await client.createAuthHeaders("bazaar"); + headers = { ...headers, ...authHeaders.headers }; + + const queryParams = new URLSearchParams(); + queryParams.set("query", params.query); + if (params.type !== undefined) { + queryParams.set("type", params.type); + } + if (params.payTo !== undefined) { + queryParams.set("payTo", params.payTo); + } + if (params.scheme !== undefined) { + queryParams.set("scheme", params.scheme); + } + if (params.network !== undefined) { + queryParams.set("network", params.network); + } + if (params.extensions !== undefined) { + queryParams.set("extensions", params.extensions); + } + if (params.limit !== undefined) { + queryParams.set("limit", params.limit.toString()); + } + if (params.cursor !== undefined) { + queryParams.set("cursor", params.cursor); + } + + const endpoint = `${client.url}/discovery/search?${queryParams.toString()}`; + + const response = await fetch(endpoint, { + method: "GET", + headers, + }); + + if (!response.ok) { + const errorText = await response.text().catch(() => response.statusText); + throw new Error( + `Facilitator searchDiscoveryResources failed (${response.status}): ${errorText}`, + ); + } + + return (await response.json()) as SearchDiscoveryResourcesResponse; + }, }, } as WithExtensions["extensions"]; diff --git a/typescript/packages/extensions/src/bazaar/http/types.ts b/typescript/packages/extensions/src/bazaar/http/types.ts index be47d0d6b0..d8dd612a08 100644 --- a/typescript/packages/extensions/src/bazaar/http/types.ts +++ b/typescript/packages/extensions/src/bazaar/http/types.ts @@ -176,6 +176,10 @@ export interface DiscoveredHTTPResource { resourceUrl: string; description?: string; mimeType?: string; + /** Sanitized service metadata. See `sanitizeResourceServiceMetadata` for rules. */ + serviceName?: string; + tags?: string[]; + iconUrl?: string; /** Present after server extension enrichment; may be absent for pre-enrichment data */ method?: string; routeTemplate?: string; diff --git a/typescript/packages/extensions/src/bazaar/index.ts b/typescript/packages/extensions/src/bazaar/index.ts index 235f713bfd..6a6afa1755 100644 --- a/typescript/packages/extensions/src/bazaar/index.ts +++ b/typescript/packages/extensions/src/bazaar/index.ts @@ -114,10 +114,15 @@ export { validateDiscoveryExtension, isValidRouteTemplate, validateRouteTemplate, + isValidServiceName, + sanitizeTags, + isValidIconUrl, + sanitizeResourceServiceMetadata, extractDiscoveryInfo, extractDiscoveryInfoFromExtension, validateAndExtract, type ValidationResult, + type SanitizedResourceServiceMetadata, type DiscoveredHTTPResource, type DiscoveredMCPResource, type DiscoveredResource, @@ -129,8 +134,10 @@ export { extractDiscoveryInfoV1, isDiscoverableV1, extractResourceMetadataV1 } f // Export client extension (for facilitator clients querying discovery) export { withBazaar, - BazaarClientExtension, - ListDiscoveryResourcesParams, - DiscoveryResource, - DiscoveryResourcesResponse, + type BazaarClientExtension, + type ListDiscoveryResourcesParams, + type SearchDiscoveryResourcesParams, + type DiscoveryResource, + type DiscoveryResourcesResponse, + type SearchDiscoveryResourcesResponse, } from "./facilitatorClient"; diff --git a/typescript/packages/extensions/src/bazaar/mcp/resourceService.ts b/typescript/packages/extensions/src/bazaar/mcp/resourceService.ts index ca8b122323..3802575c39 100644 --- a/typescript/packages/extensions/src/bazaar/mcp/resourceService.ts +++ b/typescript/packages/extensions/src/bazaar/mcp/resourceService.ts @@ -68,7 +68,9 @@ export function createMcpDiscoveryExtension({ ? { transport: { type: "string" as const, - enum: ["streamable-http", "sse"], + ...(transport === "streamable-http" || transport === "sse" + ? { enum: [transport] } + : {}), }, } : {}), diff --git a/typescript/packages/extensions/src/bazaar/mcp/types.ts b/typescript/packages/extensions/src/bazaar/mcp/types.ts index a2aa97b4a8..99f4495c65 100644 --- a/typescript/packages/extensions/src/bazaar/mcp/types.ts +++ b/typescript/packages/extensions/src/bazaar/mcp/types.ts @@ -12,7 +12,7 @@ export interface McpDiscoveryInfo { type: "mcp"; toolName: string; description?: string; - transport?: "streamable-http" | "sse"; + transport?: string; inputSchema: Record; example?: Record; }; @@ -48,7 +48,7 @@ export interface McpDiscoveryExtension { }; transport?: { type: "string"; - enum: ["streamable-http", "sse"]; + enum?: string[]; }; inputSchema: Record; example?: Record; @@ -70,7 +70,7 @@ export interface McpDiscoveryExtension { export interface DeclareMcpDiscoveryExtensionConfig { toolName: string; description?: string; - transport?: "streamable-http" | "sse"; + transport?: string; inputSchema: Record; example?: Record; output?: { @@ -83,6 +83,10 @@ export interface DiscoveredMCPResource { resourceUrl: string; description?: string; mimeType?: string; + /** Sanitized service metadata. See `sanitizeResourceServiceMetadata` for rules. */ + serviceName?: string; + tags?: string[]; + iconUrl?: string; toolName: string; x402Version: number; discoveryInfo: DiscoveryInfo; diff --git a/typescript/packages/extensions/src/sign-in-with-x/evm.ts b/typescript/packages/extensions/src/sign-in-with-x/evm.ts index 8dfae8bafc..3395ab6c62 100644 --- a/typescript/packages/extensions/src/sign-in-with-x/evm.ts +++ b/typescript/packages/extensions/src/sign-in-with-x/evm.ts @@ -6,7 +6,7 @@ */ import { verifyMessage } from "viem"; -import { SiweMessage } from "siwe"; +import { SiweMessage } from "@signinwithethereum/siwe"; import type { EVMMessageVerifier } from "./types"; import type { CompleteSIWxInfo } from "./client"; import type { SIWxSigner } from "./sign"; diff --git a/typescript/packages/extensions/test/bazaar.test.ts b/typescript/packages/extensions/test/bazaar.test.ts index 69ca52ce80..f0459606b2 100644 --- a/typescript/packages/extensions/test/bazaar.test.ts +++ b/typescript/packages/extensions/test/bazaar.test.ts @@ -8,6 +8,10 @@ import { declareDiscoveryExtension, validateDiscoveryExtension, isValidRouteTemplate, + isValidServiceName, + sanitizeTags, + isValidIconUrl, + sanitizeResourceServiceMetadata, extractDiscoveryInfo, extractDiscoveryInfoFromExtension, extractDiscoveryInfoV1, @@ -2053,4 +2057,243 @@ describe("Bazaar Discovery Extension", () => { expect(isValidRouteTemplate("/users/%2E%2E/admin")).toBe(false); }); }); + + describe("isValidServiceName", () => { + it("accepts non-empty strings up to 32 chars", () => { + expect(isValidServiceName("Example Weather")).toBe(true); + expect(isValidServiceName("a")).toBe(true); + expect(isValidServiceName("a".repeat(32))).toBe(true); + }); + + it("rejects empty, undefined, and over-cap strings", () => { + expect(isValidServiceName(undefined)).toBe(false); + expect(isValidServiceName("")).toBe(false); + expect(isValidServiceName("a".repeat(33))).toBe(false); + }); + + it("rejects non-ASCII characters", () => { + // Multi-byte chars in UTF-8 — would otherwise diverge across SDKs + // (UTF-16 code units in TS, code points in Python, bytes in Go). + expect(isValidServiceName("Café Service")).toBe(false); + expect(isValidServiceName("東京 Weather")).toBe(false); + expect(isValidServiceName("🚀 Service")).toBe(false); + }); + + it("rejects ASCII control characters", () => { + expect(isValidServiceName("Service\x00")).toBe(false); + expect(isValidServiceName("Line\nBreak")).toBe(false); + expect(isValidServiceName("Tab\there")).toBe(false); + }); + + it("accepts printable ASCII with spaces and punctuation", () => { + expect(isValidServiceName("Example Weather")).toBe(true); + expect(isValidServiceName("AT&T")).toBe(true); + expect(isValidServiceName("Coinbase, Inc.")).toBe(true); + expect(isValidServiceName("Service v2.0!")).toBe(true); + }); + }); + + describe("sanitizeTags", () => { + it("returns undefined for non-arrays", () => { + expect(sanitizeTags(undefined)).toBeUndefined(); + expect(sanitizeTags("weather")).toBeUndefined(); + expect(sanitizeTags({ tag: "weather" })).toBeUndefined(); + }); + + it("drops non-string and out-of-range entries", () => { + const result = sanitizeTags(["weather", "", "a".repeat(33), 42, null, "forecast"]); + expect(result).toEqual(["weather", "forecast"]); + }); + + it("truncates to 5 valid entries", () => { + const result = sanitizeTags(["a", "b", "c", "d", "e", "f", "g"]); + expect(result).toEqual(["a", "b", "c", "d", "e"]); + }); + + it("returns undefined when nothing survives", () => { + expect(sanitizeTags(["", "a".repeat(33), 7])).toBeUndefined(); + expect(sanitizeTags([])).toBeUndefined(); + }); + + it("drops non-ASCII tags but keeps ASCII siblings", () => { + const result = sanitizeTags(["weather", "café", "東京", "🚀", "forecast"]); + expect(result).toEqual(["weather", "forecast"]); + }); + + it("dedupes case-insensitively keeping first occurrence", () => { + const result = sanitizeTags(["Weather", "weather", "WEATHER", "forecast"]); + expect(result).toEqual(["Weather", "forecast"]); + }); + }); + + describe("isValidIconUrl", () => { + it("accepts plain https and http urls", () => { + expect(isValidIconUrl("https://api.example.com/icon.png")).toBe(true); + expect(isValidIconUrl("http://api.example.com/icon")).toBe(true); + }); + + it("rejects empty, undefined, and over-cap strings", () => { + expect(isValidIconUrl(undefined)).toBe(false); + expect(isValidIconUrl("")).toBe(false); + expect(isValidIconUrl("https://example.com/" + "a".repeat(2048))).toBe(false); + }); + + it("rejects non-http schemes", () => { + expect(isValidIconUrl("data:image/png;base64,iVBOR")).toBe(false); + expect(isValidIconUrl("file:///etc/passwd")).toBe(false); + expect(isValidIconUrl("javascript:alert(1)")).toBe(false); + expect(isValidIconUrl("ftp://example.com/icon.png")).toBe(false); + }); + + it("rejects userinfo in the authority", () => { + expect(isValidIconUrl("https://user@example.com/icon.png")).toBe(false); + expect(isValidIconUrl("https://user:pass@example.com/icon.png")).toBe(false); + }); + + it("rejects IP literal hosts", () => { + expect(isValidIconUrl("http://10.0.0.1/icon.png")).toBe(false); + expect(isValidIconUrl("http://127.0.0.1/icon.png")).toBe(false); + expect(isValidIconUrl("http://[::1]/icon.png")).toBe(false); + expect(isValidIconUrl("http://[2001:db8::1]/icon.png")).toBe(false); + }); + + it("rejects decimal-encoded and short-form IP hosts", () => { + // 2130706433 == 127.0.0.1; 0 expands to 0.0.0.0 on Linux. + expect(isValidIconUrl("http://2130706433/icon.png")).toBe(false); + expect(isValidIconUrl("http://0/icon.png")).toBe(false); + expect(isValidIconUrl("http://3232235521/icon.png")).toBe(false); + }); + + it("rejects hex-encoded IP hosts", () => { + // 0x7f000001 == 127.0.0.1. + expect(isValidIconUrl("http://0x7f000001/icon.png")).toBe(false); + expect(isValidIconUrl("http://0X7F000001/icon.png")).toBe(false); + }); + + it("rejects localhost", () => { + expect(isValidIconUrl("http://localhost/icon.png")).toBe(false); + expect(isValidIconUrl("http://LOCALHOST/icon.png")).toBe(false); + }); + + it("rejects loopback aliases from /etc/hosts", () => { + expect(isValidIconUrl("http://localhost.localdomain/icon.png")).toBe(false); + expect(isValidIconUrl("http://ip6-localhost/icon.png")).toBe(false); + expect(isValidIconUrl("http://ip6-loopback/icon.png")).toBe(false); + }); + + it("rejects IDN / full-width localhost confusables", () => { + // Full-width Latin "localhost" normalizes to "localhost" via UTS #46. + expect(isValidIconUrl("http://localhost/icon.png")).toBe(false); + }); + + it("rejects control characters", () => { + expect(isValidIconUrl("https://example.com/\x00icon.png")).toBe(false); + expect(isValidIconUrl("https://example.com/icon\n.png")).toBe(false); + expect(isValidIconUrl("https://example.com/icon\x7f.png")).toBe(false); + }); + + it("rejects relative paths", () => { + expect(isValidIconUrl("/icon.png")).toBe(false); + expect(isValidIconUrl("icon.png")).toBe(false); + }); + }); + + describe("sanitizeResourceServiceMetadata", () => { + it("preserves all valid fields", () => { + const out = sanitizeResourceServiceMetadata({ + url: "https://api.example.com/x", + serviceName: "Example Weather", + tags: ["weather", "forecast"], + iconUrl: "https://api.example.com/icon.png", + }); + expect(out).toEqual({ + serviceName: "Example Weather", + tags: ["weather", "forecast"], + iconUrl: "https://api.example.com/icon.png", + }); + }); + + it("soft-drops only the invalid fields", () => { + const out = sanitizeResourceServiceMetadata({ + url: "https://api.example.com/x", + serviceName: "a".repeat(33), + tags: ["weather", "forecast"], + iconUrl: "data:image/png;base64,iVBOR", + }); + expect(out).toEqual({ tags: ["weather", "forecast"] }); + }); + + it("returns empty object for missing or non-object input", () => { + expect(sanitizeResourceServiceMetadata(undefined)).toEqual({}); + expect(sanitizeResourceServiceMetadata(null)).toEqual({}); + }); + }); + + describe("extractDiscoveryInfo - service metadata", () => { + it("surfaces sanitized serviceName / tags / iconUrl on the discovered resource", () => { + const declared = declareDiscoveryExtension({ + method: "GET", + input: { city: "NYC" }, + inputSchema: { properties: { city: { type: "string" } } }, + }); + + const paymentPayload = { + x402Version: 2, + scheme: "exact", + network: "eip155:8453" as unknown, + payload: {}, + accepted: {} as unknown, + resource: { + url: "https://api.example.com/weather", + description: "Weather API", + mimeType: "application/json", + serviceName: "Example Weather", + tags: ["weather", "forecast"], + iconUrl: "https://api.example.com/icon.png", + }, + extensions: { + [BAZAAR.key]: declared.bazaar, + }, + }; + + const discovered = extractDiscoveryInfo(paymentPayload, {} as unknown); + + expect(discovered).not.toBeNull(); + expect(discovered!.serviceName).toBe("Example Weather"); + expect(discovered!.tags).toEqual(["weather", "forecast"]); + expect(discovered!.iconUrl).toBe("https://api.example.com/icon.png"); + }); + + it("soft-drops invalid metadata fields independently", () => { + const declared = declareDiscoveryExtension({ + method: "GET", + input: {}, + inputSchema: { properties: {} }, + }); + + const paymentPayload = { + x402Version: 2, + scheme: "exact", + network: "eip155:8453" as unknown, + payload: {}, + accepted: {} as unknown, + resource: { + url: "https://api.example.com/weather", + serviceName: "a".repeat(33), + tags: ["weather", "", "forecast"], + iconUrl: "http://localhost/icon.png", + }, + extensions: { + [BAZAAR.key]: declared.bazaar, + }, + }; + + const discovered = extractDiscoveryInfo(paymentPayload, {} as unknown); + + expect(discovered).not.toBeNull(); + expect(discovered!.serviceName).toBeUndefined(); + expect(discovered!.tags).toEqual(["weather", "forecast"]); + expect(discovered!.iconUrl).toBeUndefined(); + }); + }); }); diff --git a/typescript/packages/extensions/test/facilitatorClient.test.ts b/typescript/packages/extensions/test/facilitatorClient.test.ts index d816242369..778c653147 100644 --- a/typescript/packages/extensions/test/facilitatorClient.test.ts +++ b/typescript/packages/extensions/test/facilitatorClient.test.ts @@ -10,6 +10,8 @@ import { type DiscoveryResource, type DiscoveryResourcesResponse, type ListDiscoveryResourcesParams, + type SearchDiscoveryResourcesParams, + type SearchDiscoveryResourcesResponse, } from "../src/bazaar/facilitatorClient"; import { HTTPFacilitatorClient } from "@x402/core/http"; @@ -33,7 +35,7 @@ describe("Bazaar Client Extension - facilitatorClient", () => { }, ], lastUpdated: "2024-01-01T00:00:00.000Z", - metadata: { category: "weather" }, + extensions: { bazaar: { category: "weather" } }, }; expect(resource.resource).toBe("https://api.example.com/endpoint"); @@ -41,20 +43,20 @@ describe("Bazaar Client Extension - facilitatorClient", () => { expect(resource.x402Version).toBe(2); expect(resource.accepts).toHaveLength(1); expect(resource.lastUpdated).toBe("2024-01-01T00:00:00.000Z"); - expect(resource.metadata).toEqual({ category: "weather" }); + expect(resource.extensions).toEqual({ bazaar: { category: "weather" } }); }); - it("DiscoveryResource should allow optional metadata", () => { + it("DiscoveryResource should allow optional extensions", () => { const resource: DiscoveryResource = { resource: "https://api.example.com/endpoint", type: "http", x402Version: 1, accepts: [], lastUpdated: "2024-01-01T00:00:00.000Z", - // metadata is optional + // extensions is optional }; - expect(resource.metadata).toBeUndefined(); + expect(resource.extensions).toBeUndefined(); }); it("DiscoveryResourcesResponse should have correct shape with pagination", () => { @@ -86,13 +88,70 @@ describe("Bazaar Client Extension - facilitatorClient", () => { it("ListDiscoveryResourcesParams should accept optional parameters", () => { const params1: ListDiscoveryResourcesParams = {}; const params2: ListDiscoveryResourcesParams = { type: "http" }; - const params3: ListDiscoveryResourcesParams = { type: "http", limit: 10, offset: 5 }; + const params3: ListDiscoveryResourcesParams = { + type: "http", + payTo: "0x1234567890123456789012345678901234567890", + scheme: "exact", + network: "eip155:8453", + extensions: "bazaar", + limit: 10, + offset: 5, + }; expect(params1.type).toBeUndefined(); expect(params2.type).toBe("http"); + expect(params3.payTo).toBe("0x1234567890123456789012345678901234567890"); + expect(params3.scheme).toBe("exact"); + expect(params3.network).toBe("eip155:8453"); + expect(params3.extensions).toBe("bazaar"); expect(params3.limit).toBe(10); expect(params3.offset).toBe(5); }); + + it("SearchDiscoveryResourcesParams should require query and accept optional fields", () => { + const params1: SearchDiscoveryResourcesParams = { query: "weather APIs" }; + const params2: SearchDiscoveryResourcesParams = { + query: "financial data", + type: "http", + payTo: "0x1234567890123456789012345678901234567890", + scheme: "exact", + network: "eip155:8453", + extensions: "bazaar", + limit: 10, + cursor: "abc123", + }; + + expect(params1.query).toBe("weather APIs"); + expect(params1.type).toBeUndefined(); + expect(params2.payTo).toBe("0x1234567890123456789012345678901234567890"); + expect(params2.scheme).toBe("exact"); + expect(params2.network).toBe("eip155:8453"); + expect(params2.extensions).toBe("bazaar"); + expect(params2.limit).toBe(10); + expect(params2.cursor).toBe("abc123"); + }); + + it("SearchDiscoveryResourcesResponse should have correct shape", () => { + const response: SearchDiscoveryResourcesResponse = { + x402Version: 2, + resources: [], + pagination: { limit: 10, cursor: null }, + }; + + expect(response.x402Version).toBe(2); + expect(response.pagination?.limit).toBe(10); + expect(response.pagination?.cursor).toBeNull(); + }); + + it("SearchDiscoveryResourcesResponse should allow null pagination", () => { + const response: SearchDiscoveryResourcesResponse = { + x402Version: 2, + resources: [], + pagination: null, + }; + + expect(response.pagination).toBeNull(); + }); }); describe("withBazaar", () => { @@ -110,7 +169,7 @@ describe("Bazaar Client Extension - facilitatorClient", () => { vi.restoreAllMocks(); }); - it("should extend client with discovery.listResources method", () => { + it("should extend client with bazaar.listResources and bazaar.search methods", () => { const facilitatorClient = new HTTPFacilitatorClient({ url: "https://x402.org/facilitator", }); @@ -118,8 +177,9 @@ describe("Bazaar Client Extension - facilitatorClient", () => { const extendedClient = withBazaar(facilitatorClient); expect(extendedClient.extensions).toBeDefined(); - expect(extendedClient.extensions.discovery).toBeDefined(); - expect(typeof extendedClient.extensions.discovery.listResources).toBe("function"); + expect(extendedClient.extensions.bazaar).toBeDefined(); + expect(typeof extendedClient.extensions.bazaar.listResources).toBe("function"); + expect(typeof extendedClient.extensions.bazaar.search).toBe("function"); }); it("should preserve existing extensions when chaining", () => { @@ -138,135 +198,261 @@ describe("Bazaar Client Extension - facilitatorClient", () => { const extendedClient = withBazaar(clientWithExtensions); // Should have both the existing and new extensions - expect(extendedClient.extensions.discovery).toBeDefined(); + expect(extendedClient.extensions.bazaar).toBeDefined(); expect((extendedClient.extensions as { other?: unknown }).other).toBeDefined(); }); - it("listResources should call correct endpoint with no params", async () => { - const mockResponse: DiscoveryResourcesResponse = { - x402Version: 2, - items: [], - pagination: { limit: 20, offset: 0, total: 0 }, - }; - - mockFetch.mockResolvedValue({ - ok: true, - json: () => Promise.resolve(mockResponse), + describe("listResources", () => { + it("should call correct endpoint with no params", async () => { + const mockResponse: DiscoveryResourcesResponse = { + x402Version: 2, + items: [], + pagination: { limit: 20, offset: 0, total: 0 }, + }; + + mockFetch.mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockResponse), + }); + + const facilitatorClient = new HTTPFacilitatorClient({ + url: "https://x402.org/facilitator", + }); + const extendedClient = withBazaar(facilitatorClient); + + const result = await extendedClient.extensions.bazaar.listResources(); + + expect(mockFetch).toHaveBeenCalledTimes(1); + const [url, options] = mockFetch.mock.calls[0]; + expect(url).toBe("https://x402.org/facilitator/discovery/resources"); + expect(options.method).toBe("GET"); + expect(result).toEqual(mockResponse); }); - const facilitatorClient = new HTTPFacilitatorClient({ - url: "https://x402.org/facilitator", - }); - const extendedClient = withBazaar(facilitatorClient); - - const result = await extendedClient.extensions.discovery.listResources(); - - expect(mockFetch).toHaveBeenCalledTimes(1); - const [url, options] = mockFetch.mock.calls[0]; - expect(url).toBe("https://x402.org/facilitator/discovery/resources"); - expect(options.method).toBe("GET"); - expect(result).toEqual(mockResponse); - }); - - it("listResources should include query params when provided", async () => { - const mockResponse: DiscoveryResourcesResponse = { - x402Version: 2, - items: [], - pagination: { limit: 10, offset: 5, total: 100 }, - }; - - mockFetch.mockResolvedValue({ - ok: true, - json: () => Promise.resolve(mockResponse), + it("should include query params when provided", async () => { + const mockResponse: DiscoveryResourcesResponse = { + x402Version: 2, + items: [], + pagination: { limit: 10, offset: 5, total: 100 }, + }; + + mockFetch.mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockResponse), + }); + + const facilitatorClient = new HTTPFacilitatorClient({ + url: "https://x402.org/facilitator", + }); + const extendedClient = withBazaar(facilitatorClient); + + await extendedClient.extensions.bazaar.listResources({ + type: "http", + payTo: "0x1234567890123456789012345678901234567890", + scheme: "exact", + network: "eip155:8453", + extensions: "bazaar", + limit: 10, + offset: 5, + }); + + const [url] = mockFetch.mock.calls[0]; + expect(url).toContain("type=http"); + expect(url).toContain("payTo=0x1234567890123456789012345678901234567890"); + expect(url).toContain("scheme=exact"); + expect(url).toContain("network=eip155%3A8453"); + expect(url).toContain("extensions=bazaar"); + expect(url).toContain("limit=10"); + expect(url).toContain("offset=5"); }); - const facilitatorClient = new HTTPFacilitatorClient({ - url: "https://x402.org/facilitator", + it("should throw error on non-ok response", async () => { + mockFetch.mockResolvedValue({ + ok: false, + status: 500, + statusText: "Internal Server Error", + text: () => Promise.resolve("Server error"), + }); + + const facilitatorClient = new HTTPFacilitatorClient({ + url: "https://x402.org/facilitator", + }); + const extendedClient = withBazaar(facilitatorClient); + + await expect(extendedClient.extensions.bazaar.listResources()).rejects.toThrow( + "Facilitator listDiscoveryResources failed (500)", + ); }); - const extendedClient = withBazaar(facilitatorClient); - await extendedClient.extensions.discovery.listResources({ - type: "http", - limit: 10, - offset: 5, + it("should return properly typed response matching CDP API", async () => { + const mockResponse: DiscoveryResourcesResponse = { + x402Version: 1, + items: [ + { + resource: "https://x402.mode.network/ta/indicators", + type: "http", + x402Version: 1, + accepts: [ + { + scheme: "exact", + network: "eip155:8453", + asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + amount: "1000", + payTo: "0xa2477E16dCB42E2AD80f03FE97D7F1a1646cd1c0", + maxTimeoutSeconds: 60, + extra: { name: "USD Coin", version: "2" }, + }, + ], + lastUpdated: "2024-01-01T00:00:00.000Z", + extensions: {}, + }, + ], + pagination: { + limit: 1, + offset: 0, + total: 12234, + }, + }; + + mockFetch.mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockResponse), + }); + + const facilitatorClient = new HTTPFacilitatorClient({ + url: "https://x402.org/facilitator", + }); + const extendedClient = withBazaar(facilitatorClient); + + const result = await extendedClient.extensions.bazaar.listResources({ limit: 1 }); + + expect(result.x402Version).toBe(1); + expect(result.items).toHaveLength(1); + expect(result.items[0].resource).toBe("https://x402.mode.network/ta/indicators"); + expect(result.items[0].type).toBe("http"); + expect(result.items[0].x402Version).toBe(1); + expect(result.items[0].accepts).toHaveLength(1); + expect(result.items[0].lastUpdated).toBe("2024-01-01T00:00:00.000Z"); + expect(result.pagination.total).toBe(12234); }); - - const [url] = mockFetch.mock.calls[0]; - expect(url).toContain("type=http"); - expect(url).toContain("limit=10"); - expect(url).toContain("offset=5"); }); - it("listResources should throw error on non-ok response", async () => { - mockFetch.mockResolvedValue({ - ok: false, - status: 500, - statusText: "Internal Server Error", - text: () => Promise.resolve("Server error"), + describe("search", () => { + it("should call correct endpoint with required query param", async () => { + const mockResponse: SearchDiscoveryResourcesResponse = { + x402Version: 2, + resources: [], + }; + + mockFetch.mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockResponse), + }); + + const facilitatorClient = new HTTPFacilitatorClient({ + url: "https://x402.org/facilitator", + }); + const extendedClient = withBazaar(facilitatorClient); + + const result = await extendedClient.extensions.bazaar.search({ + query: "weather APIs", + }); + + expect(mockFetch).toHaveBeenCalledTimes(1); + const [url, options] = mockFetch.mock.calls[0]; + expect(url).toContain("/discovery/search"); + expect(url).toContain("query=weather+APIs"); + expect(options.method).toBe("GET"); + expect(result.pagination).toBeUndefined(); }); - const facilitatorClient = new HTTPFacilitatorClient({ - url: "https://x402.org/facilitator", + it("should include optional params when provided", async () => { + const mockResponse: SearchDiscoveryResourcesResponse = { + x402Version: 2, + resources: [], + pagination: { limit: 10, cursor: "eyJwYWdlIjoyfQ==" }, + }; + + mockFetch.mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockResponse), + }); + + const facilitatorClient = new HTTPFacilitatorClient({ + url: "https://x402.org/facilitator", + }); + const extendedClient = withBazaar(facilitatorClient); + + await extendedClient.extensions.bazaar.search({ + query: "financial data", + type: "http", + payTo: "0x1234567890123456789012345678901234567890", + scheme: "exact", + network: "eip155:8453", + extensions: "bazaar", + limit: 10, + cursor: "eyJwYWdlIjoyfQ==", + }); + + const [url] = mockFetch.mock.calls[0]; + expect(url).toContain("type=http"); + expect(url).toContain("payTo=0x1234567890123456789012345678901234567890"); + expect(url).toContain("scheme=exact"); + expect(url).toContain("network=eip155%3A8453"); + expect(url).toContain("extensions=bazaar"); + expect(url).toContain("limit=10"); + expect(url).toContain("cursor="); }); - const extendedClient = withBazaar(facilitatorClient); - - await expect(extendedClient.extensions.discovery.listResources()).rejects.toThrow( - "Facilitator listDiscoveryResources failed (500)", - ); - }); - it("listResources should return properly typed response matching CDP API", async () => { - // Mock response matching actual CDP API structure - const mockResponse: DiscoveryResourcesResponse = { - x402Version: 1, - items: [ - { - resource: "https://x402.mode.network/ta/indicators", - type: "http", - x402Version: 1, - accepts: [ - { - scheme: "exact", - network: "eip155:8453", - asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - amount: "1000", - payTo: "0xa2477E16dCB42E2AD80f03FE97D7F1a1646cd1c0", - maxTimeoutSeconds: 60, - extra: { name: "USD Coin", version: "2" }, - }, - ], - lastUpdated: "2024-01-01T00:00:00.000Z", - metadata: {}, - }, - ], - pagination: { - limit: 1, - offset: 0, - total: 12234, - }, - }; - - mockFetch.mockResolvedValue({ - ok: true, - json: () => Promise.resolve(mockResponse), + it("should throw error on non-ok search response", async () => { + mockFetch.mockResolvedValue({ + ok: false, + status: 400, + statusText: "Bad Request", + text: () => Promise.resolve("query is required"), + }); + + const facilitatorClient = new HTTPFacilitatorClient({ + url: "https://x402.org/facilitator", + }); + const extendedClient = withBazaar(facilitatorClient); + + await expect(extendedClient.extensions.bazaar.search({ query: "test" })).rejects.toThrow( + "Facilitator searchDiscoveryResources failed (400)", + ); }); - const facilitatorClient = new HTTPFacilitatorClient({ - url: "https://x402.org/facilitator", + it("should handle paginated search response with cursor", async () => { + const mockResponse: SearchDiscoveryResourcesResponse = { + x402Version: 2, + resources: [ + { + resource: "https://api.example.com/weather", + type: "http", + x402Version: 2, + accepts: [], + lastUpdated: "2024-01-01T00:00:00.000Z", + }, + ], + pagination: { limit: 10, cursor: "nextPageToken" }, + }; + + mockFetch.mockResolvedValue({ + ok: true, + json: () => Promise.resolve(mockResponse), + }); + + const facilitatorClient = new HTTPFacilitatorClient({ + url: "https://x402.org/facilitator", + }); + const extendedClient = withBazaar(facilitatorClient); + + const result = await extendedClient.extensions.bazaar.search({ query: "weather" }); + + expect(result.resources).toHaveLength(1); + expect(result.pagination?.limit).toBe(10); + expect(result.pagination?.cursor).toBe("nextPageToken"); }); - const extendedClient = withBazaar(facilitatorClient); - - const result = await extendedClient.extensions.discovery.listResources({ limit: 1 }); - - // Validate response structure matches our fixed types - expect(result.x402Version).toBe(1); - expect(result.items).toHaveLength(1); - expect(result.items[0].resource).toBe("https://x402.mode.network/ta/indicators"); - expect(result.items[0].type).toBe("http"); - expect(result.items[0].x402Version).toBe(1); - expect(result.items[0].accepts).toHaveLength(1); - expect(result.items[0].lastUpdated).toBe("2024-01-01T00:00:00.000Z"); - expect(result.pagination.total).toBe(12234); }); }); }); diff --git a/typescript/packages/http/axios/CHANGELOG.md b/typescript/packages/http/axios/CHANGELOG.md index db2ff2bd6b..138f5706f6 100644 --- a/typescript/packages/http/axios/CHANGELOG.md +++ b/typescript/packages/http/axios/CHANGELOG.md @@ -1,5 +1,43 @@ # @x402/axios Changelog +## 2.12.0 + +### Minor Changes + +- 45d7d19: Added processPaymentResult utility and recovery hook +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] + - @x402/core@2.12.0 + +## 2.11.0 + +### Minor Changes + +- Updated dependencies [a051f48] +- Updated dependencies [dc04108] + - @x402/core@2.11.0 + +## 2.10.0 + +### Minor Changes + +- @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization + +### Patch Changes + +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/http/axios/README.md b/typescript/packages/http/axios/README.md index 6cd3b42466..f549d2eb34 100644 --- a/typescript/packages/http/axios/README.md +++ b/typescript/packages/http/axios/README.md @@ -1,4 +1,4 @@ -# x402-axios +# `@x402/axios` [![npm version](https://img.shields.io/npm/v/%40x402%2Faxios.svg)](https://www.npmjs.com/package/@x402/axios) A utility package that extends Axios to automatically handle 402 Payment Required responses using the x402 payment protocol v2. This package enables seamless integration of payment functionality into your applications when making HTTP requests. diff --git a/typescript/packages/http/axios/package.json b/typescript/packages/http/axios/package.json index 35431041b3..3c04701760 100644 --- a/typescript/packages/http/axios/package.json +++ b/typescript/packages/http/axios/package.json @@ -1,6 +1,6 @@ { "name": "@x402/axios", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/index.d.ts", @@ -17,30 +17,32 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@eslint/js": "^9.24.0", "@types/node": "^22.13.4", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", + "axios": "^1.7.9", "eslint": "^9.24.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsdoc": "^50.6.9", "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.0.5", "vite": "^6.2.6" }, "dependencies": { - "axios": "^1.7.9", - "@x402/core": "workspace:~", - "zod": "^3.24.2" + "@x402/core": "workspace:~" + }, + "peerDependencies": { + "axios": "^1.7.9" }, "exports": { ".": { diff --git a/typescript/packages/http/axios/src/index.test.ts b/typescript/packages/http/axios/src/index.test.ts index d69f66f52f..c1eb488f42 100644 --- a/typescript/packages/http/axios/src/index.test.ts +++ b/typescript/packages/http/axios/src/index.test.ts @@ -16,6 +16,7 @@ vi.mock("@x402/core/client", () => { MockX402HTTPClient.prototype.getPaymentRequiredResponse = vi.fn(); MockX402HTTPClient.prototype.encodePaymentSignatureHeader = vi.fn(); MockX402HTTPClient.prototype.handlePaymentRequired = vi.fn(); + MockX402HTTPClient.prototype.processPaymentResult = vi.fn(); const MockX402Client = vi.fn() as ReturnType & { fromConfig: ReturnType; @@ -90,6 +91,19 @@ describe("wrapAxiosWithPayment()", () => { ); }; + const createAxiosResponse = ( + status: number, + data?: unknown, + headers?: Record, + ): AxiosResponse => + ({ + status, + statusText: status === 402 ? "Payment Required" : "OK", + data, + headers: headers || {}, + config: createErrorConfig(), + }) as AxiosResponse; + beforeEach(async () => { vi.resetAllMocks(); @@ -126,6 +140,9 @@ describe("wrapAxiosWithPayment()", () => { ( MockX402HTTPClient.prototype.handlePaymentRequired as ReturnType ).mockResolvedValue(null); + ( + MockX402HTTPClient.prototype.processPaymentResult as ReturnType + ).mockResolvedValue({ recovered: false }); // Set up the interceptor wrapAxiosWithPayment(mockAxiosClient, mockClient); @@ -306,10 +323,174 @@ describe("wrapAxiosWithPayment()", () => { await interceptor(error); const retryConfig = (mockAxiosClient.request as ReturnType).mock.calls[0][0]; - expect(retryConfig.headers.get("Access-Control-Expose-Headers")).toBe( + expect(retryConfig.headers["Access-Control-Expose-Headers"]).toBe( "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE", ); }); + + it("should clone retry headers into a serializable record", async () => { + /** + * Minimal axios-like headers object with a Map-backed set and JSON serialization. + */ + class CallerAxiosHeaders { + private readonly values = new Map(); + + /** + * Stores a header name/value pair. + * + * @param key - Header name + * @param value - Header value + */ + set(key: string, value: string): void { + this.values.set(key, value); + } + + /** + * Returns headers as a plain object for JSON-style cloning. + * + * @returns Header entries as a string record + */ + toJSON(): Record { + return Object.fromEntries(this.values); + } + } + + const successResponse = { data: "success" } as AxiosResponse; + const config = createErrorConfig(); + const callerHeaders = new CallerAxiosHeaders(); + callerHeaders.set("Accept", "application/json"); + config.headers = callerHeaders as unknown as InternalAxiosRequestConfig["headers"]; + (mockAxiosClient.request as ReturnType).mockResolvedValue(successResponse); + + const error = createAxiosError(402, config, validPaymentRequired); + await interceptor(error); + + const retryConfig = (mockAxiosClient.request as ReturnType).mock.calls[0][0]; + expect(retryConfig.headers).not.toBeInstanceOf(CallerAxiosHeaders); + expect(retryConfig.headers).not.toBe(callerHeaders); + expect(retryConfig.headers).toEqual( + expect.objectContaining({ + Accept: "application/json", + "PAYMENT-SIGNATURE": "encoded-payment-header", + }), + ); + expect(Object.values(retryConfig.headers).some(value => typeof value === "function")).toBe( + false, + ); + }); + + it("should recover from a corrective 402 paid retry with one fresh payload retry", async () => { + const { x402HTTPClient: MockX402HTTPClient } = await import("@x402/core/client"); + const correctiveResponse = createAxiosResponse(402, validPaymentRequired, { + "PAYMENT-REQUIRED": "corrective-payment-required", + }); + const successResponse = createAxiosResponse( + 200, + { data: "success" }, + { + "PAYMENT-RESPONSE": "settled", + }, + ); + const freshPaymentPayload: PaymentPayload = { + ...validPaymentPayload, + payload: { signature: "0xfreshsignature" }, + }; + + (mockClient.createPaymentPayload as ReturnType) + .mockResolvedValueOnce(validPaymentPayload) + .mockResolvedValueOnce(freshPaymentPayload); + (MockX402HTTPClient.prototype.processPaymentResult as ReturnType) + .mockResolvedValueOnce({ recovered: true }) + .mockResolvedValueOnce({ recovered: false }); + (mockAxiosClient.request as ReturnType) + .mockResolvedValueOnce(correctiveResponse) + .mockResolvedValueOnce(successResponse); + + const error = createAxiosError(402, createErrorConfig(), validPaymentRequired); + const result = await interceptor(error); + + expect(result).toBe(successResponse); + expect(mockAxiosClient.request).toHaveBeenCalledTimes(2); + expect(mockClient.createPaymentPayload).toHaveBeenCalledTimes(2); + expect(MockX402HTTPClient.prototype.processPaymentResult).toHaveBeenCalledTimes(2); + expect(MockX402HTTPClient.prototype.processPaymentResult).toHaveBeenNthCalledWith( + 1, + validPaymentPayload, + expect.any(Function), + 402, + ); + expect(MockX402HTTPClient.prototype.processPaymentResult).toHaveBeenNthCalledWith( + 2, + freshPaymentPayload, + expect.any(Function), + 200, + ); + }); + + it("should return a corrective 402 paid retry when recovery does not run", async () => { + const { x402HTTPClient: MockX402HTTPClient } = await import("@x402/core/client"); + const correctiveResponse = createAxiosResponse(402, validPaymentRequired, { + "PAYMENT-REQUIRED": "corrective-payment-required", + }); + + (mockAxiosClient.request as ReturnType).mockResolvedValue(correctiveResponse); + + const error = createAxiosError(402, createErrorConfig(), validPaymentRequired); + const result = await interceptor(error); + + expect(result).toBe(correctiveResponse); + expect(mockAxiosClient.request).toHaveBeenCalledTimes(1); + expect(mockClient.createPaymentPayload).toHaveBeenCalledTimes(1); + expect(MockX402HTTPClient.prototype.processPaymentResult).toHaveBeenCalledTimes(1); + expect(MockX402HTTPClient.prototype.processPaymentResult).toHaveBeenCalledWith( + validPaymentPayload, + expect.any(Function), + 402, + ); + }); + + it("should preserve caller validateStatus for non-402 retry statuses", async () => { + const successResponse = createAxiosResponse(200, { data: "success" }); + const config = createErrorConfig(); + config.validateStatus = status => status === 409; + (mockAxiosClient.request as ReturnType).mockResolvedValue(successResponse); + + const error = createAxiosError(402, config, validPaymentRequired); + await interceptor(error); + + const retryConfig = (mockAxiosClient.request as ReturnType).mock.calls[0][0]; + expect(retryConfig.validateStatus(402)).toBe(true); + expect(retryConfig.validateStatus(409)).toBe(true); + expect(retryConfig.validateStatus(200)).toBe(false); + expect(retryConfig.validateStatus(500)).toBe(false); + }); + + it("should fall through to paid retry when hook retry returns 402", async () => { + const { x402HTTPClient: MockX402HTTPClient } = await import("@x402/core/client"); + const hookResponse = createAxiosResponse(402, validPaymentRequired, { + "PAYMENT-REQUIRED": "hook-payment-required", + }); + const successResponse = createAxiosResponse(200, { data: "success" }); + + ( + MockX402HTTPClient.prototype.handlePaymentRequired as ReturnType + ).mockResolvedValue({ "X-HOOK": "handled" }); + (mockAxiosClient.request as ReturnType) + .mockResolvedValueOnce(hookResponse) + .mockResolvedValueOnce(successResponse); + + const error = createAxiosError(402, createErrorConfig(), validPaymentRequired); + const result = await interceptor(error); + + expect(result).toBe(successResponse); + expect(mockAxiosClient.request).toHaveBeenCalledTimes(2); + const hookConfig = (mockAxiosClient.request as ReturnType).mock.calls[0][0]; + const paidConfig = (mockAxiosClient.request as ReturnType).mock.calls[1][0]; + expect(hookConfig.validateStatus(402)).toBe(true); + expect(hookConfig.headers["X-HOOK"]).toBe("handled"); + expect(paidConfig.headers["PAYMENT-SIGNATURE"]).toBe("encoded-payment-header"); + expect(mockClient.createPaymentPayload).toHaveBeenCalledWith(validPaymentRequired); + }); }); describe("wrapAxiosWithPaymentFromConfig()", () => { diff --git a/typescript/packages/http/axios/src/index.ts b/typescript/packages/http/axios/src/index.ts index 041ef2893c..02505cf1db 100644 --- a/typescript/packages/http/axios/src/index.ts +++ b/typescript/packages/http/axios/src/index.ts @@ -1,6 +1,67 @@ import { x402Client, x402ClientConfig, x402HTTPClient } from "@x402/core/client"; import { type PaymentRequired } from "@x402/core/types"; -import type { AxiosInstance, AxiosError, InternalAxiosRequestConfig } from "axios"; +import { type AxiosInstance, type AxiosError, type InternalAxiosRequestConfig } from "axios"; + +type X402RetryConfig = InternalAxiosRequestConfig & { __is402Retry?: boolean }; +type AxiosHeaderRecord = Record; + +/** + * Clones Axios headers into a plain record so the caller's Axios instance can + * normalize them for the retry request. + * + * @param headers - Headers from the caller's original Axios request config. + * @returns Serializable headers for Axios to normalize in the caller's instance. + */ +function cloneAxiosHeaders(headers: InternalAxiosRequestConfig["headers"]): AxiosHeaderRecord { + const source = + typeof headers.toJSON === "function" + ? (headers.toJSON() as Record) + : (headers as unknown as Record); + + return Object.entries(source).reduce((acc, [key, value]) => { + if (value !== undefined && value !== null && typeof value !== "function") { + acc[key] = String(value); + } + + return acc; + }, {}); +} + +/** + * Sets a header on a retry header record. + * + * @param headers - Headers object to update. + * @param key - Header name. + * @param value - Header value. + */ +function setAxiosHeader(headers: AxiosHeaderRecord, key: string, value: string): void { + headers[key] = value; +} + +/** + * Clones an Axios internal request config so a retry can treat HTTP 402 as a successful + * response status for validation (so the interceptor can handle payment flow). + * + * @param config - Original Axios request configuration for the outgoing request. + * @returns Request config with copied headers and validateStatus that returns true for 402. + */ +function createX402RetryConfig(config: InternalAxiosRequestConfig): X402RetryConfig { + const originalValidateStatus = config.validateStatus; + + return { + ...config, + headers: cloneAxiosHeaders(config.headers) as InternalAxiosRequestConfig["headers"], + validateStatus: status => { + if (status === 402) { + return true; + } + + return originalValidateStatus + ? originalValidateStatus(status) + : status >= 200 && status < 300; + }, + }; +} /** * Wraps an Axios instance with x402 payment handling. @@ -57,9 +118,7 @@ export function wrapAxiosWithPayment( } // Check if this is already a retry to prevent infinite loops - if ( - (originalConfig as InternalAxiosRequestConfig & { __is402Retry?: boolean }).__is402Retry - ) { + if ((originalConfig as X402RetryConfig).__is402Retry) { return Promise.reject(error); } @@ -90,10 +149,9 @@ export function wrapAxiosWithPayment( // Run payment required hooks const hookHeaders = await httpClient.handlePaymentRequired(paymentRequired); if (hookHeaders) { - const hookConfig = { ...originalConfig }; - hookConfig.headers = { ...originalConfig.headers } as typeof originalConfig.headers; + const hookConfig = createX402RetryConfig(originalConfig); Object.entries(hookHeaders).forEach(([key, value]) => { - hookConfig.headers.set(key, value); + setAxiosHeader(hookConfig.headers, key, value); }); const hookResponse = await axiosInstance.request(hookConfig); if (hookResponse.status !== 402) { @@ -117,23 +175,58 @@ export function wrapAxiosWithPayment( // Encode payment header const paymentHeaders = httpClient.encodePaymentSignatureHeader(paymentPayload); - // Mark this as a retry - (originalConfig as InternalAxiosRequestConfig & { __is402Retry?: boolean }).__is402Retry = - true; + const paidConfig = createX402RetryConfig(originalConfig); + paidConfig.__is402Retry = true; // Add payment headers to the request Object.entries(paymentHeaders).forEach(([key, value]) => { - originalConfig.headers.set(key, value); + setAxiosHeader(paidConfig.headers, key, value); }); // Add CORS header to expose payment response - originalConfig.headers.set( + setAxiosHeader( + paidConfig.headers, "Access-Control-Expose-Headers", "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE", ); // Retry the request with payment - const secondResponse = await axiosInstance.request(originalConfig); + const secondResponse = await axiosInstance.request(paidConfig); + + // Fire payment response hooks and handle recovery + const getResponseHeader = (name: string) => { + const value = secondResponse.headers[name] ?? secondResponse.headers[name.toLowerCase()]; + return typeof value === "string" ? value : undefined; + }; + const result = await httpClient.processPaymentResult( + paymentPayload, + getResponseHeader, + secondResponse.status, + ); + + if (result.recovered) { + // Retry once with a fresh payload after recovery. + const freshPayload = await client.createPaymentPayload(paymentRequired); + const retryHeaders = httpClient.encodePaymentSignatureHeader(freshPayload); + const retryConfig = createX402RetryConfig(originalConfig); + Object.entries(retryHeaders).forEach(([key, value]) => { + setAxiosHeader(retryConfig.headers, key, value); + }); + setAxiosHeader( + retryConfig.headers, + "Access-Control-Expose-Headers", + "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE", + ); + const retryResponse = await axiosInstance.request(retryConfig); + // Process the final retry result without another recovery attempt. + const getRetryHeader = (name: string) => { + const value = retryResponse.headers[name] ?? retryResponse.headers[name.toLowerCase()]; + return typeof value === "string" ? value : undefined; + }; + await httpClient.processPaymentResult(freshPayload, getRetryHeader, retryResponse.status); + return retryResponse; + } + return secondResponse; } catch (retryError) { return Promise.reject(retryError); diff --git a/typescript/packages/http/express/CHANGELOG.md b/typescript/packages/http/express/CHANGELOG.md index 3b0f1a5f54..3a9729e7ab 100644 --- a/typescript/packages/http/express/CHANGELOG.md +++ b/typescript/packages/http/express/CHANGELOG.md @@ -1,5 +1,63 @@ # @x402/express Changelog +## 2.12.0 + +### Minor Changes + +- 45d7d19: Added cancellationDispatcher for failed route handlers +- ee7c156: chore: tighten viem dependency floor to ^2.48.11 + + Raises the viem floor in every `@x402/*` package.json that lists viem as a direct dep so future `pnpm install` re-resolutions cannot regress below this version. Fixes the incomplete tightening from #2013. + +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] +- Updated dependencies [ee7c156] + - @x402/core@2.12.0 + - @x402/extensions@2.12.0 + - @x402/paywall@2.12.0 + +## 2.11.0 + +### Minor Changes + +- Updated dependencies [a051f48] +- Updated dependencies [032295b] +- Updated dependencies [dc04108] +- Updated dependencies [484030b] + - @x402/core@2.11.0 + - @x402/paywall@2.11.0 + - @x402/extensions@2.11.0 + +## 2.10.0 + +### Minor Changes + +- Updated dependencies [a25800e] +- Updated dependencies [9424291] +- Updated dependencies [37b8347] +- Updated dependencies [a4e4911] + - @x402/paywall@2.10.0 + - @x402/extensions@2.10.0 + - @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization +- d352574: Add SettlementOverrides support for partial settlement (upto scheme). Route handlers can call setSettlementOverrides() to settle less than the authorized maximum, enabling usage-based billing. + +### Patch Changes + +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + - @x402/paywall@2.9.0 + - @x402/extensions@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/http/express/README.md b/typescript/packages/http/express/README.md index d9cba682f6..4344e462e3 100644 --- a/typescript/packages/http/express/README.md +++ b/typescript/packages/http/express/README.md @@ -1,4 +1,4 @@ -# @x402/express +# `@x402/express` [![npm version](https://img.shields.io/npm/v/%40x402%2Fexpress.svg)](https://www.npmjs.com/package/@x402/express) Express middleware integration for the x402 Payment Protocol. This package provides a simple middleware function for adding x402 payment requirements to your Express.js applications. diff --git a/typescript/packages/http/express/package.json b/typescript/packages/http/express/package.json index b926af8c07..4ab09bf664 100644 --- a/typescript/packages/http/express/package.json +++ b/typescript/packages/http/express/package.json @@ -1,6 +1,6 @@ { "name": "@x402/express", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/index.d.ts", @@ -17,8 +17,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@eslint/js": "^9.24.0", @@ -33,7 +33,7 @@ "express": "^4.18.2", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", @@ -41,9 +41,7 @@ }, "dependencies": { "@x402/core": "workspace:~", - "@x402/extensions": "workspace:~", - "viem": "^2.39.3", - "zod": "^3.24.2" + "@x402/extensions": "workspace:~" }, "peerDependencies": { "@x402/paywall": "workspace:^", diff --git a/typescript/packages/http/express/src/index.test.ts b/typescript/packages/http/express/src/index.test.ts index 92947c9b04..1af84211de 100644 --- a/typescript/packages/http/express/src/index.test.ts +++ b/typescript/packages/http/express/src/index.test.ts @@ -40,6 +40,24 @@ let mockProcessSettlement: ReturnType; let mockRegisterPaywallProvider: ReturnType; let mockRequiresPayment: ReturnType; +type PaymentVerifiedResult = Extract; +type MockHTTPProcessResult = + | Exclude + | (Omit & { + cancellationDispatcher?: PaymentVerifiedResult["cancellationDispatcher"]; + }); + +/** + * Creates a mock payment cancellation dispatcher. + * + * @returns Mock payment cancellation dispatcher. + */ +function createMockPaymentCancellationDispatcher(): PaymentVerifiedResult["cancellationDispatcher"] { + return { + cancel: vi.fn().mockResolvedValue(undefined), + } as unknown as PaymentVerifiedResult["cancellationDispatcher"]; +} + vi.mock("@x402/core/server", () => ({ SETTLEMENT_OVERRIDES_HEADER: "Settlement-Overrides", FacilitatorResponseError: class FacilitatorResponseError extends Error { @@ -81,6 +99,7 @@ vi.mock("@x402/core/server", () => ({ registerExtension: vi.fn(), }, })), + checkIfBazaarNeeded: vi.fn().mockReturnValue(false), })); // --- Mock Factories --- @@ -91,7 +110,7 @@ vi.mock("@x402/core/server", () => ({ * @param settlementResult - Result to return from processSettlement. */ function setupMockHttpServer( - processResult: HTTPProcessResult, + processResult: MockHTTPProcessResult, settlementResult: | { success: true; headers: Record } | { @@ -104,7 +123,15 @@ function setupMockHttpServer( headers: {}, }, ): void { - mockProcessHTTPRequest.mockResolvedValue(processResult); + const normalizedResult = + processResult.type === "payment-verified" + ? { + ...processResult, + cancellationDispatcher: + processResult.cancellationDispatcher ?? createMockPaymentCancellationDispatcher(), + } + : processResult; + mockProcessHTTPRequest.mockResolvedValue(normalizedResult); mockProcessSettlement.mockResolvedValue(settlementResult); } @@ -397,6 +424,53 @@ describe("paymentMiddleware", () => { expect(next).toHaveBeenCalled(); expect(mockProcessSettlement).not.toHaveBeenCalled(); + const cancellationDispatcher = (await mockProcessHTTPRequest.mock.results[0].value) + .cancellationDispatcher; + expect(cancellationDispatcher.cancel).toHaveBeenCalledWith( + expect.objectContaining({ + reason: "handler_failed", + responseStatus: 500, + }), + ); + }); + + it("cancels payment when handler throws", async () => { + const cancellationDispatcher = createMockPaymentCancellationDispatcher(); + setupMockHttpServer( + { + type: "payment-verified", + paymentPayload: mockPaymentPayload, + paymentRequirements: mockPaymentRequirements, + cancellationDispatcher, + }, + { success: true, headers: { "PAYMENT-RESPONSE": "settled" } }, + ); + + const middleware = paymentMiddleware( + mockRoutes, + {} as unknown as x402ResourceServer, + undefined, + undefined, + false, + ); + const req = createMockRequest(); + const res = createMockResponse(); + const handlerError = new Error("Handler failed"); + const next = vi.fn((error?: unknown) => { + if (error) { + return; + } + throw handlerError; + }); + + await middleware(req, res, next); + + expect(cancellationDispatcher.cancel).toHaveBeenCalledWith({ + reason: "handler_threw", + error: handlerError, + }); + expect(mockProcessSettlement).not.toHaveBeenCalled(); + expect(next).toHaveBeenCalledWith(handlerError); }); it("returns 402 when settlement throws error", async () => { diff --git a/typescript/packages/http/express/src/index.ts b/typescript/packages/http/express/src/index.ts index efd262fc6a..8a979b1490 100644 --- a/typescript/packages/http/express/src/index.ts +++ b/typescript/packages/http/express/src/index.ts @@ -10,6 +10,7 @@ import { getFacilitatorResponseError, SETTLEMENT_OVERRIDES_HEADER, SettlementOverrides, + checkIfBazaarNeeded, } from "@x402/core/server"; import { SchemeNetworkServer, Network } from "@x402/core/types"; import { NextFunction, Request, Response } from "express"; @@ -26,24 +27,6 @@ export function setSettlementOverrides(res: Response, overrides: SettlementOverr res.setHeader(SETTLEMENT_OVERRIDES_HEADER, JSON.stringify(overrides)); } -/** - * Check if any routes in the configuration declare bazaar extensions - * - * @param routes - Route configuration - * @returns True if any route has extensions.bazaar defined - */ -function checkIfBazaarNeeded(routes: RoutesConfig): boolean { - // Handle single route config - if ("accepts" in routes) { - return !!(routes.extensions && "bazaar" in routes.extensions); - } - - // Handle multiple routes - return Object.values(routes).some(routeConfig => { - return !!(routeConfig.extensions && "bazaar" in routeConfig.extensions); - }); -} - /** * Configuration for registering a payment scheme with a specific network */ @@ -212,7 +195,8 @@ export function paymentMiddlewareFromHTTPServer( case "payment-verified": // Payment is valid, need to wrap response for settlement - const { paymentPayload, paymentRequirements, declaredExtensions } = result; + const { cancellationDispatcher, paymentPayload, paymentRequirements, declaredExtensions } = + result; // Intercept and buffer all core methods that can commit response to client const originalWriteHead = res.writeHead.bind(res); @@ -228,6 +212,14 @@ export function paymentMiddlewareFromHTTPServer( let bufferedCalls: BufferedCall[] = []; let settled = false; + const restoreResponseMethods = () => { + settled = true; + res.writeHead = originalWriteHead; + res.write = originalWrite; + res.end = originalEnd; + res.flushHeaders = originalFlushHeaders; + }; + // Create a promise that resolves when the handler finishes and calls res.end() let endCalled: () => void; const endPromise = new Promise(resolve => { @@ -269,18 +261,28 @@ export function paymentMiddlewareFromHTTPServer( }; // Proceed to the next middleware or route handler - next(); + try { + await Promise.resolve(next()); + } catch (error) { + await cancellationDispatcher.cancel({ + reason: "handler_threw", + error, + }); + bufferedCalls = []; + restoreResponseMethods(); + return next(error); + } // Wait for the handler to actually call res.end() before checking status await endPromise; // If the response from the protected route is >= 400, do not settle payment if (res.statusCode >= 400) { - settled = true; - res.writeHead = originalWriteHead; - res.write = originalWrite; - res.end = originalEnd; - res.flushHeaders = originalFlushHeaders; + await cancellationDispatcher.cancel({ + reason: "handler_failed", + responseStatus: res.statusCode, + }); + restoreResponseMethods(); // Replay all buffered calls in order for (const [method, args] of bufferedCalls) { if (method === "writeHead") @@ -347,11 +349,7 @@ export function paymentMiddlewareFromHTTPServer( res.status(402).json({}); return; } finally { - settled = true; - res.writeHead = originalWriteHead; - res.write = originalWrite; - res.end = originalEnd; - res.flushHeaders = originalFlushHeaders; + restoreResponseMethods(); // Replay all buffered calls in order for (const [method, args] of bufferedCalls) { diff --git a/typescript/packages/http/fastify/CHANGELOG.md b/typescript/packages/http/fastify/CHANGELOG.md new file mode 100644 index 0000000000..8b8d4e9a9e --- /dev/null +++ b/typescript/packages/http/fastify/CHANGELOG.md @@ -0,0 +1,36 @@ +# @x402/fastify + +## 2.12.0 + +### Minor Changes + +- 45d7d19: Added cancellationDispatcher for failed route handlers +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] +- Updated dependencies [ee7c156] + - @x402/core@2.12.0 + - @x402/extensions@2.12.0 + - @x402/paywall@2.12.0 + +## 2.11.0 + +### Minor Changes + +- Updated dependencies [a051f48] +- Updated dependencies [032295b] +- Updated dependencies [dc04108] +- Updated dependencies [484030b] + - @x402/core@2.11.0 + - @x402/paywall@2.11.0 + - @x402/extensions@2.11.0 + +## 2.10.1 + +### Patch Changes + +- Fix `@x402/core` workspace resolution. + +## 2.10.0 + +- Implements Fastify middleware diff --git a/typescript/packages/http/fastify/README.md b/typescript/packages/http/fastify/README.md index c8b17bf6f3..e99f1bbd36 100644 --- a/typescript/packages/http/fastify/README.md +++ b/typescript/packages/http/fastify/README.md @@ -1,4 +1,4 @@ -# @x402/fastify +# `@x402/fastify` [![npm version](https://img.shields.io/npm/v/%40x402%2Ffastify.svg)](https://www.npmjs.com/package/@x402/fastify) Fastify middleware integration for the x402 Payment Protocol. This package provides payment middleware for adding x402 payment requirements to your Fastify applications. diff --git a/typescript/packages/http/fastify/package.json b/typescript/packages/http/fastify/package.json index 5956fdcd8a..caf85ddd2d 100644 --- a/typescript/packages/http/fastify/package.json +++ b/typescript/packages/http/fastify/package.json @@ -1,6 +1,6 @@ { "name": "@x402/fastify", - "version": "0.1.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/index.d.ts", @@ -17,8 +17,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol - Fastify middleware", "devDependencies": { "@eslint/js": "^9.24.0", @@ -32,7 +32,7 @@ "fastify": "^5.0.0", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", @@ -44,7 +44,7 @@ }, "peerDependencies": { "fastify": "^5.0.0", - "@x402/paywall": "workspace:*" + "@x402/paywall": "workspace:^" }, "peerDependenciesMeta": { "@x402/paywall": { diff --git a/typescript/packages/http/fastify/src/index.test.ts b/typescript/packages/http/fastify/src/index.test.ts index ce0e2afbd5..17c0e43013 100644 --- a/typescript/packages/http/fastify/src/index.test.ts +++ b/typescript/packages/http/fastify/src/index.test.ts @@ -39,6 +39,24 @@ let mockProcessSettlement: ReturnType; let mockRegisterPaywallProvider: ReturnType; let mockRequiresPayment: ReturnType; +type PaymentVerifiedResult = Extract; +type MockHTTPProcessResult = + | Exclude + | (Omit & { + cancellationDispatcher?: PaymentVerifiedResult["cancellationDispatcher"]; + }); + +/** + * Creates a mock payment cancellation dispatcher. + * + * @returns Mock payment cancellation dispatcher. + */ +function createMockPaymentCancellationDispatcher(): PaymentVerifiedResult["cancellationDispatcher"] { + return { + cancel: vi.fn().mockResolvedValue(undefined), + } as unknown as PaymentVerifiedResult["cancellationDispatcher"]; +} + vi.mock("@x402/core/server", () => ({ SETTLEMENT_OVERRIDES_HEADER: "Settlement-Overrides", FacilitatorResponseError: class FacilitatorResponseError extends Error { @@ -80,6 +98,7 @@ vi.mock("@x402/core/server", () => ({ registerExtension: vi.fn(), }, })), + checkIfBazaarNeeded: vi.fn().mockReturnValue(false), })); // --- Hook Capture --- @@ -91,6 +110,7 @@ type HookHandler = (...args: unknown[]) => Promise; interface CapturedHooks { onRequest: HookHandler[]; onSend: HookHandler[]; + onError: HookHandler[]; } /** @@ -99,12 +119,13 @@ interface CapturedHooks { * @returns Object containing the mock app and captured hooks. */ function createMockApp(): { app: FastifyInstance; hooks: CapturedHooks } { - const hooks: CapturedHooks = { onRequest: [], onSend: [] }; + const hooks: CapturedHooks = { onRequest: [], onSend: [], onError: [] }; const app = { addHook: vi.fn((name: string, handler: HookHandler) => { if (name === "onRequest") hooks.onRequest.push(handler); if (name === "onSend") hooks.onSend.push(handler); + if (name === "onError") hooks.onError.push(handler); }), decorateRequest: vi.fn(), } as unknown as FastifyInstance; @@ -119,7 +140,7 @@ function createMockApp(): { app: FastifyInstance; hooks: CapturedHooks } { * @param settlementResult - Result to return from processSettlement. */ function setupMockHttpServer( - processResult: HTTPProcessResult, + processResult: MockHTTPProcessResult, settlementResult: | { success: true; headers: Record } | { @@ -137,7 +158,15 @@ function setupMockHttpServer( headers: {}, }, ): void { - mockProcessHTTPRequest.mockResolvedValue(processResult); + const normalizedResult = + processResult.type === "payment-verified" + ? { + ...processResult, + cancellationDispatcher: + processResult.cancellationDispatcher ?? createMockPaymentCancellationDispatcher(), + } + : processResult; + mockProcessHTTPRequest.mockResolvedValue(normalizedResult); mockProcessSettlement.mockResolvedValue(settlementResult); } @@ -220,7 +249,12 @@ function createMockReply(): FastifyReply & { }), }; - return reply as unknown as typeof reply; + return reply as unknown as FastifyReply & { + _status: number; + _headers: Record; + _body: unknown; + _type: string | undefined; + }; } // --- Tests --- @@ -523,6 +557,12 @@ describe("paymentMiddleware", () => { const result = await hooks.onSend[0](request, reply, payload); expect(mockProcessSettlement).not.toHaveBeenCalled(); + expect(request.x402Context?.cancellationDispatcher.cancel).toHaveBeenCalledWith( + expect.objectContaining({ + reason: "handler_failed", + responseStatus: 500, + }), + ); expect(result).toBe(payload); }); diff --git a/typescript/packages/http/fastify/src/index.ts b/typescript/packages/http/fastify/src/index.ts index 1e32952d7a..0a649abd17 100644 --- a/typescript/packages/http/fastify/src/index.ts +++ b/typescript/packages/http/fastify/src/index.ts @@ -11,6 +11,8 @@ import { getFacilitatorResponseError, SETTLEMENT_OVERRIDES_HEADER, SettlementOverrides, + checkIfBazaarNeeded, + PaymentCancellationDispatcher, } from "@x402/core/server"; import { SchemeNetworkServer, @@ -33,6 +35,7 @@ export function setSettlementOverrides(reply: FastifyReply, overrides: Settlemen } interface X402PaymentContext { + cancellationDispatcher: PaymentCancellationDispatcher; paymentPayload: PaymentPayload; paymentRequirements: PaymentRequirements; declaredExtensions?: Record; @@ -116,22 +119,6 @@ function getResponseBodyBuffer(payload: unknown): Buffer | undefined { return Buffer.from(JSON.stringify(payload ?? {})); } -/** - * Check if any routes in the configuration declare bazaar extensions. - * - * @param routes - Route configuration - * @returns True if any route has extensions.bazaar defined - */ -function checkIfBazaarNeeded(routes: RoutesConfig): boolean { - if ("accepts" in routes) { - return !!(routes.extensions && "bazaar" in routes.extensions); - } - - return Object.values(routes).some(routeConfig => { - return !!(routeConfig.extensions && "bazaar" in routeConfig.extensions); - }); -} - /** * Buffers reply.raw method calls on a protected route so that settlement * can inspect the response body before anything reaches the client. @@ -376,6 +363,7 @@ export function paymentMiddlewareFromHTTPServer( case "payment-verified": { request.x402Context = { + cancellationDispatcher: result.cancellationDispatcher, paymentPayload: result.paymentPayload, paymentRequirements: result.paymentRequirements, declaredExtensions: result.declaredExtensions, @@ -426,6 +414,10 @@ export function paymentMiddlewareFromHTTPServer( } if (reply.statusCode >= 400) { + await x402Context.cancellationDispatcher.cancel({ + reason: "handler_failed", + responseStatus: reply.statusCode, + }); return effectivePayload; } @@ -475,6 +467,17 @@ export function paymentMiddlewareFromHTTPServer( return JSON.stringify({}); } }); + + app.addHook("onError", async (request: FastifyRequest, _reply: FastifyReply, error: Error) => { + const x402Context = request.x402Context; + if (!x402Context) { + return; + } + await x402Context.cancellationDispatcher.cancel({ + reason: "handler_threw", + error, + }); + }); } /** diff --git a/typescript/packages/http/fetch/CHANGELOG.md b/typescript/packages/http/fetch/CHANGELOG.md index da8feca42c..1cd2217d66 100644 --- a/typescript/packages/http/fetch/CHANGELOG.md +++ b/typescript/packages/http/fetch/CHANGELOG.md @@ -1,5 +1,47 @@ # @x402/fetch Changelog +## 2.12.0 + +### Minor Changes + +- 45d7d19: Added processPaymentResult utility and recovery hook +- ee7c156: chore: tighten viem dependency floor to ^2.48.11 + + Raises the viem floor in every `@x402/*` package.json that lists viem as a direct dep so future `pnpm install` re-resolutions cannot regress below this version. Fixes the incomplete tightening from #2013. + +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] + - @x402/core@2.12.0 + +## 2.11.0 + +### Minor Changes + +- Updated dependencies [a051f48] +- Updated dependencies [dc04108] + - @x402/core@2.11.0 + +## 2.10.0 + +### Minor Changes + +- @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization + +### Patch Changes + +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/http/fetch/README.md b/typescript/packages/http/fetch/README.md index d78819a247..43b6e10a8c 100644 --- a/typescript/packages/http/fetch/README.md +++ b/typescript/packages/http/fetch/README.md @@ -1,4 +1,4 @@ -# x402-fetch +# `@x402/fetch` [![npm version](https://img.shields.io/npm/v/%40x402%2Ffetch.svg)](https://www.npmjs.com/package/@x402/fetch) A utility package that extends the native `fetch` API to automatically handle 402 Payment Required responses using the x402 payment protocol v2. This package enables seamless integration of payment functionality into your applications when making HTTP requests. diff --git a/typescript/packages/http/fetch/package.json b/typescript/packages/http/fetch/package.json index e0c9520227..40c9710aa9 100644 --- a/typescript/packages/http/fetch/package.json +++ b/typescript/packages/http/fetch/package.json @@ -1,6 +1,6 @@ { "name": "@x402/fetch", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/index.d.ts", @@ -17,8 +17,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol Fetch Extension", "devDependencies": { "@eslint/js": "^9.24.0", @@ -31,16 +31,14 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.0.5" }, "dependencies": { - "@x402/core": "workspace:~", - "viem": "^2.39.3", - "zod": "^3.24.2" + "@x402/core": "workspace:~" }, "exports": { ".": { diff --git a/typescript/packages/http/fetch/src/index.test.ts b/typescript/packages/http/fetch/src/index.test.ts index f59139c531..4959f309c3 100644 --- a/typescript/packages/http/fetch/src/index.test.ts +++ b/typescript/packages/http/fetch/src/index.test.ts @@ -9,6 +9,7 @@ vi.mock("@x402/core/client", () => { MockX402HTTPClient.prototype.getPaymentRequiredResponse = vi.fn(); MockX402HTTPClient.prototype.encodePaymentSignatureHeader = vi.fn(); MockX402HTTPClient.prototype.handlePaymentRequired = vi.fn(); + MockX402HTTPClient.prototype.processPaymentResult = vi.fn(); const MockX402Client = vi.fn() as ReturnType & { fromConfig: ReturnType; @@ -94,6 +95,9 @@ describe("wrapFetchWithPayment()", () => { ( MockX402HTTPClient.prototype.handlePaymentRequired as ReturnType ).mockResolvedValue(null); + ( + MockX402HTTPClient.prototype.processPaymentResult as ReturnType + ).mockResolvedValue({ recovered: false }); wrappedFetch = wrapFetchWithPayment(mockFetch, mockClient); }); @@ -451,6 +455,9 @@ describe("wrapFetchWithPaymentFromConfig()", () => { ( MockX402HTTPClient.prototype.handlePaymentRequired as ReturnType ).mockResolvedValue(null); + ( + MockX402HTTPClient.prototype.processPaymentResult as ReturnType + ).mockResolvedValue({ recovered: false }); }); it("should create client from config and wrap fetch", async () => { diff --git a/typescript/packages/http/fetch/src/index.ts b/typescript/packages/http/fetch/src/index.ts index 63b29cb027..01cb77afb1 100644 --- a/typescript/packages/http/fetch/src/index.ts +++ b/typescript/packages/http/fetch/src/index.ts @@ -120,6 +120,36 @@ export function wrapFetchWithPayment( // Retry the request with payment const secondResponse = await fetch(clonedRequest); + + // Fire payment response hooks and handle recovery + const result = await httpClient.processPaymentResult( + paymentPayload, + name => secondResponse.headers.get(name), + secondResponse.status, + ); + + if (result.recovered) { + // Hook fixed state — retry with fresh payload (bounded to one recovery) + const freshPayload = await client.createPaymentPayload(paymentRequired); + const retryHeaders = httpClient.encodePaymentSignatureHeader(freshPayload); + const retryRequest = new Request(input, init); + for (const [k, v] of Object.entries(retryHeaders)) { + retryRequest.headers.set(k, v); + } + retryRequest.headers.set( + "Access-Control-Expose-Headers", + "PAYMENT-RESPONSE,X-PAYMENT-RESPONSE", + ); + const retryResponse = await fetch(retryRequest); + // Fire hooks on retry response — no further recovery to prevent loops + await httpClient.processPaymentResult( + freshPayload, + name => retryResponse.headers.get(name), + retryResponse.status, + ); + return retryResponse; + } + return secondResponse; }; } @@ -141,6 +171,7 @@ export function wrapFetchWithPaymentFromConfig( // Re-export types and utilities for convenience export { x402Client, x402HTTPClient } from "@x402/core/client"; +export type { x402PaymentResult } from "@x402/core/client"; export type { PaymentPolicy, SchemeRegistration, diff --git a/typescript/packages/http/hono/CHANGELOG.md b/typescript/packages/http/hono/CHANGELOG.md index 9a99c70de9..f94be15a61 100644 --- a/typescript/packages/http/hono/CHANGELOG.md +++ b/typescript/packages/http/hono/CHANGELOG.md @@ -1,5 +1,59 @@ # @x402/hono Changelog +## 2.12.0 + +### Minor Changes + +- 45d7d19: Added cancellationDispatcher for failed route handlers +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] +- Updated dependencies [ee7c156] + - @x402/core@2.12.0 + - @x402/extensions@2.12.0 + - @x402/paywall@2.12.0 + +## 2.11.0 + +### Minor Changes + +- Updated dependencies [a051f48] +- Updated dependencies [032295b] +- Updated dependencies [dc04108] +- Updated dependencies [484030b] + - @x402/core@2.11.0 + - @x402/paywall@2.11.0 + - @x402/extensions@2.11.0 + +## 2.10.0 + +### Minor Changes + +- Updated dependencies [a25800e] +- Updated dependencies [9424291] +- Updated dependencies [37b8347] +- Updated dependencies [a4e4911] + - @x402/paywall@2.10.0 + - @x402/extensions@2.10.0 + - @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization +- d352574: Add SettlementOverrides support for partial settlement (upto scheme). Route handlers can call setSettlementOverrides() to settle less than the authorized maximum, enabling usage-based billing. + +### Patch Changes + +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + - @x402/paywall@2.9.0 + - @x402/extensions@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/http/hono/README.md b/typescript/packages/http/hono/README.md index b9776b42a3..5ee8898b7f 100644 --- a/typescript/packages/http/hono/README.md +++ b/typescript/packages/http/hono/README.md @@ -1,4 +1,4 @@ -# @x402/hono +# `@x402/hono` [![npm version](https://img.shields.io/npm/v/%40x402%2Fhono.svg)](https://www.npmjs.com/package/@x402/hono) Hono middleware integration for the x402 Payment Protocol. This package provides a simple middleware function for adding x402 payment requirements to your Hono applications. diff --git a/typescript/packages/http/hono/package.json b/typescript/packages/http/hono/package.json index d3281029cc..a4580189eb 100644 --- a/typescript/packages/http/hono/package.json +++ b/typescript/packages/http/hono/package.json @@ -1,6 +1,6 @@ { "name": "@x402/hono", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/index.d.ts", @@ -17,8 +17,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@eslint/js": "^9.24.0", @@ -32,7 +32,7 @@ "hono": "^4.7.1", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", @@ -40,8 +40,7 @@ }, "dependencies": { "@x402/core": "workspace:~", - "@x402/extensions": "workspace:~", - "zod": "^3.24.2" + "@x402/extensions": "workspace:~" }, "peerDependencies": { "hono": "^4.0.0", diff --git a/typescript/packages/http/hono/src/index.test.ts b/typescript/packages/http/hono/src/index.test.ts index 0f6a2926d1..2ef5ac0612 100644 --- a/typescript/packages/http/hono/src/index.test.ts +++ b/typescript/packages/http/hono/src/index.test.ts @@ -40,6 +40,24 @@ let mockProcessSettlement: ReturnType; let mockRegisterPaywallProvider: ReturnType; let mockRequiresPayment: ReturnType; +type PaymentVerifiedResult = Extract; +type MockHTTPProcessResult = + | Exclude + | (Omit & { + cancellationDispatcher?: PaymentVerifiedResult["cancellationDispatcher"]; + }); + +/** + * Creates a mock payment cancellation dispatcher. + * + * @returns Mock payment cancellation dispatcher. + */ +function createMockPaymentCancellationDispatcher(): PaymentVerifiedResult["cancellationDispatcher"] { + return { + cancel: vi.fn().mockResolvedValue(undefined), + } as unknown as PaymentVerifiedResult["cancellationDispatcher"]; +} + vi.mock("@x402/core/server", () => ({ SETTLEMENT_OVERRIDES_HEADER: "Settlement-Overrides", FacilitatorResponseError: class FacilitatorResponseError extends Error { @@ -81,6 +99,7 @@ vi.mock("@x402/core/server", () => ({ registerExtension: vi.fn(), }, })), + checkIfBazaarNeeded: vi.fn().mockReturnValue(false), })); // --- Mock Factories --- @@ -91,7 +110,7 @@ vi.mock("@x402/core/server", () => ({ * @param settlementResult - Result to return from processSettlement. */ function setupMockHttpServer( - processResult: HTTPProcessResult, + processResult: MockHTTPProcessResult, settlementResult: | { success: true; headers: Record } | { @@ -104,7 +123,15 @@ function setupMockHttpServer( headers: {}, }, ): void { - mockProcessHTTPRequest.mockResolvedValue(processResult); + const normalizedResult = + processResult.type === "payment-verified" + ? { + ...processResult, + cancellationDispatcher: + processResult.cancellationDispatcher ?? createMockPaymentCancellationDispatcher(), + } + : processResult; + mockProcessHTTPRequest.mockResolvedValue(normalizedResult); mockProcessSettlement.mockResolvedValue(settlementResult); } diff --git a/typescript/packages/http/hono/src/index.ts b/typescript/packages/http/hono/src/index.ts index 049dd08db0..9f097d0dad 100644 --- a/typescript/packages/http/hono/src/index.ts +++ b/typescript/packages/http/hono/src/index.ts @@ -10,6 +10,7 @@ import { getFacilitatorResponseError, SETTLEMENT_OVERRIDES_HEADER, SettlementOverrides, + checkIfBazaarNeeded, } from "@x402/core/server"; import { SchemeNetworkServer, Network } from "@x402/core/types"; import { Context, MiddlewareHandler } from "hono"; @@ -26,24 +27,6 @@ export function setSettlementOverrides(c: Context, overrides: SettlementOverride c.header(SETTLEMENT_OVERRIDES_HEADER, JSON.stringify(overrides)); } -/** - * Check if any routes in the configuration declare bazaar extensions - * - * @param routes - Route configuration - * @returns True if any route has extensions.bazaar defined - */ -function checkIfBazaarNeeded(routes: RoutesConfig): boolean { - // Handle single route config - if ("accepts" in routes) { - return !!(routes.extensions && "bazaar" in routes.extensions); - } - - // Handle multiple routes - return Object.values(routes).some(routeConfig => { - return !!(routeConfig.extensions && "bazaar" in routeConfig.extensions); - }); -} - /** * Configuration for registering a payment scheme with a specific network */ @@ -209,16 +192,29 @@ export function paymentMiddlewareFromHTTPServer( case "payment-verified": // Payment is valid, need to wrap response for settlement - const { paymentPayload, paymentRequirements, declaredExtensions } = result; + const { cancellationDispatcher, paymentPayload, paymentRequirements, declaredExtensions } = + result; // Proceed to the next middleware or route handler - await next(); + try { + await next(); + } catch (error) { + await cancellationDispatcher.cancel({ + reason: "handler_threw", + error, + }); + throw error; + } // Get the current response let res = c.res; // If the response from the protected route is >= 400, do not settle payment if (res.status >= 400) { + await cancellationDispatcher.cancel({ + reason: "handler_failed", + responseStatus: res.status, + }); return; } diff --git a/typescript/packages/http/next/CHANGELOG.md b/typescript/packages/http/next/CHANGELOG.md index 161a472f01..57a64edcca 100644 --- a/typescript/packages/http/next/CHANGELOG.md +++ b/typescript/packages/http/next/CHANGELOG.md @@ -1,5 +1,59 @@ # @x402/next Changelog +## 2.12.0 + +### Minor Changes + +- 45d7d19: Added setSettlementOverrides +- 45d7d19: Added cancellationDispatcher for failed route handlers +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] +- Updated dependencies [ee7c156] + - @x402/core@2.12.0 + - @x402/extensions@2.12.0 + - @x402/paywall@2.12.0 + +## 2.11.0 + +### Minor Changes + +- Updated dependencies [a051f48] +- Updated dependencies [032295b] +- Updated dependencies [dc04108] +- Updated dependencies [484030b] + - @x402/core@2.11.0 + - @x402/paywall@2.11.0 + - @x402/extensions@2.11.0 + +## 2.10.0 + +### Minor Changes + +- Updated dependencies [a25800e] +- Updated dependencies [9424291] +- Updated dependencies [37b8347] +- Updated dependencies [a4e4911] + - @x402/paywall@2.10.0 + - @x402/extensions@2.10.0 + - @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization + +### Patch Changes + +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + - @x402/paywall@2.9.0 + - @x402/extensions@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/http/next/README.md b/typescript/packages/http/next/README.md index db135277ae..8f50d790c7 100644 --- a/typescript/packages/http/next/README.md +++ b/typescript/packages/http/next/README.md @@ -1,4 +1,4 @@ -# @x402/next +# `@x402/next` [![npm version](https://img.shields.io/npm/v/%40x402%2Fnext.svg)](https://www.npmjs.com/package/@x402/next) Next.js integration for the x402 Payment Protocol. This package allows you to easily add paywall functionality to your Next.js applications using the x402 protocol. diff --git a/typescript/packages/http/next/package.json b/typescript/packages/http/next/package.json index 56d8a2ea78..fc2df8abd1 100644 --- a/typescript/packages/http/next/package.json +++ b/typescript/packages/http/next/package.json @@ -1,6 +1,6 @@ { "name": "@x402/next", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/index.d.ts", @@ -17,8 +17,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@eslint/js": "^9.24.0", @@ -31,7 +31,7 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", @@ -39,11 +39,10 @@ }, "dependencies": { "@x402/core": "workspace:~", - "@x402/extensions": "workspace:~", - "zod": "^3.24.2" + "@x402/extensions": "workspace:~" }, "peerDependencies": { - "next": "^16.0.10", + "next": ">=16.0.10 <16.1.0", "@x402/paywall": "workspace:^" }, "peerDependenciesMeta": { diff --git a/typescript/packages/http/next/src/index.test.ts b/typescript/packages/http/next/src/index.test.ts index 3d1ded9ed6..55e3296ed4 100644 --- a/typescript/packages/http/next/src/index.test.ts +++ b/typescript/packages/http/next/src/index.test.ts @@ -1,11 +1,6 @@ import { describe, it, expect, vi, beforeEach } from "vitest"; import { NextRequest, NextResponse } from "next/server"; -import type { - HTTPProcessResult, - x402HTTPResourceServer, - PaywallProvider, - FacilitatorClient, -} from "@x402/core/server"; +import type { HTTPProcessResult, PaywallProvider, FacilitatorClient } from "@x402/core/server"; import { x402ResourceServer, x402HTTPResourceServer } from "@x402/core/server"; import type { PaymentPayload, PaymentRequirements, SchemeNetworkServer } from "@x402/core/types"; import { paymentProxy, paymentProxyFromConfig, withX402, type SchemeRegistration } from "./index"; @@ -69,6 +64,7 @@ vi.mock("@x402/core/server", () => ({ registerExtension: vi.fn(), }, })), + checkIfBazaarNeeded: vi.fn().mockReturnValue(false), })); // --- Test Fixtures --- @@ -96,6 +92,24 @@ const mockPaymentRequirements = { payTo: "0x123", } as unknown as PaymentRequirements; +type PaymentVerifiedResult = Extract; +type MockHTTPProcessResult = + | Exclude + | (Omit & { + cancellationDispatcher?: PaymentVerifiedResult["cancellationDispatcher"]; + }); + +/** + * Creates a mock payment cancellation dispatcher. + * + * @returns Mock payment cancellation dispatcher. + */ +function createMockPaymentCancellationDispatcher(): PaymentVerifiedResult["cancellationDispatcher"] { + return { + cancel: vi.fn().mockResolvedValue(undefined), + } as unknown as PaymentVerifiedResult["cancellationDispatcher"]; +} + // --- Mock Factories --- /** * Creates a mock HTTP server for testing. @@ -105,7 +119,7 @@ const mockPaymentRequirements = { * @returns A mock x402HTTPResourceServer. */ function createMockHttpServer( - processResult: HTTPProcessResult, + processResult: MockHTTPProcessResult, settlementResult: | { success: true; headers: Record } | { @@ -118,8 +132,16 @@ function createMockHttpServer( headers: {}, }, ): x402HTTPResourceServer { + const normalizedResult = + processResult.type === "payment-verified" + ? { + ...processResult, + cancellationDispatcher: + processResult.cancellationDispatcher ?? createMockPaymentCancellationDispatcher(), + } + : processResult; return { - processHTTPRequest: vi.fn().mockResolvedValue(processResult), + processHTTPRequest: vi.fn().mockResolvedValue(normalizedResult), processSettlement: vi.fn().mockResolvedValue(settlementResult), registerPaywallProvider: vi.fn(), initialize: vi.fn().mockResolvedValue(undefined), @@ -241,6 +263,7 @@ describe("paymentProxy", () => { type: "payment-verified", paymentPayload: mockPaymentPayload, paymentRequirements: mockPaymentRequirements, + declaredExtensions: {}, }, { success: true, headers: { "X-Settlement": "complete" } }, ); @@ -254,7 +277,7 @@ describe("paymentProxy", () => { expect(mockServer.processSettlement).toHaveBeenCalledWith( mockPaymentPayload, mockPaymentRequirements, - undefined, + {}, expect.objectContaining({ request: expect.objectContaining({ path: "/api/test", @@ -412,6 +435,15 @@ describe("withX402", () => { expect(handler).toHaveBeenCalled(); expect(response.status).toBe(400); expect(mockServer.processSettlement).not.toHaveBeenCalled(); + const cancellationDispatcher = ( + await vi.mocked(mockServer.processHTTPRequest).mock.results[0].value + ).cancellationDispatcher; + expect(cancellationDispatcher.cancel).toHaveBeenCalledWith( + expect.objectContaining({ + reason: "handler_failed", + responseStatus: 400, + }), + ); }); it("returns 402 when settlement throws error, not the handler response", async () => { diff --git a/typescript/packages/http/next/src/index.ts b/typescript/packages/http/next/src/index.ts index aab58e9d26..93752ece08 100644 --- a/typescript/packages/http/next/src/index.ts +++ b/typescript/packages/http/next/src/index.ts @@ -2,10 +2,14 @@ import { PaywallConfig, PaywallProvider, x402ResourceServer, + x402HTTPResourceServer, RoutesConfig, RouteConfig, FacilitatorClient, FacilitatorResponseError, + checkIfBazaarNeeded, + SETTLEMENT_OVERRIDES_HEADER, + SettlementOverrides, } from "@x402/core/server"; import { SchemeNetworkServer, Network } from "@x402/core/types"; import { NextRequest, NextResponse } from "next/server"; @@ -17,7 +21,17 @@ import { createFacilitatorErrorResponse, getFacilitatorResponseError, } from "./utils"; -import { x402HTTPResourceServer } from "@x402/core/server"; + +/** + * Set settlement overrides on the response for partial settlement. + * `withX402` reads this header before settlement and strips it from the client response. + * + * @param res - Next.js `NextResponse` from your route handler + * @param overrides - Settlement overrides (for example `{ amount: "50%" }` for partial settlement) + */ +export function setSettlementOverrides(res: NextResponse, overrides: SettlementOverrides): void { + res.headers.set(SETTLEMENT_OVERRIDES_HEADER, JSON.stringify(overrides)); +} /** * Configuration for registering a payment scheme with a specific network @@ -126,16 +140,15 @@ export function paymentProxyFromHTTPServer( case "payment-verified": { // Payment is valid, need to wrap response for settlement - const { paymentPayload, paymentRequirements, declaredExtensions } = result; - // Proceed to the next proxy or route handler const nextResponse = NextResponse.next(); return handleSettlement( httpServer, nextResponse, - paymentPayload, - paymentRequirements, - declaredExtensions, + result.paymentPayload, + result.paymentRequirements, + result.declaredExtensions, + result.cancellationDispatcher, context, ); } @@ -305,14 +318,23 @@ export function withX402FromHTTPServer( case "payment-verified": { // Payment is valid, need to wrap response for settlement - const { paymentPayload, paymentRequirements, declaredExtensions } = result; - const handlerResponse = await routeHandler(request); + let handlerResponse: NextResponse; + try { + handlerResponse = await routeHandler(request); + } catch (error) { + await result.cancellationDispatcher.cancel({ + reason: "handler_threw", + error, + }); + throw error; + } return handleSettlement( httpServer, handlerResponse, - paymentPayload, - paymentRequirements, - declaredExtensions, + result.paymentPayload, + result.paymentRequirements, + result.declaredExtensions, + result.cancellationDispatcher, context, ) as Promise>; } @@ -383,24 +405,6 @@ export function withX402( ); } -/** - * Check if any routes in the configuration declare bazaar extensions - * - * @param routes - Route configuration - * @returns True if any route has extensions.bazaar defined - */ -function checkIfBazaarNeeded(routes: RoutesConfig): boolean { - // Handle single route config - if ("accepts" in routes) { - return !!(routes.extensions && "bazaar" in routes.extensions); - } - - // Handle multiple routes - return Object.values(routes).some(routeConfig => { - return !!(routeConfig.extensions && "bazaar" in routeConfig.extensions); - }); -} - export type { PaymentRequired, PaymentRequirements, @@ -409,7 +413,12 @@ export type { SchemeNetworkServer, } from "@x402/core/types"; -export type { PaywallProvider, PaywallConfig, RouteConfig } from "@x402/core/server"; +export type { + PaywallProvider, + PaywallConfig, + RouteConfig, + SettlementOverrides, +} from "@x402/core/server"; export { x402ResourceServer, diff --git a/typescript/packages/http/next/src/utils.test.ts b/typescript/packages/http/next/src/utils.test.ts index 2b0167b008..ba9d2acd82 100644 --- a/typescript/packages/http/next/src/utils.test.ts +++ b/typescript/packages/http/next/src/utils.test.ts @@ -4,6 +4,7 @@ import type { x402HTTPResourceServer, x402ResourceServer, PaywallProvider, + PaymentCancellationDispatcher, } from "@x402/core/server"; import type { PaymentPayload, PaymentRequirements } from "@x402/core/types"; import { @@ -47,6 +48,7 @@ vi.mock("@x402/core/server", () => { }, x402HTTPResourceServer: MockHTTPResourceServer, x402ResourceServer: vi.fn(), + checkIfBazaarNeeded: vi.fn().mockReturnValue(false), }; }); @@ -249,8 +251,13 @@ describe("handleSettlement", () => { scheme: "exact", network: "eip155:84532", } as unknown as PaymentRequirements; + const mockDeclaredExtensions = {}; + let mockPaymentCancellationDispatcher: PaymentCancellationDispatcher; beforeEach(() => { + mockPaymentCancellationDispatcher = { + cancel: vi.fn().mockResolvedValue(undefined), + } as unknown as PaymentCancellationDispatcher; mockHttpServer = { processSettlement: vi .fn() @@ -266,10 +273,18 @@ describe("handleSettlement", () => { response, mockPaymentPayload, mockRequirements, + mockDeclaredExtensions, + mockPaymentCancellationDispatcher, ); expect(result.status).toBe(500); expect(mockHttpServer.processSettlement).not.toHaveBeenCalled(); + expect(mockPaymentCancellationDispatcher.cancel).toHaveBeenCalledWith( + expect.objectContaining({ + reason: "handler_failed", + responseStatus: 500, + }), + ); }); it("returns original response when status is exactly 400", async () => { @@ -280,6 +295,8 @@ describe("handleSettlement", () => { response, mockPaymentPayload, mockRequirements, + mockDeclaredExtensions, + mockPaymentCancellationDispatcher, ); expect(result.status).toBe(400); @@ -294,6 +311,8 @@ describe("handleSettlement", () => { response, mockPaymentPayload, mockRequirements, + mockDeclaredExtensions, + mockPaymentCancellationDispatcher, ); expect(result.status).toBe(200); @@ -301,11 +320,8 @@ describe("handleSettlement", () => { expect(mockHttpServer.processSettlement).toHaveBeenCalledWith( mockPaymentPayload, mockRequirements, + mockDeclaredExtensions, undefined, - expect.objectContaining({ - request: undefined, - responseBody: expect.any(Buffer), - }), ); }); @@ -332,6 +348,8 @@ describe("handleSettlement", () => { response, mockPaymentPayload, mockRequirements, + mockDeclaredExtensions, + mockPaymentCancellationDispatcher, ); expect(result.status).toBe(402); @@ -349,6 +367,8 @@ describe("handleSettlement", () => { response, mockPaymentPayload, mockRequirements, + mockDeclaredExtensions, + mockPaymentCancellationDispatcher, ); expect(result.status).toBe(402); diff --git a/typescript/packages/http/next/src/utils.ts b/typescript/packages/http/next/src/utils.ts index 11b634a66c..f058fd1303 100644 --- a/typescript/packages/http/next/src/utils.ts +++ b/typescript/packages/http/next/src/utils.ts @@ -8,8 +8,9 @@ import { RoutesConfig, FacilitatorResponseError, getFacilitatorResponseError as getCoreFacilitatorResponseError, + PaymentCancellationDispatcher, } from "@x402/core/server"; -import { PaymentPayload, PaymentRequirements } from "@x402/core/types"; +import type { PaymentPayload, PaymentRequirements } from "@x402/core/types"; import { NextAdapter } from "./adapter"; /** @@ -152,6 +153,7 @@ export function handlePaymentError(response: HTTPResponseInstructions): NextResp * @param paymentPayload - The payment payload from the client * @param paymentRequirements - The payment requirements for the route * @param declaredExtensions - Optional declared extensions (for per-key enrichment) + * @param cancellationDispatcher - Cancels verified payments that should not settle * @param httpContext - Optional HTTP request context for extensions * @returns The response with settlement headers or an error response if settlement fails */ @@ -160,11 +162,16 @@ export async function handleSettlement( response: NextResponse, paymentPayload: PaymentPayload, paymentRequirements: PaymentRequirements, - declaredExtensions?: Record, + declaredExtensions: Record | undefined, + cancellationDispatcher: PaymentCancellationDispatcher, httpContext?: HTTPRequestContext, ): Promise { // If the response from the protected route is >= 400, do not settle payment if (response.status >= 400) { + await cancellationDispatcher.cancel({ + reason: "handler_failed", + responseStatus: response.status, + }); return response; } @@ -176,7 +183,7 @@ export async function handleSettlement( paymentPayload, paymentRequirements, declaredExtensions, - { request: httpContext, responseBody }, + httpContext ? { request: httpContext, responseBody } : undefined, ); if (!result.success) { @@ -189,7 +196,7 @@ export async function handleSettlement( }); } - // Settlement succeeded - add headers and return original response + // Settlement succeeded - add headers and return original response. Object.entries(result.headers).forEach(([key, value]) => { response.headers.set(key, value); }); diff --git a/typescript/packages/http/paywall/CHANGELOG.md b/typescript/packages/http/paywall/CHANGELOG.md index ebf7028247..77ba83964c 100644 --- a/typescript/packages/http/paywall/CHANGELOG.md +++ b/typescript/packages/http/paywall/CHANGELOG.md @@ -1,5 +1,75 @@ # @x402/paywall Changelog +## 2.12.0 + +### Minor Changes + +- ee7c156: chore: tighten viem dependency floor to ^2.48.11 + + Raises the viem floor in every `@x402/*` package.json that lists viem as a direct dep so future `pnpm install` re-resolutions cannot regress below this version. Fixes the incomplete tightening from #2013. + +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] + - @x402/core@2.12.0 + +## 2.11.0 + +### Minor Changes + +- 032295b: fix(paywall): use dynamic token decimals instead of hardcoding 6 + + The EVM paywall no longer assumes all tokens have 6 decimal places. Server-side amount conversion in `evmPaywall.generateHtml`: + + - Resolves the token's decimal precision via a new `getDefaultTokenDecimals` helper that looks up the network in `@x402/evm`'s `DEFAULT_STABLECOINS` registry — the same source the scheme `getAssetDecimals` methods read from and the inline scheme dispatch in `@x402/core`'s `x402ResourceServer` uses. Falls back to 6 (USDC default) when the network is unknown. + - Replaces the lossy `parseFloat(amount) / 10**decimals` math with `Number(formatUnits(BigInt(amount), decimals))`, preserving precision through the atomic-to-display conversion. + + `@x402/evm` now publicly re-exports `DEFAULT_STABLECOINS` from `./shared/defaultAssets` so consumers can read the canonical default-asset registry directly. + +### Patch Changes + +- 484030b: chore(paywall): regenerate EVM/SVM/AVM bundles for viem 2.47.12 + + The bundled paywall templates were last regenerated against a viem version that predates chain definitions for Mezo (`eip155:31612`), Mezo Testnet (`eip155:31611`), MegaETH (`eip155:4326`), MegaETH Testnet (`eip155:6343`), Stable (`eip155:988`), Stable Testnet (`eip155:2201`), Radius (`eip155:723487`), Radius Testnet (`eip155:72344`), and 33 other chains. The lockfile moved to viem 2.47.12 in PR #2013 but the bundle was not regenerated, so @x402/paywall hard-threw `Unsupported chain ID` at component init for payments on those chains. + + This commit regenerates all nine generated files (TypeScript, Python, and Go templates for EVM/SVM/AVM) against the current lockfile. Total unique chain IDs in the EVM bundle goes from 635 to 676. + + No source code changes. Paired with a new PR-time drift check (`.github/workflows/check_paywall_template.yml`) so this stays fresh across future viem bumps. + +- Updated dependencies [a051f48] +- Updated dependencies [dc04108] + - @x402/core@2.11.0 + +## 2.10.0 + +### Minor Changes + +- a25800e: Add Algorand (AVM) chain support with exact payment scheme and paywall UI + +- 9424291: chore: bump viem lockfile to 2.47.12 + + Updates the resolved viem version across all direct dependencies, adding chain definitions for Mezo Testnet, MegaETH, Stable, and Stable Testnet that were missing from previously locked versions. + +- 37b8347: fix(paywall): read token name from payment requirements instead of hardcoding "USDC" + + The EVM paywall now reads the token name from `extra.name` in payment requirements and uses it for all display text. Falls back to "Token" (generic) when `extra.name` is absent. This fixes mislabeled token names for non-USDC chains (MegaUSD, USDT0, Mezo USD, etc.). + + - @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization + +### Patch Changes + +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/http/paywall/README.md b/typescript/packages/http/paywall/README.md index caafbcc8d8..871f4a9295 100644 --- a/typescript/packages/http/paywall/README.md +++ b/typescript/packages/http/paywall/README.md @@ -1,4 +1,4 @@ -# @x402/paywall +# `@x402/paywall` [![npm version](https://img.shields.io/npm/v/%40x402%2Fpaywall.svg)](https://www.npmjs.com/package/@x402/paywall) Modular paywall UI for the x402 payment protocol with support for EVM and Solana networks. diff --git a/typescript/packages/http/paywall/package.json b/typescript/packages/http/paywall/package.json index ec2dbaa470..af91b28cf7 100644 --- a/typescript/packages/http/paywall/package.json +++ b/typescript/packages/http/paywall/package.json @@ -1,6 +1,6 @@ { "name": "@x402/paywall", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/index.d.ts", @@ -10,7 +10,7 @@ "test": "vitest run", "test:watch": "vitest", "build": "tsup", - "build:paywall": "tsx src/evm/build.ts && tsx src/svm/build.ts", + "build:paywall": "tsx src/evm/build.ts && tsx src/svm/build.ts && tsx src/avm/build.ts", "watch": "tsc --watch", "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", @@ -24,8 +24,8 @@ "http-402" ], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol Paywall UI", "devDependencies": { "@craftamap/esbuild-plugin-html": "^0.9.0", @@ -35,10 +35,11 @@ "@types/react-dom": "^19", "@typescript-eslint/eslint-plugin": "^8.29.1", "@typescript-eslint/parser": "^8.29.1", + "@x402/avm": "workspace:~", "@x402/evm": "workspace:~", "@x402/svm": "workspace:~", "buffer": "^6.0.3", - "esbuild": "^0.25.4", + "esbuild": "^0.27.2", "eslint": "^9.24.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsdoc": "^50.6.9", @@ -47,13 +48,19 @@ "react": "^19.0.0", "react-dom": "^19.0.0", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.0.5" }, "dependencies": { + "@txnlab/use-wallet": "^4.3.1", + "@perawallet/connect": "^1.4.2", + "@blockshake/defly-connect": "^1.2.1", + "lute-connect": "^1.6.3", + "@walletconnect/sign-client": "^2.23.1", + "@algorandfoundation/algokit-utils": "10.0.0-alpha.46", "@scure/base": "^1.2.6", "@solana-program/compute-budget": "^0.8.0", "@solana-program/token": "^0.5.1", @@ -68,9 +75,8 @@ "@wallet-standard/base": "^1.1.0", "@wallet-standard/features": "^1.1.0", "@x402/core": "workspace:~", - "viem": "^2.39.3", - "wagmi": "^2.17.1", - "zod": "^3.24.2" + "viem": "^2.48.11", + "wagmi": "^2.17.1" }, "peerDependencies": { "react": "^19.0.0", @@ -106,6 +112,16 @@ "types": "./dist/cjs/svm/index.d.cts", "default": "./dist/cjs/svm/index.cjs" } + }, + "./avm": { + "import": { + "types": "./dist/esm/avm/index.d.ts", + "default": "./dist/esm/avm/index.js" + }, + "require": { + "types": "./dist/cjs/avm/index.d.cts", + "default": "./dist/cjs/avm/index.cjs" + } } }, "files": [ diff --git a/typescript/packages/http/paywall/src/PaywallApp.tsx b/typescript/packages/http/paywall/src/PaywallApp.tsx index 2abc023aaa..25cedd5035 100644 --- a/typescript/packages/http/paywall/src/PaywallApp.tsx +++ b/typescript/packages/http/paywall/src/PaywallApp.tsx @@ -2,9 +2,10 @@ import { useCallback } from "react"; import type { PaymentRequired } from "@x402/core/types"; -import { isEvmNetwork, isSvmNetwork } from "./paywallUtils"; +import { isEvmNetwork, isSvmNetwork, isAvmNetwork } from "./paywallUtils"; import { EvmPaywall } from "./evm/EvmPaywall"; import { SolanaPaywall } from "./svm/SolanaPaywall"; +import { AvmPaywall } from "./avm/AvmPaywall"; /** * Main Paywall App Component @@ -58,6 +59,15 @@ export function PaywallApp() { ); } + if (isAvmNetwork(network)) { + return ( + + ); + } + return (

diff --git a/typescript/packages/http/paywall/src/avm/AvmPaywall.tsx b/typescript/packages/http/paywall/src/avm/AvmPaywall.tsx new file mode 100644 index 0000000000..7f21aa4e35 --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/AvmPaywall.tsx @@ -0,0 +1,406 @@ +import { useCallback, useEffect, useState, useSyncExternalStore } from "react"; +import type { WalletManager } from "@txnlab/use-wallet"; +import type { AlgorandClient } from "@algorandfoundation/algokit-utils/algorand-client"; + +import { ExactAvmScheme } from "@x402/avm/exact/client"; +import { x402Client } from "@x402/core/client"; +import type { PaymentRequired } from "@x402/core/types"; + +import { Spinner } from "./Spinner"; +import { getNetworkDisplayName, ALGORAND_NETWORK_REFS } from "../paywallUtils"; +import { getAlgodClient } from "./algorand/rpc"; + +type AvmPaywallProps = { + paymentRequired: PaymentRequired; + walletManager?: WalletManager; + algorandClient?: AlgorandClient; + onSuccessfulResponse: (response: Response) => Promise; +}; + +/** + * Paywall experience for Algorand networks using @txnlab/use-wallet. + * + * Supports Pera, Defly, and Lute wallets. + * + * @param props - Component props. + * @param props.paymentRequired - Payment required response with accepts array. + * @param props.walletManager - WalletManager instance from use-wallet. + * @param props.algorandClient - Optional AlgorandClient instance for network connectivity. + * @param props.onSuccessfulResponse - Callback invoked on successful 402 response. + * @returns JSX element. + */ +export function AvmPaywall({ + paymentRequired, + walletManager, + algorandClient, + onSuccessfulResponse, +}: AvmPaywallProps) { + // WalletManager is required for AVM paywall — when used from the shared PaywallApp + // without AVM-specific initialization, show a setup message + if (!walletManager) { + return ( +
+
+

Payment Required

+

Algorand wallet support requires the AVM-specific paywall entry point.

+
+
+ ); + } + + const [status, setStatus] = useState(""); + const [isPaying, setIsPaying] = useState(false); + const [hideBalance, setHideBalance] = useState(true); + const [usdcBalance, setUsdcBalance] = useState(null); + const [isFetchingBalance, setIsFetchingBalance] = useState(false); + const [selectedWalletId, setSelectedWalletId] = useState(""); + + // Subscribe to wallet manager state changes using useSyncExternalStore + // This triggers re-renders when state changes + useSyncExternalStore( + callback => walletManager.subscribe(callback), + () => walletManager.store.state, + () => walletManager.store.state, + ); + + // In use-wallet v4, use the getters from walletManager after state change triggers re-render + const wallets = walletManager.wallets; + const activeWallet = walletManager.activeWallet; + const activeAccount = walletManager.activeAccount; + + const x402 = window.x402; + const amount = x402.amount; + + const firstRequirement = paymentRequired.accepts[0]; + if (!firstRequirement) { + throw new Error("No payment requirements in paymentRequired.accepts"); + } + + const network = firstRequirement.network; + const chainName = getNetworkDisplayName(network); + const isTestnet = network.includes(ALGORAND_NETWORK_REFS.TESTNET); + + // Get USDC ASA ID based on network + const usdcAsaId = firstRequirement.asset + ? parseInt(firstRequirement.asset as string, 10) + : isTestnet + ? 10458941 + : 31566704; + + // Format balance for display + const formattedBalance = + usdcBalance !== null ? (Number(usdcBalance) / 1_000_000).toFixed(2) : null; + + // Fetch USDC balance for connected account + const refreshBalance = useCallback(async () => { + if (!activeAccount?.address) { + return null; + } + + setIsFetchingBalance(true); + try { + const algod = getAlgodClient(network); + const accountInfo = await algod.accountInformation(activeAccount.address); + const assets = accountInfo.assets || []; + const usdcAsset = assets.find( + (asset: { assetId: bigint }) => Number(asset.assetId) === usdcAsaId, + ); + const balance = usdcAsset ? BigInt(usdcAsset.amount) : BigInt(0); + setUsdcBalance(balance); + return balance; + } catch (error) { + console.error("Failed to fetch balance:", error); + setUsdcBalance(null); + return null; + } finally { + setIsFetchingBalance(false); + } + }, [activeAccount?.address, network, usdcAsaId]); + + // Refresh balance when account changes + useEffect(() => { + if (activeAccount?.address) { + refreshBalance(); + } else { + setUsdcBalance(null); + } + }, [activeAccount?.address, refreshBalance]); + + // Auto-select first wallet if only one available + useEffect(() => { + if (!selectedWalletId && wallets.length === 1) { + setSelectedWalletId(wallets[0].id); + } + }, [wallets, selectedWalletId]); + + // Handle wallet connection + const handleConnect = useCallback(async () => { + const wallet = wallets.find(w => w.id === selectedWalletId); + if (!wallet) { + setStatus("Select an Algorand wallet to continue."); + return; + } + + try { + setStatus("Connecting to wallet..."); + await wallet.connect(); + setStatus(""); + } catch (error) { + console.error("Failed to connect wallet:", error); + setStatus(error instanceof Error ? error.message : "Failed to connect wallet."); + } + }, [wallets, selectedWalletId]); + + // Handle wallet disconnection + const handleDisconnect = useCallback(async () => { + if (activeWallet) { + try { + await activeWallet.disconnect(); + } catch (error) { + console.error("Failed to disconnect:", error); + } + } + setUsdcBalance(null); + setStatus(""); + }, [activeWallet]); + + // Handle payment + const handlePayment = useCallback(async () => { + if (!x402 || !activeAccount?.address || !activeWallet) { + setStatus("Connect an Algorand wallet before paying."); + return; + } + + setIsPaying(true); + + try { + // Check balance first + if (usdcBalance === null || usdcBalance === 0n) { + setStatus("Checking USDC balance..."); + const latestBalance = await refreshBalance(); + if (!latestBalance || latestBalance === 0n) { + throw new Error(`Insufficient balance. Make sure you have USDC on ${chainName}.`); + } + } + + setStatus("Creating payment signature..."); + + // Create signer that wraps the wallet's signTransactions function + const walletSigner = { + address: activeAccount.address, + signTransactions: async ( + txns: Uint8Array[], + indexesToSign?: number[], + ): Promise<(Uint8Array | null)[]> => { + const signedTxns = await activeWallet.signTransactions(txns, indexesToSign); + return signedTxns; + }, + }; + + const client = new x402Client(); + client.register( + "algorand:*", + new ExactAvmScheme(walletSigner, algorandClient ? { algorandClient } : undefined), + ); + + // Log payment requirements for debugging + console.log("Creating payment payload with requirements:", { + x402Version: paymentRequired.x402Version, + accepts: paymentRequired.accepts.map(a => ({ + scheme: a.scheme, + network: a.network, + amount: a.amount, + asset: a.asset, + payTo: a.payTo, + })), + }); + + const paymentPayload = await client.createPaymentPayload(paymentRequired); + + // Log the created payload for debugging + console.log("Created payment payload:", { + x402Version: paymentPayload.x402Version, + accepted: paymentPayload.accepted, + payloadKeys: Object.keys(paymentPayload.payload || {}), + }); + + const paymentHeader = btoa(JSON.stringify(paymentPayload)); + + setStatus("Requesting content with payment..."); + const response = await fetch(x402.currentUrl, { + headers: { + "PAYMENT-SIGNATURE": paymentHeader, + "Access-Control-Expose-Headers": "PAYMENT-RESPONSE,PAYMENT-REQUIRED", + }, + }); + + if (response.ok) { + await onSuccessfulResponse(response); + } else { + // Try to extract detailed error from PAYMENT-REQUIRED header or response body + let errorDetail = ""; + + // Check for PAYMENT-REQUIRED header (contains error info from facilitator) + const paymentRequiredHeader = response.headers.get("PAYMENT-REQUIRED"); + if (paymentRequiredHeader) { + try { + const paymentRequired = JSON.parse(atob(paymentRequiredHeader)); + if (paymentRequired.error) { + errorDetail = paymentRequired.error; + } + } catch { + // Ignore parse errors + } + } + + // Also try to get error from response body + if (!errorDetail) { + try { + const body = await response.json(); + if (body.error) { + errorDetail = + typeof body.error === "string" ? body.error : JSON.stringify(body.error); + } else if (body.details) { + errorDetail = body.details; + } + } catch { + // Response might not be JSON + } + } + + const errorMessage = errorDetail + ? `Payment verification failed: ${errorDetail}` + : `Request failed: ${response.status} ${response.statusText}`; + + console.error("Payment error details:", { + status: response.status, + errorDetail, + paymentRequiredHeader: paymentRequiredHeader ? "present" : "absent", + }); + + throw new Error(errorMessage); + } + } catch (error) { + setStatus(error instanceof Error ? error.message : "Payment failed."); + } finally { + setIsPaying(false); + } + }, [ + x402, + activeAccount, + activeWallet, + usdcBalance, + refreshBalance, + chainName, + algorandClient, + paymentRequired, + onSuccessfulResponse, + ]); + + return ( +
+
+

Payment Required

+

+ {paymentRequired.resource?.description && `${paymentRequired.resource.description}.`} To + access this content, please pay ${amount} {chainName} USDC. +

+ {isTestnet && ( +

+ Need Algorand Testnet USDC?{" "} + + Request some here. + +

+ )} +
+ +
+
+
+ Wallet: + + {activeAccount?.address + ? `${activeAccount.address.slice(0, 6)}...${activeAccount.address.slice(-4)}` + : "-"} + +
+
+ Available balance: + + {activeAccount?.address ? ( + + ) : ( + "-" + )} + +
+
+ Amount: + ${amount} USDC +
+
+ Network: + {chainName} +
+
+ +
+ {activeAccount?.address ? ( + + ) : ( + <> + + + + )} + {activeAccount?.address && ( + + )} +
+ + {wallets.length === 0 && ( +
+ Install an Algorand wallet such as Pera, Defly, or Lute to continue, then refresh this + page. +
+ )} + + {status &&
{status}
} +
+
+ ); +} diff --git a/typescript/packages/http/paywall/src/avm/Spinner.tsx b/typescript/packages/http/paywall/src/avm/Spinner.tsx new file mode 100644 index 0000000000..bd948ed73e --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/Spinner.tsx @@ -0,0 +1,14 @@ +/** + * Simple Spinner component for loading states + * + * @param props - The component props + * @param props.className - Optional CSS classes to apply to the spinner + * @returns The Spinner component + */ +export function Spinner({ className = "" }: { className?: string }) { + return ( +
+
+
+ ); +} diff --git a/typescript/packages/http/paywall/src/avm/algorand/features.ts b/typescript/packages/http/paywall/src/avm/algorand/features.ts new file mode 100644 index 0000000000..1567e2be7f --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/algorand/features.ts @@ -0,0 +1,62 @@ +import { + StandardConnect, + StandardDisconnect, + StandardEvents, + type StandardConnectFeature, + type StandardDisconnectFeature, + type StandardEventsFeature, +} from "@wallet-standard/features"; +import type { Wallet } from "@wallet-standard/base"; +import type { WalletWithAvmFeatures } from "./types"; + +/** + * Feature identifier for Algorand transaction signing + */ +export const AlgorandSignTransaction = "algorand:signTransaction"; + +/** + * Type guard ensuring the wallet implements Algorand signing features. + * + * @param wallet - Wallet instance to inspect. + * @returns True when the wallet supports Algorand signing. + */ +export const hasAlgorandSigning = (wallet: Wallet): wallet is WalletWithAvmFeatures => + AlgorandSignTransaction in wallet.features; + +/** + * Extracts the Algorand transaction signing feature when present. + * + * @param wallet - Wallet that may expose the signing capability. + * @returns The signing feature if available, otherwise undefined. + */ +export const getAlgorandSignTransactionFeature = (wallet: WalletWithAvmFeatures) => + wallet.features[AlgorandSignTransaction]; + +/** + * Retrieves the standard connect feature from a wallet, if supported. + * + * @param wallet - Wallet under inspection. + * @returns The connect feature when present. + */ +export const getStandardConnectFeature = (wallet: WalletWithAvmFeatures) => + (wallet.features as unknown as Partial)[StandardConnect]; + +/** + * Retrieves the standard events feature from a wallet, if supported. + * + * @param wallet - Wallet under inspection. + * @returns The events feature when present. + */ +export const getStandardEventsFeature = (wallet: WalletWithAvmFeatures) => + (wallet.features as unknown as Partial)[StandardEvents]; + +/** + * Retrieves the standard disconnect feature from a wallet, if supported. + * + * @param wallet - Wallet under inspection. + * @returns The disconnect feature when present. + */ +export const getStandardDisconnectFeature = (wallet: WalletWithAvmFeatures) => + (wallet.features as unknown as Partial)[StandardDisconnect]; + +export type { StandardEventsChangeProperties } from "@wallet-standard/features"; diff --git a/typescript/packages/http/paywall/src/avm/algorand/rpc.ts b/typescript/packages/http/paywall/src/avm/algorand/rpc.ts new file mode 100644 index 0000000000..9867948380 --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/algorand/rpc.ts @@ -0,0 +1,60 @@ +import { AlgorandClient } from "@algorandfoundation/algokit-utils/algorand-client"; +import type { AlgodClient } from "@algorandfoundation/algokit-utils/algod-client"; +import { ALGORAND_NETWORK_REFS } from "../../paywallUtils"; + +/** + * Gets an AlgorandClient for the given network. + * Uses AlgorandClient convenience methods which provide built-in AlgoNode defaults. + * + * @param network - The network to get the client for (CAIP-2 format: algorand:reference) + * @returns An AlgorandClient instance + */ +export function getAlgorandClient(network: string): AlgorandClient { + if (!network.startsWith("algorand:")) { + throw new Error( + `Invalid network format. Expected CAIP-2 format (algorand:reference), got: ${network}`, + ); + } + + const ref = network.split(":")[1]; + const isTestnet = ref === ALGORAND_NETWORK_REFS.TESTNET; + + return isTestnet ? AlgorandClient.testNet() : AlgorandClient.mainNet(); +} + +/** + * Gets the Algod client for the given network. + * Thin wrapper around getAlgorandClient for backward compatibility. + * + * @param network - The network to get the Algod client for (CAIP-2 format: algorand:reference) + * @param url - Optional URL override (ignored when using AlgorandClient defaults) + * @returns The Algod client for the given network + */ +export function getAlgodClient(network: string, url?: string): AlgodClient { + if (url) { + // When a custom URL is provided, create a custom AlgorandClient + const client = AlgorandClient.fromConfig({ + algodConfig: { server: url }, + }); + return client.client.algod; + } + return getAlgorandClient(network).client.algod; +} + +/** + * USDC ASA IDs for Algorand networks + */ +export const USDC_ASA_IDS: Record = { + [ALGORAND_NETWORK_REFS.MAINNET]: "31566704", + [ALGORAND_NETWORK_REFS.TESTNET]: "10458941", +}; + +/** + * Gets the USDC ASA ID for the given network reference. + * + * @param networkRef - The network reference (genesis hash). + * @returns The USDC ASA ID or undefined if not found. + */ +export function getUsdcAsaId(networkRef: string): string | undefined { + return USDC_ASA_IDS[networkRef]; +} diff --git a/typescript/packages/http/paywall/src/avm/algorand/types.ts b/typescript/packages/http/paywall/src/avm/algorand/types.ts new file mode 100644 index 0000000000..6eb445e683 --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/algorand/types.ts @@ -0,0 +1,31 @@ +import type { Wallet } from "@wallet-standard/base"; + +/** + * Algorand wallet with AVM signing features + */ +export interface WalletWithAvmFeatures extends Wallet { + features: Wallet["features"] & { + "algorand:signTransaction"?: { + signTransaction: (params: { + txns: Uint8Array[]; + indexesToSign?: number[]; + }) => Promise<(Uint8Array | null)[]>; + }; + }; +} + +/** + * Wallet option for dropdown selection + */ +export type WalletOption = { + value: string; + wallet: WalletWithAvmFeatures; +}; + +/** + * Algorand account from wallet + */ +export interface AlgorandAccount { + address: string; + name?: string; +} diff --git a/typescript/packages/http/paywall/src/avm/algorand/useAlgorandBalance.ts b/typescript/packages/http/paywall/src/avm/algorand/useAlgorandBalance.ts new file mode 100644 index 0000000000..53b3407069 --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/algorand/useAlgorandBalance.ts @@ -0,0 +1,103 @@ +import { useCallback, useEffect, useState } from "react"; +import { formatUnits } from "viem"; +import type { WalletAccount } from "@wallet-standard/base"; +import type { PaymentRequired } from "@x402/core/types"; +import { getAlgodClient } from "./rpc"; + +type Params = { + activeAccount: WalletAccount | null; + paymentRequired: PaymentRequired; + onStatus: (message: string) => void; +}; + +type BalanceState = { + usdcBalance: bigint | null; + formattedBalance: string; + isFetchingBalance: boolean; + refreshBalance: (account?: WalletAccount | null) => Promise; + resetBalance: () => void; +}; + +/** + * Tracks and refreshes the Algorand USDC balance for the active account. + * + * @param params - Hook parameters containing account details and callbacks. + * @param params.activeAccount - Wallet account whose balance is being tracked. + * @param params.paymentRequired - Payment required response with accepts array. + * @param params.onStatus - Callback for reporting status messages to the UI. + * @returns Balance state and helper methods for refreshing/resetting data. + */ +export function useAlgorandBalance({ + activeAccount, + paymentRequired, + onStatus, +}: Params): BalanceState { + const [usdcBalance, setUsdcBalance] = useState(null); + const [formattedBalance, setFormattedBalance] = useState(""); + const [isFetchingBalance, setIsFetchingBalance] = useState(false); + + const firstRequirement = paymentRequired.accepts[0]; + + const resetBalance = useCallback(() => { + setUsdcBalance(null); + setFormattedBalance(""); + }, []); + + const refreshBalance = useCallback( + async (account: WalletAccount | null = activeAccount) => { + if (!account || !firstRequirement) { + resetBalance(); + return null; + } + + try { + setIsFetchingBalance(true); + + const algodClient = getAlgodClient(firstRequirement.network); + const assetId = parseInt(firstRequirement.asset); + + // Get account info to find the asset holding + const accountInfo = await algodClient.accountInformation(account.address); + + const assets = accountInfo.assets || []; + + // Find the USDC asset holding + const assetHolding = assets.find( + (a: { assetId: bigint; amount: bigint }) => Number(a.assetId) === assetId, + ); + + // Get decimals from asset info + const decimals = + (firstRequirement.extra as { decimals?: number } | undefined)?.decimals ?? 6; + + const balance = assetHolding ? BigInt(assetHolding.amount) : 0n; + + setUsdcBalance(balance); + setFormattedBalance(formatUnits(balance, decimals)); + return balance; + } catch (error) { + console.error("Failed to fetch Algorand USDC balance", error); + onStatus("Unable to read your USDC balance. Please retry."); + resetBalance(); + return null; + } finally { + setIsFetchingBalance(false); + } + }, + [activeAccount, firstRequirement, onStatus, resetBalance], + ); + + useEffect(() => { + if (activeAccount) { + void refreshBalance(); + } + }, [activeAccount, refreshBalance]); + + return { + usdcBalance, + formattedBalance, + isFetchingBalance, + refreshBalance, + resetBalance, + }; +} diff --git a/typescript/packages/http/paywall/src/avm/algorand/useAlgorandSigner.ts b/typescript/packages/http/paywall/src/avm/algorand/useAlgorandSigner.ts new file mode 100644 index 0000000000..441ac2928c --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/algorand/useAlgorandSigner.ts @@ -0,0 +1,43 @@ +import { useMemo } from "react"; +import type { WalletAccount } from "@wallet-standard/base"; +import type { ClientAvmSigner } from "@x402/avm"; + +import { getAlgorandSignTransactionFeature } from "./features"; +import type { WalletWithAvmFeatures } from "./types"; + +type Params = { + activeWallet: WalletWithAvmFeatures | null; + activeAccount: WalletAccount | null; +}; + +/** + * Derives a transaction signer that proxies requests to the connected Algorand wallet. + * + * @param params - Hook parameters defining the active wallet/account. + * @param params.activeWallet - Wallet currently selected by the user. + * @param params.activeAccount - Account inside the wallet authorised for signing. + * @returns A transaction signer or null when the wallet cannot sign. + */ +export function useAlgorandSigner({ activeWallet, activeAccount }: Params): ClientAvmSigner | null { + return useMemo(() => { + if (!activeWallet || !activeAccount) { + return null; + } + + const signFeature = getAlgorandSignTransactionFeature(activeWallet); + if (!signFeature) { + return null; + } + + return { + address: activeAccount.address, + async signTransactions(txns: Uint8Array[], indexesToSign?: number[]) { + const result = await signFeature.signTransaction({ + txns, + indexesToSign, + }); + return result; + }, + }; + }, [activeWallet, activeAccount]); +} diff --git a/typescript/packages/http/paywall/src/avm/algorand/useAlgorandWalletEvents.ts b/typescript/packages/http/paywall/src/avm/algorand/useAlgorandWalletEvents.ts new file mode 100644 index 0000000000..14028cd4bb --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/algorand/useAlgorandWalletEvents.ts @@ -0,0 +1,97 @@ +import { useEffect } from "react"; +import type { WalletAccount } from "@wallet-standard/base"; + +import { AlgorandSignTransaction } from "./features"; +import { getStandardEventsFeature, type StandardEventsChangeProperties } from "./features"; +import type { WalletWithAvmFeatures } from "./types"; + +type Params = { + activeWallet: WalletWithAvmFeatures | null; + chainName: string; + setActiveWallet: (wallet: WalletWithAvmFeatures | null) => void; + setActiveAccount: (account: WalletAccount | null) => void; + setSelectedWalletValue: (value: string) => void; + setStatus: (status: string) => void; + resetBalance: () => void; + refreshBalance: (account?: WalletAccount | null) => Promise; +}; + +/** + * Listens for wallet-standard change events and keeps local state in sync. + * + * @param params - Hook parameters describing wallet state handlers and dependencies. + * @param params.activeWallet - Wallet currently active in the UI. + * @param params.chainName - Human-readable name of the active chain. + * @param params.setActiveWallet - Setter used to store the active wallet. + * @param params.setActiveAccount - Setter used to store the active account. + * @param params.setSelectedWalletValue - Setter for the selected wallet option value. + * @param params.setStatus - Setter for user-facing status messages. + * @param params.resetBalance - Helper to clear cached balance state. + * @param params.refreshBalance - Function that refreshes the cached balance. + */ +export function useAlgorandWalletEvents({ + activeWallet, + chainName, + setActiveWallet, + setActiveAccount, + setSelectedWalletValue, + setStatus, + resetBalance, + refreshBalance, +}: Params): void { + useEffect(() => { + if (!activeWallet) { + return; + } + + const eventsFeature = getStandardEventsFeature(activeWallet); + if (!eventsFeature) { + return; + } + + const unsubscribe = eventsFeature.on("change", (properties: StandardEventsChangeProperties) => { + if (properties.features && !(AlgorandSignTransaction in properties.features)) { + setActiveWallet(null); + setActiveAccount(null); + setSelectedWalletValue(""); + resetBalance(); + setStatus("Selected wallet no longer supports Algorand signing. Please reconnect."); + return; + } + + if (properties.accounts) { + if (!properties.accounts.length) { + setActiveAccount(null); + resetBalance(); + setStatus("Wallet disconnected. Select a wallet to reconnect."); + return; + } + + const nextAccount = properties.accounts[0] ?? null; + setActiveAccount(nextAccount); + + if (!nextAccount) { + setStatus("No authorized Algorand accounts available. Reconnect your wallet."); + resetBalance(); + return; + } + + setStatus(""); + void refreshBalance(nextAccount); + } + }); + + return () => { + unsubscribe(); + }; + }, [ + activeWallet, + chainName, + setActiveWallet, + setActiveAccount, + setSelectedWalletValue, + setStatus, + resetBalance, + refreshBalance, + ]); +} diff --git a/typescript/packages/http/paywall/src/avm/algorand/useAlgorandWalletOptions.ts b/typescript/packages/http/paywall/src/avm/algorand/useAlgorandWalletOptions.ts new file mode 100644 index 0000000000..3b910065b0 --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/algorand/useAlgorandWalletOptions.ts @@ -0,0 +1,43 @@ +import { useEffect, useState } from "react"; +import { getWallets } from "@wallet-standard/app"; + +import { hasAlgorandSigning } from "./features"; +import type { WalletOption } from "./types"; + +/** + * Subscribes to wallet-standard registrations and collects Algorand-capable wallets. + * + * @returns Wallet options suitable for Algorand interactions. + */ +export function useAlgorandWalletOptions(): WalletOption[] { + const [walletOptions, setWalletOptions] = useState([]); + + useEffect(() => { + const walletsApi = getWallets(); + + const mapWallets = (): WalletOption[] => + walletsApi + .get() + .filter(hasAlgorandSigning) + .map(wallet => ({ + value: wallet.name, + wallet, + })); + + setWalletOptions(mapWallets()); + + const offRegister = walletsApi.on("register", () => { + setWalletOptions(mapWallets()); + }); + const offUnregister = walletsApi.on("unregister", () => { + setWalletOptions(mapWallets()); + }); + + return () => { + offRegister(); + offUnregister(); + }; + }, []); + + return walletOptions; +} diff --git a/typescript/packages/http/paywall/src/avm/algorand/useSilentWalletConnection.ts b/typescript/packages/http/paywall/src/avm/algorand/useSilentWalletConnection.ts new file mode 100644 index 0000000000..ab5501c6c3 --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/algorand/useSilentWalletConnection.ts @@ -0,0 +1,90 @@ +import { useEffect } from "react"; +import type { MutableRefObject } from "react"; +import type { WalletAccount } from "@wallet-standard/base"; + +import { getStandardConnectFeature } from "./features"; +import type { WalletOption, WalletWithAvmFeatures } from "./types"; + +type Params = { + walletOptions: WalletOption[]; + activeWallet: WalletWithAvmFeatures | null; + attemptedSilentConnectWalletsRef: MutableRefObject>; + setSelectedWalletValue: (value: string) => void; + setActiveWallet: (wallet: WalletWithAvmFeatures | null) => void; + setActiveAccount: (account: WalletAccount | null) => void; + refreshBalance: (account?: WalletAccount | null) => Promise; + setStatus: (message: string) => void; +}; + +/** + * Attempts a silent connection with available wallets to restore prior authorization. + * + * @param params - Hook parameters controlling wallet state and callbacks. + * @param params.walletOptions - Wallets eligible for silent reconnection. + * @param params.activeWallet - Currently active wallet, if any. + * @param params.attemptedSilentConnectWalletsRef - Ref tracking wallets already attempted silently. + * @param params.setSelectedWalletValue - Setter for the currently selected wallet option. + * @param params.setActiveWallet - Setter storing the active wallet instance. + * @param params.setActiveAccount - Setter storing the active wallet account. + * @param params.refreshBalance - Callback used to refresh the USDC balance. + * @param params.setStatus - Setter used to surface user-visible status messages. + */ +export function useSilentWalletConnection({ + walletOptions, + activeWallet, + attemptedSilentConnectWalletsRef, + setSelectedWalletValue, + setActiveWallet, + setActiveAccount, + refreshBalance, + setStatus, +}: Params): void { + useEffect(() => { + if (activeWallet) { + return; + } + + for (const option of walletOptions) { + if (attemptedSilentConnectWalletsRef.current.has(option.value)) { + continue; + } + + attemptedSilentConnectWalletsRef.current.add(option.value); + const connectFeature = getStandardConnectFeature(option.wallet); + if (!connectFeature) { + continue; + } + + void (async () => { + try { + const { accounts } = await connectFeature.connect({ silent: true }); + if (!accounts?.length) { + return; + } + + const matchingAccount = accounts[0]; + if (!matchingAccount) { + return; + } + + setSelectedWalletValue(option.value); + setActiveWallet(option.wallet); + setActiveAccount(matchingAccount); + setStatus(""); + await refreshBalance(matchingAccount); + } catch { + // Wallet may throw if silent connect isn't supported or authorization is missing. Ignore. + } + })(); + } + }, [ + walletOptions, + activeWallet, + attemptedSilentConnectWalletsRef, + setSelectedWalletValue, + setActiveWallet, + setActiveAccount, + refreshBalance, + setStatus, + ]); +} diff --git a/typescript/packages/http/paywall/src/avm/build.ts b/typescript/packages/http/paywall/src/avm/build.ts new file mode 100644 index 0000000000..8dcbd3538c --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/build.ts @@ -0,0 +1,140 @@ +import esbuild from "esbuild"; +import { htmlPlugin } from "@craftamap/esbuild-plugin-html"; +import fs from "fs"; +import path from "path"; +import { getBaseTemplate } from "../baseTemplate"; +import { formatTypeScript, toPythonStringLiteral } from "../genHelpers"; + +// AVM-specific build - only bundles Algorand dependencies +const DIST_DIR = "src/avm/dist"; +const OUTPUT_HTML = path.join(DIST_DIR, "avm-paywall.html"); +const OUTPUT_TS = path.join("src/avm/gen", "template.ts"); + +// Cross-language template output paths (relative to package root where build runs) +const PYTHON_DIR = path.join("..", "..", "..", "..", "python", "x402", "http", "paywall"); +const GO_DIR = path.join("..", "..", "..", "..", "go", "http"); +const OUTPUT_PY = path.join(PYTHON_DIR, "avm_paywall_template.py"); +const OUTPUT_GO = path.join(GO_DIR, "avm_paywall_template.go"); + +const options: esbuild.BuildOptions = { + entryPoints: ["src/avm/entry.tsx", "src/styles.css"], + bundle: true, + metafile: true, + outdir: DIST_DIR, + treeShaking: true, + minify: true, + format: "iife", + sourcemap: false, + platform: "browser", + target: "es2020", + jsx: "transform", + define: { + "process.env.NODE_ENV": '"development"', + global: "globalThis", + Buffer: "globalThis.Buffer", + }, + mainFields: ["browser", "module", "main"], + conditions: ["browser"], + plugins: [ + htmlPlugin({ + files: [ + { + entryPoints: ["src/avm/entry.tsx", "src/styles.css"], + filename: "avm-paywall.html", + title: "Payment Required", + scriptLoading: "module", + inline: { + css: true, + js: true, + }, + htmlTemplate: getBaseTemplate(), + }, + ], + }), + ], + inject: ["./src/buffer-polyfill.ts"], + external: [ + "crypto", + // Mark unused wallet providers as external - we only use Pera, Defly, Lute + "@algorandfoundation/liquid-auth-use-wallet-client", + "@perawallet/connect-beta", + "@agoralabs-sh/avm-web-provider", + "@walletconnect/sign-client", + "@walletconnect/modal", + ], +}; + +/** + * Builds the AVM paywall HTML template with bundled JS and CSS. + * Also generates Python and Go template files for cross-language support. + */ +async function build() { + try { + if (!fs.existsSync(DIST_DIR)) { + fs.mkdirSync(DIST_DIR, { recursive: true }); + } + + const genDir = path.dirname(OUTPUT_TS); + if (!fs.existsSync(genDir)) { + fs.mkdirSync(genDir, { recursive: true }); + } + + await esbuild.build(options); + console.log("[AVM] Build completed successfully!"); + + if (fs.existsSync(OUTPUT_HTML)) { + const html = fs.readFileSync(OUTPUT_HTML, "utf8"); + + const rawTsContent = `// THIS FILE IS AUTO-GENERATED - DO NOT EDIT +/** + * The pre-built AVM paywall template with inlined CSS and JS + */ +export const AVM_PAYWALL_TEMPLATE = ${JSON.stringify(html)}; +`; + const tsContent = await formatTypeScript(OUTPUT_TS, rawTsContent); + + // Generate Python template file + const pyContent = `# THIS FILE IS AUTO-GENERATED - DO NOT EDIT +AVM_PAYWALL_TEMPLATE = ${toPythonStringLiteral(html)} +`; + + // Generate Go template file + const goContent = `// THIS FILE IS AUTO-GENERATED - DO NOT EDIT +package http + +// AVMPaywallTemplate is the pre-built AVM paywall template with inlined CSS and JS +const AVMPaywallTemplate = ${JSON.stringify(html)} +`; + + fs.writeFileSync(OUTPUT_TS, tsContent); + console.log(`[AVM] Generated template.ts (${(html.length / 1024 / 1024).toFixed(2)} MB)`); + + // Write the Python template file + if (fs.existsSync(PYTHON_DIR)) { + fs.writeFileSync(OUTPUT_PY, pyContent); + console.log( + `[AVM] Generated Python avm_paywall_template.py (${(html.length / 1024 / 1024).toFixed(2)} MB)`, + ); + } else { + console.warn(`[AVM] Python directory not found: ${PYTHON_DIR}`); + } + + // Write the Go template file + if (fs.existsSync(GO_DIR)) { + fs.writeFileSync(OUTPUT_GO, goContent); + console.log( + `[AVM] Generated Go avm_paywall_template.go (${(html.length / 1024 / 1024).toFixed(2)} MB)`, + ); + } else { + console.warn(`[AVM] Go directory not found: ${GO_DIR}`); + } + } else { + throw new Error(`AVM bundled HTML not found at ${OUTPUT_HTML}`); + } + } catch (error) { + console.error("[AVM] Build failed:", error); + process.exit(1); + } +} + +build(); diff --git a/typescript/packages/http/paywall/src/avm/entry.tsx b/typescript/packages/http/paywall/src/avm/entry.tsx new file mode 100644 index 0000000000..2036d73ee1 --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/entry.tsx @@ -0,0 +1,70 @@ +import React from "react"; +import { createRoot } from "react-dom/client"; +import { WalletManager, WalletId, NetworkId } from "@txnlab/use-wallet"; +import { AlgorandClient } from "@algorandfoundation/algokit-utils/algorand-client"; +import { AvmPaywall } from "./AvmPaywall"; +import type {} from "../window"; +import { ALGORAND_NETWORK_REFS } from "../paywallUtils"; + +// AVM-specific paywall entry point +window.addEventListener("load", async () => { + const rootElement = document.getElementById("root"); + if (!rootElement) { + console.error("Root element not found"); + return; + } + + const x402 = window.x402; + const paymentRequired = x402.paymentRequired; + + if (!paymentRequired?.accepts?.[0]) { + console.error("No payment requirements found"); + return; + } + + const network = paymentRequired.accepts[0].network; + const isTestnet = network.includes(ALGORAND_NETWORK_REFS.TESTNET); + + // Create AlgorandClient using algokit-utils built-in network defaults + const algorandClient = isTestnet ? AlgorandClient.testNet() : AlgorandClient.mainNet(); + + // Initialize WalletManager with Algorand wallets + // WalletManager v4 uses a networks record with algod config per network + const networkKey = isTestnet ? NetworkId.TESTNET : NetworkId.MAINNET; + const algodBaseServer = isTestnet + ? "https://testnet-api.algonode.cloud" + : "https://mainnet-api.algonode.cloud"; + + const walletManager = new WalletManager({ + wallets: [WalletId.PERA, WalletId.DEFLY, WalletId.LUTE], + defaultNetwork: networkKey, + networks: { + [networkKey]: { + algod: { + baseServer: algodBaseServer, + token: "", + port: "", + }, + }, + }, + }); + + const root = createRoot(rootElement); + root.render( + { + const contentType = response.headers.get("content-type"); + if (contentType && contentType.includes("text/html")) { + document.documentElement.innerHTML = await response.text(); + } else { + const blob = await response.blob(); + const url = window.URL.createObjectURL(blob); + window.location.href = url; + } + }} + />, + ); +}); diff --git a/typescript/packages/http/paywall/src/avm/gen/template.ts b/typescript/packages/http/paywall/src/avm/gen/template.ts new file mode 100644 index 0000000000..5e49a15157 --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/gen/template.ts @@ -0,0 +1,6 @@ +// THIS FILE IS AUTO-GENERATED - DO NOT EDIT +/** + * The pre-built AVM paywall template with inlined CSS and JS + */ +export const AVM_PAYWALL_TEMPLATE = + '\n \n \n Payment Required\n \n
\n \n \n '; diff --git a/typescript/packages/http/paywall/src/avm/index.ts b/typescript/packages/http/paywall/src/avm/index.ts new file mode 100644 index 0000000000..2ecb38bd2d --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/index.ts @@ -0,0 +1,51 @@ +import type { + PaywallNetworkHandler, + PaymentRequirements, + PaymentRequired, + PaywallConfig, +} from "../types"; +import { getAvmPaywallHtml } from "./paywall"; + +/** + * AVM paywall handler that supports Algorand-based networks (CAIP-2 format only) + */ +export const avmPaywall: PaywallNetworkHandler = { + /** + * Check if this handler supports the given payment requirement + * + * @param requirement - The payment requirement to check + * @returns True if this handler can process this requirement + */ + supports(requirement: PaymentRequirements): boolean { + return requirement.network.startsWith("algorand:"); + }, + + /** + * Generate AVM-specific paywall HTML + * + * @param requirement - The selected payment requirement + * @param paymentRequired - Full payment required response + * @param config - Paywall configuration + * @returns HTML string for the paywall page + */ + generateHtml( + requirement: PaymentRequirements, + paymentRequired: PaymentRequired, + config: PaywallConfig, + ): string { + const amount = requirement.amount + ? parseFloat(requirement.amount) / 1000000 + : requirement.maxAmountRequired + ? parseFloat(requirement.maxAmountRequired) / 1000000 + : 0; + + return getAvmPaywallHtml({ + amount, + paymentRequired, + currentUrl: paymentRequired.resource?.url || config.currentUrl || "", + testnet: config.testnet ?? true, + appName: config.appName, + appLogo: config.appLogo, + }); + }, +}; diff --git a/typescript/packages/http/paywall/src/avm/paywall.ts b/typescript/packages/http/paywall/src/avm/paywall.ts new file mode 100644 index 0000000000..459cb92fe0 --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/paywall.ts @@ -0,0 +1,71 @@ +import type { PaymentRequired } from "../types"; +import { getAvmTemplate } from "./template-loader"; + +/** + * Escapes a string for safe injection into JavaScript string literals + * + * @param str - The string to escape + * @returns The escaped string + */ +function escapeString(str: string): string { + return str + .replace(/\\/g, "\\\\") + .replace(/"/g, '\\"') + .replace(/'/g, "\\'") + .replace(/\n/g, "\\n") + .replace(/\r/g, "\\r") + .replace(/\t/g, "\\t"); +} + +interface AvmPaywallOptions { + amount: number; + paymentRequired: PaymentRequired; + currentUrl: string; + testnet: boolean; + appName?: string; + appLogo?: string; +} + +/** + * Generates AVM-specific paywall HTML + * + * @param options - The options for generating the paywall + * @param options.amount - The amount to be paid in USD + * @param options.paymentRequired - The payment required response with accepts array + * @param options.currentUrl - The URL of the content being accessed + * @param options.testnet - Whether to use testnet or mainnet + * @param options.appName - The name of the application to display in the wallet connection modal + * @param options.appLogo - The logo of the application to display in the wallet connection modal + * @returns HTML string for the paywall page + */ +export function getAvmPaywallHtml(options: AvmPaywallOptions): string { + const AVM_PAYWALL_TEMPLATE = getAvmTemplate(); + + if (!AVM_PAYWALL_TEMPLATE) { + return `

AVM Paywall (run pnpm build:paywall to generate full template)

`; + } + + const { amount, testnet, paymentRequired, currentUrl, appName, appLogo } = options; + + const logOnTestnet = testnet + ? "console.log('AVM Payment required initialized:', window.x402);" + : ""; + + const configScript = ` + `; + + return AVM_PAYWALL_TEMPLATE.replace("", `${configScript}\n`); +} diff --git a/typescript/packages/http/paywall/src/avm/template-loader.ts b/typescript/packages/http/paywall/src/avm/template-loader.ts new file mode 100644 index 0000000000..dbe2d5cf18 --- /dev/null +++ b/typescript/packages/http/paywall/src/avm/template-loader.ts @@ -0,0 +1,16 @@ +let cachedTemplate: string | null = null; + +export function getAvmTemplate(): string | null { + if (cachedTemplate !== null) { + return cachedTemplate; + } + + try { + // eslint-disable-next-line @typescript-eslint/no-require-imports + const template = require("./gen/template"); + cachedTemplate = template.AVM_PAYWALL_TEMPLATE; + return cachedTemplate; + } catch { + return null; + } +} diff --git a/typescript/packages/http/paywall/src/evm/EvmPaywall.tsx b/typescript/packages/http/paywall/src/evm/EvmPaywall.tsx index b28c130093..1272de6338 100644 --- a/typescript/packages/http/paywall/src/evm/EvmPaywall.tsx +++ b/typescript/packages/http/paywall/src/evm/EvmPaywall.tsx @@ -7,7 +7,7 @@ import { ExactEvmScheme } from "@x402/evm/exact/client"; import { x402Client } from "@x402/core/client"; import { encodePaymentSignatureHeader } from "@x402/core/http"; import type { PaymentRequired } from "@x402/core/types"; -import { getUSDCBalance } from "./utils"; +import { getTokenBalance, getTokenDecimals } from "./utils"; import { Spinner } from "./Spinner"; import { getNetworkDisplayName, isTestnetNetwork } from "../paywallUtils"; @@ -36,7 +36,7 @@ export function EvmPaywall({ paymentRequired, onSuccessfulResponse }: EvmPaywall const [status, setStatus] = useState(""); const [isCorrectChain, setIsCorrectChain] = useState(null); const [isPaying, setIsPaying] = useState(false); - const [formattedUsdcBalance, setFormattedUsdcBalance] = useState(""); + const [formattedBalance, setFormattedBalance] = useState(""); const [hideBalance, setHideBalance] = useState(true); const [selectedConnectorId, setSelectedConnectorId] = useState(""); @@ -49,6 +49,8 @@ export function EvmPaywall({ paymentRequired, onSuccessfulResponse }: EvmPaywall } const network = firstRequirement.network; + const tokenName = (firstRequirement.extra?.name as string) || "Token"; + const tokenAddress = firstRequirement.asset as `0x${string}`; const chainName = getNetworkDisplayName(network); const testnet = isTestnetNetwork(network); @@ -70,14 +72,16 @@ export function EvmPaywall({ paymentRequired, onSuccessfulResponse }: EvmPaywall [paymentChain], ); - const checkUSDCBalance = useCallback(async () => { + const checkBalance = useCallback(async () => { if (!address) { return; } - const balance = await getUSDCBalance(publicClient, address); - const formattedBalance = formatUnits(balance, 6); - setFormattedUsdcBalance(formattedBalance); - }, [address, publicClient]); + const [balance, decimals] = await Promise.all([ + getTokenBalance(publicClient, address, tokenAddress), + getTokenDecimals(publicClient, tokenAddress), + ]); + setFormattedBalance(formatUnits(balance, decimals)); + }, [address, publicClient, tokenAddress]); const handleSwitchChain = useCallback(async () => { if (isCorrectChain) { @@ -99,8 +103,8 @@ export function EvmPaywall({ paymentRequired, onSuccessfulResponse }: EvmPaywall } void handleSwitchChain(); - void checkUSDCBalance(); - }, [address, handleSwitchChain, checkUSDCBalance]); + void checkBalance(); + }, [address, handleSwitchChain, checkBalance]); useEffect(() => { if (isConnected && chainId === connectedChainId) { @@ -138,11 +142,11 @@ export function EvmPaywall({ paymentRequired, onSuccessfulResponse }: EvmPaywall setIsPaying(true); try { - setStatus("Checking USDC balance..."); - const balance = await getUSDCBalance(publicClient, address); + setStatus("Checking balance..."); + const balance = await getTokenBalance(publicClient, address, tokenAddress); if (balance === 0n) { - throw new Error(`Insufficient balance. Make sure you have USDC on ${chainName}`); + throw new Error(`Insufficient balance. Make sure you have ${tokenName} on ${chainName}`); } setStatus("Creating payment signature..."); @@ -196,11 +200,11 @@ export function EvmPaywall({ paymentRequired, onSuccessfulResponse }: EvmPaywall

Payment Required

{paymentRequired.resource?.description && `${paymentRequired.resource.description}.`} To - access this content, please pay ${amount} {chainName} USDC. + access this content, please pay ${amount} {tokenName}.

{testnet && (

- Need {chainName} USDC?{" "} + Need {tokenName} on {chainName}?{" "} Get some here. @@ -258,15 +262,17 @@ export function EvmPaywall({ paymentRequired, onSuccessfulResponse }: EvmPaywall Available balance:

Amount: - ${amount} USDC + + ${amount} {tokenName} +
Network: diff --git a/typescript/packages/http/paywall/src/evm/build.ts b/typescript/packages/http/paywall/src/evm/build.ts index 0d7d924882..b8537f81c6 100644 --- a/typescript/packages/http/paywall/src/evm/build.ts +++ b/typescript/packages/http/paywall/src/evm/build.ts @@ -2,12 +2,15 @@ import esbuild from "esbuild"; import { htmlPlugin } from "@craftamap/esbuild-plugin-html"; import fs from "fs"; import path from "path"; +import { DEFAULT_STABLECOINS } from "@x402/evm"; import { getBaseTemplate } from "../baseTemplate"; +import { formatTypeScript, toPythonStringLiteral } from "../genHelpers"; // EVM-specific build - only bundles EVM dependencies const DIST_DIR = "src/evm/dist"; const OUTPUT_HTML = path.join(DIST_DIR, "evm-paywall.html"); const OUTPUT_TS = path.join("src/evm/gen", "template.ts"); +const OUTPUT_DECIMALS = path.join("src/evm/gen", "decimals.ts"); // Cross-language template output paths (relative to package root where build runs) const PYTHON_DIR = path.join("..", "..", "..", "..", "python", "x402", "http", "paywall"); @@ -76,16 +79,17 @@ async function build() { if (fs.existsSync(OUTPUT_HTML)) { const html = fs.readFileSync(OUTPUT_HTML, "utf8"); - const tsContent = `// THIS FILE IS AUTO-GENERATED - DO NOT EDIT + const rawTsContent = `// THIS FILE IS AUTO-GENERATED - DO NOT EDIT /** * The pre-built EVM paywall template with inlined CSS and JS */ export const EVM_PAYWALL_TEMPLATE = ${JSON.stringify(html)}; `; + const tsContent = await formatTypeScript(OUTPUT_TS, rawTsContent); // Generate Python template file const pyContent = `# THIS FILE IS AUTO-GENERATED - DO NOT EDIT -EVM_PAYWALL_TEMPLATE = ${JSON.stringify(html)} +EVM_PAYWALL_TEMPLATE = ${toPythonStringLiteral(html)} `; // Generate Go template file @@ -99,6 +103,34 @@ const EVMPaywallTemplate = ${JSON.stringify(html)} fs.writeFileSync(OUTPUT_TS, tsContent); console.log(`[EVM] Generated template.ts (${(html.length / 1024 / 1024).toFixed(2)} MB)`); + // Generate a runtime-dep-free decimals lookup sourced from @x402/evm's + // DEFAULT_STABLECOINS. Keeps @x402/evm as a devDependency only while + // preserving a single source of truth for per-network decimals (CI drift + // check in check_paywall_template.yml covers regen correctness). + const decimalsMap: Record = Object.fromEntries( + Object.entries(DEFAULT_STABLECOINS).map(([network, info]) => [network, info.decimals]), + ); + const decimalsEntries = Object.entries(decimalsMap) + .sort(([a], [b]) => a.localeCompare(b)) + .map(([network, decimals]) => ` ${JSON.stringify(network)}: ${decimals},`) + .join("\n"); + const decimalsContent = `// THIS FILE IS AUTO-GENERATED - DO NOT EDIT +// Source: @x402/evm DEFAULT_STABLECOINS (decimals only). +// Regenerate via: pnpm --filter @x402/paywall run build:paywall + +/** + * Per-network default token decimals, keyed by CAIP-2 network identifier. + * Mirrors the \`decimals\` field of \`DEFAULT_STABLECOINS\` from \`@x402/evm\` + * and is emitted at build time so the paywall's runtime module graph does + * not depend on \`@x402/evm\`. + */ +export const NETWORK_DECIMALS: Record = { +${decimalsEntries} +}; +`; + fs.writeFileSync(OUTPUT_DECIMALS, decimalsContent); + console.log(`[EVM] Generated decimals.ts (${Object.keys(decimalsMap).length} networks)`); + // Write the Python template file if (fs.existsSync(PYTHON_DIR)) { fs.writeFileSync(OUTPUT_PY, pyContent); diff --git a/typescript/packages/http/paywall/src/evm/gen/decimals.ts b/typescript/packages/http/paywall/src/evm/gen/decimals.ts new file mode 100644 index 0000000000..a6a8616e2d --- /dev/null +++ b/typescript/packages/http/paywall/src/evm/gen/decimals.ts @@ -0,0 +1,24 @@ +// THIS FILE IS AUTO-GENERATED - DO NOT EDIT +// Source: @x402/evm DEFAULT_STABLECOINS (decimals only). +// Regenerate via: pnpm --filter @x402/paywall run build:paywall + +/** + * Per-network default token decimals, keyed by CAIP-2 network identifier. + * Mirrors the `decimals` field of `DEFAULT_STABLECOINS` from `@x402/evm` + * and is emitted at build time so the paywall's runtime module graph does + * not depend on `@x402/evm`. + */ +export const NETWORK_DECIMALS: Record = { + "eip155:137": 6, + "eip155:143": 6, + "eip155:2201": 6, + "eip155:31611": 18, + "eip155:42161": 6, + "eip155:421614": 6, + "eip155:4326": 18, + "eip155:72344": 6, + "eip155:723487": 6, + "eip155:8453": 6, + "eip155:84532": 6, + "eip155:988": 6, +}; diff --git a/typescript/packages/http/paywall/src/evm/gen/template.ts b/typescript/packages/http/paywall/src/evm/gen/template.ts index d31f495b40..69791d844d 100644 --- a/typescript/packages/http/paywall/src/evm/gen/template.ts +++ b/typescript/packages/http/paywall/src/evm/gen/template.ts @@ -3,4 +3,4 @@ * The pre-built EVM paywall template with inlined CSS and JS */ export const EVM_PAYWALL_TEMPLATE = - '\n \n \n Payment Required\n \n
\n \n \n '; + '\n \n \n Payment Required\n \n
\n \n \n '; diff --git a/typescript/packages/http/paywall/src/evm/index.ts b/typescript/packages/http/paywall/src/evm/index.ts index 88e24ebcc2..ab3c83087a 100644 --- a/typescript/packages/http/paywall/src/evm/index.ts +++ b/typescript/packages/http/paywall/src/evm/index.ts @@ -1,3 +1,4 @@ +import { formatUnits } from "viem"; import type { PaywallNetworkHandler, PaymentRequirements, @@ -5,6 +6,22 @@ import type { PaywallConfig, } from "../types"; import { getEvmPaywallHtml } from "./paywall"; +import { NETWORK_DECIMALS } from "./gen/decimals"; + +/** + * Resolves the token decimals for a payment requirement by looking up the + * network in the build-time-generated `NETWORK_DECIMALS` map. That map is + * derived from `@x402/evm`'s `DEFAULT_STABLECOINS` (the same source the + * scheme `getAssetDecimals` methods read from) and is regenerated via + * `pnpm --filter @x402/paywall run build:paywall`. Falls back to 6 (USDC + * default) when the network is unknown. + * + * @param requirement - The payment requirement + * @returns The number of decimals for the payment token + */ +export function getDefaultTokenDecimals(requirement: PaymentRequirements): number { + return NETWORK_DECIMALS[requirement.network] ?? 6; +} /** * EVM paywall handler that supports EVM-based networks (CAIP-2 format only) @@ -33,11 +50,11 @@ export const evmPaywall: PaywallNetworkHandler = { paymentRequired: PaymentRequired, config: PaywallConfig, ): string { - const amount = requirement.amount - ? parseFloat(requirement.amount) / 1000000 - : requirement.maxAmountRequired - ? parseFloat(requirement.maxAmountRequired) / 1000000 - : 0; + const decimals = getDefaultTokenDecimals(requirement); + const atomic = requirement.amount ?? requirement.maxAmountRequired; + // BigInt + formatUnits preserves precision through the conversion; + // parseFloat collapses sub-cent digits on real 18-decimal amounts. + const amount = atomic ? Number(formatUnits(BigInt(atomic), decimals)) : 0; return getEvmPaywallHtml({ amount, diff --git a/typescript/packages/http/paywall/src/evm/utils.ts b/typescript/packages/http/paywall/src/evm/utils.ts index 1a04f67629..e999d57b7c 100644 --- a/typescript/packages/http/paywall/src/evm/utils.ts +++ b/typescript/packages/http/paywall/src/evm/utils.ts @@ -1,18 +1,9 @@ import type { Address, Client, Chain, Transport, Account } from "viem"; /** - * USDC contract addresses by chain ID + * ERC20 ABI for balance and decimal queries */ -const USDC_ADDRESSES: Record = { - 1: "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48", // Ethereum Mainnet - 8453: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", // Base Mainnet - 84532: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", // Base Sepolia -}; - -/** - * ERC20 balanceOf ABI - */ -const ERC20_BALANCE_ABI = [ +const ERC20_ABI = [ { name: "balanceOf", type: "function", @@ -20,36 +11,68 @@ const ERC20_BALANCE_ABI = [ inputs: [{ name: "account", type: "address" }], outputs: [{ name: "balance", type: "uint256" }], }, + { + name: "decimals", + type: "function", + stateMutability: "view", + inputs: [], + outputs: [{ name: "decimals", type: "uint8" }], + }, ] as const; /** - * Gets the USDC balance for a specific address on the current chain. + * Gets the token balance for a specific address. * * @param client - Viem client instance connected to the blockchain - * @param address - Address to check the USDC balance for - * @returns USDC balance as bigint (0 if USDC not supported on chain or error) + * @param owner - Address to check the balance for + * @param tokenAddress - ERC-20 token contract address + * @returns Token balance as bigint (0 on error) */ -export async function getUSDCBalance< +export async function getTokenBalance< TTransport extends Transport, TChain extends Chain, TAccount extends Account | undefined = undefined, ->(client: Client, address: Address): Promise { - const chainId = client.chain?.id; - if (!chainId) return 0n; - - const usdcAddress = USDC_ADDRESSES[chainId]; - if (!usdcAddress) return 0n; - +>( + client: Client, + owner: Address, + tokenAddress: Address, +): Promise { try { const balance = await client.readContract({ - address: usdcAddress, - abi: ERC20_BALANCE_ABI, + address: tokenAddress, + abi: ERC20_ABI, functionName: "balanceOf", - args: [address], + args: [owner], }); return balance as bigint; } catch (error) { - console.error("Failed to fetch USDC balance:", error); + console.error("Failed to fetch token balance:", error); return 0n; } } + +/** + * Gets the token decimals from the on-chain contract. + * Falls back to 6 (USDC default) if the query fails. + * + * @param client - Viem client instance connected to the blockchain + * @param tokenAddress - ERC-20 token contract address + * @returns Token decimals (defaults to 6 on error) + */ +export async function getTokenDecimals< + TTransport extends Transport, + TChain extends Chain, + TAccount extends Account | undefined = undefined, +>(client: Client, tokenAddress: Address): Promise { + try { + const decimals = await client.readContract({ + address: tokenAddress, + abi: ERC20_ABI, + functionName: "decimals", + }); + return Number(decimals); + } catch (error) { + console.error("Failed to fetch token decimals:", error); + return 6; + } +} diff --git a/typescript/packages/http/paywall/src/genHelpers.ts b/typescript/packages/http/paywall/src/genHelpers.ts new file mode 100644 index 0000000000..0f076291d2 --- /dev/null +++ b/typescript/packages/http/paywall/src/genHelpers.ts @@ -0,0 +1,45 @@ +import prettier from "prettier"; + +/** + * Format a TypeScript file's contents using the paywall package's prettier + * config. Used to keep auto-generated template files byte-identical to what + * `pnpm run format` would emit, so CI drift checks stay reliable. + * + * @param filePath - Absolute or relative path used by prettier for config + * resolution and filetype inference. + * @param contents - Source contents to format. + * @returns The prettier-formatted contents. + */ +export async function formatTypeScript(filePath: string, contents: string): Promise { + const config = await prettier.resolveConfig(filePath); + return prettier.format(contents, { ...config, filepath: filePath }); +} + +/** + * Serialize a string as a Python source literal, choosing the quote style + * that requires fewer escapes. Mirrors ruff/black's default behavior so that + * `ruff format --check` is a no-op on generated files. + * + * @param s - Input string to serialize. + * @returns A Python string literal (quoted and escaped) representing `s`. + */ +export function toPythonStringLiteral(s: string): string { + const singleCount = (s.match(/'/g) || []).length; + const doubleCount = (s.match(/"/g) || []).length; + const useSingle = doubleCount > singleCount; + const quote = useSingle ? "'" : '"'; + + let body = s + .replace(/\\/g, "\\\\") + .replace(/\n/g, "\\n") + .replace(/\r/g, "\\r") + .replace(/\t/g, "\\t") + .replace(/\f/g, "\\f") + .replace(/\v/g, "\\v") + .replace( + /[\x00-\x08\x0e-\x1f\x7f]/g, + c => `\\x${c.charCodeAt(0).toString(16).padStart(2, "0")}`, + ); + body = useSingle ? body.replace(/'/g, "\\'") : body.replace(/"/g, '\\"'); + return `${quote}${body}${quote}`; +} diff --git a/typescript/packages/http/paywall/src/index.test.ts b/typescript/packages/http/paywall/src/index.test.ts index 00ba681871..1656e98d0c 100644 --- a/typescript/packages/http/paywall/src/index.test.ts +++ b/typescript/packages/http/paywall/src/index.test.ts @@ -1,12 +1,64 @@ -import { describe, it, expect } from "vitest"; +import { describe, expect, it } from "vitest"; +import { avmPaywall, createPaywall, evmPaywall, PaywallBuilder, svmPaywall } from "./index"; +import type { PaywallNetworkHandler, PaymentRequired, PaymentRequirements } from "./index"; -describe("@x402/paywall", () => { - it("should be defined", () => { - expect(true).toBe(true); +describe("@x402/paywall entrypoint", () => { + it("exports the paywall builder helpers", () => { + expect(createPaywall()).toBeInstanceOf(PaywallBuilder); + expect(typeof PaywallBuilder).toBe("function"); }); - // TODO: Add actual tests for paywall functionality - it.todo("should handle payment required responses"); - it.todo("should render paywall UI"); - it.todo("should process payments"); + it("exports network handlers with their CAIP-2 support checks", () => { + const evmRequirement = createRequirement("eip155:8453"); + const svmRequirement = createRequirement("solana:mainnet"); + const avmRequirement = createRequirement("algorand:mainnet"); + + expect(evmPaywall.supports(evmRequirement)).toBe(true); + expect(evmPaywall.supports(svmRequirement)).toBe(false); + + expect(svmPaywall.supports(svmRequirement)).toBe(true); + expect(svmPaywall.supports(avmRequirement)).toBe(false); + + expect(avmPaywall.supports(avmRequirement)).toBe(true); + expect(avmPaywall.supports(evmRequirement)).toBe(false); + }); + + it("builds a provider from the exported factory", () => { + const handler: PaywallNetworkHandler = { + supports: requirement => requirement.network === "test:network", + generateHtml: (requirement, paymentRequired, config) => + `${requirement.network}:${paymentRequired.x402Version}:${config.appName ?? ""}`, + }; + + const provider = createPaywall() + .withConfig({ appName: "builder app" }) + .withNetwork(handler) + .build(); + + expect(provider.generateHtml(createPaymentRequired("test:network"))).toBe( + "test:network:2:builder app", + ); + expect( + provider.generateHtml(createPaymentRequired("test:network"), { appName: "runtime app" }), + ).toBe("test:network:2:runtime app"); + }); }); + +function createRequirement(network: string): PaymentRequirements { + return { + scheme: "exact", + network, + asset: "USDC", + amount: "100000", + payTo: "0x209693Bc6afc0C5328bA36FaF04C514EF312287C", + maxTimeoutSeconds: 60, + }; +} + +function createPaymentRequired(network: string): PaymentRequired { + return { + x402Version: 2, + error: "Payment required", + accepts: [createRequirement(network)], + }; +} diff --git a/typescript/packages/http/paywall/src/index.ts b/typescript/packages/http/paywall/src/index.ts index 29443fe3e6..132a9ef171 100644 --- a/typescript/packages/http/paywall/src/index.ts +++ b/typescript/packages/http/paywall/src/index.ts @@ -15,3 +15,4 @@ export type { // Re-export network handlers for convenience export { evmPaywall } from "./evm"; export { svmPaywall } from "./svm"; +export { avmPaywall } from "./avm"; diff --git a/typescript/packages/http/paywall/src/network-handlers.test.ts b/typescript/packages/http/paywall/src/network-handlers.test.ts index cb4e506505..d1a2d20d17 100644 --- a/typescript/packages/http/paywall/src/network-handlers.test.ts +++ b/typescript/packages/http/paywall/src/network-handlers.test.ts @@ -1,5 +1,7 @@ import { describe, expect, it } from "vitest"; -import { evmPaywall } from "./evm"; +import { DEFAULT_STABLECOINS } from "@x402/evm"; +import { evmPaywall, getDefaultTokenDecimals } from "./evm"; +import { NETWORK_DECIMALS } from "./evm/gen/decimals"; import { svmPaywall } from "./svm"; import type { PaymentRequired, PaymentRequirements } from "./types"; @@ -55,6 +57,114 @@ describe("Network Handlers", () => { expect(html).toContain(""); expect(html).toMatch(/Test App|EVM Paywall/); }); + + it("renders 1e15-atomic Mezo mUSD as 0.001 (18-decimal end-to-end)", () => { + // Mezo Testnet mUSD is 18-decimal in DEFAULT_STABLECOINS. + // 1e15 atomic = 0.001 mUSD. A regression to the old `parseFloat / 1e6` + // path would render this as 1_000_000_000 (the order-of-magnitude bug + // this PR fixes). + const req: PaymentRequirements = { + scheme: "exact", + network: "eip155:31611", + asset: "0x118917a40FAF1CD7a13dB0Ef56C86De7973Ac503", + amount: "1000000000000000", + payTo: "0x209693Bc6afc0C5328bA36FaF04C514EF312287C", + maxTimeoutSeconds: 60, + }; + const html = evmPaywall.generateHtml( + req, + { ...mockPaymentRequired, accepts: [req] }, + { appName: "Mezo Test", testnet: true }, + ); + expect(html).toContain("amount: 0.001,"); + expect(html).not.toMatch(/amount: 1000000000(?!\.)/); + }); + + it("rejects non-integer atomic amount strings (BigInt strictness)", () => { + // The spec defines `amount` as an atomic integer string. The previous + // parseFloat-based implementation silently coerced non-integer inputs + // (e.g. "1.5", "1e15"); the BigInt-based implementation throws. + // This test pins that strictness so a future revert to parseFloat fails. + const req: PaymentRequirements = { + ...evmRequirement, + network: "eip155:8453", + amount: "1.5", + }; + expect(() => + evmPaywall.generateHtml( + req, + { ...mockPaymentRequired, accepts: [req] }, + { + appName: "Strictness Test", + testnet: true, + }, + ), + ).toThrow(); + }); + + it("renders 1e6-atomic Base USDC as 1 (6-decimal end-to-end)", () => { + // Base mainnet USDC is 6-decimal in DEFAULT_STABLECOINS. + // 1e6 atomic = 1.00 USDC. Asserts the same dispatch behaves correctly + // for the canonical 6-decimal case alongside the 18-decimal case above. + const req: PaymentRequirements = { + scheme: "exact", + network: "eip155:8453", + asset: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", + amount: "1000000", + payTo: "0x209693Bc6afc0C5328bA36FaF04C514EF312287C", + maxTimeoutSeconds: 60, + }; + const html = evmPaywall.generateHtml( + req, + { ...mockPaymentRequired, accepts: [req] }, + { appName: "Base Test", testnet: false }, + ); + expect(html).toContain("amount: 1,"); + }); + }); + + describe("getDefaultTokenDecimals", () => { + it("reads non-default decimals from the @x402/evm registry", () => { + // Mezo Testnet mUSD is 18-decimal in DEFAULT_STABLECOINS + const req: PaymentRequirements = { + ...evmRequirement, + network: "eip155:31611", + asset: "0x118917a40FAF1CD7a13dB0Ef56C86De7973Ac503", + }; + expect(getDefaultTokenDecimals(req)).toBe(18); + }); + + it("reads the registry value (not the fallback) for a known 6-decimal chain", () => { + // Base mainnet USDC is in the registry at 6 decimals. Asserting + // alongside DEFAULT_STABLECOINS catches the case where the registry is + // empty: the function would still return 6 via fallback, but the second + // assertion would fail. + const req: PaymentRequirements = { ...evmRequirement, network: "eip155:8453" }; + expect(getDefaultTokenDecimals(req)).toBe(6); + expect(DEFAULT_STABLECOINS["eip155:8453"]?.decimals).toBe(6); + }); + + it("falls back to 6 (USDC default) for networks not in the registry", () => { + const req: PaymentRequirements = { + ...evmRequirement, + network: "eip155:9999999", // unknown network + }; + expect(getDefaultTokenDecimals(req)).toBe(6); + }); + + it("NETWORK_DECIMALS stays in sync with DEFAULT_STABLECOINS", () => { + // The generated `src/evm/gen/decimals.ts` file is emitted by + // `src/evm/build.ts` from `@x402/evm`'s `DEFAULT_STABLECOINS`. This + // test pins the drift invariant in-process so a forgotten + // `pnpm run build:paywall` after a `DEFAULT_STABLECOINS` change is + // caught here (complements the CI regen-diff guard in #2054). + for (const [network, info] of Object.entries(DEFAULT_STABLECOINS)) { + expect(NETWORK_DECIMALS[network], `drift on ${network}`).toBe(info.decimals); + } + expect(Object.keys(NETWORK_DECIMALS).sort()).toStrictEqual( + Object.keys(DEFAULT_STABLECOINS).sort(), + ); + }); }); describe("svmPaywall", () => { diff --git a/typescript/packages/http/paywall/src/paywallUtils.ts b/typescript/packages/http/paywall/src/paywallUtils.ts index f480cbde2b..d007da3d99 100644 --- a/typescript/packages/http/paywall/src/paywallUtils.ts +++ b/typescript/packages/http/paywall/src/paywallUtils.ts @@ -16,6 +16,12 @@ export const SOLANA_NETWORK_REFS = { DEVNET: "EtWTRABZaYq6iMfeYKouRu166VU2xqa1", } as const; +// Algorand Network References (CAIP-2 format: algorand:genesisHash) +export const ALGORAND_NETWORK_REFS = { + MAINNET: "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=", + TESTNET: "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=", +} as const; + /** * Normalizes the payment requirements into an array. * @@ -90,6 +96,16 @@ export function isSvmNetwork(network: string): boolean { return network.startsWith("solana:"); } +/** + * Determines if the provided network is an AVM (Algorand) network. + * + * @param network - The network to check (CAIP-2 format: algorand:genesisHash). + * @returns True if the network is AVM based. + */ +export function isAvmNetwork(network: string): boolean { + return network.startsWith("algorand:"); +} + /** * Provides a human-readable display name for a network. * Uses viem/chains for EVM chain metadata (based on ethereum-lists/chains). @@ -117,6 +133,11 @@ export function getNetworkDisplayName(network: string): string { return ref === SOLANA_NETWORK_REFS.DEVNET ? "Solana Devnet" : "Solana Mainnet"; } + if (network.startsWith("algorand:")) { + const ref = network.split(":")[1]; + return ref === ALGORAND_NETWORK_REFS.TESTNET ? "Algorand Testnet" : "Algorand Mainnet"; + } + return network; } @@ -139,5 +160,10 @@ export function isTestnetNetwork(network: string): boolean { return ref === SOLANA_NETWORK_REFS.DEVNET; } + if (network.startsWith("algorand:")) { + const ref = network.split(":")[1]; + return ref === ALGORAND_NETWORK_REFS.TESTNET; + } + return false; } diff --git a/typescript/packages/http/paywall/src/svm/build.ts b/typescript/packages/http/paywall/src/svm/build.ts index bf1bfe0de9..d0101004e9 100644 --- a/typescript/packages/http/paywall/src/svm/build.ts +++ b/typescript/packages/http/paywall/src/svm/build.ts @@ -3,6 +3,7 @@ import { htmlPlugin } from "@craftamap/esbuild-plugin-html"; import fs from "fs"; import path from "path"; import { getBaseTemplate } from "../baseTemplate"; +import { formatTypeScript, toPythonStringLiteral } from "../genHelpers"; // SVM-specific build - only bundles Solana dependencies const DIST_DIR = "src/svm/dist"; @@ -76,16 +77,17 @@ async function build() { if (fs.existsSync(OUTPUT_HTML)) { const html = fs.readFileSync(OUTPUT_HTML, "utf8"); - const tsContent = `// THIS FILE IS AUTO-GENERATED - DO NOT EDIT + const rawTsContent = `// THIS FILE IS AUTO-GENERATED - DO NOT EDIT /** * The pre-built SVM paywall template with inlined CSS and JS */ export const SVM_PAYWALL_TEMPLATE = ${JSON.stringify(html)}; `; + const tsContent = await formatTypeScript(OUTPUT_TS, rawTsContent); // Generate Python template file const pyContent = `# THIS FILE IS AUTO-GENERATED - DO NOT EDIT -SVM_PAYWALL_TEMPLATE = ${JSON.stringify(html)} +SVM_PAYWALL_TEMPLATE = ${toPythonStringLiteral(html)} `; // Generate Go template file diff --git a/typescript/packages/http/paywall/src/svm/gen/template.ts b/typescript/packages/http/paywall/src/svm/gen/template.ts index 954431627c..044233b926 100644 --- a/typescript/packages/http/paywall/src/svm/gen/template.ts +++ b/typescript/packages/http/paywall/src/svm/gen/template.ts @@ -3,4 +3,4 @@ * The pre-built SVM paywall template with inlined CSS and JS */ export const SVM_PAYWALL_TEMPLATE = - '\n \n \n Payment Required\n \n
\n \n \n '; + '\n \n \n Payment Required\n \n
\n \n \n '; diff --git a/typescript/packages/http/paywall/tsup.config.ts b/typescript/packages/http/paywall/tsup.config.ts index cc8ba6a4fa..0a85785c96 100644 --- a/typescript/packages/http/paywall/tsup.config.ts +++ b/typescript/packages/http/paywall/tsup.config.ts @@ -5,6 +5,7 @@ const baseConfig = { index: "src/index.ts", "evm/index": "src/evm/index.ts", "svm/index": "src/svm/index.ts", + "avm/index": "src/avm/index.ts", }, dts: { resolve: true, diff --git a/typescript/packages/legacy/x402-axios/README.md b/typescript/packages/legacy/x402-axios/README.md index 9c9bb4b011..dce531ac4d 100644 --- a/typescript/packages/legacy/x402-axios/README.md +++ b/typescript/packages/legacy/x402-axios/README.md @@ -1,5 +1,9 @@ # x402-axios +> **Deprecated (v1)** +> This npm package implements x402 **v1**. It is **deprecated** and will only receive **security patches**. Please migrate to **v2** (`@x402/axios`, `@x402/evm`, etc.). See the [Migration guide: v1 to v2](https://docs.x402.org/guides/migration-v1-to-v2). +> Legacy examples are available at git tag `archive/legacy-v1-examples`. + A utility package that extends Axios to automatically handle 402 Payment Required responses using the x402 payment protocol. This package enables seamless integration of payment functionality into your applications when making HTTP requests with Axios. ## Installation diff --git a/typescript/packages/legacy/x402-axios/package.json b/typescript/packages/legacy/x402-axios/package.json index 59d7c191e1..4edaedacc7 100644 --- a/typescript/packages/legacy/x402-axios/package.json +++ b/typescript/packages/legacy/x402-axios/package.json @@ -17,8 +17,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@eslint/js": "^9.24.0", @@ -31,7 +31,7 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.0.5", @@ -39,7 +39,7 @@ }, "dependencies": { "axios": "^1.7.9", - "viem": "^2.21.26", + "viem": "^2.48.11", "x402": "workspace:^", "zod": "^3.24.2" }, diff --git a/typescript/packages/legacy/x402-express/README.md b/typescript/packages/legacy/x402-express/README.md index 4a3f63260e..e396789200 100644 --- a/typescript/packages/legacy/x402-express/README.md +++ b/typescript/packages/legacy/x402-express/README.md @@ -1,5 +1,9 @@ # x402-express +> **Deprecated (v1)** +> This npm package implements x402 **v1**. It is **deprecated** and will only receive **security patches**. Please migrate to **v2** (`@x402/express`, `@x402/core`, `@x402/evm`, etc.). See the [Migration guide: v1 to v2](https://docs.x402.org/guides/migration-v1-to-v2). +> Legacy examples are available at git tag `archive/legacy-v1-examples`. + Express middleware integration for the x402 Payment Protocol. This package allows you to easily add paywall functionality to your Express.js applications using the x402 protocol. ## Installation diff --git a/typescript/packages/legacy/x402-express/package.json b/typescript/packages/legacy/x402-express/package.json index a27ee14af6..77685cb365 100644 --- a/typescript/packages/legacy/x402-express/package.json +++ b/typescript/packages/legacy/x402-express/package.json @@ -17,8 +17,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@eslint/js": "^9.24.0", @@ -32,7 +32,7 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", @@ -42,7 +42,7 @@ "@solana/kit": "^5.0.0", "@coinbase/cdp-sdk": "^1.22.0", "express": "^4.18.2", - "viem": "^2.21.26", + "viem": "^2.48.11", "x402": "workspace:^", "zod": "^3.24.2" }, diff --git a/typescript/packages/legacy/x402-fetch/README.md b/typescript/packages/legacy/x402-fetch/README.md index 5b3bfd3886..45cf85502e 100644 --- a/typescript/packages/legacy/x402-fetch/README.md +++ b/typescript/packages/legacy/x402-fetch/README.md @@ -1,5 +1,9 @@ # x402-fetch +> **Deprecated (v1)** +> This npm package implements x402 **v1**. It is **deprecated** and will only receive **security patches**. Please migrate to **v2** (`@x402/fetch`, `@x402/evm`, etc.). See the [Migration guide: v1 to v2](https://docs.x402.org/guides/migration-v1-to-v2). +> Legacy examples are available at git tag `archive/legacy-v1-examples`. + A utility package that extends the native `fetch` API to automatically handle 402 Payment Required responses using the x402 payment protocol. This package enables seamless integration of payment functionality into your applications when making HTTP requests. ## Installation diff --git a/typescript/packages/legacy/x402-fetch/package.json b/typescript/packages/legacy/x402-fetch/package.json index 9ee5ac84a9..6720cd7912 100644 --- a/typescript/packages/legacy/x402-fetch/package.json +++ b/typescript/packages/legacy/x402-fetch/package.json @@ -17,8 +17,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@types/node": "^22.13.4", @@ -31,14 +31,14 @@ "eslint-plugin-import": "^2.31.0", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.0.5", "vite": "^6.2.6" }, "dependencies": { - "viem": "^2.21.26", + "viem": "^2.48.11", "zod": "^3.24.2", "x402": "workspace:^" }, diff --git a/typescript/packages/legacy/x402-hono/README.md b/typescript/packages/legacy/x402-hono/README.md index 44624c98d6..f3980ed9b8 100644 --- a/typescript/packages/legacy/x402-hono/README.md +++ b/typescript/packages/legacy/x402-hono/README.md @@ -1,5 +1,9 @@ # x402-hono +> **Deprecated (v1)** +> This npm package implements x402 **v1**. It is **deprecated** and will only receive **security patches**. Please migrate to **v2** (`@x402/hono`, `@x402/core`, `@x402/evm`, etc.). See the [Migration guide: v1 to v2](https://docs.x402.org/guides/migration-v1-to-v2). +> Legacy examples are available at git tag `archive/legacy-v1-examples`. + Hono middleware integration for the x402 Payment Protocol. This package allows you to easily add paywall functionality to your Hono applications using the x402 protocol. ## Installation diff --git a/typescript/packages/legacy/x402-hono/package.json b/typescript/packages/legacy/x402-hono/package.json index b69cd019b6..6f68ebc228 100644 --- a/typescript/packages/legacy/x402-hono/package.json +++ b/typescript/packages/legacy/x402-hono/package.json @@ -17,8 +17,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@eslint/js": "^9.24.0", @@ -31,7 +31,7 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", @@ -41,7 +41,7 @@ "@coinbase/cdp-sdk": "^1.22.0", "@solana/kit": "^5.0.0", "hono": "^4.7.1", - "viem": "^2.21.26", + "viem": "^2.48.11", "x402": "workspace:^", "zod": "^3.24.2" }, diff --git a/typescript/packages/legacy/x402-next/README.md b/typescript/packages/legacy/x402-next/README.md index 021ceddb2a..a9d5089d53 100644 --- a/typescript/packages/legacy/x402-next/README.md +++ b/typescript/packages/legacy/x402-next/README.md @@ -1,5 +1,9 @@ # x402-next +> **Deprecated (v1)** +> This npm package implements x402 **v1**. It is **deprecated** and will only receive **security patches**. Please migrate to **v2** (`@x402/next`, `@x402/core`, `@x402/evm`, etc.). See the [Migration guide: v1 to v2](https://docs.x402.org/guides/migration-v1-to-v2). +> Legacy examples are available at git tag `archive/legacy-v1-examples`. + Next.js middleware integration for the x402 Payment Protocol. This package allows you to easily add paywall functionality to your Next.js applications using the x402 protocol. ## Installation diff --git a/typescript/packages/legacy/x402-next/package.json b/typescript/packages/legacy/x402-next/package.json index c2ebebfdcd..60840119b2 100644 --- a/typescript/packages/legacy/x402-next/package.json +++ b/typescript/packages/legacy/x402-next/package.json @@ -17,8 +17,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@eslint/js": "^9.24.0", @@ -31,7 +31,7 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", @@ -40,7 +40,7 @@ "dependencies": { "@coinbase/cdp-sdk": "^1.22.0", "@solana/kit": "^5.0.0", - "viem": "^2.21.26", + "viem": "^2.48.11", "x402": "workspace:^", "zod": "^3.24.2" }, diff --git a/typescript/packages/legacy/x402/README.md b/typescript/packages/legacy/x402/README.md index 4008e4e287..e61b13b65b 100644 --- a/typescript/packages/legacy/x402/README.md +++ b/typescript/packages/legacy/x402/README.md @@ -1,5 +1,9 @@ # x402 +> **Deprecated (v1)** +> This npm package implements x402 **v1**. It is **deprecated** and will only receive **security patches**. Please migrate to **v2** (`@x402/core` and related packages). See the [Migration guide: v1 to v2](https://docs.x402.org/guides/migration-v1-to-v2). +> Legacy examples are available at git tag `archive/legacy-v1-examples`. + Core TypeScript implementation of the x402 Payment Protocol. This package provides the foundational types, schemas, and utilities that power all x402 integrations. ## Installation @@ -36,7 +40,7 @@ If you're not using one of our server middleware packages, you can implement the 3. Use the facilitator to settle payments 4. Return the appropriate response header to the caller -For a complete example implementation, see our [advanced server example](https://github.com/coinbase/x402/tree/main/examples/typescript/servers/advanced) which demonstrates both synchronous and asynchronous payment processing patterns. +For a complete example implementation, see our [advanced server example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/advanced) which demonstrates both synchronous and asynchronous payment processing patterns. ## Manual Client Integration @@ -55,6 +59,6 @@ If you're not using our `x402-fetch` or `x402-axios` packages, you can manually - The `Access-Control-Expose-Headers` field set to `"X-PAYMENT-RESPONSE"` to receive the server's transaction response For implementation examples, we recommend reviewing our official client packages: -- [x402-fetch implementation](https://github.com/coinbase/x402/tree/main/typescript/packages/legacy/x402-fetch) -- [x402-axios implementation](https://github.com/coinbase/x402/tree/main/typescript/packages/legacy/x402-axios) +- [x402-fetch implementation](https://github.com/x402-foundation/x402/tree/main/typescript/packages/legacy/x402-fetch) +- [x402-axios implementation](https://github.com/x402-foundation/x402/tree/main/typescript/packages/legacy/x402-axios) diff --git a/typescript/packages/legacy/x402/package.json b/typescript/packages/legacy/x402/package.json index a180d01184..dfe3a7a3cd 100644 --- a/typescript/packages/legacy/x402/package.json +++ b/typescript/packages/legacy/x402/package.json @@ -18,8 +18,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@coinbase/onchainkit": "^0.38.14", @@ -33,7 +33,7 @@ "@wagmi/connectors": "^5.8.1", "@wagmi/core": "^2.17.1", "buffer": "^6.0.3", - "esbuild": "^0.25.4", + "esbuild": "^0.27.2", "eslint": "^9.24.0", "eslint-plugin-import": "^2.31.0", "eslint-plugin-jsdoc": "^50.6.9", @@ -42,9 +42,9 @@ "react": "19.2.1", "react-dom": "19.2.1", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", - "viem": "^2.21.26", + "viem": "^2.48.11", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.0.5" @@ -60,7 +60,7 @@ "@wallet-standard/app": "^1.1.0", "@wallet-standard/base": "^1.1.0", "@wallet-standard/features": "^1.1.0", - "viem": "^2.21.26", + "viem": "^2.48.11", "wagmi": "^2.15.6", "zod": "^3.24.2" }, diff --git a/typescript/packages/mcp/CHANGELOG.md b/typescript/packages/mcp/CHANGELOG.md index a88d1f484c..9adcbdaa36 100644 --- a/typescript/packages/mcp/CHANGELOG.md +++ b/typescript/packages/mcp/CHANGELOG.md @@ -1,5 +1,55 @@ # @x402/mcp Changelog +## 2.12.0 + +### Minor Changes + +- ee7c156: chore: tighten viem dependency floor to ^2.48.11 + + Raises the viem floor in every `@x402/*` package.json that lists viem as a direct dep so future `pnpm install` re-resolutions cannot regress below this version. Fixes the incomplete tightening from #2013. + +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] + - @x402/core@2.12.0 + +## 2.11.0 + +### Minor Changes + +- 71a223d: Added `extensions` field to `PaymentWrapperConfig` so paid MCP tools can declare Bazaar discovery metadata and appear in `/discovery/resources`. + +### Patch Changes + +- a051f48: Enables `ResourceServerExtension` to register resource-server verify/settle hooks, and enforces extension mutation policy: `enrichPaymentRequiredResponse` may only change `payTo` / `amount` / `asset` when those baseline values are vacant; `scheme` / `network` / `maxTimeoutSeconds` and baseline `extra` entries are immutable. `enrichSettlementResponse` may not rewrite facilitator core fields (`success`, `transaction`, `network`, etc.). Lifecycle hook contexts are typed as read-only for core protocol fields. +- Updated dependencies [a051f48] +- Updated dependencies [dc04108] + - @x402/core@2.11.0 + +## 2.10.0 + +### Minor Changes + +- 9424291: chore: bump viem lockfile to 2.47.12 + + Updates the resolved viem version across all direct dependencies, adding chain definitions for Mezo Testnet, MegaETH, Stable, and Stable Testnet that were missing from previously locked versions. + + - @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization + +### Patch Changes + +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/mcp/README.md b/typescript/packages/mcp/README.md index 0f7eb4ef24..18dd768aeb 100644 --- a/typescript/packages/mcp/README.md +++ b/typescript/packages/mcp/README.md @@ -1,4 +1,4 @@ -# @x402/mcp +# `@x402/mcp` • [![npm version](https://img.shields.io/npm/v/%40x402%2Fmcp.svg)](https://www.npmjs.com/package/@x402/mcp) MCP (Model Context Protocol) integration for the x402 payment protocol. This package enables paid tool calls in MCP servers and automatic payment handling in MCP clients. diff --git a/typescript/packages/mcp/package.json b/typescript/packages/mcp/package.json index b7838335bf..c9276e5fcd 100644 --- a/typescript/packages/mcp/package.json +++ b/typescript/packages/mcp/package.json @@ -1,6 +1,6 @@ { "name": "@x402/mcp", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/cjs/index.d.ts", @@ -18,8 +18,8 @@ }, "keywords": [], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol", "devDependencies": { "@eslint/js": "^9.24.0", @@ -34,9 +34,9 @@ "express": "^4.21.2", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", - "viem": "^2.27.2", + "viem": "^2.48.11", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.0.5", "vite": "^6.2.6" diff --git a/typescript/packages/mcp/src/server/paymentWrapper.ts b/typescript/packages/mcp/src/server/paymentWrapper.ts index ffd72d6fff..2070efe525 100644 --- a/typescript/packages/mcp/src/server/paymentWrapper.ts +++ b/typescript/packages/mcp/src/server/paymentWrapper.ts @@ -58,6 +58,27 @@ export interface PaymentWrapperConfig { /** Called after successful settlement */ onAfterSettlement?: AfterSettlementHook; }; + + /** + * x402 extensions to include in the PaymentRequired response. + * Use this to attach Bazaar discovery metadata so facilitators can index the tool. + * + * @example + * ```typescript + * import { declareDiscoveryExtension } from "@x402/extensions/bazaar"; + * + * resource: { url: "mcp://tool/get_weather" }, + * extensions: declareDiscoveryExtension({ + * toolName: "get_weather", + * description: "Get current weather for a city", + * inputSchema: { + * properties: { city: { type: "string" } }, + * required: ["city"], + * }, + * }) + * ``` + */ + extensions?: Record; } /** @@ -184,9 +205,20 @@ export function createPaymentWrapper( ); } - // Match the client's chosen payment method against config.accepts - const paymentRequirements = resourceServer.findMatchingRequirements( + const resourceInfoForMatch = { + url: createToolResourceUrl(toolName, config.resource?.url), + description: config.resource?.description || `Tool: ${toolName}`, + mimeType: config.resource?.mimeType || "application/json", + }; + // Match on post-enrichment accepts (same as HTTP): extensions may change payTo etc. + const paymentRequiredForMatch = await resourceServer.createPaymentRequiredResponse( config.accepts, + resourceInfoForMatch, + undefined, + config.extensions, + ); + const paymentRequirements = resourceServer.findMatchingRequirements( + paymentRequiredForMatch.accepts, paymentPayload, ); @@ -199,8 +231,12 @@ export function createPaymentWrapper( ); } - // Verify payment - const verifyResult = await resourceServer.verifyPayment(paymentPayload, paymentRequirements); + const extMap = config.extensions ?? {}; + const verifyResult = await resourceServer.verifyPayment( + paymentPayload, + paymentRequirements, + extMap, + ); if (!verifyResult.isValid) { return createPaymentRequiredResult( @@ -256,6 +292,7 @@ export function createPaymentWrapper( const settleResult = await resourceServer.settlePayment( paymentPayload, paymentRequirements, + extMap, ); // Run onAfterSettlement hook if present @@ -310,6 +347,7 @@ async function createPaymentRequiredResult( config.accepts, resourceInfo, errorMessage, + config.extensions, ); return { diff --git a/typescript/packages/mcp/test/integration/mcp-sse-evm.test.ts b/typescript/packages/mcp/test/integration/mcp-sse-evm.test.ts index 4b2cd5a12a..0fdea08463 100644 --- a/typescript/packages/mcp/test/integration/mcp-sse-evm.test.ts +++ b/typescript/packages/mcp/test/integration/mcp-sse-evm.test.ts @@ -385,7 +385,38 @@ describe.skipIf(SKIP_TESTS)("Real SSE MCP Integration Tests", () => { }, 60000); // 60s timeout for blockchain transaction // ========================================================================== - // Test 6: Multiple paid tool calls work + // Test 6: 402 response includes bazaar extensions + // ========================================================================== + it("should include bazaar extensions in 402 response", async () => { + // Use a client with autoPayment disabled to see the 402 + const manualClient = new x402MCPClient( + x402ClientInstance.client, + x402ClientInstance.paymentClient, + { autoPayment: false }, + ); + + try { + await manualClient.callTool("get_weather", { city: "Chicago" }); + expect.fail("Should have thrown 402 error"); + } catch (error) { + const err = error as { + code?: number; + paymentRequired?: { extensions?: Record }; + }; + expect(err.code).toBe(402); + expect(err.paymentRequired).toBeDefined(); + // Verify bazaar extension is present — hard-fail if absent + expect(err.paymentRequired?.extensions?.bazaar).toBeDefined(); + const bazaar = err.paymentRequired!.extensions!.bazaar as Record; + const info = bazaar.info as Record; + expect(info).toBeDefined(); + const input = info.input as Record; + expect(input.toolName).toBe("get_weather"); + } + }); + + // ========================================================================== + // Test 7: Multiple paid tool calls work // ========================================================================== it("should handle multiple paid tool calls", async () => { console.log("\n🔄 Starting second paid tool call...\n"); diff --git a/typescript/packages/mcp/test/unit/server.test.ts b/typescript/packages/mcp/test/unit/server.test.ts index ae36faeec1..8fd479b7d9 100644 --- a/typescript/packages/mcp/test/unit/server.test.ts +++ b/typescript/packages/mcp/test/unit/server.test.ts @@ -143,6 +143,7 @@ describe("createPaymentWrapper", () => { expect(mockResourceServer.verifyPayment).toHaveBeenCalledWith( mockPaymentPayload, mockPaymentRequirements, + {}, ); expect(handler).toHaveBeenCalled(); expect(result.content).toEqual([{ type: "text", text: "success" }]); @@ -167,6 +168,7 @@ describe("createPaymentWrapper", () => { expect(mockResourceServer.settlePayment).toHaveBeenCalledWith( mockPaymentPayload, mockPaymentRequirements, + {}, ); }); @@ -454,6 +456,78 @@ describe("createPaymentWrapper", () => { expect(mockResourceServer.verifyPayment).toHaveBeenCalledWith( mockPaymentPayload, mockPaymentRequirements, + {}, + ); + }); + }); + + describe("extensions", () => { + it("should include extensions in 402 response when configured", async () => { + const extensions = { + bazaar: { + info: { + input: { + type: "mcp", + toolName: "test", + }, + }, + }, + }; + + const mockPaymentRequiredWithExtensions = { + ...mockPaymentRequired, + extensions, + }; + + mockResourceServer.createPaymentRequiredResponse.mockResolvedValueOnce( + mockPaymentRequiredWithExtensions, + ); + + const paid = createPaymentWrapper( + mockResourceServer as unknown as Parameters[0], + { + accepts: [mockPaymentRequirements], + extensions, + }, + ); + + const handler = vi.fn().mockResolvedValue({ + content: [{ type: "text", text: "success" }], + }); + + const wrappedHandler = paid(handler); + const result = await wrappedHandler({ test: "arg" }, {}); + + expect(result.isError).toBe(true); + expect(mockResourceServer.createPaymentRequiredResponse).toHaveBeenCalledWith( + [mockPaymentRequirements], + expect.any(Object), + "Payment required to access this tool", + extensions, + ); + expect((result.structuredContent as Record)?.extensions).toEqual(extensions); + }); + + it("should not include extensions when not configured", async () => { + const paid = createPaymentWrapper( + mockResourceServer as unknown as Parameters[0], + { + accepts: [mockPaymentRequirements], + }, + ); + + const handler = vi.fn().mockResolvedValue({ + content: [{ type: "text", text: "success" }], + }); + + const wrappedHandler = paid(handler); + await wrappedHandler({ test: "arg" }, {}); + + expect(mockResourceServer.createPaymentRequiredResponse).toHaveBeenCalledWith( + [mockPaymentRequirements], + expect.any(Object), + "Payment required to access this tool", + undefined, ); }); }); diff --git a/typescript/packages/mechanisms/aptos/CHANGELOG.md b/typescript/packages/mechanisms/aptos/CHANGELOG.md index 49b766e9a2..5759dc7df6 100644 --- a/typescript/packages/mechanisms/aptos/CHANGELOG.md +++ b/typescript/packages/mechanisms/aptos/CHANGELOG.md @@ -1,5 +1,42 @@ # @x402/aptos +## 2.12.0 + +### Minor Changes + +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] + - @x402/core@2.12.0 + +## 2.11.0 + +### Minor Changes + +- Updated dependencies [a051f48] +- Updated dependencies [dc04108] + - @x402/core@2.11.0 + +## 2.10.0 + +### Minor Changes + +- @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization + +### Patch Changes + +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/mechanisms/aptos/README.md b/typescript/packages/mechanisms/aptos/README.md index c8ed626954..dfb9eb5bc8 100644 --- a/typescript/packages/mechanisms/aptos/README.md +++ b/typescript/packages/mechanisms/aptos/README.md @@ -1,4 +1,4 @@ -# @x402/aptos +# `@x402/aptos` [![npm version](https://img.shields.io/npm/v/%40x402%2Faptos.svg)](https://www.npmjs.com/package/@x402/aptos) Aptos implementation of the x402 payment protocol. diff --git a/typescript/packages/mechanisms/aptos/package.json b/typescript/packages/mechanisms/aptos/package.json index 7147b4d1ec..981f85585c 100644 --- a/typescript/packages/mechanisms/aptos/package.json +++ b/typescript/packages/mechanisms/aptos/package.json @@ -1,6 +1,6 @@ { "name": "@x402/aptos", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/cjs/index.d.ts", @@ -24,7 +24,7 @@ ], "license": "Apache-2.0", "author": "Aptos Labs", - "repository": "https://github.com/coinbase/x402", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol Aptos Implementation", "devDependencies": { "@eslint/js": "^9.24.0", @@ -37,14 +37,14 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", "vitest": "^3.0.5" }, "dependencies": { - "@x402/core": "workspace:*", + "@x402/core": "workspace:~", "@aptos-labs/ts-sdk": "^5.2.1" }, "exports": { diff --git a/examples/typescript/legacy/clients/fetch/.prettierignore b/typescript/packages/mechanisms/avm/.prettierignore similarity index 79% rename from examples/typescript/legacy/clients/fetch/.prettierignore rename to typescript/packages/mechanisms/avm/.prettierignore index 5bd240ba90..9fd1bade5d 100644 --- a/examples/typescript/legacy/clients/fetch/.prettierignore +++ b/typescript/packages/mechanisms/avm/.prettierignore @@ -3,6 +3,5 @@ dist/ node_modules/ coverage/ .github/ -src/client **/**/*.json -*.md \ No newline at end of file +*.md diff --git a/examples/typescript/legacy/clients/fetch/.prettierrc b/typescript/packages/mechanisms/avm/.prettierrc similarity index 100% rename from examples/typescript/legacy/clients/fetch/.prettierrc rename to typescript/packages/mechanisms/avm/.prettierrc diff --git a/typescript/packages/mechanisms/avm/CHANGELOG.md b/typescript/packages/mechanisms/avm/CHANGELOG.md new file mode 100644 index 0000000000..b43e2315ea --- /dev/null +++ b/typescript/packages/mechanisms/avm/CHANGELOG.md @@ -0,0 +1,29 @@ +# @x402/avm + +## 2.12.0 + +### Minor Changes + +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] + - @x402/core@2.12.0 + +## 2.11.0 + +### Minor Changes + +- dc04108: Fixed a bug affecting USD prices with 7+ decimal places of precision (e.g. `$0.0000001` or smaller). +- Updated dependencies [a051f48] +- Updated dependencies [dc04108] + - @x402/core@2.11.0 + +## 2.10.1 + +### Patch Changes + +- Fix `@x402/core` workspace resolution. + +## 2.10.0 + +- Implement x402 v2 protocol support for the Algorand mechanism (exact scheme). diff --git a/typescript/packages/mechanisms/avm/README.md b/typescript/packages/mechanisms/avm/README.md new file mode 100644 index 0000000000..894eeaf423 --- /dev/null +++ b/typescript/packages/mechanisms/avm/README.md @@ -0,0 +1,231 @@ +# @x402/avm [![npm version](https://img.shields.io/npm/v/%40x402%2Favm.svg)](https://www.npmjs.com/package/@x402/avm) + +AVM (Algorand Virtual Machine) implementation of the x402 payment protocol using the **Exact** payment scheme with ASA (Algorand Standard Asset) transfers. + +## Installation + +```bash +npm install @x402/avm +``` + +## Overview + +This package provides three main components for handling x402 payments on Algorand: + +- **Client** - For applications that need to make payments (have wallets/signers) +- **Facilitator** - For payment processors that verify and execute on-chain transactions +- **Service** - For resource servers that accept payments and build payment requirements + +## Package Exports + +### Main Package (`@x402/avm`) + +**V2 Protocol Support** - Modern x402 protocol with CAIP-2 network identifiers + +**Client:** +- `ExactAvmClient` - V2 client implementation using ASA transfers +- `ClientAvmSigner` - TypeScript interface for client signers (implement with `@algorandfoundation/algokit-utils`) + +**Facilitator:** +- `ExactAvmFacilitator` - V2 facilitator for payment verification and settlement +- `FacilitatorAvmSigner` - TypeScript interface for facilitator signers (implement with `@algorandfoundation/algokit-utils`) + +**Service:** +- `ExactAvmServer` - V2 service for building payment requirements + +## Usage + +```typescript +import { x402Client } from "@x402/core/client"; +import { ExactAvmClient } from "@x402/avm"; + +const client = new x402Client() + .register("algorand:*", new ExactAvmClient(signer)); +``` + +## Supported Networks + +Networks are identified via CAIP-2: +- `algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8=` - Mainnet +- `algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=` - Testnet +- `algorand:*` - Wildcard (matches all Algorand networks) + +## Signer Implementation + +Use the built-in helper functions to create signers from a Base64-encoded private key. These use `generateAddressWithSigners` from `@algorandfoundation/algokit-utils` internally for canonical Ed25519 signing. + +### Client Signer + +```typescript +import { toClientAvmSigner } from "@x402/avm"; + +const signer = toClientAvmSigner(process.env.AVM_PRIVATE_KEY!); +// signer.address — the Algorand address +// signer.signTransactions(txns, indexesToSign) — signs transactions +``` + +### Facilitator Signer + +```typescript +import { toFacilitatorAvmSigner } from "@x402/avm"; + +// Default (uses AlgorandClient.testNet() / .mainNet() from algokit-utils): +const signer = toFacilitatorAvmSigner(process.env.AVM_PRIVATE_KEY!); + +// With custom Algod URLs: +const signer = toFacilitatorAvmSigner(process.env.AVM_PRIVATE_KEY!, { + testnetUrl: "https://my-testnet-node.example.com", + mainnetUrl: "https://my-mainnet-node.example.com", +}); +``` + +See [facilitator example](../../examples/typescript/facilitator/) for a full implementation. + +## Environment Variables + +### Client Applications + +Applications that make payments using an Algorand wallet. + +| Variable | Required | Description | +|----------|----------|-------------| +| `AVM_PRIVATE_KEY` | Yes | Base64-encoded 64-byte Algorand private key (32-byte seed + 32-byte public key). Used to sign payment transactions. | + +### Server (Resource Provider) + +Servers that accept payments and build payment requirements. + +| Variable | Required | Description | +|----------|----------|-------------| +| `AVM_ADDRESS` | Yes | Algorand wallet address to receive payments (58-character base32 address). | + +### Facilitator + +Payment processors that verify and settle transactions on-chain. + +| Variable | Required | Description | +|----------|----------|-------------| +| `AVM_PRIVATE_KEY` | Yes | Base64-encoded 64-byte Algorand private key. Used to submit settlement transactions and pay fees. | + +### Key Format + +The `AVM_PRIVATE_KEY` is a Base64-encoded string containing a 64-byte Algorand private key: +- First 32 bytes: Ed25519 seed (signing key) +- Last 32 bytes: Ed25519 public key + +To derive the Algorand address from the private key: + +```typescript +import { toClientAvmSigner } from "@x402/avm"; +const signer = toClientAvmSigner(process.env.AVM_PRIVATE_KEY!); +console.log(signer.address); // Algorand address +``` + +### Network Connectivity + +The SDK uses `AlgorandClient` from `@algorandfoundation/algokit-utils` for all network connectivity. By default it connects to [AlgoNode](https://algonode.io/) public endpoints (free, no authentication required). Custom endpoints can be configured via `FacilitatorAvmSignerConfig` or by passing an `AlgorandClient` instance via `ClientAvmConfig.algorandClient`. + +## Prerequisites: Account Funding & Asset Opt-In + +Algorand requires accounts to meet a **Minimum Balance Requirement (MBR)** and explicitly **opt in** to assets before receiving them. This applies to all roles: client, server (payTo), and facilitator. + +### 1. Fund Accounts with ALGO + +Every Algorand account needs a minimum ALGO balance: +- **Base MBR**: 0.1 ALGO per account +- **Per asset opt-in**: +0.1 ALGO per ASA opted into +- **Facilitator**: needs additional ALGO to cover transaction fees for gasless payments + +| Testnet Faucet | URL | +|----------------|-----| +| **ALGO** | https://lora.algokit.io/testnet/fund | +| **USDC** (Circle) | https://faucet.circle.com/ | + +### 2. Opt In to USDC ASA + +Both the **client** (payer) and **server/payTo** (receiver) accounts must opt in to USDC before any payment can be made. An opt-in is a 0-amount asset transfer to yourself. + +| Network | USDC ASA ID | +|---------|-------------| +| Testnet | `10458941` | +| Mainnet | `31566704` | + +### 3. Quick Setup (Testnet) + +```bash +# 1. Generate a key (or use an existing one) +# AVM_PRIVATE_KEY is a Base64-encoded 64-byte key (seed + pubkey) + +# 2. Fund accounts with ALGO +# Visit https://lora.algokit.io/testnet/fund + +# 3. Fund accounts with testnet USDC +# Visit https://faucet.circle.com/ (select Algorand Testnet) + +# 4. Set environment variables +export AVM_PRIVATE_KEY="" +``` + +> **Note:** The facilitator account must also be funded with ALGO to cover transaction fees. For gasless payments, the facilitator pays fees on behalf of the client, so ensure the facilitator has sufficient ALGO balance. + +## Asset Support + +Supports Algorand Standard Assets (ASA): +- USDC (primary) +- Any ASA with proper opt-in + +## Transaction Structure + +The exact payment scheme uses atomic transaction groups with: +- Payment transaction (ASA transfer or ALGO payment) +- Optional fee payer transaction (gasless transactions) +- Transaction simulation for validation + +### Transaction Fees + +Algorand transaction fees are dynamic, calculated as: + +``` +fee = max(current_fee_per_byte × transaction_size, min_fee) +``` + +Under normal (non-congested) network conditions, `current_fee_per_byte` is 0, so `fee = min_fee = 1000 µAlgo (0.001 ALGO)`. During network congestion, fees can rise above the minimum. + +The client fetches `suggestedParams` from the Algorand node to determine the current fee rate. For gasless payments with a fee payer, the exact fee is calculated from the actual encoded byte sizes of all transactions in the group, ensuring correct coverage under both normal and congested conditions via Algorand's native fee pooling. + +The facilitator enforces a maximum reasonable fee of **5000 µAlgo per transaction** in the group (5x the normal minimum). For example, a 2-transaction group has a max fee cap of 10,000 µAlgo. This prevents fee extraction attacks while accommodating reasonable congestion surcharges. + +## Error Codes + +The facilitator returns machine-readable error codes in `invalidReason` (verify) and `errorReason` (settle), using the `invalid_exact_avm_*` prefix convention. Human-readable details are in `invalidMessage` / `errorMessage`. + +**Verify errors:** `invalid_exact_avm_invalid_version`, `invalid_exact_avm_scheme`, `invalid_exact_avm_network_mismatch`, `invalid_exact_avm_payload`, `invalid_exact_avm_group_size_exceeded`, `invalid_exact_avm_payment_index`, `invalid_exact_avm_invalid_transaction`, `invalid_exact_avm_invalid_group_id`, `invalid_exact_avm_not_asset_transfer`, `invalid_exact_avm_amount_mismatch`, `invalid_exact_avm_receiver_mismatch`, `invalid_exact_avm_asset_mismatch`, `invalid_exact_avm_invalid_fee_payer`, `invalid_exact_avm_fee_too_high`, `invalid_exact_avm_payment_not_signed`, `invalid_exact_avm_invalid_signature`, `invalid_exact_avm_simulation_failed`, `invalid_exact_avm_facilitator_transferring`, `invalid_exact_avm_unsigned_non_facilitator` + +**Settle errors:** `invalid_exact_avm_settlement_failed`, `invalid_exact_avm_confirmation_failed` + +See the [AVM exact scheme spec](../../../specs/schemes/exact/scheme_exact_algo.md) for detailed descriptions. + +## Development + +```bash +# Build +pnpm build + +# Test +pnpm test + +# Integration tests +pnpm test:integration + +# Lint & Format +pnpm lint +pnpm format +``` + +## Related Packages + +- `@x402/core` - Core protocol types and client +- `@x402/fetch` - HTTP wrapper with automatic payment handling +- `@x402/evm` - EVM/Ethereum implementation +- `@x402/svm` - Solana/SVM implementation +- `@algorandfoundation/algokit-utils` - Algorand utility library (dependency) diff --git a/examples/typescript/legacy/mcp-embedded-wallet/eslint.config.js b/typescript/packages/mechanisms/avm/eslint.config.js similarity index 80% rename from examples/typescript/legacy/mcp-embedded-wallet/eslint.config.js rename to typescript/packages/mechanisms/avm/eslint.config.js index f0f301b2ca..f480c05580 100644 --- a/examples/typescript/legacy/mcp-embedded-wallet/eslint.config.js +++ b/typescript/packages/mechanisms/avm/eslint.config.js @@ -11,6 +11,7 @@ export default [ }, { files: ["**/*.ts", "**/*.tsx"], + ignores: ["**/*.test.ts", "test/**/*"], languageOptions: { parser: tsParser, sourceType: "module", @@ -21,14 +22,11 @@ export default [ module: "readonly", require: "readonly", Buffer: "readonly", - console: "readonly", exports: "readonly", setTimeout: "readonly", clearTimeout: "readonly", setInterval: "readonly", clearInterval: "readonly", - window: "readonly", - document: "readonly", }, }, plugins: { @@ -72,4 +70,22 @@ export default [ "jsdoc/require-hyphen-before-param-description": ["error", "always"], }, }, + { + files: ["**/*.test.ts", "test/**/*"], + languageOptions: { + parser: tsParser, + sourceType: "module", + ecmaVersion: 2020, + }, + plugins: { + "@typescript-eslint": ts, + prettier: prettier, + }, + rules: { + "prettier/prettier": "error", + "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/member-ordering": "off", + }, + }, ]; diff --git a/typescript/packages/mechanisms/avm/package.json b/typescript/packages/mechanisms/avm/package.json new file mode 100644 index 0000000000..8f7a857267 --- /dev/null +++ b/typescript/packages/mechanisms/avm/package.json @@ -0,0 +1,96 @@ +{ + "name": "@x402/avm", + "version": "2.12.0", + "main": "./dist/cjs/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/cjs/index.d.ts", + "scripts": { + "start": "tsx --env-file=.env index.ts", + "build": "tsup", + "test": "vitest run", + "test:integration": "vitest run --config vitest.integration.config.ts", + "test:watch": "vitest", + "watch": "tsc --watch", + "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", + "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", + "lint": "eslint . --ext .ts --fix", + "lint:check": "eslint . --ext .ts" + }, + "keywords": [ + "x402", + "payment", + "protocol", + "avm", + "algorand" + ], + "license": "Apache-2.0", + "author": "GoPlausible", + "repository": "https://github.com/x402-foundation/x402", + "description": "x402 Payment Protocol AVM (Algorand) Implementation", + "devDependencies": { + "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", + "@typescript-eslint/eslint-plugin": "^8.29.1", + "@typescript-eslint/parser": "^8.29.1", + "eslint": "^9.24.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsdoc": "^50.6.9", + "eslint-plugin-prettier": "^5.2.6", + "prettier": "3.5.2", + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3", + "vite": "^6.2.6", + "vite-tsconfig-paths": "^5.1.4", + "vitest": "^3.0.5" + }, + "dependencies": { + "@algorandfoundation/algokit-utils": "10.0.0-alpha.46", + "@x402/core": "workspace:~" + }, + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.mts", + "default": "./dist/esm/index.mjs" + }, + "require": { + "types": "./dist/cjs/index.d.ts", + "default": "./dist/cjs/index.js" + } + }, + "./exact/client": { + "import": { + "types": "./dist/esm/exact/client/index.d.mts", + "default": "./dist/esm/exact/client/index.mjs" + }, + "require": { + "types": "./dist/cjs/exact/client/index.d.ts", + "default": "./dist/cjs/exact/client/index.js" + } + }, + "./exact/server": { + "import": { + "types": "./dist/esm/exact/server/index.d.mts", + "default": "./dist/esm/exact/server/index.mjs" + }, + "require": { + "types": "./dist/cjs/exact/server/index.d.ts", + "default": "./dist/cjs/exact/server/index.js" + } + }, + "./exact/facilitator": { + "import": { + "types": "./dist/esm/exact/facilitator/index.d.mts", + "default": "./dist/esm/exact/facilitator/index.mjs" + }, + "require": { + "types": "./dist/cjs/exact/facilitator/index.d.ts", + "default": "./dist/cjs/exact/facilitator/index.js" + } + } + }, + "files": [ + "dist" + ] +} diff --git a/typescript/packages/mechanisms/avm/src/constants.ts b/typescript/packages/mechanisms/avm/src/constants.ts new file mode 100644 index 0000000000..8dc4594723 --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/constants.ts @@ -0,0 +1,116 @@ +/** + * Algorand Network Constants for x402 AVM Implementation + * + * CAIP-2 Network Identifiers use the format: algorand: + * Genesis hashes uniquely identify Algorand networks. + */ + +// ============================================================================ +// CAIP-2 Network Identifiers (V2) +// ============================================================================ + +/** + * CAIP-2 network identifier for Algorand Mainnet + * Format: algorand: + */ +export const ALGORAND_MAINNET_CAIP2 = "algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="; + +/** + * CAIP-2 network identifier for Algorand Testnet + * Format: algorand: + */ +export const ALGORAND_TESTNET_CAIP2 = "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="; + +/** + * All supported CAIP-2 network identifiers + */ +export const CAIP2_NETWORKS = [ALGORAND_MAINNET_CAIP2, ALGORAND_TESTNET_CAIP2] as const; + +// ============================================================================ +// Genesis Hashes +// ============================================================================ + +/** + * Algorand Mainnet genesis hash (base64 encoded) + */ +export const ALGORAND_MAINNET_GENESIS_HASH = "wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="; + +/** + * Algorand Testnet genesis hash (base64 encoded) + */ +export const ALGORAND_TESTNET_GENESIS_HASH = "SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="; + +// ============================================================================ +// USDC ASA (Algorand Standard Asset) Configuration +// ============================================================================ + +/** + * USDC ASA ID on Algorand Mainnet + * + * @see https://algoexplorer.io/asset/31566704 + */ +export const USDC_MAINNET_ASA_ID = "31566704"; + +/** + * USDC ASA ID on Algorand Testnet + * + * @see https://testnet.algoexplorer.io/asset/10458941 + */ +export const USDC_TESTNET_ASA_ID = "10458941"; + +/** + * USDC decimals (same across all networks) + */ +export const USDC_DECIMALS = 6; + +/** + * USDC configuration per network + */ +export const USDC_CONFIG: Record = { + [ALGORAND_MAINNET_CAIP2]: { + asaId: USDC_MAINNET_ASA_ID, + name: "USDC", + decimals: USDC_DECIMALS, + }, + [ALGORAND_TESTNET_CAIP2]: { + asaId: USDC_TESTNET_ASA_ID, + name: "USDC", + decimals: USDC_DECIMALS, + }, +}; + +// ============================================================================ +// Transaction Limits +// ============================================================================ + +/** + * Maximum reasonable fee per transaction in microAlgos (5000 µAlgo). + * + * Algorand transaction fees are calculated as: + * fee = max(current_fee_per_byte * transaction_size_in_bytes, min_fee) + * + * Under normal (non-congested) conditions, current_fee_per_byte is 0, + * so fee = min_fee = 1000 µAlgo (0.001 ALGO). + * + * During network congestion, fees can rise. This constant is set to 5x + * the minimum fee (5000 µAlgo) as a reasonable upper bound per transaction. + * + * For fee payer transactions that cover an entire group via fee pooling, + * use `maxReasonableGroupFee(groupSize)` which multiplies this per-txn + * cap by the number of transactions in the group. + */ +export const MAX_REASONABLE_FEE_PER_TXN = 5000; + +/** + * Calculates the maximum reasonable fee for a fee payer transaction + * that covers an entire atomic group via fee pooling. + * + * @param groupSize - Number of transactions in the atomic group + * @returns Maximum acceptable fee in microAlgos + */ +export function maxReasonableGroupFee(groupSize: number): number { + return MAX_REASONABLE_FEE_PER_TXN * groupSize; +} + +// Address validation: use isValidAddress() from @algorandfoundation/algokit-utils/common +// Address length: use ALGORAND_ADDRESS_LENGTH from @algorandfoundation/algokit-utils/common diff --git a/typescript/packages/mechanisms/avm/src/exact/client/index.ts b/typescript/packages/mechanisms/avm/src/exact/client/index.ts new file mode 100644 index 0000000000..4693cbfe33 --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/exact/client/index.ts @@ -0,0 +1 @@ +export { ExactAvmScheme } from "./scheme"; diff --git a/typescript/packages/mechanisms/avm/src/exact/client/scheme.ts b/typescript/packages/mechanisms/avm/src/exact/client/scheme.ts new file mode 100644 index 0000000000..65316f6b84 --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/exact/client/scheme.ts @@ -0,0 +1,218 @@ +/** + * AVM Client Scheme for Exact Payment Protocol + * + * Creates atomic transaction groups for Algorand ASA transfers. + * Uses AlgorandClient and TransactionComposer from algokit-utils v10 + * for transaction construction, fee pooling, and group management. + */ + +import { AlgorandClient } from "@algorandfoundation/algokit-utils/algorand-client"; +import { + Transaction, + encodeTransactionRaw, + groupTransactions, + makeEmptyTransactionSigner, +} from "@algorandfoundation/algokit-utils/transact"; +import { microAlgo } from "@algorandfoundation/algokit-utils/amount"; +import type { + PaymentRequirements, + SchemeNetworkClient, + PaymentPayloadResult, +} from "@x402/core/types"; +import type { ClientAvmSigner, ClientAvmConfig } from "../../signer"; +import type { ExactAvmPayloadV2 } from "../../types"; +import { encodeTransaction } from "../../utils"; +import { USDC_CONFIG } from "../../constants"; +import { isTestnetNetwork } from "../../utils"; + +/** + * AVM client implementation for the Exact payment scheme. + * + * Creates atomic transaction groups with ASA transfers for x402 payments. + * Supports optional fee payer transactions for gasless payments. + */ +export class ExactAvmScheme implements SchemeNetworkClient { + readonly scheme = "exact"; + + /** + * Creates a new ExactAvmScheme instance. + * + * @param signer - The AVM signer for client operations + * @param config - Optional configuration for Algod client + */ + constructor( + private readonly signer: ClientAvmSigner, + private readonly config?: ClientAvmConfig, + ) {} + + /** + * Creates a payment payload for the Exact scheme. + * + * Constructs an atomic transaction group with: + * - Optional fee payer transaction (if feePayer specified in requirements.extra) + * - ASA transfer transaction to payTo address + * + * Uses TransactionComposer for automatic suggested params, group ID assignment, + * and fee pooling. For sponsored (gasless) transactions, exact fees are calculated + * from actual encoded transaction sizes using the protocol fee formula: + * fee = max(fee_per_byte × txn_size_in_bytes, min_fee) + * + * @param x402Version - The x402 protocol version + * @param paymentRequirements - The payment requirements + * @returns Promise resolving to a payment payload result + */ + async createPaymentPayload( + x402Version: number, + paymentRequirements: PaymentRequirements, + ): Promise { + const { amount, asset, payTo, network, extra } = paymentRequirements; + + const algorandClient = this.getAlgorandClient(network); + + // Get asset ID (from requirements or default USDC) + const assetId = this.getAssetId(asset, network); + + // Get fee payer address from extra if provided + const feePayer = extra?.feePayer as string | undefined; + let paymentIndex = 0; + + // Use an empty signer for building — we sign manually after + // (fee payer txns stay unsigned for the facilitator to sign) + const emptySigner = makeEmptyTransactionSigner(); + + // Build the transaction group using TransactionComposer + const composer = algorandClient.newGroup(); + + if (feePayer) { + // First pass: add fee payer with a placeholder fee. + // The actual fee will be recalculated after build() using exact transaction sizes. + composer.addPayment({ + sender: feePayer, + receiver: feePayer, + amount: microAlgo(0), + note: `x402-fee-payer-${Date.now()}`, + signer: emptySigner, + }); + paymentIndex = 1; + } + + composer.addAssetTransfer({ + sender: this.signer.address, + receiver: payTo, + assetId: BigInt(assetId), + amount: BigInt(amount), + staticFee: feePayer ? microAlgo(0) : undefined, // 0 fee when fee payer covers + note: `x402-payment-v${x402Version}-${Date.now()}`, + signer: emptySigner, + }); + + // Build transactions (assigns group ID, suggested params, fees) + const built = await composer.build(); + let transactions = built.transactions.map(tws => tws.txn); + + // For sponsored transactions: recalculate the fee payer's fee using + // exact encoded sizes of all transactions in the group. + // Algorand fee formula: fee = max(fee_per_byte × txn_size, min_fee) + // + // After changing fees, the group ID must be recomputed because it is + // derived from each transaction's encoded bytes (which include the fee). + if (feePayer) { + const sp = await algorandClient.getSuggestedParams(); + const feePerByte = Number(sp.fee); + const minFee = Number(sp.minFee); + + // Calculate exact fee for each transaction based on its actual encoded size + let totalGroupFee = BigInt(0); + for (const txn of transactions) { + const txnSize = encodeTransactionRaw(txn).length; + const txnFee = feePerByte > 0 ? Math.max(feePerByte * txnSize, minFee) : minFee; + totalGroupFee += BigInt(txnFee); + } + + // Strip group ID, set correct fees, then re-group. + // groupTransactions() requires group to be absent, computes the new group hash, + // and returns new Transaction objects with the correct group ID. + const ungrouped = transactions.map((txn, i) => { + const fee = i === 0 ? totalGroupFee : BigInt(0); + return new Transaction({ ...txn, fee, group: undefined }); + }); + transactions = groupTransactions(ungrouped); + } + + // Encode all transactions to raw bytes + const encodedTxns = transactions.map(txn => encodeTransactionRaw(txn)); + + // Determine which transactions the client should sign + const clientIndexes = transactions + .map((txn, i) => (txn.sender.toString() === this.signer.address ? i : -1)) + .filter(i => i !== -1); + + // Sign client's transactions + const signedTxns = await this.signer.signTransactions(encodedTxns, clientIndexes); + + // Build payment group with signed/unsigned transactions + const paymentGroup: string[] = encodedTxns.map((txnBytes, i) => { + const signedTxn = signedTxns[i]; + if (signedTxn) { + return encodeTransaction(signedTxn); + } + // Return unsigned transaction for facilitator to sign + return encodeTransaction(txnBytes); + }); + + const payload: ExactAvmPayloadV2 = { + paymentGroup, + paymentIndex, + }; + + return { + x402Version, + payload: payload as unknown as Record, + }; + } + + /** + * Creates or retrieves an AlgorandClient for the given network. + * + * @param network - Network identifier (CAIP-2 format) + * @returns AlgorandClient instance + */ + private getAlgorandClient(network: string): AlgorandClient { + if (this.config?.algorandClient) { + return this.config.algorandClient; + } + if (this.config?.algodUrl) { + return AlgorandClient.fromConfig({ + algodConfig: { + server: this.config.algodUrl, + token: this.config.algodToken ?? "", + }, + }); + } + // Auto-detect network + return isTestnetNetwork(network) ? AlgorandClient.testNet() : AlgorandClient.mainNet(); + } + + /** + * Gets the asset ID from the requirements or defaults to USDC + * + * @param asset - Asset identifier from requirements + * @param network - Network identifier + * @returns Asset ID as string + */ + private getAssetId(asset: string, network: string): string { + // If asset is already a numeric string, use it directly + if (/^\d+$/.test(asset)) { + return asset; + } + + // Try to get from USDC config + const usdcConfig = USDC_CONFIG[network]; + if (usdcConfig) { + return usdcConfig.asaId; + } + + // Default to the asset as-is (might be an ASA ID) + return asset; + } +} diff --git a/typescript/packages/mechanisms/avm/src/exact/facilitator/errors.ts b/typescript/packages/mechanisms/avm/src/exact/facilitator/errors.ts new file mode 100644 index 0000000000..1d0a08a77b --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/exact/facilitator/errors.ts @@ -0,0 +1,45 @@ +/** + * AVM Facilitator error codes for verify and settle responses. + * + * Uses snake_case `invalid_exact_avm_*` prefix convention, + * consistent with EVM (`invalid_exact_evm_*`) and SVM patterns. + */ + +// Verify errors — scheme/network/version +export const ErrInvalidScheme = "invalid_exact_avm_scheme"; +export const ErrNetworkMismatch = "invalid_exact_avm_network_mismatch"; +export const ErrInvalidVersion = "invalid_exact_avm_invalid_version"; + +// Verify errors — payload structure +export const ErrInvalidPayload = "invalid_exact_avm_payload"; +export const ErrGroupSizeExceeded = "invalid_exact_avm_group_size_exceeded"; +export const ErrInvalidPaymentIndex = "invalid_exact_avm_payment_index"; +export const ErrInvalidTransaction = "invalid_exact_avm_invalid_transaction"; +export const ErrInvalidGroupId = "invalid_exact_avm_invalid_group_id"; + +// Verify errors — payment correctness +export const ErrNotAssetTransfer = "invalid_exact_avm_not_asset_transfer"; +export const ErrAmountMismatch = "invalid_exact_avm_amount_mismatch"; +export const ErrReceiverMismatch = "invalid_exact_avm_receiver_mismatch"; +export const ErrAssetMismatch = "invalid_exact_avm_asset_mismatch"; + +// Verify errors — fee payer +export const ErrInvalidFeePayer = "invalid_exact_avm_invalid_fee_payer"; +export const ErrFeeTooHigh = "invalid_exact_avm_fee_too_high"; + +// Verify errors — signature +export const ErrPaymentNotSigned = "invalid_exact_avm_payment_not_signed"; +export const ErrInvalidSignature = "invalid_exact_avm_invalid_signature"; + +// Verify errors — simulation +export const ErrSimulationFailed = "invalid_exact_avm_simulation_failed"; + +// Verify errors — facilitator safety +export const ErrFacilitatorTransferring = "invalid_exact_avm_facilitator_transferring"; + +// Security errors +export const ErrUnsignedNonFacilitator = "invalid_exact_avm_unsigned_non_facilitator"; + +// Settle errors +export const ErrSettleFailed = "invalid_exact_avm_settlement_failed"; +export const ErrConfirmationFailed = "invalid_exact_avm_confirmation_failed"; diff --git a/typescript/packages/mechanisms/avm/src/exact/facilitator/index.ts b/typescript/packages/mechanisms/avm/src/exact/facilitator/index.ts new file mode 100644 index 0000000000..3abed7f94c --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/exact/facilitator/index.ts @@ -0,0 +1,2 @@ +export { ExactAvmScheme } from "./scheme"; +export * as Errors from "./errors"; diff --git a/typescript/packages/mechanisms/avm/src/exact/facilitator/scheme.ts b/typescript/packages/mechanisms/avm/src/exact/facilitator/scheme.ts new file mode 100644 index 0000000000..c332de7c09 --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/exact/facilitator/scheme.ts @@ -0,0 +1,636 @@ +/** + * AVM Facilitator Scheme for Exact Payment Protocol + * + * Verifies and settles Algorand ASA transfer payments. + */ + +import { + decodeTransaction as decodeUnsignedTxn, + decodeSignedTransaction as decodeSignedTxn, + encodeTransactionRaw, + encodeSignedTransaction, + bytesForSigning, +} from "@algorandfoundation/algokit-utils/transact"; +import type { Transaction, SignedTransaction } from "@algorandfoundation/algokit-utils/transact"; +import { ed25519Verifier } from "@algorandfoundation/algokit-utils/crypto"; +import type { + Network, + PaymentPayload, + PaymentRequirements, + SchemeNetworkFacilitator, + SettleResponse, + VerifyResponse, +} from "@x402/core/types"; +import type { FacilitatorAvmSigner } from "../../signer"; +import type { ExactAvmPayloadV2 } from "../../types"; +import { isExactAvmPayload } from "../../types"; +import { MAX_TRANSACTION_GROUP_SIZE } from "@algorandfoundation/algokit-utils/common"; +import { decodeTransaction, hasSignature } from "../../utils"; +import { maxReasonableGroupFee } from "../../constants"; +import * as Errors from "./errors"; + +/** + * AVM facilitator implementation for the Exact payment scheme. + * + * Verifies atomic transaction groups and settles ASA transfers for x402 payments. + * Supports gasless transactions by signing fee payer transactions. + */ +export class ExactAvmScheme implements SchemeNetworkFacilitator { + readonly scheme = "exact"; + readonly caipFamily = "algorand:*"; + + /** + * Creates a new ExactAvmScheme facilitator instance. + * + * @param signer - The AVM signer for facilitator operations + */ + constructor(private readonly signer: FacilitatorAvmSigner) {} + + /** + * Get mechanism-specific extra data for the supported kinds endpoint. + * For AVM, returns the feePayer address for gasless transactions. + * + * @param _ - The network identifier (unused, feePayer is network-agnostic) + * @returns Extra data with feePayer address + */ + getExtra(_: string): Record | undefined { + const addresses = this.signer.getAddresses(); + if (addresses.length === 0) { + return undefined; + } + + // Random selection distributes ALGO fee costs across multiple signer accounts, + // preventing any single fee payer from being depleted faster than others. + const randomIndex = Math.floor(Math.random() * addresses.length); + return { feePayer: addresses[randomIndex] }; + } + + /** + * Get signer addresses used by this facilitator. + * Returns all addresses this facilitator can use for signing fee payer transactions. + * + * @param _ - The network identifier (unused, addresses are network-agnostic) + * @returns Array of facilitator wallet addresses + */ + getSigners(_: string): string[] { + return [...this.signer.getAddresses()]; + } + + /** + * Verifies a payment payload. + * + * Verification steps: + * 1. Validate x402Version, scheme, and network + * 2. Validate payload format and structure + * 3. Check group size does not exceed maximum (16) + * 4. Decode and validate transaction group + * 5. Verify payment transaction (amount, receiver, asset) + * 6. Prepare signed group (verify fee payer safety + sign) + * 7. Simulate transaction group + * + * @param payload - The payment payload to verify + * @param requirements - The payment requirements + * @returns Promise resolving to verification response + */ + async verify( + payload: PaymentPayload, + requirements: PaymentRequirements, + ): Promise { + try { + // Validate x402 version + if (payload.x402Version !== 2) { + return { + isValid: false, + invalidReason: Errors.ErrInvalidVersion, + invalidMessage: `Expected x402Version 2, got ${payload.x402Version}`, + }; + } + + // Validate scheme + if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") { + return { + isValid: false, + invalidReason: Errors.ErrInvalidScheme, + invalidMessage: `Expected scheme "exact", got payload="${payload.accepted.scheme}" requirements="${requirements.scheme}"`, + }; + } + + // Validate network + if (payload.accepted.network !== requirements.network) { + return { + isValid: false, + invalidReason: Errors.ErrNetworkMismatch, + invalidMessage: `Network mismatch: payload="${payload.accepted.network}" requirements="${requirements.network}"`, + }; + } + + const rawPayload = payload.payload as unknown; + + if (!isExactAvmPayload(rawPayload)) { + return { + isValid: false, + invalidReason: Errors.ErrInvalidPayload, + invalidMessage: "Payload does not match ExactAvmPayloadV2 format", + }; + } + + const { paymentGroup, paymentIndex } = rawPayload as ExactAvmPayloadV2; + + if (paymentGroup.length > MAX_TRANSACTION_GROUP_SIZE) { + return { + isValid: false, + invalidReason: Errors.ErrGroupSizeExceeded, + invalidMessage: `Transaction group has ${paymentGroup.length} transactions, maximum is ${MAX_TRANSACTION_GROUP_SIZE}`, + }; + } + + if (paymentIndex < 0 || paymentIndex >= paymentGroup.length) { + return { + isValid: false, + invalidReason: Errors.ErrInvalidPaymentIndex, + invalidMessage: `Payment index ${paymentIndex} out of bounds for group of ${paymentGroup.length}`, + }; + } + + const facilitatorAddresses = this.signer.getAddresses(); + + // Decode all transactions and validate group structure + const decoded = this.decodeTransactionGroup(paymentGroup, facilitatorAddresses); + if ("error" in decoded) return decoded.error; + + // Extract payer from payment transaction + const paymentTxn = decoded.txns[paymentIndex].txn; + const payer = paymentTxn.sender.toString(); + + // SECURITY: Verify facilitator's signers are not transferring their own funds + if (facilitatorAddresses.includes(payer)) { + return { + isValid: false, + invalidReason: Errors.ErrFacilitatorTransferring, + invalidMessage: "Facilitator signer cannot be the payment sender", + }; + } + + // Payment transaction correctness + const paymentCheck = await this.verifyPaymentTransaction( + decoded.txns[paymentIndex], + requirements, + paymentGroup[paymentIndex], + ); + if (!paymentCheck.isValid) return paymentCheck; + + // Verify fee payers and sign them for simulation + const prepared = await this.prepareSignedGroup(decoded.txns, paymentGroup); + if ("error" in prepared) return prepared.error; + + // Simulate the assembled group + const simResult = await this.simulateTransactionGroup( + prepared.signedTxns, + requirements.network, + ); + if (!simResult.isValid) return simResult; + + return { isValid: true, payer }; + } catch (error) { + return { + isValid: false, + invalidReason: Errors.ErrInvalidPayload, + invalidMessage: `Unexpected error: ${error instanceof Error ? error.message : "Unknown"}`, + }; + } + } + + /** + * Settles a payment by submitting the transaction group. + * + * Settlement steps: + * 1. Verify the payment first + * 2. Decode and sign fee payer transactions (reuses shared decode/sign logic) + * 3. Submit transaction group + * 4. Wait for on-chain confirmation + * 5. Return transaction ID + * + * @param payload - The payment payload to settle + * @param requirements - The payment requirements + * @returns Promise resolving to settlement response + */ + async settle( + payload: PaymentPayload, + requirements: PaymentRequirements, + ): Promise { + // First verify the payment + const verification = await this.verify(payload, requirements); + if (!verification.isValid) { + return { + success: false, + errorReason: verification.invalidReason, + errorMessage: verification.invalidMessage, + transaction: "", + network: requirements.network, + payer: verification.payer, + }; + } + + const avmPayload = payload.payload as unknown as ExactAvmPayloadV2; + const { paymentGroup, paymentIndex } = avmPayload; + const facilitatorAddresses = this.signer.getAddresses(); + + // Reuse shared decode logic + const decoded = this.decodeTransactionGroup(paymentGroup, facilitatorAddresses); + if ("error" in decoded) { + return { + success: false, + errorReason: Errors.ErrSettleFailed, + errorMessage: decoded.error.invalidMessage ?? decoded.error.invalidReason, + transaction: "", + network: requirements.network, + payer: verification.payer, + }; + } + + // Reuse shared sign logic + const prepared = await this.prepareSignedGroup(decoded.txns, paymentGroup); + if ("error" in prepared) { + return { + success: false, + errorReason: Errors.ErrSettleFailed, + errorMessage: prepared.error.invalidMessage ?? prepared.error.invalidReason, + transaction: "", + network: requirements.network, + payer: verification.payer, + }; + } + + // Get the payment transaction ID before submission + const paymentTxnBytes = prepared.signedTxns[paymentIndex]; + const paymentStxn = decodeSignedTxn(paymentTxnBytes); + const paymentTxId = paymentStxn.txn.txId(); + + // Submit transaction group + try { + await this.signer.sendTransactions(prepared.signedTxns, requirements.network); + } catch (error) { + return { + success: false, + errorReason: Errors.ErrSettleFailed, + errorMessage: `Failed to submit transaction: ${error instanceof Error ? error.message : "Unknown error"}`, + transaction: paymentTxId, + network: requirements.network, + payer: verification.payer, + }; + } + + // Wait for on-chain confirmation + try { + // Wait up to 10 rounds for on-chain confirmation + await this.signer.waitForConfirmation(paymentTxId, requirements.network, 10); + } catch (error) { + return { + success: false, + errorReason: Errors.ErrConfirmationFailed, + errorMessage: `Transaction submitted but confirmation failed: ${error instanceof Error ? error.message : "Unknown error"}`, + transaction: paymentTxId, + network: requirements.network, + payer: verification.payer, + }; + } + + return { + success: true, + transaction: paymentTxId, + network: requirements.network, + payer: verification.payer, + }; + } + + /** + * Decodes all transactions in the group and validates structure. + * + * - Signed transactions are decoded as-is + * - Unsigned transactions are only accepted from facilitator addresses (fee payers) + * - Verifies group ID consistency across all transactions + * + * @param paymentGroup - Array of base64-encoded transaction strings + * @param facilitatorAddresses - Addresses controlled by this facilitator + * @returns Decoded transactions or an error response + */ + private decodeTransactionGroup( + paymentGroup: string[], + facilitatorAddresses: readonly string[], + ): { txns: SignedTransaction[] } | { error: VerifyResponse } { + const txns: SignedTransaction[] = []; + + for (let i = 0; i < paymentGroup.length; i++) { + try { + const bytes = decodeTransaction(paymentGroup[i]); + + try { + const stxn = decodeSignedTxn(bytes); + // Validate that decoding actually produced a valid signed transaction. + // algokit-utils decodeSignedTransaction is lenient and may succeed on raw unsigned + // bytes, returning a transaction with type "unknown" and missing fields. + if (!stxn.txn.type || stxn.txn.type === "unknown") { + throw new Error("Invalid signed transaction: missing type"); + } + txns.push(stxn); + } catch { + // Unsigned transaction — only the facilitator's fee payer txn should be unsigned + const unsignedTxn = decodeUnsignedTxn(bytes); + const sender = unsignedTxn.sender.toString(); + + if (!facilitatorAddresses.includes(sender)) { + return { + error: { + isValid: false, + invalidReason: Errors.ErrUnsignedNonFacilitator, + invalidMessage: `Unsigned transaction at index ${i} from ${sender} is not a facilitator address`, + }, + }; + } + + // Wrap unsigned txn for simulation (empty signature) + const encodedForSimulate = encodeSignedTransaction({ txn: unsignedTxn }); + txns.push(decodeSignedTxn(encodedForSimulate)); + } + } catch { + return { + error: { + isValid: false, + invalidReason: Errors.ErrInvalidTransaction, + invalidMessage: `Failed to decode transaction at index ${i}`, + }, + }; + } + } + + // Verify group ID consistency + if (txns.length > 1) { + const firstGroup = txns[0].txn.group; + const firstGroupId = firstGroup ? Buffer.from(firstGroup).toString("base64") : null; + + for (let i = 1; i < txns.length; i++) { + const group = txns[i].txn.group; + const groupId = group ? Buffer.from(group).toString("base64") : null; + if (groupId !== firstGroupId) { + return { + error: { + isValid: false, + invalidReason: Errors.ErrInvalidGroupId, + invalidMessage: "Transactions have inconsistent group IDs", + }, + }; + } + } + } + + return { txns }; + } + + /** + * Verifies fee payer transactions and signs them, returning the assembled group + * ready for simulation or submission. + * + * @param decodedTxns - Decoded signed transaction objects + * @param paymentGroup - Original base64-encoded transaction strings + * @returns Signed transaction bytes or an error response + */ + private async prepareSignedGroup( + decodedTxns: SignedTransaction[], + paymentGroup: string[], + ): Promise<{ signedTxns: Uint8Array[] } | { error: VerifyResponse }> { + const facilitatorAddresses = this.signer.getAddresses(); + const signedTxns: Uint8Array[] = []; + + for (let i = 0; i < decodedTxns.length; i++) { + const txn = decodedTxns[i].txn; + const sender = txn.sender.toString(); + + if (facilitatorAddresses.includes(sender)) { + const feeCheck = this.verifyFeePayerTransaction(txn, decodedTxns.length); + if (!feeCheck.isValid) return { error: feeCheck }; + + try { + const signedTxn = await this.signer.signTransaction(encodeTransactionRaw(txn), sender); + signedTxns.push(signedTxn); + } catch (error) { + return { + error: { + isValid: false, + invalidReason: Errors.ErrInvalidFeePayer, + invalidMessage: `Failed to sign fee payer transaction: ${error instanceof Error ? error.message : "Unknown error"}`, + }, + }; + } + } else { + signedTxns.push(decodeTransaction(paymentGroup[i])); + } + } + + return { signedTxns }; + } + + /** + * Simulates the transaction group and returns the verification result. + * + * @param signedTxns - Signed transaction bytes to simulate + * @param network - Target network for simulation + * @returns Verification result from simulation + */ + private async simulateTransactionGroup( + signedTxns: Uint8Array[], + network: Network, + ): Promise { + try { + const simResult = (await this.signer.simulateTransactions(signedTxns, network)) as { + txnGroups?: Array<{ failureMessage?: string }>; + }; + + if (simResult.txnGroups?.[0]?.failureMessage) { + return { + isValid: false, + invalidReason: Errors.ErrSimulationFailed, + invalidMessage: simResult.txnGroups[0].failureMessage, + }; + } + + return { isValid: true }; + } catch (error) { + return { + isValid: false, + invalidReason: Errors.ErrSimulationFailed, + invalidMessage: error instanceof Error ? error.message : "Unknown error", + }; + } + } + + /** + * Verifies the payment transaction matches requirements + * + * @param stxn - The signed payment transaction + * @param requirements - Payment requirements to verify against + * @param encodedTxn - Base64-encoded transaction for signature check + * @returns Verification result + */ + private async verifyPaymentTransaction( + stxn: SignedTransaction, + requirements: PaymentRequirements, + encodedTxn: string, + ): Promise { + const txn = stxn.txn; + + // Must be an asset transfer + if (txn.type !== "axfer") { + return { + isValid: false, + invalidReason: Errors.ErrNotAssetTransfer, + invalidMessage: `Expected asset transfer, got "${txn.type}"`, + }; + } + + // Access asset transfer properties — properly typed in algokit-utils v10 + const assetTransfer = txn.assetTransfer; + + if (!assetTransfer) { + return { + isValid: false, + invalidReason: Errors.ErrNotAssetTransfer, + invalidMessage: "Missing assetTransfer data", + }; + } + + // Use BigInt comparison to avoid string format mismatches (e.g. "1000" vs "1000.0") + const amount = assetTransfer.amount ?? BigInt(0); + + if (amount !== BigInt(requirements.amount)) { + return { + isValid: false, + invalidReason: Errors.ErrAmountMismatch, + invalidMessage: `Expected ${requirements.amount}, got ${amount.toString()}`, + }; + } + + // Verify receiver address matches payTo + const receiver = assetTransfer.receiver ? assetTransfer.receiver.toString() : ""; + + if (receiver !== requirements.payTo) { + return { + isValid: false, + invalidReason: Errors.ErrReceiverMismatch, + invalidMessage: `Expected ${requirements.payTo}, got ${receiver}`, + }; + } + + // Verify asset + const assetId = assetTransfer.assetId?.toString() ?? ""; + + if (assetId !== requirements.asset) { + return { + isValid: false, + invalidReason: Errors.ErrAssetMismatch, + invalidMessage: `Expected asset ${requirements.asset}, got ${assetId}`, + }; + } + + // Verify signature exists + const txnBytes = decodeTransaction(encodedTxn); + if (!hasSignature(txnBytes)) { + return { + isValid: false, + invalidReason: Errors.ErrPaymentNotSigned, + invalidMessage: "Payment transaction is not signed", + }; + } + + // Verify the ed25519 signature was actually made by the sender + if (stxn.sig) { + const signedMsg = bytesForSigning.transaction(txn); + const isValidSig = await ed25519Verifier(stxn.sig, signedMsg, txn.sender.publicKey); + if (!isValidSig) { + return { + isValid: false, + invalidReason: Errors.ErrInvalidSignature, + invalidMessage: "Payment transaction signature does not match sender", + }; + } + } + + return { isValid: true }; + } + + /** + * Verifies a fee payer transaction is safe to sign + * + * @param txn - The fee payer transaction to validate + * @param groupSize - Number of transactions in the atomic group (for fee cap calculation) + * @returns Verification result + */ + private verifyFeePayerTransaction(txn: Transaction, groupSize: number): VerifyResponse { + // Must be a payment transaction (for fee payment) + if (txn.type !== "pay") { + return { + isValid: false, + invalidReason: Errors.ErrInvalidFeePayer, + invalidMessage: `Expected payment transaction, got ${txn.type}`, + }; + } + + // Access payment fields — properly typed in algokit-utils v10 + const paymentFields = txn.payment; + + // Must have zero amount (self-payment for fee coverage) + const payAmount = paymentFields?.amount ?? BigInt(0); + if (payAmount > BigInt(0)) { + return { + isValid: false, + invalidReason: Errors.ErrInvalidFeePayer, + invalidMessage: "Fee payer amount must be 0", + }; + } + + // Must be self-payment (receiver == sender) + if (paymentFields?.receiver) { + const receiverAddr = paymentFields.receiver.toString(); + const senderAddr = txn.sender.toString(); + if (receiverAddr !== senderAddr) { + return { + isValid: false, + invalidReason: Errors.ErrInvalidFeePayer, + invalidMessage: "Fee payer receiver must be same as sender (self-payment)", + }; + } + } + + // Must not have close remainder to + if (paymentFields?.closeRemainderTo) { + return { + isValid: false, + invalidReason: Errors.ErrInvalidFeePayer, + invalidMessage: "closeRemainderTo not allowed on fee payer", + }; + } + + // Must not have rekey to + if (txn.rekeyTo) { + return { + isValid: false, + invalidReason: Errors.ErrInvalidFeePayer, + invalidMessage: "rekeyTo not allowed on fee payer", + }; + } + + // Fee must be reasonable — during congestion fees can rise, so the cap + // is 5x the minimum fee (5000 µAlgo) per transaction in the group. + // The fee payer covers the entire group via Algorand's fee pooling. + const fee = Number(txn.fee ?? 0); + const maxFee = maxReasonableGroupFee(groupSize); + if (fee > maxFee) { + return { + isValid: false, + invalidReason: Errors.ErrFeeTooHigh, + invalidMessage: `Fee ${fee} exceeds maximum ${maxFee} (${groupSize} txns × 5000 µAlgo)`, + }; + } + + return { isValid: true }; + } +} diff --git a/typescript/packages/mechanisms/avm/src/exact/index.ts b/typescript/packages/mechanisms/avm/src/exact/index.ts new file mode 100644 index 0000000000..cb7372f85e --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/exact/index.ts @@ -0,0 +1 @@ +export { ExactAvmScheme } from "./client/scheme"; diff --git a/typescript/packages/mechanisms/avm/src/exact/server/index.ts b/typescript/packages/mechanisms/avm/src/exact/server/index.ts new file mode 100644 index 0000000000..4693cbfe33 --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/exact/server/index.ts @@ -0,0 +1 @@ +export { ExactAvmScheme } from "./scheme"; diff --git a/typescript/packages/mechanisms/avm/src/exact/server/scheme.ts b/typescript/packages/mechanisms/avm/src/exact/server/scheme.ts new file mode 100644 index 0000000000..01b1ad21f2 --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/exact/server/scheme.ts @@ -0,0 +1,199 @@ +/** + * AVM Server Scheme for Exact Payment Protocol + * + * Parses prices and builds payment requirements for Algorand ASA transfers. + */ + +import type { + AssetAmount, + Network, + PaymentRequirements, + Price, + SchemeNetworkServer, + MoneyParser, +} from "@x402/core/types"; +import { convertToTokenAmount, numberToDecimalString } from "@x402/core/utils"; +import { USDC_CONFIG, USDC_DECIMALS } from "../../constants"; + +/** + * AVM server implementation for the Exact payment scheme. + * + * Handles price parsing and payment requirements enhancement for Algorand networks. + */ +export class ExactAvmScheme implements SchemeNetworkServer { + readonly scheme = "exact"; + private moneyParsers: MoneyParser[] = []; + + /** + * Register a custom money parser in the parser chain. + * Multiple parsers can be registered - they will be tried in registration order. + * Each parser receives a decimal amount (e.g., 1.50 for $1.50). + * If a parser returns null, the next parser in the chain will be tried. + * The default parser is always the final fallback. + * + * @param parser - Custom function to convert amount to AssetAmount (or null to skip) + * @returns The server instance for chaining + * + * @example + * ```typescript + * avmServer.registerMoneyParser(async (amount, network) => { + * // Custom conversion logic for non-USDC assets + * if (amount > 100) { + * return { amount: (amount * 1e6).toString(), asset: "12345678" }; + * } + * return null; // Use next parser + * }); + * ``` + */ + registerMoneyParser(parser: MoneyParser): ExactAvmScheme { + this.moneyParsers.push(parser); + return this; + } + + /** + * Parses a price into an asset amount. + * If price is already an AssetAmount, returns it directly. + * If price is Money (string | number), parses to decimal and tries custom parsers. + * Falls back to default conversion if all custom parsers return null. + * + * @param price - The price to parse + * @param network - The network to use + * @returns Promise that resolves to the parsed asset amount + */ + async parsePrice(price: Price, network: Network): Promise { + // If already an AssetAmount, return it directly + if (typeof price === "object" && price !== null && "amount" in price) { + if (!price.asset) { + throw new Error(`Asset ID must be specified for AssetAmount on network ${network}`); + } + return { + amount: price.amount, + asset: price.asset, + extra: price.extra || {}, + }; + } + + // Parse Money to decimal number + const amount = this.parseMoneyToDecimal(price); + + // Try each custom money parser in order + for (const parser of this.moneyParsers) { + const result = await parser(amount, network); + if (result !== null) { + return result; + } + } + + // All custom parsers returned null, use default conversion + return this.defaultMoneyConversion(amount, network); + } + + /** + * Build payment requirements for this scheme/network combination + * + * @param paymentRequirements - The base payment requirements + * @param supportedKind - The supported kind from facilitator (contains extra data like feePayer) + * @param supportedKind.x402Version - The x402 version + * @param supportedKind.scheme - The logical payment scheme + * @param supportedKind.network - The network identifier in CAIP-2 format + * @param supportedKind.extra - Optional extra metadata (e.g., feePayer address) + * @param extensionKeys - Extension keys supported by the facilitator + * @returns Payment requirements ready to be sent to clients + */ + enhancePaymentRequirements( + paymentRequirements: PaymentRequirements, + supportedKind: { + x402Version: number; + scheme: string; + network: Network; + extra?: Record; + }, + extensionKeys: string[], + ): Promise { + // Mark unused parameter + void extensionKeys; + + // Get USDC config for the network + const usdcConfig = USDC_CONFIG[supportedKind.network]; + const decimals = usdcConfig?.decimals ?? USDC_DECIMALS; + + // Build enhanced requirements with feePayer and decimals + const enhanced: PaymentRequirements = { + ...paymentRequirements, + extra: { + ...paymentRequirements.extra, + decimals, + }, + }; + + // Add feePayer from supportedKind.extra if provided + if (supportedKind.extra?.feePayer) { + enhanced.extra = { + ...enhanced.extra, + feePayer: supportedKind.extra.feePayer, + }; + } + + return Promise.resolve(enhanced); + } + + /** + * Parse Money (string | number) to a decimal number. + * Handles formats like "$1.50", "1.50", 1.50, etc. + * + * @param money - The money value to parse + * @returns Decimal number + */ + private parseMoneyToDecimal(money: string | number): number { + if (typeof money === "number") { + return money; + } + + // Remove $ sign and whitespace, then parse + const cleanMoney = money.replace(/^\$/, "").trim(); + const amount = parseFloat(cleanMoney); + + if (isNaN(amount)) { + throw new Error(`Invalid money format: ${money}`); + } + + return amount; + } + + /** + * Default money conversion implementation. + * Converts decimal amount to the default stablecoin (USDC) on the specified network. + * + * @param amount - The decimal amount (e.g., 1.50) + * @param network - The network to use + * @returns The parsed asset amount in USDC + */ + private defaultMoneyConversion(amount: number, network: Network): AssetAmount { + const assetInfo = this.getDefaultAsset(network); + const tokenAmount = convertToTokenAmount(numberToDecimalString(amount), assetInfo.decimals); + + return { + amount: tokenAmount, + asset: assetInfo.asaId, + }; + } + + /** + * Get the default asset info for a network (USDC) + * + * @param network - The network to get asset info for + * @returns The asset information including ASA ID, name, and decimals + */ + private getDefaultAsset(network: Network): { + asaId: string; + name: string; + decimals: number; + } { + const assetInfo = USDC_CONFIG[network]; + if (!assetInfo) { + throw new Error(`No default asset configured for network ${network}`); + } + + return assetInfo; + } +} diff --git a/typescript/packages/mechanisms/avm/src/index.ts b/typescript/packages/mechanisms/avm/src/index.ts new file mode 100644 index 0000000000..3331eead1b --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/index.ts @@ -0,0 +1,90 @@ +/** + * @module @x402/avm - x402 Payment Protocol AVM (Algorand) Implementation + * + * This module provides the Algorand-specific implementation of the x402 payment protocol. + * + * @example Client signer: + * ```typescript + * import { toClientAvmSigner } from "@x402/avm"; + * + * const signer = toClientAvmSigner(process.env.AVM_PRIVATE_KEY!); + * ``` + * + * @example Facilitator signer: + * ```typescript + * import { toFacilitatorAvmSigner } from "@x402/avm"; + * + * const signer = toFacilitatorAvmSigner(process.env.AVM_PRIVATE_KEY!); + * ``` + */ + +// Exact scheme client +export { ExactAvmScheme } from "./exact"; + +// Signer helpers and interfaces +export { + isAvmSignerWallet, + toClientAvmSigner, + toFacilitatorAvmSigner, + getAlgokitSigner, + ALGOKIT_SIGNER, +} from "./signer"; +export type { + ClientAvmSigner, + ClientAvmConfig, + FacilitatorAvmSigner, + FacilitatorAvmSignerConfig, +} from "./signer"; + +// Re-export algokit-utils signer types for consumers who want native interop +export type { + AddressWithTransactionSigner, + AddressWithSigners, + TransactionSigner, +} from "@algorandfoundation/algokit-utils/transact"; + +// Types +export type { ExactAvmPayloadV2 } from "./types"; +export { isExactAvmPayload } from "./types"; + +// Constants +export { + // CAIP-2 Network Identifiers + ALGORAND_MAINNET_CAIP2, + ALGORAND_TESTNET_CAIP2, + CAIP2_NETWORKS, + // Genesis Hashes + ALGORAND_MAINNET_GENESIS_HASH, + ALGORAND_TESTNET_GENESIS_HASH, + // USDC Configuration + USDC_MAINNET_ASA_ID, + USDC_TESTNET_ASA_ID, + USDC_DECIMALS, + USDC_CONFIG, + // Transaction Limits + MAX_REASONABLE_FEE_PER_TXN, + maxReasonableGroupFee, +} from "./constants"; + +// Re-export algokit-utils constants that consumers may need +export { ALGORAND_ADDRESS_LENGTH } from "@algorandfoundation/algokit-utils/common"; +export { ALGORAND_MIN_TX_FEE } from "@algorandfoundation/algokit-utils/amount"; + +// Utilities +export { + encodeTransaction, + decodeTransaction, + decodeSignedTransaction, + decodeUnsignedTransaction, + isValidAlgorandAddress, + getSenderFromTransaction, + convertToTokenAmount, + convertFromTokenAmount, + getNetworkFromCaip2, + isAlgorandNetwork, + isTestnetNetwork, + getGenesisHashFromTransaction, + validateGroupId, + getTransactionId, + hasSignature, +} from "./utils"; diff --git a/typescript/packages/mechanisms/avm/src/signer.ts b/typescript/packages/mechanisms/avm/src/signer.ts new file mode 100644 index 0000000000..7990d0a01a --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/signer.ts @@ -0,0 +1,396 @@ +/** + * AVM (Algorand) Signer Interfaces for x402 Payment Protocol + * + * This module defines the signer interfaces for client and facilitator operations. + * Use the `toClientAvmSigner` and `toFacilitatorAvmSigner` helper functions to create + * signers from a Base64-encoded private key. + * + * @example Client signer: + * ```typescript + * import { toClientAvmSigner } from "@x402/avm"; + * + * const signer = toClientAvmSigner(process.env.AVM_PRIVATE_KEY!); + * ``` + * + * @example Facilitator signer: + * ```typescript + * import { toFacilitatorAvmSigner } from "@x402/avm"; + * + * const signer = toFacilitatorAvmSigner(process.env.AVM_PRIVATE_KEY!); + * ``` + */ + +import { AlgorandClient } from "@algorandfoundation/algokit-utils/algorand-client"; +import { ed25519Generator } from "@algorandfoundation/algokit-utils/crypto"; +import { + decodeTransaction, + generateAddressWithSigners, +} from "@algorandfoundation/algokit-utils/transact"; +import type { + AddressWithSigners, + AddressWithTransactionSigner, +} from "@algorandfoundation/algokit-utils/transact"; +import { waitForConfirmation } from "@algorandfoundation/algokit-utils/transaction"; +import type { Network } from "@x402/core/types"; +import { ALGORAND_TESTNET_CAIP2 } from "./constants"; + +/** + * Symbol key used to attach the internal algokit-utils AddressWithSigners + * to a ClientAvmSigner created via toClientAvmSigner(). + * This enables internal code to extract the native algokit signer for + * use with TransactionComposer and AlgorandClient. + */ +export const ALGOKIT_SIGNER = Symbol("algokit-signer"); + +/** + * Client-side signer interface for Algorand wallets + * + * Compatible with @txnlab/use-wallet and similar wallet libraries. + * Used to sign payment transactions on the client side. + */ +export interface ClientAvmSigner { + /** + * The Algorand address of the signer + */ + address: string; + + /** + * Sign one or more transactions + * + * @param txns - Array of unsigned transactions (encoded as Uint8Array) + * @param indexesToSign - Optional array of indexes to sign (if not provided, sign all) + * @returns Promise resolving to array of signed transactions (null for unsigned) + */ + signTransactions(txns: Uint8Array[], indexesToSign?: number[]): Promise<(Uint8Array | null)[]>; +} + +/** + * Configuration for client AVM operations + */ +export interface ClientAvmConfig { + /** + * Pre-configured AlgorandClient instance (takes precedence over URL/token) + * Use AlgorandClient.testNet(), .mainNet(), .fromConfig(), etc. + */ + algorandClient?: import("@algorandfoundation/algokit-utils/algorand-client").AlgorandClient; + + /** + * Algod API URL (used if algorandClient not provided) + */ + algodUrl?: string; + + /** + * Algod API token + */ + algodToken?: string; +} + +/** + * Facilitator signer interface for Algorand operations + * + * Used by the facilitator to verify and settle payments. + * Supports multiple addresses for load balancing and key rotation. + * + * @example Using the helper function: + * ```typescript + * import { toFacilitatorAvmSigner } from "@x402/avm"; + * + * const signer = toFacilitatorAvmSigner(process.env.AVM_PRIVATE_KEY!); + * ``` + */ +export interface FacilitatorAvmSigner { + /** + * Get all addresses this facilitator can use as fee payers + * + * @returns Array of Algorand addresses + */ + getAddresses(): readonly string[]; + + /** + * Sign a transaction with the signer matching the sender address + * + * @param txn - Transaction bytes to sign + * @param senderAddress - Expected sender address (for verification) + * @returns Promise resolving to signed transaction bytes + */ + signTransaction(txn: Uint8Array, senderAddress: string): Promise; + + /** + * Get Algod client for a specific network + * + * @param network - Network identifier (CAIP-2 or V1 format) + * @returns AlgodClient instance from @algorandfoundation/algokit-utils + */ + getAlgodClient( + network: Network, + ): import("@algorandfoundation/algokit-utils/algod-client").AlgodClient; + + /** + * Simulate a transaction group before submission + * + * @param txns - Array of signed transaction bytes + * @param network - Network identifier + * @returns Promise resolving to SimulateResponse + */ + simulateTransactions( + txns: Uint8Array[], + network: Network, + ): Promise; + + /** + * Submit signed transactions to the network + * + * @param signedTxns - Array of signed transaction bytes + * @param network - Network identifier + * @returns Promise resolving to transaction ID + */ + sendTransactions(signedTxns: Uint8Array[], network: Network): Promise; + + /** + * Wait for a transaction to be confirmed + * + * @param txId - Transaction ID + * @param network - Network identifier + * @param waitRounds - Number of rounds to wait (default: 4) + * @returns Promise resolving to PendingTransactionResponse + */ + waitForConfirmation( + txId: string, + network: Network, + waitRounds?: number, + ): Promise; +} + +/** + * Configuration for creating a facilitator signer + */ +export interface FacilitatorAvmSignerConfig { + /** + * Algod URL for mainnet + */ + mainnetUrl?: string; + + /** + * Algod URL for testnet + */ + testnetUrl?: string; + + /** + * Algod API token + */ + algodToken?: string; +} + +/** + * Type guard to check if a wallet implements ClientAvmSigner + * + * @param wallet - The wallet to check + * @returns True if the wallet implements ClientAvmSigner + */ +export function isAvmSignerWallet(wallet: unknown): wallet is ClientAvmSigner { + return ( + typeof wallet === "object" && + wallet !== null && + "address" in wallet && + typeof (wallet as ClientAvmSigner).address === "string" && + "signTransactions" in wallet && + typeof (wallet as ClientAvmSigner).signTransactions === "function" + ); +} + +/** + * Decodes a Base64-encoded 64-byte private key into address and raw Ed25519 signer. + * + * @param privateKeyBase64 - Base64-encoded 64-byte key (32-byte seed + 32-byte public key) + * @returns Address and raw Ed25519 signer function + */ +function decodePrivateKey(privateKeyBase64: string) { + const secretKey = Buffer.from(privateKeyBase64, "base64"); + if (secretKey.length !== 64) { + throw new Error( + "AVM private key must be a Base64-encoded 64-byte key (32-byte seed + 32-byte public key)", + ); + } + const seed = secretKey.subarray(0, 32); + return ed25519Generator(seed); +} + +/** + * Creates a ClientAvmSigner from a Base64-encoded private key. + * + * This is the recommended way to create a client-side AVM signer for x402 payments. + * + * @param privateKeyBase64 - Base64-encoded 64-byte key (32-byte seed + 32-byte public key) + * @returns A complete ClientAvmSigner ready for use with ExactAvmScheme + * + * @example + * ```typescript + * import { toClientAvmSigner } from "@x402/avm"; + * import { ExactAvmScheme } from "@x402/avm/exact/client"; + * + * const signer = toClientAvmSigner(process.env.AVM_PRIVATE_KEY!); + * client.register("algorand:*", new ExactAvmScheme(signer)); + * ``` + */ +export function toClientAvmSigner(privateKeyBase64: string): ClientAvmSigner { + const { ed25519Pubkey, rawEd25519Signer } = decodePrivateKey(privateKeyBase64); + + // Use algokit-utils generateAddressWithSigners for the canonical signer implementation + const algokitSigners = generateAddressWithSigners({ ed25519Pubkey, rawEd25519Signer }); + const address = algokitSigners.addr.toString(); + + const signer: ClientAvmSigner = { + address, + signTransactions: async (txns: Uint8Array[], indexesToSign?: number[]) => { + return Promise.all( + txns.map(async (txn, i) => { + if (indexesToSign && !indexesToSign.includes(i)) return null; + const decoded = decodeTransaction(txn); + // Delegate to the algokit-utils signer (signs a single transaction in a group) + const signedBytes = await algokitSigners.signer([decoded], [0]); + return signedBytes[0]; + }), + ); + }, + }; + + // Attach the internal algokit-utils AddressWithSigners for use by internal code + // (e.g., TransactionComposer integration in client scheme) + Object.defineProperty(signer, ALGOKIT_SIGNER, { + value: algokitSigners, + enumerable: false, + writable: false, + }); + + return signer; +} + +/** + * Extracts the internal algokit-utils AddressWithTransactionSigner from a ClientAvmSigner, + * if available. Returns null for wallet-created signers that don't have an internal + * algokit signer (e.g., signers created from browser wallet adapters). + * + * This is useful for internal code that needs to register the signer with + * AlgorandClient or TransactionComposer. + * + * @param signer - A ClientAvmSigner instance + * @returns The internal AddressWithTransactionSigner, or null if not available + */ +export function getAlgokitSigner(signer: ClientAvmSigner): AddressWithTransactionSigner | null { + const internal = (signer as unknown as Record)[ALGOKIT_SIGNER] as + | AddressWithSigners + | undefined; + if (internal && "addr" in internal && "signer" in internal) { + return { addr: internal.addr, signer: internal.signer }; + } + return null; +} + +/** + * Determines if a network identifier refers to testnet. + * + * @param network - The network identifier (CAIP-2 format) + * @returns True if the network is testnet + */ +function isTestnet(network: string): boolean { + return network === ALGORAND_TESTNET_CAIP2; +} + +/** + * Creates a FacilitatorAvmSigner from a Base64-encoded private key. + * + * This is the recommended way to create a facilitator-side AVM signer for x402 payments. + * Uses `AlgorandClient.testNet()` / `AlgorandClient.mainNet()` from AlgoKit Utils for + * network connectivity, with optional URL overrides via config. + * + * @param privateKeyBase64 - Base64-encoded 64-byte key (32-byte seed + 32-byte public key) + * @param config - Optional configuration for custom Algod URLs + * @returns A complete FacilitatorAvmSigner ready for use with ExactAvmScheme + * + * @example + * ```typescript + * import { toFacilitatorAvmSigner } from "@x402/avm"; + * import { ExactAvmScheme } from "@x402/avm/exact/facilitator"; + * + * // Default (AlgoNode endpoints): + * const signer = toFacilitatorAvmSigner(process.env.AVM_PRIVATE_KEY!); + * + * // With custom URLs: + * const signer = toFacilitatorAvmSigner(process.env.AVM_PRIVATE_KEY!, { + * testnetUrl: "https://my-testnet-node.example.com", + * mainnetUrl: "https://my-mainnet-node.example.com", + * }); + * + * facilitator.register("algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=", new ExactAvmScheme(signer)); + * ``` + */ +export function toFacilitatorAvmSigner( + privateKeyBase64: string, + config?: FacilitatorAvmSignerConfig, +): FacilitatorAvmSigner { + const { ed25519Pubkey, rawEd25519Signer } = decodePrivateKey(privateKeyBase64); + + // Use algokit-utils generateAddressWithSigners for the canonical signer implementation + const algokitSigners = generateAddressWithSigners({ ed25519Pubkey, rawEd25519Signer }); + const address = algokitSigners.addr.toString(); + + // Create AlgorandClient instances for each network, with optional URL overrides + const getAlgorandClientForNetwork = (network: string) => { + if (isTestnet(network)) { + if (config?.testnetUrl) { + return AlgorandClient.fromConfig({ + algodConfig: { server: config.testnetUrl, token: config.algodToken ?? "" }, + }); + } + return AlgorandClient.testNet(); + } + if (config?.mainnetUrl) { + return AlgorandClient.fromConfig({ + algodConfig: { server: config.mainnetUrl, token: config.algodToken ?? "" }, + }); + } + return AlgorandClient.mainNet(); + }; + + // Cache AlgorandClient instances per network + const clientCache = new Map>(); + + const getClient = (network: string) => { + const key = isTestnet(network) ? "testnet" : "mainnet"; + let client = clientCache.get(key); + if (!client) { + client = getAlgorandClientForNetwork(network); + clientCache.set(key, client); + } + return client; + }; + + return { + getAddresses: () => [address] as readonly string[], + + signTransaction: async (txn: Uint8Array, _: string) => { + const decoded = decodeTransaction(txn); + // Delegate to the algokit-utils signer + const signedBytes = await algokitSigners.signer([decoded], [0]); + return signedBytes[0]; + }, + + getAlgodClient: (network: string) => getClient(network).client.algod, + + simulateTransactions: async (txns: Uint8Array[], network: string) => { + const algod = getClient(network).client.algod; + return await algod.simulateRawTransactions(txns); + }, + + sendTransactions: async (signedTxns: Uint8Array[], network: string) => { + const algod = getClient(network).client.algod; + const response = await algod.sendRawTransaction(signedTxns); + return response.txId; + }, + + waitForConfirmation: async (txId: string, network: string, waitRounds: number = 5) => { + const algod = getClient(network).client.algod; + return await waitForConfirmation(txId, waitRounds, algod); + }, + }; +} diff --git a/typescript/packages/mechanisms/avm/src/types.ts b/typescript/packages/mechanisms/avm/src/types.ts new file mode 100644 index 0000000000..8848448d25 --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/types.ts @@ -0,0 +1,57 @@ +/** + * AVM (Algorand) Types for x402 Payment Protocol + * + * Defines payload structures and type guards for Algorand transactions. + */ + +/** + * V2 Payload for Algorand exact payment scheme + * + * Contains an atomic transaction group with a designated payment transaction. + * Transactions are encoded as base64 msgpack. + * + * @example + * ```typescript + * const payload: ExactAvmPayloadV2 = { + * paymentGroup: [ + * "gqNzaWfEQ...", // Fee payer transaction (signed by facilitator) + * "gqNzaWfEQ...", // ASA transfer (signed by client) + * ], + * paymentIndex: 1, // Payment is the second transaction + * }; + * ``` + */ +export interface ExactAvmPayloadV2 { + /** + * Array of base64-encoded msgpack transactions forming an atomic group. + * May include unsigned transactions (for fee payer) that the facilitator will sign. + */ + paymentGroup: string[]; + + /** + * Zero-based index of the payment transaction within paymentGroup. + * This transaction must be an ASA transfer to the payTo address. + */ + paymentIndex: number; +} + +/** + * Type guard to check if a payload is an ExactAvmPayloadV2 + * + * @param payload - The payload to check + * @returns True if the payload is a valid ExactAvmPayloadV2 + */ +export function isExactAvmPayload(payload: unknown): payload is ExactAvmPayloadV2 { + return ( + typeof payload === "object" && + payload !== null && + "paymentGroup" in payload && + "paymentIndex" in payload && + Array.isArray((payload as ExactAvmPayloadV2).paymentGroup) && + typeof (payload as ExactAvmPayloadV2).paymentIndex === "number" && + (payload as ExactAvmPayloadV2).paymentGroup.every(item => typeof item === "string") + ); +} + +// Transaction and SignedTransaction types are provided by @algorandfoundation/algokit-utils/transact +// Use those directly instead of custom type definitions. diff --git a/typescript/packages/mechanisms/avm/src/utils.ts b/typescript/packages/mechanisms/avm/src/utils.ts new file mode 100644 index 0000000000..5d2456a9b7 --- /dev/null +++ b/typescript/packages/mechanisms/avm/src/utils.ts @@ -0,0 +1,224 @@ +/** + * AVM (Algorand) Utilities for x402 Payment Protocol + * + * Provides utility functions for Algod client creation, transaction encoding/decoding, + * address validation, and network identification. + */ + +import { + decodeTransaction as decodeUnsignedTxn, + decodeSignedTransaction as decodeSignedTxn, +} from "@algorandfoundation/algokit-utils/transact"; +import { isValidAddress } from "@algorandfoundation/algokit-utils/common"; +import { + ALGORAND_MAINNET_GENESIS_HASH, + ALGORAND_TESTNET_GENESIS_HASH, + ALGORAND_TESTNET_CAIP2, +} from "./constants"; + +/** + * Encodes transaction bytes to base64 string + * + * @param txn - Transaction bytes (Uint8Array) + * @returns Base64 encoded string + */ +export function encodeTransaction(txn: Uint8Array): string { + return Buffer.from(txn).toString("base64"); +} + +/** + * Decodes a base64 encoded transaction to bytes + * + * @param encoded - Base64 encoded transaction string + * @returns Transaction bytes (Uint8Array) + */ +export function decodeTransaction(encoded: string): Uint8Array { + return new Uint8Array(Buffer.from(encoded, "base64")); +} + +/** + * Decodes a signed transaction from base64 msgpack + * + * @param encoded - Base64 encoded signed transaction + * @returns Decoded signed transaction object + */ +export function decodeSignedTransaction(encoded: string) { + const bytes = decodeTransaction(encoded); + return decodeSignedTxn(bytes); +} + +/** + * Decodes an unsigned transaction from base64 msgpack + * + * @param encoded - Base64 encoded unsigned transaction + * @returns Decoded transaction object + */ +export function decodeUnsignedTransaction(encoded: string) { + const bytes = decodeTransaction(encoded); + return decodeUnsignedTxn(bytes); +} + +/** + * Validates an Algorand address + * + * Uses isValidAddress from algokit-utils which performs full checksum validation. + * + * @param address - The address to validate + * @returns True if the address is valid + */ +export function isValidAlgorandAddress(address: string): boolean { + return isValidAddress(address); +} + +/** + * Gets the sender address from a transaction (signed or unsigned) + * + * @param txnBytes - Transaction bytes + * @param isSigned - Whether the transaction is signed (default: true) + * @returns Sender address string + */ +export function getSenderFromTransaction(txnBytes: Uint8Array, isSigned: boolean = true): string { + if (isSigned) { + const signedTxn = decodeSignedTxn(txnBytes); + return signedTxn.txn.sender.toString(); + } + const txn = decodeUnsignedTxn(txnBytes); + return txn.sender.toString(); +} + +// Re-export from core for backward compatibility +export { convertToTokenAmount, numberToDecimalString } from "@x402/core/utils"; + +/** + * Converts atomic units to decimal amount + * + * @param atomicAmount - Amount in atomic units (string or bigint) + * @param decimals - Number of decimal places + * @returns Decimal amount as a string + */ +export function convertFromTokenAmount(atomicAmount: string | bigint, decimals: number): string { + const amount = BigInt(atomicAmount); + const divisor = BigInt(10 ** decimals); + const intPart = amount / divisor; + const decPart = amount % divisor; + + if (decPart === BigInt(0)) { + return intPart.toString(); + } + + const decStr = decPart.toString().padStart(decimals, "0"); + // Remove trailing zeros + const trimmedDec = decStr.replace(/0+$/, ""); + return `${intPart}.${trimmedDec}`; +} + +/** + * Gets the network type from a CAIP-2 identifier + * + * @param caip2 - CAIP-2 network identifier + * @returns Network type ("mainnet" | "testnet") or null if unknown + */ +export function getNetworkFromCaip2(caip2: string): "mainnet" | "testnet" | null { + if (!caip2.startsWith("algorand:")) { + return null; + } + + const genesisHash = caip2.slice("algorand:".length); + + if (genesisHash === ALGORAND_MAINNET_GENESIS_HASH) { + return "mainnet"; + } + if (genesisHash === ALGORAND_TESTNET_GENESIS_HASH) { + return "testnet"; + } + + return null; +} + +/** + * Checks if a network identifier is an Algorand network + * + * @param network - Network identifier (CAIP-2 format) + * @returns True if the network is an Algorand network + */ +export function isAlgorandNetwork(network: string): boolean { + return network.startsWith("algorand:"); +} + +/** + * Checks if a network identifier is a testnet + * + * @param network - Network identifier (CAIP-2 format) + * @returns True if the network is a testnet + */ +export function isTestnetNetwork(network: string): boolean { + return network === ALGORAND_TESTNET_CAIP2; +} + +/** + * Gets the genesis hash from a transaction + * + * @param txn - The transaction object + * @param txn.genesisHash - The genesis hash bytes + * @returns Base64 encoded genesis hash + */ +export function getGenesisHashFromTransaction(txn: { genesisHash?: Uint8Array }): string { + if (!txn.genesisHash) { + throw new Error("Transaction does not have a genesis hash"); + } + return Buffer.from(txn.genesisHash).toString("base64"); +} + +/** + * Validates that all transactions in a group have the same group ID + * + * @param txns - Array of transaction bytes + * @returns True if all transactions have matching group IDs + */ +export function validateGroupId(txns: Uint8Array[]): boolean { + if (txns.length <= 1) { + return true; + } + + let expectedGroupId: string | null = null; + + for (const txnBytes of txns) { + const txn = decodeUnsignedTxn(txnBytes); + const groupId = txn.group ? Buffer.from(txn.group).toString("base64") : null; + + if (expectedGroupId === null) { + expectedGroupId = groupId; + } else if (groupId !== expectedGroupId) { + return false; + } + } + + return true; +} + +/** + * Extracts the transaction ID from signed transaction bytes + * + * @param signedTxnBytes - Signed transaction bytes + * @returns Transaction ID string + */ +export function getTransactionId(signedTxnBytes: Uint8Array): string { + const signedTxn = decodeSignedTxn(signedTxnBytes); + return signedTxn.txn.txId(); +} + +/** + * Checks if a signed transaction has a valid signature + * + * @param signedTxnBytes - Signed transaction bytes + * @returns True if the transaction has a signature + */ +export function hasSignature(signedTxnBytes: Uint8Array): boolean { + const signedTxn = decodeSignedTxn(signedTxnBytes); + return ( + signedTxn.sig !== undefined || signedTxn.lsig !== undefined || signedTxn.msig !== undefined + ); +} + +// Re-export algokit-utils types that consumers may need +export { Address, encodeAddress, decodeAddress } from "@algorandfoundation/algokit-utils/common"; diff --git a/typescript/packages/mechanisms/avm/test/integrations/exact-avm.test.ts b/typescript/packages/mechanisms/avm/test/integrations/exact-avm.test.ts new file mode 100644 index 0000000000..bf0c9a912e --- /dev/null +++ b/typescript/packages/mechanisms/avm/test/integrations/exact-avm.test.ts @@ -0,0 +1,553 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { x402Client, x402HTTPClient } from "@x402/core/client"; +import { x402Facilitator } from "@x402/core/facilitator"; +import { + HTTPAdapter, + HTTPResponseInstructions, + x402HTTPResourceServer, + x402ResourceServer, + FacilitatorClient, +} from "@x402/core/server"; +import { + Network, + PaymentPayload, + PaymentRequirements, + VerifyResponse, + SettleResponse, + SupportedResponse, +} from "@x402/core/types"; +import { + ExactAvmScheme as ExactAvmClient, + ALGORAND_TESTNET_CAIP2, + USDC_TESTNET_ASA_ID, + toClientAvmSigner, + toFacilitatorAvmSigner, +} from "../../src"; +import { ExactAvmScheme as ExactAvmServer } from "../../src/exact/server/scheme"; +import { ExactAvmScheme as ExactAvmFacilitator } from "../../src/exact/facilitator/scheme"; +import type { ExactAvmPayloadV2 } from "../../src/types"; + +// Load private keys from environment (Base64-encoded 64-byte keys) +const CLIENT_PRIVATE_KEY = process.env.CLIENT_PRIVATE_KEY; +const FACILITATOR_PRIVATE_KEY = process.env.FACILITATOR_PRIVATE_KEY; +// Server address (payTo) — must be opt-in to USDC. +const SERVER_ADDRESS = process.env.SERVER_ADDRESS; + +if (!CLIENT_PRIVATE_KEY || !FACILITATOR_PRIVATE_KEY || !SERVER_ADDRESS) { + throw new Error( + "CLIENT_PRIVATE_KEY, FACILITATOR_PRIVATE_KEY, and SERVER_ADDRESS environment variables must be set for integration tests", + ); +} + +// Create signers using helper functions +const clientSigner = toClientAvmSigner(CLIENT_PRIVATE_KEY); +const facilitatorSigner = toFacilitatorAvmSigner(FACILITATOR_PRIVATE_KEY); +const FACILITATOR_ADDRESS = facilitatorSigner.getAddresses()[0]; + +/** + * AVM Facilitator Client wrapper + * Wraps the x402Facilitator for use with x402ResourceServer + */ +class AvmFacilitatorClient implements FacilitatorClient { + readonly scheme = "exact"; + readonly network = ALGORAND_TESTNET_CAIP2; + readonly x402Version = 2; + + /** + * Creates a new AvmFacilitatorClient instance + * + * @param facilitator - The x402 facilitator to wrap + */ + constructor(private readonly facilitator: x402Facilitator) {} + + /** + * Verifies a payment payload + * + * @param paymentPayload - The payment payload to verify + * @param paymentRequirements - The payment requirements + * @returns Promise resolving to verification response + */ + verify( + paymentPayload: PaymentPayload, + paymentRequirements: PaymentRequirements, + ): Promise { + return this.facilitator.verify(paymentPayload, paymentRequirements); + } + + /** + * Settles a payment + * + * @param paymentPayload - The payment payload to settle + * @param paymentRequirements - The payment requirements + * @returns Promise resolving to settlement response + */ + settle( + paymentPayload: PaymentPayload, + paymentRequirements: PaymentRequirements, + ): Promise { + return this.facilitator.settle(paymentPayload, paymentRequirements); + } + + /** + * Gets supported payment kinds + * + * @returns Promise resolving to supported response + */ + getSupported(): Promise { + return Promise.resolve(this.facilitator.getSupported()); + } +} + +/** + * Build AVM payment requirements for testing + * + * @param payTo - The recipient address + * @param amount - The payment amount in smallest units + * @param network - The network identifier (defaults to Algorand Testnet) + * @returns Payment requirements object + */ +function buildAvmPaymentRequirements( + payTo: string, + amount: string, + network: Network = ALGORAND_TESTNET_CAIP2, +): PaymentRequirements { + return { + scheme: "exact", + network, + asset: USDC_TESTNET_ASA_ID, // Algorand Testnet USDC + amount, + payTo, + maxTimeoutSeconds: 3600, + extra: { + feePayer: FACILITATOR_ADDRESS, + }, + }; +} + +describe("AVM Integration Tests", () => { + describe("x402Client / x402ResourceServer / x402Facilitator - AVM Flow", () => { + let client: x402Client; + let server: x402ResourceServer; + let clientAddress: string; + + beforeEach(async () => { + clientAddress = clientSigner.address; + + const avmClient = new ExactAvmClient(clientSigner); + client = new x402Client().register(ALGORAND_TESTNET_CAIP2, avmClient); + + const avmFacilitator = new ExactAvmFacilitator(facilitatorSigner); + const facilitator = new x402Facilitator().register(ALGORAND_TESTNET_CAIP2, avmFacilitator); + + const facilitatorClient = new AvmFacilitatorClient(facilitator); + server = new x402ResourceServer(facilitatorClient); + server.register(ALGORAND_TESTNET_CAIP2, new ExactAvmServer()); + await server.initialize(); + }); + + it( + "server should successfully verify and settle an AVM payment from a client", + { timeout: 30000 }, + async () => { + // Server - builds PaymentRequired response + const accepts = [ + buildAvmPaymentRequirements( + SERVER_ADDRESS, + "1000", // 0.001 USDC + ), + ]; + const resource = { + url: "https://company.co", + description: "Company Co. resource", + mimeType: "application/json", + }; + const paymentRequired = await server.createPaymentRequiredResponse(accepts, resource); + + // Client - responds with PaymentPayload response + const paymentPayload = await client.createPaymentPayload(paymentRequired); + + expect(paymentPayload).toBeDefined(); + expect(paymentPayload.x402Version).toBe(2); + expect(paymentPayload.accepted.scheme).toBe("exact"); + + // Verify the payload structure + const avmPayload = paymentPayload.payload as ExactAvmPayloadV2; + expect(avmPayload.paymentGroup).toBeDefined(); + expect(avmPayload.paymentGroup.length).toBeGreaterThan(0); + expect(typeof avmPayload.paymentGroup[0]).toBe("string"); + expect(avmPayload.paymentGroup[0].length).toBeGreaterThan(0); + + // Server - maps payment payload to payment requirements + const accepted = server.findMatchingRequirements(accepts, paymentPayload); + expect(accepted).toBeDefined(); + + const verifyResponse = await server.verifyPayment(paymentPayload, accepted!); + + if (!verifyResponse.isValid) { + console.log("❌ Verification failed!"); + console.log("Invalid reason:", verifyResponse.invalidReason); + console.log("Payer:", verifyResponse.payer); + console.log("Client address:", clientAddress); + console.log("Payload:", JSON.stringify(paymentPayload, null, 2)); + } + + expect(verifyResponse.isValid).toBe(true); + expect(verifyResponse.payer).toBe(clientAddress); + + // Server does work here + + const settleResponse = await server.settlePayment(paymentPayload, accepted!); + + if (!settleResponse.success) { + console.log("❌ Direct Settlement failed!", JSON.stringify(settleResponse, null, 2)); + } + + expect(settleResponse.success).toBe(true); + expect(settleResponse.network).toBe(ALGORAND_TESTNET_CAIP2); + expect(settleResponse.transaction).toBeDefined(); + expect(settleResponse.payer).toBe(clientAddress); + }, + ); + }); + + describe("x402HTTPClient / x402HTTPResourceServer / x402Facilitator - AVM Flow", () => { + let client: x402HTTPClient; + let httpServer: x402HTTPResourceServer; + + const routes = { + "/api/protected": { + accepts: { + scheme: "exact", + payTo: SERVER_ADDRESS, + price: "$0.001", + network: ALGORAND_TESTNET_CAIP2 as Network, + }, + description: "Access to protected API", + mimeType: "application/json", + }, + }; + + const mockAdapter: HTTPAdapter = { + getHeader: () => { + return undefined; + }, + getMethod: () => "GET", + getPath: () => "/api/protected", + getUrl: () => "https://example.com/api/protected", + getAcceptHeader: () => "application/json", + getUserAgent: () => "TestClient/1.0", + }; + + beforeEach(async () => { + // Brief pause to avoid rate limiting on free public algod nodes + // (the previous test suite makes multiple algod calls) + await new Promise(resolve => setTimeout(resolve, 3000)); + + const avmFacilitator = new ExactAvmFacilitator(facilitatorSigner); + const facilitator = new x402Facilitator().register(ALGORAND_TESTNET_CAIP2, avmFacilitator); + + const facilitatorClient = new AvmFacilitatorClient(facilitator); + + const avmClient = new ExactAvmClient(clientSigner); + const paymentClient = new x402Client().register(ALGORAND_TESTNET_CAIP2, avmClient); + client = new x402HTTPClient(paymentClient) as x402HTTPClient; + + // Create resource server and register schemes (composition pattern) + const ResourceServer = new x402ResourceServer(facilitatorClient); + ResourceServer.register(ALGORAND_TESTNET_CAIP2, new ExactAvmServer()); + await ResourceServer.initialize(); // Initialize to fetch supported kinds + + httpServer = new x402HTTPResourceServer(ResourceServer, routes); + }); + + it( + "middleware should successfully verify and settle an AVM payment from an http client", + { timeout: 30000 }, + async () => { + // Middleware creates a PaymentRequired response + const context = { + adapter: mockAdapter, + path: "/api/protected", + method: "GET", + }; + + // No payment made, get PaymentRequired response & header + const httpProcessResult = (await httpServer.processHTTPRequest(context))!; + + expect(httpProcessResult.type).toBe("payment-error"); + + const initial402Response = ( + httpProcessResult as { type: "payment-error"; response: HTTPResponseInstructions } + ).response; + + expect(initial402Response).toBeDefined(); + expect(initial402Response.status).toBe(402); + expect(initial402Response.headers).toBeDefined(); + expect(initial402Response.headers["PAYMENT-REQUIRED"]).toBeDefined(); + + // Client responds to PaymentRequired and submits a request with a PaymentPayload + const paymentRequired = client.getPaymentRequiredResponse( + name => initial402Response.headers[name], + initial402Response.body, + ); + const paymentPayload = await client.createPaymentPayload(paymentRequired); + + expect(paymentPayload).toBeDefined(); + expect(paymentPayload.accepted.scheme).toBe("exact"); + + const requestHeaders = await client.encodePaymentSignatureHeader(paymentPayload); + + // Middleware handles PAYMENT-SIGNATURE request + mockAdapter.getHeader = (name: string) => { + if (name === "PAYMENT-SIGNATURE") { + return requestHeaders["PAYMENT-SIGNATURE"]; + } + return undefined; + }; + + const httpProcessResult2 = await httpServer.processHTTPRequest(context); + + // No need to respond, can continue with request + expect(httpProcessResult2.type).toBe("payment-verified"); + const { + paymentPayload: verifiedPaymentPayload, + paymentRequirements: verifiedPaymentRequirements, + } = httpProcessResult2 as { + type: "payment-verified"; + paymentPayload: PaymentPayload; + paymentRequirements: PaymentRequirements; + }; + + expect(verifiedPaymentPayload).toBeDefined(); + expect(verifiedPaymentRequirements).toBeDefined(); + + const settlementResult = await httpServer.processSettlement( + verifiedPaymentPayload, + verifiedPaymentRequirements, + 200, + ); + + expect(settlementResult).toBeDefined(); + + if (!settlementResult.success) { + console.log("❌ HTTP Settlement failed!", JSON.stringify(settlementResult, null, 2)); + } + + expect(settlementResult.success).toBe(true); + + if (settlementResult.success) { + expect(settlementResult.headers).toBeDefined(); + expect(settlementResult.headers["PAYMENT-RESPONSE"]).toBeDefined(); + } + }, + ); + }); + + describe("Price Parsing Integration", () => { + let server: x402ResourceServer; + let avmServer: ExactAvmServer; + + beforeEach(async () => { + const facilitator = new x402Facilitator().register( + ALGORAND_TESTNET_CAIP2, + new ExactAvmFacilitator(facilitatorSigner), + ); + + const facilitatorClient = new AvmFacilitatorClient(facilitator); + server = new x402ResourceServer(facilitatorClient); + + avmServer = new ExactAvmServer(); + server.register(ALGORAND_TESTNET_CAIP2, avmServer); + await server.initialize(); + }); + + it("should parse Money formats and build payment requirements", async () => { + // Test different Money formats + const testCases = [ + { input: "$1.00", expectedAmount: "1000000" }, + { input: "1.50", expectedAmount: "1500000" }, + { input: 2.5, expectedAmount: "2500000" }, + ]; + + for (const testCase of testCases) { + const requirements = await server.buildPaymentRequirements({ + scheme: "exact", + payTo: SERVER_ADDRESS, + price: testCase.input, + network: ALGORAND_TESTNET_CAIP2 as Network, + }); + + expect(requirements).toHaveLength(1); + expect(requirements[0].amount).toBe(testCase.expectedAmount); + expect(requirements[0].asset).toBe(USDC_TESTNET_ASA_ID); // Algorand Testnet USDC + } + }); + + it("should handle AssetAmount pass-through", async () => { + const customAsset = { + amount: "5000000", + asset: "12345678", + extra: { foo: "bar" }, + }; + + const requirements = await server.buildPaymentRequirements({ + scheme: "exact", + payTo: SERVER_ADDRESS, + price: customAsset, + network: ALGORAND_TESTNET_CAIP2 as Network, + }); + + expect(requirements).toHaveLength(1); + expect(requirements[0].amount).toBe("5000000"); + expect(requirements[0].asset).toBe("12345678"); + expect(requirements[0].extra?.foo).toBe("bar"); + }); + + it("should use registerMoneyParser for custom conversion", async () => { + // Register custom parser: large amounts use custom token + avmServer.registerMoneyParser(async (amount, _network) => { + if (amount > 100) { + return { + amount: (amount * 1e6).toString(), // Custom token with 6 decimals + asset: "99999999", + extra: { token: "CUSTOM", tier: "large" }, + }; + } + return null; // Use default for small amounts + }); + + // Test large amount - should use custom parser + const largeRequirements = await server.buildPaymentRequirements({ + scheme: "exact", + payTo: SERVER_ADDRESS, + price: 150, // Large amount + network: ALGORAND_TESTNET_CAIP2 as Network, + }); + + expect(largeRequirements[0].amount).toBe((150 * 1e6).toString()); + expect(largeRequirements[0].asset).toBe("99999999"); + expect(largeRequirements[0].extra?.token).toBe("CUSTOM"); + expect(largeRequirements[0].extra?.tier).toBe("large"); + + // Test small amount - should use default USDC + const smallRequirements = await server.buildPaymentRequirements({ + scheme: "exact", + payTo: SERVER_ADDRESS, + price: 50, // Small amount + network: ALGORAND_TESTNET_CAIP2 as Network, + }); + + expect(smallRequirements[0].amount).toBe("50000000"); // 50 * 1e6 (USDC) + expect(smallRequirements[0].asset).toBe(USDC_TESTNET_ASA_ID); // Algorand Testnet USDC + }); + + it("should support multiple MoneyParser in chain", async () => { + avmServer + .registerMoneyParser(async amount => { + if (amount > 1000) { + return { + amount: (amount * 1e6).toString(), + asset: "88888888", + extra: { tier: "vip" }, + }; + } + return null; + }) + .registerMoneyParser(async amount => { + if (amount > 100) { + return { + amount: (amount * 1e6).toString(), + asset: "77777777", + extra: { tier: "premium" }, + }; + } + return null; + }); + // < 100 uses default USDC + + // VIP tier + const vipReq = await server.buildPaymentRequirements({ + scheme: "exact", + payTo: SERVER_ADDRESS, + price: 2000, + network: ALGORAND_TESTNET_CAIP2 as Network, + }); + expect(vipReq[0].extra?.tier).toBe("vip"); + expect(vipReq[0].asset).toBe("88888888"); + + // Premium tier + const premiumReq = await server.buildPaymentRequirements({ + scheme: "exact", + payTo: SERVER_ADDRESS, + price: 500, + network: ALGORAND_TESTNET_CAIP2 as Network, + }); + expect(premiumReq[0].extra?.tier).toBe("premium"); + expect(premiumReq[0].asset).toBe("77777777"); + + // Standard tier (default) + const standardReq = await server.buildPaymentRequirements({ + scheme: "exact", + payTo: SERVER_ADDRESS, + price: 50, + network: ALGORAND_TESTNET_CAIP2 as Network, + }); + expect(standardReq[0].asset).toBe(USDC_TESTNET_ASA_ID); // Default USDC + }); + + it("should work with async MoneyParser (e.g., exchange rate lookup)", async () => { + const mockExchangeRate = 1.02; + + avmServer.registerMoneyParser(async (amount, _network) => { + // Simulate async API call + await new Promise(resolve => setTimeout(resolve, 10)); + + const usdcAmount = amount * mockExchangeRate; + return { + amount: Math.floor(usdcAmount * 1e6).toString(), + asset: USDC_TESTNET_ASA_ID, + extra: { + exchangeRate: mockExchangeRate, + originalUSD: amount, + }, + }; + }); + + const requirements = await server.buildPaymentRequirements({ + scheme: "exact", + payTo: SERVER_ADDRESS, + price: 100, + network: ALGORAND_TESTNET_CAIP2 as Network, + }); + + // 100 USD * 1.02 = 102 USDC + expect(requirements[0].amount).toBe("102000000"); + expect(requirements[0].extra?.exchangeRate).toBe(1.02); + expect(requirements[0].extra?.originalUSD).toBe(100); + }); + + it("should avoid floating-point rounding error", async () => { + // Test different Money formats + const testCases = [ + { input: "$4.02", expectedAmount: "4020000" }, + { input: "4.02", expectedAmount: "4020000" }, + { input: "4.02 USDC", expectedAmount: "4020000" }, + { input: "4.02 USD", expectedAmount: "4020000" }, + { input: 4.02, expectedAmount: "4020000" }, + ]; + + for (const testCase of testCases) { + const requirements = await server.buildPaymentRequirements({ + scheme: "exact", + payTo: SERVER_ADDRESS, + price: testCase.input, + network: ALGORAND_TESTNET_CAIP2 as Network, + }); + + expect(requirements).toHaveLength(1); + expect(requirements[0].amount).toBe(testCase.expectedAmount); + expect(requirements[0].asset).toBe(USDC_TESTNET_ASA_ID); // Algorand Testnet USDC + } + }); + }); +}); diff --git a/typescript/packages/mechanisms/avm/test/unit/index.test.ts b/typescript/packages/mechanisms/avm/test/unit/index.test.ts new file mode 100644 index 0000000000..28b0a06b11 --- /dev/null +++ b/typescript/packages/mechanisms/avm/test/unit/index.test.ts @@ -0,0 +1,100 @@ +import { describe, it, expect } from "vitest"; +import { + ALGORAND_MAINNET_CAIP2, + ALGORAND_TESTNET_CAIP2, + USDC_MAINNET_ASA_ID, + USDC_TESTNET_ASA_ID, + isValidAlgorandAddress, + isAlgorandNetwork, + isTestnetNetwork, + convertToTokenAmount, + convertFromTokenAmount, + isExactAvmPayload, +} from "../../src"; + +describe("@x402/avm", () => { + describe("constants", () => { + it("should export correct CAIP-2 network identifiers", () => { + expect(ALGORAND_MAINNET_CAIP2).toBe("algorand:wGHE2Pwdvd7S12BL5FaOP20EGYesN73ktiC1qzkkit8="); + expect(ALGORAND_TESTNET_CAIP2).toBe("algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="); + }); + + it("should export correct USDC ASA IDs", () => { + expect(USDC_MAINNET_ASA_ID).toBe("31566704"); + expect(USDC_TESTNET_ASA_ID).toBe("10458941"); + }); + }); + + describe("isValidAlgorandAddress", () => { + it("should return true for valid Algorand addresses", () => { + // Valid Algorand address (58 characters base32) + const validAddress = "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ"; + expect(isValidAlgorandAddress(validAddress)).toBe(true); + }); + + it("should return false for invalid Algorand addresses", () => { + expect(isValidAlgorandAddress("invalid")).toBe(false); + expect(isValidAlgorandAddress("0x1234")).toBe(false); + expect(isValidAlgorandAddress("")).toBe(false); + }); + }); + + describe("isAlgorandNetwork", () => { + it("should return true for CAIP-2 Algorand networks", () => { + expect(isAlgorandNetwork(ALGORAND_MAINNET_CAIP2)).toBe(true); + expect(isAlgorandNetwork(ALGORAND_TESTNET_CAIP2)).toBe(true); + expect(isAlgorandNetwork("algorand:some-hash")).toBe(true); + }); + + it("should return false for non-Algorand networks", () => { + expect(isAlgorandNetwork("eip155:1")).toBe(false); + expect(isAlgorandNetwork("solana:mainnet")).toBe(false); + }); + }); + + describe("isTestnetNetwork", () => { + it("should return true for testnet networks", () => { + expect(isTestnetNetwork(ALGORAND_TESTNET_CAIP2)).toBe(true); + }); + + it("should return false for mainnet networks", () => { + expect(isTestnetNetwork(ALGORAND_MAINNET_CAIP2)).toBe(false); + }); + }); + + describe("token amount conversion", () => { + it("should convert decimal to token amount", () => { + expect(convertToTokenAmount("1.50", 6)).toBe("1500000"); + expect(convertToTokenAmount("0.10", 6)).toBe("100000"); + expect(convertToTokenAmount("100", 6)).toBe("100000000"); + expect(convertToTokenAmount("0.000001", 6)).toBe("1"); + }); + + it("should convert token amount to decimal", () => { + expect(convertFromTokenAmount("1500000", 6)).toBe("1.5"); + expect(convertFromTokenAmount("100000", 6)).toBe("0.1"); + expect(convertFromTokenAmount("100000000", 6)).toBe("100"); + expect(convertFromTokenAmount("1", 6)).toBe("0.000001"); + }); + }); + + describe("isExactAvmPayload", () => { + it("should return true for valid payloads", () => { + const validPayload = { + paymentGroup: ["base64encoded1", "base64encoded2"], + paymentIndex: 1, + }; + expect(isExactAvmPayload(validPayload)).toBe(true); + }); + + it("should return false for invalid payloads", () => { + expect(isExactAvmPayload(null)).toBe(false); + expect(isExactAvmPayload(undefined)).toBe(false); + expect(isExactAvmPayload({})).toBe(false); + expect(isExactAvmPayload({ paymentGroup: [] })).toBe(false); + expect(isExactAvmPayload({ paymentIndex: 0 })).toBe(false); + expect(isExactAvmPayload({ paymentGroup: "not-array", paymentIndex: 0 })).toBe(false); + expect(isExactAvmPayload({ paymentGroup: [], paymentIndex: "0" })).toBe(false); + }); + }); +}); diff --git a/typescript/packages/mechanisms/avm/test/unit/signer.test.ts b/typescript/packages/mechanisms/avm/test/unit/signer.test.ts new file mode 100644 index 0000000000..395760df1a --- /dev/null +++ b/typescript/packages/mechanisms/avm/test/unit/signer.test.ts @@ -0,0 +1,208 @@ +import { describe, it, expect } from "vitest"; +import { + toClientAvmSigner, + toFacilitatorAvmSigner, + getAlgokitSigner, + isAvmSignerWallet, + ALGOKIT_SIGNER, +} from "../../src"; +import type { ClientAvmSigner } from "../../src"; + +// Generate a valid test key: 32-byte seed + 32-byte public key = 64 bytes, base64 encoded +// This is a throwaway test key — not used on any network +const TEST_PRIVATE_KEY_BASE64 = + "mZHHvLfOqJrIxIMTYPFdGWxfZy1MtaT3J6aJny+4yW1jkF6o6oKpKU7m5JfNdghc26oLTvRnEEBkDjY14WU3Cw=="; + +describe("AVM Signer", () => { + describe("toClientAvmSigner", () => { + it("should create a client signer from a valid Base64 private key", () => { + const signer = toClientAvmSigner(TEST_PRIVATE_KEY_BASE64); + + expect(signer).toBeDefined(); + expect(signer.address).toBeDefined(); + expect(typeof signer.address).toBe("string"); + expect(signer.address.length).toBe(58); // Algorand address length + }); + + it("should derive a consistent address from the same key", () => { + const signer1 = toClientAvmSigner(TEST_PRIVATE_KEY_BASE64); + const signer2 = toClientAvmSigner(TEST_PRIVATE_KEY_BASE64); + + expect(signer1.address).toBe(signer2.address); + }); + + it("should have a working signTransactions method", () => { + const signer = toClientAvmSigner(TEST_PRIVATE_KEY_BASE64); + + expect(signer.signTransactions).toBeDefined(); + expect(typeof signer.signTransactions).toBe("function"); + }); + + it("should throw for invalid private key (wrong length)", () => { + expect(() => toClientAvmSigner("dG9vc2hvcnQ=")).toThrow( + "AVM private key must be a Base64-encoded 64-byte key", + ); + }); + + it("should throw for invalid private key (not base64)", () => { + expect(() => toClientAvmSigner("not-valid-base64!!!")).toThrow(); + }); + + it("should throw for empty string", () => { + expect(() => toClientAvmSigner("")).toThrow(); + }); + + it("should attach internal algokit signer via ALGOKIT_SIGNER symbol", () => { + const signer = toClientAvmSigner(TEST_PRIVATE_KEY_BASE64); + + // The symbol property should exist but not be enumerable + const symbolKeys = Object.getOwnPropertySymbols(signer); + expect(symbolKeys).toContain(ALGOKIT_SIGNER); + + // Should not appear in regular enumeration + expect(Object.keys(signer)).not.toContain(ALGOKIT_SIGNER.toString()); + }); + }); + + describe("toFacilitatorAvmSigner", () => { + it("should create a facilitator signer from a valid Base64 private key", () => { + const signer = toFacilitatorAvmSigner(TEST_PRIVATE_KEY_BASE64); + + expect(signer).toBeDefined(); + }); + + it("should return correct addresses", () => { + const signer = toFacilitatorAvmSigner(TEST_PRIVATE_KEY_BASE64); + const addresses = signer.getAddresses(); + + expect(addresses).toHaveLength(1); + expect(typeof addresses[0]).toBe("string"); + expect(addresses[0].length).toBe(58); + }); + + it("should derive the same address as toClientAvmSigner for the same key", () => { + const clientSigner = toClientAvmSigner(TEST_PRIVATE_KEY_BASE64); + const facilitatorSigner = toFacilitatorAvmSigner(TEST_PRIVATE_KEY_BASE64); + + expect(facilitatorSigner.getAddresses()[0]).toBe(clientSigner.address); + }); + + it("should implement all required interface methods", () => { + const signer = toFacilitatorAvmSigner(TEST_PRIVATE_KEY_BASE64); + + expect(signer.getAddresses).toBeDefined(); + expect(signer.signTransaction).toBeDefined(); + expect(signer.getAlgodClient).toBeDefined(); + expect(signer.simulateTransactions).toBeDefined(); + expect(signer.sendTransactions).toBeDefined(); + expect(signer.waitForConfirmation).toBeDefined(); + }); + + it("should accept custom URL configuration", () => { + const signer = toFacilitatorAvmSigner(TEST_PRIVATE_KEY_BASE64, { + testnetUrl: "https://custom-testnet.example.com", + mainnetUrl: "https://custom-mainnet.example.com", + algodToken: "custom-token", + }); + + expect(signer).toBeDefined(); + expect(signer.getAddresses()).toHaveLength(1); + }); + + it("should work with default config (no custom URLs)", () => { + const signer = toFacilitatorAvmSigner(TEST_PRIVATE_KEY_BASE64); + + expect(signer).toBeDefined(); + // getAlgodClient should return an algod client using AlgorandClient defaults + const algod = signer.getAlgodClient("algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI="); + expect(algod).toBeDefined(); + }); + + it("should throw for invalid private key", () => { + expect(() => toFacilitatorAvmSigner("dG9vc2hvcnQ=")).toThrow( + "AVM private key must be a Base64-encoded 64-byte key", + ); + }); + }); + + describe("getAlgokitSigner", () => { + it("should return AddressWithTransactionSigner for toClientAvmSigner-created signers", () => { + const signer = toClientAvmSigner(TEST_PRIVATE_KEY_BASE64); + const algokitSigner = getAlgokitSigner(signer); + + expect(algokitSigner).not.toBeNull(); + expect(algokitSigner!.addr).toBeDefined(); + expect(algokitSigner!.signer).toBeDefined(); + expect(typeof algokitSigner!.signer).toBe("function"); + expect(algokitSigner!.addr.toString()).toBe(signer.address); + }); + + it("should return null for manually created signers (e.g., wallet adapters)", () => { + const manualSigner: ClientAvmSigner = { + address: "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAY5HFKQ", + signTransactions: async (txns, indexesToSign) => { + return txns.map((_, i) => { + if (indexesToSign && !indexesToSign.includes(i)) return null; + return new Uint8Array([0]); + }); + }, + }; + + const algokitSigner = getAlgokitSigner(manualSigner); + expect(algokitSigner).toBeNull(); + }); + + it("should return null for objects without the ALGOKIT_SIGNER symbol", () => { + const fakeSigner = { + address: "SOME_ADDRESS", + signTransactions: async () => [], + } as ClientAvmSigner; + + expect(getAlgokitSigner(fakeSigner)).toBeNull(); + }); + }); + + describe("isAvmSignerWallet", () => { + it("should return true for valid ClientAvmSigner objects", () => { + const signer = toClientAvmSigner(TEST_PRIVATE_KEY_BASE64); + expect(isAvmSignerWallet(signer)).toBe(true); + }); + + it("should return true for manually created objects with correct shape", () => { + const manual = { + address: "SOME_ADDRESS", + signTransactions: async () => [], + }; + expect(isAvmSignerWallet(manual)).toBe(true); + }); + + it("should return false for null", () => { + expect(isAvmSignerWallet(null)).toBe(false); + }); + + it("should return false for undefined", () => { + expect(isAvmSignerWallet(undefined)).toBe(false); + }); + + it("should return false for objects missing address", () => { + expect(isAvmSignerWallet({ signTransactions: async () => [] })).toBe(false); + }); + + it("should return false for objects missing signTransactions", () => { + expect(isAvmSignerWallet({ address: "test" })).toBe(false); + }); + + it("should return false for objects with wrong types", () => { + expect(isAvmSignerWallet({ address: 123, signTransactions: async () => [] })).toBe(false); + expect(isAvmSignerWallet({ address: "test", signTransactions: "not-a-function" })).toBe( + false, + ); + }); + + it("should return false for primitive values", () => { + expect(isAvmSignerWallet("string")).toBe(false); + expect(isAvmSignerWallet(42)).toBe(false); + expect(isAvmSignerWallet(true)).toBe(false); + }); + }); +}); diff --git a/typescript/packages/mechanisms/avm/test/unit/types.test.ts b/typescript/packages/mechanisms/avm/test/unit/types.test.ts new file mode 100644 index 0000000000..40e6bab382 --- /dev/null +++ b/typescript/packages/mechanisms/avm/test/unit/types.test.ts @@ -0,0 +1,98 @@ +import { describe, it, expect } from "vitest"; +import { isExactAvmPayload } from "../../src"; +import type { ExactAvmPayloadV2 } from "../../src"; + +describe("AVM Types", () => { + describe("ExactAvmPayloadV2", () => { + it("should accept valid payload with payment group and index", () => { + const payload: ExactAvmPayloadV2 = { + paymentGroup: ["base64encoded1", "base64encoded2"], + paymentIndex: 1, + }; + + expect(payload.paymentGroup).toHaveLength(2); + expect(payload.paymentIndex).toBe(1); + }); + + it("should accept payload with single transaction", () => { + const payload: ExactAvmPayloadV2 = { + paymentGroup: ["singleTransaction"], + paymentIndex: 0, + }; + + expect(payload.paymentGroup).toHaveLength(1); + expect(payload.paymentIndex).toBe(0); + }); + + it("should accept payload with long base64 strings", () => { + const longBase64 = "A".repeat(1000) + "=="; + const payload: ExactAvmPayloadV2 = { + paymentGroup: [longBase64], + paymentIndex: 0, + }; + + expect(payload.paymentGroup[0]).toBe(longBase64); + expect(payload.paymentGroup[0].length).toBe(1002); + }); + }); + + describe("isExactAvmPayload", () => { + it("should return true for valid payloads", () => { + expect( + isExactAvmPayload({ + paymentGroup: ["tx1", "tx2"], + paymentIndex: 1, + }), + ).toBe(true); + }); + + it("should return true for single-transaction payload", () => { + expect( + isExactAvmPayload({ + paymentGroup: ["tx1"], + paymentIndex: 0, + }), + ).toBe(true); + }); + + it("should return false for null", () => { + expect(isExactAvmPayload(null)).toBe(false); + }); + + it("should return false for undefined", () => { + expect(isExactAvmPayload(undefined)).toBe(false); + }); + + it("should return false for empty object", () => { + expect(isExactAvmPayload({})).toBe(false); + }); + + it("should return false when paymentGroup is missing", () => { + expect(isExactAvmPayload({ paymentIndex: 0 })).toBe(false); + }); + + it("should return false when paymentIndex is missing", () => { + expect(isExactAvmPayload({ paymentGroup: ["tx1"] })).toBe(false); + }); + + it("should return false when paymentGroup is not an array", () => { + expect(isExactAvmPayload({ paymentGroup: "not-array", paymentIndex: 0 })).toBe(false); + }); + + it("should return false when paymentIndex is not a number", () => { + expect(isExactAvmPayload({ paymentGroup: ["tx1"], paymentIndex: "0" })).toBe(false); + }); + + it("should accept empty paymentGroup (valid structure)", () => { + // An empty paymentGroup is structurally valid per the type guard + // (the facilitator will reject it at verification time) + expect(isExactAvmPayload({ paymentGroup: [], paymentIndex: 0 })).toBe(true); + }); + + it("should return false for primitive values", () => { + expect(isExactAvmPayload("string")).toBe(false); + expect(isExactAvmPayload(42)).toBe(false); + expect(isExactAvmPayload(true)).toBe(false); + }); + }); +}); diff --git a/typescript/packages/mechanisms/avm/tsconfig.json b/typescript/packages/mechanisms/avm/tsconfig.json new file mode 100644 index 0000000000..1fa3e6b51c --- /dev/null +++ b/typescript/packages/mechanisms/avm/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "lib": ["ES2020"], + "allowJs": false, + "checkJs": false + }, + "include": ["src", "test/index.test.ts"] +} diff --git a/typescript/packages/mechanisms/avm/tsup.config.ts b/typescript/packages/mechanisms/avm/tsup.config.ts new file mode 100644 index 0000000000..1143bfeaf5 --- /dev/null +++ b/typescript/packages/mechanisms/avm/tsup.config.ts @@ -0,0 +1,30 @@ +import { defineConfig } from "tsup"; + +const baseConfig = { + entry: { + index: "src/index.ts", + "exact/client/index": "src/exact/client/index.ts", + "exact/server/index": "src/exact/server/index.ts", + "exact/facilitator/index": "src/exact/facilitator/index.ts", + }, + dts: { + resolve: true, + }, + sourcemap: true, + target: "es2020", +}; + +export default defineConfig([ + { + ...baseConfig, + format: "esm", + outDir: "dist/esm", + clean: true, + }, + { + ...baseConfig, + format: "cjs", + outDir: "dist/cjs", + clean: false, + }, +]); diff --git a/typescript/packages/mechanisms/avm/vitest.config.ts b/typescript/packages/mechanisms/avm/vitest.config.ts new file mode 100644 index 0000000000..ce2ed4375c --- /dev/null +++ b/typescript/packages/mechanisms/avm/vitest.config.ts @@ -0,0 +1,15 @@ +import { loadEnv } from "vite"; +import { defineConfig } from "vitest/config"; +import tsconfigPaths from "vite-tsconfig-paths"; + +export default defineConfig(({ mode }) => ({ + test: { + env: loadEnv(mode, process.cwd(), ""), + exclude: [ + "**/node_modules/**", + "**/dist/**", + "**/test/integrations/**", // Exclude integration tests from default run + ], + }, + plugins: [tsconfigPaths({ projects: ["."] })], +})); diff --git a/typescript/packages/mechanisms/avm/vitest.integration.config.ts b/typescript/packages/mechanisms/avm/vitest.integration.config.ts new file mode 100644 index 0000000000..4713c67427 --- /dev/null +++ b/typescript/packages/mechanisms/avm/vitest.integration.config.ts @@ -0,0 +1,11 @@ +import { loadEnv } from "vite"; +import { defineConfig } from "vitest/config"; +import tsconfigPaths from "vite-tsconfig-paths"; + +export default defineConfig(({ mode }) => ({ + test: { + env: loadEnv(mode, process.cwd(), ""), + include: ["**/test/integrations/**/*.test.ts"], + }, + plugins: [tsconfigPaths({ projects: ["."] })], +})); diff --git a/typescript/packages/mechanisms/evm/CHANGELOG.md b/typescript/packages/mechanisms/evm/CHANGELOG.md index 19e9a93d82..7f4608c5bd 100644 --- a/typescript/packages/mechanisms/evm/CHANGELOG.md +++ b/typescript/packages/mechanisms/evm/CHANGELOG.md @@ -1,5 +1,71 @@ # @x402/evm Changelog +## 2.12.0 + +### Minor Changes + +- 45d7d19: Implemented batch-settlement mechanism +- e7150b3: Add Radius Network (chain ID 723487) and Radius Testnet (chain ID 72344) support with SBC as the default stablecoin +- ee7c156: chore: tighten viem dependency floor to ^2.48.11 + + Raises the viem floor in every `@x402/*` package.json that lists viem as a direct dep so future `pnpm install` re-resolutions cannot regress below this version. Fixes the incomplete tightening from #2013. + +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] + - @x402/core@2.12.0 + +## 2.11.0 + +### Minor Changes + +- 032295b: fix(paywall): use dynamic token decimals instead of hardcoding 6 + + The EVM paywall no longer assumes all tokens have 6 decimal places. Server-side amount conversion in `evmPaywall.generateHtml`: + + - Resolves the token's decimal precision via a new `getDefaultTokenDecimals` helper that looks up the network in `@x402/evm`'s `DEFAULT_STABLECOINS` registry — the same source the scheme `getAssetDecimals` methods read from and the inline scheme dispatch in `@x402/core`'s `x402ResourceServer` uses. Falls back to 6 (USDC default) when the network is unknown. + - Replaces the lossy `parseFloat(amount) / 10**decimals` math with `Number(formatUnits(BigInt(amount), decimals))`, preserving precision through the atomic-to-display conversion. + + `@x402/evm` now publicly re-exports `DEFAULT_STABLECOINS` from `./shared/defaultAssets` so consumers can read the canonical default-asset registry directly. + +### Patch Changes + +- dc04108: Fixed a bug affecting USD prices with 7+ decimal places of precision (e.g. `$0.0000001` or smaller). +- Updated dependencies [a051f48] +- Updated dependencies [dc04108] + - @x402/core@2.11.0 + +## 2.10.0 + +### Minor Changes + +- 9424291: chore: bump viem lockfile to 2.47.12 + + Updates the resolved viem version across all direct dependencies, adding chain definitions for Mezo Testnet, MegaETH, Stable, and Stable Testnet that were missing from previously locked versions. + + - @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 8c80edd: Add Polygon mainnet (chain ID 137) support with USDC as the default stablecoin +- bbe45f5: Add Stable mainnet (chain ID 988) support with USDT0 as the default stablecoin +- bff876d: Add Stable testnet (chain ID 2201) support with USDT0 as the default stablecoin +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization +- d352574: Add upto payment scheme TypeScript SDK with client, facilitator, and server support for permit2-based "up to" payments on EVM chains. + +### Patch Changes + +- 9f52f9c: Add Arbitrum One (chain ID 42161) and Arbitrum Sepolid (chain ID 421614) support with USDC as the default stablecoin +- 011e680: Add Mezo Testnet (chain ID 31611) support with mUSD as the default stablecoin +- ad2658a: Updated x402UptoPermit2Proxy canonical address to 0x4020A4f3b7b90ccA423B9fabCc0CE57C6C240002, deployed with deterministic bytecode for reproducible cross-chain CREATE2 addresses +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/mechanisms/evm/README.md b/typescript/packages/mechanisms/evm/README.md index 7fb2af2849..58353c03ae 100644 --- a/typescript/packages/mechanisms/evm/README.md +++ b/typescript/packages/mechanisms/evm/README.md @@ -1,4 +1,4 @@ -# @x402/evm +# `@x402/evm` [![npm version](https://img.shields.io/npm/v/%40x402%2Fevm.svg)](https://www.npmjs.com/package/@x402/evm) EVM (Ethereum Virtual Machine) implementation of the x402 payment protocol using the **Exact** payment scheme with EIP-3009 TransferWithAuthorization. @@ -145,7 +145,7 @@ Supports two asset transfer methods: - **EIP-3009**: Tokens with native `transferWithAuthorization()` (e.g., USDC, EURC) — simplest, truly gasless - **Permit2**: Any ERC-20 token — universal fallback, requires one-time approval -See [DEFAULT_ASSET.md](src/exact/server/DEFAULT_ASSET.md) for the current list of configured chains and how to add new ones. +For the current list of chains with default assets configured, see [Default Assets for Dollar-String Pricing](../../../../docs/core-concepts/network-and-token-support.mdx#default-assets-for-dollar-string-pricing) in the x402 docs. To add default asset support for a new chain, see [Adding Support for New Networks](../../../../docs/core-concepts/network-and-token-support.mdx#adding-support-for-new-networks). ## Development diff --git a/typescript/packages/mechanisms/evm/package.json b/typescript/packages/mechanisms/evm/package.json index ffceb6cfbf..d4e4624beb 100644 --- a/typescript/packages/mechanisms/evm/package.json +++ b/typescript/packages/mechanisms/evm/package.json @@ -1,6 +1,6 @@ { "name": "@x402/evm", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/cjs/index.d.ts", @@ -24,8 +24,8 @@ "ethereum" ], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol EVM Implementation", "devDependencies": { "@eslint/js": "^9.24.0", @@ -38,7 +38,7 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", @@ -46,7 +46,7 @@ }, "dependencies": { "@x402/core": "workspace:~", - "viem": "^2.39.3", + "viem": "^2.48.11", "zod": "^3.24.2" }, "exports": { @@ -149,6 +149,36 @@ "types": "./dist/cjs/upto/facilitator/index.d.ts", "default": "./dist/cjs/upto/facilitator/index.js" } + }, + "./batch-settlement/client": { + "import": { + "types": "./dist/esm/batch-settlement/client/index.d.mts", + "default": "./dist/esm/batch-settlement/client/index.mjs" + }, + "require": { + "types": "./dist/cjs/batch-settlement/client/index.d.ts", + "default": "./dist/cjs/batch-settlement/client/index.js" + } + }, + "./batch-settlement/server": { + "import": { + "types": "./dist/esm/batch-settlement/server/index.d.mts", + "default": "./dist/esm/batch-settlement/server/index.mjs" + }, + "require": { + "types": "./dist/cjs/batch-settlement/server/index.d.ts", + "default": "./dist/cjs/batch-settlement/server/index.js" + } + }, + "./batch-settlement/facilitator": { + "import": { + "types": "./dist/esm/batch-settlement/facilitator/index.d.mts", + "default": "./dist/esm/batch-settlement/facilitator/index.mjs" + }, + "require": { + "types": "./dist/cjs/batch-settlement/facilitator/index.d.ts", + "default": "./dist/cjs/batch-settlement/facilitator/index.js" + } } }, "files": [ diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/README.md b/typescript/packages/mechanisms/evm/src/batch-settlement/README.md new file mode 100644 index 0000000000..1ae4de5949 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/README.md @@ -0,0 +1,223 @@ +# Batch-Settlement EVM Scheme (`@x402/evm/batch-settlement`) + +The **batch-settlement** scheme enables high-throughput, low-cost EVM payments via **stateless unidirectional payment channels**. Clients deposit funds into an onchain escrow once, then sign off-chain **cumulative vouchers** per request. Servers verify vouchers with a fast signature check and claim them onchain in batches. + +A single claim transaction can cover many channels at once, and claimed funds are swept to the receiver in a separate `settle` step. The scheme also supports **dynamic pricing**: the client authorizes a max per-request and the server charges only what was actually used. + +See the [scheme specification](https://github.com/x402-foundation/x402/blob/main/specs/schemes/batch-settlement/scheme_batch_settlement_evm.md) for full protocol details. + +## Import Paths + +| Role | Import | +|------|--------| +| Client | `@x402/evm/batch-settlement/client` | +| Server | `@x402/evm/batch-settlement/server` | +| Facilitator | `@x402/evm/batch-settlement/facilitator` | + +## Client Usage + +Register `BatchSettlementEvmScheme` with an `x402Client`. The client handles deposits, voucher signing, channel-state recovery, and corrective 402 resync. + +```typescript +import { x402Client } from "@x402/core/client"; +import { toClientEvmSigner } from "@x402/evm"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/client"; +import { privateKeyToAccount } from "viem/accounts"; +import { createPublicClient, http } from "viem"; +import { baseSepolia } from "viem/chains"; + +const account = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`); +const publicClient = createPublicClient({ chain: baseSepolia, transport: http() }); +const signer = toClientEvmSigner(account, publicClient); + +const scheme = new BatchSettlementEvmScheme(signer, { + depositPolicy: { depositMultiplier: 5 }, +}); + +const client = new x402Client(); +client.register("eip155:*", scheme); +``` + +### Deposit Policy + +Controls how much the client deposits when the channel needs funding or top-up: + +| Field | Description | +|-------|-------------| +| `depositMultiplier` | Per-request `amount × multiplier` is deposited (default 5, minimum 3) | + +Use `depositStrategy` for app-specific deposit decisions. The strategy can: + +- Return `undefined` to use the SDK default deposit amount. +- Return `false` to skip this deposit attempt. +- Return a base-unit string or bigint to choose a custom amount. The amount must cover the next voucher. + +```typescript +const maxDeposit = 1_000_000n; + +const scheme = new BatchSettlementEvmScheme(signer, { + depositPolicy: { depositMultiplier: 5 }, + depositStrategy: ({ depositAmount }) => { + const amount = BigInt(depositAmount); + return amount > maxDeposit ? maxDeposit : undefined; + }, +}); +``` + +### Voucher Signer Delegation + +By default, vouchers are signed by the same key as the payer. For better performance — especially when the payer is a **smart wallet** (EIP-1271) — delegate voucher signing to a dedicated EOA. The scheme commits this address as the channel's `payerAuthorizer`, so the facilitator can verify vouchers via fast ECDSA recovery instead of an onchain `isValidSignature` RPC. + +```typescript +const voucherSigner = toClientEvmSigner(privateKeyToAccount(VOUCHER_KEY)); +const scheme = new BatchSettlementEvmScheme(signer, { voucherSigner }); +``` + +### Cooperative Refund + +Trigger a cooperative refund request: + +```typescript +// Full refund: refunds the remaining channel balance. +const settle = await scheme.refund("https://api.example.com/any-protected-route"); + +// Partial refund: +await scheme.refund(url, { amount: "1000000" }); +``` + +The server claims any outstanding vouchers and then executes `refundWithSignature` to return `balance - totalClaimed` or `amount` to the payer. + +### Persistence + +By default, channel state is stored in memory. For long-lived clients, use `FileClientChannelStorage`: + +```typescript +import { FileClientChannelStorage } from "@x402/evm/batch-settlement/client"; + +const scheme = new BatchSettlementEvmScheme(signer, { + storage: new FileClientChannelStorage({ directory: "./channels" }), +}); +``` + +If state is lost, the client recovers from onchain `channels(channelId)` plus corrective 402s — see the spec's *Recovery After State Loss* section. + +## Server Usage + +Register the scheme with an `x402ResourceServer` and pair it with a `ChannelManager` to handle batched claims, settlements, and refunds. + +```typescript +import { x402ResourceServer } from "@x402/core/server"; +import { + BatchSettlementEvmScheme, + FileChannelStorage, + RedisChannelStorage, +} from "@x402/evm/batch-settlement/server"; + +const scheme = new BatchSettlementEvmScheme(receiverAddress, { + receiverAuthorizerSigner, // optional: self-managed authorizer (recommended) + withdrawDelay: 900, // 15 min – 30 days + storage: new FileChannelStorage({ directory: "./channels" }), +}); + +const server = new x402ResourceServer(facilitatorClient).register("eip155:84532", scheme); + +const manager = scheme.createChannelManager(facilitatorClient, "eip155:84532"); +manager.start({ + claimIntervalSecs: 60, + settleIntervalSecs: 300, + refundIntervalSecs: 3600, + selectClaimChannels: channels => channels, + selectRefundChannels: channels => + channels.filter(channel => Date.now() - channel.lastRequestTimestamp >= 3_600_000), +}); +``` + +For serverless deployments or multi-instance servers, use Redis/Valkey-backed storage so channel updates survive cold starts and are atomic across processes: + +```typescript +const scheme = new BatchSettlementEvmScheme(receiverAddress, { + storage: new RedisChannelStorage({ client: redisClient }), +}); +``` + +Use the same `selectClaimChannels` policy with one-shot cron jobs when you need to claim a specific channel subset: + +```typescript +const selectedChannelIds = new Set(["0x..."]); + +await manager.claimAndSettle({ + maxClaimsPerBatch: 100, + selectClaimChannels: channels => + channels.filter(channel => selectedChannelIds.has(channel.channelId.toLowerCase())), +}); +``` + +### Receiver Authorizer + +The `receiverAuthorizer` signs `ClaimBatch` and `Refund` EIP-712 messages and is committed into the channel's identity at deposit time: + +- **Self-managed** (recommended): pass a `receiverAuthorizerSigner` (an EOA you control). Channels survive facilitator changes — any facilitator can relay your signed claims and refunds. +- **Facilitator-delegated**: omit `receiverAuthorizerSigner`. The scheme picks up `extra.receiverAuthorizer` advertised by the facilitator's `/supported`. Switching facilitators requires opening **new channels**, so claim and refund existing channels first with. + +### Pricing + +Set the route `price` to the per-request maximum. To bill less than the max, override at handler time: + +```typescript +import { setSettlementOverrides } from "@x402/express"; + +app.get("/api/generate", (req, res) => { + const actualUsage = computeCost(); + setSettlementOverrides(res, { amount: String(actualUsage) }); + res.json({ result: "..." }); +}); +``` + +`amount` accepts raw atomic units, percentages (`"50%"`), or dollar prices (`"$0.001"`). + +## Facilitator Usage + +```typescript +import { x402Facilitator } from "@x402/core/facilitator"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/facilitator"; + +const facilitator = new x402Facilitator().register( + "eip155:84532", + new BatchSettlementEvmScheme(evmSigner, authorizerSigner), +); +``` + +The `authorizerSigner` produces the EIP-712 signatures advertised in `/supported.kinds[].extra.receiverAuthorizer`. Servers may delegate to it (see above) or supply their own. The `evmSigner` (the wallet account) submits transactions for `deposit`, `claimWithSignature`, `settle`, and `refundWithSignature` — anyone can submit a valid claim/refund tx, but only the configured signer here will be used by this facilitator. + +## Supported Networks + +| Network | CAIP-2 ID | +|---------|-----------| +| Base Mainnet | `eip155:8453` | +| Base Sepolia | `eip155:84532` | + +Requires the x402 batch-settlement contract deployed on the target network. + +## Asset Transfer Methods + +Deposits use one of two onchain transfer methods, controlled by `extra.assetTransferMethod`: + +| Method | Description | +|--------|-------------| +| `eip3009` | `receiveWithAuthorization` — for tokens that support EIP-3009 (e.g. USDC). Default. | +| `permit2` | Universal fallback for any ERC-20 via Uniswap Permit2. | + +Deposits are sponsored by the facilitator (gasless for the client). + +## Examples + +- [Server example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/batch-settlement) +- [Client example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/batch-settlement) +- [Facilitator example](https://github.com/x402-foundation/x402/tree/main/examples/typescript/facilitator/batch-settlement) +- [Streaming server (SSE, mid-stream voucher renewal)](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/batch-settlement-streaming) + +## See Also + +- [Exact EVM Scheme](../exact/README.md) — fixed-price, no escrow +- [Upto EVM Scheme](../upto/README.md) — usage-based, single-shot +- [Batch-Settlement EVM Scheme Specification](https://github.com/x402-foundation/x402/blob/main/specs/schemes/batch-settlement/scheme_batch_settlement_evm.md) diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/abi.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/abi.ts new file mode 100644 index 0000000000..ee939c5fd7 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/abi.ts @@ -0,0 +1,217 @@ +export const channelConfigComponents = [ + { name: "payer", type: "address" }, + { name: "payerAuthorizer", type: "address" }, + { name: "receiver", type: "address" }, + { name: "receiverAuthorizer", type: "address" }, + { name: "token", type: "address" }, + { name: "withdrawDelay", type: "uint40" }, + { name: "salt", type: "bytes32" }, +] as const; + +const voucherClaimComponents = [ + { + name: "voucher", + type: "tuple", + components: [ + { + name: "channel", + type: "tuple", + components: channelConfigComponents, + }, + { name: "maxClaimableAmount", type: "uint128" }, + ], + }, + { name: "signature", type: "bytes" }, + { name: "totalClaimed", type: "uint128" }, +] as const; + +export const batchSettlementABI = [ + { + type: "function", + name: "multicall", + inputs: [{ name: "data", type: "bytes[]" }], + outputs: [{ name: "results", type: "bytes[]" }], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "deposit", + inputs: [ + { name: "config", type: "tuple", components: channelConfigComponents }, + { name: "amount", type: "uint128" }, + { name: "collector", type: "address" }, + { name: "collectorData", type: "bytes" }, + ], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "claim", + inputs: [{ name: "voucherClaims", type: "tuple[]", components: voucherClaimComponents }], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "claimWithSignature", + inputs: [ + { name: "voucherClaims", type: "tuple[]", components: voucherClaimComponents }, + { name: "authorizerSignature", type: "bytes" }, + ], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "settle", + inputs: [ + { name: "receiver", type: "address" }, + { name: "token", type: "address" }, + ], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "initiateWithdraw", + inputs: [ + { name: "config", type: "tuple", components: channelConfigComponents }, + { name: "amount", type: "uint128" }, + ], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "finalizeWithdraw", + inputs: [{ name: "config", type: "tuple", components: channelConfigComponents }], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "refund", + inputs: [ + { name: "config", type: "tuple", components: channelConfigComponents }, + { name: "amount", type: "uint128" }, + ], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "refundWithSignature", + inputs: [ + { name: "config", type: "tuple", components: channelConfigComponents }, + { name: "amount", type: "uint128" }, + { name: "nonce", type: "uint256" }, + { name: "receiverAuthorizerSignature", type: "bytes" }, + ], + outputs: [], + stateMutability: "nonpayable", + }, + { + type: "function", + name: "getChannelId", + inputs: [{ name: "config", type: "tuple", components: channelConfigComponents }], + outputs: [{ name: "", type: "bytes32" }], + stateMutability: "view", + }, + { + type: "function", + name: "CHANNEL_CONFIG_TYPEHASH", + inputs: [], + outputs: [{ name: "", type: "bytes32" }], + stateMutability: "view", + }, + { + type: "function", + name: "channels", + inputs: [{ name: "channelId", type: "bytes32" }], + outputs: [ + { name: "balance", type: "uint128" }, + { name: "totalClaimed", type: "uint128" }, + ], + stateMutability: "view", + }, + { + type: "function", + name: "pendingWithdrawals", + inputs: [{ name: "channelId", type: "bytes32" }], + outputs: [ + { name: "amount", type: "uint128" }, + { name: "initiatedAt", type: "uint40" }, + ], + stateMutability: "view", + }, + { + type: "function", + name: "receivers", + inputs: [ + { name: "receiver", type: "address" }, + { name: "token", type: "address" }, + ], + outputs: [ + { name: "totalClaimed", type: "uint128" }, + { name: "totalSettled", type: "uint128" }, + ], + stateMutability: "view", + }, + { + type: "function", + name: "getVoucherDigest", + inputs: [ + { name: "channelId", type: "bytes32" }, + { name: "maxClaimableAmount", type: "uint128" }, + ], + outputs: [{ name: "", type: "bytes32" }], + stateMutability: "view", + }, + { + type: "function", + name: "getRefundDigest", + inputs: [ + { name: "channelId", type: "bytes32" }, + { name: "nonce", type: "uint256" }, + { name: "amount", type: "uint128" }, + ], + outputs: [{ name: "", type: "bytes32" }], + stateMutability: "view", + }, + { + type: "function", + name: "refundNonce", + inputs: [{ name: "channelId", type: "bytes32" }], + outputs: [{ name: "", type: "uint256" }], + stateMutability: "view", + }, + { + type: "function", + name: "getClaimBatchDigest", + inputs: [{ name: "voucherClaims", type: "tuple[]", components: voucherClaimComponents }], + outputs: [{ name: "", type: "bytes32" }], + stateMutability: "view", + }, + { + type: "event", + name: "Settled", + inputs: [ + { name: "receiver", type: "address", indexed: true }, + { name: "token", type: "address", indexed: true }, + { name: "sender", type: "address", indexed: true }, + { name: "amount", type: "uint128", indexed: false }, + ], + anonymous: false, + }, +] as const; + +export const erc20BalanceOfABI = [ + { + type: "function", + name: "balanceOf", + inputs: [{ name: "account", type: "address" }], + outputs: [{ name: "", type: "uint256" }], + stateMutability: "view", + }, +] as const; diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/authorizerSigner.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/authorizerSigner.ts new file mode 100644 index 0000000000..9c65ea8f9e --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/authorizerSigner.ts @@ -0,0 +1,66 @@ +import type { AuthorizerSigner, BatchSettlementVoucherClaim } from "./types"; +import { claimBatchTypes, refundTypes } from "./constants"; +import { computeChannelId, getBatchSettlementEip712Domain } from "./utils"; +import { getEvmChainId } from "../utils"; + +/** + * Signs a `ClaimBatch` EIP-712 digest for `claimWithSignature()`. + * + * @param signer - Authorizer signer holding the `receiverAuthorizer` key. + * @param claims - Voucher claims to include in the batch. + * @param network - CAIP-2 network identifier (e.g. `"eip155:84532"`). + * @returns EIP-712 signature over `ClaimBatch(ClaimEntry[] claims)`. + */ +export async function signClaimBatch( + signer: AuthorizerSigner, + claims: BatchSettlementVoucherClaim[], + network: string, +): Promise<`0x${string}`> { + const chainId = getEvmChainId(network); + + const claimEntries = claims.map(c => ({ + channelId: computeChannelId(c.voucher.channel, chainId), + maxClaimableAmount: BigInt(c.voucher.maxClaimableAmount), + totalClaimed: BigInt(c.totalClaimed), + })); + + return signer.signTypedData({ + domain: getBatchSettlementEip712Domain(chainId), + types: claimBatchTypes, + primaryType: "ClaimBatch", + message: { + claims: claimEntries, + }, + }); +} + +/** + * Signs a `Refund` EIP-712 digest for `refundWithSignature()`. + * + * @param signer - Authorizer signer holding the `receiverAuthorizer` key. + * @param channelId - Channel to authorize refund for. + * @param amount - Refund amount (capped to unclaimed escrow onchain). + * @param nonce - Must match onchain `refundNonce(channelId)`. + * @param network - CAIP-2 network identifier (e.g. `"eip155:84532"`). + * @returns EIP-712 signature over `Refund(channelId, nonce, amount)`. + */ +export async function signRefund( + signer: AuthorizerSigner, + channelId: `0x${string}`, + amount: string, + nonce: string, + network: string, +): Promise<`0x${string}`> { + const chainId = getEvmChainId(network); + + return signer.signTypedData({ + domain: getBatchSettlementEip712Domain(chainId), + types: refundTypes, + primaryType: "Refund", + message: { + channelId, + nonce: BigInt(nonce), + amount: BigInt(amount), + }, + }); +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/channel.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/channel.ts new file mode 100644 index 0000000000..a5693a9911 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/channel.ts @@ -0,0 +1,259 @@ +import { decodePaymentResponseHeader } from "@x402/core/http"; +import type { PaymentRequirements, SettleResponse } from "@x402/core/types"; +import { getAddress } from "viem"; +import type { ClientEvmSigner } from "../../signer"; +import { batchSettlementABI } from "../abi"; +import { BATCH_SETTLEMENT_ADDRESS, MIN_WITHDRAW_DELAY } from "../constants"; +import type { + BatchSettlementPaymentRequirementsExtra, + BatchSettlementPaymentResponseExtra, + ChannelConfig, +} from "../types"; +import { computeChannelId } from "../utils"; +import type { BatchSettlementClientContext, ClientChannelStorage } from "./storage"; + +type ResponseChannelState = NonNullable; + +/** + * Reads the nested channel state from a settlement response extra object. + * + * @param extra - Settlement response extra fields. + * @returns Channel state fields, or undefined when absent. + */ +function readResponseChannelState( + extra: Record, +): ResponseChannelState | undefined { + const channelState = extra.channelState; + if (typeof channelState !== "object" || channelState === null) { + return undefined; + } + return channelState as ResponseChannelState; +} + +/** + * Runtime dependency bag shared by every storage-bound client helper (channel, + * recovery, refund) and the {@link BatchSettlementEvmScheme} class. + */ +export interface BatchSettlementClientDeps { + signer: ClientEvmSigner; + storage: ClientChannelStorage; + salt: `0x${string}`; + payerAuthorizer?: `0x${string}`; + voucherSigner?: ClientEvmSigner; +} + +/** + * Constructs the immutable {@link ChannelConfig} from payment requirements and + * a client deps bag (signer, salt, optional payerAuthorizer / voucherSigner). + * + * @param deps - Client identity inputs. + * @param paymentRequirements - Server payment requirements providing receiver, asset, and extra fields. + * @returns The ChannelConfig that uniquely identifies this payment channel. + */ +export function buildChannelConfig( + deps: BatchSettlementClientDeps, + paymentRequirements: PaymentRequirements, +): ChannelConfig { + const extra = paymentRequirements.extra as + | Partial + | undefined; + const receiverAuthorizer = extra?.receiverAuthorizer; + if ( + !receiverAuthorizer || + getAddress(receiverAuthorizer) === "0x0000000000000000000000000000000000000000" + ) { + throw new Error("Payment requirements must include a non-zero extra.receiverAuthorizer"); + } + + return { + payer: deps.signer.address, + payerAuthorizer: getAddress( + deps.payerAuthorizer ?? deps.voucherSigner?.address ?? deps.signer.address, + ), + receiver: paymentRequirements.payTo as `0x${string}`, + receiverAuthorizer: getAddress(receiverAuthorizer), + token: paymentRequirements.asset as `0x${string}`, + withdrawDelay: + typeof extra?.withdrawDelay === "number" ? extra.withdrawDelay : MIN_WITHDRAW_DELAY, + salt: deps.salt, + }; +} + +/** + * Updates local channel state from a parsed `SettleResponse`. + * + * @param storage - Client channel storage. + * @param settle - The parsed settle response. + */ +export async function processSettleResponse( + storage: ClientChannelStorage, + settle: SettleResponse, +): Promise { + const extra = settle.extra ?? {}; + const channelState = readResponseChannelState(extra); + if (!channelState) return; + + const channelId = channelState.channelId; + const key = channelId.toLowerCase(); + + const prev = await storage.get(key); + const next: BatchSettlementClientContext = { ...(prev ?? {}) }; + + if (channelState.chargedCumulativeAmount !== undefined) { + next.chargedCumulativeAmount = String(channelState.chargedCumulativeAmount); + } + if (channelState.balance !== undefined) { + next.balance = String(channelState.balance); + } + if (channelState.totalClaimed !== undefined) { + next.totalClaimed = String(channelState.totalClaimed); + } + + await storage.set(key, next); +} + +/** + * Reconciles local channel state with the outcome of a cooperative refund. + * + * Deletes the channel record when the post-refund balance is zero (full refund), + * otherwise updates local state from the server snapshot. + * + * @param storage - Client channel storage. + * @param channelKey - Lowercased channel id used as the storage key. + * @param settleExtra - The `extra` block from the refund settle response. + */ +export async function updateChannelAfterRefund( + storage: ClientChannelStorage, + channelKey: string, + settleExtra: Record, +): Promise { + const channelState = readResponseChannelState(settleExtra); + if (!channelState) { + await storage.delete(channelKey); + return; + } + + const balanceAfter = + channelState.balance !== undefined ? BigInt(String(channelState.balance)) : undefined; + + if (balanceAfter === undefined || balanceAfter <= 0n) { + await storage.delete(channelKey); + return; + } + + const prev = await storage.get(channelKey); + const next: BatchSettlementClientContext = { ...(prev ?? {}) }; + next.balance = balanceAfter.toString(); + if (channelState.chargedCumulativeAmount !== undefined) { + next.chargedCumulativeAmount = String(channelState.chargedCumulativeAmount); + } + if (channelState.totalClaimed !== undefined) { + next.totalClaimed = String(channelState.totalClaimed); + } + await storage.set(channelKey, next); +} + +/** + * Processes the `PAYMENT-RESPONSE` header after a successful request. + * + * Decodes the header into a `SettleResponse` and delegates to + * {@link processSettleResponse}. + * + * @param storage - Client channel storage. + * @param getHeader - Function to retrieve a response header by name. + */ +export async function processPaymentResponse( + storage: ClientChannelStorage, + getHeader: (name: string) => string | null | undefined, +): Promise { + const raw = getHeader("PAYMENT-RESPONSE"); + if (!raw) return; + + const settle = decodePaymentResponseHeader(raw); + await processSettleResponse(storage, settle); +} + +/** + * Recovers a channel record from onchain state (useful after a cold start or + * channel record loss). + * + * @param deps - Signer + storage + identity inputs. + * @param paymentRequirements - Server payment requirements used to derive the ChannelConfig. + * @returns The recovered client context. + */ +export async function recoverChannel( + deps: BatchSettlementClientDeps, + paymentRequirements: PaymentRequirements, +): Promise { + if (!deps.signer.readContract) { + throw new Error("recoverChannel requires ClientEvmSigner.readContract"); + } + + const config = buildChannelConfig(deps, paymentRequirements); + const channelId = computeChannelId(config, paymentRequirements.network); + + const [chBalance, chTotalClaimed] = await readChannelBalanceAndTotalClaimed( + deps.signer, + channelId, + ); + + const ctx: BatchSettlementClientContext = { + chargedCumulativeAmount: chTotalClaimed.toString(), + balance: chBalance.toString(), + totalClaimed: chTotalClaimed.toString(), + }; + + await deps.storage.set(channelId.toLowerCase(), ctx); + return ctx; +} + +/** + * Reads `channels(channelId)` returning `[balance, totalClaimed]`. + * + * @param signer - Signer providing `readContract`. + * @param channelId - The `bytes32` channel id to query. + * @returns Tuple of `[balance, totalClaimed]` as bigints. + */ +export async function readChannelBalanceAndTotalClaimed( + signer: ClientEvmSigner, + channelId: `0x${string}`, +): Promise<[bigint, bigint]> { + if (!signer.readContract) { + throw new Error("readChannelBalanceAndTotalClaimed requires ClientEvmSigner.readContract"); + } + return (await signer.readContract({ + address: BATCH_SETTLEMENT_ADDRESS, + abi: batchSettlementABI, + functionName: "channels", + args: [channelId], + })) as [bigint, bigint]; +} + +/** + * Returns whether a local channel record exists for the given channel. + * + * @param storage - Client channel storage. + * @param channelId - The channel identifier to check. + * @returns `true` when a channel record is stored. + */ +export async function hasChannel( + storage: ClientChannelStorage, + channelId: string, +): Promise { + const channel = await storage.get(channelId.toLowerCase()); + return channel !== undefined; +} + +/** + * Returns the local channel context for a channel, if present. + * + * @param storage - Client channel storage. + * @param channelId - The channel identifier. + * @returns Stored context or `undefined`. + */ +export async function getChannel( + storage: ClientChannelStorage, + channelId: string, +): Promise { + return storage.get(channelId.toLowerCase()); +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/config.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/config.ts new file mode 100644 index 0000000000..59b8c86116 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/config.ts @@ -0,0 +1,155 @@ +import type { PaymentRequirements } from "@x402/core/types"; +import type { ClientEvmSigner } from "../../signer"; +import type { EvmSchemeOptions } from "../../shared/rpc"; +import type { ChannelConfig } from "../types"; +import { type ClientChannelStorage, InMemoryClientChannelStorage } from "./storage"; +import type { BatchSettlementClientContext } from "./storage"; + +const DEFAULT_SALT = + "0x0000000000000000000000000000000000000000000000000000000000000000" as `0x${string}`; + +/** + * Caller-tunable policy controlling how the client sizes channel deposits. + */ +export interface BatchSettlementDepositPolicy { + depositMultiplier?: number; +} + +/** + * Return shape for custom deposit sizing. + */ +export type BatchSettlementDepositStrategyResult = string | bigint | false | undefined; + +/** + * Information supplied before the client signs a deposit authorization. + */ +export interface BatchSettlementDepositStrategyContext { + paymentRequirements: PaymentRequirements; + channelConfig: ChannelConfig; + channelId: `0x${string}`; + clientContext: BatchSettlementClientContext; + requestAmount: string; + maxClaimableAmount: string; + currentBalance: string; + minimumDepositAmount: string; + depositAmount: string; +} + +/** + * Custom deposit sizing callback for initial deposits and top-ups. + */ +export type BatchSettlementDepositStrategy = ( + context: BatchSettlementDepositStrategyContext, +) => BatchSettlementDepositStrategyResult | Promise; + +/** + * Full options object accepted by `BatchSettlementEvmScheme`. Either this or a + * bare {@link BatchSettlementDepositPolicy} can be passed as the second + * constructor argument. + */ +export interface BatchSettlementEvmSchemeOptions { + depositPolicy?: BatchSettlementDepositPolicy; + /** Optional callback for app-specific deposit sizing or skipping. */ + depositStrategy?: BatchSettlementDepositStrategy; + storage?: ClientChannelStorage; + salt?: `0x${string}`; + payerAuthorizer?: `0x${string}`; + rpcUrl?: string; + /** When set, EIP-712 vouchers are signed with this key; deposits still use the main `signer`. */ + voucherSigner?: ClientEvmSigner; +} + +/** + * Resolved options after merging defaults — used internally by the scheme, + * recovery, and refund modules. + */ +export interface ResolvedClientOptions { + depositPolicy?: BatchSettlementDepositPolicy; + depositStrategy?: BatchSettlementDepositStrategy; + storage: ClientChannelStorage; + salt: `0x${string}`; + payerAuthorizer?: `0x${string}`; + voucherSigner?: ClientEvmSigner; + extensionRpcOptions?: EvmSchemeOptions; +} + +/** + * Discriminates a full options object from a bare deposit-policy object. + * + * @param o - Constructor argument that may be options, deposit policy only, or undefined. + * @returns `true` when `o` is a {@link BatchSettlementEvmSchemeOptions} object. + */ +export function isBatchSettlementEvmSchemeOptions( + o: BatchSettlementEvmSchemeOptions | BatchSettlementDepositPolicy | undefined, +): o is BatchSettlementEvmSchemeOptions { + return ( + o !== undefined && + typeof o === "object" && + ("storage" in o || + "depositPolicy" in o || + "depositStrategy" in o || + "salt" in o || + "payerAuthorizer" in o || + "rpcUrl" in o || + "voucherSigner" in o) + ); +} + +/** + * Normalises the constructor's second argument into a uniform options shape. + * + * @param second - Optional second constructor argument (options or deposit policy). + * @returns Resolved storage, salt, deposit policy, and optional payer authorizer. + */ +export function resolveClientOptions( + second?: BatchSettlementEvmSchemeOptions | BatchSettlementDepositPolicy, +): ResolvedClientOptions { + if (second === undefined) { + return { storage: new InMemoryClientChannelStorage(), salt: DEFAULT_SALT }; + } + if (isBatchSettlementEvmSchemeOptions(second)) { + return { + storage: second.storage ?? new InMemoryClientChannelStorage(), + depositPolicy: second.depositPolicy, + depositStrategy: second.depositStrategy, + salt: second.salt ?? DEFAULT_SALT, + payerAuthorizer: second.payerAuthorizer, + voucherSigner: second.voucherSigner, + extensionRpcOptions: second.rpcUrl ? { rpcUrl: second.rpcUrl } : undefined, + }; + } + return { + storage: new InMemoryClientChannelStorage(), + depositPolicy: second, + salt: DEFAULT_SALT, + }; +} + +/** + * Validates a {@link BatchSettlementDepositPolicy}, throwing on invalid fields. + * + * @param policy - The policy to validate (no-op when undefined). + */ +export function validateDepositPolicy(policy: BatchSettlementDepositPolicy | undefined): void { + if (!policy) return; + + const m = policy.depositMultiplier; + if (m !== undefined && (!Number.isInteger(m) || m < 3)) { + throw new Error("depositMultiplier must be an integer >= 3"); + } +} + +/** + * Computes the deposit amount based on the deposit multiplier. + * + * @param policy - Deposit policy controlling multiplier (may be undefined). + * @param requestAmount - Amount requested for this operation, in token base units. + * @returns Deposit amount string in token base units. + */ +export function depositAmountForRequest( + policy: BatchSettlementDepositPolicy | undefined, + requestAmount: bigint, +): string { + const mult = BigInt(policy?.depositMultiplier ?? 5); + return (mult * requestAmount).toString(); +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/eip3009.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/eip3009.ts new file mode 100644 index 0000000000..6d53b41b80 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/eip3009.ts @@ -0,0 +1,100 @@ +import { PaymentRequirements, PaymentPayloadResult } from "@x402/core/types"; +import { getAddress } from "viem"; +import { ClientEvmSigner } from "../../signer"; +import { ChannelConfig, BatchSettlementDepositPayload } from "../types"; +import { ERC3009_DEPOSIT_COLLECTOR_ADDRESS, receiveAuthorizationTypes } from "../constants"; +import { createNonce, getEvmChainId } from "../../utils"; +import { signVoucher } from "./voucher"; +import { computeChannelId } from "../utils"; +import { buildErc3009DepositNonce } from "../encoding"; + +/** + * Creates a deposit payload that bundles an ERC-3009 `receiveWithAuthorization` approval + * together with a cumulative voucher signature. + * + * When the facilitator submits this payload onchain, the contract atomically transfers + * tokens from the payer into the channel and records the initial voucher. + * + * @param signer - Client wallet used to sign the ERC-3009 authorization (`from` = payer). + * @param x402Version - Protocol version to embed in the payload envelope. + * @param paymentRequirements - Server-provided payment requirements (asset, network, amount, etc.). + * @param channelConfig - Immutable channel configuration (payer, receiver, token, …). + * @param depositAmount - Number of tokens (decimal string) to deposit into the channel. + * @param maxClaimableAmount - Cumulative ceiling for the accompanying voucher. + * @param voucherSigner - Optional key that signs the voucher; defaults to `signer` (same as payer). + * @returns A {@link PaymentPayloadResult} containing the signed deposit + voucher payload. + */ +export async function createBatchSettlementEIP3009DepositPayload( + signer: ClientEvmSigner, + x402Version: number, + paymentRequirements: PaymentRequirements, + channelConfig: ChannelConfig, + depositAmount: string, + maxClaimableAmount: string, + voucherSigner?: ClientEvmSigner, +): Promise { + const salt = createNonce(); + const now = Math.floor(Date.now() / 1000); + const chainId = getEvmChainId(paymentRequirements.network); + + if (!paymentRequirements.extra?.name || !paymentRequirements.extra?.version) { + throw new Error( + `EIP-712 domain parameters (name, version) are required in payment requirements for asset ${paymentRequirements.asset}`, + ); + } + + const { name, version } = paymentRequirements.extra; + + const channelId = computeChannelId(channelConfig, paymentRequirements.network); + + const erc3009Nonce = buildErc3009DepositNonce(channelId, salt); + + const signature = await signer.signTypedData({ + domain: { + name, + version, + chainId, + verifyingContract: getAddress(paymentRequirements.asset), + }, + types: receiveAuthorizationTypes, + primaryType: "ReceiveWithAuthorization", + message: { + from: getAddress(signer.address), + to: getAddress(ERC3009_DEPOSIT_COLLECTOR_ADDRESS), + value: BigInt(depositAmount), + validAfter: BigInt(now - 600), + validBefore: BigInt(now + paymentRequirements.maxTimeoutSeconds), + nonce: erc3009Nonce, + }, + }); + + const vSigner = voucherSigner ?? signer; + const voucher = await signVoucher( + vSigner, + channelId, + maxClaimableAmount, + paymentRequirements.network, + ); + + const payload: BatchSettlementDepositPayload = { + type: "deposit", + channelConfig, + voucher, + deposit: { + amount: depositAmount, + authorization: { + erc3009Authorization: { + validAfter: (now - 600).toString(), + validBefore: (now + paymentRequirements.maxTimeoutSeconds).toString(), + salt, + signature, + }, + }, + }, + }; + + return { + x402Version, + payload, + }; +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/fileStorage.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/fileStorage.ts new file mode 100644 index 0000000000..16e6921c5c --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/fileStorage.ts @@ -0,0 +1,68 @@ +import { unlink } from "node:fs/promises"; +import { join } from "node:path"; + +import { isNodeEnoent, readJsonFile, writeJsonAtomic } from "../storage-utils"; +import type { FileChannelStorageOptions } from "../types"; +import type { ClientChannelStorage, BatchSettlementClientContext } from "./storage"; + +/** + * Node.js file-backed {@link ClientChannelStorage} for the batched client scheme. + * Each channel's context is persisted as `{root}/client/{channelId}.json` so that channel + * records survive process restarts. + */ +export class FileClientChannelStorage implements ClientChannelStorage { + private readonly root: string; + + /** + * Creates file-backed client channel storage under the given root directory. + * + * @param options - Configuration including the storage root directory. + */ + constructor(options: FileChannelStorageOptions) { + this.root = options.directory; + } + + /** + * Loads the stored client context for a channel, if present. + * + * @param key - Channel storage key (typically a lowercased channelId). + * @returns Parsed context or `undefined` when the file is missing. + */ + async get(key: string): Promise { + return readJsonFile(this.filePath(key)); + } + + /** + * Persists the client context for a channel. + * + * @param key - Channel storage key. + * @param context - Context record to write. + */ + async set(key: string, context: BatchSettlementClientContext): Promise { + await writeJsonAtomic(this.filePath(key), context); + } + + /** + * Removes the persisted context file for a channel, if it exists. + * + * @param key - Channel storage key. + */ + async delete(key: string): Promise { + try { + await unlink(this.filePath(key)); + } catch (err: unknown) { + if (isNodeEnoent(err)) return; + throw err; + } + } + + /** + * Absolute path to the JSON file for a channel. + * + * @param key - Channel storage key. + * @returns Filesystem path under `{root}/client/...`. + */ + private filePath(key: string): string { + return join(this.root, "client", `${key.toLowerCase()}.json`); + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/hooks.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/hooks.ts new file mode 100644 index 0000000000..917d99abc6 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/hooks.ts @@ -0,0 +1,55 @@ +import type { PaymentResponseContext } from "@x402/core/client"; +import type { SchemeClientHooks } from "@x402/core/types"; +import { isBatchSettlementRefundPayload } from "../types"; +import type { BatchSettlementClientDeps } from "./channel"; +import { processSettleResponse, updateChannelAfterRefund } from "./channel"; +import { processCorrectivePaymentRequired } from "./recovery"; + +/** + * Creates storage-aware client hooks for batch-settlement payment responses. + * + * @param deps - Client identity and storage inputs. + * @returns Scheme hooks for response reconciliation and corrective recovery. + */ +export function createBatchSettlementClientHooks( + deps: BatchSettlementClientDeps, +): SchemeClientHooks { + return { + onPaymentResponse: ctx => handleBatchSettlementPaymentResponse(deps, ctx), + }; +} + +/** + * Reconciles batch-settlement client state after a paid request or refund attempt. + * + * @param deps - Client identity and storage inputs. + * @param ctx - Core payment response context. + * @returns A recovery signal when corrective recovery succeeds. + */ +export async function handleBatchSettlementPaymentResponse( + deps: BatchSettlementClientDeps, + ctx: PaymentResponseContext, +): Promise { + if (ctx.settleResponse) { + if (isBatchSettlementRefundPayload(ctx.paymentPayload.payload)) { + const extra = ctx.settleResponse.extra ?? {}; + const channelState = extra.channelState; + const channelId = + typeof channelState === "object" && channelState !== null && "channelId" in channelState + ? channelState.channelId + : undefined; + if (typeof channelId === "string" && channelId) { + await updateChannelAfterRefund(deps.storage, channelId.toLowerCase(), extra); + } + return; + } + + await processSettleResponse(deps.storage, ctx.settleResponse); + return; + } + + if (ctx.paymentRequired) { + const recovered = await processCorrectivePaymentRequired(deps, ctx.paymentRequired); + return recovered ? { recovered: true } : undefined; + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/index.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/index.ts new file mode 100644 index 0000000000..8f2e3abce4 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/index.ts @@ -0,0 +1,44 @@ +export { BatchSettlementEvmScheme } from "./scheme"; +export type { + BatchSettlementClientContext, + BatchSettlementDepositPolicy, + BatchSettlementDepositStrategy, + BatchSettlementDepositStrategyContext, + BatchSettlementDepositStrategyResult, + BatchSettlementEvmSchemeOptions, +} from "./scheme"; +export type { ClientChannelStorage } from "./storage"; +export { InMemoryClientChannelStorage } from "./storage"; +export { FileClientChannelStorage } from "./fileStorage"; +export { createBatchSettlementEIP3009DepositPayload } from "./eip3009"; +export { signVoucher } from "./voucher"; +export { refundChannel } from "./refund"; +export type { RefundOptions } from "./refund"; +export { createBatchSettlementClientHooks, handleBatchSettlementPaymentResponse } from "./hooks"; +export { computeChannelId } from "../utils"; + +export { + depositAmountForRequest, + isBatchSettlementEvmSchemeOptions, + resolveClientOptions, + validateDepositPolicy, +} from "./config"; +export type { ResolvedClientOptions } from "./config"; + +export { + buildChannelConfig, + getChannel, + hasChannel, + processPaymentResponse, + processSettleResponse, + readChannelBalanceAndTotalClaimed, + recoverChannel, + updateChannelAfterRefund, +} from "./channel"; +export type { BatchSettlementClientDeps } from "./channel"; + +export { + processCorrectivePaymentRequired, + recoverFromOnChainState, + recoverFromSignature, +} from "./recovery"; diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/permit2.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/permit2.ts new file mode 100644 index 0000000000..cce19d36d9 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/permit2.ts @@ -0,0 +1,92 @@ +import { PaymentRequirements, PaymentPayloadResult } from "@x402/core/types"; +import { getAddress } from "viem"; +import { PERMIT2_ADDRESS } from "../../constants"; +import { ClientEvmSigner } from "../../signer"; +import { createPermit2Nonce, getEvmChainId } from "../../utils"; +import { PERMIT2_DEPOSIT_COLLECTOR_ADDRESS, batchPermit2WitnessTypes } from "../constants"; +import { ChannelConfig, BatchSettlementDepositPayload } from "../types"; +import { computeChannelId } from "../utils"; +import { signVoucher } from "./voucher"; + +/** + * Builds a batch deposit payload using a channel-bound Permit2 witness transfer. + * + * @param signer - Payer signer for the Permit2 authorization. + * @param x402Version - Protocol version for the payment envelope. + * @param paymentRequirements - Server-provided payment requirements. + * @param channelConfig - Channel configuration bound into the voucher and witness. + * @param depositAmount - Token amount deposited into the channel. + * @param maxClaimableAmount - Cumulative amount signed in the voucher. + * @param voucherSigner - Optional signer for the voucher. + * @returns Signed deposit payload and voucher. + */ +export async function createBatchSettlementPermit2DepositPayload( + signer: ClientEvmSigner, + x402Version: number, + paymentRequirements: PaymentRequirements, + channelConfig: ChannelConfig, + depositAmount: string, + maxClaimableAmount: string, + voucherSigner?: ClientEvmSigner, +): Promise { + const chainId = getEvmChainId(paymentRequirements.network); + const nonce = createPermit2Nonce(); + const deadline = Math.floor(Date.now() / 1000 + paymentRequirements.maxTimeoutSeconds).toString(); + const channelId = computeChannelId(channelConfig, paymentRequirements.network); + + const permit2Authorization = { + from: signer.address, + permitted: { + token: getAddress(paymentRequirements.asset), + amount: depositAmount, + }, + spender: getAddress(PERMIT2_DEPOSIT_COLLECTOR_ADDRESS), + nonce, + deadline, + witness: { + channelId, + }, + }; + + const signature = await signer.signTypedData({ + domain: { name: "Permit2", chainId, verifyingContract: PERMIT2_ADDRESS }, + types: batchPermit2WitnessTypes, + primaryType: "PermitWitnessTransferFrom", + message: { + permitted: { + token: permit2Authorization.permitted.token, + amount: BigInt(permit2Authorization.permitted.amount), + }, + spender: permit2Authorization.spender, + nonce: BigInt(permit2Authorization.nonce), + deadline: BigInt(permit2Authorization.deadline), + witness: { + channelId, + }, + }, + }); + + const voucher = await signVoucher( + voucherSigner ?? signer, + channelId, + maxClaimableAmount, + paymentRequirements.network, + ); + + const payload: BatchSettlementDepositPayload = { + type: "deposit", + channelConfig, + voucher, + deposit: { + amount: depositAmount, + authorization: { + permit2Authorization: { + ...permit2Authorization, + signature, + }, + }, + }, + }; + + return { x402Version, payload }; +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/recovery.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/recovery.ts new file mode 100644 index 0000000000..d64b7ba322 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/recovery.ts @@ -0,0 +1,167 @@ +import type { PaymentRequired, PaymentRequirements } from "@x402/core/types"; +import { getAddress, recoverTypedDataAddress } from "viem"; +import { BATCH_SETTLEMENT_SCHEME, voucherTypes } from "../constants"; +import type { BatchSettlementClientContext } from "./storage"; +import { computeChannelId, getBatchSettlementEip712Domain } from "../utils"; +import { getEvmChainId } from "../../utils"; +import { + type BatchSettlementClientDeps, + buildChannelConfig, + readChannelBalanceAndTotalClaimed, +} from "./channel"; +import * as Errors from "../errors"; +import type { BatchSettlementChannelStateExtra, BatchSettlementVoucherStateExtra } from "../types"; + +/** + * Handles a corrective 402 response from the server when the client's + * cumulative base is out of sync. + * + * Validates the server-provided state (chargedCumulativeAmount, + * signedMaxClaimable, signature) against onchain data and the client's own + * signing key, then updates the local channel state if everything checks out. + * + * @param deps - Signer + storage + identity inputs. + * @param paymentRequired - The decoded 402 response body. + * @returns `true` if the channel state was successfully resynced and the request can be retried. + */ +export async function processCorrectivePaymentRequired( + deps: BatchSettlementClientDeps, + paymentRequired: PaymentRequired, +): Promise { + if ( + paymentRequired.error !== Errors.ErrCumulativeAmountMismatch && + paymentRequired.error !== Errors.ErrCumulativeAmountBelowClaimed + ) { + return false; + } + + const accept = paymentRequired.accepts.find(a => a.scheme === BATCH_SETTLEMENT_SCHEME); + if (!accept) { + return false; + } + + const channelState = accept.extra.channelState as BatchSettlementChannelStateExtra | undefined; + const voucherState = accept.extra.voucherState as BatchSettlementVoucherStateExtra | undefined; + const hasSig = + channelState?.chargedCumulativeAmount !== undefined && + voucherState?.signedMaxClaimable !== undefined && + voucherState.signature !== undefined; + + if (!hasSig) { + return recoverFromOnChainState(deps, accept); + } + + return recoverFromSignature(deps, accept, channelState, voucherState); +} + +/** + * Recovers channel state from a corrective 402 that includes a server-provided + * voucher signature. Verifies the signature matches the client's own signing + * key before accepting. + * + * @param deps - Signer + storage + identity inputs. + * @param accept - Batch settlement payment requirements from the corrective 402. + * @param channelState - Server channel snapshot from `accept.extra.channelState`. + * @param voucherState - Latest signed voucher proof from `accept.extra.voucherState`. + * @returns `true` when local channel state was updated successfully. + */ +export async function recoverFromSignature( + deps: BatchSettlementClientDeps, + accept: PaymentRequirements, + channelState: BatchSettlementChannelStateExtra, + voucherState: BatchSettlementVoucherStateExtra, +): Promise { + const chargedRaw = channelState.chargedCumulativeAmount; + const signedRaw = voucherState.signedMaxClaimable; + const sig = voucherState.signature as `0x${string}`; + + const charged = BigInt(String(chargedRaw)); + const signed = BigInt(String(signedRaw)); + + if (charged > signed) { + return false; + } + + const config = buildChannelConfig(deps, accept); + const channelId = computeChannelId(config, accept.network); + + if (!deps.signer.readContract) { + return false; + } + + const [chBalance, chTotalClaimed] = await readChannelBalanceAndTotalClaimed( + deps.signer, + channelId, + ); + + if (charged < chTotalClaimed) { + return false; + } + + const chainId = getEvmChainId(accept.network); + const recovered = await recoverTypedDataAddress({ + domain: getBatchSettlementEip712Domain(chainId), + types: voucherTypes, + primaryType: "Voucher", + message: { + channelId, + maxClaimableAmount: signed, + }, + signature: sig, + }); + + const expectedSigner = getAddress( + deps.payerAuthorizer ?? deps.voucherSigner?.address ?? deps.signer.address, + ); + if (recovered.toLowerCase() !== expectedSigner.toLowerCase()) { + return false; + } + + const ctx: BatchSettlementClientContext = { + chargedCumulativeAmount: charged.toString(), + signedMaxClaimable: signed.toString(), + signature: sig, + balance: chBalance.toString(), + totalClaimed: chTotalClaimed.toString(), + }; + + await deps.storage.set(channelId.toLowerCase(), ctx); + return true; +} + +/** + * Recovers channel state purely from onchain state when the server has no stored + * voucher (e.g. after a cooperative refund deleted the channel record). The onchain + * `totalClaimed` becomes the new baseline — no signature verification is + * needed because the contract is the source of truth when no outstanding + * voucher exists. + * + * @param deps - Signer + storage + identity inputs. + * @param accept - Batch settlement payment requirements from the corrective 402. + * @returns `true` when local channel state was updated from onchain data. + */ +export async function recoverFromOnChainState( + deps: BatchSettlementClientDeps, + accept: PaymentRequirements, +): Promise { + if (!deps.signer.readContract) { + return false; + } + + const config = buildChannelConfig(deps, accept); + const channelId = computeChannelId(config, accept.network); + + const [chBalance, chTotalClaimed] = await readChannelBalanceAndTotalClaimed( + deps.signer, + channelId, + ); + + const ctx: BatchSettlementClientContext = { + chargedCumulativeAmount: chTotalClaimed.toString(), + balance: chBalance.toString(), + totalClaimed: chTotalClaimed.toString(), + }; + + await deps.storage.set(channelId.toLowerCase(), ctx); + return true; +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/refund.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/refund.ts new file mode 100644 index 0000000000..0e07d2e5dd --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/refund.ts @@ -0,0 +1,322 @@ +import { decodePaymentRequiredHeader, decodePaymentResponseHeader } from "@x402/core/http"; +import { x402Client, x402HTTPClient } from "@x402/core/client"; +import type { + PaymentPayload, + PaymentRequired, + PaymentRequirements, + SettleResponse, +} from "@x402/core/types"; +import { BATCH_SETTLEMENT_SCHEME } from "../constants"; +import * as Errors from "../errors"; +import type { + BatchSettlementPaymentRequirementsExtra, + BatchSettlementRefundPayload, +} from "../types"; +import { computeChannelId } from "../utils"; +import { type BatchSettlementClientDeps, buildChannelConfig, recoverChannel } from "./channel"; +import { createBatchSettlementClientHooks } from "./hooks"; +import { signVoucher } from "./voucher"; + +/** + * Refund-specific server errors that the client cannot recover from automatically. + * Seeing any of these means the user should adjust their request (or accept that the + * channel has nothing left to refund) — retrying will not help. + */ +const NON_RECOVERABLE_REFUND_ERRORS: ReadonlySet = new Set([ + Errors.ErrRefundNoBalance, + Errors.ErrRefundAmountInvalid, +]); + +interface RefundRequirementsProbe { + paymentRequired: PaymentRequired; + requirements: PaymentRequirements; +} + +/** + * Caller-facing options for {@link refundChannel}. + */ +export interface RefundOptions { + /** Token base units to refund; omit for a full refund (drains remaining balance). */ + amount?: string; + /** Custom fetch implementation (defaults to `globalThis.fetch`). */ + fetch?: typeof fetch; +} + +/** + * Sends a cooperative refund request to the channel that backs `url`. + * + * Flow: + * 1. Probe the URL with `GET` (no payment) to obtain the route's payment requirements. + * 2. Build the `ChannelConfig` and resolve the local session (or recover it). + * 3. Sign a zero-charge refund voucher (`maxClaimableAmount = chargedCumulativeAmount`). + * 4. Send the voucher via `PAYMENT-SIGNATURE`. On a corrective 402, run the + * standard recovery path and retry once. + * 5. Return the parsed `SettleResponse` from the server. + * + * @param ctx - Identity inputs (storage, signers, salt, payerAuthorizer). + * @param url - Any protected route on the channel to refund (the resource handler is bypassed). + * @param options - Optional `amount` (partial refund) and `fetch` override. + * @returns The settle response describing the refund outcome. + * @throws When the probe fails, the receiver lacks an authorizer, or recovery fails. + */ +export async function refundChannel( + ctx: BatchSettlementClientDeps, + url: string, + options?: RefundOptions, +): Promise { + const fetchImpl = options?.fetch ?? globalThis.fetch; + if (!fetchImpl) { + throw new Error("refund requires a fetch implementation (globalThis.fetch unavailable)"); + } + + const refundAmount = normalizeRefundAmount(options?.amount); + const probe = await probeRefundRequirements(url, fetchImpl); + return executeRefund(ctx, url, probe, refundAmount, fetchImpl); +} + +/** + * Probes a URL with an unauthenticated GET to retrieve batch-settlement payment + * requirements via the 402 PAYMENT-REQUIRED header. + * + * @param url - The protected URL to probe. + * @param fetchImpl - Fetch implementation used for the probe. + * @returns Matching batch-settlement payment requirements for the route. + */ +async function probeRefundRequirements( + url: string, + fetchImpl: typeof fetch, +): Promise { + const probe = await fetchImpl(url, { method: "GET" }); + if (probe.status !== 402) { + throw new Error(`Refund probe expected 402, got ${probe.status}`); + } + + const header = probe.headers.get("PAYMENT-REQUIRED"); + if (!header) { + throw new Error("Refund probe response missing PAYMENT-REQUIRED header"); + } + + const paymentRequired = decodePaymentRequiredHeader(header); + const requirements = paymentRequired.accepts.find(a => a.scheme === BATCH_SETTLEMENT_SCHEME); + if (!requirements) { + throw new Error(`No ${BATCH_SETTLEMENT_SCHEME} payment option at ${url}`); + } + + const extra = requirements.extra as Partial | undefined; + if (!extra?.receiverAuthorizer) { + throw new Error("Refund requires a configured receiverAuthorizer on the receiver"); + } + + return { paymentRequired, requirements }; +} + +/** + * Builds and submits the refund voucher, retrying once after a corrective 402. + * + * @param ctx - Identity inputs (storage, signers, salt, payerAuthorizer). + * @param url - The protected URL to send the refund voucher to. + * @param probe - Resolved payment requirements and probe metadata for this channel. + * @param refundAmount - Optional partial refund amount in token base units. + * @param fetchImpl - Fetch implementation used for the request. + * @returns The parsed settle response. + */ +async function executeRefund( + ctx: BatchSettlementClientDeps, + url: string, + probe: RefundRequirementsProbe, + refundAmount: string | undefined, + fetchImpl: typeof fetch, +): Promise { + const maxAttempts = 2; + const { paymentRequired, requirements } = probe; + const httpClient = createRefundHttpClient(ctx, requirements); + + for (let attempt = 1; attempt <= maxAttempts; attempt += 1) { + const paymentPayload = await buildRefundPaymentPayload( + ctx, + paymentRequired, + requirements, + refundAmount, + ); + const headers = httpClient.encodePaymentSignatureHeader(paymentPayload); + + const response = await fetchImpl(url, { method: "GET", headers }); + + if (response.status === 402) { + const nonRecoverable = getNonRecoverableRefundFailure(response); + if (nonRecoverable) { + throw new Error(nonRecoverable); + } + } + + const result = await httpClient.processPaymentResult( + paymentPayload, + name => response.headers.get(name), + response.status, + ); + + if (response.status === 402) { + if (result.recovered && attempt < maxAttempts) { + continue; + } + if (result.recovered) { + throw new Error(`Refund failed: server returned 402 after ${attempt} attempt(s)`); + } + + const corrective = getRefundPaymentRequired(response); + throw new Error(`Refund failed: ${corrective.error ?? "unknown"}`); + } + + if (!result.settleResponse) { + throw new Error( + `Refund response missing PAYMENT-RESPONSE header (status ${response.status})`, + ); + } + + return result.settleResponse; + } + + throw new Error("Refund failed: retry budget exhausted"); +} + +/** + * Builds the refund payload with a zero-charge `maxClaimableAmount`. + * + * @param ctx - Identity inputs (storage, signers, salt, payerAuthorizer). + * @param paymentRequired - Decoded 402 body from the probe (resource, extensions, etc.). + * @param requirements - Resolved payment requirements for the channel. + * @param refundAmount - Optional partial refund amount in token base units. + * @returns A full payment payload wrapping the signed refund request. + */ +async function buildRefundPaymentPayload( + ctx: BatchSettlementClientDeps, + paymentRequired: PaymentRequired, + requirements: PaymentRequirements, + refundAmount: string | undefined, +): Promise { + const config = buildChannelConfig(ctx, requirements); + const channelId = computeChannelId(config, requirements.network); + const key = channelId.toLowerCase(); + + let channel = await ctx.storage.get(key); + if (channel === undefined && ctx.signer.readContract) { + channel = await recoverChannel(ctx, requirements); + } + if (channel === undefined) { + throw new Error( + "Refund requires an existing channel record; deposit first or call from a context with an EVM RPC", + ); + } + + // Avoid a refund request when local state shows the channel has no refundable balance. + const charged = channel.chargedCumulativeAmount ?? "0"; + if (channel.balance !== undefined && BigInt(channel.balance) <= BigInt(charged)) { + throw new Error( + `Refund failed: channel has no remaining balance (balance=${channel.balance}, chargedCumulativeAmount=${charged})`, + ); + } + + const voucherSigner = ctx.voucherSigner ?? ctx.signer; + const voucher = await signVoucher(voucherSigner, channelId, charged, requirements.network); + + const payload: BatchSettlementRefundPayload = { + type: "refund", + channelConfig: config, + voucher, + ...(refundAmount !== undefined ? { amount: refundAmount } : {}), + }; + + return { + x402Version: 2, + accepted: requirements, + payload: payload as unknown as Record, + ...(paymentRequired.resource ? { resource: paymentRequired.resource } : {}), + ...(paymentRequired.extensions ? { extensions: paymentRequired.extensions } : {}), + }; +} + +/** + * Creates an x402 HTTP client for batch settlement with hooks; refund payloads are supplied + * by {@link refundChannel} instead of the default payment builder. + * + * @param ctx - Identity inputs (storage, signers, salt, payerAuthorizer). + * @param requirements - Resolved payment requirements for the channel network. + * @returns An `x402HTTPClient` wired for batch-settlement scheme hooks. + */ +function createRefundHttpClient( + ctx: BatchSettlementClientDeps, + requirements: PaymentRequirements, +): x402HTTPClient { + const client = new x402Client().register(requirements.network, { + scheme: BATCH_SETTLEMENT_SCHEME, + schemeHooks: createBatchSettlementClientHooks(ctx), + createPaymentPayload: async () => { + throw new Error("Refund payloads are built by refundChannel"); + }, + }); + return new x402HTTPClient(client); +} + +/** + * If the refund HTTP response cannot be recovered by retrying, returns a user-facing message; + * otherwise returns `undefined`. + * + * @param response - The refund request response (402 with headers or settle failure). + * @returns A formatted failure string, or `undefined` when retry may succeed. + */ +function getNonRecoverableRefundFailure(response: Response): string | undefined { + const settleHeader = response.headers.get("PAYMENT-RESPONSE"); + if (settleHeader) { + return formatRefundFailure(decodePaymentResponseHeader(settleHeader)); + } + + const paymentRequired = getRefundPaymentRequired(response); + const errorCode = paymentRequired.error; + if (errorCode && NON_RECOVERABLE_REFUND_ERRORS.has(errorCode)) { + return `Refund failed: ${errorCode}`; + } +} + +/** + * Reads and decodes the `PAYMENT-REQUIRED` header from a refund-related 402 response. + * + * @param response - HTTP response that must include `PAYMENT-REQUIRED`. + * @returns The decoded {@link PaymentRequired} payload. + * @throws When the header is missing. + */ +function getRefundPaymentRequired(response: Response): PaymentRequired { + const requiredHeader = response.headers.get("PAYMENT-REQUIRED"); + if (!requiredHeader) { + throw new Error("Refund 402 missing PAYMENT-REQUIRED header"); + } + return decodePaymentRequiredHeader(requiredHeader); +} + +/** + * Builds a human-readable error message from a settle failure response. + * + * @param settle - The decoded SettleResponse from the server's 402 reply. + * @returns A formatted error string suitable for `throw new Error(...)`. + */ +function formatRefundFailure(settle: SettleResponse): string { + const reason = settle.errorReason ?? "unknown_settlement_error"; + const message = settle.errorMessage; + if (message && message !== reason) { + return `Refund failed: ${reason}: ${message}`; + } + return `Refund failed: ${reason}`; +} + +/** + * Validates and normalises the optional `refundAmount` argument. + * + * @param amount - Raw amount from caller (string of base units). + * @returns The same string when valid, or `undefined` when omitted. + */ +function normalizeRefundAmount(amount: string | undefined): string | undefined { + if (amount === undefined) return undefined; + if (!/^\d+$/.test(amount) || amount === "0") { + throw new Error(`Invalid refund amount "${amount}": must be a positive integer string`); + } + return amount; +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/scheme.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/scheme.ts new file mode 100644 index 0000000000..caebb71b78 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/scheme.ts @@ -0,0 +1,376 @@ +import { + SchemeNetworkClient, + SchemeClientHooks, + PaymentRequired, + PaymentRequirements, + PaymentPayloadResult, + PaymentPayloadContext, + SettleResponse, +} from "@x402/core/types"; +import { getAddress } from "viem"; +import { ClientEvmSigner } from "../../signer"; +import { BATCH_SETTLEMENT_SCHEME } from "../constants"; +import { + BatchSettlementAssetTransferMethod, + BatchSettlementVoucherPayload, + ChannelConfig, +} from "../types"; +import { computeChannelId } from "../utils"; +import { + trySignEip2612PermitExtension, + trySignErc20ApprovalExtension, +} from "../../shared/extensions"; +import type { EvmSchemeOptions } from "../../shared/rpc"; +import { createBatchSettlementEIP3009DepositPayload } from "./eip3009"; +import { createBatchSettlementPermit2DepositPayload } from "./permit2"; +import { + type BatchSettlementDepositStrategy, + type BatchSettlementDepositStrategyContext, + type BatchSettlementDepositPolicy, + type BatchSettlementEvmSchemeOptions, + depositAmountForRequest, + resolveClientOptions, + validateDepositPolicy, +} from "./config"; +import { refundChannel, type RefundOptions } from "./refund"; +import { + type BatchSettlementClientDeps, + buildChannelConfig, + processSettleResponse, + recoverChannel, +} from "./channel"; +import { createBatchSettlementClientHooks } from "./hooks"; +import { processCorrectivePaymentRequired } from "./recovery"; +import type { ClientChannelStorage } from "./storage"; +import { signVoucher } from "./voucher"; + +export type { BatchSettlementClientContext } from "./storage"; +export type { + BatchSettlementDepositPolicy, + BatchSettlementDepositStrategy, + BatchSettlementDepositStrategyContext, + BatchSettlementDepositStrategyResult, + BatchSettlementEvmSchemeOptions, +} from "./config"; +export type { RefundOptions } from "./refund"; + +/** + * Client-side implementation of the `batch-settlement` scheme for EVM networks. + * + * Builds payment payloads (deposit + voucher or voucher-only), processes server + * responses to update local session state via {@link processSettleResponse}, + * handles corrective 402 resynchronisation via + * {@link processCorrectivePaymentRequired}, and supports on-demand cooperative + * refund requests via {@link refundChannel}. + */ +export class BatchSettlementEvmScheme implements SchemeNetworkClient { + readonly scheme = BATCH_SETTLEMENT_SCHEME; + + readonly schemeHooks: SchemeClientHooks; + + private readonly storage: ClientChannelStorage; + private readonly depositPolicy: BatchSettlementDepositPolicy | undefined; + private readonly depositStrategy: BatchSettlementDepositStrategy | undefined; + private readonly salt: `0x${string}`; + private readonly payerAuthorizer: `0x${string}` | undefined; + private readonly voucherSigner: ClientEvmSigner | undefined; + private readonly extensionRpcOptions: EvmSchemeOptions | undefined; + + /** + * Constructs a batched client scheme. + * + * @param signer - Client EVM wallet used for signing vouchers and ERC-3009 authorizations. + * @param optionsOrPolicy - Either a full options object or a bare deposit-policy. + */ + constructor( + private readonly signer: ClientEvmSigner, + optionsOrPolicy?: BatchSettlementEvmSchemeOptions | BatchSettlementDepositPolicy, + ) { + const { + storage, + depositPolicy, + depositStrategy, + salt, + payerAuthorizer, + voucherSigner, + extensionRpcOptions, + } = resolveClientOptions(optionsOrPolicy); + this.storage = storage; + this.depositPolicy = depositPolicy; + this.depositStrategy = depositStrategy; + this.salt = salt; + this.payerAuthorizer = payerAuthorizer; + this.voucherSigner = voucherSigner; + this.extensionRpcOptions = extensionRpcOptions; + + if ( + payerAuthorizer !== undefined && + voucherSigner !== undefined && + getAddress(payerAuthorizer) !== getAddress(voucherSigner.address) + ) { + throw new Error("payerAuthorizer address must match voucherSigner.address"); + } + + validateDepositPolicy(depositPolicy); + this.schemeHooks = createBatchSettlementClientHooks(this.deps()); + } + + /** + * Creates the payment payload for a batched request. + * + * If the channel has no onchain deposit (or needs a top-up), builds an + * ERC-3009 deposit payload bundled with a voucher. Otherwise, signs and + * returns a voucher-only payload. + * + * @param x402Version - Protocol version for the payload envelope. + * @param paymentRequirements - Server payment requirements (scheme, network, asset, amount). + * @param context - Optional payment payload context with extension hints. + * @returns A {@link PaymentPayloadResult} ready to be sent as the `X-PAYMENT` header. + */ + async createPaymentPayload( + x402Version: number, + paymentRequirements: PaymentRequirements, + context?: PaymentPayloadContext, + ): Promise { + const deps = this.deps(); + const config = buildChannelConfig(deps, paymentRequirements); + const channelId = computeChannelId(config, paymentRequirements.network); + const key = channelId.toLowerCase(); + + let batchedCtx = await this.storage.get(key); + if (batchedCtx === undefined && this.signer.readContract) { + batchedCtx = await recoverChannel(deps, paymentRequirements); + } + batchedCtx = batchedCtx ?? {}; + + const needsInitialDeposit = !batchedCtx.balance || batchedCtx.balance === "0"; + + const baseCumulative = BigInt(batchedCtx.chargedCumulativeAmount ?? "0"); + const requestAmount = BigInt(paymentRequirements.amount); + const maxClaimableAmount = (baseCumulative + requestAmount).toString(); + + const currentBalance = BigInt(batchedCtx.balance ?? "0"); + const needsTopUp = !needsInitialDeposit && BigInt(maxClaimableAmount) > currentBalance; + + if (needsInitialDeposit || needsTopUp) { + const computedDeposit = depositAmountForRequest(this.depositPolicy, requestAmount); + const minimumDepositAmount = BigInt(maxClaimableAmount) - currentBalance; + const depositAmount = await this.resolveDepositAmount({ + paymentRequirements, + channelConfig: config, + channelId, + clientContext: batchedCtx, + requestAmount: requestAmount.toString(), + maxClaimableAmount, + currentBalance: currentBalance.toString(), + minimumDepositAmount: minimumDepositAmount.toString(), + depositAmount: computedDeposit, + }); + if (depositAmount === false) { + return this.createVoucherPayload( + x402Version, + channelId, + maxClaimableAmount, + paymentRequirements.network, + config, + ); + } + + const assetTransferMethod = + (paymentRequirements.extra?.assetTransferMethod as BatchSettlementAssetTransferMethod) ?? + "eip3009"; + + if (assetTransferMethod === "eip3009") { + return createBatchSettlementEIP3009DepositPayload( + this.signer, + x402Version, + paymentRequirements, + config, + depositAmount, + maxClaimableAmount, + this.voucherSigner, + ); + } + + if (assetTransferMethod !== "permit2") { + throw new Error(`unsupported batch-settlement assetTransferMethod: ${assetTransferMethod}`); + } + + const result = await createBatchSettlementPermit2DepositPayload( + this.signer, + x402Version, + paymentRequirements, + config, + depositAmount, + maxClaimableAmount, + this.voucherSigner, + ); + + const eip2612Extensions = await trySignEip2612PermitExtension( + this.signer, + this.extensionRpcOptions, + paymentRequirements, + result, + context, + depositAmount, + ); + if (eip2612Extensions) { + return { ...result, extensions: eip2612Extensions }; + } + + const erc20Extensions = await trySignErc20ApprovalExtension( + this.signer, + this.extensionRpcOptions, + paymentRequirements, + context, + depositAmount, + ); + if (erc20Extensions) { + return { ...result, extensions: erc20Extensions }; + } + + return result; + } + + return this.createVoucherPayload( + x402Version, + channelId, + maxClaimableAmount, + paymentRequirements.network, + config, + ); + } + + /** + * Sends a cooperative refund request. + * + * @param url - The route URL backing the channel to refund. + * @param options - Optional `amount` (partial refund) and `fetch` override. + * @returns The settle response describing the refund outcome. + */ + async refund(url: string, options?: RefundOptions): Promise { + return refundChannel(this.deps(), url, options); + } + + /** + * Updates local channel state from a settle response. + * + * @param settle - The parsed settle response from the server. + * @returns Resolves when local channel state has been updated. + */ + async processSettleResponse(settle: SettleResponse): Promise { + return processSettleResponse(this.storage, settle); + } + + /** + * Resyncs local channel state from a corrective 402 response. + * + * @param paymentRequired - The decoded 402 response body. + * @returns `true` if local state was successfully resynced and a retry is warranted. + */ + async processCorrectivePaymentRequired(paymentRequired: PaymentRequired): Promise { + return processCorrectivePaymentRequired(this.deps(), paymentRequired); + } + + /** + * Builds the immutable {@link ChannelConfig} for a given set of payment + * requirements, using the scheme's own signer and salt. + * + * @param paymentRequirements - Server payment requirements for the channel. + * @returns The channel config that uniquely identifies the payment channel. + */ + buildChannelConfig(paymentRequirements: PaymentRequirements): ChannelConfig { + return buildChannelConfig(this.deps(), paymentRequirements); + } + + /** + * Resolves the deposit amount after applying the optional custom strategy. + * + * @param context - Deposit attempt context exposed to the strategy. + * @returns The deposit amount to sign, or `false` to skip this deposit attempt. + */ + private async resolveDepositAmount( + context: BatchSettlementDepositStrategyContext, + ): Promise { + const strategyResult = await this.depositStrategy?.(context); + if (strategyResult === false) return false; + if (strategyResult === undefined) return context.depositAmount; + + const depositAmount = this.normalizeStrategyDepositAmount(strategyResult); + if (BigInt(depositAmount) < BigInt(context.minimumDepositAmount)) { + throw new Error( + `depositStrategy returned ${depositAmount}, below required top-up ${context.minimumDepositAmount}`, + ); + } + return depositAmount; + } + + /** + * Normalizes and validates a strategy-provided base-unit deposit amount. + * + * @param value - Strategy-provided string or bigint amount. + * @returns Normalized decimal string. + */ + private normalizeStrategyDepositAmount(value: string | bigint): string { + if (typeof value === "bigint") { + if (value <= 0n) { + throw new Error("depositStrategy must return a positive integer deposit amount"); + } + return value.toString(); + } + + if (/^\d+$/.test(value) && BigInt(value) > 0n) { + return BigInt(value).toString(); + } + + throw new Error("depositStrategy must return a positive integer deposit amount"); + } + + /** + * Signs a voucher-only payment payload for the current channel. + * + * @param x402Version - Protocol version for the payload envelope. + * @param channelId - Channel identifier for the voucher. + * @param maxClaimableAmount - Cumulative ceiling for the voucher. + * @param network - CAIP-2 network identifier. + * @param config - Immutable channel configuration. + * @returns Voucher-only payment payload. + */ + private async createVoucherPayload( + x402Version: number, + channelId: `0x${string}`, + maxClaimableAmount: string, + network: string, + config: ChannelConfig, + ): Promise { + const voucherSigner = this.voucherSigner ?? this.signer; + const voucher = await signVoucher(voucherSigner, channelId, maxClaimableAmount, network); + + const payload: BatchSettlementVoucherPayload = { + type: "voucher", + channelConfig: config, + voucher, + }; + + return { + x402Version, + payload, + }; + } + + /** + * Bundles the class state into the {@link BatchSettlementClientDeps} shape + * consumed by the `channel`, `recovery`, and `refund` modules. + * + * @returns Client deps wrapping the scheme's own signer and storage. + */ + private deps(): BatchSettlementClientDeps { + return { + signer: this.signer, + storage: this.storage, + salt: this.salt, + payerAuthorizer: this.payerAuthorizer, + voucherSigner: this.voucherSigner, + }; + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/storage.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/storage.ts new file mode 100644 index 0000000000..70b9654d8d --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/storage.ts @@ -0,0 +1,59 @@ +/** + * Client-side channel fields mirrored from PAYMENT-RESPONSE / recovery flows. + */ +export interface BatchSettlementClientContext { + /** Current cumulative amount charged by the server for this channel */ + chargedCumulativeAmount?: string; + /** Current onchain channel balance */ + balance?: string; + /** Total claimed onchain */ + totalClaimed?: string; + /** Latest client-signed maxClaimableAmount cap (after corrective recovery, optional) */ + signedMaxClaimable?: string; + /** Client voucher signature for {@link signedMaxClaimable} (optional) */ + signature?: `0x${string}`; +} + +export interface ClientChannelStorage { + get(key: string): Promise; + set(key: string, context: BatchSettlementClientContext): Promise; + delete(key: string): Promise; +} + +/** + * Default in-memory {@link ClientChannelStorage} (channel records do not survive process restart). + */ +export class InMemoryClientChannelStorage implements ClientChannelStorage { + private readonly channels = new Map(); + + /** + * Returns the channel record for `key` if present. + * + * @param key - Channel storage key (channelId). + * @returns Persisted context or undefined. + */ + async get(key: string): Promise { + return this.channels.get(key); + } + + /** + * Stores or replaces the channel record for `key`. + * + * @param key - Channel storage key. + * @param context - Channel fields to persist. + * @returns Resolves when stored. + */ + async set(key: string, context: BatchSettlementClientContext): Promise { + this.channels.set(key, context); + } + + /** + * Removes the channel record for `key` if it exists. + * + * @param key - Channel storage key. + * @returns Resolves when removed. + */ + async delete(key: string): Promise { + this.channels.delete(key); + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/client/voucher.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/client/voucher.ts new file mode 100644 index 0000000000..9fb49e09d4 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/client/voucher.ts @@ -0,0 +1,43 @@ +import { ClientEvmSigner } from "../../signer"; +import { voucherTypes } from "../constants"; +import { BatchSettlementVoucherFields } from "../types"; +import { getEvmChainId } from "../../utils"; +import { getBatchSettlementEip712Domain } from "../utils"; + +/** + * Signs a cumulative voucher using the client's wallet. + * + * The voucher authorises the receiver to claim up to `maxClaimableAmount` from the + * channel identified by `channelId`. The signature covers the EIP-712 `Voucher` struct + * under the batched domain. + * + * @param signer - Client wallet used to produce the EIP-712 signature. + * @param channelId - Identifier of the payment channel (`keccak256(abi.encode(ChannelConfig))`). + * @param maxClaimableAmount - Cumulative ceiling the receiver may claim (decimal string in token units). + * @param network - CAIP-2 network identifier (e.g. `eip155:84532`). + * @returns Signed voucher fields ready to be included in a payment payload. + */ +export async function signVoucher( + signer: ClientEvmSigner, + channelId: `0x${string}`, + maxClaimableAmount: string, + network: string, +): Promise { + const chainId = getEvmChainId(network); + + const signature = await signer.signTypedData({ + domain: getBatchSettlementEip712Domain(chainId), + types: voucherTypes, + primaryType: "Voucher", + message: { + channelId, + maxClaimableAmount: BigInt(maxClaimableAmount), + }, + }); + + return { + channelId, + maxClaimableAmount, + signature, + }; +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/constants.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/constants.ts new file mode 100644 index 0000000000..7b01805563 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/constants.ts @@ -0,0 +1,102 @@ +import { keccak256, toBytes } from "viem"; + +/** Scheme identifier for the batch-settlement payment scheme. */ +export const BATCH_SETTLEMENT_SCHEME = "batch-settlement" as const; + +/** Deployed address of the x402BatchSettlement contract. */ +export const BATCH_SETTLEMENT_ADDRESS = "0x4020074e9dF2ce1deE5A9C1b5c3f541D02a10003" as const; + +/** Deployed address of the ERC3009DepositCollector contract. */ +export const ERC3009_DEPOSIT_COLLECTOR_ADDRESS = + "0x4020806089470a89826cB9fB1f4059150b550004" as const; + +/** Deployed address of the Permit2DepositCollector contract. */ +export const PERMIT2_DEPOSIT_COLLECTOR_ADDRESS = + "0x4020425FAf3B746C082C2f942b4E5159887B0005" as const; + +/** Minimum withdraw delay in seconds (15 minutes), matching the onchain constant. */ +export const MIN_WITHDRAW_DELAY = 900; + +/** Maximum withdraw delay in seconds (30 days), matching the onchain constant. */ +export const MAX_WITHDRAW_DELAY = 2_592_000; + +/** EIP-712 domain fields shared across all batch-settlement typed-data signatures. */ +export const BATCH_SETTLEMENT_DOMAIN = { + name: "x402 Batch Settlement", + version: "1", +} as const; + +/** EIP-712 type hash for channel identity. */ +export const CHANNEL_CONFIG_TYPEHASH = keccak256( + toBytes( + "ChannelConfig(address payer,address payerAuthorizer,address receiver,address receiverAuthorizer,address token,uint40 withdrawDelay,bytes32 salt)", + ), +); + +/** EIP-712 type definition for a channel configuration. */ +export const channelConfigTypes = { + ChannelConfig: [ + { name: "payer", type: "address" }, + { name: "payerAuthorizer", type: "address" }, + { name: "receiver", type: "address" }, + { name: "receiverAuthorizer", type: "address" }, + { name: "token", type: "address" }, + { name: "withdrawDelay", type: "uint40" }, + { name: "salt", type: "bytes32" }, + ], +} as const; + +/** EIP-712 type definition for a cumulative voucher: `Voucher(bytes32 channelId, uint128 maxClaimableAmount)`. */ +export const voucherTypes = { + Voucher: [ + { name: "channelId", type: "bytes32" }, + { name: "maxClaimableAmount", type: "uint128" }, + ], +} as const; + +/** EIP-712 type definition for cooperative refund: `Refund(bytes32 channelId, uint256 nonce, uint128 amount)`. */ +export const refundTypes = { + Refund: [ + { name: "channelId", type: "bytes32" }, + { name: "nonce", type: "uint256" }, + { name: "amount", type: "uint128" }, + ], +} as const; + +/** EIP-712 type definitions for a receiver-authorizer claim batch (nested ClaimEntry). */ +export const claimBatchTypes = { + ClaimBatch: [{ name: "claims", type: "ClaimEntry[]" }], + ClaimEntry: [ + { name: "channelId", type: "bytes32" }, + { name: "maxClaimableAmount", type: "uint128" }, + { name: "totalClaimed", type: "uint128" }, + ], +} as const; + +/** EIP-712 type definition for ERC-3009 `ReceiveWithAuthorization` (used for gasless deposits). */ +export const receiveAuthorizationTypes = { + ReceiveWithAuthorization: [ + { name: "from", type: "address" }, + { name: "to", type: "address" }, + { name: "value", type: "uint256" }, + { name: "validAfter", type: "uint256" }, + { name: "validBefore", type: "uint256" }, + { name: "nonce", type: "bytes32" }, + ], +} as const; + +/** Permit2 typed data for channel-bound batch deposits. */ +export const batchPermit2WitnessTypes = { + PermitWitnessTransferFrom: [ + { name: "permitted", type: "TokenPermissions" }, + { name: "spender", type: "address" }, + { name: "nonce", type: "uint256" }, + { name: "deadline", type: "uint256" }, + { name: "witness", type: "DepositWitness" }, + ], + TokenPermissions: [ + { name: "token", type: "address" }, + { name: "amount", type: "uint256" }, + ], + DepositWitness: [{ name: "channelId", type: "bytes32" }], +} as const; diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/encoding.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/encoding.ts new file mode 100644 index 0000000000..5723d9a4a5 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/encoding.ts @@ -0,0 +1,94 @@ +/** + * @file Encoding helpers for batch-settlement deposit collectors. + */ +import { encodeAbiParameters, keccak256 } from "viem"; + +/** + * Computes the ERC-3009 nonce used by the deposit collector: + * `keccak256(abi.encode(channelId, salt))`. + * + * @param channelId - The `bytes32` channel id binding the authorization to a channel. + * @param salt - Random salt provided by the client to make the nonce unique per deposit. + * @returns The `bytes32` ERC-3009 nonce. + */ +export function buildErc3009DepositNonce( + channelId: `0x${string}`, + salt: `0x${string}`, +): `0x${string}` { + return keccak256( + encodeAbiParameters([{ type: "bytes32" }, { type: "uint256" }], [channelId, BigInt(salt)]), + ); +} + +/** + * Encodes the `collectorData` payload for `ERC3009DepositCollector.collect()`: + * `abi.encode(validAfter, validBefore, salt, signature)`. + * + * @param validAfter - Earliest unix timestamp the authorization is valid (decimal string). + * @param validBefore - Latest unix timestamp the authorization is valid (decimal string). + * @param salt - Random salt provided by the client (hex string). + * @param signature - ERC-3009 `ReceiveWithAuthorization` signature. + * @returns ABI-encoded collector data passed to `deposit(..., collector, collectorData)`. + */ +export function buildErc3009CollectorData( + validAfter: string, + validBefore: string, + salt: `0x${string}`, + signature: `0x${string}`, +): `0x${string}` { + return encodeAbiParameters( + [{ type: "uint256" }, { type: "uint256" }, { type: "uint256" }, { type: "bytes" }], + [BigInt(validAfter), BigInt(validBefore), BigInt(salt), signature], + ); +} + +/** + * Encodes optional EIP-2612 permit data consumed by `Permit2DepositCollector`. + * + * @param params - Permit amount, deadline, and split signature fields. + * @param params.value - Approved Permit2 allowance value. + * @param params.deadline - EIP-2612 permit deadline. + * @param params.v - Signature recovery id. + * @param params.r - Signature `r` value. + * @param params.s - Signature `s` value. + * @returns ABI-encoded permit segment. + */ +export function buildEip2612PermitData(params: { + value: string; + deadline: string; + v: number; + r: `0x${string}`; + s: `0x${string}`; +}): `0x${string}` { + return encodeAbiParameters( + [ + { type: "uint256" }, + { type: "uint256" }, + { type: "uint8" }, + { type: "bytes32" }, + { type: "bytes32" }, + ], + [BigInt(params.value), BigInt(params.deadline), params.v, params.r, params.s], + ); +} + +/** + * Encodes the `collectorData` payload for `Permit2DepositCollector.collect()`. + * + * @param nonce - Permit2 transfer nonce. + * @param deadline - Permit2 transfer deadline. + * @param permit2Signature - Signature over the channel-bound Permit2 authorization. + * @param eip2612PermitData - Optional encoded EIP-2612 permit segment. + * @returns ABI-encoded collector data passed to `deposit`. + */ +export function buildPermit2CollectorData( + nonce: string, + deadline: string, + permit2Signature: `0x${string}`, + eip2612PermitData: `0x${string}` = "0x", +): `0x${string}` { + return encodeAbiParameters( + [{ type: "uint256" }, { type: "uint256" }, { type: "bytes" }, { type: "bytes" }], + [BigInt(nonce), BigInt(deadline), permit2Signature, eip2612PermitData], + ); +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/errors.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/errors.ts new file mode 100644 index 0000000000..279f8a67f2 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/errors.ts @@ -0,0 +1,67 @@ +/** Error codes for the batch-settlement EVM scheme (see scheme_batch_settlement_evm2.md). */ + +export const ErrChannelNotFound = "invalid_batch_settlement_evm_channel_not_found"; +export const ErrTokenMismatch = "invalid_batch_settlement_evm_token_mismatch"; +export const ErrInvalidVoucherSignature = "invalid_batch_settlement_evm_voucher_signature"; +export const ErrCumulativeExceedsBalance = + "invalid_batch_settlement_evm_cumulative_exceeds_balance"; +export const ErrCumulativeAmountBelowClaimed = + "invalid_batch_settlement_evm_cumulative_below_claimed"; +export const ErrInsufficientBalance = "invalid_batch_settlement_evm_insufficient_balance"; +export const ErrDepositTransactionFailed = + "invalid_batch_settlement_evm_deposit_transaction_failed"; +export const ErrClaimTransactionFailed = "invalid_batch_settlement_evm_claim_transaction_failed"; +export const ErrSettleTransactionFailed = "invalid_batch_settlement_evm_settle_transaction_failed"; +export const ErrInvalidScheme = "invalid_batch_settlement_evm_scheme"; +export const ErrNetworkMismatch = "invalid_batch_settlement_evm_network_mismatch"; +export const ErrMissingEip712Domain = "invalid_batch_settlement_evm_missing_eip712_domain"; +export const ErrValidBeforeExpired = + "invalid_batch_settlement_evm_payload_authorization_valid_before"; +export const ErrValidAfterInFuture = + "invalid_batch_settlement_evm_payload_authorization_valid_after"; +export const ErrInvalidReceiveAuthorizationSignature = + "invalid_batch_settlement_evm_receive_authorization_signature"; +export const ErrErc3009AuthorizationRequired = + "invalid_batch_settlement_evm_erc3009_authorization_required"; +export const ErrRefundTransactionFailed = "invalid_batch_settlement_evm_refund_transaction_failed"; +export const ErrInvalidPayloadType = "invalid_batch_settlement_evm_payload_type"; +export const ErrWithdrawDelayOutOfRange = + "invalid_batch_settlement_evm_withdraw_delay_out_of_range"; +export const ErrChannelIdMismatch = "invalid_batch_settlement_evm_channel_id_mismatch"; +export const ErrReceiverMismatch = "invalid_batch_settlement_evm_receiver_mismatch"; +export const ErrReceiverAuthorizerMismatch = + "invalid_batch_settlement_evm_receiver_authorizer_mismatch"; +export const ErrWithdrawDelayMismatch = "invalid_batch_settlement_evm_withdraw_delay_mismatch"; +export const ErrAuthorizerAddressMismatch = + "invalid_batch_settlement_evm_authorizer_address_mismatch"; +export const ErrDepositSimulationFailed = "invalid_batch_settlement_evm_deposit_simulation_failed"; +export const ErrClaimSimulationFailed = "invalid_batch_settlement_evm_claim_simulation_failed"; +export const ErrSettleSimulationFailed = "invalid_batch_settlement_evm_settle_simulation_failed"; +export const ErrRefundPayload = "invalid_batch_settlement_evm_refund_payload"; +export const ErrRefundSimulationFailed = "invalid_batch_settlement_evm_refund_simulation_failed"; +export const ErrRpcReadFailed = "invalid_batch_settlement_evm_rpc_read_failed"; +export const ErrPermit2AuthorizationRequired = + "invalid_batch_settlement_evm_permit2_authorization_required"; +export const ErrPermit2InvalidSpender = "invalid_batch_settlement_evm_permit2_invalid_spender"; +export const ErrPermit2AmountMismatch = "invalid_batch_settlement_evm_permit2_amount_mismatch"; +export const ErrPermit2DeadlineExpired = "invalid_batch_settlement_evm_permit2_deadline_expired"; +export const ErrPermit2InvalidSignature = "invalid_batch_settlement_evm_permit2_invalid_signature"; +export const ErrPermit2AllowanceRequired = + "invalid_batch_settlement_evm_permit2_allowance_required"; +export const ErrEip2612AmountMismatch = "invalid_batch_settlement_evm_eip2612_amount_mismatch"; +export const ErrEip2612OwnerMismatch = "invalid_batch_settlement_evm_eip2612_owner_mismatch"; +export const ErrEip2612AssetMismatch = "invalid_batch_settlement_evm_eip2612_asset_mismatch"; +export const ErrEip2612SpenderMismatch = "invalid_batch_settlement_evm_eip2612_spender_mismatch"; +export const ErrEip2612DeadlineExpired = "invalid_batch_settlement_evm_eip2612_deadline_expired"; +export const ErrErc20ApprovalUnavailable = + "invalid_batch_settlement_evm_erc20_approval_unavailable"; + +/** Resource server: 402 `error` and lifecycle `reason` (same strings as the spec). */ +export const ErrCumulativeAmountMismatch = + "invalid_batch_settlement_evm_cumulative_amount_mismatch"; +export const ErrChannelBusy = "invalid_batch_settlement_evm_channel_busy"; +export const ErrChargeExceedsSignedCumulative = + "invalid_batch_settlement_evm_charge_exceeds_signed_cumulative"; +export const ErrMissingChannel = "invalid_batch_settlement_evm_missing_channel"; +export const ErrRefundNoBalance = "invalid_batch_settlement_evm_refund_no_balance"; +export const ErrRefundAmountInvalid = "invalid_batch_settlement_evm_refund_amount_invalid"; diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/claim.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/claim.ts new file mode 100644 index 0000000000..37054d9807 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/claim.ts @@ -0,0 +1,123 @@ +import { SettleResponse, PaymentRequirements } from "@x402/core/types"; +import { getAddress } from "viem"; +import { FacilitatorEvmSigner } from "../../signer"; +import type { AuthorizerSigner, BatchSettlementClaimPayload } from "../types"; +import { batchSettlementABI } from "../abi"; +import { BATCH_SETTLEMENT_ADDRESS } from "../constants"; +import { signClaimBatch } from "../authorizerSigner"; +import * as Errors from "../errors"; +import { toContractChannelConfig } from "./utils"; + +/** + * Converts an array of {@link BatchSettlementVoucherClaim} into the onchain tuple format + * expected by the contract's `claimWithSignature()` function. + * + * @param claims - Typed voucher claims with channel config, amounts, and signatures. + * @returns Contract-ready VoucherClaim argument array. + */ +export function buildVoucherClaimArgs(claims: BatchSettlementClaimPayload["claims"]) { + return claims.map(c => ({ + voucher: { + channel: toContractChannelConfig(c.voucher.channel), + maxClaimableAmount: BigInt(c.voucher.maxClaimableAmount), + }, + signature: c.signature, + totalClaimed: BigInt(c.totalClaimed), + })); +} + +/** + * Submits a batch claim via `claimWithSignature()`. + * + * When `claimAuthorizerSignature` is present in the payload it is used directly. + * When absent the facilitator signs the `ClaimBatch` EIP-712 digest using + * `authorizerSigner`, after verifying that every claim's `receiverAuthorizer` + * matches `authorizerSigner.address`. + * + * @param signer - Facilitator signer used to submit the claim transaction. + * @param payload - Claim payload containing voucher claims and optional authorizer signature. + * @param requirements - Payment requirements for network identification. + * @param authorizerSigner - Dedicated key for producing `ClaimBatch` EIP-712 signatures. + * @returns A {@link SettleResponse} with the transaction hash on success. + */ +export async function executeClaimWithSignature( + signer: FacilitatorEvmSigner, + payload: BatchSettlementClaimPayload, + requirements: PaymentRequirements, + authorizerSigner: AuthorizerSigner, +): Promise { + const network = requirements.network; + const claimArgs = buildVoucherClaimArgs(payload.claims); + + let sig = payload.claimAuthorizerSignature; + + if (!sig) { + for (const claim of payload.claims) { + if ( + getAddress(claim.voucher.channel.receiverAuthorizer) !== + getAddress(authorizerSigner.address) + ) { + return { + success: false, + errorReason: Errors.ErrAuthorizerAddressMismatch, + transaction: "", + network, + }; + } + } + sig = await signClaimBatch(authorizerSigner, payload.claims, network); + } + + try { + await signer.readContract({ + address: getAddress(BATCH_SETTLEMENT_ADDRESS), + abi: batchSettlementABI, + functionName: "claimWithSignature", + args: [claimArgs, sig], + }); + } catch (e) { + return { + success: false, + errorReason: Errors.ErrClaimSimulationFailed, + errorMessage: e instanceof Error ? e.message : String(e), + transaction: "", + network, + }; + } + + try { + const tx = await signer.writeContract({ + address: getAddress(BATCH_SETTLEMENT_ADDRESS), + abi: batchSettlementABI, + functionName: "claimWithSignature", + args: [claimArgs, sig], + }); + + const receipt = await signer.waitForTransactionReceipt({ hash: tx }); + + if (receipt.status !== "success") { + return { + success: false, + errorReason: Errors.ErrClaimTransactionFailed, + errorMessage: `transaction reverted (receipt status ${receipt.status})`, + transaction: tx, + network, + }; + } + + return { + success: true, + transaction: tx, + network, + amount: "", + }; + } catch (e) { + return { + success: false, + errorReason: Errors.ErrClaimTransactionFailed, + errorMessage: e instanceof Error ? e.message : String(e), + transaction: "", + network, + }; + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/deposit-eip3009.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/deposit-eip3009.ts new file mode 100644 index 0000000000..9d4fd9fd05 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/deposit-eip3009.ts @@ -0,0 +1,148 @@ +import { PaymentRequirements, VerifyResponse } from "@x402/core/types"; +import { getAddress } from "viem"; +import { FacilitatorEvmSigner } from "../../signer"; +import { BatchSettlementDepositPayload } from "../types"; +import { ERC3009_DEPOSIT_COLLECTOR_ADDRESS, receiveAuthorizationTypes } from "../constants"; +import { buildErc3009CollectorData, buildErc3009DepositNonce } from "../encoding"; +import * as Errors from "../errors"; +import { erc3009AuthorizationTimeInvalidReason } from "./utils"; + +/** + * Returns the collector contract used for EIP-3009 deposits. + * + * @returns ERC-3009 deposit collector address. + */ +export function getEip3009DepositCollectorAddress(): `0x${string}` { + return getAddress(ERC3009_DEPOSIT_COLLECTOR_ADDRESS); +} + +/** + * Encodes collector data for an EIP-3009 deposit payload. + * + * @param payload - Deposit payload containing the ERC-3009 authorization. + * @returns ABI-encoded collector data. + */ +export function buildEip3009DepositCollectorData( + payload: BatchSettlementDepositPayload, +): `0x${string}` { + const auth = payload.deposit.authorization.erc3009Authorization; + if (!auth) { + throw new Error(Errors.ErrErc3009AuthorizationRequired); + } + + return buildErc3009CollectorData(auth.validAfter, auth.validBefore, auth.salt, auth.signature); +} + +/** + * Verifies the ERC-3009 authorization fields and typed-data signature. + * + * @param signer - Facilitator signer for typed-data verification. + * @param payload - Deposit payload to verify. + * @param requirements - Payment requirements containing token domain metadata. + * @param chainId - EVM chain id. + * @returns A failure response, or `null` when valid. + */ +export async function verifyEip3009DepositAuthorization( + signer: FacilitatorEvmSigner, + payload: BatchSettlementDepositPayload, + requirements: PaymentRequirements, + chainId: number, +): Promise { + const { deposit, voucher } = payload; + const payer = payload.channelConfig.payer; + const auth = deposit.authorization.erc3009Authorization; + + if (!auth) { + return { isValid: false, invalidReason: Errors.ErrErc3009AuthorizationRequired, payer }; + } + + const extra = requirements.extra as { name?: string; version?: string } | undefined; + if (!extra?.name || !extra?.version) { + return { isValid: false, invalidReason: Errors.ErrMissingEip712Domain, payer }; + } + + const validAfter = BigInt(auth.validAfter); + const validBefore = BigInt(auth.validBefore); + const timeInvalid = erc3009AuthorizationTimeInvalidReason(validAfter, validBefore); + if (timeInvalid) { + return { isValid: false, invalidReason: timeInvalid, payer }; + } + + const erc3009Nonce = buildErc3009DepositNonce(voucher.channelId, auth.salt); + const receiveAuthOk = await verifyReceiveAuth(signer, { + payer, + asset: requirements.asset, + name: extra.name, + version: extra.version, + chainId, + amount: deposit.amount, + validAfter, + validBefore, + nonce: erc3009Nonce, + signature: auth.signature, + }); + + if (!receiveAuthOk) { + return { isValid: false, invalidReason: Errors.ErrInvalidReceiveAuthorizationSignature, payer }; + } + + return null; +} + +/** + * Verifies a `ReceiveWithAuthorization` signature. + * + * @param signer - Facilitator signer used for typed-data verification. + * @param params - Authorization fields and signature. + * @param params.payer - Expected authorization signer. + * @param params.asset - ERC-20 verifying contract. + * @param params.name - ERC-20 EIP-712 domain name. + * @param params.version - ERC-20 EIP-712 domain version. + * @param params.chainId - EVM chain id. + * @param params.amount - Authorized token amount. + * @param params.validAfter - Earliest valid timestamp. + * @param params.validBefore - Expiration timestamp. + * @param params.nonce - ERC-3009 nonce. + * @param params.signature - Receive authorization signature. + * @returns True when the signature matches the expected payer. + */ +async function verifyReceiveAuth( + signer: FacilitatorEvmSigner, + params: { + payer: `0x${string}`; + asset: string; + name: string; + version: string; + chainId: number; + amount: string; + validAfter: bigint; + validBefore: bigint; + nonce: `0x${string}`; + signature: `0x${string}`; + }, +): Promise { + try { + return await signer.verifyTypedData({ + address: getAddress(params.payer), + domain: { + name: params.name, + version: params.version, + chainId: params.chainId, + verifyingContract: getAddress(params.asset), + }, + types: receiveAuthorizationTypes, + primaryType: "ReceiveWithAuthorization", + message: { + from: getAddress(params.payer), + to: getAddress(ERC3009_DEPOSIT_COLLECTOR_ADDRESS), + value: BigInt(params.amount), + validAfter: params.validAfter, + validBefore: params.validBefore, + nonce: params.nonce, + }, + signature: params.signature, + }); + } catch { + return false; + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/deposit-permit2.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/deposit-permit2.ts new file mode 100644 index 0000000000..989c6c4e94 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/deposit-permit2.ts @@ -0,0 +1,360 @@ +import { + FacilitatorContext, + PaymentPayload, + PaymentRequirements, + VerifyResponse, +} from "@x402/core/types"; +import { encodeFunctionData, getAddress } from "viem"; +import { + extractEip2612GasSponsoringInfo, + extractErc20ApprovalGasSponsoringInfo, + ERC20_APPROVAL_GAS_SPONSORING_KEY, + resolveErc20ApprovalExtensionSigner, + type Eip2612GasSponsoringInfo, + type Erc20ApprovalGasSponsoringFacilitatorExtension, + type Erc20ApprovalGasSponsoringSigner, +} from "../../exact/extensions"; +import { validateErc20ApprovalForPayment } from "../../shared/erc20approval"; +import { validateEip2612PermitForPayment, splitEip2612Signature } from "../../shared/permit2"; +import { PERMIT2_ADDRESS, erc20AllowanceAbi } from "../../constants"; +import { FacilitatorEvmSigner } from "../../signer"; +import { batchSettlementABI } from "../abi"; +import { + BATCH_SETTLEMENT_ADDRESS, + PERMIT2_DEPOSIT_COLLECTOR_ADDRESS, + batchPermit2WitnessTypes, +} from "../constants"; +import { buildEip2612PermitData, buildPermit2CollectorData } from "../encoding"; +import { BatchSettlementDepositPayload } from "../types"; +import { toContractChannelConfig } from "./utils"; +import * as Errors from "../errors"; + +export type Permit2DepositBranch = + | { + kind: "standard"; + collectorData: `0x${string}`; + } + | { + kind: "eip2612"; + collectorData: `0x${string}`; + } + | { + kind: "erc20Approval"; + collectorData: `0x${string}`; + signedTransaction: `0x${string}`; + extensionSigner: Erc20ApprovalGasSponsoringSigner; + }; + +/** + * Returns the collector contract used for Permit2 deposits. + * + * @returns Permit2 deposit collector address. + */ +export function getPermit2DepositCollectorAddress(): `0x${string}` { + return getAddress(PERMIT2_DEPOSIT_COLLECTOR_ADDRESS); +} + +/** + * Encodes collector data for a Permit2 deposit payload. + * + * @param payload - Deposit payload containing the Permit2 authorization. + * @param eip2612PermitData - Optional encoded EIP-2612 permit segment. + * @returns ABI-encoded collector data. + */ +export function buildPermit2DepositCollectorData( + payload: BatchSettlementDepositPayload, + eip2612PermitData: `0x${string}` = "0x", +): `0x${string}` { + const auth = payload.deposit.authorization.permit2Authorization; + if (!auth) { + throw new Error(Errors.ErrPermit2AuthorizationRequired); + } + + return buildPermit2CollectorData(auth.nonce, auth.deadline, auth.signature, eip2612PermitData); +} + +/** + * Verifies Permit2 authorization fields, setup branch, and approval-bundle simulation. + * + * @param signer - Facilitator signer for reads and signature verification. + * @param payment - Full payment envelope containing optional extensions. + * @param payload - Batch deposit payload. + * @param requirements - Payment requirements for the request. + * @param chainId - EVM chain id. + * @param context - Optional facilitator extension context. + * @returns A failure response, or `null` when valid. + */ +export async function verifyPermit2DepositAuthorization( + signer: FacilitatorEvmSigner, + payment: PaymentPayload, + payload: BatchSettlementDepositPayload, + requirements: PaymentRequirements, + chainId: number, + context?: FacilitatorContext, +): Promise { + const authResult = await verifyPermit2TypedData(signer, payload, requirements, chainId); + if (authResult) { + return authResult; + } + + const branchResult = await resolvePermit2DepositBranch( + signer, + payment, + payload, + requirements, + context, + ); + if ("isValid" in branchResult) { + return branchResult; + } + + if (branchResult.kind !== "erc20Approval" || !branchResult.extensionSigner.simulateTransactions) { + return null; + } + + const ok = await branchResult.extensionSigner.simulateTransactions([ + branchResult.signedTransaction, + buildDepositTransaction(payload, branchResult.collectorData), + ]); + if (!ok) { + return { + isValid: false, + invalidReason: Errors.ErrDepositSimulationFailed, + payer: payload.channelConfig.payer, + }; + } + + return null; +} + +/** + * Resolves the Permit2 setup branch and collector data for verification or settlement. + * + * @param signer - Facilitator signer for allowance reads. + * @param payment - Full payment envelope containing optional extensions. + * @param payload - Batch deposit payload. + * @param requirements - Payment requirements for the request. + * @param context - Optional facilitator extension context. + * @returns Resolved branch, or a verification failure response. + */ +export async function resolvePermit2DepositBranch( + signer: FacilitatorEvmSigner, + payment: PaymentPayload, + payload: BatchSettlementDepositPayload, + requirements: PaymentRequirements, + context?: FacilitatorContext, +): Promise { + const payer = payload.channelConfig.payer; + const tokenAddress = getAddress(requirements.asset); + const eip2612Info = extractEip2612GasSponsoringInfo(payment); + if (eip2612Info) { + const result = validateBatchEip2612Permit( + eip2612Info, + payer, + tokenAddress, + payload.deposit.amount, + ); + if (!result.isValid) { + return { isValid: false, invalidReason: result.invalidReason, payer }; + } + + const { v, r, s } = splitEip2612Signature(eip2612Info.signature); + return { + kind: "eip2612", + collectorData: buildPermit2DepositCollectorData( + payload, + buildEip2612PermitData({ + value: eip2612Info.amount, + deadline: eip2612Info.deadline, + v, + r, + s, + }), + ), + }; + } + + const erc20Info = extractErc20ApprovalGasSponsoringInfo(payment); + if (erc20Info) { + const extensionSigner = resolveErc20ApprovalExtensionSigner( + context?.getExtension( + ERC20_APPROVAL_GAS_SPONSORING_KEY, + ), + requirements.network, + ); + if (!extensionSigner) { + return { isValid: false, invalidReason: Errors.ErrErc20ApprovalUnavailable, payer }; + } + + const result = await validateErc20ApprovalForPayment(erc20Info, payer, tokenAddress); + if (!result.isValid) { + return { + isValid: false, + invalidReason: result.invalidReason, + invalidMessage: result.invalidMessage, + payer, + }; + } + + return { + kind: "erc20Approval", + collectorData: buildPermit2DepositCollectorData(payload), + signedTransaction: erc20Info.signedTransaction, + extensionSigner, + }; + } + + try { + const allowance = (await signer.readContract({ + address: tokenAddress, + abi: erc20AllowanceAbi, + functionName: "allowance", + args: [payer, PERMIT2_ADDRESS], + })) as bigint; + + if (allowance < BigInt(payload.deposit.amount)) { + return { isValid: false, invalidReason: Errors.ErrPermit2AllowanceRequired, payer }; + } + } catch { + return { isValid: false, invalidReason: Errors.ErrPermit2AllowanceRequired, payer }; + } + + return { + kind: "standard", + collectorData: buildPermit2DepositCollectorData(payload), + }; +} + +/** + * Builds the unsigned batch `deposit` transaction used after a sponsored approval. + * + * @param payload - Batch deposit payload. + * @param collectorData - Encoded Permit2 collector data. + * @returns Transaction request for the extension signer. + */ +export function buildDepositTransaction( + payload: BatchSettlementDepositPayload, + collectorData: `0x${string}`, +): { to: `0x${string}`; data: `0x${string}`; gas: bigint } { + return { + to: getAddress(BATCH_SETTLEMENT_ADDRESS), + data: encodeFunctionData({ + abi: batchSettlementABI, + functionName: "deposit", + args: [ + toContractChannelConfig(payload.channelConfig), + BigInt(payload.deposit.amount), + getPermit2DepositCollectorAddress(), + collectorData, + ], + }), + gas: 300_000n, + }; +} + +/** + * Verifies the channel-bound Permit2 typed-data authorization. + * + * @param signer - Facilitator signer for typed-data verification. + * @param payload - Batch deposit payload. + * @param requirements - Payment requirements for token matching. + * @param chainId - EVM chain id. + * @returns A failure response, or `null` when valid. + */ +async function verifyPermit2TypedData( + signer: FacilitatorEvmSigner, + payload: BatchSettlementDepositPayload, + requirements: PaymentRequirements, + chainId: number, +): Promise { + const auth = payload.deposit.authorization.permit2Authorization; + const payer = payload.channelConfig.payer; + + if (!auth) { + return { isValid: false, invalidReason: Errors.ErrPermit2AuthorizationRequired, payer }; + } + + if (getAddress(auth.from) !== getAddress(payer)) { + return { isValid: false, invalidReason: Errors.ErrPermit2InvalidSignature, payer }; + } + + if (getAddress(auth.spender) !== getPermit2DepositCollectorAddress()) { + return { isValid: false, invalidReason: Errors.ErrPermit2InvalidSpender, payer }; + } + + if (getAddress(auth.permitted.token) !== getAddress(requirements.asset)) { + return { isValid: false, invalidReason: Errors.ErrTokenMismatch, payer }; + } + + if (BigInt(auth.permitted.amount) !== BigInt(payload.deposit.amount)) { + return { isValid: false, invalidReason: Errors.ErrPermit2AmountMismatch, payer }; + } + + if (auth.witness.channelId !== payload.voucher.channelId) { + return { isValid: false, invalidReason: Errors.ErrChannelIdMismatch, payer }; + } + + const now = Math.floor(Date.now() / 1000); + if (BigInt(auth.deadline) < BigInt(now + 6)) { + return { isValid: false, invalidReason: Errors.ErrPermit2DeadlineExpired, payer }; + } + + try { + const ok = await signer.verifyTypedData({ + address: getAddress(auth.from), + domain: { name: "Permit2", chainId, verifyingContract: PERMIT2_ADDRESS }, + types: batchPermit2WitnessTypes, + primaryType: "PermitWitnessTransferFrom", + message: { + permitted: { + token: getAddress(auth.permitted.token), + amount: BigInt(auth.permitted.amount), + }, + spender: getAddress(auth.spender), + nonce: BigInt(auth.nonce), + deadline: BigInt(auth.deadline), + witness: { + channelId: auth.witness.channelId, + }, + }, + signature: auth.signature, + }); + if (!ok) { + return { isValid: false, invalidReason: Errors.ErrPermit2InvalidSignature, payer }; + } + } catch { + return { isValid: false, invalidReason: Errors.ErrPermit2InvalidSignature, payer }; + } + + return null; +} + +/** + * Applies batch-specific EIP-2612 validation on top of the shared Permit2 checks. + * + * @param info - EIP-2612 sponsoring info from the payment envelope. + * @param payer - Expected token owner. + * @param tokenAddress - Expected token contract. + * @param depositAmount - Required approval amount. + * @returns Validation result. + */ +function validateBatchEip2612Permit( + info: Eip2612GasSponsoringInfo, + payer: `0x${string}`, + tokenAddress: `0x${string}`, + depositAmount: string, +): { isValid: true } | { isValid: false; invalidReason: string } { + const baseline = validateEip2612PermitForPayment(info, payer, tokenAddress); + if (!baseline.isValid) { + return { + isValid: false, + invalidReason: baseline.invalidReason ?? Errors.ErrInvalidPayloadType, + }; + } + + if (BigInt(info.amount) !== BigInt(depositAmount)) { + return { isValid: false, invalidReason: Errors.ErrEip2612AmountMismatch }; + } + + return { isValid: true }; +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/deposit.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/deposit.ts new file mode 100644 index 0000000000..36c9412532 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/deposit.ts @@ -0,0 +1,505 @@ +import { + FacilitatorContext, + PaymentPayload, + PaymentRequirements, + VerifyResponse, + SettleResponse, +} from "@x402/core/types"; +import { getAddress } from "viem"; +import { FacilitatorEvmSigner } from "../../signer"; +import type { TransactionRequest } from "../../exact/extensions"; +import { BatchSettlementAssetTransferMethod, BatchSettlementDepositPayload } from "../types"; +import { batchSettlementABI, erc20BalanceOfABI } from "../abi"; +import { BATCH_SETTLEMENT_ADDRESS } from "../constants"; +import { getEvmChainId } from "../../utils"; +import { multicall } from "../../multicall"; +import * as Errors from "../errors"; +import { + readChannelState, + toContractChannelConfig, + validateChannelConfig, + verifyBatchSettlementVoucherTypedData, +} from "./utils"; +import { + buildEip3009DepositCollectorData, + getEip3009DepositCollectorAddress, + verifyEip3009DepositAuthorization, +} from "./deposit-eip3009"; +import { + buildDepositTransaction, + getPermit2DepositCollectorAddress, + resolvePermit2DepositBranch, + verifyPermit2DepositAuthorization, +} from "./deposit-permit2"; + +/** + * Verifies a deposit payload (authorization + voucher) without executing any + * onchain transaction. + * + * Performs the following validations: + * - Token in channelConfig matches the payment requirements asset. + * - Deposit authorization is valid for the selected transfer method. + * - Accompanying voucher signature is valid (ECDSA or ERC-1271). + * - Payer has sufficient token balance for the deposit. + * - Resulting `maxClaimableAmount` does not exceed effective balance (existing + deposit). + * + * @param signer - Facilitator signer for onchain reads and signature verification. + * @param payment - Full payment envelope containing optional extensions. + * @param payload - The full deposit payload including channelConfig, amount, authorization, and voucher. + * @param requirements - Server payment requirements (asset, EIP-712 domain info, timeout, etc.). + * @param context - Optional facilitator extension context. + * @returns A {@link VerifyResponse} with channel state in `extra` on success. + */ +export async function verifyDeposit( + signer: FacilitatorEvmSigner, + payment: PaymentPayload, + payload: BatchSettlementDepositPayload, + requirements: PaymentRequirements, + context?: FacilitatorContext, +): Promise { + const payer = payload.channelConfig.payer; + const chainId = getEvmChainId(requirements.network); + const configErr = validateChannelConfig( + payload.channelConfig, + payload.voucher.channelId, + requirements, + ); + if (configErr) { + return { isValid: false, invalidReason: configErr, payer }; + } + + const transferMethod = resolveDepositTransferMethod(payload, requirements); + if (transferMethod === "permit2" && !payload.deposit.authorization.permit2Authorization) { + return { isValid: false, invalidReason: Errors.ErrInvalidPayloadType, payer }; + } + + const methodErr = + transferMethod === "permit2" + ? await verifyPermit2DepositAuthorization( + signer, + payment, + payload, + requirements, + chainId, + context, + ) + : await verifyEip3009DepositAuthorization(signer, payload, requirements, chainId); + + if (methodErr) { + return methodErr; + } + + const shared = await verifySharedDepositState(signer, payload, requirements); + if (!shared.ok) { + return shared.response; + } + + const { depositAmount, chBalance, chTotalClaimed, wdInitiatedAt, refundNonceVal } = shared; + + const execution = await resolveDepositExecution(signer, payment, payload, requirements, context); + if ("isValid" in execution) { + return execution; + } + + if (!execution.skipDirectSimulation) { + try { + await signer.readContract({ + address: getAddress(BATCH_SETTLEMENT_ADDRESS), + abi: batchSettlementABI, + functionName: "deposit", + args: [ + toContractChannelConfig(payload.channelConfig), + depositAmount, + execution.collector, + execution.collectorData, + ], + }); + } catch (e) { + return { + isValid: false, + invalidReason: Errors.ErrDepositSimulationFailed, + invalidMessage: e instanceof Error ? e.message : String(e), + payer, + }; + } + } + + return { + isValid: true, + payer, + extra: { + channelId: payload.voucher.channelId, + balance: chBalance.toString(), + totalClaimed: chTotalClaimed.toString(), + withdrawRequestedAt: Number(wdInitiatedAt), + refundNonce: refundNonceVal.toString(), + }, + }; +} + +/** + * Verifies channel, voucher, balance, and cumulative amount invariants. + * + * @param signer - Facilitator signer for reads and voucher verification. + * @param payload - Batch deposit payload. + * @param requirements - Payment requirements for the request. + * @returns Shared channel state on success, or a verification failure. + */ +async function verifySharedDepositState( + signer: FacilitatorEvmSigner, + payload: BatchSettlementDepositPayload, + requirements: PaymentRequirements, +): Promise< + | { + ok: true; + chainId: number; + depositAmount: bigint; + payer: `0x${string}`; + chBalance: bigint; + chTotalClaimed: bigint; + wdInitiatedAt: bigint; + refundNonceVal: bigint; + } + | { ok: false; response: VerifyResponse } +> { + const { deposit, voucher } = payload; + const config = payload.channelConfig; + const payer = config.payer; + const chainId = getEvmChainId(requirements.network); + + const configErr = validateChannelConfig(config, voucher.channelId, requirements); + if (configErr) { + return { ok: false, response: { isValid: false, invalidReason: configErr, payer } }; + } + + const voucherOk = await verifyBatchSettlementVoucherTypedData( + signer, + { + channelId: voucher.channelId, + maxClaimableAmount: voucher.maxClaimableAmount, + payerAuthorizer: config.payerAuthorizer, + payer: config.payer, + signature: voucher.signature, + }, + chainId, + ); + if (!voucherOk) { + return { + ok: false, + response: { isValid: false, invalidReason: Errors.ErrInvalidVoucherSignature, payer }, + }; + } + + const mcResults = await multicall(signer.readContract.bind(signer), [ + { + address: getAddress(BATCH_SETTLEMENT_ADDRESS), + abi: batchSettlementABI, + functionName: "channels", + args: [voucher.channelId], + }, + { + address: getAddress(requirements.asset), + abi: erc20BalanceOfABI, + functionName: "balanceOf", + args: [getAddress(payer)], + }, + { + address: getAddress(BATCH_SETTLEMENT_ADDRESS), + abi: batchSettlementABI, + functionName: "pendingWithdrawals", + args: [voucher.channelId], + }, + { + address: getAddress(BATCH_SETTLEMENT_ADDRESS), + abi: batchSettlementABI, + functionName: "refundNonce", + args: [voucher.channelId], + }, + ]); + + const [chRes, balRes, wdRes, rnRes] = mcResults; + if ( + chRes.status === "failure" || + balRes.status === "failure" || + wdRes.status === "failure" || + rnRes.status === "failure" + ) { + return { + ok: false, + response: { isValid: false, invalidReason: Errors.ErrRpcReadFailed, payer }, + }; + } + + const [chBalance, chTotalClaimed] = chRes.result as [bigint, bigint]; + const payerBalance = balRes.result as bigint; + const [, wdInitiatedAt] = wdRes.result as [bigint, bigint]; + const refundNonceVal = rnRes.result as bigint; + const depositAmount = BigInt(deposit.amount); + + if (payerBalance < depositAmount) { + return { + ok: false, + response: { isValid: false, invalidReason: Errors.ErrInsufficientBalance, payer }, + }; + } + + const effectiveBalance = chBalance + depositAmount; + const maxClaimableAmount = BigInt(voucher.maxClaimableAmount); + + if (maxClaimableAmount > effectiveBalance) { + return { + ok: false, + response: { isValid: false, invalidReason: Errors.ErrCumulativeExceedsBalance, payer }, + }; + } + + if (maxClaimableAmount <= chTotalClaimed) { + return { + ok: false, + response: { isValid: false, invalidReason: Errors.ErrCumulativeAmountBelowClaimed, payer }, + }; + } + + return { + ok: true, + chainId, + depositAmount, + payer, + chBalance, + chTotalClaimed, + wdInitiatedAt, + refundNonceVal, + }; +} + +/** + * Executes a deposit onchain through the collector for the selected transfer method. + * + * The deposit is first verified via {@link verifyDeposit}; if invalid the returned + * {@link SettleResponse} will have `success: false` with the verification reason. + * + * @param signer - Facilitator signer used to submit the onchain transaction. + * @param payment - Full payment envelope containing optional extensions. + * @param payload - The deposit payload (channelConfig, amount, authorization, voucher). + * @param requirements - Server payment requirements. + * @param context - Optional facilitator extension context. + * @returns A {@link SettleResponse} with the transaction hash and updated channel state in `extra`. + */ +export async function settleDeposit( + signer: FacilitatorEvmSigner, + payment: PaymentPayload, + payload: BatchSettlementDepositPayload, + requirements: PaymentRequirements, + context?: FacilitatorContext, +): Promise { + const { deposit, voucher } = payload; + const config = payload.channelConfig; + const payer = config.payer; + + const verified = await verifyDeposit(signer, payment, payload, requirements, context); + if (!verified.isValid) { + const reason = verified.invalidReason ?? Errors.ErrInvalidPayloadType; + return { + success: false, + errorReason: reason, + errorMessage: verified.invalidMessage ?? reason, + transaction: "", + network: requirements.network, + payer: verified.payer, + }; + } + + try { + const execution = await resolveDepositExecution( + signer, + payment, + payload, + requirements, + context, + ); + if ("isValid" in execution) { + const reason = execution.invalidReason ?? Errors.ErrInvalidPayloadType; + return { + success: false, + errorReason: reason, + errorMessage: execution.invalidMessage ?? reason, + transaction: "", + network: requirements.network, + payer: execution.payer, + }; + } + + const depositTx = buildDepositTransaction(payload, execution.collectorData); + const tx = + execution.kind === "erc20Approval" + ? ( + await execution.extensionSigner.sendTransactions([ + execution.signedTransaction, + depositTx, + ]) + )[1] + : await signer.writeContract({ + address: getAddress(BATCH_SETTLEMENT_ADDRESS), + abi: batchSettlementABI, + functionName: "deposit", + args: [ + toContractChannelConfig(config), + BigInt(deposit.amount), + execution.collector, + execution.collectorData, + ], + }); + + const receipt = await signer.waitForTransactionReceipt({ hash: tx }); + + if (receipt.status !== "success") { + return { + success: false, + errorReason: Errors.ErrDepositTransactionFailed, + errorMessage: `transaction reverted (receipt status ${receipt.status})`, + transaction: tx, + network: requirements.network, + payer, + }; + } + + const optimisticExtra = { + channelState: { + channelId: voucher.channelId, + balance: ( + BigInt(String(verified.extra?.balance ?? "0")) + BigInt(deposit.amount) + ).toString(), + totalClaimed: String(verified.extra?.totalClaimed ?? "0"), + withdrawRequestedAt: Number(verified.extra?.withdrawRequestedAt ?? 0), + refundNonce: String(verified.extra?.refundNonce ?? "0"), + }, + }; + + // Poll the RPC until it reflects the just-confirmed deposit, so subsequent verify reads are guaranteed to see this balance + const expectedMinBalance = BigInt(optimisticExtra.channelState.balance); + const rpcDeadline = Date.now() + 2_000; + let postState = await readChannelState(signer, voucher.channelId); + while (postState.balance < expectedMinBalance && Date.now() < rpcDeadline) { + await new Promise(resolve => setTimeout(resolve, 150)); + postState = await readChannelState(signer, voucher.channelId); + } + + const rpcCaughtUp = postState.balance >= expectedMinBalance; + + return { + success: true, + transaction: tx, + network: requirements.network, + payer, + amount: deposit.amount, + extra: rpcCaughtUp + ? { + ...optimisticExtra, + channelState: { + channelId: voucher.channelId, + balance: postState.balance.toString(), + totalClaimed: postState.totalClaimed.toString(), + withdrawRequestedAt: postState.withdrawRequestedAt, + refundNonce: postState.refundNonce.toString(), + }, + } + : optimisticExtra, + }; + } catch (e) { + return { + success: false, + errorReason: Errors.ErrDepositTransactionFailed, + errorMessage: e instanceof Error ? e.message : String(e), + transaction: "", + network: requirements.network, + payer, + }; + } +} + +type DepositExecution = + | { + kind: "direct"; + collector: `0x${string}`; + collectorData: `0x${string}`; + skipDirectSimulation?: false; + } + | { + kind: "erc20Approval"; + collector: `0x${string}`; + collectorData: `0x${string}`; + signedTransaction: `0x${string}`; + extensionSigner: { + sendTransactions(transactions: TransactionRequest[]): Promise<`0x${string}`[]>; + }; + skipDirectSimulation: true; + }; + +/** + * Resolves the collector address and collector data for a deposit payload. + * + * @param signer - Facilitator signer for Permit2 allowance reads. + * @param payment - Full payment envelope containing optional extensions. + * @param payload - Batch deposit payload. + * @param requirements - Payment requirements for the request. + * @param context - Optional facilitator extension context. + * @returns Execution details, or a verification failure response. + */ +async function resolveDepositExecution( + signer: FacilitatorEvmSigner, + payment: PaymentPayload, + payload: BatchSettlementDepositPayload, + requirements: PaymentRequirements, + context?: FacilitatorContext, +): Promise { + const transferMethod = resolveDepositTransferMethod(payload, requirements); + if (transferMethod === "eip3009") { + return { + kind: "direct", + collector: getEip3009DepositCollectorAddress(), + collectorData: buildEip3009DepositCollectorData(payload), + }; + } + + const branch = await resolvePermit2DepositBranch(signer, payment, payload, requirements, context); + if ("isValid" in branch) { + return branch; + } + + if (branch.kind === "erc20Approval") { + return { + kind: "erc20Approval", + collector: getPermit2DepositCollectorAddress(), + collectorData: branch.collectorData, + signedTransaction: branch.signedTransaction, + extensionSigner: branch.extensionSigner, + skipDirectSimulation: true, + }; + } + + return { + kind: "direct", + collector: getPermit2DepositCollectorAddress(), + collectorData: branch.collectorData, + }; +} + +/** + * Selects the transfer method from requirements, falling back to payload shape. + * + * @param payload - Batch deposit payload. + * @param requirements - Payment requirements for the request. + * @returns Selected batch-settlement transfer method. + */ +function resolveDepositTransferMethod( + payload: BatchSettlementDepositPayload, + requirements: PaymentRequirements, +): BatchSettlementAssetTransferMethod { + const hinted = ( + requirements.extra as { assetTransferMethod?: BatchSettlementAssetTransferMethod } + )?.assetTransferMethod; + if (hinted) { + return hinted; + } + return payload.deposit.authorization.permit2Authorization ? "permit2" : "eip3009"; +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/index.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/index.ts new file mode 100644 index 0000000000..a1bca12efd --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/index.ts @@ -0,0 +1 @@ +export { BatchSettlementEvmScheme } from "./scheme"; diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/refund.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/refund.ts new file mode 100644 index 0000000000..c0b5429141 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/refund.ts @@ -0,0 +1,305 @@ +import { SettleResponse, PaymentRequirements } from "@x402/core/types"; +import { encodeFunctionData, getAddress } from "viem"; +import { FacilitatorEvmSigner } from "../../signer"; +import type { + AuthorizerSigner, + BatchSettlementEnrichedRefundPayload, + ChannelState, +} from "../types"; +import { batchSettlementABI } from "../abi"; +import { BATCH_SETTLEMENT_ADDRESS } from "../constants"; +import { computeChannelId } from "../utils"; +import { signClaimBatch, signRefund } from "../authorizerSigner"; +import * as Errors from "../errors"; +import { buildVoucherClaimArgs } from "./claim"; +import { readChannelState, toContractChannelConfig } from "./utils"; + +type RefundSettlementExtra = { + channelState: { + channelId: `0x${string}`; + balance: string; + totalClaimed: string; + withdrawRequestedAt: number; + refundNonce: string; + }; +}; + +type RefundSettlementDetails = { + amount: string; + extra: RefundSettlementExtra; +}; + +const REFUND_STATE_POLL_MS = 2_000; +const REFUND_STATE_POLL_INTERVAL_MS = 150; + +/** + * Builds facilitator-owned response details for a refund settlement after applying the refund amount. + * + * @param payload - Refund payload containing claims and amount. + * @param channelId - Canonical channel id for the refund. + * @param preState - Onchain channel state before this refund, or null if unknown. + * @returns Actual refund amount and extra fields for the settlement response. + */ +function buildRefundExtra( + payload: BatchSettlementEnrichedRefundPayload, + channelId: `0x${string}`, + preState: ChannelState | null, +): RefundSettlementDetails { + const preTotalClaimed = preState?.totalClaimed ?? 0n; + const preBalance = preState?.balance ?? 0n; + + const lastClaimTotal = + payload.claims.length > 0 + ? BigInt(payload.claims[payload.claims.length - 1].totalClaimed) + : preTotalClaimed; + const postClaimTotalClaimed = lastClaimTotal > preTotalClaimed ? lastClaimTotal : preTotalClaimed; + + const available = preBalance - postClaimTotalClaimed; + const requestedAmount = BigInt(payload.amount); + const actualRefund = requestedAmount > available ? available : requestedAmount; + + return { + amount: actualRefund.toString(), + extra: { + channelState: { + channelId, + balance: (preBalance - actualRefund).toString(), + totalClaimed: postClaimTotalClaimed.toString(), + withdrawRequestedAt: 0, + refundNonce: String((preState?.refundNonce ?? 0n) + 1n), + }, + }, + }; +} + +/** + * Reads the post-refund state when pending withdrawal state can be affected. + * + * @param signer - Facilitator signer used for onchain reads. + * @param channelId - Channel that was refunded. + * @param submittedNonce - Nonce used for this refund transaction. + * @returns Fresh channel state once the nonce advances, or `null` if RPC reads lag. + */ +async function readPostRefundState( + signer: FacilitatorEvmSigner, + channelId: `0x${string}`, + submittedNonce: string, +): Promise { + const expectedNonce = BigInt(submittedNonce) + 1n; + const deadline = Date.now() + REFUND_STATE_POLL_MS; + + do { + let state: ChannelState; + try { + state = await readChannelState(signer, channelId); + } catch { + return null; + } + if (state.refundNonce >= expectedNonce) { + return state; + } + await new Promise(resolve => setTimeout(resolve, REFUND_STATE_POLL_INTERVAL_MS)); + } while (Date.now() < deadline); + + return null; +} + +/** + * Builds refund response details from confirmed post-transaction state. + * + * @param channelId - Canonical channel id for the refund. + * @param preState - Onchain state read before the transaction. + * @param postState - Onchain state after the transaction. + * @returns Actual refund amount and extra fields for the settlement response. + */ +function buildRefundExtraFromPostState( + channelId: `0x${string}`, + preState: ChannelState, + postState: ChannelState, +): RefundSettlementDetails { + const actualRefund = + preState.balance > postState.balance ? preState.balance - postState.balance : 0n; + + return { + amount: actualRefund.toString(), + extra: { + channelState: { + channelId, + balance: postState.balance.toString(), + totalClaimed: postState.totalClaimed.toString(), + withdrawRequestedAt: postState.withdrawRequestedAt, + refundNonce: postState.refundNonce.toString(), + }, + }, + }; +} + +/** + * Executes a cooperative refund via `refundWithSignature`. + * + * When `refundAuthorizerSignature` / `claimAuthorizerSignature` are present they are used + * directly. When absent the facilitator signs the missing digests using + * `authorizerSigner`, after verifying that `config.receiverAuthorizer` matches + * `authorizerSigner.address`. + * + * If `payload.claims` is non-empty, the claim and refund are batched atomically via + * the contract's `multicall`. + * + * @param signer - Facilitator signer used to submit the onchain transactions. + * @param payload - Refund payload with optional signatures, amount, and nonce. + * @param requirements - Payment requirements for network identification. + * @param authorizerSigner - Dedicated key for producing EIP-712 signatures. + * @returns A {@link SettleResponse} with the transaction hash on success. + */ +export async function executeRefundWithSignature( + signer: FacilitatorEvmSigner, + payload: BatchSettlementEnrichedRefundPayload, + requirements: PaymentRequirements, + authorizerSigner: AuthorizerSigner, +): Promise { + const network = requirements.network; + + try { + const channelId = computeChannelId(payload.channelConfig, network); + const preState = await readChannelState(signer, channelId); + const contractAddr = getAddress(BATCH_SETTLEMENT_ADDRESS); + + const hasClientSig = payload.refundAuthorizerSignature !== undefined; + const authorizerMismatch = + getAddress(payload.channelConfig.receiverAuthorizer) !== getAddress(authorizerSigner.address); + + if (!hasClientSig && authorizerMismatch) { + return { + success: false, + errorReason: Errors.ErrAuthorizerAddressMismatch, + transaction: "", + network, + }; + } + + const refundSig = + payload.refundAuthorizerSignature ?? + (await signRefund(authorizerSigner, channelId, payload.amount, payload.refundNonce, network)); + + const refundCalldata = encodeFunctionData({ + abi: batchSettlementABI, + functionName: "refundWithSignature", + args: [ + toContractChannelConfig(payload.channelConfig), + BigInt(payload.amount), + BigInt(payload.refundNonce), + refundSig, + ], + }); + + let tx: `0x${string}`; + + if (payload.claims.length > 0) { + let claimSig = payload.claimAuthorizerSignature; + if (!claimSig) { + claimSig = await signClaimBatch(authorizerSigner, payload.claims, network); + } + + const claimCalldata = encodeFunctionData({ + abi: batchSettlementABI, + functionName: "claimWithSignature", + args: [buildVoucherClaimArgs(payload.claims), claimSig], + }); + + try { + await signer.readContract({ + address: contractAddr, + abi: batchSettlementABI, + functionName: "multicall", + args: [[claimCalldata, refundCalldata]], + }); + } catch (e) { + return { + success: false, + errorReason: Errors.ErrRefundSimulationFailed, + errorMessage: e instanceof Error ? e.message : String(e), + transaction: "", + network, + }; + } + + tx = await signer.writeContract({ + address: contractAddr, + abi: batchSettlementABI, + functionName: "multicall", + args: [[claimCalldata, refundCalldata]], + }); + } else { + try { + await signer.readContract({ + address: contractAddr, + abi: batchSettlementABI, + functionName: "refundWithSignature", + args: [ + toContractChannelConfig(payload.channelConfig), + BigInt(payload.amount), + BigInt(payload.refundNonce), + refundSig, + ], + }); + } catch (e) { + return { + success: false, + errorReason: Errors.ErrRefundSimulationFailed, + errorMessage: e instanceof Error ? e.message : String(e), + transaction: "", + network, + }; + } + + tx = await signer.writeContract({ + address: contractAddr, + abi: batchSettlementABI, + functionName: "refundWithSignature", + args: [ + toContractChannelConfig(payload.channelConfig), + BigInt(payload.amount), + BigInt(payload.refundNonce), + refundSig, + ], + }); + } + + const receipt = await signer.waitForTransactionReceipt({ hash: tx }); + if (receipt.status !== "success") { + return { + success: false, + errorReason: Errors.ErrRefundTransactionFailed, + errorMessage: `transaction reverted (receipt status ${receipt.status})`, + transaction: tx, + network, + }; + } + + const postState = + preState && preState.withdrawRequestedAt !== 0 + ? await readPostRefundState(signer, channelId, payload.refundNonce) + : null; + const refundDetails = + preState && postState + ? buildRefundExtraFromPostState(channelId, preState, postState) + : buildRefundExtra(payload, channelId, preState); + + return { + success: true, + transaction: tx, + network, + payer: payload.channelConfig.payer, + amount: refundDetails.amount, + extra: refundDetails.extra, + }; + } catch (e) { + return { + success: false, + errorReason: Errors.ErrRefundTransactionFailed, + errorMessage: e instanceof Error ? e.message : String(e), + transaction: "", + network, + }; + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/scheme.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/scheme.ts new file mode 100644 index 0000000000..521417ff33 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/scheme.ts @@ -0,0 +1,168 @@ +import { + PaymentPayload, + PaymentRequirements, + SchemeNetworkFacilitator, + FacilitatorContext, + SettleResponse, + VerifyResponse, +} from "@x402/core/types"; +import { FacilitatorEvmSigner } from "../../signer"; +import { BATCH_SETTLEMENT_SCHEME } from "../constants"; +import { + isBatchSettlementDepositPayload, + isBatchSettlementVoucherPayload, + isBatchSettlementClaimPayload, + isBatchSettlementSettlePayload, + isBatchSettlementRefundPayload, + isBatchSettlementEnrichedRefundPayload, +} from "../types"; +import type { AuthorizerSigner } from "../types"; +import { verifyDeposit, settleDeposit } from "./deposit"; +import { verifyVoucher } from "./voucher"; +import { executeClaimWithSignature } from "./claim"; +import { executeSettle } from "./settle"; +import { executeRefundWithSignature } from "./refund"; +import * as Errors from "../errors"; + +/** + * Facilitator-side implementation of the `batch-settlement` scheme for EVM networks. + * + * Routes incoming verify/settle requests to the appropriate handler based on payload + * type (deposit, voucher, claim, settle, refund). + */ +export class BatchSettlementEvmScheme implements SchemeNetworkFacilitator { + readonly scheme = BATCH_SETTLEMENT_SCHEME; + readonly caipFamily = "eip155:*"; + + /** + * Creates a facilitator scheme for verifying and settling batch-settlement payments. + * + * @param signer - Facilitator EVM signer(s) used for tx submission and onchain reads. + * @param authorizerSigner - Dedicated key that provides EIP-712 signatures for + * `claimWithSignature` / `refundWithSignature`. The facilitator will sign missing + * authorizer signatures using this key when the server omits them. + */ + constructor( + private readonly signer: FacilitatorEvmSigner, + private readonly authorizerSigner: AuthorizerSigner, + ) {} + + /** + * Returns facilitator-specific extra fields to be merged into payment requirements. + * + * Exposes the configured `receiverAuthorizer` address so the server and client can + * embed it in `ChannelConfig`. + * + * @param _ - Network identifier (unused). + * @returns Extra fields containing `receiverAuthorizer`. + */ + getExtra(_: string): { receiverAuthorizer: `0x${string}` } | undefined { + return { receiverAuthorizer: this.authorizerSigner.address }; + } + + /** + * Returns all facilitator signer addresses available for the given network. + * + * @param _ - Network identifier (unused). + * @returns Array of hex addresses. + */ + getSigners(_: string): `0x${string}`[] { + return [...this.signer.getAddresses()]; + } + + /** + * Verifies a payment payload (deposit or voucher) without executing settlement. + * + * @param payload - The x402 payment payload envelope. + * @param requirements - Server payment requirements (scheme, network, asset, amount). + * @param context - Optional facilitator extension context. + * @returns A {@link VerifyResponse} indicating validity with payer and channel state in `extra`. + */ + async verify( + payload: PaymentPayload, + requirements: PaymentRequirements, + context?: FacilitatorContext, + ): Promise { + const rawPayload = payload.payload; + + if ( + payload.accepted.scheme !== BATCH_SETTLEMENT_SCHEME || + requirements.scheme !== BATCH_SETTLEMENT_SCHEME + ) { + return { isValid: false, invalidReason: Errors.ErrInvalidScheme }; + } + + if (payload.accepted.network !== requirements.network) { + return { isValid: false, invalidReason: Errors.ErrNetworkMismatch }; + } + + if (isBatchSettlementDepositPayload(rawPayload)) { + return verifyDeposit(this.signer, payload, rawPayload, requirements, context); + } + + if (isBatchSettlementVoucherPayload(rawPayload)) { + return verifyVoucher(this.signer, rawPayload, requirements, rawPayload.channelConfig); + } + + if (isBatchSettlementRefundPayload(rawPayload)) { + return verifyVoucher(this.signer, rawPayload, requirements, rawPayload.channelConfig); + } + + return { isValid: false, invalidReason: Errors.ErrInvalidPayloadType }; + } + + /** + * Executes settlement for a payment payload. + * + * Dispatches to the correct handler based on payload settle action: + * - `deposit` → onchain `deposit(config, amount, collector, collectorData)` + * - `claim` → onchain `claimWithSignature(VoucherClaim[], bytes)` + * - `settle` → onchain `settle(receiver, token)` + * - `refund` → optional claim + onchain `refundWithSignature(config, amount, nonce, sig)` + * + * @param payload - The x402 payment payload envelope. + * @param requirements - Server payment requirements. + * @param context - Optional facilitator extension context. + * @returns A {@link SettleResponse} with the transaction hash on success. + */ + async settle( + payload: PaymentPayload, + requirements: PaymentRequirements, + context?: FacilitatorContext, + ): Promise { + const rawPayload = payload.payload; + + if (isBatchSettlementDepositPayload(rawPayload)) { + return settleDeposit(this.signer, payload, rawPayload, requirements, context); + } + + if (isBatchSettlementClaimPayload(rawPayload)) { + return executeClaimWithSignature( + this.signer, + rawPayload, + requirements, + this.authorizerSigner, + ); + } + + if (isBatchSettlementEnrichedRefundPayload(rawPayload)) { + return executeRefundWithSignature( + this.signer, + rawPayload, + requirements, + this.authorizerSigner, + ); + } + + if (isBatchSettlementSettlePayload(rawPayload)) { + return executeSettle(this.signer, rawPayload, requirements); + } + + return { + success: false, + errorReason: Errors.ErrInvalidPayloadType, + transaction: "", + network: requirements.network, + }; + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/settle.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/settle.ts new file mode 100644 index 0000000000..cc5adc4c1c --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/settle.ts @@ -0,0 +1,95 @@ +import { SettleResponse, PaymentRequirements } from "@x402/core/types"; +import { getAddress, isAddressEqual, parseEventLogs } from "viem"; +import { FacilitatorEvmSigner } from "../../signer"; +import { BatchSettlementSettlePayload } from "../types"; +import { batchSettlementABI } from "../abi"; +import { BATCH_SETTLEMENT_ADDRESS } from "../constants"; +import * as Errors from "../errors"; + +/** + * Transfers claimed funds from the contract. + * + * This should be called after one or more `claim()` transactions have updated the + * receiver's `totalClaimed` accounting onchain. + * + * @param signer - Facilitator signer used to submit the settlement transaction. + * @param payload - Settle payload containing the receiver address and token address. + * @param requirements - Payment requirements for network identification. + * @returns A {@link SettleResponse} with the transaction hash on success. + */ +export async function executeSettle( + signer: FacilitatorEvmSigner, + payload: BatchSettlementSettlePayload, + requirements: PaymentRequirements, +): Promise { + const network = requirements.network; + const contractAddr = getAddress(BATCH_SETTLEMENT_ADDRESS); + const receiver = getAddress(payload.receiver); + const token = getAddress(payload.token); + + try { + await signer.readContract({ + address: contractAddr, + abi: batchSettlementABI, + functionName: "settle", + args: [receiver, token], + }); + } catch (e) { + return { + success: false, + errorReason: Errors.ErrSettleSimulationFailed, + errorMessage: e instanceof Error ? e.message : String(e), + transaction: "", + network, + }; + } + + try { + const tx = await signer.writeContract({ + address: contractAddr, + abi: batchSettlementABI, + functionName: "settle", + args: [receiver, token], + }); + + const receipt = await signer.waitForTransactionReceipt({ hash: tx }); + + if (receipt.status !== "success") { + return { + success: false, + errorReason: Errors.ErrSettleTransactionFailed, + errorMessage: `transaction reverted (receipt status ${receipt.status})`, + transaction: tx, + network, + }; + } + + let amount = ""; + if (receipt.logs) { + const logs = parseEventLogs({ + abi: batchSettlementABI, + eventName: "Settled", + logs: receipt.logs.filter(log => isAddressEqual(log.address, contractAddr)), + }); + const settledLog = logs.find( + log => isAddressEqual(log.args.receiver, receiver) && isAddressEqual(log.args.token, token), + ); + amount = settledLog?.args.amount.toString() ?? "0"; + } + + return { + success: true, + transaction: tx, + network, + amount, + }; + } catch (e) { + return { + success: false, + errorReason: Errors.ErrSettleTransactionFailed, + errorMessage: e instanceof Error ? e.message : String(e), + transaction: "", + network, + }; + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/utils.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/utils.ts new file mode 100644 index 0000000000..8b7a2835e8 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/utils.ts @@ -0,0 +1,217 @@ +import { getAddress, verifyTypedData as viemVerifyTypedData } from "viem"; +import type { PaymentRequirements } from "@x402/core/types"; +import { FacilitatorEvmSigner } from "../../signer"; +import { multicall } from "../../multicall"; +import { + BATCH_SETTLEMENT_ADDRESS, + MIN_WITHDRAW_DELAY, + MAX_WITHDRAW_DELAY, + voucherTypes, +} from "../constants"; +import { batchSettlementABI } from "../abi"; +import type { + BatchSettlementPaymentRequirementsExtra, + ChannelConfig, + ChannelState, +} from "../types"; +import { computeChannelId, getBatchSettlementEip712Domain } from "../utils"; +import * as Errors from "../errors"; + +/** + * Normalises a {@link ChannelConfig} into the checksummed-address tuple expected by the + * batch-settlement contract's `deposit` / `refundWithSignature` / `claimWithSignature` calls. + * + * @param config - In-memory channel configuration. + * @returns Channel config tuple with all address fields checksummed via `getAddress`. + */ +export function toContractChannelConfig(config: ChannelConfig) { + return { + payer: getAddress(config.payer), + payerAuthorizer: getAddress(config.payerAuthorizer), + receiver: getAddress(config.receiver), + receiverAuthorizer: getAddress(config.receiverAuthorizer), + token: getAddress(config.token), + withdrawDelay: config.withdrawDelay, + salt: config.salt, + }; +} + +/** + * Case-insensitive comparison of two channel id hex strings. + * + * @param a - First channel id. + * @param b - Second channel id (may be any unknown value). + * @returns `true` when both ids refer to the same channel. + */ +export function channelIdsEqual(a: `0x${string}`, b: unknown): boolean { + if (typeof b !== "string" || b.length === 0) return false; + const norm = (x: string) => { + let s = x.toLowerCase(); + if (s.startsWith("0x")) s = s.slice(2); + return `0x${s}`; + }; + return norm(a) === norm(b); +} + +/** + * Validates the time window of an ERC-3009 `ReceiveWithAuthorization`. + * + * @param validAfter - Earliest unix timestamp the authorization is valid (in seconds). + * @param validBefore - Latest unix timestamp before which the authorization is valid. + * @returns An error code string if the time window is invalid, otherwise `undefined`. + */ +export function erc3009AuthorizationTimeInvalidReason( + validAfter: bigint, + validBefore: bigint, +): string | undefined { + const now = Math.floor(Date.now() / 1000); + if (validBefore < BigInt(now + 6)) return Errors.ErrValidBeforeExpired; + if (validAfter > BigInt(now)) return Errors.ErrValidAfterInFuture; + return undefined; +} + +/** + * Dual-path voucher signature verification. + * + * When `payerAuthorizer` is a non-zero address, the signature is verified off-chain via + * ECDSA recovery against that address (no RPC call). When `payerAuthorizer` is `address(0)`, + * verification falls back to an ERC-1271 `isValidSignature` call against the payer contract + * (smart-wallet path). + * + * @param signer - Facilitator signer providing `verifyTypedData` (may issue RPC for ERC-1271). + * @param params - Voucher fields and authorizer addresses needed for verification. + * @param params.channelId - EIP-712 voucher channel id (`bytes32` hex). + * @param params.maxClaimableAmount - Max cumulative claimable amount as a decimal string. + * @param params.payerAuthorizer - Address that signed the voucher; zero address selects ERC-1271 verification. + * @param params.payer - Payer contract address (used for ERC-1271). + * @param params.signature - EIP-712 signature bytes over the voucher. + * @param chainId - Numeric EVM chain id for the EIP-712 domain. + * @returns `true` when the voucher signature is valid. + */ +export async function verifyBatchSettlementVoucherTypedData( + signer: FacilitatorEvmSigner, + params: { + channelId: `0x${string}`; + maxClaimableAmount: string; + payerAuthorizer: `0x${string}`; + payer: `0x${string}`; + signature: `0x${string}`; + }, + chainId: number, +): Promise { + const domain = getBatchSettlementEip712Domain(chainId); + const message = { + channelId: params.channelId, + maxClaimableAmount: BigInt(params.maxClaimableAmount), + }; + + const zeroAddress = "0x0000000000000000000000000000000000000000"; + + if (params.payerAuthorizer !== zeroAddress) { + return viemVerifyTypedData({ + address: getAddress(params.payerAuthorizer), + domain, + types: voucherTypes, + primaryType: "Voucher", + message, + signature: params.signature, + }); + } + + return signer.verifyTypedData({ + address: getAddress(params.payer), + domain, + types: voucherTypes, + primaryType: "Voucher", + message, + signature: params.signature, + }); +} + +/** + * Validates that a {@link ChannelConfig} is consistent with the claimed `channelId` and + * the server's {@link PaymentRequirements}. + * + * @param config - The channel configuration from the payload. + * @param channelId - The `channelId` claimed in the payload. + * @param requirements - Server payment requirements to cross-check against. + * @returns An error code string if validation fails, otherwise `undefined`. + */ +export function validateChannelConfig( + config: ChannelConfig, + channelId: `0x${string}`, + requirements: PaymentRequirements, +): string | undefined { + const computedId = computeChannelId(config, requirements.network); + if (computedId.toLowerCase() !== channelId.toLowerCase()) { + return Errors.ErrChannelIdMismatch; + } + + if (getAddress(config.receiver) !== getAddress(requirements.payTo)) { + return Errors.ErrReceiverMismatch; + } + + const extra = requirements.extra as Partial | undefined; + const requiredReceiverAuthorizer = extra?.receiverAuthorizer; + + if ( + !requiredReceiverAuthorizer || + getAddress(requiredReceiverAuthorizer) === "0x0000000000000000000000000000000000000000" || + getAddress(config.receiverAuthorizer) !== getAddress(requiredReceiverAuthorizer) + ) { + return Errors.ErrReceiverAuthorizerMismatch; + } + + if (getAddress(config.token) !== getAddress(requirements.asset)) { + return Errors.ErrTokenMismatch; + } + + if (extra?.withdrawDelay !== undefined && config.withdrawDelay !== Number(extra.withdrawDelay)) { + return Errors.ErrWithdrawDelayMismatch; + } + + if (config.withdrawDelay < MIN_WITHDRAW_DELAY || config.withdrawDelay > MAX_WITHDRAW_DELAY) { + return Errors.ErrWithdrawDelayOutOfRange; + } + + return undefined; +} + +/** + * Reads onchain channel state via a 3-call multicall: + * `channels(channelId)`, `pendingWithdrawals(channelId)`, `refundNonce(channelId)`. + * + * Throws when any sub-call fails so callers can distinguish RPC failures + * from missing channels (which return zero balance/totalClaimed/refundNonce). + * + * @param signer - Facilitator signer for onchain reads. + * @param channelId - The `bytes32` channel id. + * @returns Fresh {@link ChannelState}. + */ +export async function readChannelState( + signer: FacilitatorEvmSigner, + channelId: `0x${string}`, +): Promise { + const target = getAddress(BATCH_SETTLEMENT_ADDRESS); + const mcResults = await multicall(signer.readContract.bind(signer), [ + { address: target, abi: batchSettlementABI, functionName: "channels", args: [channelId] }, + { + address: target, + abi: batchSettlementABI, + functionName: "pendingWithdrawals", + args: [channelId], + }, + { address: target, abi: batchSettlementABI, functionName: "refundNonce", args: [channelId] }, + ]); + + const [chRes, wdRes, rnRes] = mcResults; + if (chRes.status === "failure" || wdRes.status === "failure" || rnRes.status === "failure") { + throw new Error(`${Errors.ErrRpcReadFailed}: multicall returned failure for ${channelId}`); + } + + const [balance, totalClaimed] = chRes.result as [bigint, bigint]; + const [, wdInitiatedAt] = wdRes.result as [bigint, bigint]; + const refundNonce = rnRes.result as bigint; + + return { balance, totalClaimed, withdrawRequestedAt: Number(wdInitiatedAt), refundNonce }; +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/voucher.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/voucher.ts new file mode 100644 index 0000000000..abee9f40e6 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/facilitator/voucher.ts @@ -0,0 +1,98 @@ +import { PaymentRequirements, VerifyResponse } from "@x402/core/types"; +import { FacilitatorEvmSigner } from "../../signer"; +import { + BatchSettlementRefundPayload, + BatchSettlementVoucherPayload, + ChannelConfig, +} from "../types"; +import { getEvmChainId } from "../../utils"; +import * as Errors from "../errors"; +import { + validateChannelConfig, + verifyBatchSettlementVoucherTypedData, + readChannelState, +} from "./utils"; + +/** + * Verifies a cumulative voucher payload against onchain channel state. + * + * @param signer - Facilitator signer used for onchain reads and signature verification. + * @param payload - Voucher or refund payload with signed voucher fields. + * @param requirements - Server payment requirements (asset, network, amount). + * @param channelConfig - Reconstructed channel configuration for the payer/receiver pair. + * @returns A {@link VerifyResponse} indicating validity and returning channel state in `extra`. + */ +export async function verifyVoucher( + signer: FacilitatorEvmSigner, + payload: BatchSettlementVoucherPayload | BatchSettlementRefundPayload, + requirements: PaymentRequirements, + channelConfig: ChannelConfig, +): Promise { + const { voucher } = payload; + const channelId = voucher.channelId; + const chainId = getEvmChainId(requirements.network); + + const configErr = validateChannelConfig(channelConfig, channelId, requirements); + if (configErr) { + return { isValid: false, invalidReason: configErr, payer: channelConfig.payer }; + } + + const voucherOk = await verifyBatchSettlementVoucherTypedData( + signer, + { + channelId, + maxClaimableAmount: voucher.maxClaimableAmount, + payerAuthorizer: channelConfig.payerAuthorizer, + payer: channelConfig.payer, + signature: voucher.signature, + }, + chainId, + ); + if (!voucherOk) { + return { + isValid: false, + invalidReason: Errors.ErrInvalidVoucherSignature, + payer: channelConfig.payer, + }; + } + + const state = await readChannelState(signer, channelId); + + if (state.balance === 0n) { + return { isValid: false, invalidReason: Errors.ErrChannelNotFound, payer: channelConfig.payer }; + } + + const maxClaimableAmount = BigInt(voucher.maxClaimableAmount); + + if (maxClaimableAmount > state.balance) { + return { + isValid: false, + invalidReason: Errors.ErrCumulativeExceedsBalance, + payer: channelConfig.payer, + }; + } + + const belowClaimed = + payload.type === "refund" + ? maxClaimableAmount < state.totalClaimed + : maxClaimableAmount <= state.totalClaimed; + if (belowClaimed) { + return { + isValid: false, + invalidReason: Errors.ErrCumulativeAmountBelowClaimed, + payer: channelConfig.payer, + }; + } + + return { + isValid: true, + payer: channelConfig.payer, + extra: { + channelId, + balance: state.balance.toString(), + totalClaimed: state.totalClaimed.toString(), + withdrawRequestedAt: state.withdrawRequestedAt, + refundNonce: state.refundNonce.toString(), + }, + }; +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/index.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/index.ts new file mode 100644 index 0000000000..541e7478f1 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/index.ts @@ -0,0 +1,2 @@ +export { BatchSettlementEvmScheme } from "./client/scheme"; +export { computeChannelId } from "./utils"; diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/server/channelManager.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/server/channelManager.ts new file mode 100644 index 0000000000..c8ca1a33b2 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/server/channelManager.ts @@ -0,0 +1,791 @@ +import type { + Network, + PaymentPayload, + PaymentRequirements, + SettleResponse, +} from "@x402/core/types"; +import type { FacilitatorClient } from "@x402/core/server"; +import type { BatchSettlementVoucherClaim } from "../types"; +import type { BatchSettlementEvmScheme } from "./scheme"; +import { computeChannelId } from "../utils"; +import { BATCH_SETTLEMENT_SCHEME } from "../constants"; +import { signClaimBatch, signRefund } from "../authorizerSigner"; +import type { Channel } from "./storage"; + +export interface ChannelManagerConfig { + scheme: BatchSettlementEvmScheme; + facilitator: FacilitatorClient; + receiver: `0x${string}`; + token: `0x${string}`; + network: Network; +} + +export type ClaimChannelSelector = ( + channels: Channel[], + context: AutoSettlementContext, +) => Channel[] | Promise; + +export interface ClaimOptions { + maxClaimsPerBatch?: number; + idleSecs?: number; + selectClaimChannels?: ClaimChannelSelector; +} + +export interface AutoSettlementConfig { + claimIntervalSecs?: number; + settleIntervalSecs?: number; + refundIntervalSecs?: number; + maxClaimsPerBatch?: number; + selectClaimChannels?: ClaimChannelSelector; + shouldSettle?: (context: AutoSettlementContext) => boolean | Promise; + selectRefundChannels?: ( + channels: Channel[], + context: AutoSettlementContext, + ) => Channel[] | Promise; + onClaim?: (result: ClaimResult) => void; + onSettle?: (result: SettleResult) => void; + onRefund?: (result: RefundResult) => void; + onError?: (error: unknown) => void; +} + +export interface AutoSettlementContext { + now: number; + lastClaimTime: number; + lastSettleTime: number; + pendingSettle: boolean; +} + +export interface ClaimResult { + vouchers: number; + transaction: string; +} + +export interface SettleResult { + transaction: string; +} + +export interface RefundResult { + channel: string; + transaction: string; +} + +type AutoJob = "claim" | "settle" | "refund"; + +const AUTO_JOB_PRIORITY: AutoJob[] = ["claim", "settle", "refund"]; + +/** + * Formats a `Facilitator.settle()` failure into a human-readable error message. + * + * @param operation - Operation label (e.g. `"Claim"`, `"Settle"`, `"Refund"`). + * @param response - The failed settle response. + * @returns Error message including reason and (when available) facilitator-provided detail. + */ +function formatFacilitatorFailure(operation: string, response: SettleResponse): string { + return `${operation} failed: ${response.errorReason ?? "unknown"} — ${response.errorMessage ?? ""}`; +} + +/** + * Checks whether a channel has a non-expired payer request reservation. + * + * @param channel - Channel state to inspect. + * @param now - Current wall-clock time in milliseconds. + * @returns Whether the channel is busy with a live pending request. + */ +function hasLivePendingRequest(channel: Channel, now = Date.now()): boolean { + return channel.pendingRequest !== undefined && channel.pendingRequest.expiresAt > now; +} + +/** + * Manages the server-side channel lifecycle for the `batch-settlement` scheme: + * batch claiming of vouchers, settlement of claimed funds, and cooperative refund. + * + * Provides one-shot operations (`claim()`, `settle()`, `claimAndSettle()`, + * `refundIdleChannels()`) and an optional interval runner. + */ +export class BatchSettlementChannelManager { + private readonly scheme: BatchSettlementEvmScheme; + private readonly facilitator: FacilitatorClient; + private readonly receiver: `0x${string}`; + private readonly token: `0x${string}`; + private readonly network: Network; + + private timers: Partial>> = {}; + private lastClaimTime = 0; + private lastSettleTime = 0; + private pendingSettle = false; + private running = false; + private pendingJobs = new Set(); + private drainingJobs = false; + private autoSettleConfig: AutoSettlementConfig = {}; + + /** + * Creates a new channel manager. + * + * @param config - Manager configuration: scheme, facilitator, receiver, token, network. + */ + constructor(config: ChannelManagerConfig) { + this.scheme = config.scheme; + this.facilitator = config.facilitator; + this.receiver = config.receiver; + this.token = config.token; + this.network = config.network; + } + + /** + * Collects claimable vouchers and submits them in batches to the facilitator via `claim()`. + * + * @param opts - Optional claim execution and target selection options. + * @param opts.maxClaimsPerBatch - Max vouchers per facilitator `claim` batch. + * @param opts.idleSecs - When set, only include channels idle for at least this many seconds. + * @param opts.selectClaimChannels - Optional selector for choosing channels before claimability checks. + * @returns Array of claim results (one per batch). + */ + async claim(opts?: ClaimOptions): Promise { + const channels = await this.selectClaimTargets(opts); + return this.claimFromChannels(channels, { + maxClaimsPerBatch: opts?.maxClaimsPerBatch ?? 100, + ...(opts?.idleSecs !== undefined ? { idleSecs: opts.idleSecs } : {}), + }); + } + + /** + * Transfers claimed (but unsettled) funds to the receiver by calling `settle(receiver, token)`. + * + * @returns Settle result with the transaction hash. + */ + async settle(): Promise { + const paymentPayload = this.buildSettlePaymentPayload(); + const requirements = this.buildPaymentRequirements(); + + const response = await this.facilitator.settle(paymentPayload, requirements); + if (!response.success) { + throw new Error(formatFacilitatorFailure("Settle", response)); + } + + this.pendingSettle = false; + return { transaction: response.transaction }; + } + + /** + * Convenience: claims all eligible vouchers then settles in one call. + * + * @param opts - Optional claim execution and target selection options. + * @param opts.maxClaimsPerBatch - Max vouchers per claim batch before settling. + * @param opts.idleSecs - When set, only include channels idle for at least this many seconds. + * @param opts.selectClaimChannels - Optional selector for choosing channels before claimability checks. + * @returns Combined claim and settle results. + */ + async claimAndSettle( + opts?: ClaimOptions, + ): Promise<{ claims: ClaimResult[]; settle?: SettleResult }> { + const claims = await this.claim(opts); + let settleResult: SettleResult | undefined; + if (claims.length > 0) { + settleResult = await this.settle(); + } + return { claims, settle: settleResult }; + } + + /** + * Initiates cooperative refunds for one or more channels. + * + * @param channelIds - Specific channels to refund; defaults to all sessions. + * @returns One result per successfully refunded channel. + */ + async refund(channelIds?: string[]): Promise { + const storage = this.scheme.getStorage(); + const channels = await storage.list(); + + const now = Date.now(); + const targets = ( + channelIds + ? channels.filter(s => + channelIds.some(id => id.toLowerCase() === s.channelId.toLowerCase()), + ) + : channels + ).filter(channel => !hasLivePendingRequest(channel, now)); + + if (targets.length === 0) { + return []; + } + + return this.refundChannels(targets); + } + + /** + * Refunds idle channels with non-zero balances. + * + * @param opts - Idle refund options. + * @param opts.idleSecs - Minimum seconds since the last request. + * @returns One result per successfully refunded channel. + */ + async refundIdleChannels(opts: { idleSecs: number }): Promise { + const channels = await this.getIdleChannelsForRefund(opts.idleSecs); + return this.refundChannels(channels); + } + + /** + * Collects vouchers that are eligible for onchain claiming. + * + * A voucher is claimable when its `chargedCumulativeAmount` exceeds what has already + * been claimed onchain. An optional idle filter skips sessions that received a + * request within the last `idleSecs` seconds. + * + * @param opts - Optional filtering: `idleSecs` to only return idle channels. + * @param opts.idleSecs - Minimum seconds since last request for a channel to be included. + * @returns Array of {@link BatchSettlementVoucherClaim} entries for batch submission. + */ + async getClaimableVouchers(opts?: { idleSecs?: number }): Promise { + const channels = await this.scheme.getStorage().list(); + return this.getClaimableVouchersFromChannels(channels, opts); + } + + /** + * Returns channels that have a pending payer-initiated withdrawal. + * + * @returns All stored channel records with `withdrawRequestedAt` set. + */ + async getWithdrawalPendingSessions(): Promise { + const channels = await this.scheme.getStorage().list(); + return channels.filter(s => s.withdrawRequestedAt > 0); + } + + /** + * Starts auto-settlement jobs for configured claim, settle, and refund intervals. + * + * @param config - Auto-settlement policy configuration. + */ + start(config: AutoSettlementConfig = {}): void { + if (this.running) { + return; + } + + const now = Date.now(); + this.lastClaimTime = now; + this.lastSettleTime = now; + this.running = true; + this.autoSettleConfig = config; + + this.startAutoTimer("claim", config.claimIntervalSecs); + this.startAutoTimer("settle", config.settleIntervalSecs); + this.startAutoTimer("refund", config.refundIntervalSecs); + } + + /** + * Stops the auto-settlement loop. + * + * @param opts - Stop options. + * @param opts.flush - When true, run `claimAndSettle` before stopping. + * @returns Resolves when the loop is stopped (and flush work completes, if requested). + */ + async stop(opts?: { flush?: boolean }): Promise { + this.running = false; + for (const timer of Object.values(this.timers)) { + clearInterval(timer); + } + this.timers = {}; + this.pendingJobs.clear(); + + if (opts?.flush) { + await this.claimAndSettle({ + maxClaimsPerBatch: this.autoSettleConfig.maxClaimsPerBatch, + selectClaimChannels: this.autoSettleConfig.selectClaimChannels, + }); + } + } + + /** + * Refunds a single channel and removes it from storage after success. + * + * @param target - Channel to refund. + * @returns Successful refund transaction. + */ + private async refundChannel(target: Channel): Promise { + const authorizerSigner = this.scheme.getReceiverAuthorizerSigner(); + const claims = this.buildRefundClaims(target); + + const refundAmount = ( + BigInt(target.balance) - BigInt(target.chargedCumulativeAmount) + ).toString(); + + const nonce = String(target.refundNonce ?? 0); + + const refundAuthorizerSignature = authorizerSigner + ? await signRefund( + authorizerSigner, + target.channelId as `0x${string}`, + refundAmount, + nonce, + this.network, + ) + : undefined; + + const claimAuthorizerSignature = + authorizerSigner && claims.length > 0 + ? await signClaimBatch(authorizerSigner, claims, this.network) + : undefined; + + const paymentPayload: PaymentPayload = { + x402Version: 2, + accepted: this.buildPaymentRequirements(), + payload: { + type: "refund", + channelConfig: target.channelConfig, + voucher: { + channelId: target.channelId as `0x${string}`, + maxClaimableAmount: target.signedMaxClaimable, + signature: target.signature as `0x${string}`, + }, + amount: refundAmount, + refundNonce: nonce, + claims, + ...(refundAuthorizerSignature ? { refundAuthorizerSignature } : {}), + ...(claimAuthorizerSignature ? { claimAuthorizerSignature } : {}), + }, + }; + + const response = await this.facilitator.settle(paymentPayload, this.buildPaymentRequirements()); + if (!response.success) { + throw new Error(formatFacilitatorFailure("Refund", response)); + } + + await this.scheme + .getStorage() + .updateChannel(target.channelId, current => + current && !hasLivePendingRequest(current) ? undefined : current, + ); + + return { + channel: target.channelId, + transaction: response.transaction, + }; + } + + /** + * Starts a recurring timer for one auto job. + * + * @param job - Job to enqueue when the interval fires. + * @param intervalSecs - Timer interval in seconds. + */ + private startAutoTimer(job: AutoJob, intervalSecs?: number): void { + if (intervalSecs === undefined) { + return; + } + + this.timers[job] = setInterval(() => { + this.enqueueJob(job); + }, intervalSecs * 1000); + } + + /** + * Adds an auto job to the coalescing queue. + * + * @param job - Job to run. + */ + private enqueueJob(job: AutoJob): void { + if (!this.running) { + return; + } + + this.pendingJobs.add(job); + if (!this.drainingJobs) { + void this.drainJobs(); + } + } + + /** + * Drains queued auto jobs in priority order. + */ + private async drainJobs(): Promise { + if (this.drainingJobs) { + return; + } + + this.drainingJobs = true; + try { + while (this.running && this.pendingJobs.size > 0) { + const job = this.nextPendingJob(); + if (!job) { + return; + } + this.pendingJobs.delete(job); + await this.runAutoJob(job); + } + } finally { + this.drainingJobs = false; + } + } + + /** + * Returns the highest-priority queued auto job. + * + * @returns Next job to run. + */ + private nextPendingJob(): AutoJob | undefined { + return AUTO_JOB_PRIORITY.find(job => this.pendingJobs.has(job)); + } + + /** + * Runs one auto job. + * + * @param job - Job to run. + */ + private async runAutoJob(job: AutoJob): Promise { + switch (job) { + case "claim": + await this.runClaimJob(); + return; + case "settle": + await this.runSettleJob(); + return; + case "refund": + await this.runRefundJob(); + return; + } + } + + /** + * Runs the claim auto job. + */ + private async runClaimJob(): Promise { + const cfg = this.autoSettleConfig; + try { + const targets = await this.selectClaimTargets({ + selectClaimChannels: cfg.selectClaimChannels, + }); + const results = await this.claimFromChannels(targets, { + maxClaimsPerBatch: cfg.maxClaimsPerBatch ?? 100, + }); + + this.lastClaimTime = Date.now(); + for (const result of results) { + cfg.onClaim?.(result); + } + } catch (err) { + cfg.onError?.(err); + } + } + + /** + * Runs the settlement auto job. + */ + private async runSettleJob(): Promise { + const cfg = this.autoSettleConfig; + const context = this.buildAutoSettlementContext(Date.now()); + if (!context.pendingSettle) { + return; + } + + try { + if (cfg.shouldSettle && !(await cfg.shouldSettle(context))) { + return; + } + + const result = await this.settle(); + this.lastSettleTime = Date.now(); + cfg.onSettle?.(result); + } catch (err) { + cfg.onError?.(err); + } + } + + /** + * Runs the refund auto job. + */ + private async runRefundJob(): Promise { + const cfg = this.autoSettleConfig; + if (!cfg.selectRefundChannels) { + return; + } + + try { + const context = this.buildAutoSettlementContext(Date.now()); + const channels = await this.scheme.getStorage().list(); + const targets = await cfg.selectRefundChannels(channels, context); + for (const result of await this.refundChannels(targets)) { + cfg.onRefund?.(result); + } + } catch (err) { + cfg.onError?.(err); + } + } + + /** + * Claims vouchers from a provided channel snapshot. + * + * @param channels - Channels to inspect for claimable vouchers. + * @param opts - Claim batching and filtering options. + * @param opts.maxClaimsPerBatch - Max vouchers per facilitator claim transaction. + * @param opts.idleSecs - Optional idle filter. + * @returns Claim results, one per submitted batch. + */ + private async claimFromChannels( + channels: Channel[], + opts: { + maxClaimsPerBatch: number; + idleSecs?: number; + }, + ): Promise { + const allClaims = this.getClaimableVouchersFromChannels( + channels, + opts.idleSecs !== undefined ? { idleSecs: opts.idleSecs } : undefined, + ); + + if (allClaims.length === 0) { + return []; + } + + const results: ClaimResult[] = []; + for (let i = 0; i < allClaims.length; i += opts.maxClaimsPerBatch) { + const batch = allClaims.slice(i, i + opts.maxClaimsPerBatch); + const result = await this.submitClaim(batch); + results.push(result); + await this.updateClaimedSessions(batch); + } + + if (results.length > 0) { + this.pendingSettle = true; + } + + return results; + } + + /** + * Loads stored channels and applies the configured claim selector, if any. + * + * @param opts - Claim options containing an optional target selector. + * @returns The channel snapshot that should be inspected for claimable vouchers. + */ + private async selectClaimTargets( + opts?: Pick, + ): Promise { + const channels = await this.scheme.getStorage().list(); + if (!opts?.selectClaimChannels) { + return channels; + } + + const context = this.buildAutoSettlementContext(Date.now()); + return opts.selectClaimChannels(channels, context); + } + + /** + * Refunds each eligible channel independently. + * + * @param channels - Channels to refund. + * @returns Successful refund results. + */ + private async refundChannels(channels: Channel[]): Promise { + const results: RefundResult[] = []; + for (const channel of channels) { + if (hasLivePendingRequest(channel)) { + continue; + } + results.push(await this.refundChannel(channel)); + } + return results; + } + + /** + * Builds an outstanding voucher claim for a refund payload. + * + * @param channel - Channel being refunded. + * @returns Claim payloads needed before refunding unclaimed balance. + */ + private buildRefundClaims(channel: Channel): BatchSettlementVoucherClaim[] { + if (BigInt(channel.chargedCumulativeAmount) <= BigInt(channel.totalClaimed)) { + return []; + } + + return [ + { + voucher: { + channel: channel.channelConfig, + maxClaimableAmount: channel.signedMaxClaimable, + }, + signature: channel.signature as `0x${string}`, + totalClaimed: channel.chargedCumulativeAmount, + }, + ]; + } + + /** + * Builds the policy context passed to interval hooks. + * + * @param now - Current wall-clock time in milliseconds. + * @returns Auto-settlement policy context. + */ + private buildAutoSettlementContext(now: number): AutoSettlementContext { + return { + now, + lastClaimTime: this.lastClaimTime, + lastSettleTime: this.lastSettleTime, + pendingSettle: this.pendingSettle, + }; + } + + /** + * Collects claimable vouchers from a provided channel snapshot. + * + * @param channels - Channels to inspect. + * @param opts - Optional idle filter. + * @param opts.idleSecs - Minimum seconds since last request. + * @returns Claimable voucher payloads. + */ + private getClaimableVouchersFromChannels( + channels: Channel[], + opts?: { idleSecs?: number }, + ): BatchSettlementVoucherClaim[] { + const now = Date.now(); + const claims: BatchSettlementVoucherClaim[] = []; + + for (const c of channels) { + if (BigInt(c.chargedCumulativeAmount) <= BigInt(c.totalClaimed)) { + continue; + } + if (opts?.idleSecs !== undefined) { + const idleMs = now - c.lastRequestTimestamp; + if (idleMs < opts.idleSecs * 1000) { + continue; + } + } + claims.push({ + voucher: { + channel: c.channelConfig, + maxClaimableAmount: c.signedMaxClaimable, + }, + signature: c.signature as `0x${string}`, + totalClaimed: c.chargedCumulativeAmount, + }); + } + + return claims; + } + + /** + * Filters idle channels that can be cooperatively refunded. + * + * @param channels - Channels to inspect. + * @param idleSecs - Minimum seconds since the last request. + * @returns Idle refundable channels. + */ + private getIdleChannelsForRefundFromChannels(channels: Channel[], idleSecs: number): Channel[] { + const now = Date.now(); + const idleMs = idleSecs * 1000; + return channels.filter(c => { + if (BigInt(c.balance) === 0n) return false; + if (hasLivePendingRequest(c, now)) return false; + return now - c.lastRequestTimestamp >= idleMs; + }); + } + + /** + * Returns channels that have been idle longer than `idleSecs` and still have + * a non-zero balance (candidates for cooperative refund). + * + * @param idleSecs - Minimum seconds since last request for a session to count as idle. + * @returns Channels meeting the idle and balance criteria. + */ + private async getIdleChannelsForRefund(idleSecs: number): Promise { + const channels = await this.scheme.getStorage().list(); + return this.getIdleChannelsForRefundFromChannels(channels, idleSecs); + } + + /** + * Submits a batch of voucher claims to the facilitator. + * + * @param claims - Voucher claims to send in one `type: "claim"` payload. + * @returns Per-batch claim summary (count and transaction hash). + */ + private async submitClaim(claims: BatchSettlementVoucherClaim[]): Promise { + const authorizerSigner = this.scheme.getReceiverAuthorizerSigner(); + + const claimAuthorizerSignature = authorizerSigner + ? await signClaimBatch(authorizerSigner, claims, this.network) + : undefined; + + const paymentPayload: PaymentPayload = { + x402Version: 2, + accepted: this.buildPaymentRequirements(), + payload: { + type: "claim", + claims, + ...(claimAuthorizerSignature ? { claimAuthorizerSignature } : {}), + }, + }; + + const response: SettleResponse = await this.facilitator.settle( + paymentPayload, + this.buildPaymentRequirements(), + ); + + if (!response.success) { + throw new Error(formatFacilitatorFailure("Claim", response)); + } + + return { vouchers: claims.length, transaction: response.transaction }; + } + + /** + * Builds a settlement payment payload for `settle(receiver, token)`. + * + * @returns Payload with `type: "settle"` and receiver/token fields. + */ + private buildSettlePaymentPayload(): PaymentPayload { + return { + x402Version: 2, + accepted: this.buildPaymentRequirements(), + payload: { + type: "settle", + receiver: this.receiver, + token: this.token, + }, + }; + } + + /** + * Builds a minimal {@link PaymentRequirements} for channel manager operations. + * + * @returns Requirements describing batched operations for this manager. + */ + private buildPaymentRequirements(): PaymentRequirements { + return { + scheme: BATCH_SETTLEMENT_SCHEME, + network: this.network, + asset: this.token, + amount: "0", + payTo: this.receiver, + maxTimeoutSeconds: 0, + extra: {}, + }; + } + + /** + * Updates session records after a successful claim submission so that + * `getClaimableVouchers` no longer returns already-claimed vouchers. + * + * @param claims - Voucher claims that were included in the submitted settlement transaction. + */ + private async updateClaimedSessions(claims: BatchSettlementVoucherClaim[]): Promise { + const storage = this.scheme.getStorage(); + for (const claim of claims) { + const channelId = computeChannelId(claim.voucher.channel, this.network); + const channel = await storage.get(channelId); + if (!channel) { + continue; + } + const claimedAmount = BigInt(claim.totalClaimed); + if (claimedAmount <= BigInt(channel.totalClaimed)) { + continue; + } + await storage.updateChannel(channelId, current => { + if (!current || claimedAmount <= BigInt(current.totalClaimed)) { + return current; + } + return { + ...current, + totalClaimed: claimedAmount.toString(), + }; + }); + } + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/server/fileStorage.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/server/fileStorage.ts new file mode 100644 index 0000000000..d3038b62ab --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/server/fileStorage.ts @@ -0,0 +1,143 @@ +import { mkdir, open, readdir, readFile, unlink } from "node:fs/promises"; +import { constants } from "node:fs"; +import { dirname, join } from "node:path"; + +import { isNodeEnoent, readJsonFile, writeJsonAtomic } from "../storage-utils"; +import type { FileChannelStorageOptions } from "../types"; +import type { ChannelStorage, Channel, ChannelUpdateResult } from "./storage"; + +export type { FileChannelStorageOptions }; + +/** + * Node.js file-backed {@link ChannelStorage} for the batched server scheme. + */ +export class FileChannelStorage implements ChannelStorage { + private readonly root: string; + + /** + * Creates file-backed server channel storage under the given root directory. + * + * @param options - Configuration including the storage root directory. + */ + constructor(options: FileChannelStorageOptions) { + this.root = options.directory; + } + + /** + * Loads a persisted channel record, if present. + * + * @param channelId - The channel identifier (path segment is lowercased). + * @returns Parsed channel record or `undefined` when the file is missing. + */ + async get(channelId: string): Promise { + return readJsonFile(this.filePath(channelId)); + } + + /** + * Lists all stored channel records by reading the server directory. + * + * @returns Channel records sorted by channelId; empty array if the directory is missing. + */ + async list(): Promise { + const dir = join(this.root, "server"); + let names: string[]; + try { + names = await readdir(dir); + } catch (err: unknown) { + if (isNodeEnoent(err)) return []; + throw err; + } + + const channels: Channel[] = []; + for (const name of names) { + if (!name.endsWith(".json")) continue; + const path = join(dir, name); + try { + const raw = await readFile(path, "utf8"); + channels.push(JSON.parse(raw) as Channel); + } catch (err: unknown) { + // Skip files that disappeared between readdir and readFile (e.g. concurrent delete). + // Rethrow other failures (corrupt JSON, permission denied) so callers see them. + if (isNodeEnoent(err)) continue; + throw err; + } + } + return channels.sort((a, b) => a.channelId.localeCompare(b.channelId)); + } + + /** + * Atomically inspects and mutates a channel record under a cross-process file lock. + * + * @param channelId - The channel identifier. + * @param update - Mutation callback. Return `undefined` to delete, or `current` to leave unchanged. + * @returns The final stored channel and whether storage updated, stayed unchanged, or deleted. + */ + async updateChannel( + channelId: string, + update: (current: Channel | undefined) => Channel | undefined, + ): Promise { + const lockPath = this.filePath(channelId) + ".lock"; + await mkdir(dirname(lockPath), { recursive: true }); + const lockHandle = await this.acquireLock(lockPath); + + try { + const path = this.filePath(channelId); + let current: Channel | undefined; + try { + const raw = await readFile(path, "utf8"); + current = JSON.parse(raw) as Channel; + } catch (err: unknown) { + if (!isNodeEnoent(err)) throw err; + } + + const next = update(current); + if (next === current) { + return { channel: current, status: "unchanged" }; + } + + if (!next) { + try { + await unlink(path); + } catch (err: unknown) { + if (!isNodeEnoent(err)) throw err; + } + return { channel: undefined, status: current ? "deleted" : "unchanged" }; + } + + await writeJsonAtomic(path, next); + return { channel: next, status: "updated" }; + } finally { + await lockHandle.close(); + await unlink(lockPath).catch(() => {}); + } + } + + /** + * Absolute path to the JSON file for a channel. + * + * @param channelId - The channel identifier. + * @returns Filesystem path under `{root}/server/...`. + */ + private filePath(channelId: string): string { + return join(this.root, "server", `${channelId.toLowerCase()}.json`); + } + + /** + * Creates an exclusive lock file, polling until no other process holds it. + * + * @param lockPath - Absolute path for the lock file (created with `O_EXCL`). + * @returns Writable file handle for the lock file; caller must close it to release. + */ + private async acquireLock(lockPath: string) { + while (true) { + try { + return await open(lockPath, constants.O_CREAT | constants.O_EXCL | constants.O_WRONLY); + } catch (err: unknown) { + if ((err as NodeJS.ErrnoException).code !== "EEXIST") { + throw err; + } + await new Promise(resolve => setTimeout(resolve, 10)); + } + } + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/server/index.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/server/index.ts new file mode 100644 index 0000000000..eb4f408fbe --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/server/index.ts @@ -0,0 +1,26 @@ +export { BatchSettlementEvmScheme } from "./scheme"; +export type { BatchSettlementEvmSchemeServerConfig, BatchSettlementRequestContext } from "./scheme"; +export type { AuthorizerSigner } from "../types"; +export { InMemoryChannelStorage } from "./storage"; +export type { Channel, ChannelStorage, ChannelUpdateResult, PendingRequest } from "./storage"; +export type { FileChannelStorageOptions } from "./fileStorage"; +export { FileChannelStorage } from "./fileStorage"; +export { RedisChannelStorage } from "./redisStorage"; +export type { + RedisChannelStorageClient, + RedisChannelStorageOptions, + RedisEvalOptions, + RedisScanOptions, + RedisSetOptions, +} from "./redisStorage"; +export { BatchSettlementChannelManager } from "./channelManager"; +export type { + ChannelManagerConfig, + AutoSettlementConfig, + AutoSettlementContext, + ClaimChannelSelector, + ClaimOptions, + ClaimResult, + SettleResult, + RefundResult, +} from "./channelManager"; diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/server/redisStorage.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/server/redisStorage.ts new file mode 100644 index 0000000000..c07b39288b --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/server/redisStorage.ts @@ -0,0 +1,235 @@ +import type { Channel, ChannelStorage, ChannelUpdateResult } from "./storage"; + +const DEFAULT_KEY_PREFIX = "x402:batch-settlement"; +const DEFAULT_LOCK_RETRY_INTERVAL_MS = 10; +const DEFAULT_SCAN_COUNT = 100; + +const UPDATE_CHANNEL_SCRIPT = ` +local current = redis.call("GET", KEYS[1]) +local expectedExists = ARGV[1] +local expected = ARGV[2] +local operation = ARGV[3] +local nextValue = ARGV[4] + +if expectedExists == "0" then + if current ~= false then + return {0, current} + end +elseif current ~= expected then + return {0, current or false} +end + +if operation == "delete" then + redis.call("DEL", KEYS[1]) + return {1, false} +end + +if operation == "set" then + redis.call("SET", KEYS[1], nextValue) + return {1, nextValue} +end + +return {1, current or false} +`; + +export type RedisEvalOptions = { + keys: string[]; + arguments: string[]; +}; + +export type RedisSetOptions = { + NX?: true; + PX?: number; +}; + +export type RedisScanOptions = { + MATCH?: string; + COUNT?: number; +}; + +export type RedisChannelStorageClient = { + get(key: string): Promise; + set(key: string, value: string, options?: RedisSetOptions): Promise; + del(key: string): Promise; + eval(script: string, options: RedisEvalOptions): Promise; + scanIterator(options: RedisScanOptions): AsyncIterable; +}; + +export type RedisChannelStorageOptions = { + client: RedisChannelStorageClient; + keyPrefix?: string; + lockTtlMs?: number; + lockRetryIntervalMs?: number; + lockRenewalIntervalMs?: number; + scanCount?: number; +}; + +type RedisUpdateOperation = "delete" | "keep" | "set"; + +type ParsedRedisUpdateResult = { + applied: boolean; +}; + +/** + * Redis-backed {@link ChannelStorage} with optimistic atomic updates. + */ +export class RedisChannelStorage implements ChannelStorage { + private readonly client: RedisChannelStorageClient; + private readonly keyPrefix: string; + private readonly channelKeyPrefix: string; + private readonly lockRetryIntervalMs: number; + private readonly scanCount: number; + + /** + * Creates Redis-backed server channel storage. + * + * @param options - Redis client and optional key/retry configuration. + */ + constructor(options: RedisChannelStorageOptions) { + this.client = options.client; + this.keyPrefix = options.keyPrefix ?? DEFAULT_KEY_PREFIX; + this.channelKeyPrefix = `${this.keyPrefix}:server:channel`; + this.lockRetryIntervalMs = options.lockRetryIntervalMs ?? DEFAULT_LOCK_RETRY_INTERVAL_MS; + this.scanCount = options.scanCount ?? DEFAULT_SCAN_COUNT; + } + + /** + * Loads a persisted channel record, if present. + * + * @param channelId - The channel identifier. + * @returns Parsed channel record or `undefined` when the key is missing. + */ + async get(channelId: string): Promise { + const raw = await this.client.get(this.channelKey(channelId)); + if (!raw) return undefined; + return JSON.parse(raw) as Channel; + } + + /** + * Lists all stored channel records by scanning Redis keys. + * + * @returns Channel records sorted by channelId. + */ + async list(): Promise { + const channels: Channel[] = []; + for await (const keyOrKeys of this.client.scanIterator({ + MATCH: `${this.channelKeyPrefix}:*`, + COUNT: this.scanCount, + })) { + const keys = Array.isArray(keyOrKeys) ? keyOrKeys : [keyOrKeys]; + for (const key of keys) { + if (key.endsWith(":lock")) continue; + const raw = await this.client.get(key); + if (!raw) continue; + channels.push(JSON.parse(raw) as Channel); + } + } + return channels.sort((a, b) => a.channelId.localeCompare(b.channelId)); + } + + /** + * Atomically inspects and mutates a channel record with Redis compare-and-write retries. + * + * @param channelId - The channel identifier. + * @param update - Mutation callback. Return `undefined` to delete, or `current` to leave unchanged. + * @returns The final stored channel and whether storage updated, stayed unchanged, or deleted. + */ + async updateChannel( + channelId: string, + update: (current: Channel | undefined) => Channel | undefined, + ): Promise { + const key = this.channelKey(channelId); + while (true) { + const currentRaw = await this.client.get(key); + const current = currentRaw ? (JSON.parse(currentRaw) as Channel) : undefined; + const next = update(current); + + if (next === current) { + const result = await this.commitUpdate(key, currentRaw, "keep"); + if (result.applied) return { channel: current, status: "unchanged" }; + await sleep(this.lockRetryIntervalMs); + continue; + } + + if (!next) { + const result = await this.commitUpdate(key, currentRaw, "delete"); + if (result.applied) { + return { channel: undefined, status: current ? "deleted" : "unchanged" }; + } + await sleep(this.lockRetryIntervalMs); + continue; + } + + const nextRaw = JSON.stringify(next); + const result = await this.commitUpdate(key, currentRaw, "set", nextRaw); + if (result.applied) return { channel: next, status: "updated" }; + await sleep(this.lockRetryIntervalMs); + } + } + + /** + * Applies a channel mutation only if the key still contains the value that was inspected. + * + * @param key - Redis channel key to mutate. + * @param expectedRaw - Raw JSON value observed before running the update callback. + * @param operation - Mutation to apply when the observed value is still current. + * @param nextRaw - Raw JSON value to write for set operations. + * @returns Whether the mutation was applied. + */ + private async commitUpdate( + key: string, + expectedRaw: string | null, + operation: RedisUpdateOperation, + nextRaw = "", + ): Promise { + return parseRedisUpdateResult( + await this.client.eval(UPDATE_CHANNEL_SCRIPT, { + keys: [key], + arguments: [expectedRaw === null ? "0" : "1", expectedRaw ?? "", operation, nextRaw], + }), + ); + } + + /** + * Builds the Redis key for a stored channel record. + * + * @param channelId - The channel identifier. + * @returns Redis key for the channel JSON. + */ + private channelKey(channelId: string) { + return `${this.channelKeyPrefix}:${channelId.toLowerCase()}`; + } +} + +/** + * Parses the Redis script response. + * + * @param value - Raw response from the Redis client. + * @returns Whether the compare-and-write applied. + */ +function parseRedisUpdateResult(value: unknown): ParsedRedisUpdateResult { + if (!Array.isArray(value) || value.length < 1) { + throw new Error("Unexpected Redis update response"); + } + + const [applied, raw] = value; + if (applied !== 0 && applied !== 1) { + throw new Error("Unexpected Redis update status"); + } + + if (raw !== false && raw !== null && raw !== undefined && typeof raw !== "string") { + throw new Error("Unexpected Redis update value"); + } + + return { applied: applied === 1 }; +} + +/** + * Resolves after the requested delay. + * + * @param ms - Delay in milliseconds. + * @returns Promise resolved after the delay. + */ +function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/server/scheme.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/server/scheme.ts new file mode 100644 index 0000000000..1a261c31e4 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/server/scheme.ts @@ -0,0 +1,427 @@ +import { + AssetAmount, + Network, + PaymentPayload, + PaymentRequirements, + Price, + SchemeNetworkServer, + SchemeServerHooks, + MoneyParser, +} from "@x402/core/types"; +import type { DeepReadonly } from "@x402/core/types"; +import type { SettleContext, SettleResultContext } from "@x402/core/server"; +import { convertToTokenAmount, numberToDecimalString } from "@x402/core/utils"; +import type { FacilitatorClient } from "@x402/core/server"; +import { getAddress } from "viem"; +import { BatchSettlementChannelManager } from "./channelManager"; +import { getDefaultAsset } from "../../shared/defaultAssets"; +import type { AuthorizerSigner } from "../types"; +import { BATCH_SETTLEMENT_SCHEME, MIN_WITHDRAW_DELAY } from "../constants"; +import { InMemoryChannelStorage, ChannelStorage, type Channel } from "./storage"; +import { + handleAfterVerify, + handleBeforeVerify, + handleEnrichPaymentRequiredResponse, + handleVerifyFailure, + handleVerifiedPaymentCanceled, +} from "./verify"; +import { + handleAfterSettle, + handleBeforeSettle, + handleEnrichSettlementPayload, + handleEnrichSettlementResponse, + handleSettleFailure, +} from "./settle"; + +export interface BatchSettlementEvmSchemeServerConfig { + storage?: ChannelStorage; + receiverAuthorizerSigner?: AuthorizerSigner; + withdrawDelay?: number; + onchainStateTtlMs?: number; +} + +export interface BatchSettlementRequestContext { + channelId?: string; + pendingId?: string; + channelSnapshot?: Channel; + localVerify?: boolean; +} + +/** + * Server-side implementation of the `batch-settlement` scheme for EVM networks. + */ +export class BatchSettlementEvmScheme implements SchemeNetworkServer { + readonly scheme = BATCH_SETTLEMENT_SCHEME; + readonly schemeHooks: SchemeServerHooks; + + private readonly requestContexts = new WeakMap< + DeepReadonly, + BatchSettlementRequestContext + >(); + private moneyParsers: MoneyParser[] = []; + private readonly storage: ChannelStorage; + private readonly receiverAuthorizerSigner: AuthorizerSigner | undefined; + private readonly receiverAddress: `0x${string}`; + private readonly withdrawDelay: number; + private readonly onchainStateTtlMs: number; + + /** + * Constructs a batched server scheme. + * + * @param receiverAddress - The server's receiver address (payTo). + * @param config - Optional configuration for storage, receiver-authorizer signer, and withdraw delay. + */ + constructor(receiverAddress: `0x${string}`, config?: BatchSettlementEvmSchemeServerConfig) { + this.receiverAddress = receiverAddress; + this.storage = config?.storage ?? new InMemoryChannelStorage(); + this.receiverAuthorizerSigner = config?.receiverAuthorizerSigner; + this.withdrawDelay = config?.withdrawDelay ?? MIN_WITHDRAW_DELAY; + this.onchainStateTtlMs = + config?.onchainStateTtlMs ?? defaultOnchainStateTtlMs(this.withdrawDelay); + this.schemeHooks = { + onBeforeVerify: ctx => handleBeforeVerify(this, ctx), + onAfterVerify: ctx => handleAfterVerify(this, ctx), + onBeforeSettle: ctx => handleBeforeSettle(this, ctx), + onAfterSettle: ctx => handleAfterSettle(this, ctx), + onVerifyFailure: ctx => handleVerifyFailure(this, ctx), + onSettleFailure: ctx => handleSettleFailure(this, ctx), + onVerifiedPaymentCanceled: ctx => handleVerifiedPaymentCanceled(this, ctx), + }; + } + + /** + * Adds server-owned settlement fields before facilitator settlement. + * + * @param ctx - Settlement context for the current payment. + * @returns Additive payload fields, or nothing when no enrichment is needed. + */ + enrichSettlementPayload = (ctx: SettleContext): Promise | void> => + handleEnrichSettlementPayload(this, ctx); + + /** + * Adds corrective channel state to payment-required responses when available. + * + * @param ctx - Payment-required response context for the current request. + * @returns Updated payment requirements, or nothing when no enrichment is needed. + */ + enrichPaymentRequiredResponse = ( + ctx: Parameters[1], + ): Promise => handleEnrichPaymentRequiredResponse(this, ctx); + + /** + * Adds server-owned extra fields after facilitator settlement. + * + * @param ctx - Settlement result context for the current payment. + * @returns Additive response extra fields, or nothing when no enrichment is needed. + */ + enrichSettlementResponse = (ctx: SettleResultContext): Promise | void> => + handleEnrichSettlementResponse(this, ctx); + + /** + * Merges batch-settlement state into the current request context. + * + * @param payload - Request-scoped payment payload object. + * @param context - Partial context fields to merge. + */ + mergeRequestContext( + payload: DeepReadonly, + context: BatchSettlementRequestContext, + ): void { + this.requestContexts.set(payload, { + ...this.requestContexts.get(payload), + ...context, + }); + } + + /** + * Reads batch-settlement state for the current request without clearing it. + * + * @param payload - Request-scoped payment payload object. + * @returns Request context, if one was recorded. + */ + readRequestContext( + payload: DeepReadonly, + ): BatchSettlementRequestContext | undefined { + return this.requestContexts.get(payload); + } + + /** + * Reads and clears batch-settlement state for the current request. + * + * @param payload - Request-scoped payment payload object. + * @returns Request context, if one was recorded. + */ + takeRequestContext( + payload: DeepReadonly, + ): BatchSettlementRequestContext | undefined { + const context = this.requestContexts.get(payload); + this.requestContexts.delete(payload); + return context; + } + + /** + * Stores a channel snapshot for the current settlement request. + * + * @param payload - Request-scoped payment payload object. + * @param channel - Channel state to use during response enrichment. + */ + rememberChannelSnapshot(payload: DeepReadonly, channel: Channel): void { + this.mergeRequestContext(payload, { + channelId: channel.channelId, + channelSnapshot: channel, + }); + } + + /** + * Reads and clears a channel snapshot for the current settlement request. + * + * @param payload - Request-scoped payment payload object. + * @returns Stored channel state, if one was recorded. + */ + takeChannelSnapshot(payload: DeepReadonly): Channel | undefined { + return this.takeRequestContext(payload)?.channelSnapshot; + } + + /** + * Clears this request's pending reservation without touching newer reservations. + * + * @param payload - Request-scoped payment payload object. + */ + async clearPendingRequest(payload: DeepReadonly): Promise { + const context = this.takeRequestContext(payload); + if (!context?.channelId || !context.pendingId) { + return; + } + + await this.storage.updateChannel(context.channelId, current => { + if (!current || current.pendingRequest?.pendingId !== context.pendingId) { + return current; + } + + if (!context.channelSnapshot) { + return undefined; + } + + return { + ...current, + pendingRequest: undefined, + }; + }); + } + + /** + * Registers a custom money parser for converting price strings to token amounts. + * + * @param parser - A parser function to try before the default USD→token conversion. + * @returns `this` for chaining. + */ + registerMoneyParser(parser: MoneyParser): BatchSettlementEvmScheme { + this.moneyParsers.push(parser); + return this; + } + + /** + * Resolves a human-readable price (e.g. `"$0.01"`) into an onchain token amount. + * + * @param price - A price string, number, or explicit {@link AssetAmount}. + * @param network - CAIP-2 network identifier for looking up the default asset. + * @returns Token amount with asset address and metadata. + */ + async parsePrice(price: Price, network: Network): Promise { + if (typeof price === "object" && price !== null && "amount" in price) { + if (!price.asset) { + throw new Error(`Asset address must be specified for AssetAmount on network ${network}`); + } + return { + amount: price.amount, + asset: price.asset, + extra: price.extra || {}, + }; + } + + const amount = this.parseMoneyToDecimal(price); + + for (const parser of this.moneyParsers) { + const result = await parser(amount, network); + if (result !== null) { + return result; + } + } + + return this.defaultMoneyConversion(amount, network); + } + + /** + * Injects batched-specific fields into the payment requirements returned to + * the client (receiverAuthorizer, withdrawDelay, EIP-712 domain info). + * + * @param paymentRequirements - Base payment requirements from the middleware. + * @param supportedKind - Matched scheme/network kind (extra may contain overrides). + * @param supportedKind.x402Version - Protocol version from the matched kind. + * @param supportedKind.scheme - Scheme name from the matched kind. + * @param supportedKind.network - Network identifier from the matched kind. + * @param supportedKind.extra - Optional extra fields on the matched kind. + * @param _extensionKeys - Extension keys (unused). + * @returns Enhanced payment requirements with batched fields in `extra`. + */ + async enhancePaymentRequirements( + paymentRequirements: PaymentRequirements, + supportedKind: { + x402Version: number; + scheme: string; + network: Network; + extra?: Record; + }, + _extensionKeys: string[], + ): Promise { + void _extensionKeys; + + const assetInfo = getDefaultAsset(paymentRequirements.network as Network); + + const receiverAuthorizer = + this.receiverAuthorizerSigner?.address ?? + (typeof supportedKind.extra?.receiverAuthorizer === "string" + ? supportedKind.extra.receiverAuthorizer + : undefined); + + if ( + !receiverAuthorizer || + getAddress(receiverAuthorizer) === "0x0000000000000000000000000000000000000000" + ) { + throw new Error("Payment requirements must include a non-zero extra.receiverAuthorizer"); + } + + return { + ...paymentRequirements, + extra: { + ...paymentRequirements.extra, + receiverAuthorizer: getAddress(receiverAuthorizer), + withdrawDelay: this.withdrawDelay, + name: assetInfo.name, + version: assetInfo.version, + assetTransferMethod: + paymentRequirements.extra?.assetTransferMethod ?? assetInfo.assetTransferMethod, + }, + }; + } + + /** + * Returns the underlying channel storage instance. + * + * @returns The configured {@link ChannelStorage} backend. + */ + getStorage(): ChannelStorage { + return this.storage; + } + + /** + * Returns the server's receiver address. + * + * @returns Receiver wallet address for the payment channel. + */ + getReceiverAddress(): `0x${string}` { + return this.receiverAddress; + } + + /** + * Returns the configured withdraw delay (seconds). + * + * @returns Withdraw delay in seconds before uncooperative withdrawal is allowed. + */ + getWithdrawDelay(): number { + return this.withdrawDelay; + } + + /** + * Returns how long mirrored onchain channel state is trusted for local voucher verification. + * + * @returns Freshness window in milliseconds. + */ + getOnchainStateTtlMs(): number { + return this.onchainStateTtlMs; + } + + /** + * Returns the receiver-authorizer signer, if configured. + * + * @returns Receiver-authorizer signer, or `undefined` when not set. + */ + getReceiverAuthorizerSigner(): AuthorizerSigner | undefined { + return this.receiverAuthorizerSigner; + } + + /** + * Creates a {@link BatchSettlementChannelManager} pre-configured with this scheme's + * receiver, default token for the given network, and the provided facilitator. + * + * @param facilitator - Facilitator client for submitting onchain claims/settlements. + * @param network - CAIP-2 network identifier (e.g. `"eip155:84532"`). + * @returns A ready-to-use channel manager. + */ + createChannelManager( + facilitator: FacilitatorClient, + network: Network, + ): BatchSettlementChannelManager { + const token = getDefaultAsset(network).address as `0x${string}`; + return new BatchSettlementChannelManager({ + scheme: this, + facilitator, + receiver: this.receiverAddress, + token, + network, + }); + } + + /** + * Parses a human-readable money string (e.g. `"$1.50"`) into a decimal number. + * + * @param money - Money string (may include `$`) or numeric amount. + * @returns Parsed finite number. + */ + private parseMoneyToDecimal(money: string | number): number { + if (typeof money === "number") { + return money; + } + + const cleanMoney = money.replace(/^\$/, "").trim(); + const amount = parseFloat(cleanMoney); + + if (isNaN(amount)) { + throw new Error(`Invalid money format: ${money}`); + } + + return amount; + } + + /** + * Converts a decimal dollar amount to the network's default token amount. + * + * @param amount - Decimal amount in display units. + * @param network - Target chain/network for default asset resolution. + * @returns {@link AssetAmount} with integer token amount, contract address, and metadata. + */ + private defaultMoneyConversion(amount: number, network: Network): AssetAmount { + const assetInfo = getDefaultAsset(network); + const tokenAmount = convertToTokenAmount(numberToDecimalString(amount), assetInfo.decimals); + + return { + amount: tokenAmount, + asset: assetInfo.address, + extra: { + name: assetInfo.name, + version: assetInfo.version, + }, + }; + } +} + +/** + * Derives a reasonable onchain state freshness window from the channel withdraw delay. + * + * @param withdrawDelaySeconds - Onchain withdraw delay for the channel, in seconds. + * @returns TTL in milliseconds, clamped between 30 seconds and 5 minutes. + */ +function defaultOnchainStateTtlMs(withdrawDelaySeconds: number): number { + const withdrawDelayMs = Math.max(0, withdrawDelaySeconds) * 1000; + return Math.min(5 * 60 * 1000, Math.max(30 * 1000, Math.floor(withdrawDelayMs / 3))); +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/server/settle.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/server/settle.ts new file mode 100644 index 0000000000..902bf1fdd8 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/server/settle.ts @@ -0,0 +1,421 @@ +import type { SettleResponse } from "@x402/core/types"; +import type { SettleContext, SettleFailureContext, SettleResultContext } from "@x402/core/server"; +import { signClaimBatch, signRefund } from "../authorizerSigner"; +import { + isBatchSettlementDepositPayload, + isBatchSettlementRefundPayload, + isBatchSettlementVoucherPayload, +} from "../types"; +import type { BatchSettlementPaymentResponseExtra, BatchSettlementVoucherClaim } from "../types"; +import { computeChannelId } from "../utils"; +import * as Errors from "../errors"; +import type { BatchSettlementEvmScheme } from "./scheme"; +import type { Channel } from "./storage"; +import { + parseRefundSettlementSnapshot, + readChannelStateExtra, + readExtraNumber, + readExtraString, +} from "./utils"; + +/** + * Converts stored channel state into the public response snapshot shape. + * + * @param channel - Stored channel state. + * @param chargedCumulativeAmount - Optional current charged cumulative amount. + * @returns Response-ready channel snapshot. + */ +function channelStateExtra( + channel: Pick< + Channel, + "channelId" | "balance" | "totalClaimed" | "withdrawRequestedAt" | "refundNonce" + >, + chargedCumulativeAmount?: string, +): NonNullable { + return { + channelId: channel.channelId as `0x${string}`, + balance: channel.balance, + totalClaimed: channel.totalClaimed, + withdrawRequestedAt: channel.withdrawRequestedAt, + refundNonce: String(channel.refundNonce), + ...(chargedCumulativeAmount !== undefined ? { chargedCumulativeAmount } : {}), + }; +} + +/** + * Lifecycle hook: runs before the facilitator settles a payment. + * + * For voucher payloads the server does NOT trigger an onchain settle. Instead, it + * increments the local `chargedCumulativeAmount` and returns a `skip` result so the + * middleware responds immediately. Cooperative refund payloads proceed to settlement + * enrichment before facilitator settlement. + * + * @param scheme - Owning `BatchSettlementEvmScheme` instance for storage access. + * @param ctx - Settle lifecycle context (payload and requirements). + * @returns Nothing to proceed; `abort` to fail; `skip` with a result to short-circuit settlement. + */ +export async function handleBeforeSettle( + scheme: BatchSettlementEvmScheme, + ctx: SettleContext, +): Promise< + void | { abort: true; reason: string; message?: string } | { skip: true; result: SettleResponse } +> { + const { paymentPayload, requirements } = ctx; + + const raw = paymentPayload.payload; + const storage = scheme.getStorage(); + + if (!isBatchSettlementVoucherPayload(raw)) { + return; + } + + const { voucher } = raw; + const channelId = voucher.channelId; + const pendingId = scheme.readRequestContext(paymentPayload)?.pendingId; + + const increment = BigInt(requirements.amount); + const signedCap = BigInt(voucher.maxClaimableAmount); + let outcome: + | { status: "missing" } + | { status: "pending_mismatch" } + | { status: "cap_exceeded"; charged: string } + | { status: "committed"; previous: Channel; current: Channel } + | undefined; + + const updateResult = await storage.updateChannel(channelId, current => { + if (!current) { + outcome = { status: "missing" }; + return current; + } + + if (!pendingId || current.pendingRequest?.pendingId !== pendingId) { + outcome = { status: "pending_mismatch" }; + return current; + } + + const newCharged = BigInt(current.chargedCumulativeAmount) + increment; + if (newCharged > signedCap) { + outcome = { status: "cap_exceeded", charged: newCharged.toString() }; + return { + ...current, + pendingRequest: undefined, + }; + } + + const updatedChannel: Channel = { + ...current, + chargedCumulativeAmount: newCharged.toString(), + signedMaxClaimable: voucher.maxClaimableAmount, + signature: voucher.signature, + lastRequestTimestamp: Date.now(), + pendingRequest: undefined, + }; + outcome = { status: "committed", previous: current, current: updatedChannel }; + return updatedChannel; + }); + + if (outcome?.status === "missing") { + scheme.takeRequestContext(paymentPayload); + return { + abort: true, + reason: Errors.ErrMissingChannel, + message: "No channel record", + }; + } + + if (outcome?.status === "cap_exceeded") { + scheme.takeRequestContext(paymentPayload); + return { + abort: true, + reason: Errors.ErrChargeExceedsSignedCumulative, + message: `Charged ${outcome.charged} exceeds signed max ${signedCap.toString()}`, + }; + } + + if (updateResult.status !== "updated" || outcome?.status !== "committed") { + scheme.takeRequestContext(paymentPayload); + return { + abort: true, + reason: Errors.ErrChannelBusy, + message: "Concurrent request modified channel state", + }; + } + scheme.takeRequestContext(paymentPayload); + + const skipExtra: BatchSettlementPaymentResponseExtra = { + channelState: channelStateExtra(outcome.previous, outcome.current.chargedCumulativeAmount), + chargedAmount: requirements.amount, + }; + + return { + skip: true, + result: { + success: true, + payer: outcome.previous.channelConfig.payer.toLowerCase() as `0x${string}`, + transaction: "", + network: requirements.network, + amount: "", + extra: skipExtra, + }, + }; +} + +/** + * Enriches cooperative refund vouchers with facilitator settlement fields. + * + * @param scheme - Owning `BatchSettlementEvmScheme` instance for storage and signer access. + * @param ctx - Settlement context for the current payment. + * @returns Additive refund settlement fields, or nothing for non-refund payloads. + */ +export async function handleEnrichSettlementPayload( + scheme: BatchSettlementEvmScheme, + ctx: SettleContext, +): Promise | void> { + const { paymentPayload, requirements } = ctx; + const raw = paymentPayload.payload; + if (!isBatchSettlementRefundPayload(raw)) { + return; + } + + const channelId = computeChannelId(raw.channelConfig, requirements.network); + if (raw.voucher.channelId !== channelId) { + throw new Error("refund channelId does not match channelConfig"); + } + + const channel = await scheme.getStorage().get(channelId); + if (!channel) { + throw new Error(Errors.ErrMissingChannel); + } + const pendingId = scheme.readRequestContext(paymentPayload)?.pendingId; + if (!pendingId || channel.pendingRequest?.pendingId !== pendingId) { + throw new Error(Errors.ErrChannelBusy); + } + if (BigInt(raw.voucher.maxClaimableAmount) !== BigInt(channel.chargedCumulativeAmount)) { + throw new Error(Errors.ErrCumulativeAmountMismatch); + } + if (raw.voucher.signature !== channel.signature) { + throw new Error(Errors.ErrInvalidVoucherSignature); + } + + const config = raw.channelConfig; + + const claimEntry: BatchSettlementVoucherClaim = { + voucher: { + channel: config, + maxClaimableAmount: raw.voucher.maxClaimableAmount, + }, + signature: raw.voucher.signature, + totalClaimed: channel.chargedCumulativeAmount, + }; + + const remainder = BigInt(channel.balance) - BigInt(channel.chargedCumulativeAmount); + if (remainder <= 0n) { + throw new Error(Errors.ErrRefundNoBalance); + } + + let refundAmountBig = remainder; + if (raw.amount !== undefined) { + if (!/^\d+$/.test(raw.amount)) { + throw new Error(Errors.ErrRefundAmountInvalid); + } + const requested = BigInt(raw.amount); + if (requested <= 0n) { + throw new Error(Errors.ErrRefundAmountInvalid); + } + refundAmountBig = requested; + } + + const refundAmount = refundAmountBig.toString(); + const nonce = String(channel.refundNonce ?? 0); + + const receiverAuthorizerSigner = scheme.getReceiverAuthorizerSigner(); + + const refundAuthorizerSignature = receiverAuthorizerSigner + ? await signRefund( + receiverAuthorizerSigner, + channelId as `0x${string}`, + refundAmount, + nonce, + requirements.network, + ) + : undefined; + + const claimAuthorizerSignature = receiverAuthorizerSigner + ? await signClaimBatch(receiverAuthorizerSigner, [claimEntry], requirements.network) + : undefined; + + scheme.rememberChannelSnapshot(paymentPayload, channel); + + return { + ...(raw.amount === undefined ? { amount: refundAmount } : {}), + refundNonce: nonce, + claims: [claimEntry], + refundAuthorizerSignature, + claimAuthorizerSignature, + }; +} + +/** + * Lifecycle hook: runs after the facilitator settles a payment. + * + * Updates channel state to reflect the settlement outcome — adjusting charged amounts, + * balances, and handling cooperative-refund cleanup (channel record deletion). + * + * @param scheme - Owning `BatchSettlementEvmScheme` instance for storage access. + * @param ctx - Post-settle lifecycle context. + * @param ctx.paymentPayload - Payment payload that was settled (possibly rewritten). + * @param ctx.requirements - Requirements used for settlement. + * @param ctx.result - Facilitator settle response. + * @returns Resolves when session updates are complete (no return value). + */ +export async function handleAfterSettle( + scheme: BatchSettlementEvmScheme, + ctx: SettleResultContext, +): Promise { + const { paymentPayload, requirements, result } = ctx; + if (!result.success) { + return; + } + + const raw = paymentPayload.payload; + const storage = scheme.getStorage(); + + if (isBatchSettlementRefundPayload(raw)) { + const channelId = computeChannelId(raw.channelConfig, requirements.network); + const pendingId = scheme.readRequestContext(paymentPayload)?.pendingId; + const now = Date.now(); + + const snapshot = parseRefundSettlementSnapshot(result.extra); + const updateResult = await storage.updateChannel(channelId, current => { + if (!current) { + return current; + } + if (!pendingId || current.pendingRequest?.pendingId !== pendingId) { + return current; + } + if (BigInt(snapshot.balance) <= BigInt(current.chargedCumulativeAmount)) { + return undefined; + } + return { + ...current, + ...snapshot, + onchainSyncedAt: now, + lastRequestTimestamp: now, + pendingRequest: undefined, + }; + }); + if (updateResult.status === "unchanged") { + throw new Error(Errors.ErrChannelBusy); + } + if (!updateResult.channel) { + return; + } + return; + } + + if (isBatchSettlementVoucherPayload(raw)) { + return; + } + + if (isBatchSettlementDepositPayload(raw)) { + const channelId = raw.voucher.channelId; + const pendingId = scheme.readRequestContext(paymentPayload)?.pendingId; + const ex = result.extra ?? {}; + const channelState = readChannelStateExtra(ex); + const config = raw.channelConfig; + const signedMaxClaimable = raw.voucher.maxClaimableAmount; + const now = Date.now(); + + const updateResult = await storage.updateChannel(channelId, current => { + if (!current) { + return current; + } + if (!pendingId || current.pendingRequest?.pendingId !== pendingId) { + return current; + } + const chargedActual = ( + BigInt(current.chargedCumulativeAmount) + BigInt(requirements.amount) + ).toString(); + return { + channelId, + channelConfig: config, + chargedCumulativeAmount: chargedActual, + signedMaxClaimable, + signature: raw.voucher.signature, + balance: readExtraString(channelState, "balance", current.balance), + totalClaimed: readExtraString(channelState, "totalClaimed", current.totalClaimed), + withdrawRequestedAt: readExtraNumber( + channelState, + "withdrawRequestedAt", + current.withdrawRequestedAt, + ), + refundNonce: readExtraNumber(channelState, "refundNonce", current.refundNonce), + onchainSyncedAt: now, + lastRequestTimestamp: now, + }; + }); + if (updateResult.status === "updated" && updateResult.channel) { + scheme.rememberChannelSnapshot(paymentPayload, updateResult.channel); + return; + } + scheme.takeRequestContext(paymentPayload); + throw new Error(Errors.ErrChannelBusy); + } +} + +/** + * Cleanup hook: clears this request's reservation after settlement throws. + * + * @param scheme - Owning `BatchSettlementEvmScheme` instance. + * @param ctx - Settle failure context for the current payment. + */ +export async function handleSettleFailure( + scheme: BatchSettlementEvmScheme, + ctx: SettleFailureContext, +): Promise { + await scheme.clearPendingRequest(ctx.paymentPayload); +} + +/** + * Supplies server-owned settlement response fields from the channel snapshot. + * + * @param scheme - Owning `BatchSettlementEvmScheme` instance for snapshot access. + * @param ctx - Settlement result context for the current payment. + * @returns Additive response extra fields, or nothing when no snapshot exists. + */ +export async function handleEnrichSettlementResponse( + scheme: BatchSettlementEvmScheme, + ctx: SettleResultContext, +): Promise | void> { + const raw = ctx.paymentPayload.payload; + if (isBatchSettlementVoucherPayload(raw)) { + return; + } + + const channel = scheme.takeChannelSnapshot(ctx.paymentPayload); + if (!channel) { + return; + } + + if (isBatchSettlementRefundPayload(raw)) { + return { + channelState: { + chargedCumulativeAmount: channel.chargedCumulativeAmount, + }, + }; + } + + if (isBatchSettlementDepositPayload(raw)) { + return { + channelState: { + chargedCumulativeAmount: channel.chargedCumulativeAmount, + }, + chargedAmount: ctx.requirements.amount, + }; + } + return { + channelState: { + chargedCumulativeAmount: channel.chargedCumulativeAmount, + }, + }; +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/server/storage.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/server/storage.ts new file mode 100644 index 0000000000..f2e843cf9d --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/server/storage.ts @@ -0,0 +1,133 @@ +import type { ChannelConfig } from "../types"; + +export interface Channel { + channelId: string; + channelConfig: ChannelConfig; + chargedCumulativeAmount: string; + signedMaxClaimable: string; + signature: string; + balance: string; + totalClaimed: string; + withdrawRequestedAt: number; + refundNonce: number; + onchainSyncedAt?: number; + lastRequestTimestamp: number; + pendingRequest?: PendingRequest; +} + +export interface PendingRequest { + pendingId: string; + signedMaxClaimable: string; + expiresAt: number; +} + +export interface ChannelUpdateResult { + channel: Channel | undefined; + status: "updated" | "unchanged" | "deleted"; +} + +export interface ChannelStorage { + get(channelId: string): Promise; + list(): Promise; + /** + * Atomically inspects and mutates a channel record. + * + * Implementations must guarantee that no concurrent mutation can interleave between + * reading `current` and writing the callback result for all application instances that + * share the backend. The in-memory backend only provides this guarantee inside one JS + * runtime; production multi-instance deployments need storage with backend-level atomic + * conditional mutation, such as Redis/Valkey Lua scripts, SQL transactions, or Durable Objects. + * + * @param channelId - The channel identifier. + * @param update - Mutation callback. Return `undefined` to delete, or `current` to leave unchanged. + * @returns The final stored channel and whether storage updated, stayed unchanged, or deleted. + */ + updateChannel( + channelId: string, + update: (current: Channel | undefined) => Channel | undefined, + ): Promise; +} + +/** + * In-memory {@link ChannelStorage} backed by a Map keyed by `channelId`. + */ +export class InMemoryChannelStorage implements ChannelStorage { + private readonly channels = new Map(); + private readonly channelLocks = new Map>(); + + /** + * Returns the channel record for a channel, if present. + * + * @param channelId - The channel identifier. + * @returns The channel record or undefined when not found. + */ + async get(channelId: string): Promise { + return this.channels.get(channelId.toLowerCase()); + } + + /** + * Lists all stored channel records. + * + * @returns All channel records in storage. + */ + async list(): Promise { + return [...this.channels.values()]; + } + + /** + * Atomically inspects and mutates a channel record while holding a per-channel lock. + * + * @param channelId - The channel identifier. + * @param update - Mutation callback. Return `undefined` to delete, or `current` to leave unchanged. + * @returns The final stored channel and whether storage updated, stayed unchanged, or deleted. + */ + async updateChannel( + channelId: string, + update: (current: Channel | undefined) => Channel | undefined, + ): Promise { + const key = channelId.toLowerCase(); + return this.withChannelLock(key, async () => { + const current = this.channels.get(key); + const next = update(current); + + if (next === current) { + return { channel: current, status: "unchanged" }; + } + + if (!next) { + this.channels.delete(key); + return { channel: undefined, status: current ? "deleted" : "unchanged" }; + } + + this.channels.set(key, next); + return { channel: next, status: "updated" }; + }); + } + + /** + * Runs `fn` after any prior locked work for the same channel key has finished. + * + * @param key - Lowercased channel id used as the lock key. + * @param fn - Async work to run while holding the logical per-channel lock. + * @returns The resolved result of `fn`. + */ + private async withChannelLock(key: string, fn: () => Promise): Promise { + const previous = this.channelLocks.get(key) ?? Promise.resolve(); + let release!: () => void; + const current = new Promise(resolve => { + release = resolve; + }); + const next = previous.catch(() => {}).then(() => current); + this.channelLocks.set(key, next); + + await previous.catch(() => {}); + try { + return await fn(); + } finally { + release(); + if (this.channelLocks.get(key) === next) { + this.channelLocks.delete(key); + } + } + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/server/utils.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/server/utils.ts new file mode 100644 index 0000000000..1c91b80bf5 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/server/utils.ts @@ -0,0 +1,118 @@ +import type { BatchSettlementChannelStateExtra } from "../types"; +import { ErrRefundPayload } from "../errors"; + +/** + * Reads the nested channel snapshot from payment response extra fields. + * + * @param extra - Payment response extra fields. + * @returns Channel state object, or undefined when absent. + */ +export function readChannelStateExtra( + extra: Record | undefined, +): Partial | undefined { + const value = extra?.channelState; + if (typeof value !== "object" || value === null) { + return undefined; + } + return value as Partial; +} + +/** + * Reads a string value from optional payment `extra`, with a fallback when missing or invalid. + * + * @param extra - Optional payment extra record. + * @param key - Key on `BatchSettlementPaymentResponseExtra` to read. + * @param fallback - Value returned when the entry is absent or not coercible to string. + * @returns String representation of the value, or `fallback`. + */ +export function readExtraString( + extra: Partial> | undefined, + key: keyof BatchSettlementChannelStateExtra, + fallback: string, +): string { + const value = extra?.[key]; + if (typeof value === "string") return value; + if (typeof value === "number") return String(value); + return fallback; +} + +/** + * Reads a numeric value from optional payment `extra`, with a fallback when missing or invalid. + * + * @param extra - Optional payment extra record. + * @param key - Key on `BatchSettlementPaymentResponseExtra` to read. + * @param fallback - Value returned when the entry is absent or not parseable as a number. + * @returns Parsed number, or `fallback`. + */ +export function readExtraNumber( + extra: Partial> | undefined, + key: keyof BatchSettlementChannelStateExtra, + fallback: number, +): number { + const value = extra?.[key]; + if (typeof value === "number") return value; + if (typeof value === "string") return parseInt(value, 10) || fallback; + return fallback; +} + +export type RefundSettlementSnapshot = { + balance: string; + totalClaimed: string; + withdrawRequestedAt: number; + refundNonce: number; +}; + +/** + * Parses the facilitator's post-refund channel snapshot. + * + * @param extra - Settlement response extra fields. + * @returns Validated refund settlement snapshot. + */ +export function parseRefundSettlementSnapshot( + extra: Record | undefined, +): RefundSettlementSnapshot { + const channelState = readChannelStateExtra(extra); + return { + balance: parseUintStringExtra(channelState, "balance"), + totalClaimed: parseUintStringExtra(channelState, "totalClaimed"), + withdrawRequestedAt: parseUintNumberExtra(channelState, "withdrawRequestedAt"), + refundNonce: parseUintNumberExtra(channelState, "refundNonce"), + }; +} + +/** + * Parses a non-negative integer as a decimal string from refund snapshot `extra`. + * + * @param extra - Settlement response extra fields from the facilitator. + * @param key - Field name: `balance` or `totalClaimed`. + * @returns Decimal string representation of the uint (digits only). + */ +function parseUintStringExtra( + extra: Partial> | undefined, + key: "balance" | "totalClaimed", +): string { + const value = extra?.[key]; + if (typeof value === "string" && /^\d+$/.test(value)) return value; + if (typeof value === "number" && Number.isInteger(value) && value >= 0) return String(value); + throw new Error(ErrRefundPayload); +} + +/** + * Parses a non-negative integer from refund snapshot `extra`. + * + * @param extra - Settlement response extra fields from the facilitator. + * @param key - Field name: `withdrawRequestedAt` or `refundNonce`. + * @returns Parsed non-negative integer. + */ +function parseUintNumberExtra( + extra: Partial> | undefined, + key: "withdrawRequestedAt" | "refundNonce", +): number { + const value = extra?.[key]; + if (typeof value === "number" && Number.isInteger(value) && value >= 0) return value; + if (typeof value === "string" && /^\d+$/.test(value)) { + const parsed = parseInt(value, 10); + if (!Number.isNaN(parsed)) return parsed; + } + throw new Error(ErrRefundPayload); +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/server/verify.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/server/verify.ts new file mode 100644 index 0000000000..adb4f17a50 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/server/verify.ts @@ -0,0 +1,543 @@ +import type { + VerifiedPaymentCanceledContext, + VerifyContext, + VerifyFailureContext, + VerifyResultContext, +} from "@x402/core/server"; +import type { VerifyResponse } from "@x402/core/types"; +import type { SchemePaymentRequiredContext } from "@x402/core/types"; +import { getAddress, verifyTypedData } from "viem"; +import { + type BatchSettlementDepositPayload, + type BatchSettlementRefundPayload, + type BatchSettlementVoucherPayload, + isBatchSettlementDepositPayload, + isBatchSettlementRefundPayload, + isBatchSettlementVoucherPayload, +} from "../types"; +import { BATCH_SETTLEMENT_SCHEME, voucherTypes } from "../constants"; +import type { ChannelConfig } from "../types"; +import { createNonce, getEvmChainId } from "../../utils"; +import { computeChannelId, getBatchSettlementEip712Domain } from "../utils"; +import { validateChannelConfig } from "../facilitator/utils"; +import * as Errors from "../errors"; +import type { BatchSettlementEvmScheme } from "./scheme"; +import type { Channel, PendingRequest } from "./storage"; +import { readExtraNumber, readExtraString } from "./utils"; + +// Framework cleanup hooks clear pending reservations for normal failures +// This bounded TTL releases channels when cleanup cannot run or complete +const MIN_PENDING_TTL_MS = 5_000; // 5 seconds +const MAX_PENDING_TTL_MS = 10 * 60 * 1000; // 600 seconds + +/** + * Computes the bounded pending reservation expiry time. + * + * @param maxTimeoutSeconds - Resource timeout from payment requirements. + * @param now - Current wall-clock time in milliseconds. + * @returns Expiry timestamp in milliseconds. + */ +function pendingExpiresAt(maxTimeoutSeconds: number | undefined, now: number): number { + const requestedMs = Math.max(0, maxTimeoutSeconds ?? 0) * 1000; + const ttlMs = Math.min(MAX_PENDING_TTL_MS, Math.max(MIN_PENDING_TTL_MS, requestedMs)); + return now + ttlMs; +} + +/** + * Checks whether a pending reservation still blocks same-channel work. + * + * @param pending - Pending reservation to inspect. + * @param now - Current wall-clock time in milliseconds. + * @returns Whether the reservation exists and has not expired. + */ +function isPendingLive(pending: PendingRequest | undefined, now: number): boolean { + return pending !== undefined && pending.expiresAt > now; +} + +/** + * Lifecycle hook: runs before the facilitator verifies a payment. + * + * For paid payloads, checks whether the client's cumulative amount matches server + * state. If mismatched, aborts with `invalid_batch_settlement_evm_cumulative_amount_mismatch`. + * + * Refund vouchers are zero-charge: the expected `maxClaimableAmount` equals + * the existing `chargedCumulativeAmount`. + * + * When no local channel record exists, verification is delegated to the facilitator (which checks onchain state); + * `handleAfterVerify` then rebuilds the channel record from the verify response. + * + * @param scheme - Owning `BatchSettlementEvmScheme` instance for storage access. + * @param ctx - Verify lifecycle context (payload, requirements, and related state). + * @returns Nothing to continue verification; or an object with `abort` to fail with a reason. + */ +export async function handleBeforeVerify( + scheme: BatchSettlementEvmScheme, + ctx: VerifyContext, +): Promise< + void | { abort: true; reason: string; message?: string } | { skip: true; result: VerifyResponse } +> { + const { paymentPayload, requirements } = ctx; + + const raw = paymentPayload.payload; + const isPaidPayload = + isBatchSettlementVoucherPayload(raw) || isBatchSettlementDepositPayload(raw); + const isZeroChargePayload = isBatchSettlementRefundPayload(raw); + if (!isPaidPayload && !isZeroChargePayload) { + return; + } + + const channelId = raw.voucher.channelId; + const now = Date.now(); + const pendingId = createNonce(); + let outcome: + | { status: "reserved"; channelSnapshot?: Channel } + | { status: "busy" } + | { status: "mismatch"; channel: Channel } + | undefined; + + await scheme.getStorage().updateChannel(channelId, current => { + if (isPendingLive(current?.pendingRequest, now)) { + outcome = { status: "busy" }; + return current; + } + + const chargedCumulativeAmount = + current?.chargedCumulativeAmount ?? + inferMissingLocalChargedAmount( + raw.voucher.maxClaimableAmount, + requirements.amount, + isPaidPayload, + ); + const expectedMaxClaimable = isZeroChargePayload + ? BigInt(chargedCumulativeAmount) + : BigInt(chargedCumulativeAmount) + BigInt(requirements.amount); + + if (BigInt(raw.voucher.maxClaimableAmount) !== expectedMaxClaimable) { + if (current) { + outcome = { status: "mismatch", channel: current }; + } else { + outcome = { + status: "mismatch", + channel: buildProvisionalChannel(raw, chargedCumulativeAmount), + }; + } + return current; + } + + const pendingRequest: PendingRequest = { + pendingId, + signedMaxClaimable: raw.voucher.maxClaimableAmount, + expiresAt: pendingExpiresAt(requirements.maxTimeoutSeconds, now), + }; + + outcome = { status: "reserved", channelSnapshot: current }; + return { + ...(current ?? buildProvisionalChannel(raw, chargedCumulativeAmount)), + pendingRequest, + lastRequestTimestamp: now, + }; + }); + + if (outcome?.status === "busy") { + return { + abort: true, + reason: Errors.ErrChannelBusy, + message: "Channel is already processing a request", + }; + } + + if (outcome?.status === "mismatch") { + scheme.rememberChannelSnapshot(paymentPayload, outcome.channel); + return { + abort: true, + reason: Errors.ErrCumulativeAmountMismatch, + message: "Client voucher base does not match server state", + }; + } + + if (outcome?.status === "reserved") { + scheme.mergeRequestContext(paymentPayload, { + channelId, + pendingId, + channelSnapshot: outcome.channelSnapshot, + }); + + if (isBatchSettlementVoucherPayload(raw)) { + const localResult = await verifyVoucherLocally( + scheme, + raw, + requirements, + outcome.channelSnapshot, + now, + ); + if (localResult) { + scheme.mergeRequestContext(paymentPayload, { localVerify: true }); + return { skip: true, result: localResult }; + } + } + } +} + +/** + * Adds server channel state to corrective 402 responses for cumulative mismatches. + * + * @param scheme - Owning `BatchSettlementEvmScheme` instance for storage access. + * @param ctx - Payment-required response context. + */ +export async function handleEnrichPaymentRequiredResponse( + scheme: BatchSettlementEvmScheme, + ctx: SchemePaymentRequiredContext, +): Promise { + if (ctx.error !== Errors.ErrCumulativeAmountMismatch) { + return; + } + + const { paymentPayload } = ctx; + if (!paymentPayload) { + return; + } + + const raw = paymentPayload.payload; + if ( + !isBatchSettlementVoucherPayload(raw) && + !isBatchSettlementDepositPayload(raw) && + !isBatchSettlementRefundPayload(raw) + ) { + return; + } + + const channel = + scheme.takeChannelSnapshot(paymentPayload) ?? + (await scheme.getStorage().get(raw.voucher.channelId)); + if (!channel) { + return; + } + + const accept = ctx.requirements.find( + req => + req.scheme === BATCH_SETTLEMENT_SCHEME && req.network === paymentPayload.accepted.network, + ); + if (!accept) { + return; + } + + accept.extra = { + ...accept.extra, + channelState: { + channelId: channel.channelId, + balance: channel.balance, + totalClaimed: channel.totalClaimed, + withdrawRequestedAt: channel.withdrawRequestedAt, + refundNonce: String(channel.refundNonce), + chargedCumulativeAmount: channel.chargedCumulativeAmount, + }, + voucherState: { + signedMaxClaimable: channel.signedMaxClaimable, + signature: channel.signature as `0x${string}`, + }, + }; +} + +/** + * Lifecycle hook: runs after the facilitator verifies a payment. + * + * Persists channel state (balance, totalClaimed, voucher info) so that + * subsequent requests can correctly calculate cumulative amounts and detect stale state. + * + * For refund payloads, additionally returns a `skipHandler` directive so that + * the resource server bypasses the application handler and settles inline. + * + * @param scheme - Owning `BatchSettlementEvmScheme` instance for storage access. + * @param ctx - Post-verify lifecycle context. + * @param ctx.paymentPayload - Incoming payment payload that was verified. + * @param ctx.requirements - Requirements used for verification. + * @param ctx.result - Facilitator verify response. + * @returns Optional `skipHandler` directive when this is a refund voucher; otherwise void. + */ +export async function handleAfterVerify( + scheme: BatchSettlementEvmScheme, + ctx: VerifyResultContext, +): Promise { + const { paymentPayload, result } = ctx; + if (!result.isValid || !result.payer) { + await scheme.clearPendingRequest(paymentPayload); + return; + } + + const raw = paymentPayload.payload; + let channelId: string; + let signedMaxClaimable: string; + let signature: `0x${string}`; + let channelConfig: ChannelConfig; + let isRefundVoucher = false; + + if (isBatchSettlementDepositPayload(raw)) { + channelId = raw.voucher.channelId; + signedMaxClaimable = raw.voucher.maxClaimableAmount; + signature = raw.voucher.signature; + channelConfig = raw.channelConfig; + } else if (isBatchSettlementVoucherPayload(raw)) { + channelId = raw.voucher.channelId; + signedMaxClaimable = raw.voucher.maxClaimableAmount; + signature = raw.voucher.signature; + channelConfig = raw.channelConfig; + } else if (isBatchSettlementRefundPayload(raw)) { + channelId = raw.voucher.channelId; + signedMaxClaimable = raw.voucher.maxClaimableAmount; + signature = raw.voucher.signature; + channelConfig = raw.channelConfig; + isRefundVoucher = true; + } else { + return; + } + + const ex = result.extra ?? {}; + const balance = readExtraString(ex, "balance", "0"); + const totalClaimed = readExtraString(ex, "totalClaimed", "0"); + const withdrawRequestedAt = readExtraNumber(ex, "withdrawRequestedAt", 0); + const refundNonce = readExtraNumber(ex, "refundNonce", 0); + const now = Date.now(); + + const storage = scheme.getStorage(); + const requestContext = scheme.readRequestContext(paymentPayload); + if (!requestContext?.pendingId) { + return; + } + if (requestContext.localVerify && isBatchSettlementVoucherPayload(raw)) { + return; + } + + const updateResult = await storage.updateChannel(channelId, current => { + if (!current || current.pendingRequest?.pendingId !== requestContext.pendingId) { + return current; + } + + const channel: Channel = { + channelId, + channelConfig, + chargedCumulativeAmount: current.chargedCumulativeAmount, + signedMaxClaimable, + signature, + balance, + totalClaimed, + withdrawRequestedAt, + refundNonce, + onchainSyncedAt: requestContext.localVerify ? current.onchainSyncedAt : now, + lastRequestTimestamp: now, + pendingRequest: current.pendingRequest, + }; + return channel; + }); + if (updateResult.status === "updated" && updateResult.channel) { + scheme.rememberChannelSnapshot(paymentPayload, updateResult.channel); + } + + if (isRefundVoucher && updateResult.status === "updated") { + return { + skipHandler: true, + response: { + contentType: "application/json", + body: { message: "Refund acknowledged", channelId }, + }, + }; + } +} + +/** + * Cleanup hook: clears this request's reservation after verify throws. + * + * @param scheme - Owning `BatchSettlementEvmScheme` instance. + * @param ctx - Verify failure context for the current payment. + */ +export async function handleVerifyFailure( + scheme: BatchSettlementEvmScheme, + ctx: VerifyFailureContext, +): Promise { + await scheme.clearPendingRequest(ctx.paymentPayload); +} + +/** + * Cleanup hook: clears this request's reservation when handler work is canceled. + * + * @param scheme - Owning `BatchSettlementEvmScheme` instance. + * @param ctx - Verified-payment cancellation context. + */ +export async function handleVerifiedPaymentCanceled( + scheme: BatchSettlementEvmScheme, + ctx: VerifiedPaymentCanceledContext, +): Promise { + if (ctx.reason !== "handler_threw" && ctx.reason !== "handler_failed") { + return; + } + await scheme.clearPendingRequest(ctx.paymentPayload); +} + +/** + * Verifies a voucher against locally cached channel state when that state is fresh. + * + * @param scheme - Batch settlement scheme (TTL for onchain sync freshness). + * @param raw - Decoded batch-settlement voucher payload. + * @param requirements - Payment requirements (network, etc.). + * @param channel - Cached channel row, if any. + * @param now - Current wall-clock time in milliseconds. + * @returns A {@link VerifyResponse}, or `undefined` to fall back to facilitator verification. + */ +async function verifyVoucherLocally( + scheme: BatchSettlementEvmScheme, + raw: BatchSettlementVoucherPayload, + requirements: VerifyContext["requirements"], + channel: Channel | undefined, + now: number, +): Promise { + if (!channel || !isOnchainStateFresh(channel, scheme.getOnchainStateTtlMs(), now)) { + return; + } + + if (raw.channelConfig.payerAuthorizer === "0x0000000000000000000000000000000000000000") { + return; + } + + const payer = raw.channelConfig.payer; + const configErr = validateChannelConfig( + raw.channelConfig, + raw.voucher.channelId, + requirements as Parameters[2], + ); + if (configErr) { + return invalidVerifyResponse(payer, configErr); + } + + if ( + computeChannelId(raw.channelConfig, requirements.network).toLowerCase() !== + channel.channelId.toLowerCase() + ) { + return invalidVerifyResponse(payer, Errors.ErrChannelIdMismatch); + } + + const signatureOk = await verifyLocalVoucherSignature(raw, requirements.network); + if (!signatureOk) { + return invalidVerifyResponse(payer, Errors.ErrInvalidVoucherSignature); + } + + const maxClaimableAmount = BigInt(raw.voucher.maxClaimableAmount); + if (maxClaimableAmount > BigInt(channel.balance)) { + return invalidVerifyResponse(payer, Errors.ErrCumulativeExceedsBalance); + } + + if (maxClaimableAmount <= BigInt(channel.totalClaimed)) { + return invalidVerifyResponse(payer, Errors.ErrCumulativeAmountBelowClaimed); + } + + return { + isValid: true, + payer, + extra: { + channelId: raw.voucher.channelId, + balance: channel.balance, + totalClaimed: channel.totalClaimed, + withdrawRequestedAt: channel.withdrawRequestedAt, + refundNonce: channel.refundNonce.toString(), + }, + }; +} + +/** + * Returns whether cached onchain fields for a channel are still within the freshness window. + * + * @param channel - Cached channel row. + * @param ttlMs - Maximum age of `onchainSyncedAt` in milliseconds. + * @param now - Current wall-clock time in milliseconds. + * @returns `true` if onchain sync time is present and still within `ttlMs` of `now`. + */ +function isOnchainStateFresh(channel: Channel, ttlMs: number, now: number): boolean { + return channel.onchainSyncedAt !== undefined && now - channel.onchainSyncedAt <= ttlMs; +} + +/** + * Verifies the EIP-712 voucher signature against the payer authorizer. + * + * @param raw - Decoded batch-settlement voucher payload. + * @param network - EVM network identifier for chain ID / domain. + * @returns Whether the typed-data signature is valid. + */ +async function verifyLocalVoucherSignature( + raw: BatchSettlementVoucherPayload, + network: string, +): Promise { + try { + return await verifyTypedData({ + address: getAddress(raw.channelConfig.payerAuthorizer), + domain: getBatchSettlementEip712Domain(getEvmChainId(network)), + types: voucherTypes, + primaryType: "Voucher", + message: { + channelId: raw.voucher.channelId, + maxClaimableAmount: BigInt(raw.voucher.maxClaimableAmount), + }, + signature: raw.voucher.signature, + }); + } catch { + return false; + } +} + +/** + * Builds a failed verify response with the payer address preserved for reporting. + * + * @param payer - Payer address from the payload. + * @param invalidReason - Machine-readable failure reason. + * @returns Invalid {@link VerifyResponse} with `isValid: false`. + */ +function invalidVerifyResponse(payer: `0x${string}`, invalidReason: string): VerifyResponse { + return { isValid: false, invalidReason, payer }; +} + +/** + * Builds the minimal local channel record needed to reserve missing state. + * + * @param raw - Batch-settlement payload containing channel config and voucher. + * @param chargedCumulativeAmount - Local charged base inferred before facilitator verification. + * @returns Provisional channel state. + */ +function buildProvisionalChannel( + raw: BatchSettlementVoucherPayload | BatchSettlementDepositPayload | BatchSettlementRefundPayload, + chargedCumulativeAmount: string, +): Channel { + return { + channelId: raw.voucher.channelId, + channelConfig: raw.channelConfig, + chargedCumulativeAmount, + signedMaxClaimable: raw.voucher.maxClaimableAmount, + signature: raw.voucher.signature, + balance: "0", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: Date.now(), + }; +} + +/** + * Infers the local charged base when storage has no channel record. + * + * @param signedMaxClaimable - Client-signed cumulative voucher cap. + * @param price - Current request amount. + * @param isPaidPayload - Whether the payload should add `price` to the local base. + * @returns Inferred charged base as a decimal string. + */ +function inferMissingLocalChargedAmount( + signedMaxClaimable: string, + price: string, + isPaidPayload: boolean, +): string { + if (!isPaidPayload) { + return signedMaxClaimable; + } + + const signed = BigInt(signedMaxClaimable); + const amount = BigInt(price); + if (signed < amount) { + return "0"; + } + return (signed - amount).toString(); +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/storage-utils.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/storage-utils.ts new file mode 100644 index 0000000000..039ac8d0bd --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/storage-utils.ts @@ -0,0 +1,52 @@ +import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises"; +import { dirname, join } from "node:path"; + +/** + * Returns true when `err` is a Node.js `ENOENT` filesystem error (file does not exist). + * + * @param err - The thrown value to inspect. + * @returns `true` for `ENOENT`, `false` for any other value or error code. + */ +export function isNodeEnoent(err: unknown): boolean { + if (!err || typeof err !== "object" || !("code" in err)) return false; + return (err as NodeJS.ErrnoException).code === "ENOENT"; +} + +/** + * Reads a JSON file and parses it. Returns `undefined` if the file does not exist. + * Other errors (permission, malformed JSON) are rethrown. + * + * @param filePath - Path to the JSON file. + * @returns Parsed value, or `undefined` for `ENOENT`. + */ +export async function readJsonFile(filePath: string): Promise { + try { + const raw = await readFile(filePath, "utf8"); + return JSON.parse(raw) as T; + } catch (err: unknown) { + if (isNodeEnoent(err)) return undefined; + throw err; + } +} + +/** + * Writes JSON to `filePath` atomically (temp file in the same directory, then rename). + * Creates parent directories as needed. + * + * @param filePath - Destination file path; parent dirs are created if missing. + * @param value - JSON-serializable value to persist. + */ +export async function writeJsonAtomic(filePath: string, value: unknown): Promise { + const dir = dirname(filePath); + await mkdir(dir, { recursive: true }); + const tmp = join(dir, `.${process.pid}.${Date.now()}.${Math.random().toString(36).slice(2)}.tmp`); + const body = `${JSON.stringify(value, null, 2)}\n`; + await writeFile(tmp, body, "utf8"); + try { + await rename(tmp, filePath); + } catch { + // On Windows, rename() onto an existing file throws EEXIST; unlink + rename is intentional. + await unlink(filePath).catch(() => {}); + await rename(tmp, filePath); + } +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/types.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/types.ts new file mode 100644 index 0000000000..157a097563 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/types.ts @@ -0,0 +1,288 @@ +import type { TypedData } from "viem"; + +export interface AuthorizerSigner { + address: `0x${string}`; + signTypedData(params: { + domain: Record; + types: TypedData; + primaryType: string; + message: Record; + }): Promise<`0x${string}`>; +} + +export type ChannelState = { + balance: bigint; + totalClaimed: bigint; + withdrawRequestedAt: number; + refundNonce: bigint; +}; + +export type ChannelConfig = { + payer: `0x${string}`; + payerAuthorizer: `0x${string}`; + receiver: `0x${string}`; + receiverAuthorizer: `0x${string}`; + token: `0x${string}`; + withdrawDelay: number; + salt: `0x${string}`; +}; + +export type BatchSettlementErc3009Authorization = { + validAfter: string; + validBefore: string; + salt: `0x${string}`; + signature: `0x${string}`; +}; + +export type BatchSettlementPermit2Authorization = { + from: `0x${string}`; + permitted: { + token: `0x${string}`; + amount: string; + }; + spender: `0x${string}`; + nonce: string; + deadline: string; + witness: { + channelId: `0x${string}`; + }; + signature: `0x${string}`; +}; + +export type BatchSettlementAssetTransferMethod = "eip3009" | "permit2"; + +export type BatchSettlementDepositAuthorization = + | { + erc3009Authorization: BatchSettlementErc3009Authorization; + permit2Authorization?: never; + } + | { + erc3009Authorization?: never; + permit2Authorization: BatchSettlementPermit2Authorization; + }; + +export type BatchSettlementDepositPayload = { + type: "deposit"; + channelConfig: ChannelConfig; + voucher: BatchSettlementVoucherFields; + deposit: { + amount: string; + authorization: BatchSettlementDepositAuthorization; + }; +}; + +export type BatchSettlementVoucherPayload = { + type: "voucher"; + channelConfig: ChannelConfig; + voucher: BatchSettlementVoucherFields; +}; + +export type BatchSettlementRefundPayload = { + type: "refund"; + channelConfig: ChannelConfig; + voucher: BatchSettlementVoucherFields; + amount?: string; +}; + +export type BatchSettlementVoucherFields = { + channelId: `0x${string}`; + maxClaimableAmount: string; + signature: `0x${string}`; +}; + +export type BatchSettlementVoucherClaim = { + voucher: { + channel: ChannelConfig; + maxClaimableAmount: string; + }; + signature: `0x${string}`; + totalClaimed: string; +}; + +export type BatchSettlementChannelStateExtra = { + channelId: `0x${string}`; + balance: string; + totalClaimed: string; + withdrawRequestedAt: number; + refundNonce: string; + chargedCumulativeAmount?: string; +}; + +export type BatchSettlementVoucherStateExtra = { + signedMaxClaimable?: string; + signature?: `0x${string}`; +}; + +export type BatchSettlementPaymentRequirementsExtra = { + receiverAuthorizer: `0x${string}`; + withdrawDelay: number; + name: string; + version: string; + assetTransferMethod?: BatchSettlementAssetTransferMethod; + channelState?: BatchSettlementChannelStateExtra; + voucherState?: BatchSettlementVoucherStateExtra; +}; + +export type FileChannelStorageOptions = { + /** Root directory; channels are stored under `{directory}/{client|server}/{channelId}.json`. */ + directory: string; +}; + +export type BatchSettlementPaymentResponseExtra = { + chargedAmount?: string; + channelState?: BatchSettlementChannelStateExtra; + voucherState?: BatchSettlementVoucherStateExtra; +}; + +export type BatchSettlementClaimPayload = { + type: "claim"; + claims: BatchSettlementVoucherClaim[]; + claimAuthorizerSignature?: `0x${string}`; +}; + +export type BatchSettlementSettlePayload = { + type: "settle"; + receiver: `0x${string}`; + token: `0x${string}`; +}; + +export type BatchSettlementEnrichedRefundPayload = BatchSettlementRefundPayload & { + amount: string; + refundNonce: string; + claims: BatchSettlementVoucherClaim[]; + refundAuthorizerSignature?: `0x${string}`; + claimAuthorizerSignature?: `0x${string}`; +}; + +export type BatchSettlementPayload = + | BatchSettlementDepositPayload + | BatchSettlementVoucherPayload + | BatchSettlementRefundPayload; + +export type BatchSettlementFacilitatorSettlePayload = + | BatchSettlementDepositPayload + | BatchSettlementClaimPayload + | BatchSettlementSettlePayload + | BatchSettlementEnrichedRefundPayload; + +/** + * Returns true when the value is a non-null object (a usable record). + * + * @param payload - Value of unknown shape. + * @returns True if `payload` is an object that can be indexed by string keys. + */ +function isObject(payload: unknown): payload is Record { + return typeof payload === "object" && payload !== null; +} + +/** + * Type guard for internal voucher field shape (channel, amount, signature). + * + * @param payload - Unknown value to check. + * @returns True if `payload` is an object with `channelId`, `maxClaimableAmount`, and `signature`. + */ +function isVoucherFields(payload: unknown): payload is BatchSettlementVoucherFields { + return ( + isObject(payload) && + "channelId" in payload && + "maxClaimableAmount" in payload && + "signature" in payload + ); +} + +/** + * Type guard for {@link BatchSettlementDepositPayload}. + * + * @param payload - Unknown payload to check. + * @returns True if `payload` is a deposit payload (carries `deposit` and `voucher`). + */ +export function isBatchSettlementDepositPayload( + payload: unknown, +): payload is BatchSettlementDepositPayload { + return ( + isObject(payload) && + payload.type === "deposit" && + "channelConfig" in payload && + isVoucherFields(payload.voucher) && + isObject(payload.deposit) && + typeof payload.deposit.amount === "string" && + isObject(payload.deposit.authorization) + ); +} + +/** + * Type guard for {@link BatchSettlementVoucherPayload}. + * + * @param payload - Unknown payload to check. + * @returns True if `payload` is a voucher payload with channel and signature fields. + */ +export function isBatchSettlementVoucherPayload( + payload: unknown, +): payload is BatchSettlementVoucherPayload { + return ( + isObject(payload) && + payload.type === "voucher" && + "channelConfig" in payload && + isVoucherFields(payload.voucher) + ); +} + +/** + * Type guard for {@link BatchSettlementRefundPayload}. + * + * @param payload - Unknown payload to check. + * @returns True if `payload` is a refund payload with channel config and voucher fields. + */ +export function isBatchSettlementRefundPayload( + payload: unknown, +): payload is BatchSettlementRefundPayload { + return ( + isObject(payload) && + payload.type === "refund" && + "channelConfig" in payload && + isVoucherFields(payload.voucher) + ); +} + +/** + * Type guard for {@link BatchSettlementClaimPayload}. + * + * @param payload - Unknown payload to check. + * @returns True if `payload` is a settle-action `claimWithSignature` payload. + */ +export function isBatchSettlementClaimPayload( + payload: unknown, +): payload is BatchSettlementClaimPayload { + return isObject(payload) && payload.type === "claim" && "claims" in payload; +} + +/** + * Type guard for {@link BatchSettlementSettlePayload}. + * + * @param payload - Unknown payload to check. + * @returns True if `payload` is a settle-action `settle` payload. + */ +export function isBatchSettlementSettlePayload( + payload: unknown, +): payload is BatchSettlementSettlePayload { + return ( + isObject(payload) && payload.type === "settle" && "receiver" in payload && "token" in payload + ); +} + +/** + * Type guard for {@link BatchSettlementEnrichedRefundPayload}. + * + * @param payload - Unknown payload to check. + * @returns True if `payload` is a settle-action `refundWithSignature` payload. + */ +export function isBatchSettlementEnrichedRefundPayload( + payload: unknown, +): payload is BatchSettlementEnrichedRefundPayload { + return ( + isBatchSettlementRefundPayload(payload) && + "amount" in payload && + "refundNonce" in payload && + "claims" in payload + ); +} diff --git a/typescript/packages/mechanisms/evm/src/batch-settlement/utils.ts b/typescript/packages/mechanisms/evm/src/batch-settlement/utils.ts new file mode 100644 index 0000000000..4604205cc6 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/batch-settlement/utils.ts @@ -0,0 +1,47 @@ +import { getAddress, hashTypedData } from "viem"; +import { BATCH_SETTLEMENT_ADDRESS, BATCH_SETTLEMENT_DOMAIN, channelConfigTypes } from "./constants"; +import type { ChannelConfig } from "./types"; +import { getEvmChainId } from "../utils"; + +/** + * Computes the chain-bound channel id from a {@link ChannelConfig} struct. + * + * @param config - The immutable channel configuration. + * @param networkOrChainId - CAIP-2 network identifier or numeric EVM chain id. + * @returns The `bytes32` channel id as a hex string. + */ +export function computeChannelId( + config: ChannelConfig, + networkOrChainId: string | number, +): `0x${string}` { + const chainId = + typeof networkOrChainId === "number" ? networkOrChainId : getEvmChainId(networkOrChainId); + return hashTypedData({ + domain: getBatchSettlementEip712Domain(chainId), + types: channelConfigTypes, + primaryType: "ChannelConfig", + message: { + payer: config.payer, + payerAuthorizer: config.payerAuthorizer, + receiver: config.receiver, + receiverAuthorizer: config.receiverAuthorizer, + token: config.token, + withdrawDelay: config.withdrawDelay, + salt: config.salt, + }, + }); +} + +/** + * Returns the full EIP-712 domain for the batch-settlement contract on the given chain. + * + * @param chainId - Numeric EVM chain id. + * @returns EIP-712 domain with `name`, `version`, `chainId`, and checksummed `verifyingContract`. + */ +export function getBatchSettlementEip712Domain(chainId: number) { + return { + ...BATCH_SETTLEMENT_DOMAIN, + chainId, + verifyingContract: getAddress(BATCH_SETTLEMENT_ADDRESS), + } as const; +} diff --git a/typescript/packages/mechanisms/evm/src/exact/README.md b/typescript/packages/mechanisms/evm/src/exact/README.md new file mode 100644 index 0000000000..2bf475f2b3 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/exact/README.md @@ -0,0 +1,177 @@ +# Exact EVM Scheme (`@x402/evm/exact`) + +The **exact** scheme is the default x402 payment scheme for EVM networks. The client pays the exact advertised price — no more, no less. It supports two on-chain transfer methods: **EIP-3009** (`transferWithAuthorization`) and **Permit2** (Uniswap's signature-based approval). + +## Import Paths + +| Role | Import | +|------|--------| +| Client | `@x402/evm/exact/client` | +| Server | `@x402/evm/exact/server` | +| Facilitator | `@x402/evm/exact/facilitator` | +| Client (V1 legacy) | `@x402/evm/exact/v1/client` | +| Facilitator (V1 legacy) | `@x402/evm/exact/v1/facilitator` | + +## Client Usage + +Register `ExactEvmScheme` with an `x402Client` to automatically handle payments for EVM-network services that use the `exact` scheme. + +```typescript +import { x402Client } from "@x402/core/client"; +import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { privateKeyToAccount } from "viem/accounts"; + +const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`); + +const client = new x402Client(); +client.register("eip155:*", new ExactEvmScheme(signer)); +``` + +The client selects between EIP-3009 and Permit2 based on `paymentRequirements.extra.assetTransferMethod` (defaults to `eip3009`). + +### Permit2 Approval + +If the service requires Permit2, the client may need to approve the Permit2 contract first: + +```typescript +import { createPermit2ApprovalTx, getPermit2AllowanceReadParams } from "@x402/evm/exact/client"; +``` + +## Server Usage + +Register `ExactEvmScheme` with an `x402ResourceServer` to protect routes with fixed-price payments. + +```typescript +import { x402ResourceServer } from "@x402/core/server"; +import { ExactEvmScheme } from "@x402/evm/exact/server"; + +const server = new x402ResourceServer(facilitatorClient); +server.register("eip155:*", new ExactEvmScheme()); +``` + +In your route config, set `scheme: "exact"` and `price` to the fixed amount: + +```typescript +{ + "GET /weather": { + accepts: { + scheme: "exact", + price: "$0.001", + network: "eip155:84532", + payTo: "0xYourAddress", + }, + }, +} +``` + +## Facilitator Usage + +For custom facilitator implementations: + +```typescript +import { ExactEvmScheme } from "@x402/evm/exact/facilitator"; + +const scheme = new ExactEvmScheme({ signers: [wallet] }); +``` + +## Supported Networks + +Works on any EIP-155 compatible network. Common networks: + +| Network | CAIP-2 ID | +|---------|-----------| +| Base Mainnet | `eip155:8453` | +| Base Sepolia | `eip155:84532` | + +## Transfer Methods + +| Method | Description | +|--------|-------------| +| EIP-3009 | `transferWithAuthorization` — gasless, single-signature transfer (default) | +| Permit2 | Uniswap Permit2 — signature-based approval + transfer via proxy contract | + +## Gas Sponsoring Extensions (Permit2 only) + +When using the Permit2 transfer method, the exact scheme integrates with two gas sponsoring extensions that let the **facilitator** pay for the client's Permit2 approval transaction on-chain. This is transparent to both server and client — the client SDK automatically detects advertised extensions and signs the appropriate data. + +> Gas sponsoring does **not** apply to the EIP-3009 path, which is already gasless by design. + +### EIP-2612 Gas Sponsoring + +The preferred path. If the payment token supports [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612) (gasless `permit`), the client signs an off-chain EIP-2612 permit and the facilitator calls `settleWithPermit` — bundling the approval and settlement in a single transaction with no gas cost to the client. + +**Server:** Declare the extension in your route config and ensure the token's `name` and `version` are included in `extra` (the default for EIP-2612-compatible tokens): + +```typescript +import { declareEip2612GasSponsoringExtension } from "@x402/extensions"; + +{ + "GET /weather": { + accepts: { + scheme: "exact", + price: "$0.001", + network: "eip155:84532", + payTo: "0xYourAddress", + }, + extensions: { + ...declareEip2612GasSponsoringExtension(), + }, + }, +} +``` + +**Client:** No additional setup required. `ExactEvmScheme` automatically checks for the `eip2612GasSponsoring` extension in the server's payment requirements and signs the permit when applicable. + +**Facilitator:** Register the extension: + +```typescript +import { EIP2612_GAS_SPONSORING } from "@x402/extensions"; + +facilitator.registerExtension(EIP2612_GAS_SPONSORING); +``` + +### ERC-20 Approval Gas Sponsoring + +Fallback for tokens that **do not** support EIP-2612. The client signs a raw ERC-20 `approve(Permit2, MaxUint256)` transaction off-chain and includes it in the payment payload. The facilitator broadcasts this approval transaction on-chain before settling. + +**Server:** Declare the extension and omit `name`/`version` from the token config to signal clients to skip EIP-2612: + +```typescript +import { declareErc20ApprovalGasSponsoringExtension } from "@x402/extensions"; + +{ + "GET /weather": { + accepts: { /* ... */ }, + extensions: { + ...declareErc20ApprovalGasSponsoringExtension(), + }, + }, +} +``` + +**Client:** The signer must support transaction signing (`signTransaction`, `getTransactionCount`). `ExactEvmScheme` falls back to this path when EIP-2612 is not available. + +**Facilitator:** Register with a signer that can broadcast transactions: + +```typescript +import { createErc20ApprovalGasSponsoringExtension } from "@x402/extensions"; + +facilitator.registerExtension(createErc20ApprovalGasSponsoringExtension(erc20ApprovalSigner)); +``` + +### Extension Priority + +When **both** extensions are advertised, EIP-2612 takes priority. The client tries EIP-2612 first; if the token lacks `name`/`version` in `extra` (meaning it doesn't support EIP-2612), it falls back to ERC-20 approval gas sponsoring. + +## Examples + +- [Express server](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/express) +- [Fetch client](https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients/fetch) +- [EIP-2612 gas sponsoring server](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/advanced/eip2612-gas-sponsoring.ts) + +## See Also + +- [Upto EVM Scheme](../upto/README.md) — usage-based billing with partial settlement +- [x402 Docs: Quickstart for Sellers](https://docs.x402.org/getting-started/quickstart-for-sellers) +- [x402 Docs: Quickstart for Buyers](https://docs.x402.org/getting-started/quickstart-for-buyers) +- [Exact EVM Scheme Specification](https://github.com/x402-foundation/x402/blob/main/specs/schemes/exact/scheme_exact_evm.md) diff --git a/typescript/packages/mechanisms/evm/src/exact/facilitator/eip3009-utils.ts b/typescript/packages/mechanisms/evm/src/exact/facilitator/eip3009-utils.ts index 2d8f2c4a69..73a7506845 100644 --- a/typescript/packages/mechanisms/evm/src/exact/facilitator/eip3009-utils.ts +++ b/typescript/packages/mechanisms/evm/src/exact/facilitator/eip3009-utils.ts @@ -188,6 +188,33 @@ export async function diagnoseEip3009SimulationFailure( return { isValid: false, invalidReason: Errors.ErrEip3009SimulationFailed, payer }; } +/** + * Maps an EIP-3009 contract revert error to a specific error code. + * Falls back to ErrTransactionFailed when the revert reason is unknown. + * + * @param error - The error thrown during transfer execution + * @returns A specific error reason string + */ +export function parseEip3009TransferError(error: unknown): string { + const msg = error instanceof Error ? error.message : String(error); + if (/authorization.*(expired|valid before)/i.test(msg) || /AuthorizationExpired/i.test(msg)) { + return Errors.ErrValidBeforeExpired; + } + if (/authorization.*not.*valid|AuthorizationNotYetValid/i.test(msg)) { + return Errors.ErrValidAfterInFuture; + } + if (/authorization.*used|AuthorizationAlreadyUsed|AuthorizationUsedOrCanceled/i.test(msg)) { + return Errors.ErrEip3009NonceAlreadyUsed; + } + if (/transfer.*exceeds.*balance|insufficient.*balance|ERC20InsufficientBalance/i.test(msg)) { + return Errors.ErrEip3009InsufficientBalance; + } + if (/invalid.*signature|SignerMismatch|InvalidSignatureV|InvalidSignatureS/i.test(msg)) { + return Errors.ErrInvalidSignature; + } + return Errors.ErrTransactionFailed; +} + /** * Executes transferWithAuthorization onchain. * diff --git a/typescript/packages/mechanisms/evm/src/exact/facilitator/eip3009.ts b/typescript/packages/mechanisms/evm/src/exact/facilitator/eip3009.ts index 69056a938b..5dab3b5526 100644 --- a/typescript/packages/mechanisms/evm/src/exact/facilitator/eip3009.ts +++ b/typescript/packages/mechanisms/evm/src/exact/facilitator/eip3009.ts @@ -13,6 +13,7 @@ import * as Errors from "./errors"; import { diagnoseEip3009SimulationFailure, executeTransferWithAuthorization, + parseEip3009TransferError, simulateEip3009Transfer, } from "./eip3009-utils"; @@ -318,10 +319,10 @@ export async function settleEIP3009( network: payload.accepted.network, payer, }; - } catch { + } catch (error) { return { success: false, - errorReason: Errors.ErrTransactionFailed, + errorReason: parseEip3009TransferError(error), transaction: "", network: payload.accepted.network, payer, diff --git a/typescript/packages/mechanisms/evm/src/exact/server/DEFAULT_ASSET.md b/typescript/packages/mechanisms/evm/src/exact/server/DEFAULT_ASSET.md deleted file mode 100644 index 7c03ba892d..0000000000 --- a/typescript/packages/mechanisms/evm/src/exact/server/DEFAULT_ASSET.md +++ /dev/null @@ -1,163 +0,0 @@ -# Default Assets for EVM Chains - -This document explains how to add a default stablecoin asset for a new EVM chain. - -## Overview - -When a server uses `price: "$0.10"` syntax (USD string pricing), x402 needs to know which stablecoin to use for that chain. The default asset is configured in `scheme.ts` within the `getDefaultAsset()` method. - -## Adding a New Chain - -To add support for a new EVM chain, add an entry to the `stablecoins` map in `getDefaultAsset()`: -```typescript -const stablecoins: Record = { - "eip155:8453": { - address: "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913", - name: "USD Coin", - version: "2", - decimals: 6, - }, // Base mainnet USDC (EIP-3009) - // Add your chain here: - "eip155:YOUR_CHAIN_ID": { - address: "0xYOUR_STABLECOIN_ADDRESS", - name: "Token Name", // Must match EIP-712 domain name - version: "1", // Must match EIP-712 domain version - decimals: 6, // Token decimals (typically 6 for USDC) - // assetTransferMethod: "permit2", // Uncomment if token doesn't support EIP-3009 - // supportsEip2612: true, // Set if permit2 token implements EIP-2612 permit() - }, -}; -``` - -### Fields - -| Field | Description | -|-------|-------------| -| `address` | Contract address of the stablecoin | -| `name` | EIP-712 domain name (must match the token's domain separator) | -| `version` | EIP-712 domain version (must match the token's domain separator) | -| `decimals` | Token decimal places (typically 6 for USDC) | -| `assetTransferMethod` | Transfer method override: `"permit2"` for tokens that don't support EIP-3009. Omit for EIP-3009 tokens (default behavior). | -| `supportsEip2612` | Set to `true` for permit2 tokens that implement EIP-2612 `permit()`. When true, `name` and `version` are included in `extra` so the client can sign a gasless EIP-2612 permit for Permit2 approval. When false/absent on a permit2 token, the client skips EIP-2612 and uses ERC-20 approval gas sponsoring instead. Ignored for EIP-3009 tokens (which always include `name`/`version`). | - -## Asset Transfer Methods - -x402 supports two methods for transferring assets: - -| Method | Use Case | Recommendation | -|--------|----------|----------------| -| **EIP-3009** | Tokens with native `transferWithAuthorization` (e.g., USDC) | **Recommended** (Simplest, truly gasless) | -| **Permit2** | Any ERC-20 token | **Universal Fallback** (Requires one-time approval) | - -### Default Behavior - -If no `assetTransferMethod` is specified, the client defaults to **EIP-3009**. This maintains backward compatibility with existing deployments. - -### Using Permit2 for Custom Tokens - -For tokens that don't support EIP-3009 and aren't in the default config, use the `registerMoneyParser` method to specify Permit2: - -```typescript -import { ExactEvmScheme } from "@x402/evm/exact/server"; - -const server = new ExactEvmScheme(); - -// Register a custom token that requires Permit2 -server.registerMoneyParser(async (amount, network) => { - if (network === "eip155:8453") { - return { - amount: (amount * 1e18).toString(), // Adjust decimals for your token - asset: "0xYourTokenAddress", - extra: { - assetTransferMethod: "permit2", // Required for non-EIP-3009 tokens - }, - }; - } - return null; // Fall through to next parser or default -}); -``` - -### Using Permit2 with Pre-Parsed Prices - -You can also specify Permit2 directly when using pre-parsed `AssetAmount`: - -```typescript -// In route configuration -{ - "GET /api/resource": { - accepts: { - payTo: "0x...", - scheme: "exact", - network: "eip155:8453", - price: { - amount: "1000000", - asset: "0xYourTokenAddress", - extra: { - assetTransferMethod: "permit2", - }, - }, - }, - }, -} -``` - -### Client Requirements for Permit2 - -When a server specifies `assetTransferMethod: "permit2"`, clients must: - -1. **One-time approval**: Approve the Permit2 contract to spend their tokens - ```typescript - // Using @x402/evm helpers - import { createPermit2ApprovalTx, PERMIT2_ADDRESS } from "@x402/evm"; - - const tx = createPermit2ApprovalTx(tokenAddress); - await walletClient.sendTransaction(tx); - ``` - -2. **Sign the payment**: The client SDK handles this automatically once approval exists - -If the client hasn't approved Permit2, they'll receive a `412 Precondition Failed` response with error code `PERMIT2_ALLOWANCE_REQUIRED`. - -## Asset Selection Policy - -The default asset is chosen **per chain** based on the following guidelines: - -1. **Chain-endorsed stablecoin**: If the chain has officially selected or endorsed a stablecoin (e.g., XDAI on Gnosis), that asset should be used. - -2. **No official stance**: If the chain team has not taken a public position on a preferred stablecoin, we encourage the team behind that chain to make the selection and submit a PR. - -3. **Community PRs welcome**: Chain teams and community members may submit PRs to add their chain's default asset, provided: - - The selection aligns with the chain's ecosystem preferences - - The EIP-712 domain parameters are correctly specified - -## Contributing - -To add a new chain's default asset: - -1. Obtain the correct EIP-712 domain `name` and `version` from the token contract -2. Check whether the token supports EIP-3009 (`transferWithAuthorization`): - - If yes: add the entry without `assetTransferMethod` (EIP-3009 is the default) - - If no: add `assetTransferMethod: "permit2"` to the entry so the client uses Permit2 automatically -3. For permit2 tokens, check whether the token supports EIP-2612 (`permit()`): - - If yes: add `supportsEip2612: true` so clients can use gasless EIP-2612 permits for Permit2 approval - - If no: omit `supportsEip2612` — clients will fall back to ERC-20 approval gas sponsoring -4. Add the entry to `getDefaultAsset()` in `scheme.ts` -5. Submit a PR with the chain name and rationale for the asset selection - -## Cross-SDK Checklist - -When adding a new chain's default asset, update all three SDKs to maintain parity: - -| SDK | File to edit | What to add | -|-----|-------------|-------------| -| **Go** | `go/mechanisms/evm/constants.go` | Entry in `NetworkConfigs` map | -| **TypeScript** | `typescript/packages/mechanisms/evm/src/exact/server/scheme.ts` | Entry in `stablecoins` map inside `getDefaultAsset()` | -| **Python** | `python/x402/mechanisms/evm/constants.py` | Entry in `NETWORK_CONFIGS` dict | - -All three must use: -- The same CAIP-2 network key (e.g., `eip155:YOUR_CHAIN_ID`) -- The same token contract address -- The same EIP-712 domain `name` and `version` -- The same `decimals` value -- The same asset transfer method (EIP-3009 default, or Permit2 if specified) - diff --git a/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts b/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts index a8fbfbf536..fd74977973 100644 --- a/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts +++ b/typescript/packages/mechanisms/evm/src/exact/server/scheme.ts @@ -6,6 +6,7 @@ import { SchemeNetworkServer, MoneyParser, } from "@x402/core/types"; +import { convertToTokenAmount, numberToDecimalString } from "@x402/core/utils"; import { getDefaultAsset, type ExactDefaultAssetInfo } from "../../shared/defaultAssets"; /** @@ -154,7 +155,7 @@ export class ExactEvmScheme implements SchemeNetworkServer { */ private defaultMoneyConversion(amount: number, network: Network): AssetAmount { const assetInfo: ExactDefaultAssetInfo = getDefaultAsset(network); - const tokenAmount = this.convertToTokenAmount(amount.toString(), assetInfo.decimals); + const tokenAmount = convertToTokenAmount(numberToDecimalString(amount), assetInfo.decimals); // EIP-3009 tokens always need name/version for their transferWithAuthorization domain. // Permit2 tokens only need them if the token supports EIP-2612 (for gasless permit signing). @@ -176,22 +177,4 @@ export class ExactEvmScheme implements SchemeNetworkServer { }, }; } - - /** - * Converts a decimal string amount to an integer token amount using the given decimals. - * - * @param decimalAmount - The amount as a decimal string (e.g. "1.5") - * @param decimals - The number of decimal places for the token - * @returns The token amount as an integer string in smallest units - */ - private convertToTokenAmount(decimalAmount: string, decimals: number): string { - const amount = parseFloat(decimalAmount); - if (isNaN(amount)) { - throw new Error(`Invalid amount: ${decimalAmount}`); - } - const [intPart, decPart = ""] = String(amount).split("."); - const paddedDec = decPart.padEnd(decimals, "0").slice(0, decimals); - const tokenAmount = (intPart + paddedDec).replace(/^0+/, "") || "0"; - return tokenAmount; - } } diff --git a/typescript/packages/mechanisms/evm/src/index.ts b/typescript/packages/mechanisms/evm/src/index.ts index 38277afe0c..da0b194cc2 100644 --- a/typescript/packages/mechanisms/evm/src/index.ts +++ b/typescript/packages/mechanisms/evm/src/index.ts @@ -36,6 +36,52 @@ export { UptoEvmScheme } from "./upto"; export type { UptoPermit2Payload, UptoPermit2Witness, UptoPermit2Authorization } from "./types"; export { isUptoPermit2Payload } from "./types"; +// Batch-settlement scheme client +export { BatchSettlementEvmScheme } from "./batch-settlement"; + +// Batch-settlement types +export type { + AuthorizerSigner, + ChannelConfig, + ChannelState, + BatchSettlementDepositPayload, + BatchSettlementVoucherPayload, + BatchSettlementRefundPayload, + BatchSettlementVoucherFields, + BatchSettlementErc3009Authorization, + BatchSettlementClaimPayload, + BatchSettlementEnrichedRefundPayload, + BatchSettlementVoucherClaim, + BatchSettlementPayload, + BatchSettlementSettlePayload, + BatchSettlementFacilitatorSettlePayload, + BatchSettlementPaymentRequirementsExtra, + BatchSettlementPaymentResponseExtra, +} from "./types"; +export { + isBatchSettlementDepositPayload, + isBatchSettlementVoucherPayload, + isBatchSettlementRefundPayload, + isBatchSettlementClaimPayload, + isBatchSettlementSettlePayload, + isBatchSettlementEnrichedRefundPayload, +} from "./types"; + +// Batch-settlement constants +export { + BATCH_SETTLEMENT_ADDRESS, + BATCH_SETTLEMENT_SCHEME, + ERC3009_DEPOSIT_COLLECTOR_ADDRESS, + BATCH_SETTLEMENT_DOMAIN, + voucherTypes, + refundTypes, + claimBatchTypes, +} from "./batch-settlement/constants"; + +// Default stablecoins (USD string pricing → token address per chain) +export { getDefaultAsset } from "./shared/defaultAssets"; +export type { DefaultAssetInfo, ExactDefaultAssetInfo } from "./shared/defaultAssets"; + // Constants export { PERMIT2_ADDRESS, @@ -48,3 +94,6 @@ export { x402ExactPermit2ProxyABI, x402UptoPermit2ProxyABI, } from "./constants"; + +// Default-asset registry (network → token metadata) +export { DEFAULT_STABLECOINS } from "./shared/defaultAssets"; diff --git a/typescript/packages/mechanisms/evm/src/shared/defaultAssets.ts b/typescript/packages/mechanisms/evm/src/shared/defaultAssets.ts index f62ecbd804..4b8db4cf10 100644 --- a/typescript/packages/mechanisms/evm/src/shared/defaultAssets.ts +++ b/typescript/packages/mechanisms/evm/src/shared/defaultAssets.ts @@ -97,6 +97,30 @@ export const DEFAULT_STABLECOINS: Record = { version: "2", decimals: 6, }, // Arbitrum Sepolia USDC + "eip155:31611": { + address: "0x118917a40FAF1CD7a13dB0Ef56C86De7973Ac503", + name: "Mezo USD", + version: "1", + decimals: 18, + assetTransferMethod: "permit2", + supportsEip2612: true, + }, // Mezo Testnet mUSD (no EIP-3009, supports EIP-2612) + "eip155:723487": { + address: "0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb", + name: "Stable Coin", + version: "1", + decimals: 6, + assetTransferMethod: "permit2", + supportsEip2612: true, + }, // Radius Network SBC (no EIP-3009, supports EIP-2612) + "eip155:72344": { + address: "0x33ad9e4BD16B69B5BFdED37D8B5D9fF9aba014Fb", + name: "Stable Coin", + version: "1", + decimals: 6, + assetTransferMethod: "permit2", + supportsEip2612: true, + }, // Radius Testnet SBC (no EIP-3009, supports EIP-2612) }; /** diff --git a/typescript/packages/mechanisms/evm/src/shared/extensions.ts b/typescript/packages/mechanisms/evm/src/shared/extensions.ts index 11baee6625..44a4518076 100644 --- a/typescript/packages/mechanisms/evm/src/shared/extensions.ts +++ b/typescript/packages/mechanisms/evm/src/shared/extensions.ts @@ -16,6 +16,7 @@ import { resolveExtensionRpcCapabilities, type ExactEvmSchemeOptions } from "./r * @param requirements - The payment requirements from the server * @param result - The payment payload result from the scheme * @param context - Optional context containing server extensions and metadata + * @param approvalAmount - Optional amount to approve instead of `requirements.amount` * @returns Extension data for EIP-2612 gas sponsoring, or undefined if not applicable */ export async function trySignEip2612PermitExtension( @@ -24,6 +25,7 @@ export async function trySignEip2612PermitExtension( requirements: PaymentRequirements, result: PaymentPayloadResult, context?: PaymentPayloadContext, + approvalAmount?: string, ): Promise | undefined> { const capabilities = resolveExtensionRpcCapabilities(requirements.network, signer, options); @@ -43,6 +45,7 @@ export async function trySignEip2612PermitExtension( const chainId = getEvmChainId(requirements.network); const tokenAddress = getAddress(requirements.asset) as `0x${string}`; + const requiredAllowance = approvalAmount ?? requirements.amount; try { const allowance = (await capabilities.readContract({ @@ -52,7 +55,7 @@ export async function trySignEip2612PermitExtension( args: [signer.address, PERMIT2_ADDRESS], })) as bigint; - if (allowance >= BigInt(requirements.amount)) { + if (allowance >= BigInt(requiredAllowance)) { return undefined; } } catch { @@ -75,7 +78,7 @@ export async function trySignEip2612PermitExtension( tokenVersion, chainId, deadline, - requirements.amount, + requiredAllowance, ); return { @@ -90,6 +93,7 @@ export async function trySignEip2612PermitExtension( * @param options - Optional RPC configuration for backfilling capabilities * @param requirements - The payment requirements from the server * @param context - Optional context containing server extensions and metadata + * @param approvalAmount - Optional amount to check for Permit2 allowance * @returns Extension data for ERC-20 approval gas sponsoring, or undefined if not applicable */ export async function trySignErc20ApprovalExtension( @@ -97,6 +101,7 @@ export async function trySignErc20ApprovalExtension( options: ExactEvmSchemeOptions | undefined, requirements: PaymentRequirements, context?: PaymentPayloadContext, + approvalAmount?: string, ): Promise | undefined> { const capabilities = resolveExtensionRpcCapabilities(requirements.network, signer, options); @@ -114,6 +119,7 @@ export async function trySignErc20ApprovalExtension( const chainId = getEvmChainId(requirements.network); const tokenAddress = getAddress(requirements.asset) as `0x${string}`; + const requiredAllowance = approvalAmount ?? requirements.amount; try { const allowance = (await capabilities.readContract({ @@ -123,7 +129,7 @@ export async function trySignErc20ApprovalExtension( args: [signer.address, PERMIT2_ADDRESS], })) as bigint; - if (allowance >= BigInt(requirements.amount)) { + if (allowance >= BigInt(requiredAllowance)) { return undefined; } } catch { diff --git a/typescript/packages/mechanisms/evm/src/signer.ts b/typescript/packages/mechanisms/evm/src/signer.ts index 66ec3de62d..4ec807bdd6 100644 --- a/typescript/packages/mechanisms/evm/src/signer.ts +++ b/typescript/packages/mechanisms/evm/src/signer.ts @@ -1,3 +1,5 @@ +import type { Log } from "viem"; + /** * ClientEvmSigner - Used by x402 clients to sign payment authorizations. * @@ -92,7 +94,10 @@ export type FacilitatorEvmSigner = { gas?: bigint; }): Promise<`0x${string}`>; sendTransaction(args: { to: `0x${string}`; data: `0x${string}` }): Promise<`0x${string}`>; - waitForTransactionReceipt(args: { hash: `0x${string}` }): Promise<{ status: string }>; + waitForTransactionReceipt(args: { hash: `0x${string}` }): Promise<{ + status: string; + logs?: readonly Log[]; + }>; getCode(args: { address: `0x${string}` }): Promise<`0x${string}` | undefined>; }; diff --git a/typescript/packages/mechanisms/evm/src/types.ts b/typescript/packages/mechanisms/evm/src/types.ts index 04633277ae..67bdc558b9 100644 --- a/typescript/packages/mechanisms/evm/src/types.ts +++ b/typescript/packages/mechanisms/evm/src/types.ts @@ -109,13 +109,44 @@ export type UptoPermit2Payload = { }; }; +// Batch-settlement EVM scheme payload types +export type { + AuthorizerSigner, + ChannelConfig, + ChannelState, + BatchSettlementDepositPayload, + BatchSettlementVoucherPayload, + BatchSettlementRefundPayload, + BatchSettlementVoucherFields, + BatchSettlementErc3009Authorization, + BatchSettlementPermit2Authorization, + BatchSettlementDepositAuthorization, + BatchSettlementAssetTransferMethod, + BatchSettlementClaimPayload, + BatchSettlementEnrichedRefundPayload, + BatchSettlementVoucherClaim, + BatchSettlementPayload, + BatchSettlementSettlePayload, + BatchSettlementFacilitatorSettlePayload, + BatchSettlementPaymentRequirementsExtra, + BatchSettlementPaymentResponseExtra, +} from "./batch-settlement/types"; +export { + isBatchSettlementDepositPayload, + isBatchSettlementVoucherPayload, + isBatchSettlementRefundPayload, + isBatchSettlementClaimPayload, + isBatchSettlementSettlePayload, + isBatchSettlementEnrichedRefundPayload, +} from "./batch-settlement/types"; + /** * Type guard to check if a payload is an upto Permit2 payload. * Validates structural presence of all required fields: signature, permit2Authorization * (with from, permitted, spender, nonce, deadline), and a witness containing facilitator. * - * @param payload - The payload to check - * @returns True if the payload is an upto Permit2 payload, false otherwise + * @param payload - The payload to check. + * @returns True if the payload is an upto Permit2 payload, false otherwise. */ export function isUptoPermit2Payload( payload: Record, diff --git a/typescript/packages/mechanisms/evm/src/upto/README.md b/typescript/packages/mechanisms/evm/src/upto/README.md new file mode 100644 index 0000000000..13e4817116 --- /dev/null +++ b/typescript/packages/mechanisms/evm/src/upto/README.md @@ -0,0 +1,190 @@ +# Upto EVM Scheme (`@x402/evm/upto`) + +The **upto** scheme enables usage-based billing on EVM networks. The client authorizes a **maximum** payment amount, but the server settles **only what was actually used**. This is ideal for variable-cost endpoints like LLM token generation, compute time, or bandwidth metering. + +Uses **Permit2** exclusively (no EIP-3009 path). The on-chain proxy contract accepts a variable `amount` parameter at settlement time, so the facilitator can settle any amount up to the authorized maximum. + +## Import Paths + +| Role | Import | +|------|--------| +| Client | `@x402/evm/upto/client` | +| Server | `@x402/evm/upto/server` | +| Facilitator | `@x402/evm/upto/facilitator` | + +## Client Usage + +Register `UptoEvmScheme` with an `x402Client` to handle payments for services that use the `upto` scheme. From the buyer's perspective, usage is transparent — the SDK signs a max-authorization and the server charges only what was consumed. + +```typescript +import { x402Client } from "@x402/core/client"; +import { ExactEvmScheme } from "@x402/evm/exact/client"; +import { UptoEvmScheme } from "@x402/evm/upto/client"; +import { privateKeyToAccount } from "viem/accounts"; + +const signer = privateKeyToAccount(process.env.EVM_PRIVATE_KEY as `0x${string}`); + +const client = new x402Client(); +client.register("eip155:*", new ExactEvmScheme(signer)); // fixed-price services +client.register("eip155:*", new UptoEvmScheme(signer)); // usage-based services +``` + +### Key Difference from Exact + +The upto client requires `paymentRequirements.extra.facilitatorAddress` (provided automatically by the facilitator via `getExtra()`). This address is embedded in the Permit2 witness so only the designated facilitator can settle the payment. + +## Server Usage + +Register `UptoEvmScheme` with an `x402ResourceServer` and use `setSettlementOverrides` in your handler to specify the actual charge. + +```typescript +import { paymentMiddleware, setSettlementOverrides, x402ResourceServer } from "@x402/express"; +import { UptoEvmScheme } from "@x402/evm/upto/server"; + +const server = new x402ResourceServer(facilitatorClient) + .register("eip155:84532", new UptoEvmScheme()); + +// In your route config, `price` is the maximum authorized amount: +const routes = { + "GET /api/generate": { + accepts: { + scheme: "upto", + price: "$0.10", // client authorizes up to 10 cents + network: "eip155:84532", + payTo: "0xYourAddress", + }, + description: "AI text generation — billed by token usage", + }, +}; + +// In your handler, settle the actual usage: +app.get("/api/generate", (req, res) => { + const actualUsage = computeActualCost(); // your billing logic + setSettlementOverrides(res, { amount: String(actualUsage) }); + res.json({ result: "..." }); +}); +``` + +### Settlement Override Formats + +The `amount` in `setSettlementOverrides` supports three formats: + +| Format | Example | Description | +|--------|---------|-------------| +| Raw atomic units | `"50000"` | Settles exactly 50,000 atomic units | +| Percentage | `"50%"` | Settles 50% of the authorized maximum | +| Dollar price | `"$0.05"` | Converts to atomic units (when route used `$` pricing) | + +Setting `amount` to `"0"` skips on-chain settlement entirely — the client is not charged. + +## Facilitator Usage + +For custom facilitator implementations: + +```typescript +import { UptoEvmScheme } from "@x402/evm/upto/facilitator"; + +const scheme = new UptoEvmScheme({ signers: [wallet] }); +``` + +The upto facilitator's `getExtra()` returns a `facilitatorAddress` that the client embeds in the signed Permit2 witness. Only this address can call `settle()` on the upto proxy contract. + +## Supported Networks + +Works on any EIP-155 compatible network that has the Permit2 and x402 upto proxy contracts deployed: + +| Network | CAIP-2 ID | +|---------|-----------| +| Base Mainnet | `eip155:8453` | +| Base Sepolia | `eip155:84532` | + +## How It Works + +1. Server advertises `scheme: "upto"` with a max `price` +2. Client signs a Permit2 authorization for the max amount, with a witness containing the `facilitator` address +3. Server performs work, calculates actual cost +4. Server calls `setSettlementOverrides` with the actual amount +5. Facilitator settles on-chain for the actual amount (≤ max) +6. If actual amount is `0`, no on-chain transaction occurs + +## Gas Sponsoring Extensions + +Since the upto scheme uses Permit2 exclusively, it fully supports both gas sponsoring extensions. These let the **facilitator** pay for the client's Permit2 approval transaction, removing all gas costs from the client. The client SDK detects advertised extensions automatically. + +### EIP-2612 Gas Sponsoring + +The preferred path. If the payment token supports [EIP-2612](https://eips.ethereum.org/EIPS/eip-2612), the client signs an off-chain permit and the facilitator bundles approval + settlement in a single `settleWithPermit` call — zero gas for the client. + +**Server:** Declare the extension in your route config: + +```typescript +import { declareEip2612GasSponsoringExtension } from "@x402/extensions"; + +{ + "GET /api/generate": { + accepts: { + scheme: "upto", + price: "$0.10", + network: "eip155:84532", + payTo: "0xYourAddress", + }, + extensions: { + ...declareEip2612GasSponsoringExtension(), + }, + }, +} +``` + +**Client:** No additional setup. `UptoEvmScheme` automatically checks for the extension and signs the permit when applicable. + +**Facilitator:** Register the extension: + +```typescript +import { EIP2612_GAS_SPONSORING } from "@x402/extensions"; + +facilitator.registerExtension(EIP2612_GAS_SPONSORING); +``` + +### ERC-20 Approval Gas Sponsoring + +Fallback for tokens that do not support EIP-2612. The client signs a raw `approve(Permit2, MaxUint256)` transaction off-chain; the facilitator broadcasts it before settling. + +**Server:** Declare the extension (omit `name`/`version` from token config to signal non-EIP-2612 tokens): + +```typescript +import { declareErc20ApprovalGasSponsoringExtension } from "@x402/extensions"; + +{ + "GET /api/generate": { + accepts: { /* ... */ }, + extensions: { + ...declareErc20ApprovalGasSponsoringExtension(), + }, + }, +} +``` + +**Client:** The signer must support transaction signing (`signTransaction`, `getTransactionCount`). `UptoEvmScheme` falls back to this when EIP-2612 is unavailable. + +**Facilitator:** Register with a signer that can broadcast transactions: + +```typescript +import { createErc20ApprovalGasSponsoringExtension } from "@x402/extensions"; + +facilitator.registerExtension(createErc20ApprovalGasSponsoringExtension(erc20ApprovalSigner)); +``` + +### Extension Priority + +When both extensions are advertised, EIP-2612 takes priority. The client tries EIP-2612 first; if the token lacks `name`/`version` in `extra`, it falls back to ERC-20 approval gas sponsoring. + +## Examples + +- [Express upto server](https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers/upto) + +## See Also + +- [Exact EVM Scheme](../exact/README.md) — fixed-price payments +- [x402 Docs: Payment Schemes](https://docs.x402.org/getting-started/quickstart-for-sellers#payment-schemes-exact-vs-upto) +- [x402 Docs: Quickstart for Sellers](https://docs.x402.org/getting-started/quickstart-for-sellers) +- [x402 Docs: Quickstart for Buyers](https://docs.x402.org/getting-started/quickstart-for-buyers) diff --git a/typescript/packages/mechanisms/evm/src/upto/server/scheme.ts b/typescript/packages/mechanisms/evm/src/upto/server/scheme.ts index 7c3549c85e..3632561a2c 100644 --- a/typescript/packages/mechanisms/evm/src/upto/server/scheme.ts +++ b/typescript/packages/mechanisms/evm/src/upto/server/scheme.ts @@ -6,6 +6,7 @@ import { SchemeNetworkServer, MoneyParser, } from "@x402/core/types"; +import { convertToTokenAmount, numberToDecimalString } from "@x402/core/utils"; import { getAddress } from "viem"; import { getDefaultAsset } from "../../shared/defaultAssets"; @@ -140,7 +141,7 @@ export class UptoEvmScheme implements SchemeNetworkServer { */ private defaultMoneyConversion(amount: number, network: Network): AssetAmount { const assetInfo = getDefaultAsset(network); - const tokenAmount = this.convertToTokenAmount(amount.toString(), assetInfo.decimals); + const tokenAmount = convertToTokenAmount(numberToDecimalString(amount), assetInfo.decimals); return { amount: tokenAmount, @@ -152,22 +153,4 @@ export class UptoEvmScheme implements SchemeNetworkServer { }, }; } - - /** - * Converts a decimal string amount to an integer token amount using the given decimals. - * - * @param decimalAmount - The amount as a decimal string (e.g. "1.5") - * @param decimals - The number of decimal places for the token - * @returns The token amount as an integer string in smallest units - */ - private convertToTokenAmount(decimalAmount: string, decimals: number): string { - const amount = parseFloat(decimalAmount); - if (isNaN(amount)) { - throw new Error(`Invalid amount: ${decimalAmount}`); - } - const [intPart, decPart = ""] = String(amount).split("."); - const paddedDec = decPart.padEnd(decimals, "0").slice(0, decimals); - const tokenAmount = (intPart + paddedDec).replace(/^0+/, "") || "0"; - return tokenAmount; - } } diff --git a/typescript/packages/mechanisms/evm/test/integrations/batch-settlement-evm.test.ts b/typescript/packages/mechanisms/evm/test/integrations/batch-settlement-evm.test.ts new file mode 100644 index 0000000000..82edccb2fc --- /dev/null +++ b/typescript/packages/mechanisms/evm/test/integrations/batch-settlement-evm.test.ts @@ -0,0 +1,438 @@ +import { randomBytes } from "node:crypto"; +import { beforeEach, describe, expect, it } from "vitest"; +import { x402Client, x402HTTPClient } from "@x402/core/client"; +import { x402Facilitator } from "@x402/core/facilitator"; +import { + HTTPAdapter, + HTTPResponseInstructions, + x402HTTPResourceServer, + x402ResourceServer, + FacilitatorClient, +} from "@x402/core/server"; +import { + Network, + PaymentPayload, + PaymentRequirements, + VerifyResponse, + SettleResponse, + SupportedResponse, +} from "@x402/core/types"; +import { toClientEvmSigner, toFacilitatorEvmSigner } from "../../src"; +import { BatchSettlementEvmScheme as BatchSettlementEvmClient } from "../../src/batch-settlement/client/scheme"; +import { processSettleResponse } from "../../src/batch-settlement/client/channel"; +import { InMemoryClientChannelStorage } from "../../src/batch-settlement/client/storage"; +import { BatchSettlementEvmScheme as BatchSettlementEvmServer } from "../../src/batch-settlement/server/scheme"; +import { BatchSettlementEvmScheme as BatchSettlementEvmFacilitator } from "../../src/batch-settlement/facilitator/scheme"; +import type { AuthorizerSigner } from "../../src/batch-settlement/types"; +import { privateKeyToAccount } from "viem/accounts"; +import { createWalletClient, createPublicClient, http, getAddress } from "viem"; +import { baseSepolia } from "viem/chains"; +import { batchSettlementABI } from "../../src/batch-settlement/abi"; +import { BATCH_SETTLEMENT_ADDRESS } from "../../src/batch-settlement/constants"; + +const CLIENT_PRIVATE_KEY = process.env.CLIENT_PRIVATE_KEY as `0x${string}` | undefined; +const FACILITATOR_PRIVATE_KEY = process.env.FACILITATOR_PRIVATE_KEY as `0x${string}` | undefined; +const RECEIVER_AUTHORIZER_PRIVATE_KEY = process.env.RECEIVER_AUTHORIZER_PRIVATE_KEY as + | `0x${string}` + | undefined; + +const HAS_KEYS = Boolean(CLIENT_PRIVATE_KEY && FACILITATOR_PRIVATE_KEY); +const describeOnChain = HAS_KEYS ? describe : describe.skip; + +if (!HAS_KEYS) { + console.warn( + "[batch-settlement-evm.test.ts] Skipping on-chain tests: CLIENT_PRIVATE_KEY and FACILITATOR_PRIVATE_KEY env vars are required.", + ); +} + +const NETWORK: Network = "eip155:84532"; +const ASSET_USDC_BASE_SEPOLIA = "0x036CbD53842c5426634e7929541eC2318f3dCF7e"; + +/** + * Waits until an RPC read sees non-zero channel balance (some providers lag after receipt). + * + * @param publicClient - Viem public client for the chain. + * @param channelId - Channel id to poll. + */ +async function waitForChannelBalanceOnChain( + publicClient: ReturnType, + channelId: `0x${string}`, +): Promise { + const timeoutMs = 20000; + const intervalMs = 250; + const start = Date.now(); + while (Date.now() - start < timeoutMs) { + const [balance] = (await publicClient.readContract({ + address: getAddress(BATCH_SETTLEMENT_ADDRESS), + abi: batchSettlementABI, + functionName: "channels", + args: [channelId], + })) as [bigint, bigint]; + if (balance > 0n) return; + await new Promise(resolve => setTimeout(resolve, intervalMs)); + } + throw new Error(`Timed out waiting for channel ${channelId} balance > 0`); +} + +/** + * Wraps an x402Facilitator instance for use as a FacilitatorClient. + */ +class EvmFacilitatorClient implements FacilitatorClient { + /** + * @param facilitator - The x402 facilitator to wrap. + */ + constructor(private readonly facilitator: x402Facilitator) {} + + /** + * @param paymentPayload - Payment payload to verify. + * @param paymentRequirements - Payment requirements to verify against. + * @returns Verification response from the wrapped facilitator. + */ + verify( + paymentPayload: PaymentPayload, + paymentRequirements: PaymentRequirements, + ): Promise { + return this.facilitator.verify(paymentPayload, paymentRequirements); + } + + /** + * @param paymentPayload - Payment payload to settle. + * @param paymentRequirements - Payment requirements for settlement. + * @returns Settlement response from the wrapped facilitator. + */ + settle( + paymentPayload: PaymentPayload, + paymentRequirements: PaymentRequirements, + ): Promise { + return this.facilitator.settle(paymentPayload, paymentRequirements); + } + + /** + * @returns Supported payment kinds reported by the wrapped facilitator. + */ + getSupported(): Promise { + return Promise.resolve(this.facilitator.getSupported()); + } +} + +/** + * Builds payment requirements suitable for the batched scheme on Base Sepolia. + * + * @param payTo - Receiver address. + * @param amount - Amount in smallest token units (USDC has 6 decimals). + * @param receiverAuthorizer - Receiver-authorizer address (must be non-zero on-chain). + * @returns Configured {@link PaymentRequirements}. + */ +function buildBatchSettlementRequirements( + payTo: `0x${string}`, + amount: string, + receiverAuthorizer: `0x${string}`, +): PaymentRequirements { + return { + scheme: "batch-settlement", + network: NETWORK, + asset: ASSET_USDC_BASE_SEPOLIA, + amount, + payTo, + maxTimeoutSeconds: 3600, + extra: { + name: "USDC", + version: "2", + assetTransferMethod: "eip3009", + receiverAuthorizer, + }, + }; +} + +/** + * Constructs the wired client + server + facilitator pipeline for Base Sepolia + * batch-settlement integration tests. + * + * @returns The configured client/server pair plus the receiver address. + */ +function buildPipeline(): { + client: x402Client; + server: x402ResourceServer; + receiverAddress: `0x${string}`; + clientAddress: `0x${string}`; + authorizerSigner: AuthorizerSigner; + publicClient: ReturnType; + batchSettlementClient: BatchSettlementEvmClient; + batchSettlementStorage: InMemoryClientChannelStorage; +} { + const clientAccount = privateKeyToAccount(CLIENT_PRIVATE_KEY!); + const facilitatorAccount = privateKeyToAccount(FACILITATOR_PRIVATE_KEY!); + const authorizerAccount = privateKeyToAccount( + RECEIVER_AUTHORIZER_PRIVATE_KEY ?? FACILITATOR_PRIVATE_KEY!, + ); + + const publicClient = createPublicClient({ chain: baseSepolia, transport: http() }); + const facilitatorWalletClient = createWalletClient({ + account: facilitatorAccount, + chain: baseSepolia, + transport: http(), + }); + + const facilitatorSigner = toFacilitatorEvmSigner({ + address: facilitatorAccount.address, + readContract: args => publicClient.readContract({ ...args, args: args.args || [] } as never), + verifyTypedData: args => publicClient.verifyTypedData(args as never), + writeContract: args => + facilitatorWalletClient.writeContract({ ...args, args: args.args || [] } as never), + sendTransaction: args => facilitatorWalletClient.sendTransaction(args), + waitForTransactionReceipt: args => publicClient.waitForTransactionReceipt(args), + getCode: args => publicClient.getCode(args), + }); + + const authorizerSigner: AuthorizerSigner = { + address: authorizerAccount.address, + signTypedData: msg => + authorizerAccount.signTypedData({ + domain: msg.domain, + types: msg.types, + primaryType: msg.primaryType, + message: msg.message, + } as Parameters[0]), + }; + + const facilitator = new x402Facilitator().register( + NETWORK, + new BatchSettlementEvmFacilitator(facilitatorSigner, authorizerSigner), + ); + const facilitatorClient = new EvmFacilitatorClient(facilitator); + + const clientSigner = toClientEvmSigner(clientAccount, publicClient); + const channelSalt = `0x${randomBytes(32).toString("hex")}` as `0x${string}`; + const batchSettlementStorage = new InMemoryClientChannelStorage(); + const batchSettlementClient = new BatchSettlementEvmClient(clientSigner, { + depositPolicy: { depositMultiplier: 3 }, + salt: channelSalt, + storage: batchSettlementStorage, + }); + const client = new x402Client().register(NETWORK, batchSettlementClient); + + const server = new x402ResourceServer(facilitatorClient); + server.register( + NETWORK, + new BatchSettlementEvmServer(facilitatorAccount.address, { + receiverAuthorizerSigner: authorizerSigner, + }), + ); + + return { + client, + server, + receiverAddress: facilitatorAccount.address, + clientAddress: clientAccount.address, + authorizerSigner, + publicClient, + batchSettlementClient, + batchSettlementStorage, + }; +} + +describe("Batch-Settlement EVM Integration Tests", () => { + describeOnChain("x402Client / x402ResourceServer / x402Facilitator - direct API", () => { + let client: x402Client; + let server: x402ResourceServer; + let receiverAddress: `0x${string}`; + let clientAddress: `0x${string}`; + let receiverAuthorizer: `0x${string}`; + let batchSettlementStorage: InMemoryClientChannelStorage; + let publicClient: ReturnType; + + beforeEach(async () => { + const pipeline = buildPipeline(); + client = pipeline.client; + server = pipeline.server; + receiverAddress = pipeline.receiverAddress; + clientAddress = pipeline.clientAddress; + receiverAuthorizer = pipeline.authorizerSigner.address; + batchSettlementStorage = pipeline.batchSettlementStorage; + publicClient = pipeline.publicClient; + await server.initialize(); + }); + + it( + "verifies and settles a deposit-with-voucher payment, then a follow-up voucher payment", + { timeout: 60000 }, + async () => { + const accepts = [ + buildBatchSettlementRequirements(receiverAddress, "1000", receiverAuthorizer), + ]; + const resource = { + url: "https://example.com/api", + description: "Batched test resource", + mimeType: "application/json", + }; + + const paymentRequired = await server.createPaymentRequiredResponse(accepts, resource); + const firstPayload = await client.createPaymentPayload(paymentRequired); + + expect(firstPayload.x402Version).toBe(2); + expect(firstPayload.accepted.scheme).toBe("batch-settlement"); + const firstRaw = firstPayload.payload as Record; + expect(firstRaw.type).toBe("deposit"); + + const accepted = server.findMatchingRequirements(accepts, firstPayload); + expect(accepted).toBeDefined(); + + const verifyResponse = await server.verifyPayment(firstPayload, accepted!); + expect(verifyResponse.isValid).toBe(true); + expect(verifyResponse.payer?.toLowerCase()).toBe(clientAddress.toLowerCase()); + + const settleResponse = await server.settlePayment(firstPayload, accepted!); + expect(settleResponse.success, JSON.stringify(settleResponse)).toBe(true); + expect(settleResponse.network).toBe(NETWORK); + expect(settleResponse.transaction).toBeDefined(); + expect(settleResponse.payer?.toLowerCase()).toBe(clientAddress.toLowerCase()); + + const depositChannelId = (firstPayload.payload as { voucher: { channelId: `0x${string}` } }) + .voucher.channelId; + await waitForChannelBalanceOnChain(publicClient, depositChannelId); + + await processSettleResponse(batchSettlementStorage, settleResponse); + + const followupRequired = await server.createPaymentRequiredResponse(accepts, resource); + const secondPayload = await client.createPaymentPayload(followupRequired); + const secondRaw = secondPayload.payload as Record; + expect(secondRaw.type).toBe("voucher"); + + const accepted2 = server.findMatchingRequirements(accepts, secondPayload); + expect(accepted2).toBeDefined(); + + const verify2 = await server.verifyPayment(secondPayload, accepted2!); + expect(verify2.isValid).toBe(true); + + const settle2 = await server.settlePayment(secondPayload, accepted2!); + expect(settle2.success, JSON.stringify(settle2)).toBe(true); + expect(settle2.payer?.toLowerCase()).toBe(clientAddress.toLowerCase()); + }, + ); + }); + + describeOnChain("x402HTTPClient / x402HTTPResourceServer / x402Facilitator - HTTP API", () => { + let httpClient: x402HTTPClient; + let httpServer: x402HTTPResourceServer; + let receiverAddress: `0x${string}`; + let clientAddress: `0x${string}`; + + const routes = { + "/api/protected": { + accepts: { + scheme: "batch-settlement", + payTo: "0x0000000000000000000000000000000000000000" as `0x${string}`, + price: "$0.001", + network: NETWORK, + }, + description: "Batched protected API", + mimeType: "application/json", + }, + }; + + const adapter: HTTPAdapter = { + getHeader: () => undefined, + getMethod: () => "GET", + getPath: () => "/api/protected", + getUrl: () => "https://example.com/api/protected", + getAcceptHeader: () => "application/json", + getUserAgent: () => "TestClient/1.0", + }; + + beforeEach(async () => { + const pipeline = buildPipeline(); + receiverAddress = pipeline.receiverAddress; + clientAddress = pipeline.clientAddress; + + routes["/api/protected"].accepts.payTo = receiverAddress; + + const resourceServer = new x402ResourceServer( + new EvmFacilitatorClient( + new x402Facilitator().register( + NETWORK, + new BatchSettlementEvmFacilitator( + toFacilitatorEvmSigner({ + address: privateKeyToAccount(FACILITATOR_PRIVATE_KEY!).address, + readContract: args => + pipeline.publicClient.readContract({ + ...args, + args: args.args || [], + } as never), + verifyTypedData: args => pipeline.publicClient.verifyTypedData(args as never), + writeContract: args => + createWalletClient({ + account: privateKeyToAccount(FACILITATOR_PRIVATE_KEY!), + chain: baseSepolia, + transport: http(), + }).writeContract({ ...args, args: args.args || [] } as never), + sendTransaction: args => + createWalletClient({ + account: privateKeyToAccount(FACILITATOR_PRIVATE_KEY!), + chain: baseSepolia, + transport: http(), + }).sendTransaction(args), + waitForTransactionReceipt: args => + pipeline.publicClient.waitForTransactionReceipt(args), + getCode: args => pipeline.publicClient.getCode(args), + }), + pipeline.authorizerSigner, + ), + ), + ), + ); + resourceServer.register( + NETWORK, + new BatchSettlementEvmServer(receiverAddress, { + receiverAuthorizerSigner: pipeline.authorizerSigner, + }), + ); + await resourceServer.initialize(); + + httpServer = new x402HTTPResourceServer(resourceServer, routes); + httpClient = new x402HTTPClient(pipeline.client) as x402HTTPClient; + }); + + it( + "negotiates a batched payment via HTTP middleware end-to-end", + { timeout: 60000 }, + async () => { + const context = { adapter, path: "/api/protected", method: "GET" }; + + const initial = (await httpServer.processHTTPRequest(context))!; + expect(initial.type).toBe("payment-error"); + const response402 = ( + initial as { type: "payment-error"; response: HTTPResponseInstructions } + ).response; + expect(response402.status).toBe(402); + expect(response402.headers["PAYMENT-REQUIRED"]).toBeDefined(); + + const paymentRequired = httpClient.getPaymentRequiredResponse( + name => response402.headers[name], + response402.body, + ); + const paymentPayload = await httpClient.createPaymentPayload(paymentRequired); + expect(paymentPayload.accepted.scheme).toBe("batch-settlement"); + + const requestHeaders = await httpClient.encodePaymentSignatureHeader(paymentPayload); + adapter.getHeader = (name: string) => + name === "PAYMENT-SIGNATURE" ? requestHeaders["PAYMENT-SIGNATURE"] : undefined; + + const verified = await httpServer.processHTTPRequest(context); + expect(verified.type).toBe("payment-verified"); + + const { paymentPayload: verifiedPayload, paymentRequirements: verifiedReqs } = verified as { + type: "payment-verified"; + paymentPayload: PaymentPayload; + paymentRequirements: PaymentRequirements; + }; + + const settlement = await httpServer.processSettlement(verifiedPayload, verifiedReqs, 200); + expect(settlement.success).toBe(true); + if (settlement.success) { + expect(settlement.headers["PAYMENT-RESPONSE"]).toBeDefined(); + } + expect(clientAddress).toMatch(/^0x[0-9a-fA-F]{40}$/); + }, + ); + }); +}); diff --git a/typescript/packages/mechanisms/evm/test/unit/batch-settlement/channelManager.test.ts b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/channelManager.test.ts new file mode 100644 index 0000000000..ee7df9dfe4 --- /dev/null +++ b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/channelManager.test.ts @@ -0,0 +1,792 @@ +import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; +import type { MockedFunction } from "vitest"; +import { privateKeyToAccount } from "viem/accounts"; +import { + BatchSettlementChannelManager, + type ClaimResult, + type SettleResult, + type RefundResult, +} from "../../../src/batch-settlement/server/channelManager"; +import { BatchSettlementEvmScheme } from "../../../src/batch-settlement/server/scheme"; +import { InMemoryChannelStorage, type Channel } from "../../../src/batch-settlement/server/storage"; +import { computeChannelId as computeChannelIdForNetwork } from "../../../src/batch-settlement/utils"; +import type { ChannelConfig, AuthorizerSigner } from "../../../src/batch-settlement/types"; +import type { FacilitatorClient } from "@x402/core/server"; +import type { + PaymentPayload, + PaymentRequirements, + SettleResponse, + VerifyResponse, + SupportedResponse, +} from "@x402/core/types"; + +const RECEIVER = "0x9876543210987654321098765432109876543210" as `0x${string}`; +const PAYER = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" as `0x${string}`; +const TOKEN = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" as `0x${string}`; +const ZERO = "0x0000000000000000000000000000000000000000" as `0x${string}`; +const NETWORK = "eip155:84532"; + +function computeChannelId(config: ChannelConfig): `0x${string}` { + return computeChannelIdForNetwork(config, NETWORK); +} + +function buildAuthorizerSigner(): AuthorizerSigner { + const account = privateKeyToAccount( + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", + ); + return { + address: account.address, + signTypedData: msg => + account.signTypedData({ + domain: msg.domain, + types: msg.types, + primaryType: msg.primaryType, + message: msg.message, + } as Parameters[0]), + }; +} + +function buildChannelConfig(saltSuffix = "00"): ChannelConfig { + const salt = `0x${"00".repeat(31)}${saltSuffix.padStart(2, "0")}` as `0x${string}`; + return { + payer: PAYER, + payerAuthorizer: ZERO, + receiver: RECEIVER, + receiverAuthorizer: ZERO, + token: TOKEN, + withdrawDelay: 900, + salt, + }; +} + +function buildSession(overrides: Partial = {}): Channel { + const config = overrides.channelConfig ?? buildChannelConfig(); + const channelId = overrides.channelId ?? computeChannelId(config); + return { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0xdeadbeef", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: Date.now(), + ...overrides, + }; +} + +async function storeChannel(storage: InMemoryChannelStorage, channel: Channel): Promise { + await storage.updateChannel(channel.channelId, () => channel); +} + +type FakeFacilitator = FacilitatorClient & { + verify: MockedFunction; + settle: MockedFunction; + getSupported: MockedFunction; +}; + +function buildFacilitator( + settleImpl: ( + payload: PaymentPayload, + reqs: PaymentRequirements, + ) => Promise = async (_, reqs) => ({ + success: true, + transaction: "0xtx", + network: reqs.network, + }), +): FakeFacilitator { + return { + verify: vi.fn( + async () => + ({ + isValid: true, + }) as VerifyResponse, + ), + settle: vi.fn(settleImpl), + getSupported: vi.fn( + async () => + ({ + kinds: [], + }) as unknown as SupportedResponse, + ), + }; +} + +function buildManager(opts?: { + authorizerSigner?: AuthorizerSigner; + facilitator?: FakeFacilitator; + storage?: InMemoryChannelStorage; +}): { + manager: BatchSettlementChannelManager; + scheme: BatchSettlementEvmScheme; + facilitator: FakeFacilitator; + storage: InMemoryChannelStorage; +} { + const storage = opts?.storage ?? new InMemoryChannelStorage(); + const scheme = new BatchSettlementEvmScheme(RECEIVER, { + storage, + receiverAuthorizerSigner: opts?.authorizerSigner, + }); + const facilitator = opts?.facilitator ?? buildFacilitator(); + const manager = new BatchSettlementChannelManager({ + scheme, + facilitator, + receiver: RECEIVER, + token: TOKEN, + network: NETWORK, + }); + return { manager, scheme, facilitator, storage }; +} + +describe("BatchSettlementChannelManager — claim()", () => { + it("returns no results when there are no claimable vouchers", async () => { + const { manager, facilitator } = buildManager(); + const results = await manager.claim(); + expect(results).toEqual([]); + expect(facilitator.settle).not.toHaveBeenCalled(); + }); + + it("submits a single claim batch when claimable vouchers exist", async () => { + const { manager, storage, facilitator } = buildManager(); + const session = buildSession({ chargedCumulativeAmount: "5000", totalClaimed: "0" }); + await storeChannel(storage, session); + + const results = await manager.claim(); + expect(results).toHaveLength(1); + expect(results[0].vouchers).toBe(1); + expect(results[0].transaction).toBe("0xtx"); + + expect(facilitator.settle).toHaveBeenCalledTimes(1); + const [paymentPayload] = facilitator.settle.mock.calls[0]; + const payload = paymentPayload.payload as Record; + expect(payload.type).toBe("claim"); + expect(payload.claims).toHaveLength(1); + }); + + it("splits claims across multiple batches respecting maxClaimsPerBatch", async () => { + const { manager, storage, facilitator } = buildManager(); + for (let i = 0; i < 5; i++) { + const config = buildChannelConfig(i.toString(16)); + await storeChannel( + storage, + buildSession({ + channelConfig: config, + channelId: computeChannelId(config), + chargedCumulativeAmount: String(1000 * (i + 1)), + totalClaimed: "0", + }), + ); + } + + const results = await manager.claim({ maxClaimsPerBatch: 2 }); + expect(results).toHaveLength(3); + expect(results.map(r => r.vouchers)).toEqual([2, 2, 1]); + expect(facilitator.settle).toHaveBeenCalledTimes(3); + }); + + it("defaults to 100 vouchers per claim batch", async () => { + const { manager, storage, facilitator } = buildManager(); + for (let i = 0; i < 101; i++) { + const config = buildChannelConfig(i.toString(16)); + await storeChannel( + storage, + buildSession({ + channelConfig: config, + channelId: computeChannelId(config), + chargedCumulativeAmount: String(1000 * (i + 1)), + totalClaimed: "0", + }), + ); + } + + const results = await manager.claim(); + expect(results).toHaveLength(2); + expect(results.map(r => r.vouchers)).toEqual([100, 1]); + expect(facilitator.settle).toHaveBeenCalledTimes(2); + }); + + it("skips sessions that are not idle long enough when idleSecs is set", async () => { + const { manager, storage, facilitator } = buildManager(); + const fresh = buildSession({ + chargedCumulativeAmount: "5000", + lastRequestTimestamp: Date.now(), + }); + await storeChannel(storage, fresh); + + const results = await manager.claim({ idleSecs: 60 }); + expect(results).toEqual([]); + expect(facilitator.settle).not.toHaveBeenCalled(); + }); + + it("claims only channels selected by the claim selector", async () => { + const { manager, storage, facilitator } = buildManager(); + const selectedConfig = buildChannelConfig("01"); + const skippedConfig = buildChannelConfig("02"); + const selected = buildSession({ + channelConfig: selectedConfig, + channelId: computeChannelId(selectedConfig), + chargedCumulativeAmount: "5000", + }); + const skipped = buildSession({ + channelConfig: skippedConfig, + channelId: computeChannelId(skippedConfig), + chargedCumulativeAmount: "7000", + }); + await storeChannel(storage, selected); + await storeChannel(storage, skipped); + + const results = await manager.claim({ + selectClaimChannels: channels => + channels.filter(channel => channel.channelId === selected.channelId), + }); + + expect(results).toHaveLength(1); + expect(results[0].vouchers).toBe(1); + expect(facilitator.settle).toHaveBeenCalledTimes(1); + expect((await storage.get(selected.channelId))?.totalClaimed).toBe("5000"); + expect((await storage.get(skipped.channelId))?.totalClaimed).toBe("0"); + }); + + it("updates session.totalClaimed after a successful claim", async () => { + const { manager, storage } = buildManager(); + const session = buildSession({ chargedCumulativeAmount: "5000", totalClaimed: "0" }); + await storeChannel(storage, session); + + await manager.claim(); + + const updated = await storage.get(session.channelId); + expect(updated?.totalClaimed).toBe("5000"); + }); + + it("includes a claim authorizer signature when an authorizer signer is configured", async () => { + const authorizer = buildAuthorizerSigner(); + const config = buildChannelConfig(); + const channelId = computeChannelId({ ...config, receiverAuthorizer: authorizer.address }); + const { manager, storage, facilitator } = buildManager({ authorizerSigner: authorizer }); + await storeChannel( + storage, + buildSession({ + channelId, + channelConfig: { ...config, receiverAuthorizer: authorizer.address }, + chargedCumulativeAmount: "5000", + }), + ); + + await manager.claim(); + + const [paymentPayload] = facilitator.settle.mock.calls[0]; + const payload = paymentPayload.payload as Record; + expect(payload.claimAuthorizerSignature).toMatch(/^0x[0-9a-f]+$/i); + }); + + it("propagates a facilitator failure as a thrown error and leaves session intact", async () => { + const facilitator = buildFacilitator(async () => ({ + success: false, + errorReason: "boom", + errorMessage: "Claim reverted", + transaction: "", + network: NETWORK, + })); + const { manager, storage } = buildManager({ facilitator }); + const session = buildSession({ chargedCumulativeAmount: "5000" }); + await storeChannel(storage, session); + + await expect(manager.claim()).rejects.toThrow(/Claim failed/); + + const stored = await storage.get(session.channelId); + expect(stored?.totalClaimed).toBe("0"); + }); +}); + +describe("BatchSettlementChannelManager — settle()", () => { + it('calls the facilitator with a type="settle" payload', async () => { + const { manager, facilitator } = buildManager(); + const result = await manager.settle(); + + expect(result.transaction).toBe("0xtx"); + const [paymentPayload, reqs] = facilitator.settle.mock.calls[0]; + expect((paymentPayload.payload as Record).type).toBe("settle"); + expect((paymentPayload.payload as Record).receiver).toBe(RECEIVER); + expect((paymentPayload.payload as Record).token).toBe(TOKEN); + expect(reqs.network).toBe(NETWORK); + }); + + it("throws when the facilitator reports a failure", async () => { + const facilitator = buildFacilitator(async () => ({ + success: false, + errorReason: "boom", + errorMessage: "settle reverted", + transaction: "", + network: NETWORK, + })); + const { manager } = buildManager({ facilitator }); + await expect(manager.settle()).rejects.toThrow(/Settle failed/); + }); +}); + +describe("BatchSettlementChannelManager — claimAndSettle()", () => { + it("returns only the empty claims when no claimable vouchers exist", async () => { + const { manager, facilitator } = buildManager(); + const result = await manager.claimAndSettle(); + expect(result.claims).toEqual([]); + expect(result.settle).toBeUndefined(); + expect(facilitator.settle).not.toHaveBeenCalled(); + }); + + it("runs both claim and settle when there are claimable vouchers", async () => { + const { manager, storage, facilitator } = buildManager(); + const session = buildSession({ chargedCumulativeAmount: "5000" }); + await storeChannel(storage, session); + + const result = await manager.claimAndSettle(); + expect(result.claims).toHaveLength(1); + expect(result.settle?.transaction).toBe("0xtx"); + expect(facilitator.settle).toHaveBeenCalledTimes(2); + }); + + it("does not settle when the claim selector returns no claim work", async () => { + const { manager, storage, facilitator } = buildManager(); + const session = buildSession({ chargedCumulativeAmount: "5000" }); + await storeChannel(storage, session); + + const result = await manager.claimAndSettle({ + selectClaimChannels: () => [], + }); + + expect(result.claims).toEqual([]); + expect(result.settle).toBeUndefined(); + expect(facilitator.settle).not.toHaveBeenCalled(); + expect((await storage.get(session.channelId))?.totalClaimed).toBe("0"); + }); +}); + +describe("BatchSettlementChannelManager — refund()", () => { + it("returns no channels when storage is empty", async () => { + const { manager, facilitator } = buildManager(); + const result = await manager.refund(); + expect(result).toEqual([]); + expect(facilitator.settle).not.toHaveBeenCalled(); + }); + + it("filters by provided channel ids (case-insensitive)", async () => { + const { manager, storage, facilitator } = buildManager(); + const session = buildSession({ chargedCumulativeAmount: "1000", balance: "10000" }); + await storeChannel(storage, session); + + const idUpper = session.channelId.toUpperCase().replace("0X", "0x"); + const result = await manager.refund([idUpper]); + + expect(result).toEqual([{ channel: session.channelId, transaction: "0xtx" }]); + expect(facilitator.settle).toHaveBeenCalledTimes(1); + const [paymentPayload] = facilitator.settle.mock.calls[0]; + const payload = paymentPayload.payload as Record; + expect(payload.type).toBe("refund"); + expect(payload.amount).toBe("9000"); + expect(payload.chargedCumulativeAmount).toBeUndefined(); + }); + + it("includes outstanding voucher claims and deletes session on success", async () => { + const { manager, storage } = buildManager(); + const session = buildSession({ + chargedCumulativeAmount: "3000", + totalClaimed: "1000", + balance: "10000", + }); + await storeChannel(storage, session); + + await manager.refund(); + + const stored = await storage.get(session.channelId); + expect(stored).toBeUndefined(); + }); + + it("refunds multiple channels with one facilitator transaction per channel", async () => { + const { manager, storage, facilitator } = buildManager(); + for (let i = 0; i < 2; i++) { + const config = buildChannelConfig(i.toString(16)); + await storeChannel( + storage, + buildSession({ + channelConfig: config, + channelId: computeChannelId(config), + chargedCumulativeAmount: "1000", + balance: "10000", + }), + ); + } + + const result = await manager.refund(); + + expect(result).toHaveLength(2); + expect(facilitator.settle).toHaveBeenCalledTimes(2); + for (const { channel } of result) { + expect(await storage.get(channel)).toBeUndefined(); + } + }); + + it("refundIdleChannels only refunds channels idle long enough", async () => { + const { manager, storage } = buildManager(); + const idleConfig = buildChannelConfig("01"); + const freshConfig = buildChannelConfig("02"); + const idle = buildSession({ + channelConfig: idleConfig, + channelId: computeChannelId(idleConfig), + lastRequestTimestamp: Date.now() - 120_000, + }); + const fresh = buildSession({ + channelConfig: freshConfig, + channelId: computeChannelId(freshConfig), + lastRequestTimestamp: Date.now(), + }); + await storeChannel(storage, idle); + await storeChannel(storage, fresh); + + const result = await manager.refundIdleChannels({ idleSecs: 60 }); + + expect(result).toEqual([{ channel: idle.channelId, transaction: "0xtx" }]); + expect(await storage.get(idle.channelId)).toBeUndefined(); + expect(await storage.get(fresh.channelId)).toBeDefined(); + }); + + it("throws when facilitator reports failure", async () => { + const facilitator = buildFacilitator(async () => ({ + success: false, + errorReason: "boom", + errorMessage: "refund reverted", + transaction: "", + network: NETWORK, + })); + const { manager, storage } = buildManager({ facilitator }); + const session = buildSession({ chargedCumulativeAmount: "1000", balance: "10000" }); + await storeChannel(storage, session); + + await expect(manager.refund()).rejects.toThrow(/Refund failed/); + + const stored = await storage.get(session.channelId); + expect(stored).toBeDefined(); + }); +}); + +describe("BatchSettlementChannelManager — start()/stop() loop", () => { + beforeEach(() => { + vi.useFakeTimers(); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + it("schedules configured auto job timers and clears them on stop", async () => { + const { manager } = buildManager(); + const setIntervalSpy = vi.spyOn(global, "setInterval"); + const clearIntervalSpy = vi.spyOn(global, "clearInterval"); + + manager.start({ claimIntervalSecs: 1, settleIntervalSecs: 2, refundIntervalSecs: 3 }); + expect(setIntervalSpy).toHaveBeenCalledTimes(3); + + await manager.stop(); + expect(clearIntervalSpy).toHaveBeenCalledTimes(3); + }); + + it("is a no-op to call start twice (single timer)", () => { + const { manager } = buildManager(); + const setIntervalSpy = vi.spyOn(global, "setInterval"); + + manager.start({ claimIntervalSecs: 1 }); + manager.start({ settleIntervalSecs: 1 }); + expect(setIntervalSpy).toHaveBeenCalledTimes(1); + }); + + it("flushes pending claims and settles on stop({ flush: true })", async () => { + const { manager, storage, facilitator } = buildManager(); + const session = buildSession({ chargedCumulativeAmount: "5000" }); + await storeChannel(storage, session); + + manager.start(); + await manager.stop({ flush: true }); + + expect(facilitator.settle).toHaveBeenCalledTimes(2); + }); + + it("flushes pending claims and settles without refunding on stop({ flush: true })", async () => { + const { manager, storage } = buildManager(); + const session = buildSession({ chargedCumulativeAmount: "1000", balance: "10000" }); + await storeChannel(storage, session); + + const onRefund = vi.fn<(r: RefundResult) => void>(); + manager.start({ onRefund }); + await manager.stop({ flush: true }); + + expect(onRefund).not.toHaveBeenCalled(); + expect(await storage.get(session.channelId)).toBeDefined(); + }); + + it("uses the configured claim selector during stop({ flush: true })", async () => { + const { manager, storage, facilitator } = buildManager(); + const selectedConfig = buildChannelConfig("01"); + const skippedConfig = buildChannelConfig("02"); + const selected = buildSession({ + channelConfig: selectedConfig, + channelId: computeChannelId(selectedConfig), + chargedCumulativeAmount: "5000", + }); + const skipped = buildSession({ + channelConfig: skippedConfig, + channelId: computeChannelId(skippedConfig), + chargedCumulativeAmount: "7000", + }); + await storeChannel(storage, selected); + await storeChannel(storage, skipped); + + manager.start({ + selectClaimChannels: channels => + channels.filter(channel => channel.channelId === selected.channelId), + }); + await manager.stop({ flush: true }); + + expect(facilitator.settle).toHaveBeenCalledTimes(2); + expect((await storage.get(selected.channelId))?.totalClaimed).toBe("5000"); + expect((await storage.get(skipped.channelId))?.totalClaimed).toBe("0"); + }); + + it("forwards flush errors from claimAndSettle", async () => { + const facilitator = buildFacilitator(async payload => { + const action = (payload.payload as Record).type; + if (action === "claim") { + return { + success: false, + errorReason: "boom", + errorMessage: "claim reverted", + transaction: "", + network: NETWORK, + }; + } + return { success: true, transaction: "0xtx", network: NETWORK }; + }); + const { manager, storage } = buildManager({ facilitator }); + const session = buildSession({ chargedCumulativeAmount: "1000", balance: "10000" }); + await storeChannel(storage, session); + + manager.start(); + + await expect(manager.stop({ flush: true })).rejects.toThrow(/Claim failed/); + }); +}); + +describe("BatchSettlementChannelManager — auto-loop tick policies", () => { + beforeEach(() => { + vi.useFakeTimers(); + vi.setSystemTime(new Date("2025-01-01T00:00:00Z")); + }); + + afterEach(() => { + vi.useRealTimers(); + }); + + it("runs aligned claim and settle timers in priority order", async () => { + const { manager, storage, facilitator } = buildManager(); + const session = buildSession({ chargedCumulativeAmount: "5000" }); + await storeChannel(storage, session); + + const onClaim = vi.fn<(r: ClaimResult) => void>(); + const onSettle = vi.fn<(r: SettleResult) => void>(); + manager.start({ + claimIntervalSecs: 1, + settleIntervalSecs: 1, + onClaim, + onSettle, + }); + + await vi.advanceTimersByTimeAsync(1100); + await vi.runAllTicks(); + + await manager.stop(); + expect(onClaim).toHaveBeenCalled(); + expect(onSettle).toHaveBeenCalled(); + const settleTypes = facilitator.settle.mock.calls.map( + ([p]) => (p.payload as Record).type, + ); + expect(settleTypes).toEqual(["claim", "settle"]); + }); + + it("coalesces repeated same-type timer events while a job is running", async () => { + vi.useRealTimers(); + const flushMicrotasks = async () => { + for (let i = 0; i < 20; i++) { + await Promise.resolve(); + } + }; + let onClaimInterval: () => void = () => {}; + const setIntervalSpy = vi + .spyOn(globalThis, "setInterval") + .mockImplementation((handler: TimerHandler) => { + onClaimInterval = typeof handler === "function" ? (handler as () => void) : () => {}; + return 999 as unknown as ReturnType; + }); + const clearIntervalSpy = vi.spyOn(globalThis, "clearInterval").mockImplementation(() => {}); + + const { manager } = buildManager(); + let releaseFirstSelection: (() => void) | undefined; + const firstSelection = new Promise(resolve => { + releaseFirstSelection = resolve; + }); + const selectClaimChannels = vi.fn(async (channels: Channel[]) => { + if (selectClaimChannels.mock.calls.length === 1) { + await firstSelection; + } + return channels; + }); + + try { + manager.start({ + claimIntervalSecs: 1, + selectClaimChannels, + }); + + onClaimInterval(); + await flushMicrotasks(); + expect(selectClaimChannels).toHaveBeenCalledTimes(1); + + onClaimInterval(); + onClaimInterval(); + + releaseFirstSelection?.(); + await flushMicrotasks(); + + await manager.stop(); + expect(selectClaimChannels).toHaveBeenCalledTimes(2); + } finally { + setIntervalSpy.mockRestore(); + clearIntervalSpy.mockRestore(); + vi.useFakeTimers(); + vi.setSystemTime(new Date("2025-01-01T00:00:00Z")); + } + }); + + it("settles pending claims without reading the full channel list", async () => { + const { manager, storage, facilitator } = buildManager(); + const session = buildSession({ chargedCumulativeAmount: "5000" }); + await storeChannel(storage, session); + await manager.claim(); + facilitator.settle.mockClear(); + + const listSpy = vi.spyOn(storage, "list"); + const onSettle = vi.fn<(r: SettleResult) => void>(); + manager.start({ + settleIntervalSecs: 1, + onSettle, + }); + + await vi.advanceTimersByTimeAsync(1100); + await vi.runAllTicks(); + + await manager.stop(); + expect(onSettle).toHaveBeenCalled(); + expect(listSpy).not.toHaveBeenCalled(); + const settleTypes = facilitator.settle.mock.calls.map( + ([p]) => (p.payload as Record).type, + ); + expect(settleTypes).toEqual(["settle"]); + }); + + it("claims only channels selected by the auto claim selector", async () => { + const { manager, storage } = buildManager(); + const selectedConfig = buildChannelConfig("01"); + const skippedConfig = buildChannelConfig("02"); + const selected = buildSession({ + channelConfig: selectedConfig, + channelId: computeChannelId(selectedConfig), + chargedCumulativeAmount: "5000", + }); + const skipped = buildSession({ + channelConfig: skippedConfig, + channelId: computeChannelId(skippedConfig), + chargedCumulativeAmount: "7000", + }); + await storeChannel(storage, selected); + await storeChannel(storage, skipped); + + manager.start({ + claimIntervalSecs: 1, + selectClaimChannels: channels => + channels.filter(channel => channel.channelId === selected.channelId), + }); + + await vi.advanceTimersByTimeAsync(1100); + await vi.runAllTicks(); + + await manager.stop(); + expect((await storage.get(selected.channelId))?.totalClaimed).toBe("5000"); + expect((await storage.get(skipped.channelId))?.totalClaimed).toBe("0"); + }); + + it("does not refund or read channels without a refund selector", async () => { + const { manager, storage, facilitator } = buildManager(); + const listSpy = vi.spyOn(storage, "list"); + const onRefund = vi.fn<(r: RefundResult) => void>(); + + manager.start({ refundIntervalSecs: 1, onRefund }); + + await vi.advanceTimersByTimeAsync(1100); + await vi.runAllTicks(); + + await manager.stop(); + expect(listSpy).not.toHaveBeenCalled(); + expect(onRefund).not.toHaveBeenCalled(); + expect(facilitator.settle).not.toHaveBeenCalled(); + }); + + it("refunds only channels selected by the refund selector", async () => { + const { manager, storage } = buildManager(); + const selectedConfig = buildChannelConfig("01"); + const skippedConfig = buildChannelConfig("02"); + const selected = buildSession({ + channelConfig: selectedConfig, + channelId: computeChannelId(selectedConfig), + balance: "10000", + }); + const skipped = buildSession({ + channelConfig: skippedConfig, + channelId: computeChannelId(skippedConfig), + balance: "10000", + }); + await storeChannel(storage, selected); + await storeChannel(storage, skipped); + + const onRefund = vi.fn<(r: RefundResult) => void>(); + manager.start({ + refundIntervalSecs: 1, + selectRefundChannels: channels => + channels.filter(channel => channel.channelId === selected.channelId), + onRefund, + }); + + await vi.advanceTimersByTimeAsync(1100); + await vi.runAllTicks(); + + await manager.stop(); + expect(onRefund).toHaveBeenCalledWith({ channel: selected.channelId, transaction: "0xtx" }); + expect(await storage.get(selected.channelId)).toBeUndefined(); + expect(await storage.get(skipped.channelId)).toBeDefined(); + }); + + it("invokes onError when an auto job throws", async () => { + const facilitator = buildFacilitator(async () => { + throw new Error("network down"); + }); + const { manager, storage } = buildManager({ facilitator }); + const session = buildSession({ chargedCumulativeAmount: "5000" }); + await storeChannel(storage, session); + + const onError = vi.fn<(e: unknown) => void>(); + manager.start({ claimIntervalSecs: 1, onError }); + + await vi.advanceTimersByTimeAsync(1100); + await vi.runAllTicks(); + + await manager.stop(); + expect(onError).toHaveBeenCalled(); + }); +}); diff --git a/typescript/packages/mechanisms/evm/test/unit/batch-settlement/client.test.ts b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/client.test.ts new file mode 100644 index 0000000000..0760defb28 --- /dev/null +++ b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/client.test.ts @@ -0,0 +1,1223 @@ +import { describe, it, expect, vi } from "vitest"; +import { privateKeyToAccount } from "viem/accounts"; +import { getAddress } from "viem"; +import { x402HTTPClient } from "@x402/core/client"; +import { BatchSettlementEvmScheme } from "../../../src/batch-settlement/client/scheme"; +import { + type BatchSettlementClientDeps, + buildChannelConfig, + getChannel, + hasChannel, + processSettleResponse, + recoverChannel, + updateChannelAfterRefund, +} from "../../../src/batch-settlement/client/channel"; +import { processCorrectivePaymentRequired } from "../../../src/batch-settlement/client/recovery"; +import { InMemoryClientChannelStorage } from "../../../src/batch-settlement/client/storage"; +import { computeChannelId as computeChannelIdForNetwork } from "../../../src/batch-settlement/utils"; +import { PERMIT2_ADDRESS } from "../../../src/constants"; +import { PERMIT2_DEPOSIT_COLLECTOR_ADDRESS } from "../../../src/batch-settlement/constants"; +import { + isBatchSettlementDepositPayload, + isBatchSettlementVoucherPayload, +} from "../../../src/batch-settlement/types"; +import { createBatchSettlementClientHooks } from "../../../src/batch-settlement/client/hooks"; +import type { ClientEvmSigner } from "../../../src/signer"; +import type { + PaymentPayload, + PaymentRequirements, + SettleResponse, + PaymentRequired, +} from "@x402/core/types"; +import * as Errors from "../../../src/batch-settlement/errors"; + +const PAYER_PRIVATE_KEY = "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d"; +const VOUCHER_PRIVATE_KEY = "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a"; +const RECEIVER_ADDRESS = "0x9876543210987654321098765432109876543210" as `0x${string}`; +const RECEIVER_AUTHORIZER = "0x1111111111111111111111111111111111111111" as `0x${string}`; +const ASSET = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" as `0x${string}`; +const NETWORK = "eip155:84532"; +const DEFAULT_SALT = + "0x0000000000000000000000000000000000000000000000000000000000000000" as `0x${string}`; + +function computeChannelId(config: ReturnType): `0x${string}` { + return computeChannelIdForNetwork(config, NETWORK); +} + +function buildSigner(privateKey: `0x${string}`): ClientEvmSigner { + const account = privateKeyToAccount(privateKey); + return { + address: account.address, + signTypedData: msg => + account.signTypedData({ + domain: msg.domain, + types: msg.types, + primaryType: msg.primaryType, + message: msg.message, + } as Parameters[0]), + }; +} + +function buildSignerWithRead( + privateKey: `0x${string}`, + readContract: ClientEvmSigner["readContract"], +): ClientEvmSigner { + const base = buildSigner(privateKey); + return { ...base, readContract }; +} + +function makeRequirements(overrides?: Partial): PaymentRequirements { + return { + scheme: "batch-settlement", + network: NETWORK, + amount: "1000", + asset: ASSET, + payTo: RECEIVER_ADDRESS, + maxTimeoutSeconds: 3600, + extra: { + name: "USDC", + version: "2", + receiverAuthorizer: RECEIVER_AUTHORIZER, + withdrawDelay: 900, + }, + ...overrides, + }; +} + +function makePaymentPayload(payload: Record): PaymentPayload { + return { + x402Version: 2, + accepted: makeRequirements(), + payload, + }; +} + +interface ClientShape { + signer: ClientEvmSigner; + storage?: InMemoryClientChannelStorage; + salt?: `0x${string}`; + payerAuthorizer?: `0x${string}`; + voucherSigner?: ClientEvmSigner; +} + +function makeDeps(c: ClientShape): BatchSettlementClientDeps { + return { + signer: c.signer, + storage: c.storage ?? new InMemoryClientChannelStorage(), + salt: c.salt ?? DEFAULT_SALT, + payerAuthorizer: c.payerAuthorizer, + voucherSigner: c.voucherSigner, + }; +} + +describe("BatchSettlementEvmScheme — construction", () => { + it("exposes the batch-settlement scheme id", () => { + const client = new BatchSettlementEvmScheme(buildSigner(PAYER_PRIVATE_KEY)); + expect(client.scheme).toBe("batch-settlement"); + }); + + it("accepts a bare deposit policy as second argument", () => { + const client = new BatchSettlementEvmScheme(buildSigner(PAYER_PRIVATE_KEY), { + depositMultiplier: 5, + }); + expect(client).toBeDefined(); + }); + + it("accepts full options object", () => { + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(buildSigner(PAYER_PRIVATE_KEY), { + storage, + depositPolicy: { depositMultiplier: 3 }, + salt: "0x0000000000000000000000000000000000000000000000000000000000000077", + }); + expect(client).toBeDefined(); + }); + + it("rejects non-integer depositMultiplier", () => { + expect( + () => + new BatchSettlementEvmScheme(buildSigner(PAYER_PRIVATE_KEY), { + depositMultiplier: 1.5, + }), + ).toThrow(/depositMultiplier/); + }); + + it("rejects depositMultiplier < 3", () => { + expect( + () => + new BatchSettlementEvmScheme(buildSigner(PAYER_PRIVATE_KEY), { + depositMultiplier: 2, + }), + ).toThrow(/depositMultiplier/); + }); + + it("rejects payerAuthorizer that does not match voucherSigner", () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const voucherSigner = buildSigner(VOUCHER_PRIVATE_KEY); + expect( + () => + new BatchSettlementEvmScheme(signer, { + payerAuthorizer: "0x0000000000000000000000000000000000000001", + voucherSigner, + }), + ).toThrow(/payerAuthorizer address must match voucherSigner.address/); + }); + + it("accepts payerAuthorizer matching voucherSigner.address", () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const voucherSigner = buildSigner(VOUCHER_PRIVATE_KEY); + expect( + () => + new BatchSettlementEvmScheme(signer, { + payerAuthorizer: voucherSigner.address, + voucherSigner, + }), + ).not.toThrow(); + }); +}); + +describe("buildChannelConfig", () => { + it("uses signer's address as payer and payerAuthorizer when not overridden", () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + + expect(config.payer).toBe(signer.address); + expect(config.payerAuthorizer).toBe(getAddress(signer.address)); + expect(config.receiver).toBe(RECEIVER_ADDRESS); + expect(config.token).toBe(ASSET); + expect(config.withdrawDelay).toBe(900); + expect(config.salt).toBe("0x0000000000000000000000000000000000000000000000000000000000000000"); + }); + + it("uses payerAuthorizer override when provided", () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const voucherSigner = buildSigner(VOUCHER_PRIVATE_KEY); + const config = buildChannelConfig( + makeDeps({ signer, voucherSigner, payerAuthorizer: voucherSigner.address }), + makeRequirements(), + ); + expect(config.payerAuthorizer).toBe(getAddress(voucherSigner.address)); + }); + + it("falls back to voucherSigner.address when payerAuthorizer is not set", () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const voucherSigner = buildSigner(VOUCHER_PRIVATE_KEY); + const config = buildChannelConfig(makeDeps({ signer, voucherSigner }), makeRequirements()); + expect(config.payerAuthorizer).toBe(getAddress(voucherSigner.address)); + }); + + it("uses receiverAuthorizer from extra when present", () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const recv = "0x2222222222222222222222222222222222222222" as `0x${string}`; + const cfg = buildChannelConfig( + makeDeps({ signer }), + makeRequirements({ extra: { receiverAuthorizer: recv } }), + ); + expect(cfg.receiverAuthorizer).toBe(getAddress(recv)); + }); + + it("throws when receiverAuthorizer is missing or zero", () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + expect(() => buildChannelConfig(makeDeps({ signer }), makeRequirements({ extra: {} }))).toThrow( + /receiverAuthorizer/, + ); + expect(() => + buildChannelConfig( + makeDeps({ signer }), + makeRequirements({ + extra: { receiverAuthorizer: "0x0000000000000000000000000000000000000000" }, + }), + ), + ).toThrow(/receiverAuthorizer/); + }); + + it("defaults withdrawDelay to 900 when not in extra", () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const cfg = buildChannelConfig( + makeDeps({ signer }), + makeRequirements({ extra: { receiverAuthorizer: RECEIVER_AUTHORIZER } }), + ); + expect(cfg.withdrawDelay).toBe(900); + }); + + it("respects custom salt from options", () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const salt = + "0xabc1230000000000000000000000000000000000000000000000000000000099" as `0x${string}`; + const cfg = buildChannelConfig(makeDeps({ signer, salt }), makeRequirements()); + expect(cfg.salt).toBe(salt); + }); +}); + +describe("BatchSettlementEvmScheme — createPaymentPayload", () => { + it("returns a deposit-then-voucher payload on first request (no balance)", async () => { + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, async () => [0n, 0n]); + const client = new BatchSettlementEvmScheme(signer); + + const result = await client.createPaymentPayload(2, makeRequirements()); + expect(result.x402Version).toBe(2); + expect(isBatchSettlementDepositPayload(result.payload as Record)).toBe(true); + }); + + it("voucher.maxClaimableAmount equals charged + amount on first request", async () => { + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, async () => [0n, 0n]); + const client = new BatchSettlementEvmScheme(signer); + + const result = await client.createPaymentPayload(2, makeRequirements({ amount: "5000" })); + const payload = result.payload as { voucher: { maxClaimableAmount: string } }; + expect(payload.voucher.maxClaimableAmount).toBe("5000"); + }); + + it("returns a voucher-only payload when balance is sufficient", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { storage }); + + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "0", + balance: "10000", + totalClaimed: "0", + }); + + const result = await client.createPaymentPayload(2, makeRequirements({ amount: "1000" })); + expect(isBatchSettlementVoucherPayload(result.payload as Record)).toBe(true); + expect( + (result.payload as { voucher: { maxClaimableAmount: string } }).voucher.maxClaimableAmount, + ).toBe("1000"); + }); + + it("creates a top-up deposit when balance is insufficient", async () => { + const readContract = vi.fn().mockResolvedValue([100n, 0n]); + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, readContract); + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { storage }); + + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "100", + balance: "100", + totalClaimed: "0", + }); + + const result = await client.createPaymentPayload(2, makeRequirements({ amount: "1000" })); + expect(isBatchSettlementDepositPayload(result.payload as Record)).toBe(true); + }); + + it("allows depositStrategy to skip a top-up and return a voucher", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + const depositStrategy = vi.fn(() => false); + const client = new BatchSettlementEvmScheme(signer, { + storage, + depositStrategy, + }); + + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "0", + balance: "100", + totalClaimed: "0", + }); + + const result = await client.createPaymentPayload(2, makeRequirements({ amount: "1000" })); + expect(isBatchSettlementVoucherPayload(result.payload as Record)).toBe(true); + expect(depositStrategy).toHaveBeenCalledTimes(1); + }); + + it("createPaymentPayload keeps refund requests on the refund() path", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { storage }); + + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "0", + balance: "10000", + totalClaimed: "0", + }); + + const result = await client.createPaymentPayload(2, makeRequirements()); + expect(result.payload.type).toBe("voucher"); + expect( + (client as unknown as { requestRefund?: (id: string) => void }).requestRefund, + ).toBeUndefined(); + }); + + it("uses voucherSigner to sign the voucher when provided", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const voucherSigner = buildSigner(VOUCHER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { storage, voucherSigner }); + + const config = buildChannelConfig(makeDeps({ signer, voucherSigner }), makeRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "0", + balance: "10000", + totalClaimed: "0", + }); + + const result = await client.createPaymentPayload(2, makeRequirements()); + expect(isBatchSettlementVoucherPayload(result.payload as Record)).toBe(true); + }); + + it("computed channelId matches the on-the-wire payload channelId", async () => { + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, async () => [0n, 0n]); + const client = new BatchSettlementEvmScheme(signer); + + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + const expectedId = computeChannelId(config); + + const result = await client.createPaymentPayload(2, makeRequirements()); + const payload = result.payload as { voucher: { channelId: string } }; + expect(payload.voucher.channelId.toLowerCase()).toBe(expectedId.toLowerCase()); + }); + + it("throws when EIP-712 domain (name/version) is missing for deposit flow", async () => { + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, async () => [0n, 0n]); + const client = new BatchSettlementEvmScheme(signer); + + await expect( + client.createPaymentPayload( + 2, + makeRequirements({ + extra: { receiverAuthorizer: RECEIVER_AUTHORIZER, withdrawDelay: 900 }, + }), + ), + ).rejects.toThrow(/EIP-712 domain parameters/); + }); + + it("respects depositMultiplier in deposit amount", async () => { + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, async () => [0n, 0n]); + const client = new BatchSettlementEvmScheme(signer, { depositMultiplier: 7 }); + + const result = await client.createPaymentPayload(2, makeRequirements({ amount: "1000" })); + const payload = result.payload as { deposit: { amount: string } }; + expect(payload.deposit.amount).toBe("7000"); + }); + + it("allows depositStrategy to cap deposits when the cap covers the request", async () => { + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, async () => [0n, 0n]); + const client = new BatchSettlementEvmScheme(signer, { + depositPolicy: { depositMultiplier: 100 }, + depositStrategy: ({ depositAmount }) => { + const maxDeposit = 5000n; + const amount = BigInt(depositAmount); + return amount > maxDeposit ? maxDeposit : amount; + }, + }); + const result = await client.createPaymentPayload(2, makeRequirements({ amount: "1000" })); + const payload = result.payload as { deposit: { amount: string } }; + expect(payload.deposit.amount).toBe("5000"); + }); + + it("calls depositStrategy for initial deposits and top-ups", async () => { + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, async () => [0n, 0n]); + const storage = new InMemoryClientChannelStorage(); + const depositStrategy = vi.fn(({ depositAmount }) => depositAmount); + const client = new BatchSettlementEvmScheme(signer, { storage, depositStrategy }); + + await client.createPaymentPayload(2, makeRequirements({ amount: "1000" })); + + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "100", + balance: "100", + totalClaimed: "0", + }); + + await client.createPaymentPayload(2, makeRequirements({ amount: "1000" })); + + expect(depositStrategy).toHaveBeenCalledTimes(2); + expect(depositStrategy.mock.calls[0][0]).toMatchObject({ + requestAmount: "1000", + maxClaimableAmount: "1000", + currentBalance: "0", + minimumDepositAmount: "1000", + depositAmount: "5000", + }); + expect(depositStrategy.mock.calls[1][0]).toMatchObject({ + requestAmount: "1000", + maxClaimableAmount: "1100", + currentBalance: "100", + minimumDepositAmount: "1000", + depositAmount: "5000", + }); + }); + + it("allows depositStrategy to skip an initial deposit", async () => { + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, async () => [0n, 0n]); + const depositStrategy = vi.fn(() => false); + const client = new BatchSettlementEvmScheme(signer, { depositStrategy }); + + const result = await client.createPaymentPayload(2, makeRequirements({ amount: "1000" })); + + expect(isBatchSettlementVoucherPayload(result.payload as Record)).toBe(true); + expect(depositStrategy).toHaveBeenCalledTimes(1); + }); + + it("rejects insufficient strategy-returned deposit amounts before signing", async () => { + const baseSigner = buildSigner(PAYER_PRIVATE_KEY); + const signer = { + ...baseSigner, + signTypedData: vi.fn(baseSigner.signTypedData), + }; + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { + storage, + depositStrategy: () => "999", + }); + + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "100", + balance: "100", + totalClaimed: "0", + }); + + await expect( + client.createPaymentPayload(2, makeRequirements({ amount: "1000" })), + ).rejects.toThrow(/below required top-up/); + expect(signer.signTypedData).not.toHaveBeenCalled(); + }); + + it("creates a Permit2 deposit payload when requested by assetTransferMethod", async () => { + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, async () => [0n, 0n]); + const client = new BatchSettlementEvmScheme(signer); + const result = await client.createPaymentPayload( + 2, + makeRequirements({ + extra: { + name: "USDC", + version: "2", + receiverAuthorizer: RECEIVER_AUTHORIZER, + assetTransferMethod: "permit2", + }, + }), + ); + + expect(isBatchSettlementDepositPayload(result.payload as Record)).toBe(true); + const payload = result.payload as { + voucher: { channelId: `0x${string}` }; + deposit: { + amount: string; + authorization: { + permit2Authorization: { + from: `0x${string}`; + permitted: { token: `0x${string}`; amount: string }; + spender: `0x${string}`; + witness: { channelId: `0x${string}` }; + }; + }; + }; + }; + + const auth = payload.deposit.authorization.permit2Authorization; + expect(payload.deposit.amount).toBe("5000"); + expect(auth.from).toBe(signer.address); + expect(auth.permitted.token).toBe(ASSET); + expect(auth.permitted.amount).toBe(payload.deposit.amount); + expect(auth.spender).toBe(getAddress(PERMIT2_DEPOSIT_COLLECTOR_ADDRESS)); + expect(auth.witness.channelId).toBe(payload.voucher.channelId); + }); + + it("signs EIP-2612 Permit2 approval for deposit.amount", async () => { + const storage = new InMemoryClientChannelStorage(); + const baseSigner = buildSigner(PAYER_PRIVATE_KEY); + const config = buildChannelConfig( + makeDeps({ signer: baseSigner, storage }), + makeRequirements(), + ); + await storage.set(computeChannelId(config).toLowerCase(), {}); + + const readContract = vi.fn(async ({ functionName }: { functionName: string }) => { + if (functionName === "allowance") return 0n; + if (functionName === "nonces") return 7n; + return [0n, 0n]; + }); + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, readContract); + const client = new BatchSettlementEvmScheme(signer, { storage }); + const result = await client.createPaymentPayload( + 2, + makeRequirements({ + extra: { + name: "USDC", + version: "2", + receiverAuthorizer: RECEIVER_AUTHORIZER, + assetTransferMethod: "permit2", + }, + }), + { extensions: { eip2612GasSponsoring: {} } } as never, + ); + + const extensions = result.extensions as + | Record }> + | undefined; + const info = extensions?.eip2612GasSponsoring?.info as + | { amount?: string; spender?: string } + | undefined; + expect(info?.amount).toBe("5000"); + expect(info?.spender).toBe(getAddress(PERMIT2_ADDRESS)); + }); +}); + +describe("processSettleResponse / schemeHooks", () => { + it("updates session fields from settle response extras", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + + const channelId = "0xabc1230000000000000000000000000000000000000000000000000000000001"; + + const settle: SettleResponse = { + success: true, + transaction: "0x", + network: NETWORK, + payer: signer.address, + extra: { + channelState: { + channelId, + chargedCumulativeAmount: "1000", + balance: "9000", + totalClaimed: "500", + }, + }, + }; + + await processSettleResponse(storage, settle); + const ctx = await storage.get(channelId.toLowerCase()); + expect(ctx?.chargedCumulativeAmount).toBe("1000"); + expect(ctx?.balance).toBe("9000"); + expect(ctx?.totalClaimed).toBe("500"); + }); + + it("ignores settle responses with no channelId", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + + await processSettleResponse(storage, { + success: true, + transaction: "0x", + network: NETWORK, + payer: signer.address, + extra: {}, + } as SettleResponse); + + const all = await Promise.all( + ["0xabc1230000000000000000000000000000000000000000000000000000000001"].map(id => + storage.get(id), + ), + ); + expect(all.every(c => c === undefined)).toBe(true); + }); + + it("deletes channel record after a full refund response", async () => { + const storage = new InMemoryClientChannelStorage(); + + const channelId = "0xabc1230000000000000000000000000000000000000000000000000000000002"; + await storage.set(channelId.toLowerCase(), { chargedCumulativeAmount: "1000" }); + + await updateChannelAfterRefund(storage, channelId.toLowerCase(), { + channelState: { channelId, balance: "0" }, + }); + + expect(await storage.get(channelId.toLowerCase())).toBeUndefined(); + }); + + it("schemeHooks.onPaymentResponse delegates to processSettleResponse", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { storage }); + + const channelId = "0xabc1230000000000000000000000000000000000000000000000000000000003"; + await client.schemeHooks.onPaymentResponse!({ + paymentPayload: makePaymentPayload({ type: "voucher" }), + requirements: makeRequirements(), + settleResponse: { + success: true, + transaction: "0x", + network: NETWORK, + payer: signer.address, + extra: { channelState: { channelId, chargedCumulativeAmount: "42" } }, + } as SettleResponse, + } as Parameters>[0]); + + const ctx = await storage.get(channelId.toLowerCase()); + expect(ctx?.chargedCumulativeAmount).toBe("42"); + }); + + it("routes refund settle responses through refund reconciliation", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + const deps = makeDeps({ signer, storage }); + const hooks = createBatchSettlementClientHooks(deps); + const channelId = "0xabc1230000000000000000000000000000000000000000000000000000000004"; + const config = buildChannelConfig(deps, makeRequirements()); + + await storage.set(channelId.toLowerCase(), { chargedCumulativeAmount: "1000" }); + await hooks.onPaymentResponse!({ + paymentPayload: makePaymentPayload({ + type: "refund", + channelConfig: config, + voucher: { + channelId, + maxClaimableAmount: "1000", + signature: "0xdead", + }, + }), + requirements: makeRequirements(), + settleResponse: { + success: true, + transaction: "0x", + network: NETWORK, + payer: signer.address, + extra: { channelState: { channelId, balance: "0" } }, + } as SettleResponse, + }); + + expect(await storage.get(channelId.toLowerCase())).toBeUndefined(); + + await hooks.onPaymentResponse!({ + paymentPayload: makePaymentPayload({ type: "voucher" }), + requirements: makeRequirements(), + settleResponse: { + success: true, + transaction: "0x", + network: NETWORK, + payer: signer.address, + extra: { channelState: { channelId, balance: "0" } }, + } as SettleResponse, + }); + + expect((await storage.get(channelId.toLowerCase()))?.balance).toBe("0"); + }); +}); + +describe("recoverChannel / hasChannel / getChannel", () => { + it("recoverChannel reads on-chain channels() and stores context", async () => { + const readContract = vi.fn().mockResolvedValue([5000n, 1000n]); + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, readContract); + const storage = new InMemoryClientChannelStorage(); + + const ctx = await recoverChannel(makeDeps({ signer, storage }), makeRequirements()); + expect(ctx.balance).toBe("5000"); + expect(ctx.totalClaimed).toBe("1000"); + expect(ctx.chargedCumulativeAmount).toBe("1000"); + + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + const id = computeChannelId(config); + expect((await storage.get(id.toLowerCase()))?.balance).toBe("5000"); + }); + + it("recoverChannel throws when readContract is unavailable", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + await expect(recoverChannel(makeDeps({ signer, storage }), makeRequirements())).rejects.toThrow( + /readContract/, + ); + }); + + it("hasChannel / getChannel reflect storage state", async () => { + const storage = new InMemoryClientChannelStorage(); + + const id = "0xabc1230000000000000000000000000000000000000000000000000000000010"; + expect(await hasChannel(storage, id)).toBe(false); + expect(await getChannel(storage, id)).toBeUndefined(); + + await storage.set(id.toLowerCase(), { chargedCumulativeAmount: "100" }); + expect(await hasChannel(storage, id)).toBe(true); + expect((await getChannel(storage, id))?.chargedCumulativeAmount).toBe("100"); + }); +}); + +describe("processCorrectivePaymentRequired", () => { + function makeAccept( + channelState: Record, + voucherState: Record, + ): PaymentRequirements { + return makeRequirements({ + extra: { ...makeRequirements().extra, channelState, voucherState }, + }); + } + + it("returns false for unrelated error codes", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + + const ok = await processCorrectivePaymentRequired(makeDeps({ signer, storage }), { + x402Version: 2, + error: "some_other_error", + accepts: [makeRequirements()], + } as unknown as PaymentRequired); + expect(ok).toBe(false); + }); + + it("returns false when no batch-settlement accept entry is present", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + + const ok = await processCorrectivePaymentRequired(makeDeps({ signer, storage }), { + x402Version: 2, + error: Errors.ErrCumulativeAmountMismatch, + accepts: [{ ...makeRequirements(), scheme: "exact" }], + } as unknown as PaymentRequired); + expect(ok).toBe(false); + }); + + it("recoverFromOnChainState updates session when no signature is present", async () => { + const readContract = vi.fn().mockResolvedValue([10000n, 2500n]); + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, readContract); + const storage = new InMemoryClientChannelStorage(); + + const ok = await processCorrectivePaymentRequired(makeDeps({ signer, storage }), { + x402Version: 2, + error: Errors.ErrCumulativeAmountMismatch, + accepts: [makeRequirements()], + } as unknown as PaymentRequired); + + expect(ok).toBe(true); + const id = computeChannelId(buildChannelConfig(makeDeps({ signer }), makeRequirements())); + const ctx = await storage.get(id.toLowerCase()); + expect(ctx?.chargedCumulativeAmount).toBe("2500"); + expect(ctx?.balance).toBe("10000"); + }); + + it("recoverFromSignature succeeds when signature comes from this client's signer", async () => { + const readContract = vi.fn().mockResolvedValue([10000n, 500n]); + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, readContract); + const storage = new InMemoryClientChannelStorage(); + + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + const channelId = computeChannelId(config); + + const { signVoucher } = await import("../../../src/batch-settlement/client/voucher"); + const signed = await signVoucher(signer, channelId, "1500", NETWORK); + + const channelState = { + chargedCumulativeAmount: "1000", + }; + const voucherState = { + signedMaxClaimable: signed.maxClaimableAmount, + signature: signed.signature, + }; + const accept = makeAccept(channelState, voucherState); + + const ok = await processCorrectivePaymentRequired(makeDeps({ signer, storage }), { + x402Version: 2, + error: Errors.ErrCumulativeAmountMismatch, + accepts: [accept], + } as unknown as PaymentRequired); + + expect(ok).toBe(true); + const ctx = await storage.get(channelId.toLowerCase()); + expect(ctx?.chargedCumulativeAmount).toBe("1000"); + expect(ctx?.signedMaxClaimable).toBe("1500"); + expect(ctx?.balance).toBe("10000"); + expect(ctx?.totalClaimed).toBe("500"); + }); + + it("recoverFromSignature returns false when signature is from a different signer", async () => { + const readContract = vi.fn().mockResolvedValue([10000n, 500n]); + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, readContract); + const storage = new InMemoryClientChannelStorage(); + + const otherSigner = buildSigner(VOUCHER_PRIVATE_KEY); + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + const channelId = computeChannelId(config); + const { signVoucher } = await import("../../../src/batch-settlement/client/voucher"); + const signed = await signVoucher(otherSigner, channelId, "1500", NETWORK); + + const channelState = { + chargedCumulativeAmount: "1000", + }; + const voucherState = { + signedMaxClaimable: signed.maxClaimableAmount, + signature: signed.signature, + }; + const accept = makeAccept(channelState, voucherState); + + const ok = await processCorrectivePaymentRequired(makeDeps({ signer, storage }), { + x402Version: 2, + error: Errors.ErrCumulativeAmountMismatch, + accepts: [accept], + } as unknown as PaymentRequired); + expect(ok).toBe(false); + }); + + it("recoverFromSignature returns false when charged > signedMaxClaimable", async () => { + const readContract = vi.fn().mockResolvedValue([10000n, 500n]); + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, readContract); + const storage = new InMemoryClientChannelStorage(); + + const channelState = { + chargedCumulativeAmount: "2000", + }; + const voucherState = { + signedMaxClaimable: "1500", + signature: "0xdead", + }; + const accept = makeAccept(channelState, voucherState); + + const ok = await processCorrectivePaymentRequired(makeDeps({ signer, storage }), { + x402Version: 2, + error: Errors.ErrCumulativeAmountMismatch, + accepts: [accept], + } as unknown as PaymentRequired); + expect(ok).toBe(false); + }); + + it("recoverFromSignature returns false when charged < on-chain totalClaimed", async () => { + const readContract = vi.fn().mockResolvedValue([10000n, 5000n]); + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, readContract); + const storage = new InMemoryClientChannelStorage(); + + const config = buildChannelConfig(makeDeps({ signer }), makeRequirements()); + const channelId = computeChannelId(config); + const { signVoucher } = await import("../../../src/batch-settlement/client/voucher"); + const signed = await signVoucher(signer, channelId, "2000", NETWORK); + + const channelState = { + chargedCumulativeAmount: "1000", + }; + const voucherState = { + signedMaxClaimable: signed.maxClaimableAmount, + signature: signed.signature, + }; + const accept = makeAccept(channelState, voucherState); + + const ok = await processCorrectivePaymentRequired(makeDeps({ signer, storage }), { + x402Version: 2, + error: Errors.ErrCumulativeAmountMismatch, + accepts: [accept], + } as unknown as PaymentRequired); + expect(ok).toBe(false); + }); + + it("schemeHooks.onPaymentResponse returns { recovered: true } on a successful corrective", async () => { + const readContract = vi.fn().mockResolvedValue([10000n, 0n]); + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, readContract); + const client = new BatchSettlementEvmScheme(signer); + + const result = await client.schemeHooks.onPaymentResponse!({ + paymentPayload: makePaymentPayload({ type: "voucher" }), + requirements: makeRequirements(), + paymentRequired: { + x402Version: 2, + error: Errors.ErrCumulativeAmountMismatch, + accepts: [makeRequirements()], + } as unknown as PaymentRequired, + } as Parameters>[0]); + + expect(result).toEqual({ recovered: true }); + }); +}); + +describe("BatchSettlementEvmScheme — refund()", () => { + const REFUND_URL = "https://example.test/protected"; + + function buildRefundRequirements(): PaymentRequirements { + return makeRequirements({ + extra: { + name: "USDC", + version: "2", + withdrawDelay: 900, + receiverAuthorizer: "0x1111111111111111111111111111111111111111", + }, + }); + } + + function makeFetch( + handlers: Array<(input: RequestInfo | URL, init?: RequestInit) => Promise>, + ): typeof fetch { + let i = 0; + return (async (input: RequestInfo | URL, init?: RequestInit) => { + const handler = handlers[i++] ?? handlers[handlers.length - 1]; + return handler(input, init); + }) as typeof fetch; + } + + async function probe402Response(): Promise { + const { encodePaymentRequiredHeader } = await import("@x402/core/http"); + const reqs = buildRefundRequirements(); + const header = encodePaymentRequiredHeader({ + x402Version: 2, + accepts: [reqs], + } as unknown as PaymentRequired); + return new Response(null, { status: 402, headers: { "PAYMENT-REQUIRED": header } }); + } + + async function refundSuccessResponse( + extra: Record, + amount?: string, + ): Promise { + const { encodePaymentResponseHeader } = await import("@x402/core/http"); + const settle: SettleResponse = { + success: true, + transaction: "0xtx", + network: NETWORK, + payer: privateKeyToAccount(PAYER_PRIVATE_KEY).address, + ...(amount !== undefined ? { amount } : {}), + extra, + } as SettleResponse; + const header = encodePaymentResponseHeader(settle); + return new Response(null, { status: 200, headers: { "PAYMENT-RESPONSE": header } }); + } + + it("performs a full refund: probes, sends voucher, deletes channel record", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { storage }); + + const config = buildChannelConfig(makeDeps({ signer }), buildRefundRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "500", + balance: "10000", + totalClaimed: "0", + }); + + let capturedSig: string | undefined; + const fetchImpl = makeFetch([ + async () => probe402Response(), + async (_url, init) => { + capturedSig = (init?.headers as Record | undefined)?.["PAYMENT-SIGNATURE"]; + return refundSuccessResponse( + { + channelState: { + channelId, + balance: "0", + totalClaimed: "500", + withdrawRequestedAt: 0, + refundNonce: "1", + chargedCumulativeAmount: "500", + }, + }, + "9500", + ); + }, + ]); + const processSpy = vi.spyOn(x402HTTPClient.prototype, "processPaymentResult"); + + const settle = await client.refund(REFUND_URL, { fetch: fetchImpl }); + expect(settle.success).toBe(true); + expect(settle.amount).toBe("9500"); + expect(settle.extra?.channelState).toMatchObject({ + channelId, + balance: "0", + chargedCumulativeAmount: "500", + }); + expect(processSpy).toHaveBeenCalledTimes(1); + expect(capturedSig).toBeTruthy(); + const { decodePaymentSignatureHeader } = await import("@x402/core/http"); + const sentPayload = decodePaymentSignatureHeader(capturedSig!); + expect(sentPayload.payload.type).toBe("refund"); + expect(sentPayload.accepted).toEqual(buildRefundRequirements()); + expect((sentPayload.payload as { amount?: string }).amount).toBeUndefined(); + expect(await storage.get(channelId.toLowerCase())).toBeUndefined(); + processSpy.mockRestore(); + }); + + it("performs a partial refund: keeps the channel record and updates balance", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { storage }); + + const config = buildChannelConfig(makeDeps({ signer }), buildRefundRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "500", + balance: "10000", + totalClaimed: "0", + }); + + const fetchImpl = makeFetch([ + async () => probe402Response(), + async () => + refundSuccessResponse({ + channelState: { + channelId, + balance: "8000", + chargedCumulativeAmount: "500", + totalClaimed: "0", + }, + }), + ]); + + const settle = await client.refund(REFUND_URL, { amount: "2000", fetch: fetchImpl }); + expect(settle.success).toBe(true); + + const ctx = await storage.get(channelId.toLowerCase()); + expect(ctx?.balance).toBe("8000"); + expect(ctx?.chargedCumulativeAmount).toBe("500"); + }); + + it("rejects an invalid refund amount before contacting the server", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const client = new BatchSettlementEvmScheme(signer); + const fetchImpl = vi.fn() as unknown as typeof fetch; + + await expect(client.refund(REFUND_URL, { amount: "0", fetch: fetchImpl })).rejects.toThrow( + /Invalid refund amount/, + ); + await expect(client.refund(REFUND_URL, { amount: "1.5", fetch: fetchImpl })).rejects.toThrow( + /Invalid refund amount/, + ); + expect(fetchImpl).not.toHaveBeenCalled(); + }); + + it("recovers from a corrective 402 and retries once", async () => { + const readContract = vi.fn().mockResolvedValue([10000n, 500n]); + const signer = buildSignerWithRead(PAYER_PRIVATE_KEY, readContract); + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { storage }); + + const config = buildChannelConfig(makeDeps({ signer }), buildRefundRequirements()); + const channelId = computeChannelId(config); + + const { encodePaymentRequiredHeader } = await import("@x402/core/http"); + const correctiveHeader = encodePaymentRequiredHeader({ + x402Version: 2, + error: Errors.ErrCumulativeAmountBelowClaimed, + accepts: [buildRefundRequirements()], + } as PaymentRequired); + + const fetchImpl = makeFetch([ + async () => probe402Response(), + async () => + new Response(null, { status: 402, headers: { "PAYMENT-REQUIRED": correctiveHeader } }), + async () => refundSuccessResponse({ channelState: { channelId, balance: "0" } }), + ]); + const processSpy = vi.spyOn(x402HTTPClient.prototype, "processPaymentResult"); + + const settle = await client.refund(REFUND_URL, { fetch: fetchImpl }); + expect(settle.success).toBe(true); + expect(readContract).toHaveBeenCalled(); + expect(processSpy).toHaveBeenCalledTimes(2); + processSpy.mockRestore(); + }); + + it("throws when the probe receives a non-402 response", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const client = new BatchSettlementEvmScheme(signer); + const fetchImpl = makeFetch([async () => new Response("ok", { status: 200 })]); + + await expect(client.refund(REFUND_URL, { fetch: fetchImpl })).rejects.toThrow( + /Refund probe expected 402/, + ); + }); + + it("fails fast (no retry) when server returns 402 with refund no balance error", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { storage }); + + const config = buildChannelConfig(makeDeps({ signer }), buildRefundRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "500", + balance: "10000", + totalClaimed: "0", + }); + + const { encodePaymentResponseHeader } = await import("@x402/core/http"); + const failureSettle: SettleResponse = { + success: false, + transaction: "", + network: NETWORK, + payer: signer.address, + errorReason: Errors.ErrRefundNoBalance, + errorMessage: "Channel has no remaining balance to refund", + } as SettleResponse; + const failureHeader = encodePaymentResponseHeader(failureSettle); + + const refundCall = vi.fn(async () => { + return new Response(null, { status: 402, headers: { "PAYMENT-RESPONSE": failureHeader } }); + }); + const fetchImpl = makeFetch([async () => probe402Response(), refundCall]); + + await expect(client.refund(REFUND_URL, { fetch: fetchImpl })).rejects.toThrow( + new RegExp(Errors.ErrRefundNoBalance), + ); + expect(refundCall).toHaveBeenCalledTimes(1); + }); + + it("fails fast on a verify-side 402 with a non-recoverable refund error", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { storage }); + + const config = buildChannelConfig(makeDeps({ signer }), buildRefundRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "500", + balance: "10000", + totalClaimed: "0", + }); + + const { encodePaymentRequiredHeader } = await import("@x402/core/http"); + const requiredHeader = encodePaymentRequiredHeader({ + x402Version: 2, + error: Errors.ErrRefundNoBalance, + accepts: [buildRefundRequirements()], + } as PaymentRequired); + + const refundCall = vi.fn(async () => { + return new Response(null, { status: 402, headers: { "PAYMENT-REQUIRED": requiredHeader } }); + }); + const fetchImpl = makeFetch([async () => probe402Response(), refundCall]); + + await expect(client.refund(REFUND_URL, { fetch: fetchImpl })).rejects.toThrow( + new RegExp(Errors.ErrRefundNoBalance), + ); + expect(refundCall).toHaveBeenCalledTimes(1); + }); + + it("throws before any PAYMENT-SIGNATURE request when local session shows the channel is drained", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const storage = new InMemoryClientChannelStorage(); + const client = new BatchSettlementEvmScheme(signer, { storage }); + + const config = buildChannelConfig(makeDeps({ signer }), buildRefundRequirements()); + const channelId = computeChannelId(config); + await storage.set(channelId.toLowerCase(), { + chargedCumulativeAmount: "61800", + balance: "61800", + totalClaimed: "61800", + }); + + const refundCall = vi.fn(async () => { + throw new Error("refund request should not have been sent"); + }); + const fetchImpl = makeFetch([async () => probe402Response(), refundCall]); + + await expect(client.refund(REFUND_URL, { fetch: fetchImpl })).rejects.toThrow( + /channel has no remaining balance/, + ); + expect(refundCall).not.toHaveBeenCalled(); + }); + + it("throws when the receiver lacks a configured receiverAuthorizer", async () => { + const signer = buildSigner(PAYER_PRIVATE_KEY); + const client = new BatchSettlementEvmScheme(signer); + + const { encodePaymentRequiredHeader } = await import("@x402/core/http"); + const reqs = makeRequirements({ extra: { name: "USDC", version: "2", withdrawDelay: 900 } }); + const header = encodePaymentRequiredHeader({ + x402Version: 2, + accepts: [reqs], + } as unknown as PaymentRequired); + const fetchImpl = makeFetch([ + async () => new Response(null, { status: 402, headers: { "PAYMENT-REQUIRED": header } }), + ]); + + await expect(client.refund(REFUND_URL, { fetch: fetchImpl })).rejects.toThrow( + /receiverAuthorizer/, + ); + }); +}); diff --git a/typescript/packages/mechanisms/evm/test/unit/batch-settlement/facilitator.test.ts b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/facilitator.test.ts new file mode 100644 index 0000000000..0861cc28c5 --- /dev/null +++ b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/facilitator.test.ts @@ -0,0 +1,1118 @@ +import { describe, it, expect, beforeEach, vi } from "vitest"; +import type { MockedFunction } from "vitest"; +import { privateKeyToAccount } from "viem/accounts"; +import { encodeAbiParameters, encodeEventTopics, getAddress, isAddress } from "viem"; +import type { Log } from "viem"; + +vi.mock("../../../src/multicall", async importOriginal => { + const actual = await importOriginal(); + return { ...actual, multicall: vi.fn() }; +}); + +import { multicall } from "../../../src/multicall"; +import { BatchSettlementEvmScheme } from "../../../src/batch-settlement/facilitator/scheme"; +import { computeChannelId as computeChannelIdForNetwork } from "../../../src/batch-settlement/utils"; +import { + BATCH_SETTLEMENT_ADDRESS, + ERC3009_DEPOSIT_COLLECTOR_ADDRESS, + PERMIT2_DEPOSIT_COLLECTOR_ADDRESS, +} from "../../../src/batch-settlement/constants"; +import { batchSettlementABI } from "../../../src/batch-settlement/abi"; +import * as Errors from "../../../src/batch-settlement/errors"; +import type { + ChannelConfig, + AuthorizerSigner, + BatchSettlementDepositPayload, + BatchSettlementVoucherPayload, + BatchSettlementRefundPayload, + BatchSettlementClaimPayload, + BatchSettlementSettlePayload, + BatchSettlementEnrichedRefundPayload, +} from "../../../src/batch-settlement/types"; +import type { FacilitatorEvmSigner } from "../../../src/signer"; +import type { PaymentPayload, PaymentRequirements } from "@x402/core/types"; + +const mockedMulticall = multicall as unknown as MockedFunction; + +const PAYER = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" as `0x${string}`; +const RECEIVER = "0x9876543210987654321098765432109876543210" as `0x${string}`; +const ASSET = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" as `0x${string}`; +const FACILITATOR_ADDRESS = "0xFAC11174700123456789012345678901234aBCDe" as `0x${string}`; +const NETWORK = "eip155:84532"; + +function computeChannelId(config: ChannelConfig): `0x${string}` { + return computeChannelIdForNetwork(config, NETWORK); +} + +function buildAuthorizerSigner(): AuthorizerSigner { + const account = privateKeyToAccount( + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", + ); + return { + address: account.address, + signTypedData: msg => + account.signTypedData({ + domain: msg.domain, + types: msg.types, + primaryType: msg.primaryType, + message: msg.message, + } as Parameters[0]), + }; +} + +const ZERO_ADDR = "0x0000000000000000000000000000000000000000" as `0x${string}`; +const RECEIVER_AUTHORIZER = "0x1111111111111111111111111111111111111111" as `0x${string}`; + +function buildChannelConfig(overrides: Partial = {}): ChannelConfig { + return { + payer: PAYER, + payerAuthorizer: ZERO_ADDR, + receiver: RECEIVER, + receiverAuthorizer: RECEIVER_AUTHORIZER, + token: ASSET, + withdrawDelay: 900, + salt: "0x0000000000000000000000000000000000000000000000000000000000000000", + ...overrides, + }; +} + +function makeRequirements(overrides: Partial = {}): PaymentRequirements { + return { + scheme: "batch-settlement", + network: NETWORK, + amount: "1000", + asset: ASSET, + payTo: RECEIVER, + maxTimeoutSeconds: 3600, + extra: { + name: "USDC", + version: "2", + receiverAuthorizer: RECEIVER_AUTHORIZER, + assetTransferMethod: "eip3009", + withdrawDelay: 900, + }, + ...overrides, + }; +} + +function buildSigner(overrides: Partial = {}): FacilitatorEvmSigner { + return { + getAddresses: () => [FACILITATOR_ADDRESS], + readContract: vi.fn().mockResolvedValue(undefined), + verifyTypedData: vi.fn().mockResolvedValue(true), + writeContract: vi.fn().mockResolvedValue("0xtxhash" as `0x${string}`), + sendTransaction: vi.fn(), + waitForTransactionReceipt: vi.fn().mockResolvedValue({ status: "success" }), + getCode: vi.fn(), + ...overrides, + }; +} + +function buildSettledLog( + overrides: { + receiver?: `0x${string}`; + token?: `0x${string}`; + sender?: `0x${string}`; + amount?: string; + address?: `0x${string}`; + } = {}, +): Log { + const receiver = overrides.receiver ?? RECEIVER; + const token = overrides.token ?? ASSET; + const sender = overrides.sender ?? FACILITATOR_ADDRESS; + + return { + address: overrides.address ?? BATCH_SETTLEMENT_ADDRESS, + topics: encodeEventTopics({ + abi: batchSettlementABI, + eventName: "Settled", + args: { receiver, token, sender }, + }), + data: encodeAbiParameters([{ type: "uint128" }], [BigInt(overrides.amount ?? "2500")]), + blockHash: null, + blockNumber: null, + logIndex: null, + transactionHash: null, + transactionIndex: null, + removed: false, + } as Log; +} + +function envelopeVoucher(payload: BatchSettlementVoucherPayload): PaymentPayload { + return { + x402Version: 2, + accepted: { scheme: "batch-settlement", network: NETWORK }, + payload: payload as unknown as Record, + } as unknown as PaymentPayload; +} + +function envelopeRefund(payload: BatchSettlementRefundPayload): PaymentPayload { + return { + x402Version: 2, + accepted: { scheme: "batch-settlement", network: NETWORK }, + payload: payload as unknown as Record, + } as unknown as PaymentPayload; +} + +function envelopeDeposit(payload: BatchSettlementDepositPayload): PaymentPayload { + return { + x402Version: 2, + accepted: { scheme: "batch-settlement", network: NETWORK }, + payload: payload as unknown as Record, + } as unknown as PaymentPayload; +} + +function envelopeSettle(payload: Record): PaymentPayload { + return { + x402Version: 2, + accepted: { scheme: "batch-settlement", network: NETWORK }, + payload, + } as unknown as PaymentPayload; +} + +beforeEach(() => { + mockedMulticall.mockReset(); +}); + +describe("BatchSettlementEvmScheme (Facilitator) — construction & metadata", () => { + const authorizer = buildAuthorizerSigner(); + + it("exposes scheme id and CAIP family", () => { + const scheme = new BatchSettlementEvmScheme(buildSigner(), authorizer); + expect(scheme.scheme).toBe("batch-settlement"); + expect(scheme.caipFamily).toBe("eip155:*"); + }); + + it("getExtra returns the receiver-authorizer address from authorizerSigner", () => { + const scheme = new BatchSettlementEvmScheme(buildSigner(), authorizer); + expect(scheme.getExtra(NETWORK)).toEqual({ receiverAuthorizer: authorizer.address }); + }); + + it("getSigners returns the facilitator addresses", () => { + const scheme = new BatchSettlementEvmScheme(buildSigner(), authorizer); + expect(scheme.getSigners(NETWORK)).toEqual([FACILITATOR_ADDRESS]); + }); +}); + +describe("BatchSettlementEvmScheme (Facilitator) — verify routing", () => { + const authorizer = buildAuthorizerSigner(); + + it("rejects with InvalidScheme when accepted.scheme mismatches", async () => { + const scheme = new BatchSettlementEvmScheme(buildSigner(), authorizer); + const config = buildChannelConfig(); + const result = await scheme.verify( + { + x402Version: 2, + accepted: { scheme: "exact", network: NETWORK }, + payload: { type: "voucher", channelConfig: config } as Record, + } as unknown as PaymentPayload, + makeRequirements(), + ); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrInvalidScheme); + }); + + it("rejects with NetworkMismatch when accepted.network mismatches requirements", async () => { + const scheme = new BatchSettlementEvmScheme(buildSigner(), authorizer); + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const voucher: BatchSettlementVoucherPayload = { + type: "voucher", + channelConfig: config, + voucher: { + channelId, + maxClaimableAmount: "1000", + signature: "0xdead", + }, + }; + const result = await scheme.verify( + { + x402Version: 2, + accepted: { scheme: "batch-settlement", network: "eip155:1" }, + payload: voucher as unknown as Record, + } as unknown as PaymentPayload, + makeRequirements(), + ); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrNetworkMismatch); + }); + + it("rejects with InvalidPayloadType for an unknown payload shape", async () => { + const scheme = new BatchSettlementEvmScheme(buildSigner(), authorizer); + const result = await scheme.verify( + { + x402Version: 2, + accepted: { scheme: "batch-settlement", network: NETWORK }, + payload: { foo: "bar" } as Record, + } as unknown as PaymentPayload, + makeRequirements(), + ); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrInvalidPayloadType); + }); +}); + +describe("BatchSettlementEvmScheme (Facilitator) — verifyVoucher", () => { + const authorizer = buildAuthorizerSigner(); + + function makeVoucherPayload( + overrides: { + config?: ChannelConfig; + voucher?: Partial; + } = {}, + ): { payload: PaymentPayload; channelId: `0x${string}`; config: ChannelConfig } { + const config = overrides.config ?? buildChannelConfig(); + const channelId = computeChannelId(config); + const voucher: BatchSettlementVoucherPayload = { + type: "voucher", + channelConfig: config, + voucher: { + channelId, + maxClaimableAmount: overrides.voucher?.maxClaimableAmount ?? "1000", + signature: overrides.voucher?.signature ?? ("0xdead" as `0x${string}`), + }, + }; + return { payload: envelopeVoucher(voucher), channelId, config }; + } + + it("returns isValid=true with channel state in extra on happy path", async () => { + const signer = buildSigner(); + mockedMulticall.mockResolvedValue([ + { status: "success", result: [10000n, 0n] }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload, channelId } = makeVoucherPayload(); + + const result = await scheme.verify(payload, makeRequirements()); + expect(result.isValid).toBe(true); + expect(result.payer).toBe(PAYER); + expect(result.extra?.channelId).toBe(channelId); + expect(result.extra?.balance).toBe("10000"); + expect(result.extra?.totalClaimed).toBe("0"); + }); + + it("returns InvalidVoucherSignature when verifyTypedData fails", async () => { + const signer = buildSigner({ verifyTypedData: vi.fn().mockResolvedValue(false) }); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const config = buildChannelConfig({ + payerAuthorizer: "0x0000000000000000000000000000000000000000", + }); + const channelId = computeChannelId(config); + const payload = envelopeVoucher({ + type: "voucher", + channelConfig: config, + voucher: { + channelId, + maxClaimableAmount: "1000", + signature: "0xdead", + }, + }); + + const result = await scheme.verify(payload, makeRequirements()); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrInvalidVoucherSignature); + }); + + it("uses ECDSA path (not ERC-1271) when payerAuthorizer is non-zero", async () => { + const signer = buildSigner(); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const account = privateKeyToAccount( + "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a", + ); + const config = buildChannelConfig({ payerAuthorizer: account.address }); + const channelId = computeChannelId(config); + const sig = await account.signTypedData({ + domain: { + name: "x402 Batch Settlement", + version: "1", + chainId: 84532, + verifyingContract: getAddress(BATCH_SETTLEMENT_ADDRESS), + }, + types: { + Voucher: [ + { name: "channelId", type: "bytes32" }, + { name: "maxClaimableAmount", type: "uint128" }, + ], + }, + primaryType: "Voucher", + message: { channelId, maxClaimableAmount: 1000n }, + }); + + mockedMulticall.mockResolvedValue([ + { status: "success", result: [10000n, 0n] }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + + const payload = envelopeVoucher({ + type: "voucher", + channelConfig: config, + voucher: { + channelId, + maxClaimableAmount: "1000", + signature: sig, + }, + }); + + const result = await scheme.verify(payload, makeRequirements()); + expect(result.isValid).toBe(true); + expect(signer.verifyTypedData).not.toHaveBeenCalled(); + }); + + it("propagates ErrRpcReadFailed when multicall reads fail", async () => { + const signer = buildSigner(); + mockedMulticall.mockResolvedValue([ + { status: "failure", error: new Error("revert") }, + { status: "failure", error: new Error("revert") }, + { status: "failure", error: new Error("revert") }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = makeVoucherPayload(); + + await expect(scheme.verify(payload, makeRequirements())).rejects.toThrow( + Errors.ErrRpcReadFailed, + ); + }); + + it("returns ChannelNotFound when balance is zero", async () => { + const signer = buildSigner(); + mockedMulticall.mockResolvedValue([ + { status: "success", result: [0n, 0n] }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = makeVoucherPayload(); + + const result = await scheme.verify(payload, makeRequirements()); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrChannelNotFound); + }); + + it("returns CumulativeExceedsBalance when maxClaimable > balance", async () => { + const signer = buildSigner(); + mockedMulticall.mockResolvedValue([ + { status: "success", result: [500n, 0n] }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = makeVoucherPayload({ voucher: { maxClaimableAmount: "1000" } }); + + const result = await scheme.verify(payload, makeRequirements()); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrCumulativeExceedsBalance); + }); + + it("returns CumulativeAmountBelowClaimed when maxClaimable <= totalClaimed", async () => { + const signer = buildSigner(); + mockedMulticall.mockResolvedValue([ + { status: "success", result: [10000n, 1000n] }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = makeVoucherPayload({ voucher: { maxClaimableAmount: "1000" } }); + + const result = await scheme.verify(payload, makeRequirements()); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrCumulativeAmountBelowClaimed); + }); + + it("accepts a refund payload whose maxClaimable equals totalClaimed", async () => { + const signer = buildSigner(); + mockedMulticall.mockResolvedValue([ + { status: "success", result: [10000n, 1000n] }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const refundVoucher: BatchSettlementRefundPayload = { + type: "refund", + channelConfig: config, + voucher: { + channelId, + maxClaimableAmount: "1000", + signature: "0xdead", + }, + }; + + const result = await scheme.verify(envelopeRefund(refundVoucher), makeRequirements()); + expect(result.isValid).toBe(true); + }); + + it("still rejects a refund payload whose maxClaimable is below totalClaimed", async () => { + const signer = buildSigner(); + mockedMulticall.mockResolvedValue([ + { status: "success", result: [10000n, 1000n] }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const refundVoucher: BatchSettlementRefundPayload = { + type: "refund", + channelConfig: config, + voucher: { + channelId, + maxClaimableAmount: "500", + signature: "0xdead", + }, + }; + + const result = await scheme.verify(envelopeRefund(refundVoucher), makeRequirements()); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrCumulativeAmountBelowClaimed); + }); + + it("returns ChannelIdMismatch when payload channelId does not match config", async () => { + const signer = buildSigner(); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const config = buildChannelConfig(); + const payload = envelopeVoucher({ + type: "voucher", + channelConfig: config, + voucher: { + channelId: + "0x0000000000000000000000000000000000000000000000000000000000000099" as `0x${string}`, + maxClaimableAmount: "1000", + signature: "0xdead", + }, + }); + + const result = await scheme.verify(payload, makeRequirements()); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrChannelIdMismatch); + }); +}); + +describe("BatchSettlementEvmScheme (Facilitator) — verifyDeposit", () => { + const authorizer = buildAuthorizerSigner(); + + function buildDeposit(overrides: Partial = {}): { + payload: PaymentPayload; + channelId: `0x${string}`; + } { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const now = Math.floor(Date.now() / 1000); + const dp: BatchSettlementDepositPayload = { + type: "deposit", + channelConfig: config, + voucher: { + channelId, + maxClaimableAmount: "1000", + signature: "0xcafebabe", + }, + deposit: { + amount: "10000", + authorization: { + erc3009Authorization: { + validAfter: String(now - 600), + validBefore: String(now + 3600), + salt: "0x0000000000000000000000000000000000000000000000000000000000000001", + signature: "0xfeedface", + }, + }, + ...overrides, + }, + }; + return { payload: envelopeDeposit(dp), channelId }; + } + + it("returns isValid=true on the happy path", async () => { + const signer = buildSigner(); + mockedMulticall.mockResolvedValue([ + { status: "success", result: [0n, 0n] }, + { status: "success", result: 1_000_000n }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload, channelId } = buildDeposit(); + + const result = await scheme.verify(payload, makeRequirements()); + expect(result.isValid).toBe(true); + expect(result.payer).toBe(PAYER); + expect(result.extra?.channelId).toBe(channelId); + }); + + it("returns InsufficientBalance when payer balance < deposit amount", async () => { + const signer = buildSigner(); + mockedMulticall.mockResolvedValue([ + { status: "success", result: [0n, 0n] }, + { status: "success", result: 1n }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = buildDeposit(); + + const result = await scheme.verify(payload, makeRequirements()); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrInsufficientBalance); + }); + + it("returns InvalidReceiveAuthorizationSignature when verifyTypedData fails", async () => { + const signer = buildSigner({ verifyTypedData: vi.fn().mockResolvedValue(false) }); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = buildDeposit(); + + const result = await scheme.verify(payload, makeRequirements()); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrInvalidReceiveAuthorizationSignature); + }); + + it("returns ErrErc3009AuthorizationRequired when authorization is absent", async () => { + const signer = buildSigner(); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const dp: BatchSettlementDepositPayload = { + type: "deposit", + channelConfig: config, + voucher: { channelId, maxClaimableAmount: "1000", signature: "0xcafebabe" }, + deposit: { + amount: "10000", + authorization: {} as BatchSettlementDepositPayload["deposit"]["authorization"], + }, + }; + const result = await scheme.verify(envelopeDeposit(dp), makeRequirements()); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrErc3009AuthorizationRequired); + }); + + it("returns ErrMissingEip712Domain when extra lacks name/version", async () => { + const signer = buildSigner(); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = buildDeposit(); + const reqs = makeRequirements({ + extra: { receiverAuthorizer: RECEIVER_AUTHORIZER, assetTransferMethod: "eip3009" }, + }); + const result = await scheme.verify(payload, reqs); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrMissingEip712Domain); + }); + + it("returns ErrInvalidPayloadType when assetTransferMethod is not eip3009", async () => { + const signer = buildSigner(); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = buildDeposit(); + const reqs = makeRequirements({ + extra: { + name: "USDC", + version: "2", + receiverAuthorizer: RECEIVER_AUTHORIZER, + assetTransferMethod: "permit2", + }, + }); + const result = await scheme.verify(payload, reqs); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrInvalidPayloadType); + }); + + it("returns ErrValidBeforeExpired when validBefore is in the past", async () => { + const signer = buildSigner(); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = buildDeposit({ + authorization: { + erc3009Authorization: { + validAfter: "0", + validBefore: "1", + salt: "0x0000000000000000000000000000000000000000000000000000000000000001", + signature: "0xfeedface", + }, + }, + }); + const result = await scheme.verify(payload, makeRequirements()); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrValidBeforeExpired); + }); + + function buildPermit2Deposit( + overrides: Partial< + NonNullable + > = {}, + ): { payload: PaymentPayload; channelId: `0x${string}` } { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const now = Math.floor(Date.now() / 1000); + const authorization = { + from: PAYER, + permitted: { token: ASSET, amount: "10000" }, + spender: PERMIT2_DEPOSIT_COLLECTOR_ADDRESS, + nonce: "123", + deadline: String(now + 3600), + witness: { channelId }, + signature: "0xfeedface" as `0x${string}`, + ...overrides, + }; + const dp: BatchSettlementDepositPayload = { + type: "deposit", + channelConfig: config, + voucher: { channelId, maxClaimableAmount: "1000", signature: "0xcafebabe" }, + deposit: { + amount: "10000", + authorization: { permit2Authorization: authorization }, + }, + }; + return { payload: envelopeDeposit(dp), channelId }; + } + + it("accepts a Permit2 deposit and simulates with the Permit2 collector", async () => { + const readContract = vi.fn(async ({ functionName }: { functionName: string }) => { + if (functionName === "allowance") return 1_000_000n; + return undefined; + }); + const signer = buildSigner({ readContract }); + mockedMulticall.mockResolvedValue([ + { status: "success", result: [0n, 0n] }, + { status: "success", result: 1_000_000n }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = buildPermit2Deposit(); + + const result = await scheme.verify( + payload, + makeRequirements({ + extra: { + assetTransferMethod: "permit2", + name: "USDC", + version: "2", + receiverAuthorizer: RECEIVER_AUTHORIZER, + }, + }), + ); + + expect(result.isValid).toBe(true); + expect(readContract).toHaveBeenCalledWith( + expect.objectContaining({ + functionName: "deposit", + args: expect.arrayContaining([getAddress(PERMIT2_DEPOSIT_COLLECTOR_ADDRESS)]), + }), + ); + }); + + it("rejects Permit2 deposits with a wrong spender", async () => { + const signer = buildSigner(); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = buildPermit2Deposit({ + spender: "0x0000000000000000000000000000000000000001", + }); + + const result = await scheme.verify( + payload, + makeRequirements({ + extra: { + assetTransferMethod: "permit2", + name: "USDC", + version: "2", + receiverAuthorizer: RECEIVER_AUTHORIZER, + }, + }), + ); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrPermit2InvalidSpender); + }); + + it("rejects Permit2 deposits whose amount differs from deposit.amount", async () => { + const signer = buildSigner(); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = buildPermit2Deposit({ + permitted: { token: ASSET, amount: "9999" }, + }); + + const result = await scheme.verify( + payload, + makeRequirements({ + extra: { + assetTransferMethod: "permit2", + name: "USDC", + version: "2", + receiverAuthorizer: RECEIVER_AUTHORIZER, + }, + }), + ); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrPermit2AmountMismatch); + }); + + it("rejects Permit2 deposits without Permit2 allowance or sponsoring data", async () => { + const readContract = vi.fn(async ({ functionName }: { functionName: string }) => { + if (functionName === "allowance") return 1n; + return undefined; + }); + const signer = buildSigner({ readContract }); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const { payload } = buildPermit2Deposit(); + + const result = await scheme.verify( + payload, + makeRequirements({ + extra: { + assetTransferMethod: "permit2", + name: "USDC", + version: "2", + receiverAuthorizer: RECEIVER_AUTHORIZER, + }, + }), + ); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe(Errors.ErrPermit2AllowanceRequired); + }); +}); + +describe("BatchSettlementEvmScheme (Facilitator) — settle routing", () => { + const authorizer = buildAuthorizerSigner(); + + it("returns InvalidPayloadType for an unknown settle payload", async () => { + const scheme = new BatchSettlementEvmScheme(buildSigner(), authorizer); + const result = await scheme.settle(envelopeSettle({ unknown: true }), makeRequirements()); + expect(result.success).toBe(false); + expect(result.errorReason).toBe(Errors.ErrInvalidPayloadType); + }); + + it("dispatches deposit settle payloads via settleDeposit", async () => { + const signer = buildSigner(); + // verifyDeposit uses a 4-call batch; post-tx readChannelState uses 3 calls with a + // different shape — reusing the 4-tuple for the second batch mis-associates + // token balance with pendingWithdrawals and throws. + mockedMulticall + .mockResolvedValueOnce([ + { status: "success", result: [0n, 0n] }, + { status: "success", result: 1_000_000n }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]) + .mockResolvedValue([ + { status: "success", result: [10_000n, 0n] }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const now = Math.floor(Date.now() / 1000); + + const dp: BatchSettlementDepositPayload = { + type: "deposit", + channelConfig: config, + voucher: { channelId, maxClaimableAmount: "1000", signature: "0xcafebabe" }, + deposit: { + amount: "10000", + authorization: { + erc3009Authorization: { + validAfter: String(now - 600), + validBefore: String(now + 3600), + salt: "0x0000000000000000000000000000000000000000000000000000000000000001", + signature: "0xfeedface", + }, + }, + }, + }; + + const result = await scheme.settle(envelopeDeposit(dp), makeRequirements()); + expect(result.success).toBe(true); + expect(result.amount).toBe("10000"); + expect(result.extra).toMatchObject({ + channelState: { + channelId, + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: "0", + }, + }); + expect(signer.writeContract).toHaveBeenCalledWith( + expect.objectContaining({ + address: getAddress(BATCH_SETTLEMENT_ADDRESS), + functionName: "deposit", + }), + ); + }); + + it('rejects voucher-less type:"deposit" envelopes as unknown payload type', async () => { + const scheme = new BatchSettlementEvmScheme(buildSigner(), authorizer); + const config = buildChannelConfig(); + const now = Math.floor(Date.now() / 1000); + + const voucherLessDeposit = { + type: "deposit", + channelConfig: config, + deposit: { + amount: "10000", + authorization: { + erc3009Authorization: { + validAfter: String(now - 600), + validBefore: String(now + 3600), + salt: "0x0000000000000000000000000000000000000000000000000000000000000002", + signature: "0xfeedface", + }, + }, + }, + }; + + const result = await scheme.settle( + envelopeSettle(voucherLessDeposit as unknown as Record), + makeRequirements(), + ); + expect(result.success).toBe(false); + expect(result.errorReason).toBe(Errors.ErrInvalidPayloadType); + }); + + it("dispatches settle payloads via executeSettle", async () => { + const signer = buildSigner({ + waitForTransactionReceipt: vi.fn().mockResolvedValue({ + status: "success", + logs: [buildSettledLog({ amount: "4321" })], + }), + }); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const sp: BatchSettlementSettlePayload = { + type: "settle", + receiver: RECEIVER, + token: ASSET, + }; + const result = await scheme.settle( + envelopeSettle(sp as unknown as Record), + makeRequirements(), + ); + expect(result.success).toBe(true); + expect(result.amount).toBe("4321"); + expect(signer.writeContract).toHaveBeenCalledWith( + expect.objectContaining({ + functionName: "settle", + }), + ); + }); + + it("returns zero amount for no-op settle receipts without a Settled event", async () => { + const signer = buildSigner({ + waitForTransactionReceipt: vi.fn().mockResolvedValue({ status: "success", logs: [] }), + }); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const sp: BatchSettlementSettlePayload = { + type: "settle", + receiver: RECEIVER, + token: ASSET, + }; + const result = await scheme.settle( + envelopeSettle(sp as unknown as Record), + makeRequirements(), + ); + expect(result.success).toBe(true); + expect(result.amount).toBe("0"); + }); + + it("returns empty amount when settle receipt logs are unavailable", async () => { + const signer = buildSigner(); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const sp: BatchSettlementSettlePayload = { + type: "settle", + receiver: RECEIVER, + token: ASSET, + }; + const result = await scheme.settle( + envelopeSettle(sp as unknown as Record), + makeRequirements(), + ); + expect(result.success).toBe(true); + expect(result.amount).toBe(""); + }); + + it("dispatches claim payloads via executeClaimWithSignature", async () => { + const signer = buildSigner(); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const config = buildChannelConfig({ receiverAuthorizer: authorizer.address }); + const cp: BatchSettlementClaimPayload = { + type: "claim", + claims: [ + { + voucher: { channel: config, maxClaimableAmount: "1000" }, + signature: "0xcafe", + totalClaimed: "1000", + }, + ], + }; + const result = await scheme.settle( + envelopeSettle(cp as unknown as Record), + makeRequirements(), + ); + expect(result.success).toBe(true); + expect(result.amount).toBe(""); + expect(signer.writeContract).toHaveBeenCalledWith( + expect.objectContaining({ functionName: "claimWithSignature" }), + ); + }); + + it("returns AuthorizerAddressMismatch when claim authorizer doesn't match config", async () => { + const signer = buildSigner(); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const config = buildChannelConfig({ + receiverAuthorizer: "0x1111111111111111111111111111111111111111", + }); + const cp: BatchSettlementClaimPayload = { + type: "claim", + claims: [ + { + voucher: { channel: config, maxClaimableAmount: "1000" }, + signature: "0xcafe", + totalClaimed: "1000", + }, + ], + }; + const result = await scheme.settle( + envelopeSettle(cp as unknown as Record), + makeRequirements(), + ); + expect(result.success).toBe(false); + expect(result.errorReason).toBe(Errors.ErrAuthorizerAddressMismatch); + }); + + it("dispatches enriched refund payloads via executeRefundWithSignature", async () => { + const signer = buildSigner(); + mockedMulticall.mockResolvedValue([ + { status: "success", result: [10000n, 0n] }, + { status: "success", result: [0n, 0n] }, + { status: "success", result: 0n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const config = buildChannelConfig({ receiverAuthorizer: authorizer.address }); + const channelId = computeChannelId(config); + const rp: BatchSettlementEnrichedRefundPayload = { + type: "refund", + channelConfig: config, + voucher: { + channelId, + maxClaimableAmount: "0", + signature: "0xdead", + }, + amount: "9000", + refundNonce: "0", + claims: [], + }; + const result = await scheme.settle( + envelopeSettle(rp as unknown as Record), + makeRequirements(), + ); + expect(result.success).toBe(true); + expect(result.amount).toBe("9000"); + expect(result.extra).toMatchObject({ + channelState: { + channelId, + balance: "1000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: "1", + }, + }); + expect(mockedMulticall).toHaveBeenCalledTimes(1); + expect(signer.writeContract).toHaveBeenCalledWith( + expect.objectContaining({ functionName: "refundWithSignature" }), + ); + }); + + it("polls post-refund state when a withdrawal is pending", async () => { + const signer = buildSigner(); + mockedMulticall + .mockResolvedValueOnce([ + { status: "success", result: [10000n, 0n] }, + { status: "success", result: [5000n, 1234n] }, + { status: "success", result: 7n }, + ]) + .mockResolvedValueOnce([ + { status: "success", result: [8000n, 0n] }, + { status: "success", result: [3000n, 1234n] }, + { status: "success", result: 8n }, + ]); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const config = buildChannelConfig({ receiverAuthorizer: authorizer.address }); + const channelId = computeChannelId(config); + const rp: BatchSettlementEnrichedRefundPayload = { + type: "refund", + channelConfig: config, + voucher: { + channelId, + maxClaimableAmount: "0", + signature: "0xdead", + }, + amount: "2000", + refundNonce: "7", + claims: [], + }; + + const result = await scheme.settle( + envelopeSettle(rp as unknown as Record), + makeRequirements(), + ); + + expect(result.success).toBe(true); + expect(result.amount).toBe("2000"); + expect(result.extra).toMatchObject({ + channelState: { + channelId, + balance: "8000", + withdrawRequestedAt: 1234, + refundNonce: "8", + }, + }); + expect(mockedMulticall).toHaveBeenCalledTimes(2); + }); + + it("returns ErrSettleSimulationFailed when settle simulation reverts", async () => { + const signer = buildSigner({ + readContract: vi.fn().mockRejectedValue(new Error("revert")), + }); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const sp: BatchSettlementSettlePayload = { + type: "settle", + receiver: RECEIVER, + token: ASSET, + }; + const result = await scheme.settle( + envelopeSettle(sp as unknown as Record), + makeRequirements(), + ); + expect(result.success).toBe(false); + expect(result.errorReason).toBe(Errors.ErrSettleSimulationFailed); + }); + + it("returns ErrSettleTransactionFailed when settle receipt is not success", async () => { + const signer = buildSigner({ + waitForTransactionReceipt: vi.fn().mockResolvedValue({ status: "reverted" }), + }); + const scheme = new BatchSettlementEvmScheme(signer, authorizer); + const sp: BatchSettlementSettlePayload = { + type: "settle", + receiver: RECEIVER, + token: ASSET, + }; + const result = await scheme.settle( + envelopeSettle(sp as unknown as Record), + makeRequirements(), + ); + expect(result.success).toBe(false); + expect(result.errorReason).toBe(Errors.ErrSettleTransactionFailed); + }); +}); + +describe("BatchSettlementEvmScheme (Facilitator) — handler contract constants", () => { + it("exposes well-formed distinct contract addresses", () => { + const addrs = [ + BATCH_SETTLEMENT_ADDRESS, + ERC3009_DEPOSIT_COLLECTOR_ADDRESS, + PERMIT2_DEPOSIT_COLLECTOR_ADDRESS, + ]; + for (const a of addrs) { + expect(isAddress(a)).toBe(true); + } + expect(new Set(addrs.map(a => getAddress(a))).size).toBe(3); + }); +}); diff --git a/typescript/packages/mechanisms/evm/test/unit/batch-settlement/server.test.ts b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/server.test.ts new file mode 100644 index 0000000000..92cb87c8d9 --- /dev/null +++ b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/server.test.ts @@ -0,0 +1,1919 @@ +import { describe, it, expect, beforeEach, vi } from "vitest"; +import { BatchSettlementEvmScheme } from "../../../src/batch-settlement/server/scheme"; +import { BatchSettlementChannelManager } from "../../../src/batch-settlement/server/channelManager"; +import { InMemoryChannelStorage, type Channel } from "../../../src/batch-settlement/server/storage"; +import { computeChannelId as computeChannelIdForNetwork } from "../../../src/batch-settlement/utils"; +import { signVoucher } from "../../../src/batch-settlement/client/voucher"; +import type { + ChannelConfig, + AuthorizerSigner, + BatchSettlementVoucherPayload, + BatchSettlementDepositPayload, + BatchSettlementRefundPayload, +} from "../../../src/batch-settlement/types"; +import type { + PaymentRequirements, + PaymentPayload, + VerifyResponse, + SettleResponse, +} from "@x402/core/types"; +import type { FacilitatorClient } from "@x402/core/server"; +import { privateKeyToAccount } from "viem/accounts"; +import * as Errors from "../../../src/batch-settlement/errors"; + +function buildManager(scheme: BatchSettlementEvmScheme): BatchSettlementChannelManager { + return new BatchSettlementChannelManager({ + scheme, + facilitator: {} as FacilitatorClient, + receiver: RECEIVER, + token: ASSET_BASE_SEPOLIA, + network: NETWORK, + }); +} + +async function storeChannel( + storage: InMemoryChannelStorage, + channelId: string, + channel: Channel, +): Promise { + await storage.updateChannel(channelId, () => channel); +} + +async function deleteChannel(storage: InMemoryChannelStorage, channelId: string): Promise { + await storage.updateChannel(channelId, () => undefined); +} + +async function reservePending( + server: BatchSettlementEvmScheme, + paymentPayload: PaymentPayload, + requirements: PaymentRequirements, +): Promise { + const result = await server.schemeHooks.onBeforeVerify!({ + paymentPayload, + requirements, + } as never); + expect(result).toBeUndefined(); +} + +const PAYER = "0x70997970C51812dc3A010C7d01b50e0d17dc79C8" as `0x${string}`; +const RECEIVER = "0x9876543210987654321098765432109876543210" as `0x${string}`; +const RECEIVER_AUTHORIZER = "0x1111111111111111111111111111111111111111" as `0x${string}`; +const ASSET_BASE_SEPOLIA = "0x036CbD53842c5426634e7929541eC2318f3dCF7e" as `0x${string}`; +const NETWORK = "eip155:84532"; + +function computeChannelId(config: ChannelConfig): `0x${string}` { + return computeChannelIdForNetwork(config, NETWORK); +} + +function buildAuthorizerSigner(): AuthorizerSigner { + const account = privateKeyToAccount( + "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d", + ); + return { + address: account.address, + signTypedData: msg => + account.signTypedData({ + domain: msg.domain, + types: msg.types, + primaryType: msg.primaryType, + message: msg.message, + } as Parameters[0]), + }; +} + +function buildChannelConfig(overrides: Partial = {}): ChannelConfig { + return { + payer: PAYER, + payerAuthorizer: PAYER, + receiver: RECEIVER, + receiverAuthorizer: RECEIVER_AUTHORIZER, + token: ASSET_BASE_SEPOLIA, + withdrawDelay: 900, + salt: "0x0000000000000000000000000000000000000000000000000000000000000000", + ...overrides, + }; +} + +function buildVoucherPayload( + channelId: string, + maxClaimableAmount: string, + config: ChannelConfig, + signature: `0x${string}` = "0xdeadbeef", +): PaymentPayload { + const payload: BatchSettlementVoucherPayload = { + type: "voucher", + channelConfig: config, + voucher: { + channelId: channelId as `0x${string}`, + maxClaimableAmount, + signature, + }, + }; + return { + x402Version: 2, + accepted: makeRequirements(), + payload: payload as unknown as Record, + }; +} + +async function buildSignedVoucherPayload( + channelId: `0x${string}`, + maxClaimableAmount: string, + config: ChannelConfig, +): Promise { + const voucher = await signVoucher( + buildAuthorizerSigner(), + channelId, + maxClaimableAmount, + NETWORK, + ); + return buildVoucherPayload(channelId, maxClaimableAmount, config, voucher.signature); +} + +function buildRefundPayload( + channelId: string, + maxClaimableAmount: string, + config: ChannelConfig, + amount?: string, +): PaymentPayload { + const payload: BatchSettlementRefundPayload = { + type: "refund", + channelConfig: config, + voucher: { + channelId: channelId as `0x${string}`, + maxClaimableAmount, + signature: "0xdeadbeef", + }, + ...(amount !== undefined ? { amount } : {}), + }; + return { + x402Version: 2, + accepted: makeRequirements(), + payload: payload as unknown as Record, + }; +} + +function buildDepositPayload( + channelId: string, + config: ChannelConfig, + amount: string, + maxClaimable: string, +): PaymentPayload { + const payload: BatchSettlementDepositPayload = { + type: "deposit", + channelConfig: config, + voucher: { + channelId: channelId as `0x${string}`, + maxClaimableAmount: maxClaimable, + signature: "0xcafebabe", + }, + deposit: { + amount, + authorization: { + erc3009Authorization: { + validAfter: "0", + validBefore: "9999999999", + salt: "0x0000000000000000000000000000000000000000000000000000000000000001", + signature: "0xfeedbeef", + }, + }, + }, + }; + return { + x402Version: 2, + accepted: makeRequirements(), + payload: payload as unknown as Record, + }; +} + +function makeRequirements(overrides: Partial = {}): PaymentRequirements { + return { + scheme: "batch-settlement", + network: NETWORK, + amount: "1000", + asset: ASSET_BASE_SEPOLIA, + payTo: RECEIVER, + maxTimeoutSeconds: 3600, + extra: { receiverAuthorizer: RECEIVER_AUTHORIZER }, + ...overrides, + }; +} + +class CountingChannelStorage extends InMemoryChannelStorage { + readonly getCalls: string[] = []; + + override async get(channelId: string): Promise { + this.getCalls.push(channelId); + return super.get(channelId); + } +} + +describe("BatchSettlementEvmScheme — construction", () => { + it("uses an in-memory channel storage by default", () => { + const server = new BatchSettlementEvmScheme(RECEIVER); + expect(server.scheme).toBe("batch-settlement"); + expect(server.getStorage()).toBeInstanceOf(InMemoryChannelStorage); + expect(server.getReceiverAddress()).toBe(RECEIVER); + expect(server.getWithdrawDelay()).toBe(900); + expect(server.getOnchainStateTtlMs()).toBe(300_000); + expect(server.getReceiverAuthorizerSigner()).toBeUndefined(); + }); + + it("allows custom storage, withdrawDelay, and onchain state TTL", () => { + const storage = new InMemoryChannelStorage(); + const signer = buildAuthorizerSigner(); + const server = new BatchSettlementEvmScheme(RECEIVER, { + storage, + withdrawDelay: 1800, + onchainStateTtlMs: 45_000, + receiverAuthorizerSigner: signer, + }); + expect(server.getStorage()).toBe(storage); + expect(server.getWithdrawDelay()).toBe(1800); + expect(server.getOnchainStateTtlMs()).toBe(45_000); + expect(server.getReceiverAuthorizerSigner()).toBe(signer); + }); +}); + +describe("BatchSettlementEvmScheme — parsePrice", () => { + const server = new BatchSettlementEvmScheme(RECEIVER); + + it("converts $ strings to USDC base units on Base Sepolia", async () => { + const result = await server.parsePrice("$0.10", NETWORK); + expect(result.amount).toBe("100000"); + expect(result.asset).toBe(ASSET_BASE_SEPOLIA); + }); + + it("converts plain decimal strings", async () => { + const result = await server.parsePrice("0.50", NETWORK); + expect(result.amount).toBe("500000"); + }); + + it("converts numeric prices", async () => { + const result = await server.parsePrice(1, NETWORK); + expect(result.amount).toBe("1000000"); + }); + + it("returns AssetAmount as-is when an explicit asset is provided", async () => { + const result = await server.parsePrice( + { + amount: "12345", + asset: "0x1111111111111111111111111111111111111111", + extra: { foo: "bar" }, + }, + NETWORK, + ); + expect(result.amount).toBe("12345"); + expect(result.asset).toBe("0x1111111111111111111111111111111111111111"); + expect(result.extra).toEqual({ foo: "bar" }); + }); + + it("throws when AssetAmount is missing the asset address", async () => { + await expect(server.parsePrice({ amount: "100" } as never, NETWORK)).rejects.toThrow( + /Asset address must be specified/, + ); + }); + + it("throws on invalid money strings", async () => { + await expect(server.parsePrice("not-a-price!", NETWORK)).rejects.toThrow( + /Invalid money format/, + ); + }); + + it("uses a registered custom money parser when it returns a result", async () => { + const server2 = new BatchSettlementEvmScheme(RECEIVER); + server2.registerMoneyParser(async (amount, network) => { + if (network === NETWORK) { + return { + amount: (amount * 1_000_000_000_000_000_000).toString(), + asset: "0x2222222222222222222222222222222222222222", + extra: {}, + }; + } + return null; + }); + const result = await server2.parsePrice("1", NETWORK); + expect(result.amount).toBe("1000000000000000000"); + expect(result.asset).toBe("0x2222222222222222222222222222222222222222"); + }); + + it("falls back to default conversion when custom parser returns null", async () => { + const server2 = new BatchSettlementEvmScheme(RECEIVER); + server2.registerMoneyParser(async () => null); + const result = await server2.parsePrice("1", NETWORK); + expect(result.amount).toBe("1000000"); + }); +}); + +describe("BatchSettlementEvmScheme — enhancePaymentRequirements", () => { + const baseReqs = makeRequirements(); + + it("injects withdrawDelay, facilitator receiverAuthorizer, name, version", async () => { + const server = new BatchSettlementEvmScheme(RECEIVER, { withdrawDelay: 1800 }); + const enhanced = await server.enhancePaymentRequirements( + baseReqs, + { + x402Version: 2, + scheme: "batch-settlement", + network: NETWORK, + extra: { receiverAuthorizer: RECEIVER_AUTHORIZER }, + }, + [], + ); + + expect(enhanced.extra?.withdrawDelay).toBe(1800); + expect(enhanced.extra?.receiverAuthorizer).toBe(RECEIVER_AUTHORIZER); + expect(enhanced.extra?.name).toBe("USDC"); + expect(enhanced.extra?.version).toBe("2"); + }); + + it("throws when neither server nor facilitator provides receiverAuthorizer", async () => { + const server = new BatchSettlementEvmScheme(RECEIVER); + await expect( + server.enhancePaymentRequirements( + baseReqs, + { x402Version: 2, scheme: "batch-settlement", network: NETWORK }, + [], + ), + ).rejects.toThrow(/receiverAuthorizer/); + }); + + it("propagates receiver-authorizer from configured signer", async () => { + const signer = buildAuthorizerSigner(); + const server = new BatchSettlementEvmScheme(RECEIVER, { receiverAuthorizerSigner: signer }); + const enhanced = await server.enhancePaymentRequirements( + baseReqs, + { x402Version: 2, scheme: "batch-settlement", network: NETWORK }, + [], + ); + expect(enhanced.extra?.receiverAuthorizer).toBe(signer.address); + }); + + it("falls back to receiverAuthorizer from supportedKind.extra when no signer is configured", async () => { + const server = new BatchSettlementEvmScheme(RECEIVER); + const enhanced = await server.enhancePaymentRequirements( + baseReqs, + { + x402Version: 2, + scheme: "batch-settlement", + network: NETWORK, + extra: { receiverAuthorizer: "0xabcdefABCDef0000000000000000000000000001" }, + }, + [], + ); + expect(enhanced.extra?.receiverAuthorizer).toBe("0xaBCDEFABcdEf0000000000000000000000000001"); + }); + + it("preserves existing extra entries", async () => { + const server = new BatchSettlementEvmScheme(RECEIVER); + const enhanced = await server.enhancePaymentRequirements( + makeRequirements({ extra: { custom: "yes" } }), + { + x402Version: 2, + scheme: "batch-settlement", + network: NETWORK, + extra: { receiverAuthorizer: RECEIVER_AUTHORIZER }, + }, + [], + ); + expect(enhanced.extra?.custom).toBe("yes"); + }); + + it("preserves explicit assetTransferMethod from payment requirements", async () => { + const server = new BatchSettlementEvmScheme(RECEIVER); + const enhanced = await server.enhancePaymentRequirements( + makeRequirements({ extra: { assetTransferMethod: "permit2" } }), + { + x402Version: 2, + scheme: "batch-settlement", + network: NETWORK, + extra: { receiverAuthorizer: RECEIVER_AUTHORIZER }, + }, + [], + ); + + expect(enhanced.extra?.assetTransferMethod).toBe("permit2"); + }); +}); + +describe("BatchSettlementEvmScheme — onBeforeVerify", () => { + let server: BatchSettlementEvmScheme; + let storage: InMemoryChannelStorage; + + beforeEach(() => { + storage = new InMemoryChannelStorage(); + server = new BatchSettlementEvmScheme(RECEIVER, { storage }); + }); + + it("does nothing when payload is not a batch-settlement cumulative payload", async () => { + const result = await server.schemeHooks.onBeforeVerify!({ + paymentPayload: { + x402Version: 2, + accepted: makeRequirements(), + payload: { type: "other" }, + }, + requirements: makeRequirements(), + } as never); + expect(result).toBeUndefined(); + }); + + it("does nothing when no channel record is stored yet", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const result = await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildVoucherPayload(channelId, "1000", config), + requirements: makeRequirements(), + } as never); + expect(result).toBeUndefined(); + }); + + it("does nothing when client cumulative matches expected", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + onchainSyncedAt: 123, + lastRequestTimestamp: 0, + }); + + const result = await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildVoucherPayload(channelId, "2000", config), + requirements: makeRequirements({ amount: "1000" }), + } as never); + expect(result).toBeUndefined(); + }); + + it("locally verifies a fresh EOA-authorized voucher", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 2, + onchainSyncedAt: Date.now(), + lastRequestTimestamp: 0, + }); + + const result = (await server.schemeHooks.onBeforeVerify!({ + paymentPayload: await buildSignedVoucherPayload(channelId, "2000", config), + requirements: makeRequirements({ amount: "1000" }), + } as never)) as unknown as { skip: true; result: VerifyResponse }; + + expect(result?.skip).toBe(true); + expect(result.result).toMatchObject({ + isValid: true, + payer: PAYER, + extra: { + channelId, + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: "2", + }, + }); + expect((await storage.get(channelId))?.pendingRequest).toBeDefined(); + }); + + it("does not refresh onchain sync time after a local voucher verify", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const onchainSyncedAt = Date.now() - 1_000; + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + onchainSyncedAt, + lastRequestTimestamp: 0, + }); + + const paymentPayload = await buildSignedVoucherPayload(channelId, "2000", config); + const verifyResult = (await server.schemeHooks.onBeforeVerify!({ + paymentPayload, + requirements: makeRequirements({ amount: "1000" }), + } as never)) as unknown as { skip: true; result: VerifyResponse }; + + await server.schemeHooks.onAfterVerify!({ + paymentPayload, + requirements: makeRequirements({ amount: "1000" }), + result: verifyResult.result, + } as never); + + expect((await storage.get(channelId))?.onchainSyncedAt).toBe(onchainSyncedAt); + }); + + it("falls through to facilitator verification when mirrored onchain state is stale", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + onchainSyncedAt: Date.now() - server.getOnchainStateTtlMs() - 1, + lastRequestTimestamp: 0, + }); + + const result = await server.schemeHooks.onBeforeVerify!({ + paymentPayload: await buildSignedVoucherPayload(channelId, "2000", config), + requirements: makeRequirements({ amount: "1000" }), + } as never); + + expect(result).toBeUndefined(); + expect((await storage.get(channelId))?.pendingRequest).toBeDefined(); + }); + + it("falls through to facilitator verification for EIP-1271 vouchers", async () => { + const config = buildChannelConfig({ + payerAuthorizer: "0x0000000000000000000000000000000000000000", + }); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + onchainSyncedAt: Date.now(), + lastRequestTimestamp: 0, + }); + + const result = await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildVoucherPayload(channelId, "2000", config), + requirements: makeRequirements({ amount: "1000" }), + } as never); + + expect(result).toBeUndefined(); + }); + + it("rejects a locally invalid voucher signature without facilitator verification", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + onchainSyncedAt: Date.now(), + lastRequestTimestamp: 0, + }); + + const result = (await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildVoucherPayload(channelId, "2000", config), + requirements: makeRequirements({ amount: "1000" }), + } as never)) as unknown as { skip: true; result: VerifyResponse }; + + expect(result?.skip).toBe(true); + expect(result.result).toMatchObject({ + isValid: false, + invalidReason: Errors.ErrInvalidVoucherSignature, + }); + }); + + it("rejects locally when the voucher cumulative amount exceeds balance", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0x", + balance: "1500", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + onchainSyncedAt: Date.now(), + lastRequestTimestamp: 0, + }); + + const result = (await server.schemeHooks.onBeforeVerify!({ + paymentPayload: await buildSignedVoucherPayload(channelId, "2000", config), + requirements: makeRequirements({ amount: "1000" }), + } as never)) as unknown as { skip: true; result: VerifyResponse }; + + expect(result?.skip).toBe(true); + expect(result.result.invalidReason).toBe(Errors.ErrCumulativeExceedsBalance); + }); + + it("rejects locally when the voucher cumulative amount is already claimed", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0x", + balance: "10000", + totalClaimed: "2000", + withdrawRequestedAt: 0, + refundNonce: 0, + onchainSyncedAt: Date.now(), + lastRequestTimestamp: 0, + }); + + const result = (await server.schemeHooks.onBeforeVerify!({ + paymentPayload: await buildSignedVoucherPayload(channelId, "2000", config), + requirements: makeRequirements({ amount: "1000" }), + } as never)) as unknown as { skip: true; result: VerifyResponse }; + + expect(result?.skip).toBe(true); + expect(result.result.invalidReason).toBe(Errors.ErrCumulativeAmountBelowClaimed); + }); + + it("does not abort initial deposit payloads with no server channel state", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const result = await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildDepositPayload(channelId, config, "10000", "1500"), + requirements: makeRequirements({ amount: "1000" }), + } as never); + + expect(result).toBeUndefined(); + }); + + it("accepts a deposit payload whose maxClaimable equals chargedCumulativeAmount plus amount", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + onchainSyncedAt: 123, + lastRequestTimestamp: 0, + }); + + const result = await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildDepositPayload(channelId, config, "10000", "2000"), + requirements: makeRequirements({ amount: "1000" }), + } as never); + + expect(result).toBeUndefined(); + }); + + it("aborts a deposit payload whose maxClaimable does not match chargedCumulativeAmount plus amount", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + onchainSyncedAt: 123, + lastRequestTimestamp: 0, + }); + + const result = (await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildDepositPayload(channelId, config, "10000", "1500"), + requirements: makeRequirements({ amount: "1000" }), + } as never)) as { abort: true; reason: string }; + + expect(result?.abort).toBe(true); + expect(result?.reason).toBe(Errors.ErrCumulativeAmountMismatch); + }); + + it("does nothing for a refund voucher when no channel record exists (defers to facilitator for on-chain recovery)", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const result = await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildRefundPayload(channelId, "0", config), + requirements: makeRequirements({ amount: "0" }), + } as never); + + expect(result).toBeUndefined(); + }); + + it("accepts a zero-charge refund voucher whose maxClaimable equals chargedCumulativeAmount", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1500", + signedMaxClaimable: "1500", + signature: "0xabcd", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + + const result = await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildRefundPayload(channelId, "1500", config), + requirements: makeRequirements({ amount: "1000" }), + } as never); + + expect(result).toBeUndefined(); + }); + + it("aborts a refund voucher whose maxClaimable does not match chargedCumulativeAmount", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1500", + signedMaxClaimable: "1500", + signature: "0xabcd", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + + const result = (await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildRefundPayload(channelId, "2500", config), + requirements: makeRequirements({ amount: "0" }), + } as never)) as { abort: true; reason: string }; + + expect(result?.abort).toBe(true); + expect(result?.reason).toBe(Errors.ErrCumulativeAmountMismatch); + }); + + it("aborts with cumulative_amount_mismatch when client cumulative is wrong", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + + const reqs = makeRequirements({ amount: "1000" }); + const result = (await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildVoucherPayload(channelId, "500", config), + requirements: reqs, + } as never)) as { + abort: true; + reason: string; + }; + + expect(result?.abort).toBe(true); + expect(result?.reason).toBe(Errors.ErrCumulativeAmountMismatch); + expect(reqs.extra?.chargedCumulativeAmount).toBeUndefined(); + }); + + it("adds channel state to corrective payment-required accepts via fallback storage read", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + + const requirements = [makeRequirements({ amount: "1000" })]; + await server.enrichPaymentRequiredResponse({ + requirements, + paymentPayload: buildVoucherPayload(channelId, "500", config), + resourceInfo: { url: "https://example.com" }, + error: Errors.ErrCumulativeAmountMismatch, + paymentRequiredResponse: { + x402Version: 2, + resource: { url: "https://example.com" }, + accepts: requirements, + }, + }); + + expect(requirements[0].extra.channelState).toMatchObject({ + channelId, + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: "0", + chargedCumulativeAmount: "1000", + }); + expect(requirements[0].extra.voucherState).toMatchObject({ + signedMaxClaimable: "1000", + signature: "0xabcd", + }); + }); + + it("adds channel state to corrective payment-required accepts for deposit mismatches", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + + const requirements = [makeRequirements({ amount: "1000" })]; + await server.enrichPaymentRequiredResponse({ + requirements, + paymentPayload: buildDepositPayload(channelId, config, "10000", "1500"), + resourceInfo: { url: "https://example.com" }, + error: Errors.ErrCumulativeAmountMismatch, + paymentRequiredResponse: { + x402Version: 2, + resource: { url: "https://example.com" }, + accepts: requirements, + }, + }); + + expect(requirements[0].extra.channelState).toMatchObject({ + channelId, + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: "0", + chargedCumulativeAmount: "1000", + }); + expect(requirements[0].extra.voucherState).toMatchObject({ + signedMaxClaimable: "1000", + signature: "0xabcd", + }); + }); + + it("reuses the mismatch channel snapshot for corrective payment-required accepts", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const countingStorage = new CountingChannelStorage(); + const snapshotServer = new BatchSettlementEvmScheme(RECEIVER, { storage: countingStorage }); + const channel: Channel = { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }; + await storeChannel(countingStorage, channelId, channel); + + const paymentPayload = buildVoucherPayload(channelId, "500", config); + const result = (await snapshotServer.schemeHooks.onBeforeVerify!({ + paymentPayload, + requirements: makeRequirements({ amount: "1000" }), + } as never)) as { + abort: true; + reason: string; + }; + + expect(result?.abort).toBe(true); + expect(result?.reason).toBe(Errors.ErrCumulativeAmountMismatch); + expect(countingStorage.getCalls).toHaveLength(0); + + await deleteChannel(countingStorage, channelId); + const requirements = [makeRequirements({ amount: "1000" })]; + await snapshotServer.enrichPaymentRequiredResponse({ + requirements, + paymentPayload, + resourceInfo: { url: "https://example.com" }, + error: Errors.ErrCumulativeAmountMismatch, + paymentRequiredResponse: { + x402Version: 2, + resource: { url: "https://example.com" }, + accepts: requirements, + }, + }); + + expect(requirements[0].extra.channelState).toMatchObject({ + channelId, + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: "0", + chargedCumulativeAmount: "1000", + }); + expect(requirements[0].extra.voucherState).toMatchObject({ + signedMaxClaimable: "1000", + signature: "0xabcd", + }); + expect(countingStorage.getCalls).toHaveLength(0); + + const laterRequirements = [makeRequirements({ amount: "1000" })]; + await snapshotServer.enrichPaymentRequiredResponse({ + requirements: laterRequirements, + paymentPayload, + resourceInfo: { url: "https://example.com" }, + error: Errors.ErrCumulativeAmountMismatch, + paymentRequiredResponse: { + x402Version: 2, + resource: { url: "https://example.com" }, + accepts: laterRequirements, + }, + }); + + expect(laterRequirements[0].extra.channelState).toBeUndefined(); + expect(countingStorage.getCalls).toHaveLength(1); + }); + + it("rejects a live same-channel reservation as busy", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "0", + signedMaxClaimable: "0", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + + await reservePending( + server, + buildVoucherPayload(channelId, "1000", config), + makeRequirements({ amount: "1000" }), + ); + + const result = (await server.schemeHooks.onBeforeVerify!({ + paymentPayload: buildVoucherPayload(channelId, "1000", config), + requirements: makeRequirements({ amount: "1000" }), + } as never)) as { abort: true; reason: string }; + + expect(result?.abort).toBe(true); + expect(result?.reason).toBe(Errors.ErrChannelBusy); + }); + + it("replaces an expired pending reservation", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "0", + signedMaxClaimable: "0", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + pendingRequest: { + pendingId: "expired", + signedMaxClaimable: "1000", + expiresAt: Date.now() - 1, + }, + }); + + await reservePending( + server, + buildVoucherPayload(channelId, "1000", config), + makeRequirements({ amount: "1000" }), + ); + + const updated = await storage.get(channelId); + expect(updated?.pendingRequest?.pendingId).not.toBe("expired"); + }); +}); + +describe("BatchSettlementEvmScheme — pending cleanup hooks", () => { + let server: BatchSettlementEvmScheme; + let storage: InMemoryChannelStorage; + + beforeEach(() => { + storage = new InMemoryChannelStorage(); + server = new BatchSettlementEvmScheme(RECEIVER, { storage }); + }); + + it("clears a pending marker when facilitator verification returns invalid", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const payload = buildDepositPayload(channelId, config, "10000", "1000"); + await reservePending(server, payload, makeRequirements({ amount: "1000" })); + + await server.schemeHooks.onAfterVerify!({ + paymentPayload: payload, + requirements: makeRequirements({ amount: "1000" }), + result: { isValid: false } as VerifyResponse, + } as never); + + expect(await storage.get(channelId)).toBeUndefined(); + }); + + it("clears only its matching pending marker on verified-payment cancellation", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "0", + signedMaxClaimable: "0", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + const payload = buildVoucherPayload(channelId, "1000", config); + await reservePending(server, payload, makeRequirements({ amount: "1000" })); + const firstPendingId = (await storage.get(channelId))?.pendingRequest?.pendingId; + + await storage.updateChannel(channelId, current => + current + ? { + ...current, + pendingRequest: { + pendingId: "newer", + signedMaxClaimable: "1000", + expiresAt: Date.now() + 60_000, + }, + } + : current, + ); + + await server.schemeHooks.onVerifiedPaymentCanceled!({ + paymentPayload: payload, + requirements: makeRequirements({ amount: "1000" }), + declaredExtensions: {}, + reason: "handler_failed", + responseStatus: 500, + } as never); + + const updated = await storage.get(channelId); + expect(firstPendingId).toBeDefined(); + expect(updated?.pendingRequest?.pendingId).toBe("newer"); + }); + + it("clears a pending marker on verify and settle failures", async () => { + const config = buildChannelConfig(); + const verifyChannelId = computeChannelId(config); + const verifyPayload = buildVoucherPayload(verifyChannelId, "1000", config); + await reservePending(server, verifyPayload, makeRequirements({ amount: "1000" })); + + await server.schemeHooks.onVerifyFailure!({ + paymentPayload: verifyPayload, + requirements: makeRequirements({ amount: "1000" }), + declaredExtensions: {}, + error: new Error("verify failed"), + } as never); + expect((await storage.get(verifyChannelId))?.pendingRequest).toBeUndefined(); + + const settleConfig = buildChannelConfig({ + salt: "0x00000000000000000000000000000000000000000000000000000000000000aa", + }); + const settleChannelId = computeChannelId(settleConfig); + const settlePayload = buildVoucherPayload(settleChannelId, "1000", settleConfig); + await storeChannel(storage, settleChannelId, { + channelId: settleChannelId, + channelConfig: settleConfig, + chargedCumulativeAmount: "0", + signedMaxClaimable: "0", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + await reservePending(server, settlePayload, makeRequirements({ amount: "1000" })); + + await server.schemeHooks.onSettleFailure!({ + paymentPayload: settlePayload, + requirements: makeRequirements({ amount: "1000" }), + declaredExtensions: {}, + error: new Error("settle failed"), + } as never); + expect((await storage.get(settleChannelId))?.pendingRequest).toBeUndefined(); + }); +}); + +describe("BatchSettlementEvmScheme — onAfterVerify", () => { + let server: BatchSettlementEvmScheme; + let storage: InMemoryChannelStorage; + + beforeEach(() => { + storage = new InMemoryChannelStorage(); + server = new BatchSettlementEvmScheme(RECEIVER, { storage }); + }); + + it("creates a channel record from a deposit payload after a successful verify", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const paymentPayload = buildDepositPayload(channelId, config, "10000", "1000"); + const requirements = makeRequirements({ amount: "1000" }); + await reservePending(server, paymentPayload, requirements); + const result: VerifyResponse = { + isValid: true, + payer: PAYER, + extra: { balance: "10000", totalClaimed: "0", refundNonce: "0" }, + } as VerifyResponse; + + await server.schemeHooks.onAfterVerify!({ + paymentPayload, + requirements, + result, + } as never); + + const channel = await storage.get(channelId); + expect(channel?.balance).toBe("10000"); + expect(channel?.signedMaxClaimable).toBe("1000"); + expect(channel?.signature).toBe("0xcafebabe"); + expect(channel?.onchainSyncedAt).toBeGreaterThan(0); + }); + + it("does not create channel record when result.isValid is false", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await server.schemeHooks.onAfterVerify!({ + paymentPayload: buildVoucherPayload(channelId, "1000", config), + requirements: makeRequirements(), + result: { isValid: false } as VerifyResponse, + } as never); + expect(await storage.get(channelId)).toBeUndefined(); + }); + + it("returns a skipHandler directive for a refund voucher", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const paymentPayload = buildRefundPayload(channelId, "0", config); + const requirements = makeRequirements({ amount: "0" }); + await reservePending(server, paymentPayload, requirements); + const result: VerifyResponse = { + isValid: true, + payer: PAYER, + extra: { balance: "10000", totalClaimed: "0", refundNonce: "0" }, + } as VerifyResponse; + + const directive = await server.schemeHooks.onAfterVerify!({ + paymentPayload, + requirements, + result, + } as never); + + expect(directive).toBeDefined(); + expect(directive!.skipHandler).toBe(true); + expect(directive!.response?.contentType).toBe("application/json"); + expect((directive!.response?.body as { message: string }).message).toBe("Refund acknowledged"); + expect((directive!.response?.body as { channelId: string }).channelId).toBe(channelId); + }); + + it("does not return a skipHandler directive for a non-refund voucher", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const paymentPayload = buildVoucherPayload(channelId, "1000", config); + const requirements = makeRequirements({ amount: "1000" }); + await reservePending(server, paymentPayload, requirements); + const result: VerifyResponse = { + isValid: true, + payer: PAYER, + extra: { balance: "10000", totalClaimed: "1000", refundNonce: "0" }, + } as VerifyResponse; + + const directive = await server.schemeHooks.onAfterVerify!({ + paymentPayload, + requirements, + result, + } as never); + + expect(directive).toBeUndefined(); + }); +}); + +describe("BatchSettlementEvmScheme — onBeforeSettle", () => { + let server: BatchSettlementEvmScheme; + let storage: InMemoryChannelStorage; + + beforeEach(() => { + storage = new InMemoryChannelStorage(); + server = new BatchSettlementEvmScheme(RECEIVER, { storage }); + }); + + it("aborts a voucher payload when no channel record exists", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const result = (await server.schemeHooks.onBeforeSettle!({ + paymentPayload: buildVoucherPayload(channelId, "1000", config), + requirements: makeRequirements({ amount: "1000" }), + } as never)) as { abort: true; reason: string }; + expect(result?.abort).toBe(true); + expect(result?.reason).toBe(Errors.ErrMissingChannel); + }); + + it("aborts when charged exceeds the signed cap", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "900", + signedMaxClaimable: "1000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + const paymentPayload = buildVoucherPayload(channelId, "950", config); + await reservePending(server, paymentPayload, makeRequirements({ amount: "50" })); + + const result = (await server.schemeHooks.onBeforeSettle!({ + paymentPayload, + requirements: makeRequirements({ amount: "500" }), + } as never)) as { abort: true; reason: string }; + expect(result?.abort).toBe(true); + expect(result?.reason).toBe(Errors.ErrChargeExceedsSignedCumulative); + }); + + it("returns skip+result for a normal voucher and updates channel record", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "0", + signedMaxClaimable: "0", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + onchainSyncedAt: 123, + lastRequestTimestamp: 0, + }); + + const paymentPayload = buildVoucherPayload(channelId, "1000", config); + await reservePending(server, paymentPayload, makeRequirements({ amount: "1000" })); + + const result = (await server.schemeHooks.onBeforeSettle!({ + paymentPayload, + requirements: makeRequirements({ amount: "1000" }), + } as never)) as { skip: true; result: SettleResponse }; + + expect(result?.skip).toBe(true); + expect(result?.result.success).toBe(true); + expect(Object.keys(result?.result ?? {}).slice(0, 5)).toEqual([ + "success", + "payer", + "transaction", + "network", + "amount", + ]); + expect(result?.result.amount).toBe(""); + expect(result?.result.extra?.chargedAmount).toBe("1000"); + expect(result?.result.extra?.channelState).toMatchObject({ + channelId, + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: "0", + chargedCumulativeAmount: "1000", + }); + + const updated = await storage.get(channelId); + expect(updated?.chargedCumulativeAmount).toBe("1000"); + expect(updated?.signedMaxClaimable).toBe("1000"); + expect(updated?.onchainSyncedAt).toBe(123); + }); + + it("enriches a zero-charge refund voucher into a full refundWithSignature payload", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "500", + signedMaxClaimable: "500", + signature: "0xdeadbeef", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 1, + lastRequestTimestamp: 0, + }); + + // Zero-charge voucher: maxClaimableAmount equals the existing chargedCumulativeAmount. + const payload = buildRefundPayload(channelId, "500", config); + await reservePending(server, payload, makeRequirements({ amount: "0" })); + const ret = await server.schemeHooks.onBeforeSettle!({ + paymentPayload: payload, + requirements: makeRequirements({ amount: "0" }), + } as never); + expect(ret).toBeUndefined(); + + const enrichment = await server.enrichSettlementPayload({ + paymentPayload: payload, + requirements: makeRequirements({ amount: "0" }), + } as never); + expect(enrichment?.amount).toBe("9500"); + expect(enrichment?.refundNonce).toBe("1"); + }); + + it("recovers a refund voucher channel record from facilitator extras when local state was lost", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + + // Local server state is empty (channel record loss scenario). + expect(await storage.get(channelId)).toBeUndefined(); + + // 1. handleBeforeVerify must not abort — it should defer to the facilitator. + const refundPayload = buildRefundPayload(channelId, "1500", config); + await reservePending(server, refundPayload, makeRequirements({ amount: "0" })); + + // 2. handleAfterVerify rebuilds the channel record from on-chain snapshot returned by the facilitator. + const verifyResult: VerifyResponse = { + isValid: true, + payer: PAYER, + extra: { balance: "10000", totalClaimed: "1500", refundNonce: "3" }, + } as VerifyResponse; + await server.schemeHooks.onAfterVerify!({ + paymentPayload: refundPayload, + requirements: makeRequirements({ amount: "0" }), + result: verifyResult, + } as never); + const recovered = await storage.get(channelId); + expect(recovered).toBeDefined(); + expect(recovered?.balance).toBe("10000"); + expect(recovered?.totalClaimed).toBe("1500"); + expect(recovered?.chargedCumulativeAmount).toBe("1500"); + expect(recovered?.refundNonce).toBe(3); + + // 3. Settlement enrichment builds a refundWithSignature payload with amount = balance - totalClaimed. + const settleRet = await server.schemeHooks.onBeforeSettle!({ + paymentPayload: refundPayload, + requirements: makeRequirements({ amount: "0" }), + } as never); + expect(settleRet).toBeUndefined(); + + const enrichment = await server.enrichSettlementPayload({ + paymentPayload: refundPayload, + requirements: makeRequirements({ amount: "0" }), + } as never); + expect(enrichment?.amount).toBe("8500"); + expect(enrichment?.refundNonce).toBe("3"); + }); + + it("aborts a recovered refund voucher with refund_no_balance when channel is fully drained", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + + // Local state is empty; on-chain shows the channel was already drained (balance == totalClaimed). + const verifyResult: VerifyResponse = { + isValid: true, + payer: PAYER, + extra: { balance: "61800", totalClaimed: "61800", refundNonce: "1" }, + } as VerifyResponse; + const settlePayload = buildRefundPayload(channelId, "61800", config); + await reservePending(server, settlePayload, makeRequirements({ amount: "0" })); + await server.schemeHooks.onAfterVerify!({ + paymentPayload: settlePayload, + requirements: makeRequirements({ amount: "0" }), + result: verifyResult, + } as never); + + const ret = await server.schemeHooks.onBeforeSettle!({ + paymentPayload: settlePayload, + requirements: makeRequirements({ amount: "0" }), + } as never); + expect(ret).toBeUndefined(); + + await expect( + server.enrichSettlementPayload({ + paymentPayload: settlePayload, + requirements: makeRequirements({ amount: "0" }), + } as never), + ).rejects.toThrow(Errors.ErrRefundNoBalance); + }); + + it("honors refund amount on a partial refund payload", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "500", + signedMaxClaimable: "500", + signature: "0xdeadbeef", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + + const payload = buildRefundPayload(channelId, "500", config, "1000"); + await reservePending(server, payload, makeRequirements({ amount: "0" })); + + const ret = await server.schemeHooks.onBeforeSettle!({ + paymentPayload: payload, + requirements: makeRequirements({ amount: "0" }), + } as never); + expect(ret).toBeUndefined(); + + const enrichment = await server.enrichSettlementPayload({ + paymentPayload: payload, + requirements: makeRequirements({ amount: "0" }), + } as never); + expect(enrichment?.amount).toBeUndefined(); + expect(enrichment?.refundNonce).toBe("0"); + }); +}); + +describe("BatchSettlementEvmScheme — onAfterSettle", () => { + let server: BatchSettlementEvmScheme; + let storage: InMemoryChannelStorage; + + beforeEach(() => { + storage = new InMemoryChannelStorage(); + server = new BatchSettlementEvmScheme(RECEIVER, { storage }); + }); + + it("updates channel record and exposes deposit response enrichment", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const payload = buildDepositPayload(channelId, config, "10000", "1000"); + await reservePending(server, payload, makeRequirements({ amount: "1000" })); + const result: SettleResponse = { + success: true, + transaction: "0xtx", + network: NETWORK, + payer: PAYER, + extra: { + channelState: { + channelId, + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: "0", + }, + }, + } as SettleResponse; + + await server.schemeHooks.onAfterSettle!({ + paymentPayload: payload, + requirements: makeRequirements({ amount: "1000" }), + result, + } as never); + + const channel = await storage.get(channelId); + expect(channel?.chargedCumulativeAmount).toBe("1000"); + expect(channel?.balance).toBe("10000"); + expect(channel?.onchainSyncedAt).toBeGreaterThan(0); + expect((result.extra as Record).chargedCumulativeAmount).toBeUndefined(); + + const enrichment = await server.enrichSettlementResponse({ + paymentPayload: payload, + requirements: makeRequirements({ amount: "1000" }), + result, + } as never); + expect(enrichment).toEqual({ + channelState: { + chargedCumulativeAmount: "1000", + }, + chargedAmount: "1000", + }); + }); + + it("deletes channel record and exposes refund response enrichment after a full refund", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const channel: Channel = { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }; + await storeChannel(storage, channelId, channel); + + const refundPayload = { + x402Version: 2, + scheme: "batch-settlement", + network: NETWORK, + payload: { + type: "refund", + channelConfig: config, + voucher: { + channelId: channelId as `0x${string}`, + maxClaimableAmount: "1000", + signature: "0xabcd", + }, + amount: "9000", + refundNonce: "0", + claims: [ + { + voucher: { channel: config, maxClaimableAmount: "1000" }, + signature: "0xabcd" as `0x${string}`, + totalClaimed: "1000", + }, + ], + } as unknown as Record, + } as unknown as PaymentPayload; + await reservePending(server, refundPayload, makeRequirements({ amount: "0" })); + server.rememberChannelSnapshot(refundPayload, channel); + + const result: SettleResponse = { + success: true, + transaction: "0xref", + network: NETWORK, + payer: PAYER, + extra: { + channelState: { + channelId, + balance: "1000", + totalClaimed: "1000", + withdrawRequestedAt: 0, + refundNonce: "1", + }, + }, + } as SettleResponse; + + await server.schemeHooks.onAfterSettle!({ + paymentPayload: refundPayload, + requirements: makeRequirements(), + result, + } as never); + + expect(await storage.get(channelId)).toBeUndefined(); + expect((result.extra as Record).refund).toBeUndefined(); + + const enrichment = await server.enrichSettlementResponse({ + paymentPayload: refundPayload, + requirements: makeRequirements(), + result, + } as never); + expect(enrichment).toEqual({ + channelState: { + chargedCumulativeAmount: "1000", + }, + }); + }); + + it("retains channel record and increments refundNonce on a partial refundWithSignature", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + const channel: Channel = { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 2, + lastRequestTimestamp: 0, + }; + await storeChannel(storage, channelId, channel); + + const refundPayload = { + x402Version: 2, + scheme: "batch-settlement", + network: NETWORK, + payload: { + type: "refund", + channelConfig: config, + voucher: { + channelId: channelId as `0x${string}`, + maxClaimableAmount: "1000", + signature: "0xabcd", + }, + amount: "2000", + refundNonce: "2", + claims: [ + { + voucher: { channel: config, maxClaimableAmount: "1000" }, + signature: "0xabcd" as `0x${string}`, + totalClaimed: "1000", + }, + ], + } as unknown as Record, + } as unknown as PaymentPayload; + await reservePending(server, refundPayload, makeRequirements({ amount: "0" })); + server.rememberChannelSnapshot(refundPayload, channel); + + const result: SettleResponse = { + success: true, + transaction: "0xref", + network: NETWORK, + payer: PAYER, + extra: { + channelState: { + channelId, + balance: "8000", + totalClaimed: "1000", + withdrawRequestedAt: 0, + refundNonce: "3", + }, + refundedAmount: "2000", + }, + } as SettleResponse; + + await server.schemeHooks.onAfterSettle!({ + paymentPayload: refundPayload, + requirements: makeRequirements(), + result, + } as never); + + const updated = await storage.get(channelId); + expect(updated).toBeDefined(); + expect(updated?.balance).toBe("8000"); + expect(updated?.refundNonce).toBe(3); + expect(updated?.onchainSyncedAt).toBeGreaterThan(0); + expect((result.extra as Record).refundedAmount).toBe("2000"); + + const enrichment = await server.enrichSettlementResponse({ + paymentPayload: refundPayload, + requirements: makeRequirements(), + result, + } as never); + expect(enrichment).toEqual({ + channelState: { + chargedCumulativeAmount: "1000", + }, + }); + }); + + it("does not modify state when result.success is false", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await server.schemeHooks.onAfterSettle!({ + paymentPayload: buildDepositPayload(channelId, config, "10000", "1000"), + requirements: makeRequirements(), + result: { success: false } as SettleResponse, + } as never); + expect(await storage.get(channelId)).toBeUndefined(); + }); +}); + +describe("BatchSettlementChannelManager — getClaimableVouchers", () => { + let server: BatchSettlementEvmScheme; + let manager: BatchSettlementChannelManager; + let storage: InMemoryChannelStorage; + + beforeEach(() => { + storage = new InMemoryChannelStorage(); + server = new BatchSettlementEvmScheme(RECEIVER, { storage }); + manager = buildManager(server); + }); + + it("returns [] when no channel records exist", async () => { + expect(await manager.getClaimableVouchers()).toEqual([]); + }); + + it("filters out channel records that have nothing to claim", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "1000", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: Date.now(), + }); + expect(await manager.getClaimableVouchers()).toEqual([]); + }); + + it("returns claimable vouchers when charged > totalClaimed", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "5000", + signedMaxClaimable: "5000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "1000", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: Date.now(), + }); + + const claims = await manager.getClaimableVouchers(); + expect(claims).toHaveLength(1); + expect(claims[0].voucher.maxClaimableAmount).toBe("5000"); + expect(claims[0].totalClaimed).toBe("5000"); + expect(claims[0].signature).toBe("0xabcd"); + expect(claims[0].voucher.channel).toEqual(config); + }); + + it("respects idleSecs filter", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "5000", + signedMaxClaimable: "5000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "1000", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: Date.now(), + }); + + expect(await manager.getClaimableVouchers({ idleSecs: 60 })).toEqual([]); + }); + + it("claims an older voucher while preserving newer pending request state", async () => { + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "5000", + signedMaxClaimable: "5000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "1000", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: Date.now(), + pendingRequest: { + pendingId: "pending", + signedMaxClaimable: "6000", + expiresAt: Date.now() + 60_000, + }, + }); + const facilitator = { + settle: vi.fn(async () => ({ + success: true, + transaction: "0xclaim", + })), + } as unknown as FacilitatorClient; + const claimManager = new BatchSettlementChannelManager({ + scheme: server, + facilitator, + receiver: RECEIVER, + token: ASSET_BASE_SEPOLIA, + network: NETWORK, + }); + + const results = await claimManager.claim(); + + expect(results).toEqual([{ vouchers: 1, transaction: "0xclaim" }]); + const updated = await storage.get(channelId); + expect(updated?.totalClaimed).toBe("5000"); + expect(updated?.pendingRequest?.pendingId).toBe("pending"); + }); +}); + +describe("BatchSettlementChannelManager — refund pending channels", () => { + it("skips channels with live pending requests", async () => { + const storage = new InMemoryChannelStorage(); + const server = new BatchSettlementEvmScheme(RECEIVER, { storage }); + const facilitator = { + settle: vi.fn(async () => ({ + success: true, + transaction: "0xref", + })), + } as unknown as FacilitatorClient; + const manager = new BatchSettlementChannelManager({ + scheme: server, + facilitator, + receiver: RECEIVER, + token: ASSET_BASE_SEPOLIA, + network: NETWORK, + }); + + const config = buildChannelConfig(); + const channelId = computeChannelId(config); + await storeChannel(storage, channelId, { + channelId, + channelConfig: config, + chargedCumulativeAmount: "1000", + signedMaxClaimable: "1000", + signature: "0xabcd", + balance: "10000", + totalClaimed: "1000", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + pendingRequest: { + pendingId: "pending", + signedMaxClaimable: "1000", + expiresAt: Date.now() + 60_000, + }, + }); + + const result = await manager.refund(); + + expect(result).toEqual([]); + expect(facilitator.settle).not.toHaveBeenCalled(); + expect(await storage.get(channelId)).toBeDefined(); + }); +}); + +describe("BatchSettlementChannelManager — getWithdrawalPendingSessions", () => { + it("returns channel records with withdrawRequestedAt > 0", async () => { + const storage = new InMemoryChannelStorage(); + const server = new BatchSettlementEvmScheme(RECEIVER, { storage }); + const manager = buildManager(server); + + const config1 = buildChannelConfig(); + const id1 = computeChannelId(config1); + const config2 = buildChannelConfig({ + salt: "0x0000000000000000000000000000000000000000000000000000000000000099", + }); + const id2 = computeChannelId(config2); + + await storeChannel(storage, id1, { + channelId: id1, + channelConfig: config1, + chargedCumulativeAmount: "0", + signedMaxClaimable: "0", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + await storeChannel(storage, id2, { + channelId: id2, + channelConfig: config2, + chargedCumulativeAmount: "0", + signedMaxClaimable: "0", + signature: "0x", + balance: "10000", + totalClaimed: "0", + withdrawRequestedAt: 12345, + refundNonce: 0, + lastRequestTimestamp: 0, + }); + + const result = await manager.getWithdrawalPendingSessions(); + expect(result).toHaveLength(1); + expect(result[0].channelId).toBe(id2); + }); +}); diff --git a/typescript/packages/mechanisms/evm/test/unit/batch-settlement/storage.test.ts b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/storage.test.ts new file mode 100644 index 0000000000..21e968f843 --- /dev/null +++ b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/storage.test.ts @@ -0,0 +1,429 @@ +import { describe, it, expect, beforeEach } from "vitest"; +import { InMemoryChannelStorage, type Channel } from "../../../src/batch-settlement/server/storage"; +import { + RedisChannelStorage, + type RedisChannelStorageClient, + type RedisEvalOptions, + type RedisScanOptions, + type RedisSetOptions, +} from "../../../src/batch-settlement/server/redisStorage"; +import { + InMemoryClientChannelStorage, + type BatchSettlementClientContext, +} from "../../../src/batch-settlement/client/storage"; +import type { ChannelConfig } from "../../../src/batch-settlement/types"; + +const CHANNEL_CONFIG: ChannelConfig = { + payer: "0x1234567890123456789012345678901234567890", + payerAuthorizer: "0x1234567890123456789012345678901234567890", + receiver: "0x9876543210987654321098765432109876543210", + receiverAuthorizer: "0x0000000000000000000000000000000000000000", + token: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + withdrawDelay: 900, + salt: "0x0000000000000000000000000000000000000000000000000000000000000000", +}; + +const CHANNEL_ID = "0xabc1230000000000000000000000000000000000000000000000000000000001"; + +const buildSession = (overrides: Partial = {}): Channel => ({ + channelId: CHANNEL_ID, + channelConfig: CHANNEL_CONFIG, + chargedCumulativeAmount: "0", + signedMaxClaimable: "0", + signature: "0x", + balance: "10000000", + totalClaimed: "0", + withdrawRequestedAt: 0, + refundNonce: 0, + lastRequestTimestamp: 0, + ...overrides, +}); + +describe("InMemoryChannelStorage", () => { + let storage: InMemoryChannelStorage; + + beforeEach(() => { + storage = new InMemoryChannelStorage(); + }); + + describe("get/updateChannel", () => { + it("returns undefined when no session exists", async () => { + expect(await storage.get(CHANNEL_ID)).toBeUndefined(); + }); + + it("stores and retrieves a session", async () => { + const session = buildSession({ chargedCumulativeAmount: "1000" }); + await storage.updateChannel(CHANNEL_ID, () => session); + expect(await storage.get(CHANNEL_ID)).toEqual(session); + }); + + it("treats channelId case-insensitively", async () => { + const session = buildSession({ chargedCumulativeAmount: "500" }); + await storage.updateChannel(CHANNEL_ID.toUpperCase(), () => session); + expect(await storage.get(CHANNEL_ID.toLowerCase())).toEqual(session); + }); + + it("overwrites a session on subsequent update", async () => { + await storage.updateChannel(CHANNEL_ID, () => buildSession({ chargedCumulativeAmount: "1" })); + await storage.updateChannel(CHANNEL_ID, () => buildSession({ chargedCumulativeAmount: "2" })); + const got = await storage.get(CHANNEL_ID); + expect(got?.chargedCumulativeAmount).toBe("2"); + }); + + it("deletes a session", async () => { + await storage.updateChannel(CHANNEL_ID, () => buildSession()); + await storage.updateChannel(CHANNEL_ID, () => undefined); + expect(await storage.get(CHANNEL_ID)).toBeUndefined(); + }); + + it("delete is a no-op when nothing is stored", async () => { + await expect(storage.updateChannel(CHANNEL_ID, () => undefined)).resolves.toEqual({ + channel: undefined, + status: "unchanged", + }); + }); + }); + + describe("list", () => { + it("returns [] for an empty storage", async () => { + expect(await storage.list()).toEqual([]); + }); + + it("returns all stored sessions", async () => { + const id1 = "0x1111111111111111111111111111111111111111111111111111111111111111"; + const id2 = "0x2222222222222222222222222222222222222222222222222222222222222222"; + await storage.updateChannel(id1, () => buildSession({ channelId: id1 })); + await storage.updateChannel(id2, () => buildSession({ channelId: id2 })); + const all = await storage.list(); + expect(all).toHaveLength(2); + expect(all.map(s => s.channelId).sort()).toEqual([id1, id2].sort()); + }); + }); + + describe("updateChannel", () => { + it("inserts a new session when none exists", async () => { + const session = buildSession({ chargedCumulativeAmount: "100" }); + const result = await storage.updateChannel(CHANNEL_ID, () => session); + expect(result).toEqual({ channel: session, status: "updated" }); + expect(await storage.get(CHANNEL_ID)).toEqual(session); + }); + + it("updates from the current stored value", async () => { + await storage.updateChannel(CHANNEL_ID, () => + buildSession({ chargedCumulativeAmount: "500" }), + ); + const updated = buildSession({ chargedCumulativeAmount: "750" }); + const result = await storage.updateChannel(CHANNEL_ID, current => + current?.chargedCumulativeAmount === "500" ? updated : current, + ); + expect(result.status).toBe("updated"); + expect((await storage.get(CHANNEL_ID))?.chargedCumulativeAmount).toBe("750"); + }); + + it("can leave the channel unchanged", async () => { + await storage.updateChannel(CHANNEL_ID, () => + buildSession({ chargedCumulativeAmount: "500" }), + ); + const updated = buildSession({ chargedCumulativeAmount: "750" }); + const result = await storage.updateChannel(CHANNEL_ID, current => + current?.chargedCumulativeAmount === "499" ? updated : current, + ); + expect(result.status).toBe("unchanged"); + expect((await storage.get(CHANNEL_ID))?.chargedCumulativeAmount).toBe("500"); + }); + + it("serializes concurrent updateChannel mutations", async () => { + await storage.updateChannel(CHANNEL_ID, () => buildSession({ chargedCumulativeAmount: "0" })); + const winner = buildSession({ chargedCumulativeAmount: "100" }); + const loser = buildSession({ chargedCumulativeAmount: "200" }); + + const [a, b] = await Promise.all([ + storage.updateChannel(CHANNEL_ID, current => + current?.chargedCumulativeAmount === "0" ? winner : current, + ), + storage.updateChannel(CHANNEL_ID, current => + current?.chargedCumulativeAmount === "0" ? loser : current, + ), + ]); + + expect([a, b].filter(result => result.status === "updated")).toHaveLength(1); + const final = await storage.get(CHANNEL_ID); + expect(["100", "200"]).toContain(final?.chargedCumulativeAmount); + }); + }); +}); + +type RedisValue = { + expiresAt?: number; + value: string; +}; + +class MockRedisClient implements RedisChannelStorageClient { + readonly store = new Map(); + updateConflicts = 0; + nextChannelGetDelay: Deferred | undefined; + nextUpdateEvalDelay: Deferred | undefined; + + async get(key: string): Promise { + await this.maybeDelayChannelGet(key); + this.expireKey(key); + return this.store.get(key)?.value ?? null; + } + + async set(key: string, value: string, options?: RedisSetOptions): Promise { + this.expireKey(key); + if (options?.NX && this.store.has(key)) { + return null; + } + + this.store.set(key, { + value, + ...(options?.PX ? { expiresAt: Date.now() + options.PX } : {}), + }); + return "OK"; + } + + async del(key: string): Promise { + this.expireKey(key); + return this.store.delete(key) ? 1 : 0; + } + + async eval(script: string, options: RedisEvalOptions): Promise { + const [key] = options.keys; + this.expireKey(key); + if (!script.includes("expectedExists")) { + throw new Error("Unsupported Redis script"); + } + + if (this.nextUpdateEvalDelay) { + const delay = this.nextUpdateEvalDelay; + this.nextUpdateEvalDelay = undefined; + await delay.promise; + } + + const [expectedExists, expected, operation, nextValue] = options.arguments; + const current = this.store.get(key); + const matches = expectedExists === "0" ? current === undefined : current?.value === expected; + + if (!matches) { + this.updateConflicts += 1; + return [0, current?.value ?? null]; + } + + if (operation === "delete") { + this.store.delete(key); + return [1, null]; + } + + if (operation === "set") { + this.store.set(key, { value: nextValue }); + return [1, nextValue]; + } + + if (operation === "keep") { + return [1, current?.value ?? null]; + } + + throw new Error("Unsupported Redis update operation"); + } + + async *scanIterator(options: RedisScanOptions): AsyncIterable { + const prefix = options.MATCH?.replace(/\*$/, "") ?? ""; + this.expireAll(); + yield [...this.store.keys()].filter(key => key.startsWith(prefix)); + } + + private expireAll() { + for (const key of this.store.keys()) { + this.expireKey(key); + } + } + + private expireKey(key: string) { + const value = this.store.get(key); + if (value?.expiresAt && value.expiresAt <= Date.now()) { + this.store.delete(key); + } + } + + private async maybeDelayChannelGet(key: string) { + if (key.endsWith(":lock") || !this.nextChannelGetDelay) return; + const delay = this.nextChannelGetDelay; + this.nextChannelGetDelay = undefined; + await delay.promise; + } +} + +type Deferred = { + promise: Promise; + resolve: (value: T) => void; + reject: (reason?: unknown) => void; +}; + +const deferred = (): Deferred => { + let resolve!: (value: T) => void; + let reject!: (reason?: unknown) => void; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + return { promise, resolve, reject }; +}; + +const waitFor = async (condition: () => boolean) => { + const startedAt = Date.now(); + while (!condition()) { + if (Date.now() - startedAt > 500) { + throw new Error("Timed out waiting for condition"); + } + await new Promise(resolve => setTimeout(resolve, 1)); + } +}; + +describe("RedisChannelStorage", () => { + let client: MockRedisClient; + let storage: RedisChannelStorage; + + beforeEach(() => { + client = new MockRedisClient(); + storage = new RedisChannelStorage({ + client, + keyPrefix: "test:x402", + lockRetryIntervalMs: 1, + }); + }); + + it("returns undefined when no channel exists", async () => { + expect(await storage.get(CHANNEL_ID)).toBeUndefined(); + }); + + it("stores and retrieves a channel", async () => { + const channel = buildSession({ chargedCumulativeAmount: "1000" }); + await storage.updateChannel(CHANNEL_ID, () => channel); + expect(await storage.get(CHANNEL_ID)).toEqual(channel); + }); + + it("treats channelId case-insensitively", async () => { + const channel = buildSession({ chargedCumulativeAmount: "500" }); + await storage.updateChannel(CHANNEL_ID.toUpperCase(), () => channel); + expect(await storage.get(CHANNEL_ID.toLowerCase())).toEqual(channel); + }); + + it("lists stored channels sorted by channelId", async () => { + const id1 = "0x2222222222222222222222222222222222222222222222222222222222222222"; + const id2 = "0x1111111111111111111111111111111111111111111111111111111111111111"; + await storage.updateChannel(id1, () => buildSession({ channelId: id1 })); + await storage.updateChannel(id2, () => buildSession({ channelId: id2 })); + await client.set(`test:x402:server:channel:${id1}:lock`, "other"); + + expect((await storage.list()).map(channel => channel.channelId)).toEqual([id2, id1]); + }); + + it("reports unchanged when the callback returns the current channel", async () => { + const channel = buildSession({ chargedCumulativeAmount: "500" }); + await storage.updateChannel(CHANNEL_ID, () => channel); + + await expect(storage.updateChannel(CHANNEL_ID, current => current)).resolves.toEqual({ + channel, + status: "unchanged", + }); + }); + + it("deletes a channel", async () => { + const channel = buildSession(); + await storage.updateChannel(CHANNEL_ID, () => channel); + + await expect(storage.updateChannel(CHANNEL_ID, () => undefined)).resolves.toEqual({ + channel: undefined, + status: "deleted", + }); + expect(await storage.get(CHANNEL_ID)).toBeUndefined(); + }); + + it("delete is a no-op when nothing is stored", async () => { + await expect(storage.updateChannel(CHANNEL_ID, () => undefined)).resolves.toEqual({ + channel: undefined, + status: "unchanged", + }); + }); + + it("retries concurrent updateChannel mutations after Redis compare conflicts", async () => { + await storage.updateChannel(CHANNEL_ID, () => buildSession({ chargedCumulativeAmount: "0" })); + const firstEvalDelay = deferred(); + client.nextUpdateEvalDelay = firstEvalDelay; + + const first = storage.updateChannel(CHANNEL_ID, current => + buildSession({ + chargedCumulativeAmount: String(Number(current?.chargedCumulativeAmount ?? "0") + 1), + }), + ); + + await waitFor(() => client.nextUpdateEvalDelay === undefined); + + const second = storage.updateChannel(CHANNEL_ID, current => + buildSession({ + chargedCumulativeAmount: String(Number(current?.chargedCumulativeAmount ?? "0") + 1), + }), + ); + + await waitFor(() => + (client.store.get(`test:x402:server:channel:${CHANNEL_ID}`)?.value ?? "").includes( + '"chargedCumulativeAmount":"1"', + ), + ); + firstEvalDelay.resolve(); + + const results = await Promise.all([first, second]); + expect(results.map(result => result.status)).toEqual(["updated", "updated"]); + expect(client.updateConflicts).toBe(1); + expect((await storage.get(CHANNEL_ID))?.chargedCumulativeAmount).toBe("2"); + }); +}); + +describe("InMemoryClientChannelStorage", () => { + let storage: InMemoryClientChannelStorage; + + beforeEach(() => { + storage = new InMemoryClientChannelStorage(); + }); + + it("returns undefined when no context exists", async () => { + expect(await storage.get(CHANNEL_ID)).toBeUndefined(); + }); + + it("stores and retrieves a context", async () => { + const ctx: BatchSettlementClientContext = { + chargedCumulativeAmount: "1000", + balance: "10000000", + totalClaimed: "0", + depositAmount: "10000000", + signedMaxClaimable: "1000", + signature: "0xdeadbeef", + }; + await storage.set(CHANNEL_ID, ctx); + expect(await storage.get(CHANNEL_ID)).toEqual(ctx); + }); + + it("overwrites a context on subsequent set", async () => { + await storage.set(CHANNEL_ID, { chargedCumulativeAmount: "1" }); + await storage.set(CHANNEL_ID, { chargedCumulativeAmount: "2" }); + const got = await storage.get(CHANNEL_ID); + expect(got?.chargedCumulativeAmount).toBe("2"); + }); + + it("deletes a context", async () => { + await storage.set(CHANNEL_ID, { chargedCumulativeAmount: "5" }); + await storage.delete(CHANNEL_ID); + expect(await storage.get(CHANNEL_ID)).toBeUndefined(); + }); + + it("delete is a no-op when nothing is stored", async () => { + await expect(storage.delete(CHANNEL_ID)).resolves.toBeUndefined(); + }); + + it("uses keys verbatim (no normalization)", async () => { + await storage.set(CHANNEL_ID.toUpperCase(), { chargedCumulativeAmount: "1" }); + expect(await storage.get(CHANNEL_ID.toLowerCase())).toBeUndefined(); + expect(await storage.get(CHANNEL_ID.toUpperCase())).toEqual({ chargedCumulativeAmount: "1" }); + }); +}); diff --git a/typescript/packages/mechanisms/evm/test/unit/batch-settlement/types.test.ts b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/types.test.ts new file mode 100644 index 0000000000..5e73a020c7 --- /dev/null +++ b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/types.test.ts @@ -0,0 +1,290 @@ +import { describe, it, expect } from "vitest"; +import { + isBatchSettlementDepositPayload, + isBatchSettlementVoucherPayload, + isBatchSettlementRefundPayload, + isBatchSettlementClaimPayload, + isBatchSettlementSettlePayload, + isBatchSettlementEnrichedRefundPayload, +} from "../../../src/batch-settlement/types"; +import type { + ChannelConfig, + BatchSettlementDepositPayload, + BatchSettlementVoucherPayload, + BatchSettlementRefundPayload, + BatchSettlementClaimPayload, + BatchSettlementSettlePayload, + BatchSettlementEnrichedRefundPayload, +} from "../../../src/batch-settlement/types"; + +const CHANNEL_CONFIG: ChannelConfig = { + payer: "0x1234567890123456789012345678901234567890", + payerAuthorizer: "0x1234567890123456789012345678901234567890", + receiver: "0x9876543210987654321098765432109876543210", + receiverAuthorizer: "0x0000000000000000000000000000000000000000", + token: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + withdrawDelay: 900, + salt: "0x0000000000000000000000000000000000000000000000000000000000000000", +}; + +const VALID_DEPOSIT_PAYLOAD: BatchSettlementDepositPayload = { + type: "deposit", + channelConfig: CHANNEL_CONFIG, + voucher: { + channelId: "0xabc1230000000000000000000000000000000000000000000000000000000001", + maxClaimableAmount: "1000000", + signature: "0xcafebabe", + }, + deposit: { + amount: "10000000", + authorization: { + erc3009Authorization: { + validAfter: "0", + validBefore: "9999999999", + salt: "0x0000000000000000000000000000000000000000000000000000000000000001", + signature: "0xdeadbeef", + }, + }, + }, +}; + +const VALID_PERMIT2_DEPOSIT_PAYLOAD: BatchSettlementDepositPayload = { + type: "deposit", + channelConfig: CHANNEL_CONFIG, + voucher: { + channelId: "0xabc1230000000000000000000000000000000000000000000000000000000001", + maxClaimableAmount: "1000000", + signature: "0xcafebabe", + }, + deposit: { + amount: "10000000", + authorization: { + permit2Authorization: { + from: "0x1234567890123456789012345678901234567890", + permitted: { + token: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + amount: "10000000", + }, + spender: "0x4020e27bcea6C226BF888C61b6C520C0fcC50005", + nonce: "123", + deadline: "9999999999", + witness: { + channelId: "0xabc1230000000000000000000000000000000000000000000000000000000001", + }, + signature: "0xdeadbeef", + }, + }, + }, +}; + +const VALID_VOUCHER_PAYLOAD: BatchSettlementVoucherPayload = { + type: "voucher", + channelConfig: CHANNEL_CONFIG, + voucher: { + channelId: "0xabc1230000000000000000000000000000000000000000000000000000000001", + maxClaimableAmount: "2000000", + signature: "0xfeedface", + }, +}; + +const VALID_REFUND_PAYLOAD: BatchSettlementRefundPayload = { + type: "refund", + channelConfig: CHANNEL_CONFIG, + voucher: { + channelId: "0xabc1230000000000000000000000000000000000000000000000000000000001", + maxClaimableAmount: "2000000", + signature: "0xfeedface", + }, +}; + +const VALID_CLAIM_PAYLOAD: BatchSettlementClaimPayload = { + type: "claim", + claims: [ + { + voucher: { channel: CHANNEL_CONFIG, maxClaimableAmount: "1000000" }, + signature: "0xaa", + totalClaimed: "1000000", + }, + ], +}; + +const VALID_SETTLE_PAYLOAD: BatchSettlementSettlePayload = { + type: "settle", + receiver: "0x9876543210987654321098765432109876543210", + token: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", +}; + +const VALID_ENRICHED_REFUND_PAYLOAD: BatchSettlementEnrichedRefundPayload = { + ...VALID_REFUND_PAYLOAD, + amount: "100000", + refundNonce: "0", + claims: [], +}; + +describe("isBatchSettlementDepositPayload", () => { + it("returns true for a complete deposit payload", () => { + expect(isBatchSettlementDepositPayload(VALID_DEPOSIT_PAYLOAD)).toBe(true); + }); + + it("returns true for a Permit2 deposit payload", () => { + expect(isBatchSettlementDepositPayload(VALID_PERMIT2_DEPOSIT_PAYLOAD)).toBe(true); + }); + + it("returns false for a voucher-only payload", () => { + expect(isBatchSettlementDepositPayload(VALID_VOUCHER_PAYLOAD)).toBe(false); + }); + + it("returns false when type is missing", () => { + const { type, ...rest } = VALID_DEPOSIT_PAYLOAD; + void type; + expect(isBatchSettlementDepositPayload(rest as unknown as Record)).toBe(false); + }); + + it("returns false when deposit is missing", () => { + const { deposit, ...rest } = VALID_DEPOSIT_PAYLOAD; + void deposit; + expect(isBatchSettlementDepositPayload(rest as unknown as Record)).toBe(false); + }); + + it("returns false when voucher is missing", () => { + const { voucher, ...rest } = VALID_DEPOSIT_PAYLOAD; + void voucher; + expect(isBatchSettlementDepositPayload(rest as unknown as Record)).toBe(false); + }); + + it("returns false for an empty object", () => { + expect(isBatchSettlementDepositPayload({})).toBe(false); + }); + + it("returns false for a settle-action payload", () => { + expect( + isBatchSettlementDepositPayload(VALID_SETTLE_PAYLOAD as unknown as Record), + ).toBe(false); + }); +}); + +describe("isBatchSettlementVoucherPayload", () => { + it("returns true for a valid voucher payload", () => { + expect(isBatchSettlementVoucherPayload(VALID_VOUCHER_PAYLOAD)).toBe(true); + }); + + it("returns false for a deposit payload", () => { + expect(isBatchSettlementVoucherPayload(VALID_DEPOSIT_PAYLOAD)).toBe(false); + }); + + it("returns false when channelConfig is missing", () => { + const { channelConfig, ...rest } = VALID_VOUCHER_PAYLOAD; + void channelConfig; + expect(isBatchSettlementVoucherPayload(rest as unknown as Record)).toBe(false); + }); + + it("returns false when channelId is missing", () => { + const { channelId, ...voucher } = VALID_VOUCHER_PAYLOAD.voucher; + void channelId; + expect(isBatchSettlementVoucherPayload({ ...VALID_VOUCHER_PAYLOAD, voucher })).toBe(false); + }); + + it("returns false when maxClaimableAmount is missing", () => { + const { maxClaimableAmount, ...voucher } = VALID_VOUCHER_PAYLOAD.voucher; + void maxClaimableAmount; + expect(isBatchSettlementVoucherPayload({ ...VALID_VOUCHER_PAYLOAD, voucher })).toBe(false); + }); + + it("returns false when signature is missing", () => { + const { signature, ...voucher } = VALID_VOUCHER_PAYLOAD.voucher; + void signature; + expect(isBatchSettlementVoucherPayload({ ...VALID_VOUCHER_PAYLOAD, voucher })).toBe(false); + }); + + it("returns false for an empty object", () => { + expect(isBatchSettlementVoucherPayload({})).toBe(false); + }); +}); + +describe("settle payload guards (mutual exclusivity)", () => { + const guards: Array<{ + name: string; + fn: (p: Record) => boolean; + matching: Record; + }> = [ + { + name: "isBatchSettlementClaimPayload", + fn: isBatchSettlementClaimPayload, + matching: VALID_CLAIM_PAYLOAD as unknown as Record, + }, + { + name: "isBatchSettlementSettlePayload", + fn: isBatchSettlementSettlePayload, + matching: VALID_SETTLE_PAYLOAD as unknown as Record, + }, + { + name: "isBatchSettlementEnrichedRefundPayload", + fn: isBatchSettlementEnrichedRefundPayload, + matching: VALID_ENRICHED_REFUND_PAYLOAD as unknown as Record, + }, + ]; + + for (const guard of guards) { + it(`${guard.name} matches its own payload`, () => { + expect(guard.fn(guard.matching)).toBe(true); + }); + + for (const other of guards) { + if (other === guard) continue; + it(`${guard.name} rejects ${other.name}'s payload`, () => { + expect(guard.fn(other.matching)).toBe(false); + }); + } + + it(`${guard.name} rejects payment payloads (deposit/voucher)`, () => { + expect(guard.fn(VALID_DEPOSIT_PAYLOAD as unknown as Record)).toBe(false); + expect(guard.fn(VALID_VOUCHER_PAYLOAD as unknown as Record)).toBe(false); + }); + + it(`${guard.name} rejects empty object`, () => { + expect(guard.fn({})).toBe(false); + }); + } +}); + +describe("isBatchSettlementRefundPayload", () => { + it("returns true for a valid refund payload", () => { + expect(isBatchSettlementRefundPayload(VALID_REFUND_PAYLOAD)).toBe(true); + }); + + it("does not require amount for a full refund", () => { + expect(isBatchSettlementRefundPayload(VALID_REFUND_PAYLOAD)).toBe(true); + }); +}); + +describe("isBatchSettlementClaimPayload (specific fields)", () => { + it("returns false when claims array is missing", () => { + const { claims, ...rest } = VALID_CLAIM_PAYLOAD; + void claims; + expect(isBatchSettlementClaimPayload(rest as unknown as Record)).toBe(false); + }); +}); + +describe("isBatchSettlementSettlePayload (specific fields)", () => { + it("returns false when receiver is missing", () => { + const { receiver, ...rest } = VALID_SETTLE_PAYLOAD; + void receiver; + expect(isBatchSettlementSettlePayload(rest as unknown as Record)).toBe(false); + }); + + it("returns false when token is missing", () => { + const { token, ...rest } = VALID_SETTLE_PAYLOAD; + void token; + expect(isBatchSettlementSettlePayload(rest as unknown as Record)).toBe(false); + }); +}); + +describe("isBatchSettlementEnrichedRefundPayload (specific fields)", () => { + it("returns false when refundNonce is missing", () => { + const { refundNonce, ...rest } = VALID_ENRICHED_REFUND_PAYLOAD; + void refundNonce; + expect(isBatchSettlementEnrichedRefundPayload(rest as unknown as Record)).toBe( + false, + ); + }); +}); diff --git a/typescript/packages/mechanisms/evm/test/unit/batch-settlement/utils.test.ts b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/utils.test.ts new file mode 100644 index 0000000000..30d4f6d68a --- /dev/null +++ b/typescript/packages/mechanisms/evm/test/unit/batch-settlement/utils.test.ts @@ -0,0 +1,257 @@ +import { describe, it, expect } from "vitest"; +import { computeChannelId as computeChannelIdForNetwork } from "../../../src/batch-settlement/utils"; +import { + channelIdsEqual, + validateChannelConfig, + erc3009AuthorizationTimeInvalidReason, +} from "../../../src/batch-settlement/facilitator/utils"; +import { + ErrChannelIdMismatch, + ErrReceiverMismatch, + ErrReceiverAuthorizerMismatch, + ErrTokenMismatch, + ErrWithdrawDelayMismatch, + ErrWithdrawDelayOutOfRange, + ErrValidAfterInFuture, + ErrValidBeforeExpired, +} from "../../../src/batch-settlement/errors"; +import { MIN_WITHDRAW_DELAY, MAX_WITHDRAW_DELAY } from "../../../src/batch-settlement/constants"; +import type { ChannelConfig } from "../../../src/batch-settlement/types"; +import type { PaymentRequirements } from "@x402/core/types"; + +const BASE_CONFIG: ChannelConfig = { + payer: "0x1234567890123456789012345678901234567890", + payerAuthorizer: "0x1234567890123456789012345678901234567890", + receiver: "0x9876543210987654321098765432109876543210", + receiverAuthorizer: "0x1111111111111111111111111111111111111111", + token: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + withdrawDelay: 900, + salt: "0x0000000000000000000000000000000000000000000000000000000000000000", +}; + +const BASE_REQUIREMENTS: PaymentRequirements = { + scheme: "batch-settlement", + network: "eip155:84532", + amount: "1000", + asset: "0x036CbD53842c5426634e7929541eC2318f3dCF7e", + payTo: "0x9876543210987654321098765432109876543210", + maxTimeoutSeconds: 3600, + extra: { + receiverAuthorizer: "0x1111111111111111111111111111111111111111", + withdrawDelay: 900, + }, +}; + +function computeChannelId( + config: ChannelConfig, + network = BASE_REQUIREMENTS.network, +): `0x${string}` { + return computeChannelIdForNetwork(config, network); +} + +describe("computeChannelId", () => { + it("is deterministic for identical configs", () => { + expect(computeChannelId(BASE_CONFIG)).toBe(computeChannelId({ ...BASE_CONFIG })); + }); + + it("returns a 32-byte hex string (0x + 64 chars)", () => { + const id = computeChannelId(BASE_CONFIG); + expect(id).toMatch(/^0x[0-9a-f]{64}$/); + }); + + it("changes when the chain changes", () => { + expect(computeChannelId(BASE_CONFIG, "eip155:84532")).not.toBe( + computeChannelId(BASE_CONFIG, "eip155:8453"), + ); + }); + + it.each([ + ["payer", { payer: "0x1111111111111111111111111111111111111111" as `0x${string}` }], + [ + "payerAuthorizer", + { payerAuthorizer: "0x2222222222222222222222222222222222222222" as `0x${string}` }, + ], + ["receiver", { receiver: "0x3333333333333333333333333333333333333333" as `0x${string}` }], + [ + "receiverAuthorizer", + { receiverAuthorizer: "0x4444444444444444444444444444444444444444" as `0x${string}` }, + ], + ["token", { token: "0x5555555555555555555555555555555555555555" as `0x${string}` }], + ["withdrawDelay", { withdrawDelay: 901 }], + [ + "salt", + { + salt: "0x0000000000000000000000000000000000000000000000000000000000000001" as `0x${string}`, + }, + ], + ])("changes when %s changes", (_field, override) => { + const base = computeChannelId(BASE_CONFIG); + const changed = computeChannelId({ ...BASE_CONFIG, ...override }); + expect(changed).not.toBe(base); + }); +}); + +describe("channelIdsEqual", () => { + const id = "0xABCdef0123456789ABCDEF0123456789abcdef0123456789ABCdef0123456789" as `0x${string}`; + + it("matches case-insensitively", () => { + expect(channelIdsEqual(id, id.toLowerCase())).toBe(true); + expect(channelIdsEqual(id, id.toUpperCase())).toBe(true); + }); + + it("returns false for non-string input", () => { + expect(channelIdsEqual(id, 123)).toBe(false); + expect(channelIdsEqual(id, null)).toBe(false); + expect(channelIdsEqual(id, undefined)).toBe(false); + }); + + it("returns false for empty string", () => { + expect(channelIdsEqual(id, "")).toBe(false); + }); + + it("returns false for completely different ids", () => { + expect( + channelIdsEqual(id, "0x1111111111111111111111111111111111111111111111111111111111111111"), + ).toBe(false); + }); +}); + +describe("validateChannelConfig", () => { + it("returns undefined when config matches requirements and computed id", () => { + const channelId = computeChannelId(BASE_CONFIG); + expect(validateChannelConfig(BASE_CONFIG, channelId, BASE_REQUIREMENTS)).toBeUndefined(); + }); + + it("returns ErrChannelIdMismatch when channelId does not match config hash", () => { + const fakeId = + "0x0000000000000000000000000000000000000000000000000000000000000001" as `0x${string}`; + expect(validateChannelConfig(BASE_CONFIG, fakeId, BASE_REQUIREMENTS)).toBe( + ErrChannelIdMismatch, + ); + }); + + it("returns ErrReceiverMismatch when receiver mismatches requirements.payTo", () => { + const config: ChannelConfig = { + ...BASE_CONFIG, + receiver: "0x1111111111111111111111111111111111111111", + }; + const channelId = computeChannelId(config); + expect(validateChannelConfig(config, channelId, BASE_REQUIREMENTS)).toBe(ErrReceiverMismatch); + }); + + it("returns ErrReceiverAuthorizerMismatch when receiverAuthorizer differs from extra", () => { + const config: ChannelConfig = { + ...BASE_CONFIG, + receiverAuthorizer: "0x2222222222222222222222222222222222222222", + }; + const requirements: PaymentRequirements = { + ...BASE_REQUIREMENTS, + extra: { + ...BASE_REQUIREMENTS.extra, + receiverAuthorizer: "0x3333333333333333333333333333333333333333", + }, + }; + const channelId = computeChannelId(config); + expect(validateChannelConfig(config, channelId, requirements)).toBe( + ErrReceiverAuthorizerMismatch, + ); + }); + + it("returns ErrTokenMismatch when token differs from requirements.asset", () => { + const config: ChannelConfig = { + ...BASE_CONFIG, + token: "0xaaaa000000000000000000000000000000000000", + }; + const channelId = computeChannelId(config); + expect(validateChannelConfig(config, channelId, BASE_REQUIREMENTS)).toBe(ErrTokenMismatch); + }); + + it("returns ErrWithdrawDelayMismatch when withdrawDelay differs from extra", () => { + const config: ChannelConfig = { ...BASE_CONFIG, withdrawDelay: 1800 }; + const channelId = computeChannelId(config); + expect(validateChannelConfig(config, channelId, BASE_REQUIREMENTS)).toBe( + ErrWithdrawDelayMismatch, + ); + }); + + it("returns ErrWithdrawDelayOutOfRange when below minimum (and extra not present)", () => { + const config: ChannelConfig = { ...BASE_CONFIG, withdrawDelay: MIN_WITHDRAW_DELAY - 1 }; + const channelId = computeChannelId(config); + const requirements: PaymentRequirements = { + ...BASE_REQUIREMENTS, + extra: { receiverAuthorizer: BASE_CONFIG.receiverAuthorizer }, + }; + expect(validateChannelConfig(config, channelId, requirements)).toBe(ErrWithdrawDelayOutOfRange); + }); + + it("returns ErrWithdrawDelayOutOfRange when above maximum (and extra not present)", () => { + const config: ChannelConfig = { ...BASE_CONFIG, withdrawDelay: MAX_WITHDRAW_DELAY + 1 }; + const channelId = computeChannelId(config); + const requirements: PaymentRequirements = { + ...BASE_REQUIREMENTS, + extra: { receiverAuthorizer: BASE_CONFIG.receiverAuthorizer }, + }; + expect(validateChannelConfig(config, channelId, requirements)).toBe(ErrWithdrawDelayOutOfRange); + }); + + it("returns ErrReceiverAuthorizerMismatch when receiverAuthorizer is missing from extra", () => { + const config: ChannelConfig = { + ...BASE_CONFIG, + receiverAuthorizer: "0x2222222222222222222222222222222222222222", + }; + const channelId = computeChannelId(config); + const requirements: PaymentRequirements = { + ...BASE_REQUIREMENTS, + extra: { withdrawDelay: 900 }, + }; + expect(validateChannelConfig(config, channelId, requirements)).toBe( + ErrReceiverAuthorizerMismatch, + ); + }); + + it("returns ErrReceiverAuthorizerMismatch when receiverAuthorizer is zero", () => { + const config: ChannelConfig = { + ...BASE_CONFIG, + receiverAuthorizer: "0x0000000000000000000000000000000000000000", + }; + const requirements: PaymentRequirements = { + ...BASE_REQUIREMENTS, + extra: { + ...BASE_REQUIREMENTS.extra, + receiverAuthorizer: "0x0000000000000000000000000000000000000000", + }, + }; + const channelId = computeChannelId(config); + expect(validateChannelConfig(config, channelId, requirements)).toBe( + ErrReceiverAuthorizerMismatch, + ); + }); +}); + +describe("erc3009AuthorizationTimeInvalidReason", () => { + const now = () => BigInt(Math.floor(Date.now() / 1000)); + + it("returns undefined inside a comfortable window", () => { + const va = now() - 60n; + const vb = now() + 3600n; + expect(erc3009AuthorizationTimeInvalidReason(va, vb)).toBeUndefined(); + }); + + it("returns ErrValidAfterInFuture when validAfter is far in future", () => { + const va = now() + 3600n; + const vb = now() + 7200n; + expect(erc3009AuthorizationTimeInvalidReason(va, vb)).toBe(ErrValidAfterInFuture); + }); + + it("returns ErrValidBeforeExpired when validBefore is in past", () => { + const va = now() - 7200n; + const vb = now() - 3600n; + expect(erc3009AuthorizationTimeInvalidReason(va, vb)).toBe(ErrValidBeforeExpired); + }); + + it("returns ErrValidBeforeExpired when validBefore is right at the edge of clock-skew margin", () => { + const va = now() - 60n; + const vb = now() + 1n; + expect(erc3009AuthorizationTimeInvalidReason(va, vb)).toBe(ErrValidBeforeExpired); + }); +}); diff --git a/typescript/packages/mechanisms/evm/test/unit/server.moneyParser.test.ts b/typescript/packages/mechanisms/evm/test/unit/server.moneyParser.test.ts index 5ca3644380..0a31ca9cc6 100644 --- a/typescript/packages/mechanisms/evm/test/unit/server.moneyParser.test.ts +++ b/typescript/packages/mechanisms/evm/test/unit/server.moneyParser.test.ts @@ -142,6 +142,22 @@ describe("ExactEvmScheme (Server) - registerMoneyParser", () => { expect(result.asset).toBe("0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"); expect(result.amount).toBe("4020000"); // 4.02* 1e6 }); + + it("should correctly convert sub-microsecond prices for 18-decimal tokens", async () => { + const server = new ExactEvmScheme(); + // MegaETH MegaUSD has 18 decimals: $0.0000001 = 1e-7 * 1e18 = 100000000000 atomic units + const result = await server.parsePrice("$0.0000001", "eip155:4326"); + expect(result.amount).toBe("100000000000"); + expect(result.asset).toBe("0xFAfDdbb3FC7688494971a79cc65DCa3EF82079E7"); + }); + + it("should throw when price is too small to represent in the token's precision", async () => { + const server = new ExactEvmScheme(); + // USDC has 6 decimals: $0.00000001 = 1e-8 * 1e6 = 0.01 → rounds to 0 → must throw + await expect(server.parsePrice("$0.00000001", "eip155:8453")).rejects.toThrow("too small"); + // Also throws when passed as a number + await expect(server.parsePrice(0.00000001, "eip155:8453")).rejects.toThrow("too small"); + }); }); describe("Multiple parsers - chain of responsibility", () => { diff --git a/typescript/packages/mechanisms/evm/tsup.config.ts b/typescript/packages/mechanisms/evm/tsup.config.ts index db132c689a..2fcd5c4c25 100644 --- a/typescript/packages/mechanisms/evm/tsup.config.ts +++ b/typescript/packages/mechanisms/evm/tsup.config.ts @@ -12,6 +12,9 @@ const baseConfig = { "upto/client/index": "src/upto/client/index.ts", "upto/server/index": "src/upto/server/index.ts", "upto/facilitator/index": "src/upto/facilitator/index.ts", + "batch-settlement/client/index": "src/batch-settlement/client/index.ts", + "batch-settlement/server/index": "src/batch-settlement/server/index.ts", + "batch-settlement/facilitator/index": "src/batch-settlement/facilitator/index.ts", }, dts: { resolve: true, diff --git a/typescript/packages/mechanisms/evm/vitest.integration.config.ts b/typescript/packages/mechanisms/evm/vitest.integration.config.ts index 0dd9d401ce..33c360cada 100644 --- a/typescript/packages/mechanisms/evm/vitest.integration.config.ts +++ b/typescript/packages/mechanisms/evm/vitest.integration.config.ts @@ -6,6 +6,7 @@ export default defineConfig(({ mode }) => ({ test: { env: loadEnv(mode, process.cwd(), ""), include: ["test/integrations/**/*.test.ts"], // Only include integration tests + fileParallelism: false, // Prevent race conditions on tx nonces }, plugins: [tsconfigPaths({ projects: ["."] })], })); diff --git a/examples/typescript/legacy/facilitator/.prettierignore b/typescript/packages/mechanisms/hedera/.prettierignore similarity index 79% rename from examples/typescript/legacy/facilitator/.prettierignore rename to typescript/packages/mechanisms/hedera/.prettierignore index 5bd240ba90..9fd1bade5d 100644 --- a/examples/typescript/legacy/facilitator/.prettierignore +++ b/typescript/packages/mechanisms/hedera/.prettierignore @@ -3,6 +3,5 @@ dist/ node_modules/ coverage/ .github/ -src/client **/**/*.json -*.md \ No newline at end of file +*.md diff --git a/examples/typescript/legacy/facilitator/.prettierrc b/typescript/packages/mechanisms/hedera/.prettierrc similarity index 100% rename from examples/typescript/legacy/facilitator/.prettierrc rename to typescript/packages/mechanisms/hedera/.prettierrc diff --git a/typescript/packages/mechanisms/hedera/CHANGELOG.md b/typescript/packages/mechanisms/hedera/CHANGELOG.md new file mode 100644 index 0000000000..f6bf89ad20 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/CHANGELOG.md @@ -0,0 +1,14 @@ +# Changelog + +## 2.12.0 + +### Minor Changes + +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] + - @x402/core@2.12.0 + +## 2.11.0 + +- Add initial `@x402/hedera` package with x402 v2 exact scheme support. diff --git a/typescript/packages/mechanisms/hedera/README.md b/typescript/packages/mechanisms/hedera/README.md new file mode 100644 index 0000000000..5e06dc27b1 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/README.md @@ -0,0 +1,163 @@ +# @x402/hedera + +Hedera implementation of the x402 `exact` payment scheme (v2). + +## Installation + +```bash +pnpm add @x402/hedera +``` + +## Features + +- x402 v2 exact scheme support for Hedera (`hedera:mainnet`, `hedera:testnet`) +- HBAR (`asset: 0.0.0`) and HTS fungible token payment validation +- Facilitator fee payer model via `paymentRequirements.extra.feePayer` +- Configurable alias handling policy (`allow` or `reject`, default `reject`) +- Server-side money parser chain with configured HTS fallback conversion + +## Usage + +### Client + +```ts +import { x402Client } from "@x402/core/client"; +import { createClientHederaSigner } from "@x402/hedera"; +import { ExactHederaScheme } from "@x402/hedera/exact/client"; +import { PrivateKey } from "@hiero-ledger/sdk"; + +const signer = createClientHederaSigner( + "0.0.1111", + PrivateKey.fromString(process.env.HEDERA_PRIVATE_KEY!), + { + network: "hedera:testnet", + }, +); + +const client = new x402Client().register("hedera:*", new ExactHederaScheme(signer)); +``` + +### Server + +```ts +import { x402ResourceServer } from "@x402/core/server"; +import { ExactHederaScheme } from "@x402/hedera/exact/server"; + +const server = new x402ResourceServer(facilitatorClient); +server.register( + "hedera:*", + new ExactHederaScheme({ + defaultAssets: { + "hedera:testnet": { asset: "0.0.6001", decimals: 6 }, + "hedera:mainnet": { asset: "0.0.9001", decimals: 6 }, + }, + }), +); +``` + +### Facilitator + +```ts +import { x402Facilitator } from "@x402/core/facilitator"; +import { ExactHederaScheme } from "@x402/hedera/exact/facilitator"; + +const facilitatorSigner = { + getAddresses: () => ["0.0.5001"], + signAndSubmitTransaction: async () => ({ transactionId: "0.0.5001@1700000000.000000000" }), +}; + +const facilitator = new x402Facilitator().register( + "hedera:*", + new ExactHederaScheme(facilitatorSigner, { aliasPolicy: "reject" }), +); +``` + +## Amount Units + +- HBAR (`asset: "0.0.0"`): amount is in tinybars (1 HBAR = 10^8 tinybars). +- HTS fungible token: amount is in token smallest units according to token decimals. + +## Alias Policy + +- `reject` (default): facilitator may reject `payTo` values that resolve as aliases/non-existing accounts. +- `allow`: facilitator allows alias destinations. + +Implementations should document and monitor this policy because alias-based auto-account creation may introduce additional cost. + +## Hedera SDK primitives + +This package re-exports a curated subset of `@hiero-ledger/sdk` primitives +(`AccountBalanceQuery`, `AccountId`, `AccountInfoQuery`, `Client`, `Hbar`, +`PrivateKey`, `TokenAssociateTransaction`, `TokenId`, `Transaction`, +`TransactionId`, `TransferTransaction`) so that a consuming application +always resolves a single SDK instance through `@x402/hedera`, even when it +lives in a sibling workspace from the one where `@x402/hedera` itself was +installed. Importing `@hiero-ledger/sdk` directly alongside `@x402/hedera` +in such setups yields duplicate on-disk installs — the SDK's internal +string-brand / `instanceof` checks then throw `t.startsWith is not a +function` at runtime. + +The re-exports are pinned to the `@hiero-ledger/sdk` version declared in +this package's `dependencies`. Consuming the re-exported symbols couples +your application to that version until `@x402/hedera` bumps its pin; a +major SDK bump is treated as a breaking change in this package. + +## Testnet Faucet + +To run on `hedera:testnet` you need funded client and facilitator accounts plus +testnet HBAR for fees. + +- **Hedera Portal (faucet + account creation):** https://portal.hedera.com/ + - Sign up, create a testnet account, and claim testnet HBAR. + - The portal also exposes your account id and ECDSA/ED25519 keys to plug into + `HEDERA_CLIENT_PRIVATE_KEY` / `HEDERA_FACILITATOR_PRIVATE_KEY`. +- **Circle USDC testnet faucet:** https://faucet.circle.com/ — select + "Hedera Testnet" to mint test USDC (`0.0.429274`) to an already-associated + account. + +## Token Association + +Hedera requires every HTS token to be explicitly associated with each account +before the account can receive it. Both the payer and the recipient must be +associated with the token used by the payment before settlement, otherwise the +transfer fails on chain with `TOKEN_NOT_ASSOCIATED_TO_ACCOUNT`. + +The Hedera portal does not expose token association, so use the Hiero SDK +directly: + +```ts +import { AccountId, Client, PrivateKey, TokenAssociateTransaction, TokenId } from "@x402/hedera"; + +const client = Client.forTestnet().setOperator( + AccountId.fromString(accountId), + PrivateKey.fromStringECDSA(privateKey), +); +await new TokenAssociateTransaction() + .setAccountId(AccountId.fromString(accountId)) + .setTokenIds([TokenId.fromString("0.0.429274")]) // testnet USDC + .execute(client) + .then(response => response.getReceipt(client)); +client.close(); +``` + +Alternatively, configure `maxAutomaticTokenAssociations` on the recipient +account (see the Hiero SDK `AccountUpdateTransaction`) to opt into automatic +associations for future HTS tokens. + +## Live Integration Testing + +The integration suite supports an env-gated live Hedera test in +`test/integrations/exact-hedera.test.ts`. + +- Create or update `typescript/packages/mechanisms/hedera/.env.test`. +- This live suite currently assumes **ECDSA** private keys for both client and facilitator. +- Use `0x`-prefixed ECDSA key strings in: + - `HEDERA_CLIENT_PRIVATE_KEY` + - `HEDERA_FACILITATOR_PRIVATE_KEY` +- Fund all accounts from the testnet faucet above before running. + +Run: + +```bash +pnpm test:integration +``` diff --git a/examples/typescript/legacy/servers/express/eslint.config.js b/typescript/packages/mechanisms/hedera/eslint.config.js similarity index 78% rename from examples/typescript/legacy/servers/express/eslint.config.js rename to typescript/packages/mechanisms/hedera/eslint.config.js index e2fde7b3b8..696586c15d 100644 --- a/examples/typescript/legacy/servers/express/eslint.config.js +++ b/typescript/packages/mechanisms/hedera/eslint.config.js @@ -10,7 +10,8 @@ export default [ ignores: ["dist/**", "node_modules/**"], }, { - files: ["**/*.ts"], + files: ["**/*.ts", "**/*.tsx"], + ignores: ["**/*.test.ts", "test/**/*"], languageOptions: { parser: tsParser, sourceType: "module", @@ -21,18 +22,18 @@ export default [ module: "readonly", require: "readonly", Buffer: "readonly", - console: "readonly", exports: "readonly", setTimeout: "readonly", clearTimeout: "readonly", setInterval: "readonly", clearInterval: "readonly", + console: "readonly", }, }, plugins: { "@typescript-eslint": ts, - prettier: prettier, - jsdoc: jsdoc, + prettier, + jsdoc, import: importPlugin, }, rules: { @@ -70,4 +71,22 @@ export default [ "jsdoc/require-hyphen-before-param-description": ["error", "always"], }, }, + { + files: ["**/*.test.ts", "test/**/*"], + languageOptions: { + parser: tsParser, + sourceType: "module", + ecmaVersion: 2020, + }, + plugins: { + "@typescript-eslint": ts, + prettier, + }, + rules: { + "prettier/prettier": "error", + "@typescript-eslint/no-unused-vars": ["error", { argsIgnorePattern: "^_" }], + "@typescript-eslint/no-explicit-any": "off", + "@typescript-eslint/member-ordering": "off", + }, + }, ]; diff --git a/typescript/packages/mechanisms/hedera/package.json b/typescript/packages/mechanisms/hedera/package.json new file mode 100644 index 0000000000..0fb6df8dc9 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/package.json @@ -0,0 +1,94 @@ +{ + "name": "@x402/hedera", + "version": "2.12.0", + "main": "./dist/cjs/index.js", + "module": "./dist/esm/index.js", + "types": "./dist/cjs/index.d.ts", + "scripts": { + "build": "tsup", + "test": "vitest run", + "test:integration": "vitest run --config vitest.integration.config.ts", + "test:watch": "vitest", + "watch": "tsc --watch", + "format": "prettier -c .prettierrc --write \"**/*.{ts,js,cjs,json,md}\"", + "format:check": "prettier -c .prettierrc --check \"**/*.{ts,js,cjs,json,md}\"", + "lint": "eslint . --ext .ts --fix", + "lint:check": "eslint . --ext .ts" + }, + "keywords": [ + "x402", + "payment", + "protocol", + "hedera" + ], + "license": "Apache-2.0", + "author": "Coinbase Inc.", + "repository": "https://github.com/coinbase/x402", + "description": "x402 Payment Protocol Hedera Implementation", + "devDependencies": { + "@eslint/js": "^9.24.0", + "@types/node": "^22.13.4", + "@typescript-eslint/eslint-plugin": "^8.29.1", + "@typescript-eslint/parser": "^8.29.1", + "eslint": "^9.24.0", + "eslint-plugin-import": "^2.31.0", + "eslint-plugin-jsdoc": "^50.6.9", + "eslint-plugin-prettier": "^5.2.6", + "prettier": "3.5.2", + "tsup": "^8.4.0", + "tsx": "^4.21.0", + "typescript": "^5.7.3", + "vite": "^6.2.6", + "vite-tsconfig-paths": "^5.1.4", + "vitest": "^3.0.5" + }, + "dependencies": { + "@x402/core": "workspace:*", + "@hiero-ledger/sdk": "2.80.0" + }, + "exports": { + ".": { + "import": { + "types": "./dist/esm/index.d.mts", + "default": "./dist/esm/index.mjs" + }, + "require": { + "types": "./dist/cjs/index.d.ts", + "default": "./dist/cjs/index.js" + } + }, + "./exact/client": { + "import": { + "types": "./dist/esm/exact/client/index.d.mts", + "default": "./dist/esm/exact/client/index.mjs" + }, + "require": { + "types": "./dist/cjs/exact/client/index.d.ts", + "default": "./dist/cjs/exact/client/index.js" + } + }, + "./exact/server": { + "import": { + "types": "./dist/esm/exact/server/index.d.mts", + "default": "./dist/esm/exact/server/index.mjs" + }, + "require": { + "types": "./dist/cjs/exact/server/index.d.ts", + "default": "./dist/cjs/exact/server/index.js" + } + }, + "./exact/facilitator": { + "import": { + "types": "./dist/esm/exact/facilitator/index.d.mts", + "default": "./dist/esm/exact/facilitator/index.mjs" + }, + "require": { + "types": "./dist/cjs/exact/facilitator/index.d.ts", + "default": "./dist/cjs/exact/facilitator/index.js" + } + } + }, + "files": [ + "dist" + ] +} diff --git a/typescript/packages/mechanisms/hedera/src/constants.ts b/typescript/packages/mechanisms/hedera/src/constants.ts new file mode 100644 index 0000000000..7d214ac1d3 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/constants.ts @@ -0,0 +1,40 @@ +/** + * CAIP-2 network identifier for Hedera Mainnet. + */ +export const HEDERA_MAINNET_CAIP2 = "hedera:mainnet"; + +/** + * CAIP-2 network identifier for Hedera Testnet. + */ +export const HEDERA_TESTNET_CAIP2 = "hedera:testnet"; + +/** + * Asset id used by x402 to represent native HBAR. + */ +export const HBAR_ASSET_ID = "0.0.0"; + +/** + * Regex for Hedera account and token IDs. + * Example: 0.0.1234 + */ +export const HEDERA_ENTITY_ID_REGEX = /^\d+\.\d+\.\d+$/; + +/** + * USDC token id on Hedera Mainnet (issued by Circle). + */ +export const HEDERA_MAINNET_USDC = "0.0.456858"; + +/** + * USDC token id on Hedera Testnet. + */ +export const HEDERA_TESTNET_USDC = "0.0.429274"; + +/** + * USDC decimals on Hedera. + */ +export const HEDERA_USDC_DECIMALS = 6; + +/** + * Supported Hedera CAIP-2 networks for this mechanism. + */ +export const SUPPORTED_HEDERA_NETWORKS = [HEDERA_MAINNET_CAIP2, HEDERA_TESTNET_CAIP2] as const; diff --git a/typescript/packages/mechanisms/hedera/src/exact/client/index.ts b/typescript/packages/mechanisms/hedera/src/exact/client/index.ts new file mode 100644 index 0000000000..7a6152d477 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/exact/client/index.ts @@ -0,0 +1 @@ +export { ExactHederaScheme } from "./scheme"; diff --git a/typescript/packages/mechanisms/hedera/src/exact/client/scheme.ts b/typescript/packages/mechanisms/hedera/src/exact/client/scheme.ts new file mode 100644 index 0000000000..fff09911a2 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/exact/client/scheme.ts @@ -0,0 +1,52 @@ +import type { + PaymentPayloadContext, + PaymentPayloadResult, + PaymentRequirements, + SchemeNetworkClient, +} from "@x402/core/types"; +import type { ClientHederaSigner } from "../../signer"; +import type { ExactHederaPayloadV2 } from "../../types"; +import { assertSupportedHederaNetwork } from "../../utils"; + +/** + * Hedera client implementation for the Exact payment scheme. + */ +export class ExactHederaScheme implements SchemeNetworkClient { + readonly scheme = "exact"; + + /** + * Creates a new ExactHederaScheme instance. + * + * @param signer - Client-side Hedera signer + */ + constructor(private readonly signer: ClientHederaSigner) {} + + /** + * Creates a payment payload for exact Hedera payments. + * + * @param x402Version - x402 protocol version + * @param paymentRequirements - Selected payment requirements + * @param _ - Optional payment payload context + * @returns Payload result + */ + async createPaymentPayload( + x402Version: number, + paymentRequirements: PaymentRequirements, + _?: PaymentPayloadContext, + ): Promise { + if (paymentRequirements.scheme !== "exact") { + throw new Error("Unsupported scheme for Hedera exact client"); + } + assertSupportedHederaNetwork(paymentRequirements.network); + + if (typeof paymentRequirements.extra?.feePayer !== "string") { + throw new Error("feePayer is required in paymentRequirements.extra for Hedera exact"); + } + + const transaction = + await this.signer.createPartiallySignedTransferTransaction(paymentRequirements); + + const payload: ExactHederaPayloadV2 = { transaction }; + return { x402Version, payload }; + } +} diff --git a/typescript/packages/mechanisms/hedera/src/exact/facilitator/index.ts b/typescript/packages/mechanisms/hedera/src/exact/facilitator/index.ts new file mode 100644 index 0000000000..ee54e6a5b1 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/exact/facilitator/index.ts @@ -0,0 +1,2 @@ +export { ExactHederaScheme } from "./scheme"; +export type { HederaFacilitatorConfig, HederaAliasPolicy } from "./scheme"; diff --git a/typescript/packages/mechanisms/hedera/src/exact/facilitator/scheme.ts b/typescript/packages/mechanisms/hedera/src/exact/facilitator/scheme.ts new file mode 100644 index 0000000000..6187a3661a --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/exact/facilitator/scheme.ts @@ -0,0 +1,560 @@ +import type { + PaymentPayload, + PaymentRequirements, + SchemeNetworkFacilitator, + SettleResponse, + VerifyResponse, +} from "@x402/core/types"; +import type { FacilitatorHederaSigner } from "../../signer"; +import type { + ExactHederaPayloadV2, + HederaTransferEntry, + InspectedHederaTransaction, +} from "../../types"; +import { + assertSupportedHederaNetwork, + extractTransactionFromPayload, + getPositiveReceivers, + hederaAccountIdsEqual, + inspectHederaTransaction, + isHbarAsset, + isValidHederaAsset, + isValidHederaEntityId, + sumTransfers, +} from "../../utils"; + +/** + * Alias handling behavior for payTo checks. + */ +export type HederaAliasPolicy = "reject" | "allow"; + +/** + * Facilitator options for exact Hedera verification. + */ +export type HederaFacilitatorConfig = { + aliasPolicy?: HederaAliasPolicy; +}; + +/** + * Hedera facilitator implementation for the Exact payment scheme. + */ +export class ExactHederaScheme implements SchemeNetworkFacilitator { + readonly scheme = "exact"; + readonly caipFamily = "hedera:*"; + private readonly aliasPolicy: HederaAliasPolicy; + + /** + * Creates a new facilitator scheme. + * + * @param signer - Facilitator signer implementation + * @param config - Optional behavior config + */ + constructor( + private readonly signer: FacilitatorHederaSigner, + config: HederaFacilitatorConfig = {}, + ) { + this.aliasPolicy = config.aliasPolicy ?? "reject"; + } + + /** + * Returns mechanism-specific `extra` data. + * + * @param _ - Network identifier + * @returns Extra object with feePayer + */ + getExtra(_: string): Record | undefined { + const addresses = this.signer.getAddresses(); + if (addresses.length === 0) { + return undefined; + } + const randomIndex = Math.floor(Math.random() * addresses.length); + return { feePayer: addresses[randomIndex] }; + } + + /** + * Returns managed signer addresses for this facilitator. + * + * @param _ - Network identifier + * @returns Signer account ids + */ + getSigners(_: string): string[] { + return [...this.signer.getAddresses()]; + } + + /** + * Verify an exact Hedera payload. + * + * @param payload - Payment payload + * @param requirements - Matched payment requirements + * @returns Verification result + */ + async verify( + payload: PaymentPayload, + requirements: PaymentRequirements, + ): Promise { + // Phase 1: requirements and accepted parity checks + const requirementsValidation = this.validateRequirements(payload, requirements); + if (requirementsValidation !== null) { + return requirementsValidation; + } + const feePayer = requirements.extra.feePayer as string; + + // Phase 2: decode and inspect transaction + const exactPayload = payload.payload as ExactHederaPayloadV2; + let transactionBase64 = ""; + try { + transactionBase64 = extractTransactionFromPayload(exactPayload); + } catch { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_transaction_could_not_be_decoded", + payer: "", + }; + } + + let inspected; + try { + inspected = inspectHederaTransaction(transactionBase64); + } catch { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_transaction_could_not_be_decoded", + payer: "", + }; + } + const inspectedValidation = this.validateInspectedTransaction(inspected); + if (inspectedValidation !== null) { + return { isValid: false, invalidReason: inspectedValidation, payer: "" }; + } + + // Phase 3: structural and transfer checks + const transferValidation = this.validateTransferSemantics(inspected, requirements, feePayer); + if (transferValidation !== null) { + return transferValidation; + } + const payerTransfers = this.getAssetTransfers( + inspected.tokenTransfers, + inspected.hbarTransfers, + requirements, + ) as HederaTransferEntry[]; + const payer = this.inferPayer(payerTransfers); + + // Phase 4: alias policy check + const payToValidation = await this.validatePayToPolicy(requirements); + if (payToValidation !== null) { + return payToValidation; + } + + // Phase 5: optional onchain preflight (balance + token association). + // Spec §6 — advisory, never throws out of verify. + // Precondition: Phase 3 transfer-semantics guarantees `payer` is non-empty + // (the payload must contain at least one debited account for `asset`). + if (typeof this.signer.preflightTransfer === "function") { + let preflight: { ok: boolean; reason?: string; message?: string }; + try { + preflight = await this.signer.preflightTransfer({ + payer, + payTo: requirements.payTo, + asset: requirements.asset, + amount: requirements.amount, + network: requirements.network, + }); + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_preflight_failed", + invalidMessage: message, + payer, + }; + } + if (!preflight.ok) { + const invalidMessage = preflight.reason + ? `${preflight.reason}${preflight.message ? `: ${preflight.message}` : ""}` + : preflight.message; + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_preflight_failed", + invalidMessage, + payer, + }; + } + } + + return { + isValid: true, + invalidReason: undefined, + payer, + }; + } + + /** + * Settles a verified exact payment. + * + * @param payload - Payment payload + * @param requirements - Matched requirements + * @returns Settlement response + */ + async settle( + payload: PaymentPayload, + requirements: PaymentRequirements, + ): Promise { + const valid = await this.verify(payload, requirements); + if (!valid.isValid) { + return { + success: false, + network: requirements.network, + transaction: "", + errorReason: valid.invalidReason ?? "verification_failed", + errorMessage: valid.invalidMessage, + payer: valid.payer || "", + }; + } + + const feePayer = requirements.extra?.feePayer as string; + const exactPayload = payload.payload as ExactHederaPayloadV2; + const transactionBase64 = extractTransactionFromPayload(exactPayload); + try { + const settled = await this.signer.signAndSubmitTransaction( + transactionBase64, + feePayer, + requirements.network, + ); + + return { + success: true, + network: requirements.network, + payer: valid.payer || feePayer, + transaction: settled.transactionId, + }; + } catch (error) { + const message = error instanceof Error ? error.message : String(error); + return { + success: false, + network: requirements.network, + transaction: "", + errorReason: "transaction_failed", + errorMessage: message, + payer: valid.payer || feePayer, + }; + } + } + + /** + * Returns the transfer list for requested asset. + * + * @param tokenTransfers - Token transfers grouped by token id + * @param hbarTransfers - Native hbar transfers + * @param requirements - Payment requirements + * @returns Transfer list or null when invalid + */ + private getAssetTransfers( + tokenTransfers: Record, + hbarTransfers: HederaTransferEntry[], + requirements: PaymentRequirements, + ): HederaTransferEntry[] | null { + if (isHbarAsset(requirements.asset)) { + if (Object.keys(tokenTransfers).length > 0) { + return null; + } + return hbarTransfers; + } + + const tokenIds = Object.keys(tokenTransfers); + if (tokenIds.length !== 1 || tokenIds[0] !== requirements.asset) { + return null; + } + + return tokenTransfers[requirements.asset] ?? null; + } + + /** + * Returns true when account has a negative transfer entry. + * + * @param transfers - Transfer list + * @param accountId - Account id + * @returns Whether account is debited + */ + private hasNegativeTransfer(transfers: HederaTransferEntry[], accountId: string): boolean { + return transfers.some( + entry => hederaAccountIdsEqual(entry.accountId, accountId) && BigInt(entry.amount) < 0n, + ); + } + + /** + * Best-effort payer inference from debited transfer entries. + * + * @param transfers - Asset transfers + * @returns Payer account id + */ + private inferPayer(transfers: HederaTransferEntry[]): string { + return transfers.find(entry => BigInt(entry.amount) < 0n)?.accountId ?? ""; + } + + /** + * Validates the basic structure returned by transaction inspection. + * + * @param inspected - Parsed transaction details + * @returns Null when valid, otherwise invalid reason code + */ + private validateInspectedTransaction(inspected: unknown): string | null { + if (!inspected || typeof inspected !== "object") { + return "invalid_exact_hedera_payload_transaction_invalid_shape"; + } + const candidate = inspected as Partial; + if ( + typeof candidate.transactionType !== "string" || + typeof candidate.transactionId !== "string" || + typeof candidate.transactionIdAccountId !== "string" || + typeof candidate.hasNonTransferOperations !== "boolean" || + !Array.isArray(candidate.hbarTransfers) || + !candidate.tokenTransfers || + typeof candidate.tokenTransfers !== "object" + ) { + return "invalid_exact_hedera_payload_transaction_invalid_shape"; + } + if (candidate.transactionId.length === 0 || candidate.transactionIdAccountId.length === 0) { + return "invalid_exact_hedera_payload_transaction_invalid_shape"; + } + if (!isValidHederaEntityId(candidate.transactionIdAccountId)) { + return "invalid_exact_hedera_payload_transaction_invalid_shape"; + } + + const allTransferLists = [ + candidate.hbarTransfers, + ...Object.values(candidate.tokenTransfers as Record), + ]; + for (const transferList of allTransferLists) { + if (!Array.isArray(transferList)) { + return "invalid_exact_hedera_payload_transaction_invalid_shape"; + } + for (const transfer of transferList) { + if ( + !transfer || + typeof transfer.accountId !== "string" || + typeof transfer.amount !== "string" || + transfer.accountId.trim().length === 0 + ) { + return "invalid_exact_hedera_payload_transaction_invalid_shape"; + } + try { + BigInt(transfer.amount); + } catch { + return "invalid_exact_hedera_payload_transaction_invalid_shape"; + } + } + } + + return null; + } + + /** + * Validates request requirements and parity with payload.accepted. + * + * @param payload - Payment payload + * @param requirements - Matched requirements + * @returns Failed verify response or null + */ + private validateRequirements( + payload: PaymentPayload, + requirements: PaymentRequirements, + ): VerifyResponse | null { + if (payload.accepted.scheme !== "exact" || requirements.scheme !== "exact") { + return { isValid: false, invalidReason: "unsupported_scheme", payer: "" }; + } + if (payload.accepted.network !== requirements.network) { + return { isValid: false, invalidReason: "network_mismatch", payer: "" }; + } + if ( + payload.accepted.asset !== requirements.asset || + payload.accepted.amount !== requirements.amount || + payload.accepted.payTo !== requirements.payTo || + payload.accepted.maxTimeoutSeconds !== requirements.maxTimeoutSeconds || + payload.accepted.extra?.feePayer !== requirements.extra?.feePayer + ) { + return { isValid: false, invalidReason: "accepted_payment_requirements_mismatch", payer: "" }; + } + + try { + assertSupportedHederaNetwork(requirements.network); + } catch { + return { isValid: false, invalidReason: "network_mismatch", payer: "" }; + } + if (!isValidHederaAsset(requirements.asset)) { + return { isValid: false, invalidReason: "invalid_asset", payer: "" }; + } + if (!this.isValidPayToFormatForPolicy(requirements.payTo)) { + return { isValid: false, invalidReason: "invalid_exact_hedera_payload_pay_to", payer: "" }; + } + if (!/^\d+$/.test(requirements.amount)) { + return { isValid: false, invalidReason: "invalid_amount", payer: "" }; + } + + const feePayer = requirements.extra?.feePayer; + if (typeof feePayer !== "string" || !isValidHederaEntityId(feePayer)) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_missing_fee_payer", + payer: "", + }; + } + const managedSigners = this.signer.getAddresses(); + if (!managedSigners.includes(feePayer)) { + return { isValid: false, invalidReason: "fee_payer_not_managed_by_facilitator", payer: "" }; + } + + return null; + } + + /** + * Validates transfer semantics from inspected transaction details. + * + * @param inspected - Parsed transaction details + * @param requirements - Matched requirements + * @param feePayer - Fee payer account id + * @returns Failed verify response or null + */ + private validateTransferSemantics( + inspected: InspectedHederaTransaction, + requirements: PaymentRequirements, + feePayer: string, + ): VerifyResponse | null { + if (inspected.transactionIdAccountId !== feePayer) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_fee_payer_mismatch", + payer: "", + }; + } + if (inspected.hasNonTransferOperations) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_contains_non_transfer_ops", + payer: "", + }; + } + if (sumTransfers(inspected.hbarTransfers) !== 0n) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_hbar_sum_non_zero", + payer: "", + }; + } + if (this.hasNegativeTransfer(inspected.hbarTransfers, feePayer)) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_fee_payer_transferring_hbar", + payer: "", + }; + } + if (!isHbarAsset(requirements.asset) && inspected.hbarTransfers.length > 0) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_unexpected_hbar_transfers", + payer: "", + }; + } + + const payerTransfers = this.getAssetTransfers( + inspected.tokenTransfers, + inspected.hbarTransfers, + requirements, + ); + if (payerTransfers === null) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_asset_mismatch", + payer: "", + }; + } + + if (sumTransfers(payerTransfers) !== 0n) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_asset_sum_non_zero", + payer: "", + }; + } + if (this.hasNegativeTransfer(payerTransfers, feePayer)) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_fee_payer_transferring_funds", + payer: "", + }; + } + + const requiredAmount = BigInt(requirements.amount); + const netToPayTo = payerTransfers + .filter(entry => hederaAccountIdsEqual(entry.accountId, requirements.payTo)) + .reduce((sum, entry) => sum + BigInt(entry.amount), 0n); + if (netToPayTo !== requiredAmount) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_amount_mismatch", + payer: "", + }; + } + + const positiveReceivers = getPositiveReceivers(payerTransfers); + if ( + positiveReceivers.some(accountId => !hederaAccountIdsEqual(accountId, requirements.payTo)) + ) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_extra_positive_transfers", + payer: "", + }; + } + + return null; + } + + /** + * Validates payTo destination based on alias policy and optional resolver. + * + * @param requirements - Matched requirements + * @returns Failed verify response or null + */ + private async validatePayToPolicy( + requirements: PaymentRequirements, + ): Promise { + if (this.aliasPolicy === "allow") { + return null; + } + if (!isValidHederaEntityId(requirements.payTo)) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_pay_to_alias_not_allowed", + payer: "", + }; + } + if (typeof this.signer.resolveAccount !== "function") { + return null; + } + const resolved = await this.signer.resolveAccount(requirements.payTo, requirements.network); + if (!resolved.exists || resolved.isAlias) { + return { + isValid: false, + invalidReason: "invalid_exact_hedera_payload_pay_to_alias_not_allowed", + payer: "", + }; + } + return null; + } + + /** + * Validates payTo format based on alias policy. + * + * @param payTo - Destination account/alias value + * @returns True when payTo has acceptable format + */ + private isValidPayToFormatForPolicy(payTo: string): boolean { + if (typeof payTo !== "string" || payTo.trim().length === 0) { + return false; + } + if (this.aliasPolicy === "allow") { + return true; + } + return isValidHederaEntityId(payTo); + } +} diff --git a/typescript/packages/mechanisms/hedera/src/exact/index.ts b/typescript/packages/mechanisms/hedera/src/exact/index.ts new file mode 100644 index 0000000000..ebe552aa3c --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/exact/index.ts @@ -0,0 +1 @@ +export { ExactHederaScheme } from "./client/scheme"; diff --git a/typescript/packages/mechanisms/hedera/src/exact/server/index.ts b/typescript/packages/mechanisms/hedera/src/exact/server/index.ts new file mode 100644 index 0000000000..afa2415363 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/exact/server/index.ts @@ -0,0 +1,2 @@ +export { ExactHederaScheme } from "./scheme"; +export type { HederaServerConfig, HederaDefaultAssetConfig } from "./scheme"; diff --git a/typescript/packages/mechanisms/hedera/src/exact/server/scheme.ts b/typescript/packages/mechanisms/hedera/src/exact/server/scheme.ts new file mode 100644 index 0000000000..c6b130b6c2 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/exact/server/scheme.ts @@ -0,0 +1,182 @@ +import type { + AssetAmount, + Money, + MoneyParser, + Network, + PaymentRequirements, + Price, + SchemeNetworkServer, +} from "@x402/core/types"; +import { convertToTokenAmount } from "@x402/core/utils"; +import { assertSupportedHederaNetwork, isValidHederaAsset } from "../../utils"; +import { + HEDERA_MAINNET_CAIP2, + HEDERA_TESTNET_CAIP2, + HEDERA_MAINNET_USDC, + HEDERA_TESTNET_USDC, + HEDERA_USDC_DECIMALS, +} from "../../constants"; + +/** + * Default token config used for Money parsing fallback. + */ +export type HederaDefaultAssetConfig = { + asset: string; + decimals: number; +}; + +/** + * Server-side options for Hedera exact scheme. + */ +export type HederaServerConfig = { + defaultAssets?: Record; +}; + +/** + * Hedera server implementation for the Exact payment scheme. + */ +export class ExactHederaScheme implements SchemeNetworkServer { + readonly scheme = "exact"; + private moneyParsers: MoneyParser[] = []; + + /** + * Creates a new server scheme. + * + * @param config - Optional server config + */ + constructor(private readonly config: HederaServerConfig = {}) {} + + /** + * Register a custom money parser in order. + * + * @param parser - Money parser callback + * @returns Scheme instance + */ + registerMoneyParser(parser: MoneyParser): ExactHederaScheme { + this.moneyParsers.push(parser); + return this; + } + + /** + * Parse Money/AssetAmount into exact payment amount + asset. + * + * @param price - Price input + * @param network - Hedera network + * @returns Asset amount + */ + async parsePrice(price: Price, network: Network): Promise { + assertSupportedHederaNetwork(network); + + if (typeof price === "object" && price !== null && "amount" in price) { + if (!price.asset || !isValidHederaAsset(price.asset)) { + throw new Error(`Invalid Hedera asset identifier: ${price.asset}`); + } + return { + amount: price.amount, + asset: price.asset, + extra: price.extra || {}, + }; + } + + const amount = this.parseMoneyToDecimal(price as Money); + + for (const parser of this.moneyParsers) { + const parsed = await parser(amount, network); + if (parsed !== null) { + return parsed; + } + } + + return this.defaultMoneyConversion(amount, network); + } + + /** + * Merge facilitator-provided values into payment requirements. + * + * @param paymentRequirements - Base requirements + * @param supportedKind - Supported kind metadata + * @param supportedKind.x402Version - x402 protocol version + * @param supportedKind.scheme - Payment scheme identifier + * @param supportedKind.network - Network identifier + * @param supportedKind.extra - Additional metadata from facilitator supported kinds + * @param facilitatorExtensions - Extension keys + * @returns Enhanced requirements + */ + enhancePaymentRequirements( + paymentRequirements: PaymentRequirements, + supportedKind: { + x402Version: number; + scheme: string; + network: Network; + extra?: Record; + }, + facilitatorExtensions: string[], + ): Promise { + void facilitatorExtensions; + const extra: Record = { ...(paymentRequirements.extra || {}) }; + if (typeof supportedKind.extra?.feePayer === "string") { + extra.feePayer = supportedKind.extra.feePayer; + } + return Promise.resolve({ ...paymentRequirements, extra }); + } + + /** + * Parse flexible money value into decimal number. + * + * @param money - Money input + * @returns Decimal number + */ + private parseMoneyToDecimal(money: string | number): number { + if (typeof money === "number") { + return money; + } + const cleanMoney = money.replace(/^\$/, "").trim(); + const amount = parseFloat(cleanMoney); + if (isNaN(amount)) { + throw new Error(`Invalid money format: ${money}`); + } + return amount; + } + + /** + * Default conversion when no custom parser handles the value. + * + * @param amount - Decimal amount + * @param network - Hedera network + * @returns AssetAmount in configured default HTS token + */ + private defaultMoneyConversion(amount: number, network: Network): AssetAmount { + const tokenConfig = this.config.defaultAssets?.[network] ?? this.getBuiltInDefault(network); + if (!tokenConfig) { + throw new Error( + `No default HTS asset configured for network ${network}. Configure defaultAssets or provide explicit AssetAmount.`, + ); + } + if (!isValidHederaAsset(tokenConfig.asset) || tokenConfig.asset === "0.0.0") { + throw new Error("Default Hedera asset must be an HTS fungible token ID"); + } + + return { + amount: convertToTokenAmount(amount.toString(), tokenConfig.decimals), + asset: tokenConfig.asset, + extra: {}, + }; + } + + /** + * Returns the built-in default asset config for known Hedera networks. + * + * @param network - CAIP-2 network identifier + * @returns Default asset config or undefined for unknown networks + */ + private getBuiltInDefault(network: Network): HederaDefaultAssetConfig | undefined { + switch (network) { + case HEDERA_MAINNET_CAIP2: + return { asset: HEDERA_MAINNET_USDC, decimals: HEDERA_USDC_DECIMALS }; + case HEDERA_TESTNET_CAIP2: + return { asset: HEDERA_TESTNET_USDC, decimals: HEDERA_USDC_DECIMALS }; + default: + return undefined; + } + } +} diff --git a/typescript/packages/mechanisms/hedera/src/index.ts b/typescript/packages/mechanisms/hedera/src/index.ts new file mode 100644 index 0000000000..6fa37720e3 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/index.ts @@ -0,0 +1,25 @@ +export * from "./exact"; +export * from "./types"; +export * from "./constants"; +export * from "./signer"; +export * from "./preflight"; +export * from "./utils"; + +// Re-export the Hiero SDK primitives consumers need so that applications +// resolve a single SDK instance through @x402/hedera. Importing +// @hiero-ledger/sdk directly alongside this package in workspaces with +// independent pnpm stores yields duplicate installs whose `instanceof` and +// string-brand checks cross-fail at runtime ("t.startsWith is not a function"). +export { + AccountBalanceQuery, + AccountId, + AccountInfoQuery, + Client, + Hbar, + PrivateKey, + TokenAssociateTransaction, + TokenId, + Transaction, + TransactionId, + TransferTransaction, +} from "@hiero-ledger/sdk"; diff --git a/typescript/packages/mechanisms/hedera/src/preflight.ts b/typescript/packages/mechanisms/hedera/src/preflight.ts new file mode 100644 index 0000000000..29d70c7125 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/preflight.ts @@ -0,0 +1,105 @@ +import { + AccountBalanceQuery, + AccountId, + AccountInfoQuery, + Client, + TokenId, +} from "@hiero-ledger/sdk"; +import { isHbarAsset } from "./utils"; + +/** + * Parameters passed to a `FacilitatorHederaSigner.preflightTransfer` hook. + */ +export type HederaPreflightParams = { + payer: string; + payTo: string; + asset: string; + amount: string; + network: string; +}; + +/** + * Result returned from a `preflightTransfer` hook. + */ +export type HederaPreflightResult = { + ok: boolean; + reason?: string; + message?: string; +}; + +/** + * Builds a `preflightTransfer` implementation backed by the Hiero SDK. + * + * Checks the payer has sufficient balance of `asset` and that `payTo` is + * either associated with `asset` or has an available auto-association slot. + * Implements the SHOULD in `specs/schemes/exact/scheme_exact_hedera.md` §6. + * + * The caller supplies `buildClient(network)` — responsible for SDK client + * construction and operator setup (and node-URL selection, if any). The + * returned function closes the client in a `finally` block. + * + * @param buildClient - Factory that produces an SDK client for a given CAIP-2 network + * @returns A function suitable for `FacilitatorHederaSigner.preflightTransfer` + */ +export function createHederaPreflightTransfer( + buildClient: (network: string) => Client, +): (params: HederaPreflightParams) => Promise { + return async ({ payer, payTo, asset, amount, network }) => { + const client = buildClient(network); + try { + const required = BigInt(amount); + const balance = await new AccountBalanceQuery() + .setAccountId(AccountId.fromString(payer)) + .execute(client); + + if (isHbarAsset(asset)) { + const payerTinybars = BigInt(balance.hbars.toTinybars().toString()); + if (payerTinybars < required) { + return { + ok: false, + reason: "insufficient_balance", + message: `payer has ${payerTinybars} tinybars, needs ${required}`, + }; + } + return { ok: true }; + } + + const tokenId = TokenId.fromString(asset); + const payerTokenBal = balance.tokens?.get(tokenId); + const held = payerTokenBal ? BigInt(payerTokenBal.toString()) : 0n; + if (held < required) { + return { + ok: false, + reason: "insufficient_balance", + message: `payer holds ${held} of ${asset}, needs ${required}`, + }; + } + + const payToInfo = await new AccountInfoQuery() + .setAccountId(AccountId.fromString(payTo)) + .execute(client); + const alreadyAssociated = payToInfo.tokenRelationships?.get(tokenId) !== undefined; + if (alreadyAssociated) { + return { ok: true }; + } + const maxAuto = payToInfo.maxAutomaticTokenAssociations?.toNumber() ?? 0; + if (maxAuto === -1) { + return { ok: true }; + } + const currentAuto = payToInfo.tokenRelationships + ? Array.from(payToInfo.tokenRelationships.values()).filter(r => r.automaticAssociation) + .length + : 0; + if (maxAuto > 0 && currentAuto < maxAuto) { + return { ok: true }; + } + return { + ok: false, + reason: "pay_to_not_associated", + message: `payTo ${payTo} is not associated with ${asset} and has no auto-association slots`, + }; + } finally { + client.close(); + } + }; +} diff --git a/typescript/packages/mechanisms/hedera/src/signer.ts b/typescript/packages/mechanisms/hedera/src/signer.ts new file mode 100644 index 0000000000..688acd966e --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/signer.ts @@ -0,0 +1,252 @@ +import type { PaymentRequirements } from "@x402/core/types"; +import { + AccountId, + Client, + Hbar, + PrivateKey, + TokenId, + Transaction, + TransactionId, + TransferTransaction, +} from "@hiero-ledger/sdk"; +import { HEDERA_MAINNET_CAIP2, HEDERA_TESTNET_CAIP2 } from "./constants"; +import { assertSupportedHederaNetwork, isHbarAsset } from "./utils"; + +/** + * Client-side signer interface for Hedera transactions. + */ +export type ClientHederaSigner = { + /** + * Hedera account id of the payer creating the transfer. + */ + readonly accountId: string; + + /** + * Builds and signs a partially-signed TransferTransaction, + * returning it as base64 serialized bytes. + * + * @param requirements - Chosen payment requirements + * @returns Base64 transaction + */ + createPartiallySignedTransferTransaction(requirements: PaymentRequirements): Promise; +}; + +/** + * Optional account resolution result for alias policy checks. + */ +export type HederaAccountResolution = { + exists: boolean; + isAlias: boolean; +}; + +/** + * Minimal facilitator signer interface for Hedera verification + settlement. + */ +export type FacilitatorHederaSigner = { + /** + * Get all fee payer account ids managed by facilitator. + */ + getAddresses(): readonly string[]; + + /** + * Add fee payer signature and submit the transaction to Hedera. + * + * Must resolve only when the transaction has reached consensus with a + * SUCCESS receipt; any non-SUCCESS status (e.g. `TOKEN_NOT_ASSOCIATED_TO_ACCOUNT`, + * `INSUFFICIENT_ACCOUNT_BALANCE`, `INVALID_SIGNATURE`) must throw. The scheme + * translates thrown errors into `SettleResponse { success: false, + * errorReason: "transaction_failed" }`; a resolved promise is treated as + * an on-chain success. Use `createHederaSignAndSubmitTransaction` for a + * correct default implementation. + * + * @param transactionBase64 - Base64 transaction payload + * @param feePayer - Fee payer account + * @param network - CAIP-2 network + * @returns Settlement metadata with the Hedera transaction id + */ + signAndSubmitTransaction( + transactionBase64: string, + feePayer: string, + network: string, + ): Promise<{ transactionId: string }>; + + /** + * Optional account resolution hook (used for alias policy). + * + * @param accountIdOrAlias - payTo field value + * @param network - CAIP-2 network + * @returns Resolution status + */ + resolveAccount?(accountIdOrAlias: string, network: string): Promise; + + /** + * Optional pre-settlement check that the transfer is expected to succeed + * on chain. Implements the SHOULD in + * `specs/schemes/exact/scheme_exact_hedera.md` §6 — verify payer balance + * and recipient token association / auto-association capacity. + * + * The hook is advisory: if it throws or is unreachable, the scheme treats + * the check as failed and reports `invalid_exact_hedera_payload_preflight_failed`, + * but verify itself never throws. There is an inherent verify→settle race + * (balance may change between calls) — this is best-effort. + * + * @param params - Preflight parameters + * @param params.payer - Payer account id (inferred from decoded transfers) + * @param params.payTo - Destination account id from the payment requirements + * @param params.asset - "0.0.0" for HBAR or HTS token id + * @param params.amount - Transfer amount in tinybars or token smallest units + * @param params.network - CAIP-2 network identifier + * @returns `{ ok: true }` when the transfer is expected to succeed, + * otherwise `{ ok: false, reason?, message? }` + */ + preflightTransfer?(params: { + payer: string; + payTo: string; + asset: string; + amount: string; + network: string; + }): Promise<{ ok: boolean; reason?: string; message?: string }>; +}; + +/** + * Wraps a facilitator signer base object into a FacilitatorHederaSigner. + * + * @param base - Signer without getAddresses (uses getAddresses from base directly) + * @returns FacilitatorHederaSigner + */ +export function toFacilitatorHederaSigner(base: FacilitatorHederaSigner): FacilitatorHederaSigner { + return base; +} + +/** + * Optional configuration for the default client signer helper. + */ +export type HederaClientSignerConfig = { + /** + * Optional explicit network. + * If omitted, defaults to testnet. + */ + network?: string; + /** + * Optional custom node endpoint. + * Useful for private Hedera environments. + */ + nodeUrl?: string; +}; + +/** + * Creates a default SDK-backed client signer from account credentials. + * + * @param accountId - Hedera account id of the payer + * @param privateKey - Hedera SDK private key for signing + * @param config - Optional client configuration + * @returns Client signer implementation + */ +export function createClientHederaSigner( + accountId: string, + privateKey: PrivateKey, + config: HederaClientSignerConfig = {}, +): ClientHederaSigner { + const configuredNetwork = config.network ?? HEDERA_TESTNET_CAIP2; + assertSupportedHederaNetwork(configuredNetwork); + const parsedAccountId = AccountId.fromString(accountId); + const parsedPrivateKey = privateKey; + + return { + accountId: parsedAccountId.toString(), + createPartiallySignedTransferTransaction: async ( + requirements: PaymentRequirements, + ): Promise => { + assertSupportedHederaNetwork(requirements.network); + const feePayer = requirements.extra?.feePayer; + if (typeof feePayer !== "string") { + throw new Error("feePayer is required in paymentRequirements.extra"); + } + const amount = BigInt(requirements.amount); + if (amount <= 0n) { + throw new Error("amount must be greater than zero"); + } + + const payTo = AccountId.fromString(requirements.payTo); + const tx = new TransferTransaction(); + if (isHbarAsset(requirements.asset)) { + tx.addHbarTransfer(parsedAccountId, Hbar.fromTinybars((-amount).toString())); + tx.addHbarTransfer(payTo, Hbar.fromTinybars(amount.toString())); + } else { + const tokenId = TokenId.fromString(requirements.asset); + tx.addTokenTransfer(tokenId, parsedAccountId, -amount); + tx.addTokenTransfer(tokenId, payTo, amount); + } + + tx.setTransactionId(TransactionId.generate(AccountId.fromString(feePayer))); + + const client = createHederaClient(configuredNetwork, config.nodeUrl); + try { + tx.freezeWith(client); + const signed = await tx.sign(parsedPrivateKey); + return Buffer.from(signed.toBytes()).toString("base64"); + } finally { + client.close(); + } + }, + }; +} + +/** + * Builds a `signAndSubmitTransaction` implementation backed by the Hiero SDK + * that waits for consensus before reporting success. + * + * The SDK's `TransferTransaction.execute(client)` only performs a pre-check + * and returns once the transaction has been forwarded to a node. Consensus + * failures (`TOKEN_NOT_ASSOCIATED_TO_ACCOUNT`, `INSUFFICIENT_ACCOUNT_BALANCE`, + * `INVALID_SIGNATURE`, …) are only observable via `response.getReceipt(client)`, + * which throws a `ReceiptStatusError` when the status is not `SUCCESS`. The + * scheme's `settle()` converts that throw into + * `SettleResponse { success: false, errorReason: "transaction_failed" }`. + * + * @param buildClient - Factory that produces an SDK client for a given CAIP-2 network + * @param feePayerKey - Facilitator fee-payer private key used to add the fee-payer signature + * @returns An implementation suitable for `FacilitatorHederaSigner.signAndSubmitTransaction` + */ +export function createHederaSignAndSubmitTransaction( + buildClient: (network: string) => Client, + feePayerKey: PrivateKey, +): FacilitatorHederaSigner["signAndSubmitTransaction"] { + return async (transactionBase64, _feePayer, network) => { + const tx = Transaction.fromBytes(Buffer.from(transactionBase64, "base64")); + if (!(tx instanceof TransferTransaction)) { + throw new Error("expected TransferTransaction"); + } + const signed = await tx.sign(feePayerKey); + const client = buildClient(network); + try { + const response = await signed.execute(client); + await response.getReceipt(client); + return { transactionId: response.transactionId.toString() }; + } finally { + client.close(); + } + }; +} + +/** + * Creates a Hedera SDK client for a CAIP-2 network. + * + * @param network - Hedera network identifier + * @param nodeUrl - Optional custom node URL + * @returns Hedera SDK client + */ +export function createHederaClient(network: string, nodeUrl?: string): Client { + if (nodeUrl) { + // A custom endpoint is mapped to account 0.0.3 by default. + // This can be overridden by constructing your own ClientHederaSigner. + return Client.forNetwork({ [nodeUrl]: AccountId.fromString("0.0.3") }); + } + if (network === HEDERA_MAINNET_CAIP2) { + return Client.forMainnet(); + } + if (network === HEDERA_TESTNET_CAIP2) { + return Client.forTestnet(); + } + throw new Error(`Unsupported Hedera network: ${network}`); +} diff --git a/typescript/packages/mechanisms/hedera/src/types.ts b/typescript/packages/mechanisms/hedera/src/types.ts new file mode 100644 index 0000000000..8ea6e022a3 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/types.ts @@ -0,0 +1,31 @@ +/** + * Exact Hedera payload structure containing a base64 encoded transaction. + */ +export type ExactHederaPayloadV2 = { + /** + * Base64 encoded serialized, partially signed Hedera transaction. + */ + transaction: string; +}; + +/** + * A single signed transfer entry. + * Positive values credit an account, negative values debit an account. + */ +export type HederaTransferEntry = { + accountId: string; + amount: string; +}; + +/** + * Parsed transaction details used by facilitator verification. + * Utilities decode Hedera bytes and return this normalized shape. + */ +export type InspectedHederaTransaction = { + transactionType: string; + transactionId: string; + transactionIdAccountId: string; + hasNonTransferOperations: boolean; + hbarTransfers: HederaTransferEntry[]; + tokenTransfers: Record; +}; diff --git a/typescript/packages/mechanisms/hedera/src/utils.ts b/typescript/packages/mechanisms/hedera/src/utils.ts new file mode 100644 index 0000000000..e5a65976a6 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/src/utils.ts @@ -0,0 +1,214 @@ +import type { Network } from "@x402/core/types"; +import { AccountId, Transaction, TransferTransaction } from "@hiero-ledger/sdk"; +import { HBAR_ASSET_ID, HEDERA_ENTITY_ID_REGEX, SUPPORTED_HEDERA_NETWORKS } from "./constants"; +import type { + HederaTransferEntry, + ExactHederaPayloadV2, + InspectedHederaTransaction, +} from "./types"; + +/** + * Validate a Hedera account or token id string. + * + * @param entityId - Entity id to validate + * @returns True when valid + */ +export function isValidHederaEntityId(entityId: string): boolean { + return HEDERA_ENTITY_ID_REGEX.test(entityId); +} + +/** + * Returns true when the network is supported by this Hedera mechanism. + * + * @param network - Network identifier + * @returns True when supported + */ +export function isSupportedHederaNetwork( + network: string, +): network is (typeof SUPPORTED_HEDERA_NETWORKS)[number] { + return SUPPORTED_HEDERA_NETWORKS.includes(network as (typeof SUPPORTED_HEDERA_NETWORKS)[number]); +} + +/** + * Assert that a Hedera CAIP-2 network is supported by this mechanism. + * + * @param network - Network identifier + */ +export function assertSupportedHederaNetwork(network: string): asserts network is Network { + if (!isSupportedHederaNetwork(network)) { + throw new Error(`Unsupported Hedera network: ${network}`); + } +} + +/** + * Returns true if the asset identifier is native HBAR. + * + * @param asset - Asset identifier + * @returns True if HBAR + */ +export function isHbarAsset(asset: string): boolean { + return asset === HBAR_ASSET_ID; +} + +/** + * Validate that an asset is either HBAR or an HTS token id. + * + * @param asset - Asset identifier + * @returns True when valid + */ +export function isValidHederaAsset(asset: string): boolean { + return isHbarAsset(asset) || isValidHederaEntityId(asset); +} + +/** + * Extract transaction string from exact hedera payload. + * + * @param payload - Hedera payload + * @returns Base64 transaction string + */ +export function extractTransactionFromPayload(payload: ExactHederaPayloadV2): string { + if (!payload || typeof payload.transaction !== "string" || payload.transaction.length === 0) { + throw new Error("invalid_exact_hedera_payload_transaction"); + } + return payload.transaction; +} + +/** + * Decode and inspect a Hedera transaction from base64 bytes. + * + * @param transactionBase64 - Base64-encoded Hedera transaction + * @returns Normalized inspected transaction details + */ +export function inspectHederaTransaction(transactionBase64: string): InspectedHederaTransaction { + const bytes = Buffer.from(transactionBase64, "base64"); + const transaction = Transaction.fromBytes(bytes); + const isTransferTransaction = transaction instanceof TransferTransaction; + const hbarTransfers = isTransferTransaction + ? normalizeHbarTransfers(transaction.hbarTransfers) + : []; + const tokenTransfers = isTransferTransaction + ? normalizeTokenTransfers(transaction.tokenTransfers) + : {}; + const transactionType = transaction.constructor?.name; + const transactionId = transaction.transactionId?.toString?.(); + const transactionIdAccountId = transaction.transactionId?.accountId?.toString?.(); + + if (!transactionType || !transactionId || !transactionIdAccountId) { + throw new Error("invalid_hedera_transaction_metadata"); + } + + return { + transactionType, + transactionId, + transactionIdAccountId, + hasNonTransferOperations: !isTransferTransaction, + hbarTransfers, + tokenTransfers, + }; +} + +/** + * Sums a transfer list and returns net amount. + * + * @param transfers - Transfer entries + * @returns Net sum + */ +export function sumTransfers(transfers: HederaTransferEntry[]): bigint { + return transfers.reduce((sum, entry) => sum + BigInt(entry.amount), 0n); +} + +/** + * Returns net transfer value received by an account. + * + * @param transfers - Transfer entries + * @param accountId - Account to calculate for + * @returns Net amount + */ +export function getNetForAccount(transfers: HederaTransferEntry[], accountId: string): bigint { + return transfers + .filter(entry => hederaAccountIdsEqual(entry.accountId, accountId)) + .reduce((sum, entry) => sum + BigInt(entry.amount), 0n); +} + +/** + * Returns all account ids with positive net receipts. + * + * @param transfers - Transfer entries + * @returns Receiver ids + */ +export function getPositiveReceivers(transfers: HederaTransferEntry[]): string[] { + const net = new Map(); + for (const entry of transfers) { + net.set(entry.accountId, (net.get(entry.accountId) ?? 0n) + BigInt(entry.amount)); + } + return [...net.entries()].filter(([, value]) => value > 0n).map(([accountId]) => accountId); +} + +/** + * Canonicalize a Hedera account id or alias when possible. + * + * @param accountIdOrAlias - Account or alias value + * @returns Canonical id/alias, or original when parsing fails + */ +export function normalizeHederaAccountIdentifier(accountIdOrAlias: string): string { + try { + return AccountId.fromString(accountIdOrAlias).toString(); + } catch { + return accountIdOrAlias; + } +} + +/** + * Returns true when two account identifiers refer to the same account/alias. + * + * @param left - Left identifier + * @param right - Right identifier + * @returns True when canonicalized identifiers match + */ +export function hederaAccountIdsEqual(left: string, right: string): boolean { + return normalizeHederaAccountIdentifier(left) === normalizeHederaAccountIdentifier(right); +} + +/** + * Normalize SDK hbar transfers into shared transfer shape. + * + * @param hbarTransfers - Public Hedera SDK hbar transfer map + * @returns Normalized transfer entries + */ +function normalizeHbarTransfers( + hbarTransfers: TransferTransaction["hbarTransfers"], +): HederaTransferEntry[] { + const normalizedTransfers: HederaTransferEntry[] = []; + for (const [accountId, amount] of hbarTransfers) { + normalizedTransfers.push({ + accountId: accountId.toString(), + amount: amount.toTinybars().toString(), + }); + } + return normalizedTransfers; +} + +/** + * Group SDK token transfers by token id. + * + * @param tokenTransfers - Public Hedera SDK token transfer map + * @returns Token transfer map keyed by token id + */ +function normalizeTokenTransfers( + tokenTransfers: TransferTransaction["tokenTransfers"], +): Record { + const grouped: Record = {}; + for (const [tokenId, accountTransfers] of tokenTransfers) { + const normalizedTokenId = tokenId.toString(); + if (!grouped[normalizedTokenId]) { + grouped[normalizedTokenId] = []; + } + for (const [accountId, amount] of accountTransfers) { + grouped[normalizedTokenId].push({ + accountId: accountId.toString(), + amount: amount.toString(), + }); + } + } + return grouped; +} diff --git a/typescript/packages/mechanisms/hedera/test/integrations/exact-hedera.test.ts b/typescript/packages/mechanisms/hedera/test/integrations/exact-hedera.test.ts new file mode 100644 index 0000000000..bb6397723b --- /dev/null +++ b/typescript/packages/mechanisms/hedera/test/integrations/exact-hedera.test.ts @@ -0,0 +1,537 @@ +import { beforeEach, describe, expect, it } from "vitest"; +import { x402Client, x402HTTPClient } from "@x402/core/client"; +import { x402Facilitator } from "@x402/core/facilitator"; +import { + HTTPAdapter, + HTTPResponseInstructions, + x402HTTPResourceServer, + x402ResourceServer, + FacilitatorClient, +} from "@x402/core/server"; +import type { + Network, + PaymentPayload, + PaymentRequirements, + SettleResponse, + SupportedResponse, + VerifyResponse, +} from "@x402/core/types"; +import { AccountId, Client, PrivateKey, Transaction, TransferTransaction } from "@hiero-ledger/sdk"; +import { + type FacilitatorHederaSigner, + createClientHederaSigner, + createHederaSignAndSubmitTransaction, +} from "../../src/signer"; +import { createHederaPreflightTransfer } from "../../src/preflight"; +import { ExactHederaScheme as ExactHederaClient } from "../../src/exact/client/scheme"; +import { ExactHederaScheme as ExactHederaServer } from "../../src/exact/server/scheme"; +import { ExactHederaScheme as ExactHederaFacilitator } from "../../src/exact/facilitator/scheme"; +import { HEDERA_TESTNET_USDC } from "../../src/constants"; + +class HederaFacilitatorClient implements FacilitatorClient { + readonly scheme = "exact"; + readonly network = "hedera:testnet"; + readonly x402Version = 2; + + constructor(private readonly facilitator: x402Facilitator) {} + + verify( + paymentPayload: PaymentPayload, + paymentRequirements: PaymentRequirements, + ): Promise { + return this.facilitator.verify(paymentPayload, paymentRequirements); + } + + settle( + paymentPayload: PaymentPayload, + paymentRequirements: PaymentRequirements, + ): Promise { + return this.facilitator.settle(paymentPayload, paymentRequirements); + } + + getSupported(): Promise { + return Promise.resolve(this.facilitator.getSupported()); + } +} + +describe("Hedera integration", () => { + const deterministicClientAccount = "0.0.9001"; + const deterministicFeePayer = "0.0.5001"; + const deterministicResourceServerAccount = "0.0.7001"; + + const liveClientAccount = process.env.HEDERA_CLIENT_ACCOUNT_ID; + const liveClientPrivateKeyRaw = process.env.HEDERA_CLIENT_PRIVATE_KEY; + const liveFeePayerAccount = process.env.HEDERA_FACILITATOR_ACCOUNT_ID; + const liveFeePayerPrivateKeyRaw = process.env.HEDERA_FACILITATOR_PRIVATE_KEY; + const liveResourceServerAccount = process.env.HEDERA_RESOURCE_SERVER_ACCOUNT_ID; + const hasLiveEnv = Boolean( + liveClientAccount && + liveClientPrivateKeyRaw && + liveFeePayerAccount && + liveFeePayerPrivateKeyRaw && + liveResourceServerAccount, + ); + + function parseEcdsaPrivateKeyFromEnv(name: string, value: string): PrivateKey { + try { + return PrivateKey.fromStringECDSA(value); + } catch { + throw new Error( + `${name} must be a valid ECDSA private key string (0x-prefixed raw key or DER-encoded key).`, + ); + } + } + + function createLocalFinalizerSigner( + feePayerAccountId: string, + feePayerPrivateKey: PrivateKey, + ): FacilitatorHederaSigner { + return { + getAddresses: () => [feePayerAccountId], + signAndSubmitTransaction: async (transactionBase64: string) => { + const tx = Transaction.fromBytes(Buffer.from(transactionBase64, "base64")); + if (!(tx instanceof TransferTransaction)) { + throw new Error("expected TransferTransaction"); + } + const signed = await tx.sign(feePayerPrivateKey); + return { transactionId: signed.transactionId?.toString() ?? "" }; + }, + resolveAccount: async () => ({ exists: true, isAlias: false }), + }; + } + + function createLiveNetworkSigner( + feePayerAccountId: string, + feePayerPrivateKey: PrivateKey, + ): FacilitatorHederaSigner { + const buildClient = (network: string): Client => { + const client = network === "hedera:mainnet" ? Client.forMainnet() : Client.forTestnet(); + client.setOperator(AccountId.fromString(feePayerAccountId), feePayerPrivateKey); + return client; + }; + return { + getAddresses: () => [feePayerAccountId], + signAndSubmitTransaction: createHederaSignAndSubmitTransaction( + buildClient, + feePayerPrivateKey, + ), + resolveAccount: async () => ({ exists: true, isAlias: false }), + preflightTransfer: createHederaPreflightTransfer(buildClient), + }; + } + + describe("x402Client / x402ResourceServer / x402Facilitator flow", () => { + let client: x402Client; + let server: x402ResourceServer; + let paymentRequirements: PaymentRequirements; + let resource: { url: string; description: string; mimeType: string }; + + beforeEach(async () => { + const clientPrivateKey = PrivateKey.generateED25519(); + const feePayerPrivateKey = PrivateKey.generateED25519(); + const clientSigner = createClientHederaSigner(deterministicClientAccount, clientPrivateKey, { + network: "hedera:testnet", + }); + client = new x402Client().register("hedera:testnet", new ExactHederaClient(clientSigner)); + const hederaFacilitator = new ExactHederaFacilitator( + createLocalFinalizerSigner(deterministicFeePayer, feePayerPrivateKey), + ); + + const facilitator = new x402Facilitator().register("hedera:testnet", hederaFacilitator); + const facilitatorClient = new HederaFacilitatorClient(facilitator); + server = new x402ResourceServer(facilitatorClient); + server.register("hedera:testnet", new ExactHederaServer()); + await server.initialize(); + + paymentRequirements = { + scheme: "exact", + network: "hedera:testnet" as Network, + asset: "0.0.0", + amount: "1", + payTo: deterministicResourceServerAccount, + maxTimeoutSeconds: 180, + extra: { feePayer: deterministicFeePayer }, + }; + resource = { + url: "https://example.com/paid", + description: "Protected endpoint", + mimeType: "application/json", + }; + }); + + it("verifies and settles a client payment end-to-end", async () => { + const accepts = [paymentRequirements]; + + const paymentRequired = await server.createPaymentRequiredResponse(accepts, resource); + const paymentPayload = await client.createPaymentPayload(paymentRequired); + const accepted = server.findMatchingRequirements(accepts, paymentPayload); + expect(accepted).toBeDefined(); + + const verifyResponse = await server.verifyPayment(paymentPayload, accepted!); + expect(verifyResponse.isValid).toBe(true); + expect(verifyResponse.payer).toBe(deterministicClientAccount); + + const settleResponse = await server.settlePayment(paymentPayload, accepted!); + expect(settleResponse.success).toBe(true); + expect(settleResponse.network).toBe("hedera:testnet"); + expect(settleResponse.payer).toBe(deterministicClientAccount); + expect(settleResponse.transaction).toContain("0.0.5001@"); + }); + + it("verifies and settles a USDC client payment end-to-end", async () => { + const usdcRequirements: PaymentRequirements = { + ...paymentRequirements, + asset: HEDERA_TESTNET_USDC, + amount: "10000", // 0.01 USDC at 6 decimals + }; + const accepts = [usdcRequirements]; + + const paymentRequired = await server.createPaymentRequiredResponse(accepts, resource); + const paymentPayload = await client.createPaymentPayload(paymentRequired); + const accepted = server.findMatchingRequirements(accepts, paymentPayload); + expect(accepted).toBeDefined(); + expect(accepted!.asset).toBe(HEDERA_TESTNET_USDC); + + const verifyResponse = await server.verifyPayment(paymentPayload, accepted!); + expect(verifyResponse.isValid).toBe(true); + expect(verifyResponse.payer).toBe(deterministicClientAccount); + + const settleResponse = await server.settlePayment(paymentPayload, accepted!); + expect(settleResponse.success).toBe(true); + expect(settleResponse.network).toBe("hedera:testnet"); + expect(settleResponse.payer).toBe(deterministicClientAccount); + }); + }); + + describe("x402HTTPClient / x402HTTPResourceServer flow", () => { + let client: x402HTTPClient; + let httpServer: x402HTTPResourceServer; + + const routes = { + "/api/protected": { + accepts: { + scheme: "exact", + payTo: deterministicResourceServerAccount, + price: { + amount: "1", + asset: "0.0.0", + }, + network: "hedera:testnet" as Network, + }, + description: "Protected API", + mimeType: "application/json", + }, + }; + + const mockAdapter: HTTPAdapter = { + getHeader: () => undefined, + getMethod: () => "GET", + getPath: () => "/api/protected", + getUrl: () => "https://example.com/api/protected", + getAcceptHeader: () => "application/json", + getUserAgent: () => "IntegrationTest/1.0", + }; + + beforeEach(async () => { + const clientPrivateKey = PrivateKey.generateED25519(); + const feePayerPrivateKey = PrivateKey.generateED25519(); + const clientSigner = createClientHederaSigner(deterministicClientAccount, clientPrivateKey, { + network: "hedera:testnet", + }); + const paymentClient = new x402Client().register( + "hedera:testnet", + new ExactHederaClient(clientSigner), + ); + client = new x402HTTPClient(paymentClient) as x402HTTPClient; + + const hederaFacilitator = new ExactHederaFacilitator( + createLocalFinalizerSigner(deterministicFeePayer, feePayerPrivateKey), + ); + const facilitator = new x402Facilitator().register("hedera:testnet", hederaFacilitator); + const resourceServer = new x402ResourceServer(new HederaFacilitatorClient(facilitator)); + resourceServer.register("hedera:testnet", new ExactHederaServer()); + await resourceServer.initialize(); + + httpServer = new x402HTTPResourceServer(resourceServer, routes); + }); + + it("returns 402 then verifies payment via PAYMENT-SIGNATURE", async () => { + const context = { + adapter: mockAdapter, + path: "/api/protected", + method: "GET", + }; + const firstResult = await httpServer.processHTTPRequest(context); + expect(firstResult.type).toBe("payment-error"); + + const firstResponse = ( + firstResult as { type: "payment-error"; response: HTTPResponseInstructions } + ).response; + expect(firstResponse.status).toBe(402); + + const paymentRequired = client.getPaymentRequiredResponse( + headerName => firstResponse.headers[headerName], + firstResponse.body, + ); + const paymentPayload = await client.createPaymentPayload(paymentRequired); + const encoded = await client.encodePaymentSignatureHeader(paymentPayload); + + mockAdapter.getHeader = (name: string) => { + if (name === "PAYMENT-SIGNATURE") { + return encoded["PAYMENT-SIGNATURE"]; + } + return undefined; + }; + + const secondResult = await httpServer.processHTTPRequest(context); + expect(secondResult.type).toBe("payment-verified"); + + const { + paymentPayload: verifiedPaymentPayload, + paymentRequirements: verifiedPaymentRequirements, + } = secondResult as { + type: "payment-verified"; + paymentPayload: PaymentPayload; + paymentRequirements: PaymentRequirements; + }; + const settlementResult = await httpServer.processSettlement( + verifiedPaymentPayload, + verifiedPaymentRequirements, + 200, + ); + expect(settlementResult.success).toBe(true); + if (settlementResult.success) { + expect(settlementResult.headers["PAYMENT-RESPONSE"]).toBeDefined(); + } + }); + }); + + describe.skipIf(!hasLiveEnv)("Live Hedera network integration (env-gated)", () => { + it("verifies and settles using real Hedera submission", async () => { + const network = "hedera:testnet" as Network; + const parsedLiveClientPrivateKey = parseEcdsaPrivateKeyFromEnv( + "HEDERA_CLIENT_PRIVATE_KEY", + liveClientPrivateKeyRaw!, + ); + const parsedLiveFeePayerPrivateKey = parseEcdsaPrivateKeyFromEnv( + "HEDERA_FACILITATOR_PRIVATE_KEY", + liveFeePayerPrivateKeyRaw!, + ); + const clientSigner = createClientHederaSigner( + liveClientAccount!, + parsedLiveClientPrivateKey, + { + network, + }, + ); + const hederaFacilitator = new ExactHederaFacilitator( + createLiveNetworkSigner(liveFeePayerAccount!, parsedLiveFeePayerPrivateKey), + ); + const facilitator = new x402Facilitator().register(network, hederaFacilitator); + const server = new x402ResourceServer(new HederaFacilitatorClient(facilitator)); + server.register(network, new ExactHederaServer()); + await server.initialize(); + const client = new x402Client().register(network, new ExactHederaClient(clientSigner)); + + const accepts = [ + { + scheme: "exact", + network, + asset: "0.0.0", + amount: "1", + payTo: liveResourceServerAccount!, + maxTimeoutSeconds: 180, + extra: { feePayer: liveFeePayerAccount! }, + }, + ]; + const resource = { + url: "https://example.com/paid", + description: "Live Hedera check", + mimeType: "application/json", + }; + + const paymentRequired = await server.createPaymentRequiredResponse(accepts, resource); + const paymentPayload = await client.createPaymentPayload(paymentRequired); + const accepted = server.findMatchingRequirements(accepts, paymentPayload); + expect(accepted).toBeDefined(); + + const verifyResponse = await server.verifyPayment(paymentPayload, accepted!); + expect(verifyResponse.isValid).toBe(true); + + const settleResponse = await server.settlePayment(paymentPayload, accepted!); + expect(settleResponse.success).toBe(true); + expect(settleResponse.transaction.length).toBeGreaterThan(0); + }); + + it("preflight rejects verify when payer has insufficient balance", async () => { + const network = "hedera:testnet" as Network; + const parsedLiveClientPrivateKey = parseEcdsaPrivateKeyFromEnv( + "HEDERA_CLIENT_PRIVATE_KEY", + liveClientPrivateKeyRaw!, + ); + const parsedLiveFeePayerPrivateKey = parseEcdsaPrivateKeyFromEnv( + "HEDERA_FACILITATOR_PRIVATE_KEY", + liveFeePayerPrivateKeyRaw!, + ); + const clientSigner = createClientHederaSigner( + liveClientAccount!, + parsedLiveClientPrivateKey, + { network }, + ); + const hederaFacilitator = new ExactHederaFacilitator( + createLiveNetworkSigner(liveFeePayerAccount!, parsedLiveFeePayerPrivateKey), + ); + const facilitator = new x402Facilitator().register(network, hederaFacilitator); + const server = new x402ResourceServer(new HederaFacilitatorClient(facilitator)); + server.register(network, new ExactHederaServer()); + await server.initialize(); + const client = new x402Client().register(network, new ExactHederaClient(clientSigner)); + + const unreasonableAmount = "100000000000000000"; // ~10^18 tinybars, far above any testnet balance + const accepts = [ + { + scheme: "exact", + network, + asset: "0.0.0", + amount: unreasonableAmount, + payTo: liveResourceServerAccount!, + maxTimeoutSeconds: 180, + extra: { feePayer: liveFeePayerAccount! }, + }, + ]; + const resource = { + url: "https://example.com/paid", + description: "Preflight insufficient-balance check", + mimeType: "application/json", + }; + + const paymentRequired = await server.createPaymentRequiredResponse(accepts, resource); + const paymentPayload = await client.createPaymentPayload(paymentRequired); + const accepted = server.findMatchingRequirements(accepts, paymentPayload); + + const verifyResponse = await server.verifyPayment(paymentPayload, accepted!); + expect(verifyResponse.isValid).toBe(false); + expect(verifyResponse.invalidReason).toBe("invalid_exact_hedera_payload_preflight_failed"); + expect(verifyResponse.invalidMessage).toContain("insufficient_balance"); + }); + + it("verifies and settles a real USDC submission", async () => { + const network = "hedera:testnet" as Network; + const usdcAsset = process.env.HEDERA_LIVE_USDC_ASSET ?? HEDERA_TESTNET_USDC; + const parsedLiveClientPrivateKey = parseEcdsaPrivateKeyFromEnv( + "HEDERA_CLIENT_PRIVATE_KEY", + liveClientPrivateKeyRaw!, + ); + const parsedLiveFeePayerPrivateKey = parseEcdsaPrivateKeyFromEnv( + "HEDERA_FACILITATOR_PRIVATE_KEY", + liveFeePayerPrivateKeyRaw!, + ); + const clientSigner = createClientHederaSigner( + liveClientAccount!, + parsedLiveClientPrivateKey, + { network }, + ); + const hederaFacilitator = new ExactHederaFacilitator( + createLiveNetworkSigner(liveFeePayerAccount!, parsedLiveFeePayerPrivateKey), + ); + const facilitator = new x402Facilitator().register(network, hederaFacilitator); + const server = new x402ResourceServer(new HederaFacilitatorClient(facilitator)); + server.register(network, new ExactHederaServer()); + await server.initialize(); + const client = new x402Client().register(network, new ExactHederaClient(clientSigner)); + + const accepts = [ + { + scheme: "exact", + network, + asset: usdcAsset, + amount: "10000", // 0.01 USDC + payTo: liveResourceServerAccount!, + maxTimeoutSeconds: 180, + extra: { feePayer: liveFeePayerAccount! }, + }, + ]; + const resource = { + url: "https://example.com/paid", + description: "Live Hedera USDC settle", + mimeType: "application/json", + }; + + const paymentRequired = await server.createPaymentRequiredResponse(accepts, resource); + const paymentPayload = await client.createPaymentPayload(paymentRequired); + const accepted = server.findMatchingRequirements(accepts, paymentPayload); + expect(accepted).toBeDefined(); + + const verifyResponse = await server.verifyPayment(paymentPayload, accepted!); + console.log(JSON.stringify(verifyResponse)); + expect(verifyResponse.isValid).toBe(true); + + const settleResponse = await server.settlePayment(paymentPayload, accepted!); + expect(settleResponse.success).toBe(true); + expect(settleResponse.transaction.length).toBeGreaterThan(0); + }); + + it.skipIf(!process.env.HEDERA_UNASSOCIATED_RESOURCE_SERVER_ACCOUNT_ID)( + "reports failure when USDC transfer fails on-chain because payTo is not token-associated", + async () => { + const network = "hedera:testnet" as Network; + const usdcAsset = process.env.HEDERA_LIVE_USDC_ASSET ?? HEDERA_TESTNET_USDC; + const unassociatedPayTo = process.env.HEDERA_UNASSOCIATED_RESOURCE_SERVER_ACCOUNT_ID!; + const parsedLiveClientPrivateKey = parseEcdsaPrivateKeyFromEnv( + "HEDERA_CLIENT_PRIVATE_KEY", + liveClientPrivateKeyRaw!, + ); + const parsedLiveFeePayerPrivateKey = parseEcdsaPrivateKeyFromEnv( + "HEDERA_FACILITATOR_PRIVATE_KEY", + liveFeePayerPrivateKeyRaw!, + ); + const clientSigner = createClientHederaSigner( + liveClientAccount!, + parsedLiveClientPrivateKey, + { network }, + ); + // Disable preflight so settlement reaches execute()+getReceipt() and + // surfaces the real on-chain failure instead of being caught upstream. + const liveSigner: FacilitatorHederaSigner = { + ...createLiveNetworkSigner(liveFeePayerAccount!, parsedLiveFeePayerPrivateKey), + preflightTransfer: undefined, + }; + const hederaFacilitator = new ExactHederaFacilitator(liveSigner); + const facilitator = new x402Facilitator().register(network, hederaFacilitator); + const server = new x402ResourceServer(new HederaFacilitatorClient(facilitator)); + server.register(network, new ExactHederaServer()); + await server.initialize(); + const client = new x402Client().register(network, new ExactHederaClient(clientSigner)); + + const accepts = [ + { + scheme: "exact", + network, + asset: usdcAsset, + amount: "10000", + payTo: unassociatedPayTo, + maxTimeoutSeconds: 180, + extra: { feePayer: liveFeePayerAccount! }, + }, + ]; + const resource = { + url: "https://example.com/paid", + description: "Live Hedera USDC unassociated payTo", + mimeType: "application/json", + }; + + const paymentRequired = await server.createPaymentRequiredResponse(accepts, resource); + const paymentPayload = await client.createPaymentPayload(paymentRequired); + const accepted = server.findMatchingRequirements(accepts, paymentPayload); + + const settleResponse = await server.settlePayment(paymentPayload, accepted!); + // On a real unassociated recipient the Hedera consensus status returns + // TOKEN_NOT_ASSOCIATED_TO_ACCOUNT. The facilitator must surface that + // as a settlement failure instead of returning success with a tx id. + expect(settleResponse.success).toBe(false); + expect(settleResponse.errorReason).toBe("transaction_failed"); + expect(settleResponse.errorMessage).toMatch(/TOKEN_NOT_ASSOCIATED_TO_ACCOUNT/i); + }, + ); + }); +}); diff --git a/typescript/packages/mechanisms/hedera/test/unit/client.test.ts b/typescript/packages/mechanisms/hedera/test/unit/client.test.ts new file mode 100644 index 0000000000..e975c31b5a --- /dev/null +++ b/typescript/packages/mechanisms/hedera/test/unit/client.test.ts @@ -0,0 +1,95 @@ +import { describe, expect, it } from "vitest"; +import type { PaymentRequirements } from "@x402/core/types"; +import { ExactHederaScheme } from "../../src/exact/client/scheme"; + +describe("ExactHedera client scheme", () => { + it("creates payment payload from signer output", async () => { + const signer = { + accountId: "0.0.7001", + createPartiallySignedTransferTransaction: async () => "YmFzZTY0LXR4", + }; + const scheme = new ExactHederaScheme(signer); + const requirements: PaymentRequirements = { + scheme: "exact", + network: "hedera:testnet", + asset: "0.0.2001", + amount: "1000", + payTo: "0.0.4001", + maxTimeoutSeconds: 180, + extra: { + feePayer: "0.0.5001", + }, + }; + + const payload = await scheme.createPaymentPayload(2, requirements); + expect(payload.x402Version).toBe(2); + expect((payload.payload as { transaction: string }).transaction).toBe("YmFzZTY0LXR4"); + }); + + it("requires feePayer in requirements.extra", async () => { + const signer = { + accountId: "0.0.7001", + createPartiallySignedTransferTransaction: async () => "YmFzZTY0LXR4", + }; + const scheme = new ExactHederaScheme(signer); + const requirements: PaymentRequirements = { + scheme: "exact", + network: "hedera:testnet", + asset: "0.0.2001", + amount: "1000", + payTo: "0.0.4001", + maxTimeoutSeconds: 180, + extra: {}, + }; + + await expect(scheme.createPaymentPayload(2, requirements)).rejects.toThrow( + "feePayer is required", + ); + }); + + it("rejects non-exact scheme requirements", async () => { + const signer = { + accountId: "0.0.7001", + createPartiallySignedTransferTransaction: async () => "YmFzZTY0LXR4", + }; + const scheme = new ExactHederaScheme(signer); + const requirements = { + scheme: "permit", + network: "hedera:testnet", + asset: "0.0.2001", + amount: "1000", + payTo: "0.0.4001", + maxTimeoutSeconds: 180, + extra: { + feePayer: "0.0.5001", + }, + } as unknown as PaymentRequirements; + + await expect(scheme.createPaymentPayload(2, requirements)).rejects.toThrow( + "Unsupported scheme", + ); + }); + + it("rejects unsupported network", async () => { + const signer = { + accountId: "0.0.7001", + createPartiallySignedTransferTransaction: async () => "YmFzZTY0LXR4", + }; + const scheme = new ExactHederaScheme(signer); + const requirements = { + scheme: "exact", + network: "eip155:1", + asset: "0.0.2001", + amount: "1000", + payTo: "0.0.4001", + maxTimeoutSeconds: 180, + extra: { + feePayer: "0.0.5001", + }, + } as unknown as PaymentRequirements; + + await expect(scheme.createPaymentPayload(2, requirements)).rejects.toThrow( + "Unsupported Hedera network", + ); + }); +}); diff --git a/typescript/packages/mechanisms/hedera/test/unit/facilitator.test.ts b/typescript/packages/mechanisms/hedera/test/unit/facilitator.test.ts new file mode 100644 index 0000000000..272bd870ae --- /dev/null +++ b/typescript/packages/mechanisms/hedera/test/unit/facilitator.test.ts @@ -0,0 +1,730 @@ +import { describe, expect, it, vi } from "vitest"; +import type { PaymentPayload, PaymentRequirements } from "@x402/core/types"; +import { + AccountId, + Client, + Hbar, + PrivateKey, + TokenId, + TopicCreateTransaction, + TransactionId, + TransferTransaction, +} from "@hiero-ledger/sdk"; +import { ExactHederaScheme } from "../../src/exact/facilitator/scheme"; +import { HEDERA_MAINNET_USDC, HEDERA_TESTNET_USDC } from "../../src/constants"; + +const baseRequirements: PaymentRequirements = { + scheme: "exact", + network: "hedera:testnet", + asset: "0.0.6001", + amount: "1000", + payTo: "0.0.7001", + maxTimeoutSeconds: 180, + extra: { feePayer: "0.0.5001" }, +}; + +const basePayload: PaymentPayload = { + x402Version: 2, + resource: { + url: "https://example.com", + description: "resource", + mimeType: "application/json", + }, + accepted: baseRequirements, + payload: { + transaction: "", + }, +}; + +function createSigner() { + return { + getAddresses: () => ["0.0.5001"], + signAndSubmitTransaction: vi.fn(async () => ({ + transactionId: "0.0.5001@1700000001.000000000", + })), + resolveAccount: vi.fn(async () => ({ exists: true, isAlias: false })), + }; +} + +async function createTransferTransactionBase64(args: { + feePayer: string; + payer: string; + payTo: string; + asset: string; + amount: string; +}): Promise { + const tx = new TransferTransaction(); + const amount = BigInt(args.amount); + + if (args.asset === "0.0.0") { + tx.addHbarTransfer(AccountId.fromString(args.payer), Hbar.fromTinybars((-amount).toString())); + tx.addHbarTransfer(AccountId.fromString(args.payTo), Hbar.fromTinybars(amount.toString())); + } else { + const tokenId = TokenId.fromString(args.asset); + tx.addTokenTransfer(tokenId, AccountId.fromString(args.payer), (-amount).toString()); + tx.addTokenTransfer(tokenId, AccountId.fromString(args.payTo), amount.toString()); + } + + tx.setTransactionId(TransactionId.generate(AccountId.fromString(args.feePayer))); + await tx.freezeWith(Client.forTestnet()); + return Buffer.from(tx.toBytes()).toString("base64"); +} + +async function createTopicTransactionBase64(args: { feePayer: string }): Promise { + const tx = new TopicCreateTransaction(); + tx.setTransactionId(TransactionId.generate(AccountId.fromString(args.feePayer))); + tx.setTopicMemo("x402-non-transfer"); + const key = PrivateKey.generateED25519(); + tx.setSubmitKey(key.publicKey); + await tx.freezeWith(Client.forTestnet()); + return Buffer.from(tx.toBytes()).toString("base64"); +} + +describe("ExactHedera facilitator scheme", () => { + it("verifies a valid payload", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...basePayload, + payload: { + transaction: await createTransferTransactionBase64({ + feePayer: "0.0.5001", + payer: "0.0.9001", + payTo: "0.0.7001", + asset: "0.0.6001", + amount: "1000", + }), + }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(true); + expect(result.payer).toBe("0.0.9001"); + }); + + it("rejects unsupported token transfers", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...basePayload, + payload: { + transaction: await createTransferTransactionBase64({ + feePayer: "0.0.5001", + payer: "0.0.9001", + payTo: "0.0.7001", + asset: "0.0.1234", + amount: "1000", + }), + }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_asset_mismatch"); + }); + + it("enforces alias rejection by default", async () => { + const signer = createSigner(); + signer.resolveAccount = vi.fn(async () => ({ exists: false, isAlias: true })); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...basePayload, + payload: { + transaction: await createTransferTransactionBase64({ + feePayer: "0.0.5001", + payer: "0.0.9001", + payTo: "0.0.7001", + asset: "0.0.6001", + amount: "1000", + }), + }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_pay_to_alias_not_allowed"); + }); + + it("can allow aliases when configured", async () => { + const signer = createSigner(); + signer.resolveAccount = vi.fn(async () => ({ exists: false, isAlias: true })); + const aliasPayTo = "0x000000000000000000000000000000000000abcd"; + const aliasRequirements = { + ...baseRequirements, + payTo: aliasPayTo, + }; + const aliasPayload = { + ...basePayload, + accepted: aliasRequirements, + payload: { + transaction: await createTransferTransactionBase64({ + feePayer: "0.0.5001", + payer: "0.0.9001", + payTo: aliasPayTo, + asset: "0.0.6001", + amount: "1000", + }), + }, + }; + const scheme = new ExactHederaScheme(signer, { aliasPolicy: "allow" }); + + const result = await scheme.verify(aliasPayload, aliasRequirements); + expect(result.isValid).toBe(true); + }); + + it("rejects undecodable transaction payload", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...basePayload, + payload: { + transaction: "not-a-valid-hedera-transaction", + }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe( + "invalid_exact_hedera_payload_transaction_could_not_be_decoded", + ); + }); + + it("settles when verify passes", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...basePayload, + payload: { + transaction: await createTransferTransactionBase64({ + feePayer: "0.0.5001", + payer: "0.0.9001", + payTo: "0.0.7001", + asset: "0.0.6001", + amount: "1000", + }), + }, + }; + + const settled = await scheme.settle(payload, baseRequirements); + expect(settled.success).toBe(true); + expect(settled.transaction).toContain("0.0.5001@"); + }); + + it("rejects unsupported scheme", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...basePayload, + accepted: { ...baseRequirements, scheme: "something-else" }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("unsupported_scheme"); + }); + + it("rejects accepted requirements mismatch", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...basePayload, + accepted: { ...baseRequirements, amount: "999" }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("accepted_payment_requirements_mismatch"); + }); + + it("rejects network mismatch", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...basePayload, + accepted: { ...baseRequirements, network: "hedera:mainnet" }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("network_mismatch"); + }); + + it("returns invalid response for unsupported network value", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const invalidNetworkRequirements = { + ...baseRequirements, + network: "eip155:1", + } as unknown as PaymentRequirements; + const payload: PaymentPayload = { + ...basePayload, + accepted: invalidNetworkRequirements, + }; + + const result = await scheme.verify(payload, invalidNetworkRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("network_mismatch"); + }); + + it("rejects invalid asset in requirements", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const invalidRequirements = { ...baseRequirements, asset: "invalid-asset" }; + const payload = { ...basePayload, accepted: invalidRequirements }; + + const result = await scheme.verify(payload, invalidRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_asset"); + }); + + it("rejects invalid amount in requirements", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const invalidRequirements = { ...baseRequirements, amount: "1.23" }; + const payload = { ...basePayload, accepted: invalidRequirements }; + + const result = await scheme.verify(payload, invalidRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_amount"); + }); + + it("rejects missing feePayer in requirements", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const invalidRequirements = { ...baseRequirements, extra: {} }; + const payload = { ...basePayload, accepted: invalidRequirements }; + + const result = await scheme.verify(payload, invalidRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_missing_fee_payer"); + }); + + it("rejects feePayer not managed by facilitator", async () => { + const signer = createSigner(); + signer.getAddresses = () => ["0.0.9999"]; + const scheme = new ExactHederaScheme(signer); + + const result = await scheme.verify(basePayload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("fee_payer_not_managed_by_facilitator"); + }); + + it("rejects transaction fee payer mismatch", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...basePayload, + payload: { + transaction: await createTransferTransactionBase64({ + feePayer: "0.0.5002", + payer: "0.0.9001", + payTo: "0.0.7001", + asset: "0.0.6001", + amount: "1000", + }), + }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_fee_payer_mismatch"); + }); + + it("rejects non-transfer transaction types", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...basePayload, + payload: { transaction: await createTopicTransactionBase64({ feePayer: "0.0.5001" }) }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_contains_non_transfer_ops"); + }); + + it("rejects non-zero hbar transfer sum", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const tx = new TransferTransaction(); + tx.addHbarTransfer(AccountId.fromString("0.0.9001"), Hbar.fromTinybars("-1000")); + tx.addHbarTransfer(AccountId.fromString("0.0.7001"), Hbar.fromTinybars("900")); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.9001"), "-1000"); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.7001"), "1000"); + tx.setTransactionId(TransactionId.generate(AccountId.fromString("0.0.5001"))); + await tx.freezeWith(Client.forTestnet()); + const payload: PaymentPayload = { + ...basePayload, + payload: { transaction: Buffer.from(tx.toBytes()).toString("base64") }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_hbar_sum_non_zero"); + }); + + it("rejects token payment payloads that include hbar transfers", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const tx = new TransferTransaction(); + tx.addHbarTransfer(AccountId.fromString("0.0.9001"), Hbar.fromTinybars("-10")); + tx.addHbarTransfer(AccountId.fromString("0.0.7001"), Hbar.fromTinybars("10")); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.9001"), "-1000"); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.7001"), "1000"); + tx.setTransactionId(TransactionId.generate(AccountId.fromString("0.0.5001"))); + await tx.freezeWith(Client.forTestnet()); + const payload: PaymentPayload = { + ...basePayload, + payload: { transaction: Buffer.from(tx.toBytes()).toString("base64") }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_unexpected_hbar_transfers"); + }); + + it("rejects feePayer sending hbar", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const tx = new TransferTransaction(); + tx.addHbarTransfer(AccountId.fromString("0.0.5001"), Hbar.fromTinybars("-10")); + tx.addHbarTransfer(AccountId.fromString("0.0.9001"), Hbar.fromTinybars("10")); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.9001"), "-1000"); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.7001"), "1000"); + tx.setTransactionId(TransactionId.generate(AccountId.fromString("0.0.5001"))); + await tx.freezeWith(Client.forTestnet()); + const payload: PaymentPayload = { + ...basePayload, + payload: { transaction: Buffer.from(tx.toBytes()).toString("base64") }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_fee_payer_transferring_hbar"); + }); + + it("rejects non-zero asset transfer sum", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const tx = new TransferTransaction(); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.9001"), "-1000"); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.7001"), "900"); + tx.setTransactionId(TransactionId.generate(AccountId.fromString("0.0.5001"))); + await tx.freezeWith(Client.forTestnet()); + const payload: PaymentPayload = { + ...basePayload, + payload: { transaction: Buffer.from(tx.toBytes()).toString("base64") }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_asset_sum_non_zero"); + }); + + it("rejects feePayer sending requested asset", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const tx = new TransferTransaction(); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.5001"), "-1"); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.9001"), "-999"); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.7001"), "1000"); + tx.setTransactionId(TransactionId.generate(AccountId.fromString("0.0.5001"))); + await tx.freezeWith(Client.forTestnet()); + const payload: PaymentPayload = { + ...basePayload, + payload: { transaction: Buffer.from(tx.toBytes()).toString("base64") }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_fee_payer_transferring_funds"); + }); + + it("rejects amount mismatch to payTo", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const tx = new TransferTransaction(); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.9001"), "-1000"); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.7001"), "999"); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.7002"), "1"); + tx.setTransactionId(TransactionId.generate(AccountId.fromString("0.0.5001"))); + await tx.freezeWith(Client.forTestnet()); + const payload: PaymentPayload = { + ...basePayload, + payload: { transaction: Buffer.from(tx.toBytes()).toString("base64") }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_amount_mismatch"); + }); + + it("rejects extra positive recipients for requested asset", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const tx = new TransferTransaction(); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.9001"), "-1001"); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.7001"), "1000"); + tx.addTokenTransfer(TokenId.fromString("0.0.6001"), AccountId.fromString("0.0.7002"), "1"); + tx.setTransactionId(TransactionId.generate(AccountId.fromString("0.0.5001"))); + await tx.freezeWith(Client.forTestnet()); + const payload: PaymentPayload = { + ...basePayload, + payload: { transaction: Buffer.from(tx.toBytes()).toString("base64") }, + }; + + const result = await scheme.verify(payload, baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_extra_positive_transfers"); + }); + + it("rejects invalid payTo format when aliases are rejected", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer, { aliasPolicy: "reject" }); + const badRequirements = { ...baseRequirements, payTo: "not-an-account" }; + const badPayload = { ...basePayload, accepted: badRequirements }; + + const result = await scheme.verify(badPayload, badRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_pay_to"); + }); + + it("returns failed settlement when verify fails", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const badRequirements = { ...baseRequirements, amount: "bad" }; + const badPayload = { ...basePayload, accepted: badRequirements }; + + const settled = await scheme.settle(badPayload, badRequirements); + expect(settled.success).toBe(false); + expect(settled.errorReason).toBe("invalid_amount"); + }); + + it("returns transaction_failed when signAndSubmitTransaction throws", async () => { + const signer = createSigner(); + signer.signAndSubmitTransaction = vi.fn(async () => { + throw new Error("submit failed"); + }); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...basePayload, + payload: { + transaction: await createTransferTransactionBase64({ + feePayer: "0.0.5001", + payer: "0.0.9001", + payTo: "0.0.7001", + asset: "0.0.6001", + amount: "1000", + }), + }, + }; + + const settled = await scheme.settle(payload, baseRequirements); + expect(settled.success).toBe(false); + expect(settled.errorReason).toBe("transaction_failed"); + expect(settled.errorMessage).toContain("submit failed"); + }); + + it("returns managed signer addresses via getSigners", () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + expect(scheme.getSigners("hedera:testnet")).toEqual(["0.0.5001"]); + }); + + it("returns feePayer in getExtra", () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const extra = scheme.getExtra("hedera:testnet"); + expect(extra).toEqual({ feePayer: "0.0.5001" }); + }); + + it("returns undefined getExtra when no signer addresses are available", () => { + const signer = createSigner(); + signer.getAddresses = () => []; + const scheme = new ExactHederaScheme(signer); + const extra = scheme.getExtra("hedera:testnet"); + expect(extra).toBeUndefined(); + }); + + describe("preflightTransfer hook", () => { + async function buildValidPayload(): Promise { + return { + ...basePayload, + payload: { + transaction: await createTransferTransactionBase64({ + feePayer: "0.0.5001", + payer: "0.0.9001", + payTo: "0.0.7001", + asset: "0.0.6001", + amount: "1000", + }), + }, + }; + } + + it("passes payer/payTo/asset/amount/network to the hook", async () => { + const signer = { + ...createSigner(), + preflightTransfer: vi.fn(async () => ({ ok: true })), + }; + const scheme = new ExactHederaScheme(signer); + const result = await scheme.verify(await buildValidPayload(), baseRequirements); + expect(result.isValid).toBe(true); + expect(signer.preflightTransfer).toHaveBeenCalledWith({ + payer: "0.0.9001", + payTo: "0.0.7001", + asset: "0.0.6001", + amount: "1000", + network: "hedera:testnet", + }); + }); + + it("fails verify when hook returns ok:false with a reason", async () => { + const signer = { + ...createSigner(), + preflightTransfer: vi.fn(async () => ({ + ok: false, + reason: "insufficient_balance", + message: "payer has 500, needs 1000", + })), + }; + const scheme = new ExactHederaScheme(signer); + const result = await scheme.verify(await buildValidPayload(), baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_preflight_failed"); + expect(result.invalidMessage).toContain("insufficient_balance"); + expect(result.invalidMessage).toContain("payer has 500"); + expect(result.payer).toBe("0.0.9001"); + }); + + it("fails verify when hook throws", async () => { + const signer = { + ...createSigner(), + preflightTransfer: vi.fn(async () => { + throw new Error("mirror node unreachable"); + }), + }; + const scheme = new ExactHederaScheme(signer); + const result = await scheme.verify(await buildValidPayload(), baseRequirements); + expect(result.isValid).toBe(false); + expect(result.invalidReason).toBe("invalid_exact_hedera_payload_preflight_failed"); + expect(result.invalidMessage).toContain("mirror node unreachable"); + }); + + it("settle surfaces preflight failure as error", async () => { + const signer = { + ...createSigner(), + preflightTransfer: vi.fn(async () => ({ ok: false, reason: "pay_to_not_associated" })), + }; + const scheme = new ExactHederaScheme(signer); + const settled = await scheme.settle(await buildValidPayload(), baseRequirements); + expect(settled.success).toBe(false); + expect(settled.errorReason).toBe("invalid_exact_hedera_payload_preflight_failed"); + expect(settled.errorMessage).toContain("pay_to_not_associated"); + expect(signer.signAndSubmitTransaction).not.toHaveBeenCalled(); + }); + + it("is a no-op when hook is not defined", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const result = await scheme.verify(await buildValidPayload(), baseRequirements); + expect(result.isValid).toBe(true); + }); + }); + + describe("settle on-chain receipt handling", () => { + async function buildValidPayload(): Promise { + return { + ...basePayload, + payload: { + transaction: await createTransferTransactionBase64({ + feePayer: "0.0.5001", + payer: "0.0.9001", + payTo: "0.0.7001", + asset: "0.0.6001", + amount: "1000", + }), + }, + }; + } + + it("treats a signer throwing after submit as transaction_failed and carries the receipt status in errorMessage", async () => { + const signer = createSigner(); + // Simulates a live signer that executed and then called getReceipt(), + // which in turn threw because consensus status was not SUCCESS. + signer.signAndSubmitTransaction = vi.fn(async () => { + throw new Error( + "receipt for transaction 0.0.5001@1700000002.000000000 contained error status TOKEN_NOT_ASSOCIATED_TO_ACCOUNT", + ); + }); + const scheme = new ExactHederaScheme(signer); + + const settled = await scheme.settle(await buildValidPayload(), baseRequirements); + expect(settled.success).toBe(false); + expect(settled.errorReason).toBe("transaction_failed"); + expect(settled.errorMessage).toContain("TOKEN_NOT_ASSOCIATED_TO_ACCOUNT"); + expect(settled.transaction).toBe(""); + }); + }); + + describe.each([ + ["hedera:testnet", HEDERA_TESTNET_USDC], + ["hedera:mainnet", HEDERA_MAINNET_USDC], + ])("USDC verify + settle happy path on %s", (network, usdcAsset) => { + const usdcRequirements: PaymentRequirements = { + scheme: "exact", + network: network as PaymentRequirements["network"], + asset: usdcAsset, + amount: "10000", // 0.01 USDC at 6 decimals + payTo: "0.0.7001", + maxTimeoutSeconds: 180, + extra: { feePayer: "0.0.5001" }, + }; + const usdcBasePayload: PaymentPayload = { + ...basePayload, + accepted: usdcRequirements, + }; + + it("verifies a USDC transfer payload", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...usdcBasePayload, + payload: { + transaction: await createTransferTransactionBase64({ + feePayer: "0.0.5001", + payer: "0.0.9001", + payTo: "0.0.7001", + asset: usdcAsset, + amount: "10000", + }), + }, + }; + + const result = await scheme.verify(payload, usdcRequirements); + expect(result.isValid).toBe(true); + expect(result.payer).toBe("0.0.9001"); + }); + + it("settles a USDC transfer payload", async () => { + const signer = createSigner(); + const scheme = new ExactHederaScheme(signer); + const payload: PaymentPayload = { + ...usdcBasePayload, + payload: { + transaction: await createTransferTransactionBase64({ + feePayer: "0.0.5001", + payer: "0.0.9001", + payTo: "0.0.7001", + asset: usdcAsset, + amount: "10000", + }), + }, + }; + + const settled = await scheme.settle(payload, usdcRequirements); + expect(settled.success).toBe(true); + expect(settled.transaction).toContain("0.0.5001@"); + }); + }); +}); diff --git a/typescript/packages/mechanisms/hedera/test/unit/index.test.ts b/typescript/packages/mechanisms/hedera/test/unit/index.test.ts new file mode 100644 index 0000000000..18a06bb4bf --- /dev/null +++ b/typescript/packages/mechanisms/hedera/test/unit/index.test.ts @@ -0,0 +1,34 @@ +import { describe, expect, it } from "vitest"; +import { + createClientHederaSigner, + HBAR_ASSET_ID, + HEDERA_MAINNET_CAIP2, + HEDERA_TESTNET_CAIP2, + ExactHederaPayloadV2, +} from "../../src"; +import { ExactHederaScheme as ExactHederaClient } from "../../src/exact/client/scheme"; +import { ExactHederaScheme as ExactHederaServer } from "../../src/exact/server/scheme"; +import { ExactHederaScheme as ExactHederaFacilitator } from "../../src/exact/facilitator/scheme"; + +describe("@x402/hedera", () => { + it("exports expected constants", () => { + expect(HEDERA_MAINNET_CAIP2).toBe("hedera:mainnet"); + expect(HEDERA_TESTNET_CAIP2).toBe("hedera:testnet"); + expect(HBAR_ASSET_ID).toBe("0.0.0"); + }); + + it("exports exact payload type shape", () => { + const payload: ExactHederaPayloadV2 = { transaction: "dGVzdA==" }; + expect(payload.transaction).toBe("dGVzdA=="); + }); + + it("exports all scheme classes", () => { + expect(ExactHederaClient).toBeDefined(); + expect(ExactHederaServer).toBeDefined(); + expect(ExactHederaFacilitator).toBeDefined(); + }); + + it("exports signer helpers", () => { + expect(createClientHederaSigner).toBeTypeOf("function"); + }); +}); diff --git a/typescript/packages/mechanisms/hedera/test/unit/preflight.test.ts b/typescript/packages/mechanisms/hedera/test/unit/preflight.test.ts new file mode 100644 index 0000000000..9c3309f6c7 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/test/unit/preflight.test.ts @@ -0,0 +1,223 @@ +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const balanceExecute = vi.fn(); +const infoExecute = vi.fn(); +const setBalanceAccountId = vi.fn(function (this: unknown) { + return this; +}); +const setInfoAccountId = vi.fn(function (this: unknown) { + return this; +}); + +vi.mock("@hiero-ledger/sdk", async () => { + const actual = await vi.importActual("@hiero-ledger/sdk"); + class AccountBalanceQuery { + setAccountId = setBalanceAccountId; + execute = balanceExecute; + } + class AccountInfoQuery { + setAccountId = setInfoAccountId; + execute = infoExecute; + } + return { ...actual, AccountBalanceQuery, AccountInfoQuery }; +}); + +// Import after mock is registered. +import { createHederaPreflightTransfer } from "../../src/preflight"; + +const HBAR = "0.0.0"; +const TOKEN = "0.0.6001"; + +function fakeClient() { + return { close: vi.fn() } as unknown as import("@hiero-ledger/sdk").Client; +} + +function hbarBalance(tinybars: bigint) { + return { + hbars: { toTinybars: () => ({ toString: () => tinybars.toString() }) }, + tokens: undefined, + }; +} + +function tokenBalance(tokenId: string, amount: bigint) { + return { + hbars: { toTinybars: () => ({ toString: () => "0" }) }, + tokens: { + get: (tid: { toString(): string }) => + tid.toString() === tokenId ? { toString: () => amount.toString() } : undefined, + }, + }; +} + +function accountInfo(opts: { tokens?: Array<{ id: string; auto: boolean }>; maxAuto?: number }) { + const entries = opts.tokens ?? []; + const relationships = new Map(); + for (const e of entries) { + relationships.set(e.id, { automaticAssociation: e.auto }); + } + return { + // Real SDK uses Map; we key by string and + // normalize TokenId via toString() on lookups from the helper. + tokenRelationships: { + get: (tid: { toString(): string }) => relationships.get(tid.toString()), + values: () => relationships.values(), + }, + maxAutomaticTokenAssociations: { toNumber: () => opts.maxAuto ?? 0 }, + }; +} + +describe("createHederaPreflightTransfer", () => { + let client: ReturnType; + let build: ReturnType; + + beforeEach(() => { + balanceExecute.mockReset(); + infoExecute.mockReset(); + setBalanceAccountId.mockClear(); + setInfoAccountId.mockClear(); + client = fakeClient(); + build = vi.fn(() => client); + }); + + it("HBAR: ok when payer balance >= amount", async () => { + balanceExecute.mockResolvedValue(hbarBalance(5000n)); + const preflight = createHederaPreflightTransfer(build); + const r = await preflight({ + payer: "0.0.9001", + payTo: "0.0.7001", + asset: HBAR, + amount: "1000", + network: "hedera:testnet", + }); + expect(r).toEqual({ ok: true }); + expect((client as unknown as { close: ReturnType }).close).toHaveBeenCalled(); + }); + + it("HBAR: insufficient_balance when payer short", async () => { + balanceExecute.mockResolvedValue(hbarBalance(500n)); + const preflight = createHederaPreflightTransfer(build); + const r = await preflight({ + payer: "0.0.9001", + payTo: "0.0.7001", + asset: HBAR, + amount: "1000", + network: "hedera:testnet", + }); + expect(r.ok).toBe(false); + expect(r.reason).toBe("insufficient_balance"); + expect(r.message).toContain("500"); + }); + + it("HTS: insufficient token balance", async () => { + balanceExecute.mockResolvedValue(tokenBalance(TOKEN, 100n)); + const preflight = createHederaPreflightTransfer(build); + const r = await preflight({ + payer: "0.0.9001", + payTo: "0.0.7001", + asset: TOKEN, + amount: "1000", + network: "hedera:testnet", + }); + expect(r.ok).toBe(false); + expect(r.reason).toBe("insufficient_balance"); + }); + + it("HTS: ok when payTo already associated", async () => { + balanceExecute.mockResolvedValue(tokenBalance(TOKEN, 5000n)); + infoExecute.mockResolvedValue( + accountInfo({ tokens: [{ id: TOKEN, auto: false }], maxAuto: 0 }), + ); + const preflight = createHederaPreflightTransfer(build); + const r = await preflight({ + payer: "0.0.9001", + payTo: "0.0.7001", + asset: TOKEN, + amount: "1000", + network: "hedera:testnet", + }); + expect(r).toEqual({ ok: true }); + }); + + it("HTS: ok when payTo has unlimited auto-association (-1)", async () => { + balanceExecute.mockResolvedValue(tokenBalance(TOKEN, 5000n)); + infoExecute.mockResolvedValue(accountInfo({ tokens: [], maxAuto: -1 })); + const preflight = createHederaPreflightTransfer(build); + const r = await preflight({ + payer: "0.0.9001", + payTo: "0.0.7001", + asset: TOKEN, + amount: "1000", + network: "hedera:testnet", + }); + expect(r).toEqual({ ok: true }); + }); + + it("HTS: ok when payTo has available auto-association slot", async () => { + balanceExecute.mockResolvedValue(tokenBalance(TOKEN, 5000n)); + infoExecute.mockResolvedValue( + accountInfo({ tokens: [{ id: "0.0.9999", auto: true }], maxAuto: 3 }), + ); + const preflight = createHederaPreflightTransfer(build); + const r = await preflight({ + payer: "0.0.9001", + payTo: "0.0.7001", + asset: TOKEN, + amount: "1000", + network: "hedera:testnet", + }); + expect(r).toEqual({ ok: true }); + }); + + it("HTS: pay_to_not_associated when no association and no slots", async () => { + balanceExecute.mockResolvedValue(tokenBalance(TOKEN, 5000n)); + infoExecute.mockResolvedValue(accountInfo({ tokens: [], maxAuto: 0 })); + const preflight = createHederaPreflightTransfer(build); + const r = await preflight({ + payer: "0.0.9001", + payTo: "0.0.7001", + asset: TOKEN, + amount: "1000", + network: "hedera:testnet", + }); + expect(r.ok).toBe(false); + expect(r.reason).toBe("pay_to_not_associated"); + }); + + it("HTS: pay_to_not_associated when auto slots fully consumed", async () => { + balanceExecute.mockResolvedValue(tokenBalance(TOKEN, 5000n)); + infoExecute.mockResolvedValue( + accountInfo({ + tokens: [ + { id: "0.0.1", auto: true }, + { id: "0.0.2", auto: true }, + ], + maxAuto: 2, + }), + ); + const preflight = createHederaPreflightTransfer(build); + const r = await preflight({ + payer: "0.0.9001", + payTo: "0.0.7001", + asset: TOKEN, + amount: "1000", + network: "hedera:testnet", + }); + expect(r.ok).toBe(false); + expect(r.reason).toBe("pay_to_not_associated"); + }); + + it("closes the client even when a query throws", async () => { + balanceExecute.mockRejectedValue(new Error("mirror down")); + const preflight = createHederaPreflightTransfer(build); + await expect( + preflight({ + payer: "0.0.9001", + payTo: "0.0.7001", + asset: HBAR, + amount: "1000", + network: "hedera:testnet", + }), + ).rejects.toThrow("mirror down"); + expect((client as unknown as { close: ReturnType }).close).toHaveBeenCalled(); + }); +}); diff --git a/typescript/packages/mechanisms/hedera/test/unit/server.moneyParser.test.ts b/typescript/packages/mechanisms/hedera/test/unit/server.moneyParser.test.ts new file mode 100644 index 0000000000..31f5813ec9 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/test/unit/server.moneyParser.test.ts @@ -0,0 +1,89 @@ +import { describe, expect, it } from "vitest"; +import { ExactHederaScheme } from "../../src/exact/server/scheme"; + +describe("ExactHedera server money parsing", () => { + it("uses configured HTS default asset conversion", async () => { + const scheme = new ExactHederaScheme({ + defaultAssets: { + "hedera:testnet": { + asset: "0.0.5555", + decimals: 6, + }, + }, + }); + + const parsed = await scheme.parsePrice("$1.25", "hedera:testnet"); + expect(parsed.asset).toBe("0.0.5555"); + expect(parsed.amount).toBe("1250000"); + }); + + it("uses custom parser before default conversion", async () => { + const scheme = new ExactHederaScheme({ + defaultAssets: { + "hedera:testnet": { + asset: "0.0.5555", + decimals: 6, + }, + }, + }); + scheme.registerMoneyParser(async amount => { + if (amount > 100) { + return { amount: "1", asset: "0.0.9999", extra: { tier: "large" } }; + } + return null; + }); + + const parsed = await scheme.parsePrice(200, "hedera:testnet"); + expect(parsed.asset).toBe("0.0.9999"); + expect(parsed.extra?.tier).toBe("large"); + }); + + it("falls back to USDC when no default asset is configured", async () => { + const scheme = new ExactHederaScheme(); + const parsed = await scheme.parsePrice("$1.00", "hedera:testnet"); + expect(parsed.asset).toBe("0.0.429274"); // Hedera testnet USDC + expect(parsed.amount).toBe("1000000"); // 1.00 with 6 decimals + }); + + it("falls back to mainnet USDC when no default asset is configured", async () => { + const scheme = new ExactHederaScheme(); + const parsed = await scheme.parsePrice("$0.01", "hedera:mainnet"); + expect(parsed.asset).toBe("0.0.456858"); // Hedera mainnet USDC (Circle issued) + expect(parsed.amount).toBe("10000"); // 0.01 USDC at 6 decimals + }); + + it("throws if default asset is not configured for unknown network", async () => { + const scheme = new ExactHederaScheme(); + await expect(scheme.parsePrice("$1.00", "hedera:unknown")).rejects.toThrow( + "Unsupported Hedera network", + ); + }); + + it("throws on invalid money string", async () => { + const scheme = new ExactHederaScheme({ + defaultAssets: { + "hedera:testnet": { + asset: "0.0.5555", + decimals: 6, + }, + }, + }); + await expect(scheme.parsePrice("$abc", "hedera:testnet")).rejects.toThrow( + "Invalid money format", + ); + }); + + it("throws when default asset is configured as HBAR", async () => { + const scheme = new ExactHederaScheme({ + defaultAssets: { + "hedera:testnet": { + asset: "0.0.0", + decimals: 8, + }, + }, + }); + await expect(scheme.parsePrice("$1.00", "hedera:testnet")).rejects.toThrow( + "Default Hedera asset must be an HTS fungible token ID", + ); + }); +}); diff --git a/typescript/packages/mechanisms/hedera/test/unit/server.test.ts b/typescript/packages/mechanisms/hedera/test/unit/server.test.ts new file mode 100644 index 0000000000..3b243c578a --- /dev/null +++ b/typescript/packages/mechanisms/hedera/test/unit/server.test.ts @@ -0,0 +1,78 @@ +import { describe, expect, it } from "vitest"; +import type { PaymentRequirements } from "@x402/core/types"; +import { ExactHederaScheme } from "../../src/exact/server/scheme"; + +describe("ExactHedera server scheme", () => { + it("passes through explicit AssetAmount", async () => { + const scheme = new ExactHederaScheme(); + const parsed = await scheme.parsePrice( + { amount: "1000", asset: "0.0.2001", extra: { token: "USDC" } }, + "hedera:testnet", + ); + expect(parsed.amount).toBe("1000"); + expect(parsed.asset).toBe("0.0.2001"); + expect(parsed.extra?.token).toBe("USDC"); + }); + + it("enhances payment requirements with feePayer", async () => { + const scheme = new ExactHederaScheme(); + const base: PaymentRequirements = { + scheme: "exact", + network: "hedera:testnet", + asset: "0.0.2001", + amount: "1000", + payTo: "0.0.3001", + maxTimeoutSeconds: 60, + extra: {}, + }; + + const enhanced = await scheme.enhancePaymentRequirements( + base, + { + x402Version: 2, + scheme: "exact", + network: "hedera:testnet", + extra: { feePayer: "0.0.5001" }, + }, + [], + ); + + expect(enhanced.extra.feePayer).toBe("0.0.5001"); + }); + + it("rejects explicit AssetAmount with invalid asset id", async () => { + const scheme = new ExactHederaScheme(); + await expect( + scheme.parsePrice( + { amount: "1000", asset: "invalid-asset", extra: { token: "USDC" } }, + "hedera:testnet", + ), + ).rejects.toThrow("Invalid Hedera asset identifier"); + }); + + it("preserves existing extra when facilitator does not provide feePayer", async () => { + const scheme = new ExactHederaScheme(); + const base: PaymentRequirements = { + scheme: "exact", + network: "hedera:testnet", + asset: "0.0.2001", + amount: "1000", + payTo: "0.0.3001", + maxTimeoutSeconds: 60, + extra: { custom: "value" }, + }; + + const enhanced = await scheme.enhancePaymentRequirements( + base, + { + x402Version: 2, + scheme: "exact", + network: "hedera:testnet", + }, + [], + ); + + expect(enhanced.extra.custom).toBe("value"); + expect(enhanced.extra.feePayer).toBeUndefined(); + }); +}); diff --git a/typescript/packages/mechanisms/hedera/test/unit/signer.test.ts b/typescript/packages/mechanisms/hedera/test/unit/signer.test.ts new file mode 100644 index 0000000000..620763316e --- /dev/null +++ b/typescript/packages/mechanisms/hedera/test/unit/signer.test.ts @@ -0,0 +1,275 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; +import { + AccountId, + Client, + Hbar, + PrivateKey, + TokenId, + TopicCreateTransaction, + TransactionId, + TransferTransaction, +} from "@hiero-ledger/sdk"; +import { createClientHederaSigner, createHederaSignAndSubmitTransaction } from "../../src/signer"; +import { inspectHederaTransaction } from "../../src/utils"; +import { HEDERA_TESTNET_USDC } from "../../src/constants"; + +describe("Hedera signer helpers", () => { + it("creates default SDK-backed client signer", async () => { + const privateKey = PrivateKey.generateED25519(); + const signer = createClientHederaSigner("0.0.1001", privateKey, { + network: "hedera:testnet", + }); + + const txBase64 = await signer.createPartiallySignedTransferTransaction({ + scheme: "exact", + network: "hedera:testnet", + asset: "0.0.0", + amount: "1000", + payTo: "0.0.1002", + maxTimeoutSeconds: 120, + extra: { + feePayer: "0.0.1003", + }, + }); + + expect(typeof txBase64).toBe("string"); + expect(txBase64.length).toBeGreaterThan(0); + }); + + it("creates token transfer transaction for HTS assets", async () => { + const privateKey = PrivateKey.generateED25519(); + const signer = createClientHederaSigner("0.0.1001", privateKey, { + network: "hedera:testnet", + }); + + const txBase64 = await signer.createPartiallySignedTransferTransaction({ + scheme: "exact", + network: "hedera:testnet", + asset: "0.0.6001", + amount: "2500", + payTo: "0.0.1002", + maxTimeoutSeconds: 120, + extra: { + feePayer: "0.0.1003", + }, + }); + const inspected = inspectHederaTransaction(txBase64); + + expect(inspected.tokenTransfers["0.0.6001"]).toBeDefined(); + expect(inspected.hbarTransfers.length).toBe(0); + }); + + it("requires feePayer in requirements.extra", async () => { + const privateKey = PrivateKey.generateED25519(); + const signer = createClientHederaSigner("0.0.1001", privateKey, { + network: "hedera:testnet", + }); + + await expect( + signer.createPartiallySignedTransferTransaction({ + scheme: "exact", + network: "hedera:testnet", + asset: "0.0.0", + amount: "1000", + payTo: "0.0.1002", + maxTimeoutSeconds: 120, + extra: {}, + }), + ).rejects.toThrow("feePayer is required"); + }); + + it("rejects zero/negative transfer amounts", async () => { + const privateKey = PrivateKey.generateED25519(); + const signer = createClientHederaSigner("0.0.1001", privateKey, { + network: "hedera:testnet", + }); + + await expect( + signer.createPartiallySignedTransferTransaction({ + scheme: "exact", + network: "hedera:testnet", + asset: "0.0.0", + amount: "0", + payTo: "0.0.1002", + maxTimeoutSeconds: 120, + extra: { + feePayer: "0.0.1003", + }, + }), + ).rejects.toThrow("amount must be greater than zero"); + }); + + it("rejects invalid payTo account format", async () => { + const privateKey = PrivateKey.generateED25519(); + const signer = createClientHederaSigner("0.0.1001", privateKey, { + network: "hedera:testnet", + }); + + await expect( + signer.createPartiallySignedTransferTransaction({ + scheme: "exact", + network: "hedera:testnet", + asset: "0.0.0", + amount: "1", + payTo: "not-an-account", + maxTimeoutSeconds: 120, + extra: { + feePayer: "0.0.1003", + }, + }), + ).rejects.toThrow(); + }); + + it("supports repeated signing calls on the same signer instance", async () => { + const privateKey = PrivateKey.generateED25519(); + const signer = createClientHederaSigner("0.0.1001", privateKey, { + network: "hedera:testnet", + }); + + const requirements = { + scheme: "exact" as const, + network: "hedera:testnet", + asset: "0.0.0", + amount: "1000", + payTo: "0.0.1002", + maxTimeoutSeconds: 120, + extra: { feePayer: "0.0.1003" }, + }; + + const first = await signer.createPartiallySignedTransferTransaction(requirements); + const second = await signer.createPartiallySignedTransferTransaction(requirements); + + expect(first.length).toBeGreaterThan(0); + expect(second.length).toBeGreaterThan(0); + }); + + it("supports custom node URL client configuration", async () => { + const privateKey = PrivateKey.generateED25519(); + const signer = createClientHederaSigner("0.0.1001", privateKey, { + network: "hedera:testnet", + nodeUrl: "127.0.0.1:50211", + }); + + const txBase64 = await signer.createPartiallySignedTransferTransaction({ + scheme: "exact", + network: "hedera:testnet", + asset: "0.0.0", + amount: "1", + payTo: "0.0.1002", + maxTimeoutSeconds: 120, + extra: { + feePayer: "0.0.1003", + }, + }); + + expect(typeof txBase64).toBe("string"); + expect(txBase64.length).toBeGreaterThan(0); + }); +}); + +describe("createHederaSignAndSubmitTransaction", () => { + const feePayerKey = PrivateKey.generateED25519(); + const feePayerAccount = "0.0.5001"; + + async function buildTransferBase64(asset: string): Promise { + const tx = new TransferTransaction(); + const amount = BigInt("10000"); + if (asset === "0.0.0") { + tx.addHbarTransfer(AccountId.fromString("0.0.9001"), Hbar.fromTinybars((-amount).toString())); + tx.addHbarTransfer(AccountId.fromString("0.0.7001"), Hbar.fromTinybars(amount.toString())); + } else { + const tokenId = TokenId.fromString(asset); + tx.addTokenTransfer(tokenId, AccountId.fromString("0.0.9001"), (-amount).toString()); + tx.addTokenTransfer(tokenId, AccountId.fromString("0.0.7001"), amount.toString()); + } + tx.setTransactionId(TransactionId.generate(AccountId.fromString(feePayerAccount))); + await tx.freezeWith(Client.forTestnet()); + return Buffer.from(tx.toBytes()).toString("base64"); + } + + function fakeClient(): Client { + return { close: vi.fn() } as unknown as Client; + } + + afterEach(() => { + vi.restoreAllMocks(); + }); + + it("returns the transactionId when the receipt reports SUCCESS", async () => { + const closeSpy = vi.fn(); + const builtClient = { close: closeSpy } as unknown as Client; + const expectedId = "0.0.5001@1700000002.000000000"; + const getReceipt = vi.fn().mockResolvedValue({ status: "SUCCESS" }); + vi.spyOn(TransferTransaction.prototype, "execute").mockResolvedValue({ + transactionId: { toString: () => expectedId }, + getReceipt, + } as never); + + const submit = createHederaSignAndSubmitTransaction(() => builtClient, feePayerKey); + const result = await submit( + await buildTransferBase64(HEDERA_TESTNET_USDC), + feePayerAccount, + "hedera:testnet", + ); + + expect(result).toEqual({ transactionId: expectedId }); + expect(getReceipt).toHaveBeenCalledWith(builtClient); + expect(closeSpy).toHaveBeenCalledTimes(1); + }); + + it.each([ + ["TOKEN_NOT_ASSOCIATED_TO_ACCOUNT", HEDERA_TESTNET_USDC], + ["INSUFFICIENT_ACCOUNT_BALANCE", "0.0.0"], + ])("surfaces %s when getReceipt rejects (asset %s)", async (statusCode, asset) => { + const closeSpy = vi.fn(); + const builtClient = { close: closeSpy } as unknown as Client; + const getReceipt = vi + .fn() + .mockRejectedValue( + new Error( + `receipt for transaction 0.0.5001@1700000002.000000000 contained error status ${statusCode}`, + ), + ); + vi.spyOn(TransferTransaction.prototype, "execute").mockResolvedValue({ + transactionId: { toString: () => "0.0.5001@1700000002.000000000" }, + getReceipt, + } as never); + + const submit = createHederaSignAndSubmitTransaction(() => builtClient, feePayerKey); + + await expect( + submit(await buildTransferBase64(asset), feePayerAccount, "hedera:testnet"), + ).rejects.toThrow(new RegExp(statusCode)); + expect(closeSpy).toHaveBeenCalledTimes(1); + }); + + it("closes the client when execute itself rejects (pre-check failure)", async () => { + const closeSpy = vi.fn(); + const builtClient = { close: closeSpy } as unknown as Client; + vi.spyOn(TransferTransaction.prototype, "execute").mockRejectedValue( + new Error("transaction precheck failed: INVALID_SIGNATURE"), + ); + + const submit = createHederaSignAndSubmitTransaction(() => builtClient, feePayerKey); + + await expect( + submit(await buildTransferBase64("0.0.0"), feePayerAccount, "hedera:testnet"), + ).rejects.toThrow(/INVALID_SIGNATURE/); + expect(closeSpy).toHaveBeenCalledTimes(1); + }); + + it("rejects payloads that are not TransferTransactions", async () => { + const tx = new TopicCreateTransaction(); + tx.setTopicMemo("not-a-transfer"); + tx.setTransactionId(TransactionId.generate(AccountId.fromString(feePayerAccount))); + const key = PrivateKey.generateED25519(); + tx.setSubmitKey(key.publicKey); + await tx.freezeWith(Client.forTestnet()); + const base64 = Buffer.from(tx.toBytes()).toString("base64"); + + const submit = createHederaSignAndSubmitTransaction(() => fakeClient(), feePayerKey); + await expect(submit(base64, feePayerAccount, "hedera:testnet")).rejects.toThrow( + /expected TransferTransaction/, + ); + }); +}); diff --git a/typescript/packages/mechanisms/hedera/test/unit/types.test.ts b/typescript/packages/mechanisms/hedera/test/unit/types.test.ts new file mode 100644 index 0000000000..0d7e2d3652 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/test/unit/types.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, it } from "vitest"; +import type { + ExactHederaPayloadV2, + HederaTransferEntry, + InspectedHederaTransaction, +} from "../../src"; + +describe("Hedera types", () => { + it("accepts exact payload", () => { + const payload: ExactHederaPayloadV2 = { transaction: "dGVzdA==" }; + expect(payload.transaction).toBe("dGVzdA=="); + }); + + it("accepts transfer entries", () => { + const entry: HederaTransferEntry = { accountId: "0.0.1001", amount: "-10" }; + expect(entry.accountId).toBe("0.0.1001"); + }); + + it("accepts inspected transaction shape", () => { + const tx: InspectedHederaTransaction = { + transactionType: "TransferTransaction", + transactionId: "0.0.10@1700000000.000000000", + transactionIdAccountId: "0.0.10", + hasNonTransferOperations: false, + hbarTransfers: [], + tokenTransfers: {}, + }; + expect(tx.transactionType).toBe("TransferTransaction"); + }); +}); diff --git a/typescript/packages/mechanisms/hedera/test/unit/utils.test.ts b/typescript/packages/mechanisms/hedera/test/unit/utils.test.ts new file mode 100644 index 0000000000..9f08fb9855 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/test/unit/utils.test.ts @@ -0,0 +1,17 @@ +import { describe, expect, it } from "vitest"; +import { HEDERA_TESTNET_CAIP2 } from "../../src/constants"; +import { assertSupportedHederaNetwork, isSupportedHederaNetwork } from "../../src/utils"; + +describe("Hedera utils", () => { + it("detects supported Hedera networks", () => { + expect(isSupportedHederaNetwork(HEDERA_TESTNET_CAIP2)).toBe(true); + expect(isSupportedHederaNetwork("hedera:previewnet")).toBe(false); + }); + + it("asserts supported Hedera networks", () => { + expect(() => assertSupportedHederaNetwork(HEDERA_TESTNET_CAIP2)).not.toThrow(); + expect(() => assertSupportedHederaNetwork("hedera:previewnet")).toThrow( + "Unsupported Hedera network: hedera:previewnet", + ); + }); +}); diff --git a/typescript/packages/mechanisms/hedera/tsconfig.json b/typescript/packages/mechanisms/hedera/tsconfig.json new file mode 100644 index 0000000000..f600458996 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/tsconfig.json @@ -0,0 +1,9 @@ +{ + "extends": "../../../tsconfig.base.json", + "compilerOptions": { + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist", "test"] +} diff --git a/typescript/packages/mechanisms/hedera/tsup.config.ts b/typescript/packages/mechanisms/hedera/tsup.config.ts new file mode 100644 index 0000000000..1143bfeaf5 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/tsup.config.ts @@ -0,0 +1,30 @@ +import { defineConfig } from "tsup"; + +const baseConfig = { + entry: { + index: "src/index.ts", + "exact/client/index": "src/exact/client/index.ts", + "exact/server/index": "src/exact/server/index.ts", + "exact/facilitator/index": "src/exact/facilitator/index.ts", + }, + dts: { + resolve: true, + }, + sourcemap: true, + target: "es2020", +}; + +export default defineConfig([ + { + ...baseConfig, + format: "esm", + outDir: "dist/esm", + clean: true, + }, + { + ...baseConfig, + format: "cjs", + outDir: "dist/cjs", + clean: false, + }, +]); diff --git a/typescript/packages/mechanisms/hedera/vitest.config.ts b/typescript/packages/mechanisms/hedera/vitest.config.ts new file mode 100644 index 0000000000..a03dc8bc65 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/vitest.config.ts @@ -0,0 +1,11 @@ +import { loadEnv } from "vite"; +import { defineConfig } from "vitest/config"; +import tsconfigPaths from "vite-tsconfig-paths"; + +export default defineConfig(({ mode }) => ({ + test: { + env: loadEnv(mode, process.cwd(), ""), + exclude: ["**/node_modules/**", "**/dist/**", "**/test/integrations/**"], + }, + plugins: [tsconfigPaths({ projects: ["."] })], +})); diff --git a/typescript/packages/mechanisms/hedera/vitest.integration.config.ts b/typescript/packages/mechanisms/hedera/vitest.integration.config.ts new file mode 100644 index 0000000000..ec2d58dd93 --- /dev/null +++ b/typescript/packages/mechanisms/hedera/vitest.integration.config.ts @@ -0,0 +1,11 @@ +import { loadEnv } from "vite"; +import { defineConfig } from "vitest/config"; +import tsconfigPaths from "vite-tsconfig-paths"; + +export default defineConfig(({ mode }) => ({ + test: { + env: loadEnv(mode, process.cwd(), ""), + include: ["test/integrations/**/*.test.ts"], + }, + plugins: [tsconfigPaths({ projects: ["."] })], +})); diff --git a/typescript/packages/mechanisms/stellar/CHANGELOG.md b/typescript/packages/mechanisms/stellar/CHANGELOG.md index f92323e95a..befbd844af 100644 --- a/typescript/packages/mechanisms/stellar/CHANGELOG.md +++ b/typescript/packages/mechanisms/stellar/CHANGELOG.md @@ -1,5 +1,43 @@ # @x402/stellar Changelog +## 2.12.0 + +### Minor Changes + +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] + - @x402/core@2.12.0 + +## 2.11.0 + +### Minor Changes + +- dc04108: Fixed a bug affecting USD prices with 7+ decimal places of precision (e.g. `$0.0000001` or smaller). +- Updated dependencies [a051f48] +- Updated dependencies [dc04108] + - @x402/core@2.11.0 + +## 2.10.0 + +### Minor Changes + +- @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization + +### Patch Changes + +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/mechanisms/stellar/README.md b/typescript/packages/mechanisms/stellar/README.md index efffd237f6..1328ba4ac8 100644 --- a/typescript/packages/mechanisms/stellar/README.md +++ b/typescript/packages/mechanisms/stellar/README.md @@ -1,4 +1,4 @@ -# @x402/stellar +# `@x402/stellar` [![npm version](https://img.shields.io/npm/v/%40x402%2Fstellar.svg)](https://www.npmjs.com/package/@x402/stellar) Stellar implementation of the x402 payment protocol using the **Exact** payment scheme with [Soroban token](https://stellar.org/protocol/sep-41) transfers. diff --git a/typescript/packages/mechanisms/stellar/package.json b/typescript/packages/mechanisms/stellar/package.json index 324a32b1c0..eb59179a45 100644 --- a/typescript/packages/mechanisms/stellar/package.json +++ b/typescript/packages/mechanisms/stellar/package.json @@ -1,6 +1,6 @@ { "name": "@x402/stellar", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/cjs/index.d.ts", @@ -25,8 +25,8 @@ "soroban" ], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol Stellar Implementation", "devDependencies": { "@eslint/js": "^9.24.0", @@ -39,7 +39,7 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", @@ -47,7 +47,7 @@ }, "dependencies": { "@stellar/stellar-sdk": "^14.6.1", - "@x402/core": "workspace:*" + "@x402/core": "workspace:~" }, "exports": { ".": { diff --git a/typescript/packages/mechanisms/stellar/src/exact/server/scheme.ts b/typescript/packages/mechanisms/stellar/src/exact/server/scheme.ts index df9e6df072..bf13699295 100644 --- a/typescript/packages/mechanisms/stellar/src/exact/server/scheme.ts +++ b/typescript/packages/mechanisms/stellar/src/exact/server/scheme.ts @@ -1,5 +1,6 @@ +import { convertToTokenAmount, numberToDecimalString } from "@x402/core/utils"; import { DEFAULT_TOKEN_DECIMALS } from "../../constants"; -import { convertToTokenAmount, getUsdcAddress } from "../../utils"; +import { getUsdcAddress } from "../../utils"; import type { AssetAmount, Network, @@ -139,7 +140,7 @@ export class ExactStellarScheme implements SchemeNetworkServer { */ private defaultMoneyConversion(amount: number, network: Network): AssetAmount { // Convert decimal amount to token amount (USDC on Stellar has 7 decimals) - const tokenAmount = convertToTokenAmount(amount.toString(), DEFAULT_TOKEN_DECIMALS); + const tokenAmount = convertToTokenAmount(numberToDecimalString(amount), DEFAULT_TOKEN_DECIMALS); return { amount: tokenAmount, diff --git a/typescript/packages/mechanisms/stellar/src/utils.ts b/typescript/packages/mechanisms/stellar/src/utils.ts index 2005cc2969..bf11818675 100644 --- a/typescript/packages/mechanisms/stellar/src/utils.ts +++ b/typescript/packages/mechanisms/stellar/src/utils.ts @@ -1,4 +1,8 @@ import { Horizon, rpc } from "@stellar/stellar-sdk"; +import { + convertToTokenAmount as coreConvertToTokenAmount, + numberToDecimalString, +} from "@x402/core/utils"; import { DEFAULT_PUBNET_HORIZON_URL, DEFAULT_TESTNET_HORIZON_URL, @@ -171,45 +175,19 @@ export function getUsdcAddress(network: Network): string { } } +export { numberToDecimalString }; + /** - * Converts a decimal amount to token smallest units - * - * Handles both regular decimal strings (e.g., "0.10") and scientific notation (e.g., "1e-7"). - * The result is truncated (not rounded) to the specified number of decimal places. + * Converts a decimal amount to token smallest units. + * Wraps the core utility with Stellar's default of 7 decimal places. * * @param decimalAmount - The decimal amount as a string - * @param decimals - Number of decimal places for the token (default: 7 for USDC) - * @returns The amount in smallest units as a string with leading zeros removed - * @throws {Error} If the amount is invalid or decimals is out of range - * - * @example - * ```ts - * convertToTokenAmount("0.1", 7) // "1000000" - * convertToTokenAmount("1.5", 7) // "15000000" - * convertToTokenAmount("1e-7", 7) // "1" - * convertToTokenAmount("1.5", 0) // "1" (truncated) - * ``` + * @param decimals - Number of decimal places for the token (default: 7 for Stellar USDC) + * @returns The amount in smallest units as a string */ export function convertToTokenAmount( decimalAmount: string, decimals: number = DEFAULT_TOKEN_DECIMALS, ): string { - const amount = parseFloat(decimalAmount); - if (isNaN(amount)) { - throw new Error(`Invalid amount: ${decimalAmount}`); - } - - if (decimals < 0 || decimals > 20) { - throw new Error(`Decimals must be between 0 and 20, got ${decimals}`); - } - - // Normalize scientific notation to fixed decimal string - const normalizedDecimal = /[eE]/.test(decimalAmount) - ? amount.toFixed(Math.max(decimals, 20)) - : decimalAmount; - - const [intPart, decPart = ""] = normalizedDecimal.split("."); - const paddedDec = decPart.padEnd(decimals, "0").slice(0, decimals); - - return (intPart + paddedDec).replace(/^0+/, "") || "0"; + return coreConvertToTokenAmount(decimalAmount, decimals); } diff --git a/typescript/packages/mechanisms/stellar/test/unit/utils.test.ts b/typescript/packages/mechanisms/stellar/test/unit/utils.test.ts index 4adaf1a44f..9db22c8589 100644 --- a/typescript/packages/mechanisms/stellar/test/unit/utils.test.ts +++ b/typescript/packages/mechanisms/stellar/test/unit/utils.test.ts @@ -331,7 +331,10 @@ describe("Stellar RPC Helper Functions", () => { it("should handle very small amounts", () => { expect(convertToTokenAmount("0.0000001")).toBe("1"); - expect(convertToTokenAmount("0.00000001")).toBe("0"); + }); + + it("should throw when amount rounds down to 0", () => { + expect(() => convertToTokenAmount("0.00000001")).toThrow("too small"); }); it("should truncate excess decimal places", () => { @@ -361,12 +364,10 @@ describe("Stellar RPC Helper Functions", () => { expect(convertToTokenAmount("-1.5")).toBe("-15000000"); }); - it("should handle scientific notation input", () => { - // Scientific notation should be correctly converted - // 1e-7 = 0.0000001, which with 7 decimals = 1 - expect(convertToTokenAmount("1e-7")).toBe("1"); - expect(convertToTokenAmount("1e-6")).toBe("10"); - expect(convertToTokenAmount("1.5e-6")).toBe("15"); + it("should throw for scientific notation input", () => { + expect(() => convertToTokenAmount("1e-7")).toThrow("scientific notation"); + expect(() => convertToTokenAmount("1e-6")).toThrow("scientific notation"); + expect(() => convertToTokenAmount("1.5e-6")).toThrow("scientific notation"); }); it("should handle very large numbers", () => { @@ -384,15 +385,6 @@ describe("Stellar RPC Helper Functions", () => { it("should throw error for NaN", () => { expect(() => convertToTokenAmount("NaN")).toThrow("Invalid amount: NaN"); }); - - it("should throw error for invalid decimals", () => { - expect(() => convertToTokenAmount("1.5", -1)).toThrow( - "Decimals must be between 0 and 20, got -1", - ); - expect(() => convertToTokenAmount("1.5", 21)).toThrow( - "Decimals must be between 0 and 20, got 21", - ); - }); }); }); }); diff --git a/typescript/packages/mechanisms/svm/CHANGELOG.md b/typescript/packages/mechanisms/svm/CHANGELOG.md index f471bd210b..b40d90f258 100644 --- a/typescript/packages/mechanisms/svm/CHANGELOG.md +++ b/typescript/packages/mechanisms/svm/CHANGELOG.md @@ -1,5 +1,45 @@ # @x402/svm Changelog +## 2.12.0 + +### Minor Changes + +- Updated dependencies [608034f] +- Updated dependencies [d235050] +- Updated dependencies [45d7d19] + - @x402/core@2.12.0 + +## 2.11.0 + +### Minor Changes + +- dc04108: Fixed a bug affecting USD prices with 7+ decimal places of precision (e.g. `$0.0000001` or smaller). +- Updated dependencies [a051f48] +- Updated dependencies [dc04108] + - @x402/core@2.11.0 + +## 2.10.0 + +### Minor Changes + +- 077b294: Add optional `extra.memo` support to SVM exact scheme. When a seller provides `extra.memo` in PaymentRequirements, the client uses it as the Memo instruction data instead of a random nonce, and the facilitator verifies the memo content matches. Enables payment reconciliation without unique deposit addresses. + +- @x402/core@2.10.0 + +## 2.9.0 + +### Minor Changes + +- 2250cae: Migrated project from coinbase/x402 to x402-foundation/x402 organization + +### Patch Changes + +- Updated dependencies [8cf3fca] +- Updated dependencies [c0e3969] +- Updated dependencies [2250cae] +- Updated dependencies [d352574] + - @x402/core@2.9.0 + ## 2.8.0 ### Minor Changes diff --git a/typescript/packages/mechanisms/svm/README.md b/typescript/packages/mechanisms/svm/README.md index 01601da1fa..4d3865e798 100644 --- a/typescript/packages/mechanisms/svm/README.md +++ b/typescript/packages/mechanisms/svm/README.md @@ -1,4 +1,4 @@ -# @x402/svm +# `@x402/svm` [![npm version](https://img.shields.io/npm/v/%40x402%2Fsvm.svg)](https://www.npmjs.com/package/@x402/svm) SVM (Solana Virtual Machine) implementation of the x402 payment protocol using the **Exact** payment scheme with SPL Token transfers. diff --git a/typescript/packages/mechanisms/svm/package.json b/typescript/packages/mechanisms/svm/package.json index c810376358..561d10b12f 100644 --- a/typescript/packages/mechanisms/svm/package.json +++ b/typescript/packages/mechanisms/svm/package.json @@ -1,6 +1,6 @@ { "name": "@x402/svm", - "version": "2.8.0", + "version": "2.12.0", "main": "./dist/cjs/index.js", "module": "./dist/esm/index.js", "types": "./dist/cjs/index.d.ts", @@ -24,8 +24,8 @@ "solana" ], "license": "Apache-2.0", - "author": "Coinbase Inc.", - "repository": "https://github.com/coinbase/x402", + "author": "x402 Foundation", + "repository": "https://github.com/x402-foundation/x402", "description": "x402 Payment Protocol SVM Implementation", "devDependencies": { "@eslint/js": "^9.24.0", @@ -39,7 +39,7 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tsup": "^8.4.0", - "tsx": "^4.19.2", + "tsx": "^4.21.0", "typescript": "^5.7.3", "vite": "^6.2.6", "vite-tsconfig-paths": "^5.1.4", diff --git a/typescript/packages/mechanisms/svm/src/constants.ts b/typescript/packages/mechanisms/svm/src/constants.ts index ea79bb3b86..62ac43b5dd 100644 --- a/typescript/packages/mechanisms/svm/src/constants.ts +++ b/typescript/packages/mechanisms/svm/src/constants.ts @@ -13,7 +13,7 @@ export const MEMO_PROGRAM_ADDRESS = "MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr * - Phantom adds 1 Lighthouse instruction (4th instruction) * - Solflare adds 2 Lighthouse instructions (4th and 5th instructions) * We allow these as optional instructions to support these wallets. - * See: https://github.com/coinbase/x402/issues/828 + * See: https://github.com/x402-foundation/x402/issues/828 */ export const LIGHTHOUSE_PROGRAM_ADDRESS = "L2TExMFKdjpN9kozasaurPirfHy9P8sbXoAN1qA3S95"; @@ -41,6 +41,7 @@ export const USDC_TESTNET_ADDRESS = "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncD export const DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 1; export const MAX_COMPUTE_UNIT_PRICE_MICROLAMPORTS = 5_000_000; // 5 lamports export const DEFAULT_COMPUTE_UNIT_LIMIT = 20_000; +export const MAX_MEMO_BYTES = 256; /** * How long a transaction is held in the duplicate settlement cache (ms). diff --git a/typescript/packages/mechanisms/svm/src/exact/client/scheme.ts b/typescript/packages/mechanisms/svm/src/exact/client/scheme.ts index a635c7558f..eada959df1 100644 --- a/typescript/packages/mechanisms/svm/src/exact/client/scheme.ts +++ b/typescript/packages/mechanisms/svm/src/exact/client/scheme.ts @@ -24,6 +24,7 @@ import type { PaymentPayload, PaymentRequirements, SchemeNetworkClient } from "@ import { DEFAULT_COMPUTE_UNIT_LIMIT, DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS, + MAX_MEMO_BYTES, MEMO_PROGRAM_ADDRESS, } from "../../constants"; import type { ClientSvmConfig, ClientSvmSigner } from "../../signer"; @@ -103,15 +104,25 @@ export class ExactSvmScheme implements SchemeNetworkClient { const { value: latestBlockhash } = await rpc.getLatestBlockhash().send(); - const nonce = crypto.getRandomValues(new Uint8Array(16)); - const memoIx = { - programAddress: MEMO_PROGRAM_ADDRESS as Address, - accounts: [] as const, - data: new TextEncoder().encode( + const sellerMemo = paymentRequirements.extra?.memo as string | undefined; + let memoData: Uint8Array; + if (sellerMemo) { + memoData = new TextEncoder().encode(sellerMemo); + if (memoData.byteLength > MAX_MEMO_BYTES) { + throw new Error(`extra.memo exceeds maximum ${MAX_MEMO_BYTES} bytes`); + } + } else { + const nonce = crypto.getRandomValues(new Uint8Array(16)); + memoData = new TextEncoder().encode( Array.from(nonce) .map(b => b.toString(16).padStart(2, "0")) .join(""), - ), + ); + } + const memoIx = { + programAddress: MEMO_PROGRAM_ADDRESS as Address, + accounts: [] as const, + data: memoData, }; const tx = pipe( diff --git a/typescript/packages/mechanisms/svm/src/exact/facilitator/scheme.ts b/typescript/packages/mechanisms/svm/src/exact/facilitator/scheme.ts index 9ea1acef26..54105be597 100644 --- a/typescript/packages/mechanisms/svm/src/exact/facilitator/scheme.ts +++ b/typescript/packages/mechanisms/svm/src/exact/facilitator/scheme.ts @@ -155,7 +155,7 @@ export class ExactSvmScheme implements SchemeNetworkFacilitator { // - 4 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse or Memo // - 5 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse + Lighthouse or Memo // - 6 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse + Lighthouse + Memo - // See: https://github.com/coinbase/x402/issues/828 + // See: https://github.com/x402-foundation/x402/issues/828 if (instructions.length < 3 || instructions.length > 6) { return { isValid: false, @@ -301,6 +301,30 @@ export class ExactSvmScheme implements SchemeNetworkFacilitator { }; } + // Step 5b: Verify memo content matches extra.memo when present + const expectedMemo = requirements.extra?.memo as string | undefined; + if (expectedMemo) { + const memoInstructions = optionalInstructions.filter( + ix => ix.programAddress.toString() === MEMO_PROGRAM_ADDRESS, + ); + if (memoInstructions.length !== 1) { + return { + isValid: false, + invalidReason: "invalid_exact_svm_payload_memo_count", + payer, + }; + } + const memoData = memoInstructions[0].data; + const actualMemo = memoData ? new TextDecoder().decode(new Uint8Array(memoData)) : ""; + if (actualMemo !== expectedMemo) { + return { + isValid: false, + invalidReason: "invalid_exact_svm_payload_memo_mismatch", + payer, + }; + } + } + // Step 6: Sign and Simulate Transaction // CRITICAL: Simulation proves transaction will succeed (catches insufficient balance, invalid accounts, etc) try { diff --git a/typescript/packages/mechanisms/svm/src/exact/server/scheme.ts b/typescript/packages/mechanisms/svm/src/exact/server/scheme.ts index 912016a876..0fd4a94a9c 100644 --- a/typescript/packages/mechanisms/svm/src/exact/server/scheme.ts +++ b/typescript/packages/mechanisms/svm/src/exact/server/scheme.ts @@ -6,7 +6,7 @@ import type { SchemeNetworkServer, MoneyParser, } from "@x402/core/types"; -import { convertToTokenAmount, getUsdcAddress } from "../../utils"; +import { convertToTokenAmount, getUsdcAddress, numberToDecimalString } from "../../utils"; /** * SVM server implementation for the Exact payment scheme. @@ -137,7 +137,7 @@ export class ExactSvmScheme implements SchemeNetworkServer { */ private defaultMoneyConversion(amount: number, network: Network): AssetAmount { // Convert decimal amount to token amount (USDC has 6 decimals) - const tokenAmount = convertToTokenAmount(amount.toString(), 6); + const tokenAmount = convertToTokenAmount(numberToDecimalString(amount), 6); return { amount: tokenAmount, diff --git a/typescript/packages/mechanisms/svm/src/exact/v1/client/scheme.ts b/typescript/packages/mechanisms/svm/src/exact/v1/client/scheme.ts index 031f41e43b..10860b4fae 100644 --- a/typescript/packages/mechanisms/svm/src/exact/v1/client/scheme.ts +++ b/typescript/packages/mechanisms/svm/src/exact/v1/client/scheme.ts @@ -30,6 +30,7 @@ import type { PaymentRequirementsV1 } from "@x402/core/types/v1"; import { DEFAULT_COMPUTE_UNIT_LIMIT, DEFAULT_COMPUTE_UNIT_PRICE_MICROLAMPORTS, + MAX_MEMO_BYTES, MEMO_PROGRAM_ADDRESS, } from "../../../constants"; import type { ClientSvmConfig, ClientSvmSigner } from "../../../signer"; @@ -112,15 +113,25 @@ export class ExactSvmSchemeV1 implements SchemeNetworkClient { const { value: latestBlockhash } = await rpc.getLatestBlockhash().send(); - const nonce = crypto.getRandomValues(new Uint8Array(16)); - const memoIx = { - programAddress: MEMO_PROGRAM_ADDRESS as Address, - accounts: [] as const, - data: new TextEncoder().encode( + const sellerMemo = selectedV1.extra?.memo as string | undefined; + let memoData: Uint8Array; + if (sellerMemo) { + memoData = new TextEncoder().encode(sellerMemo); + if (memoData.byteLength > MAX_MEMO_BYTES) { + throw new Error(`extra.memo exceeds maximum ${MAX_MEMO_BYTES} bytes`); + } + } else { + const nonce = crypto.getRandomValues(new Uint8Array(16)); + memoData = new TextEncoder().encode( Array.from(nonce) .map(b => b.toString(16).padStart(2, "0")) .join(""), - ), + ); + } + const memoIx = { + programAddress: MEMO_PROGRAM_ADDRESS as Address, + accounts: [] as const, + data: memoData, }; const tx = pipe( diff --git a/typescript/packages/mechanisms/svm/src/exact/v1/facilitator/scheme.ts b/typescript/packages/mechanisms/svm/src/exact/v1/facilitator/scheme.ts index 297eaf6ae8..5bc6d690a6 100644 --- a/typescript/packages/mechanisms/svm/src/exact/v1/facilitator/scheme.ts +++ b/typescript/packages/mechanisms/svm/src/exact/v1/facilitator/scheme.ts @@ -158,7 +158,7 @@ export class ExactSvmSchemeV1 implements SchemeNetworkFacilitator { // - 4 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse or Memo // - 5 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse + Lighthouse or Memo // - 6 instructions: ComputeLimit + ComputePrice + TransferChecked + Lighthouse + Lighthouse + Memo - // See: https://github.com/coinbase/x402/issues/828 + // See: https://github.com/x402-foundation/x402/issues/828 if (instructions.length < 3 || instructions.length > 6) { return { isValid: false, @@ -304,6 +304,30 @@ export class ExactSvmSchemeV1 implements SchemeNetworkFacilitator { }; } + // Step 5b: Verify memo content matches extra.memo when present + const expectedMemo = requirementsV1.extra?.memo as string | undefined; + if (expectedMemo) { + const memoInstructions = optionalInstructions.filter( + ix => ix.programAddress.toString() === MEMO_PROGRAM_ADDRESS, + ); + if (memoInstructions.length !== 1) { + return { + isValid: false, + invalidReason: "invalid_exact_svm_payload_memo_count", + payer, + }; + } + const memoData = memoInstructions[0].data; + const actualMemo = memoData ? new TextDecoder().decode(new Uint8Array(memoData)) : ""; + if (actualMemo !== expectedMemo) { + return { + isValid: false, + invalidReason: "invalid_exact_svm_payload_memo_mismatch", + payer, + }; + } + } + // Step 6: Sign and Simulate Transaction // CRITICAL: Simulation proves transaction will succeed (catches insufficient balance, invalid accounts, etc) try { diff --git a/typescript/packages/mechanisms/svm/src/utils.ts b/typescript/packages/mechanisms/svm/src/utils.ts index c613a3034f..28811cbd46 100644 --- a/typescript/packages/mechanisms/svm/src/utils.ts +++ b/typescript/packages/mechanisms/svm/src/utils.ts @@ -173,21 +173,5 @@ export function getUsdcAddress(network: Network): string { } } -/** - * Convert a decimal amount to token smallest units - * - * @param decimalAmount - The decimal amount (e.g., "0.10") - * @param decimals - The number of decimals for the token (e.g., 6 for USDC) - * @returns The amount in smallest units as a string - */ -export function convertToTokenAmount(decimalAmount: string, decimals: number): string { - const amount = parseFloat(decimalAmount); - if (isNaN(amount)) { - throw new Error(`Invalid amount: ${decimalAmount}`); - } - // Convert to smallest unit (e.g., for USDC with 6 decimals: 0.10 * 10^6 = 100000) - const [intPart, decPart = ""] = String(amount).split("."); - const paddedDec = decPart.padEnd(decimals, "0").slice(0, decimals); - const tokenAmount = (intPart + paddedDec).replace(/^0+/, "") || "0"; - return tokenAmount; -} +// Re-export from core for backward compatibility +export { convertToTokenAmount, numberToDecimalString } from "@x402/core/utils"; diff --git a/typescript/packages/mechanisms/svm/test/unit/duplicateTx.test.ts b/typescript/packages/mechanisms/svm/test/unit/duplicateTx.test.ts index 58f0ad7661..f0394d78df 100644 --- a/typescript/packages/mechanisms/svm/test/unit/duplicateTx.test.ts +++ b/typescript/packages/mechanisms/svm/test/unit/duplicateTx.test.ts @@ -281,6 +281,185 @@ describe("Memo Uniqueness", () => { expect(memoString).toMatch(/^[0-9a-f]+$/); }); + it("uses extra.memo as memo data when provided", async () => { + blockhashes = [FIXED_BLOCKHASH]; + + const { ExactSvmScheme } = await import("../../src/exact/client/scheme"); + const { decodeTransactionFromPayload } = await import("../../src/utils"); + + const clientSigner = await createSigner(); + const feePayer = await createSigner(); + const payTo = await createSigner(); + + const client = new ExactSvmScheme(clientSigner); + mockAtaMap = { + [clientSigner.address]: clientSigner.address as Address, + [payTo.address]: payTo.address as Address, + }; + + const sellerMemo = "pi_3abc123def456"; + const requirements: PaymentRequirements = { + scheme: "exact", + network: SOLANA_DEVNET_CAIP2, + asset: USDC_DEVNET_ADDRESS, + amount: "100000", + payTo: payTo.address, + maxTimeoutSeconds: 3600, + extra: { + feePayer: feePayer.address, + memo: sellerMemo, + }, + }; + + const payload = await client.createPaymentPayload(2, requirements); + const txBase64 = (payload.payload as { transaction: string }).transaction; + + const tx = decodeTransactionFromPayload({ transaction: txBase64 }); + const compiled = getCompiledTransactionMessageDecoder().decode(tx.messageBytes); + const decompiled = decompileTransactionMessage(compiled); + const instructions = decompiled.instructions ?? []; + + const memoIx = instructions.find(ix => ix.programAddress.toString() === MEMO_PROGRAM_ADDRESS); + expect(memoIx).toBeDefined(); + + const memoData = new TextDecoder().decode(new Uint8Array(memoIx!.data!)); + expect(memoData).toBe(sellerMemo); + }); + + it("produces identical memo data with extra.memo across calls", async () => { + blockhashes = [FIXED_BLOCKHASH, FIXED_BLOCKHASH]; + + const { ExactSvmScheme } = await import("../../src/exact/client/scheme"); + const { decodeTransactionFromPayload } = await import("../../src/utils"); + + const clientSigner = await createSigner(); + const feePayer = await createSigner(); + const payTo = await createSigner(); + + const client = new ExactSvmScheme(clientSigner); + mockAtaMap = { + [clientSigner.address]: clientSigner.address as Address, + [payTo.address]: payTo.address as Address, + }; + + const sellerMemo = "order_12345"; + const requirements: PaymentRequirements = { + scheme: "exact", + network: SOLANA_DEVNET_CAIP2, + asset: USDC_DEVNET_ADDRESS, + amount: "100000", + payTo: payTo.address, + maxTimeoutSeconds: 3600, + extra: { + feePayer: feePayer.address, + memo: sellerMemo, + }, + }; + + const payload1 = await client.createPaymentPayload(2, requirements); + const payload2 = await client.createPaymentPayload(2, requirements); + + const decode = (p: typeof payload1) => { + const txBase64 = (p.payload as { transaction: string }).transaction; + const tx = decodeTransactionFromPayload({ transaction: txBase64 }); + const compiled = getCompiledTransactionMessageDecoder().decode(tx.messageBytes); + const decompiled = decompileTransactionMessage(compiled); + const memoIx = (decompiled.instructions ?? []).find( + ix => ix.programAddress.toString() === MEMO_PROGRAM_ADDRESS, + ); + return new TextDecoder().decode(new Uint8Array(memoIx!.data!)); + }; + + expect(decode(payload1)).toBe(sellerMemo); + expect(decode(payload2)).toBe(sellerMemo); + }); + + it("falls back to random nonce when extra.memo is absent", async () => { + blockhashes = [FIXED_BLOCKHASH, FIXED_BLOCKHASH]; + + const { ExactSvmScheme } = await import("../../src/exact/client/scheme"); + const { decodeTransactionFromPayload } = await import("../../src/utils"); + + const clientSigner = await createSigner(); + const feePayer = await createSigner(); + const payTo = await createSigner(); + + const client = new ExactSvmScheme(clientSigner); + mockAtaMap = { + [clientSigner.address]: clientSigner.address as Address, + [payTo.address]: payTo.address as Address, + }; + + const requirements: PaymentRequirements = { + scheme: "exact", + network: SOLANA_DEVNET_CAIP2, + asset: USDC_DEVNET_ADDRESS, + amount: "100000", + payTo: payTo.address, + maxTimeoutSeconds: 3600, + extra: { + feePayer: feePayer.address, + // no memo + }, + }; + + const payload1 = await client.createPaymentPayload(2, requirements); + const payload2 = await client.createPaymentPayload(2, requirements); + + const decode = (p: typeof payload1) => { + const txBase64 = (p.payload as { transaction: string }).transaction; + const tx = decodeTransactionFromPayload({ transaction: txBase64 }); + const compiled = getCompiledTransactionMessageDecoder().decode(tx.messageBytes); + const decompiled = decompileTransactionMessage(compiled); + const memoIx = (decompiled.instructions ?? []).find( + ix => ix.programAddress.toString() === MEMO_PROGRAM_ADDRESS, + ); + return new TextDecoder().decode(new Uint8Array(memoIx!.data!)); + }; + + const memo1 = decode(payload1); + const memo2 = decode(payload2); + + // Random nonces should differ + expect(memo1).not.toBe(memo2); + // Random nonces are 32 hex chars + expect(memo1).toMatch(/^[0-9a-f]{32}$/); + expect(memo2).toMatch(/^[0-9a-f]{32}$/); + }); + + it("rejects extra.memo exceeding 256 bytes", async () => { + blockhashes = [FIXED_BLOCKHASH]; + + const { ExactSvmScheme } = await import("../../src/exact/client/scheme"); + + const clientSigner = await createSigner(); + const feePayer = await createSigner(); + const payTo = await createSigner(); + + const client = new ExactSvmScheme(clientSigner); + mockAtaMap = { + [clientSigner.address]: clientSigner.address as Address, + [payTo.address]: payTo.address as Address, + }; + + const requirements: PaymentRequirements = { + scheme: "exact", + network: SOLANA_DEVNET_CAIP2, + asset: USDC_DEVNET_ADDRESS, + amount: "100000", + payTo: payTo.address, + maxTimeoutSeconds: 3600, + extra: { + feePayer: feePayer.address, + memo: "x".repeat(257), + }, + }; + + await expect(client.createPaymentPayload(2, requirements)).rejects.toThrow( + /extra\.memo exceeds maximum/, + ); + }); + // Empty accounts is critical - signers break facilitator verification it("memo instruction has no accounts", async () => { blockhashes = [FIXED_BLOCKHASH]; diff --git a/typescript/packages/mechanisms/svm/test/unit/index.test.ts b/typescript/packages/mechanisms/svm/test/unit/index.test.ts index 120ab474e1..83d215cdc5 100644 --- a/typescript/packages/mechanisms/svm/test/unit/index.test.ts +++ b/typescript/packages/mechanisms/svm/test/unit/index.test.ts @@ -4,7 +4,6 @@ import { validateSvmAddress, normalizeNetwork, getUsdcAddress, - convertToTokenAmount, SVM_ADDRESS_REGEX, SOLANA_MAINNET_CAIP2, SOLANA_DEVNET_CAIP2, @@ -80,33 +79,6 @@ describe("@x402/svm", () => { }); }); - describe("convertToTokenAmount", () => { - it("should convert decimal amounts to token units (6 decimals)", () => { - expect(convertToTokenAmount("4.02", 6)).toBe("4020000"); - expect(convertToTokenAmount("0.10", 6)).toBe("100000"); - expect(convertToTokenAmount("1.00", 6)).toBe("1000000"); - expect(convertToTokenAmount("0.01", 6)).toBe("10000"); - expect(convertToTokenAmount("123.456789", 6)).toBe("123456789"); - }); - - it("should handle whole numbers", () => { - expect(convertToTokenAmount("1", 6)).toBe("1000000"); - expect(convertToTokenAmount("100", 6)).toBe("100000000"); - }); - - it("should handle different decimals", () => { - expect(convertToTokenAmount("1", 9)).toBe("1000000000"); // SOL - expect(convertToTokenAmount("1", 2)).toBe("100"); - expect(convertToTokenAmount("1", 0)).toBe("1"); - }); - - it("should throw for invalid amounts", () => { - expect(() => convertToTokenAmount("abc", 6)).toThrow("Invalid amount"); - expect(() => convertToTokenAmount("", 6)).toThrow("Invalid amount"); - expect(() => convertToTokenAmount("NaN", 6)).toThrow("Invalid amount"); - }); - }); - describe("ExactSvmScheme (Server)", () => { const server = new ServerExactSvmScheme(); @@ -228,16 +200,131 @@ describe("@x402/svm", () => { }); }); - // Integration tests would require mocking Solana RPC and transaction signing - describe("Integration (placeholder)", () => { - it.todo("should create a valid payment payload with ExactSvmScheme"); - it.todo("should verify a valid payment with ExactSvmScheme"); - it.todo("should reject invalid signatures"); - it.todo("should reject insufficient amounts"); - it.todo("should reject wrong recipients"); - it.todo("should reject expired transactions"); - it.todo("should settle valid payments"); - it.todo("should handle compute budget instructions"); - it.todo("should verify both SPL Token and Token-2022 transfers"); + describe("ExactSvmScheme (Server) - additional coverage", () => { + const server = new ServerExactSvmScheme(); + + it("should have scheme set to 'exact'", () => { + expect(server.scheme).toBe("exact"); + }); + + it("should register custom money parser and use it", async () => { + const customServer = new ServerExactSvmScheme(); + const customParser = async (amount: number, _network: string) => { + if (amount === 42) { + return { amount: "42000000", asset: "custom_asset_address", extra: {} }; + } + return null; + }; + customServer.registerMoneyParser(customParser); + + const result = await customServer.parsePrice(42, SOLANA_MAINNET_CAIP2); + expect(result.amount).toBe("42000000"); + expect(result.asset).toBe("custom_asset_address"); + }); + + it("should fall back to default when custom parser returns null", async () => { + const customServer = new ServerExactSvmScheme(); + const nullParser = async () => null; + customServer.registerMoneyParser(nullParser); + + const result = await customServer.parsePrice(1.0, SOLANA_MAINNET_CAIP2); + expect(result.amount).toBe("1000000"); + expect(result.asset).toBe(USDC_MAINNET_ADDRESS); + }); + + it("should chain registerMoneyParser calls", () => { + const customServer = new ServerExactSvmScheme(); + const parser1 = async () => null; + const parser2 = async () => null; + const result = customServer.registerMoneyParser(parser1).registerMoneyParser(parser2); + expect(result).toBe(customServer); + }); + + it("should try custom parsers in registration order", async () => { + const customServer = new ServerExactSvmScheme(); + const firstParser = async (amount: number) => { + if (amount > 0) return { amount: "first", asset: "first_asset", extra: {} }; + return null; + }; + const secondParser = async (amount: number) => { + if (amount > 0) return { amount: "second", asset: "second_asset", extra: {} }; + return null; + }; + customServer.registerMoneyParser(firstParser).registerMoneyParser(secondParser); + + const result = await customServer.parsePrice(1, SOLANA_MAINNET_CAIP2); + expect(result.amount).toBe("first"); + }); + + it("should preserve existing extra fields in enhancePaymentRequirements", async () => { + const requirements = { + scheme: "exact", + network: SOLANA_MAINNET_CAIP2, + asset: USDC_MAINNET_ADDRESS, + amount: "100000", + payTo: "11111111111111111111111111111111", + maxTimeoutSeconds: 3600, + extra: { existingField: "keep_me" }, + }; + + const result = await server.enhancePaymentRequirements( + requirements as never, + { + x402Version: 2, + scheme: "exact", + network: SOLANA_MAINNET_CAIP2, + extra: { feePayer: "FacilitatorAddr111111111111111111111" }, + }, + [], + ); + + expect(result.extra?.existingField).toBe("keep_me"); + expect(result.extra?.feePayer).toBe("FacilitatorAddr111111111111111111111"); + }); + + it("should handle enhancePaymentRequirements without feePayer", async () => { + const requirements = { + scheme: "exact", + network: SOLANA_MAINNET_CAIP2, + asset: USDC_MAINNET_ADDRESS, + amount: "100000", + payTo: "11111111111111111111111111111111", + maxTimeoutSeconds: 3600, + }; + + const result = await server.enhancePaymentRequirements( + requirements as never, + { + x402Version: 2, + scheme: "exact", + network: SOLANA_MAINNET_CAIP2, + }, + [], + ); + + expect(result.extra?.feePayer).toBeUndefined(); + }); + + it("should parse price with zero amount", async () => { + const result = await server.parsePrice(0, SOLANA_MAINNET_CAIP2); + expect(result.amount).toBe("0"); + expect(result.asset).toBe(USDC_MAINNET_ADDRESS); + }); + + it("should parse price with large amount", async () => { + const result = await server.parsePrice(1000000, SOLANA_MAINNET_CAIP2); + expect(result.amount).toBe("1000000000000"); + expect(result.asset).toBe(USDC_MAINNET_ADDRESS); + }); + + it("should handle pre-parsed AssetAmount with extra data", async () => { + const result = await server.parsePrice( + { amount: "500", asset: "custom_token", extra: { memo: "test" } }, + SOLANA_MAINNET_CAIP2, + ); + expect(result.amount).toBe("500"); + expect(result.asset).toBe("custom_token"); + expect(result.extra).toEqual({ memo: "test" }); + }); }); }); diff --git a/typescript/packages/mechanisms/svm/test/unit/server.moneyParser.test.ts b/typescript/packages/mechanisms/svm/test/unit/server.moneyParser.test.ts index ed90a092c2..96f1b5210b 100644 --- a/typescript/packages/mechanisms/svm/test/unit/server.moneyParser.test.ts +++ b/typescript/packages/mechanisms/svm/test/unit/server.moneyParser.test.ts @@ -509,6 +509,18 @@ describe("ExactSvmScheme - registerMoneyParser", () => { expect(receivedAmount).toBe(999999999.99); }); + it("should throw when price is too small to represent in USDC precision", async () => { + const server = new ExactSvmScheme(); + // USDC has 6 decimals: $0.00000001 = 1e-8 * 1e6 = 0.01 → rounds to 0 → must throw + await expect( + server.parsePrice("$0.00000001", "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"), + ).rejects.toThrow("too small"); + // Also throws when passed as a number + await expect( + server.parsePrice(0.00000001, "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp"), + ).rejects.toThrow("too small"); + }); + it("should handle negative amounts (parser can validate)", async () => { const server = new ExactSvmScheme(); diff --git a/typescript/pnpm-lock.yaml b/typescript/pnpm-lock.yaml index c30c460f81..054613a00f 100644 --- a/typescript/pnpm-lock.yaml +++ b/typescript/pnpm-lock.yaml @@ -16,15 +16,18 @@ importers: version: 0.5.2 '@changesets/cli': specifier: ^2.28.1 - version: 2.29.8(@types/node@22.18.0) + version: 2.29.8(@types/node@22.19.17) tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) + tsx: + specifier: ^4.21.0 + version: 4.21.0 turbo: specifier: ^2.5.0 version: 2.5.6 typescript: - specifier: ^5.8.3 + specifier: ^5.7.3 version: 5.9.2 packages/core: @@ -62,22 +65,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/extensions: dependencies: @@ -87,6 +90,9 @@ importers: '@scure/base': specifier: ^1.2.6 version: 1.2.6 + '@signinwithethereum/siwe': + specifier: ^4.1.0 + version: 4.1.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@x402/core': specifier: workspace:~ version: link:../core @@ -96,15 +102,12 @@ importers: jose: specifier: ^5.9.6 version: 5.10.0 - siwe: - specifier: ^2.3.2 - version: 2.3.2(ethers@6.16.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) tweetnacl: specifier: ^1.0.3 version: 1.0.3 viem: - specifier: ^2.43.5 - version: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zod: specifier: ^3.24.2 version: 3.25.76 @@ -138,34 +141,28 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/http/axios: dependencies: '@x402/core': specifier: workspace:~ version: link:../../core - axios: - specifier: ^1.7.9 - version: 1.11.0 - zod: - specifier: ^3.24.2 - version: 3.25.76 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -179,6 +176,9 @@ importers: '@typescript-eslint/parser': specifier: ^8.29.1 version: 8.42.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2) + axios: + specifier: ^1.7.9 + version: 1.11.0 eslint: specifier: ^9.24.0 version: 9.34.0(jiti@2.6.1) @@ -196,22 +196,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/http/express: dependencies: @@ -224,12 +224,6 @@ importers: '@x402/paywall': specifier: workspace:^ version: link:../paywall - viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zod: - specifier: ^3.24.2 - version: 3.25.76 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -266,22 +260,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/http/fastify: dependencies: @@ -292,7 +286,7 @@ importers: specifier: workspace:~ version: link:../../extensions '@x402/paywall': - specifier: workspace:* + specifier: workspace:^ version: link:../paywall devDependencies: '@eslint/js': @@ -321,40 +315,34 @@ importers: version: 5.5.4(eslint@9.34.0(jiti@2.6.1))(prettier@3.5.2) fastify: specifier: ^5.0.0 - version: 5.8.2 + version: 5.8.4 prettier: specifier: 3.5.2 version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/http/fetch: dependencies: '@x402/core': specifier: workspace:~ version: link:../../core - viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zod: - specifier: ^3.24.2 - version: 3.25.76 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -385,22 +373,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/http/hono: dependencies: @@ -413,9 +401,6 @@ importers: '@x402/paywall': specifier: workspace:^ version: link:../paywall - zod: - specifier: ^3.24.2 - version: 3.25.76 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -449,22 +434,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/http/next: dependencies: @@ -478,11 +463,8 @@ importers: specifier: workspace:^ version: link:../paywall next: - specifier: ^16.0.10 + specifier: '>=16.0.10 <16.1.0' version: 16.0.10(@babel/core@7.28.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) - zod: - specifier: ^3.24.2 - version: 3.25.76 devDependencies: '@eslint/js': specifier: ^9.24.0 @@ -513,25 +495,34 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/http/paywall: dependencies: + '@algorandfoundation/algokit-utils': + specifier: 10.0.0-alpha.46 + version: 10.0.0-alpha.46 + '@blockshake/defly-connect': + specifier: ^1.2.1 + version: 1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@perawallet/connect': + specifier: ^1.4.2 + version: 1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@scure/base': specifier: ^1.2.6 version: 1.2.6 @@ -549,19 +540,22 @@ importers: version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) '@solana/transaction-confirmation': specifier: ^2.1.1 - version: 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/wallet-standard-features': specifier: ^1.3.0 version: 1.3.0 '@tanstack/react-query': specifier: ^5.90.7 version: 5.90.11(react@19.2.1) + '@txnlab/use-wallet': + specifier: ^4.3.1 + version: 4.6.0(@blockshake/defly-connect@1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@perawallet/connect@1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@walletconnect/sign-client@2.23.9(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(algosdk@3.5.2)(lute-connect@1.7.0) '@wagmi/connectors': specifier: ^5.8.1 - version: 5.9.9(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + version: 5.9.9(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(zod@4.1.13) '@wagmi/core': specifier: ^2.17.1 - version: 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + version: 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) '@wallet-standard/app': specifier: ^1.1.0 version: 1.1.0 @@ -571,22 +565,25 @@ importers: '@wallet-standard/features': specifier: ^1.1.0 version: 1.1.0 + '@walletconnect/sign-client': + specifier: ^2.23.1 + version: 2.23.9(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) '@x402/core': specifier: workspace:~ version: link:../../core + lute-connect: + specifier: ^1.6.3 + version: 1.7.0 viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) wagmi: specifier: ^2.17.1 - version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) - zod: - specifier: ^3.24.2 - version: 3.25.76 + version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10))(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(zod@4.1.13) devDependencies: '@craftamap/esbuild-plugin-html': specifier: ^0.9.0 - version: 0.9.0(bufferutil@4.0.9)(esbuild@0.25.9)(utf-8-validate@5.0.10) + version: 0.9.0(bufferutil@4.0.9)(esbuild@0.27.7)(utf-8-validate@5.0.10) '@eslint/js': specifier: ^9.24.0 version: 9.34.0 @@ -605,6 +602,9 @@ importers: '@typescript-eslint/parser': specifier: ^8.29.1 version: 8.42.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2) + '@x402/avm': + specifier: workspace:~ + version: link:../../mechanisms/avm '@x402/evm': specifier: workspace:~ version: link:../../mechanisms/evm @@ -615,8 +615,8 @@ importers: specifier: ^6.0.3 version: 6.0.3 esbuild: - specifier: ^0.25.4 - version: 0.25.9 + specifier: ^0.27.2 + version: 0.27.7 eslint: specifier: ^9.24.0 version: 9.34.0(jiti@2.6.1) @@ -640,22 +640,22 @@ importers: version: 19.2.1(react@19.2.1) tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/legacy/x402: dependencies: @@ -664,19 +664,19 @@ importers: version: 1.2.6 '@solana-program/compute-budget': specifier: ^0.11.0 - version: 0.11.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + version: 0.11.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) '@solana-program/token': specifier: ^0.9.0 - version: 0.9.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + version: 0.9.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) '@solana-program/token-2022': specifier: ^0.6.1 - version: 0.6.1(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)) + version: 0.6.1(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)) '@solana/kit': specifier: ^5.0.0 - version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/transaction-confirmation': specifier: ^5.0.0 - version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/wallet-standard-features': specifier: ^1.3.0 version: 1.3.0 @@ -690,21 +690,21 @@ importers: specifier: ^1.1.0 version: 1.1.0 viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) wagmi: specifier: ^2.15.6 - version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + version: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10))(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) zod: specifier: ^3.24.2 version: 3.25.76 devDependencies: '@coinbase/onchainkit': specifier: ^0.38.14 - version: 0.38.19(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) + version: 0.38.19(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.1(react@19.2.1))(react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) '@craftamap/esbuild-plugin-html': specifier: ^0.9.0 - version: 0.9.0(bufferutil@4.0.9)(esbuild@0.25.9)(utf-8-validate@5.0.10) + version: 0.9.0(bufferutil@4.0.9)(esbuild@0.27.7)(utf-8-validate@5.0.10) '@eslint/js': specifier: ^9.24.0 version: 9.34.0 @@ -725,16 +725,16 @@ importers: version: 8.42.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2) '@wagmi/connectors': specifier: ^5.8.1 - version: 5.9.9(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + version: 5.9.9(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) '@wagmi/core': specifier: ^2.17.1 - version: 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + version: 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) buffer: specifier: ^6.0.3 version: 6.0.3 esbuild: - specifier: ^0.25.4 - version: 0.25.9 + specifier: ^0.27.2 + version: 0.27.7 eslint: specifier: ^9.24.0 version: 9.34.0(jiti@2.6.1) @@ -758,22 +758,22 @@ importers: version: 19.2.1(react@19.2.1) tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/legacy/x402-axios: dependencies: @@ -781,8 +781,8 @@ importers: specifier: ^1.7.9 version: 1.11.0 viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) x402: specifier: workspace:^ version: link:../x402 @@ -819,22 +819,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/legacy/x402-express: dependencies: @@ -848,8 +848,8 @@ importers: specifier: ^4.18.2 version: 4.21.2 viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) x402: specifier: workspace:^ version: link:../x402 @@ -889,28 +889,28 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/legacy/x402-fetch: dependencies: viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) x402: specifier: workspace:^ version: link:../x402 @@ -947,22 +947,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/legacy/x402-hono: dependencies: @@ -971,13 +971,13 @@ importers: version: 1.36.1(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) '@solana/kit': specifier: ^5.0.0 - version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) hono: specifier: ^4.7.1 version: 4.10.7 viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) x402: specifier: workspace:^ version: link:../x402 @@ -1014,22 +1014,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/legacy/x402-next: dependencies: @@ -1038,13 +1038,13 @@ importers: version: 1.36.1(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) '@solana/kit': specifier: ^5.0.0 - version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) next: specifier: '>=15.5.9 || >=16.0.10' version: 16.0.10(@babel/core@7.28.3)(react-dom@19.2.3(react@19.2.3))(react@19.2.3) viem: - specifier: ^2.21.26 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) x402: specifier: workspace:^ version: link:../x402 @@ -1081,22 +1081,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/mcp: dependencies: @@ -1145,25 +1145,25 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 viem: - specifier: ^2.27.2 - version: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/mechanisms/aptos: dependencies: @@ -1171,7 +1171,62 @@ importers: specifier: ^5.2.1 version: 5.2.1(got@11.8.6) '@x402/core': - specifier: workspace:* + specifier: workspace:~ + version: link:../../core + devDependencies: + '@eslint/js': + specifier: ^9.24.0 + version: 9.34.0 + '@types/node': + specifier: ^22.13.4 + version: 22.18.0 + '@typescript-eslint/eslint-plugin': + specifier: ^8.29.1 + version: 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/parser': + specifier: ^8.29.1 + version: 8.49.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2) + eslint: + specifier: ^9.24.0 + version: 9.34.0(jiti@2.6.1) + eslint-plugin-import: + specifier: ^2.31.0 + version: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.6.1)) + eslint-plugin-jsdoc: + specifier: ^50.6.9 + version: 50.8.0(eslint@9.34.0(jiti@2.6.1)) + eslint-plugin-prettier: + specifier: ^5.2.6 + version: 5.5.4(eslint@9.34.0(jiti@2.6.1))(prettier@3.5.2) + prettier: + specifier: 3.5.2 + version: 3.5.2 + tsup: + specifier: ^8.4.0 + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) + tsx: + specifier: ^4.21.0 + version: 4.21.0 + typescript: + specifier: ^5.7.3 + version: 5.9.2 + vite: + specifier: ^6.2.6 + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) + vitest: + specifier: ^3.0.5 + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) + + packages/mechanisms/avm: + dependencies: + '@algorandfoundation/algokit-utils': + specifier: 10.0.0-alpha.46 + version: 10.0.0-alpha.46 + '@x402/core': + specifier: workspace:~ version: link:../../core devDependencies: '@eslint/js': @@ -1203,22 +1258,22 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/mechanisms/evm: dependencies: @@ -1226,8 +1281,8 @@ importers: specifier: workspace:~ version: link:../../core viem: - specifier: ^2.39.3 - version: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zod: specifier: ^3.24.2 version: 3.25.76 @@ -1261,22 +1316,77 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) + tsx: + specifier: ^4.21.0 + version: 4.21.0 + typescript: + specifier: ^5.7.3 + version: 5.9.2 + vite: + specifier: ^6.2.6 + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) + vite-tsconfig-paths: + specifier: ^5.1.4 + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) + vitest: + specifier: ^3.0.5 + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) + + packages/mechanisms/hedera: + dependencies: + '@hiero-ledger/sdk': + specifier: 2.80.0 + version: 2.80.0(bn.js@5.2.1)(react-native@0.85.0(@babel/core@7.28.3)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)) + '@x402/core': + specifier: workspace:* + version: link:../../core + devDependencies: + '@eslint/js': + specifier: ^9.24.0 + version: 9.34.0 + '@types/node': + specifier: ^22.13.4 + version: 22.19.17 + '@typescript-eslint/eslint-plugin': + specifier: ^8.29.1 + version: 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2) + '@typescript-eslint/parser': + specifier: ^8.29.1 + version: 8.49.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2) + eslint: + specifier: ^9.24.0 + version: 9.34.0(jiti@2.6.1) + eslint-plugin-import: + specifier: ^2.31.0 + version: 2.32.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.6.1)) + eslint-plugin-jsdoc: + specifier: ^50.6.9 + version: 50.8.0(eslint@9.34.0(jiti@2.6.1)) + eslint-plugin-prettier: + specifier: ^5.2.6 + version: 5.5.4(eslint@9.34.0(jiti@2.6.1))(prettier@3.5.2) + prettier: + specifier: 3.5.2 + version: 3.5.2 + tsup: + specifier: ^8.4.0 + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.19.17)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/mechanisms/stellar: dependencies: @@ -1284,7 +1394,7 @@ importers: specifier: ^14.6.1 version: 14.6.1 '@x402/core': - specifier: workspace:* + specifier: workspace:~ version: link:../../core devDependencies: '@eslint/js': @@ -1316,37 +1426,37 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) packages/mechanisms/svm: dependencies: '@solana-program/compute-budget': specifier: ^0.11.0 - version: 0.11.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + version: 0.11.0(@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)) '@solana-program/token': specifier: ^0.9.0 - version: 0.9.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))) + version: 0.9.0(@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)) '@solana-program/token-2022': specifier: ^0.6.1 - version: 0.6.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)) + version: 0.6.1(@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)) '@solana/kit': specifier: '>=5.1.0' - version: 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + version: 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) '@x402/core': specifier: workspace:~ version: link:../../core @@ -1383,25 +1493,28 @@ importers: version: 3.5.2 tsup: specifier: ^8.4.0 - version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1) + version: 8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1) tsx: - specifier: ^4.19.2 - version: 4.20.5 + specifier: ^4.21.0 + version: 4.21.0 typescript: specifier: ^5.7.3 version: 5.9.2 vite: specifier: ^6.2.6 - version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) vite-tsconfig-paths: specifier: ^5.1.4 - version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + version: 5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) vitest: specifier: ^3.0.5 - version: 3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + version: 3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) site: dependencies: + '@algorandfoundation/algokit-utils': + specifier: 10.0.0-alpha.46 + version: 10.0.0-alpha.46 '@aptos-labs/ts-sdk': specifier: ^5.2.1 version: 5.2.1(got@11.8.6) @@ -1423,6 +1536,9 @@ importers: '@x402/aptos': specifier: workspace:* version: link:../packages/mechanisms/aptos + '@x402/avm': + specifier: workspace:* + version: link:../packages/mechanisms/avm '@x402/core': specifier: workspace:* version: link:../packages/core @@ -1460,11 +1576,11 @@ importers: specifier: ^19.2.3 version: 19.2.3(react@19.2.3) viem: - specifier: ^2.21.26 - version: 2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + specifier: ^2.48.11 + version: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) wagmi: specifier: ^2.15.6 - version: 2.16.9(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + version: 2.16.9(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) x402-legacy: specifier: npm:x402@0.1.2 version: x402@0.1.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) @@ -1518,19 +1634,20 @@ importers: specifier: ^4.0.0 version: 4.1.17 typescript: - specifier: ^5 + specifier: ^5.7.3 version: 5.9.2 packages: - '@acemir/cssom@0.9.30': - resolution: {integrity: sha512-9CnlMCI0LmCIq0olalQqdWrJHPzm0/tw3gzOA9zJSgvFX7Xau3D24mAGa4BtwxwY69nsuJW6kQqqCzf/mEcQgg==} + '@adraffy/ens-normalize@1.11.1': + resolution: {integrity: sha512-nhCBV3quEgesuf7c7KYfperqSS14T8bYuvJ8PcLJp6znkZpFc0AuW4qBtr8eKVyPPe/8RSr7sglCWPU5eaxwKQ==} - '@adraffy/ens-normalize@1.10.1': - resolution: {integrity: sha512-96Z2IP3mYmF1Xg2cDm8f1gWGf/HUVedQ3FMifV4kG/PQ4yEP51xDtRAEfhVNt5f/uzpNkZHwWQuUcu6D6K+Ekw==} + '@algorandfoundation/algokit-utils@10.0.0-alpha.46': + resolution: {integrity: sha512-Lx56ET6RmrDCFGwx6qyIr7YRX3Q3MyKgqkNeumLkFHXVkqMnXnK1aLeEbV59EOK8UHQ5UPJofSj1zvRMm9Du7w==} + engines: {node: '>=20.0'} - '@adraffy/ens-normalize@1.11.0': - resolution: {integrity: sha512-/3DDPKHqqIqxUULp8yP4zODUY1i+2xvVWsv8A79xGWdCAG+8sb0hRh0Rk2QyOJUnnbyPUAZYcpBuRe3nS2OIUg==} + '@algorandfoundation/xhd-wallet-api@2.0.0-canary.1': + resolution: {integrity: sha512-U6rSWMO6FKDLvMxWtfKyW5ctqSy2NrONWTU/jOA+BX0SGru0GPXsxwzFdcPa5w+X055V/xVVsr8eA3xA+m/5jA==} '@alloc/quick-lru@5.2.0': resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} @@ -1557,16 +1674,14 @@ packages: '@asamuzakjp/css-color@4.1.1': resolution: {integrity: sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ==} - '@asamuzakjp/dom-selector@6.7.6': - resolution: {integrity: sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg==} - - '@asamuzakjp/nwsapi@2.3.9': - resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} + '@babel/code-frame@7.29.0': + resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} + engines: {node: '>=6.9.0'} + '@babel/compat-data@7.28.0': resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} engines: {node: '>=6.9.0'} @@ -1579,6 +1694,10 @@ packages: resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.29.1': + resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -1654,6 +1773,10 @@ packages: resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -1671,6 +1794,11 @@ packages: engines: {node: '>=6.0.0'} hasBin: true + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1': resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==} engines: {node: '>=6.9.0'} @@ -2110,20 +2238,37 @@ packages: resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} + '@babel/template@7.28.6': + resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} + engines: {node: '>=6.9.0'} + '@babel/traverse@7.28.3': resolution: {integrity: sha512-7w4kZYHneL3A6NP2nxzHvT3HCZ7puDZZjFMqDpBPECub79sTtSO5CGXDkKrTQq8ksAwfD/XI2MRFX23njdDaIQ==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} + engines: {node: '>=6.9.0'} + '@babel/types@7.28.2': resolution: {integrity: sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==} engines: {node: '>=6.9.0'} + '@babel/types@7.29.0': + resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} + engines: {node: '>=6.9.0'} + '@base-org/account@1.1.1': resolution: {integrity: sha512-IfVJPrDPhHfqXRDb89472hXkpvJuQQR7FDI9isLPHEqSYt/45whIoBxSPgZ0ssTt379VhQo4+87PWI1DoLSfAQ==} '@base-org/account@2.4.0': resolution: {integrity: sha512-A4Umpi8B9/pqR78D1Yoze4xHyQaujioVRqqO3d6xuDFw9VRtjg6tK3bPlwE0aW+nVH/ntllCpPa2PbI8Rnjcug==} + '@blockshake/defly-connect@1.2.1': + resolution: {integrity: sha512-T9wAjPTFdc8iRiDzTqmeBRCIroWLgXmqZHwnpzuchjYZXXqbnj+zge+HS7UaNunpxGVjDUNK1ah7OR6hEqtJoQ==} + peerDependencies: + algosdk: ^3.0.0 + '@changesets/apply-release-plan@7.0.14': resolution: {integrity: sha512-ddBvf9PHdy2YY0OUiEl3TV78mH9sckndJR14QAt87KLEbIov81XO0q0QAmvooBxXlqRRP8I9B7XOzZwQG7JkWA==} @@ -2260,158 +2405,314 @@ packages: resolution: {integrity: sha512-YAdE/IJSpwbOTiaURNCKECdAwqrJuFiZhylmesBcIRawtYKnBR2wxPhoIewMg+Yu+QuYvHfJNReWpoxGBKOChA==} engines: {node: '>=18'} - '@esbuild/aix-ppc64@0.25.9': - resolution: {integrity: sha512-OaGtL73Jck6pBKjNIe24BnFE6agGl+6KxDtTfHhy1HmhthfKouEcOhqpSL64K4/0WCtbKFLOdzD/44cJ4k9opA==} + '@esbuild/aix-ppc64@0.25.12': + resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.9': - resolution: {integrity: sha512-IDrddSmpSv51ftWslJMvl3Q2ZT98fUSL2/rlUXuVqRXHCs5EUF1/f+jbjF5+NG9UffUDMCiTyh8iec7u8RlTLg==} + '@esbuild/android-arm64@0.25.12': + resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.9': - resolution: {integrity: sha512-5WNI1DaMtxQ7t7B6xa572XMXpHAaI/9Hnhk8lcxF4zVN4xstUgTlvuGDorBguKEnZO70qwEcLpfifMLoxiPqHQ==} + '@esbuild/android-arm@0.25.12': + resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.9': - resolution: {integrity: sha512-I853iMZ1hWZdNllhVZKm34f4wErd4lMyeV7BLzEExGEIZYsOzqDWDf+y082izYUE8gtJnYHdeDpN/6tUdwvfiw==} + '@esbuild/android-x64@0.25.12': + resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.9': - resolution: {integrity: sha512-XIpIDMAjOELi/9PB30vEbVMs3GV1v2zkkPnuyRRURbhqjyzIINwj+nbQATh4H9GxUgH1kFsEyQMxwiLFKUS6Rg==} + '@esbuild/darwin-arm64@0.25.12': + resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.9': - resolution: {integrity: sha512-jhHfBzjYTA1IQu8VyrjCX4ApJDnH+ez+IYVEoJHeqJm9VhG9Dh2BYaJritkYK3vMaXrf7Ogr/0MQ8/MeIefsPQ==} + '@esbuild/darwin-x64@0.25.12': + resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.9': - resolution: {integrity: sha512-z93DmbnY6fX9+KdD4Ue/H6sYs+bhFQJNCPZsi4XWJoYblUqT06MQUdBCpcSfuiN72AbqeBFu5LVQTjfXDE2A6Q==} + '@esbuild/freebsd-arm64@0.25.12': + resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.9': - resolution: {integrity: sha512-mrKX6H/vOyo5v71YfXWJxLVxgy1kyt1MQaD8wZJgJfG4gq4DpQGpgTB74e5yBeQdyMTbgxp0YtNj7NuHN0PoZg==} + '@esbuild/freebsd-x64@0.25.12': + resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.9': - resolution: {integrity: sha512-BlB7bIcLT3G26urh5Dmse7fiLmLXnRlopw4s8DalgZ8ef79Jj4aUcYbk90g8iCa2467HX8SAIidbL7gsqXHdRw==} + '@esbuild/linux-arm64@0.25.12': + resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.9': - resolution: {integrity: sha512-HBU2Xv78SMgaydBmdor38lg8YDnFKSARg1Q6AT0/y2ezUAKiZvc211RDFHlEZRFNRVhcMamiToo7bDx3VEOYQw==} + '@esbuild/linux-arm@0.25.12': + resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.9': - resolution: {integrity: sha512-e7S3MOJPZGp2QW6AK6+Ly81rC7oOSerQ+P8L0ta4FhVi+/j/v2yZzx5CqqDaWjtPFfYz21Vi1S0auHrap3Ma3A==} + '@esbuild/linux-ia32@0.25.12': + resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.9': - resolution: {integrity: sha512-Sbe10Bnn0oUAB2AalYztvGcK+o6YFFA/9829PhOCUS9vkJElXGdphz0A3DbMdP8gmKkqPmPcMJmJOrI3VYB1JQ==} + '@esbuild/linux-loong64@0.25.12': + resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.9': - resolution: {integrity: sha512-YcM5br0mVyZw2jcQeLIkhWtKPeVfAerES5PvOzaDxVtIyZ2NUBZKNLjC5z3/fUlDgT6w89VsxP2qzNipOaaDyA==} + '@esbuild/linux-mips64el@0.25.12': + resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.9': - resolution: {integrity: sha512-++0HQvasdo20JytyDpFvQtNrEsAgNG2CY1CLMwGXfFTKGBGQT3bOeLSYE2l1fYdvML5KUuwn9Z8L1EWe2tzs1w==} + '@esbuild/linux-ppc64@0.25.12': + resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.9': - resolution: {integrity: sha512-uNIBa279Y3fkjV+2cUjx36xkx7eSjb8IvnL01eXUKXez/CBHNRw5ekCGMPM0BcmqBxBcdgUWuUXmVWwm4CH9kg==} + '@esbuild/linux-riscv64@0.25.12': + resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.9': - resolution: {integrity: sha512-Mfiphvp3MjC/lctb+7D287Xw1DGzqJPb/J2aHHcHxflUo+8tmN/6d4k6I2yFR7BVo5/g7x2Monq4+Yew0EHRIA==} + '@esbuild/linux-s390x@0.25.12': + resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.9': - resolution: {integrity: sha512-iSwByxzRe48YVkmpbgoxVzn76BXjlYFXC7NvLYq+b+kDjyyk30J0JY47DIn8z1MO3K0oSl9fZoRmZPQI4Hklzg==} + '@esbuild/linux-x64@0.25.12': + resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.9': - resolution: {integrity: sha512-9jNJl6FqaUG+COdQMjSCGW4QiMHH88xWbvZ+kRVblZsWrkXlABuGdFJ1E9L7HK+T0Yqd4akKNa/lO0+jDxQD4Q==} + '@esbuild/netbsd-arm64@0.25.12': + resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.9': - resolution: {integrity: sha512-RLLdkflmqRG8KanPGOU7Rpg829ZHu8nFy5Pqdi9U01VYtG9Y0zOG6Vr2z4/S+/3zIyOxiK6cCeYNWOFR9QP87g==} + '@esbuild/netbsd-x64@0.25.12': + resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.9': - resolution: {integrity: sha512-YaFBlPGeDasft5IIM+CQAhJAqS3St3nJzDEgsgFixcfZeyGPCd6eJBWzke5piZuZ7CtL656eOSYKk4Ls2C0FRQ==} + '@esbuild/openbsd-arm64@0.25.12': + resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.9': - resolution: {integrity: sha512-1MkgTCuvMGWuqVtAvkpkXFmtL8XhWy+j4jaSO2wxfJtilVCi0ZE37b8uOdMItIHz4I6z1bWWtEX4CJwcKYLcuA==} + '@esbuild/openbsd-x64@0.25.12': + resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.9': - resolution: {integrity: sha512-4Xd0xNiMVXKh6Fa7HEJQbrpP3m3DDn43jKxMjxLLRjWnRsfxjORYJlXPO4JNcXtOyfajXorRKY9NkOpTHptErg==} + '@esbuild/openharmony-arm64@0.25.12': + resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.9': - resolution: {integrity: sha512-WjH4s6hzo00nNezhp3wFIAfmGZ8U7KtrJNlFMRKxiI9mxEK1scOMAaa9i4crUtu+tBr+0IN6JCuAcSBJZfnphw==} + '@esbuild/sunos-x64@0.25.12': + resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.9': - resolution: {integrity: sha512-mGFrVJHmZiRqmP8xFOc6b84/7xa5y5YvR1x8djzXpJBSv/UsNK6aqec+6JDjConTgvvQefdGhFDAs2DLAds6gQ==} + '@esbuild/win32-arm64@0.25.12': + resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.9': - resolution: {integrity: sha512-b33gLVU2k11nVx1OhX3C8QQP6UHQK4ZtN56oFWvVXvz2VkDoe6fbG8TOgHFxEvqeqohmRnIHe5A1+HADk4OQww==} + '@esbuild/win32-ia32@0.25.12': + resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.9': - resolution: {integrity: sha512-PPOl1mi6lpLNQxnGoyAfschAodRFYXJ+9fs6WHXz7CSWKbOqiMZsubC+BQsVKuul+3vKLuwTHsS2c2y9EoKwxQ==} + '@esbuild/win32-x64@0.25.12': + resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -2470,17 +2771,65 @@ packages: resolution: {integrity: sha512-zQ0IqbdX8FZ9aw11vP+dZkKDkS+kgIvQPHnSAXzP9pLu+Rfu3D3XEeLbicvoXJTYnhZiPmsZUxgdzXwNKxRPbA==} engines: {node: '>=14'} - '@exodus/bytes@1.8.0': - resolution: {integrity: sha512-8JPn18Bcp8Uo1T82gR8lh2guEOa5KKU/IEKvvdp0sgmi7coPBWf1Doi1EXsGZb2ehc8ym/StJCjffYV+ne7sXQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - '@exodus/crypto': ^1.0.0-rc.4 - peerDependenciesMeta: - '@exodus/crypto': - optional: true + '@ethersproject/abi@5.8.0': + resolution: {integrity: sha512-b9YS/43ObplgyV6SlyQsG53/vkSal0MNA1fskSC4mbnCMi8R+NkcH8K9FPYNESf6jUefBUniE4SOKms0E/KK1Q==} - '@farcaster/frame-sdk@0.1.9': - resolution: {integrity: sha512-r5cAKgHn4w8Q1jaCi84uKqItfNRd6h8Lk0YyQaz5kMoEIeJ4C0gXPpyqKPYP2TVDFuvaexg2KvzCO2CQdygWyQ==} + '@ethersproject/abstract-provider@5.8.0': + resolution: {integrity: sha512-wC9SFcmh4UK0oKuLJQItoQdzS/qZ51EJegK6EmAWlh+OptpQ/npECOR3QqECd8iGHC0RJb4WKbVdSfif4ammrg==} + + '@ethersproject/abstract-signer@5.8.0': + resolution: {integrity: sha512-N0XhZTswXcmIZQdYtUnd79VJzvEwXQw6PK0dTl9VoYrEBxxCPXqS0Eod7q5TNKRxe1/5WUMuR0u0nqTF/avdCA==} + + '@ethersproject/address@5.8.0': + resolution: {integrity: sha512-GhH/abcC46LJwshoN+uBNoKVFPxUuZm6dA257z0vZkKmU1+t8xTn8oK7B9qrj8W2rFRMch4gbJl6PmVxjxBEBA==} + + '@ethersproject/base64@5.8.0': + resolution: {integrity: sha512-lN0oIwfkYj9LbPx4xEkie6rAMJtySbpOAFXSDVQaBnAzYfB4X2Qr+FXJGxMoc3Bxp2Sm8OwvzMrywxyw0gLjIQ==} + + '@ethersproject/bignumber@5.8.0': + resolution: {integrity: sha512-ZyaT24bHaSeJon2tGPKIiHszWjD/54Sz8t57Toch475lCLljC6MgPmxk7Gtzz+ddNN5LuHea9qhAe0x3D+uYPA==} + + '@ethersproject/bytes@5.8.0': + resolution: {integrity: sha512-vTkeohgJVCPVHu5c25XWaWQOZ4v+DkGoC42/TS2ond+PARCxTJvgTFUNDZovyQ/uAQ4EcpqqowKydcdmRKjg7A==} + + '@ethersproject/constants@5.8.0': + resolution: {integrity: sha512-wigX4lrf5Vu+axVTIvNsuL6YrV4O5AXl5ubcURKMEME5TnWBouUh0CDTWxZ2GpnRn1kcCgE7l8O5+VbV9QTTcg==} + + '@ethersproject/hash@5.8.0': + resolution: {integrity: sha512-ac/lBcTbEWW/VGJij0CNSw/wPcw9bSRgCB0AIBz8CvED/jfvDoV9hsIIiWfvWmFEi8RcXtlNwp2jv6ozWOsooA==} + + '@ethersproject/keccak256@5.8.0': + resolution: {integrity: sha512-A1pkKLZSz8pDaQ1ftutZoaN46I6+jvuqugx5KYNeQOPqq+JZ0Txm7dlWesCHB5cndJSu5vP2VKptKf7cksERng==} + + '@ethersproject/logger@5.8.0': + resolution: {integrity: sha512-Qe6knGmY+zPPWTC+wQrpitodgBfH7XoceCGL5bJVejmH+yCS3R8jJm8iiWuvWbG76RUmyEG53oqv6GMVWqunjA==} + + '@ethersproject/networks@5.8.0': + resolution: {integrity: sha512-egPJh3aPVAzbHwq8DD7Po53J4OUSsA1MjQp8Vf/OZPav5rlmWUaFLiq8cvQiGK0Z5K6LYzm29+VA/p4RL1FzNg==} + + '@ethersproject/properties@5.8.0': + resolution: {integrity: sha512-PYuiEoQ+FMaZZNGrStmN7+lWjlsoufGIHdww7454FIaGdbe/p5rnaCXTr5MtBYl3NkeoVhHZuyzChPeGeKIpQw==} + + '@ethersproject/rlp@5.8.0': + resolution: {integrity: sha512-LqZgAznqDbiEunaUvykH2JAoXTT9NV0Atqk8rQN9nx9SEgThA/WMx5DnW8a9FOufo//6FZOCHZ+XiClzgbqV9Q==} + + '@ethersproject/signing-key@5.8.0': + resolution: {integrity: sha512-LrPW2ZxoigFi6U6aVkFN/fa9Yx/+4AtIUe4/HACTvKJdhm0eeb107EVCIQcrLZkxaSIgc/eCrX8Q1GtbH+9n3w==} + + '@ethersproject/strings@5.8.0': + resolution: {integrity: sha512-qWEAk0MAvl0LszjdfnZ2uC8xbR2wdv4cDabyHiBh3Cldq/T8dPH3V4BbBsAYJUeonwD+8afVXld274Ls+Y1xXg==} + + '@ethersproject/transactions@5.8.0': + resolution: {integrity: sha512-UglxSDjByHG0TuU17bDfCemZ3AnKO2vYrL5/2n2oXvKzvb7Cz+W9gOWXKARjp2URVwcWlQlPOEQyAviKwT4AHg==} + + '@ethersproject/web@5.8.0': + resolution: {integrity: sha512-j7+Ksi/9KfGviws6Qtf9Q7KCqRhpwrYKQPs+JBA/rKVFF/yaWLHJEH3zfVP2plVu+eys0d2DlFmhoQJayFewcw==} + + '@evanhahn/lottie-web-light@5.8.1': + resolution: {integrity: sha512-U0G1tt3/UEYnyCNNslWPi1dB7X1xQ9aoSip+B3GTKO/Bns8yz/p39vBkRSN9d25nkbHuCsbjky2coQftj5YVKw==} + + '@farcaster/frame-sdk@0.1.9': + resolution: {integrity: sha512-r5cAKgHn4w8Q1jaCi84uKqItfNRd6h8Lk0YyQaz5kMoEIeJ4C0gXPpyqKPYP2TVDFuvaexg2KvzCO2CQdygWyQ==} engines: {node: '>=22.11.0'} '@farcaster/miniapp-core@0.3.8': @@ -2534,11 +2883,45 @@ packages: peerDependencies: graphql: ^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0 + '@grpc/grpc-js@1.12.6': + resolution: {integrity: sha512-JXUj6PI0oqqzTGvKtzOkxtpsyPRNsrmhh41TtIz/zEB6J+AUiZZ0dxWzcMwO9Ns5rmSPuMdghlTbUuqIM48d3Q==} + engines: {node: '>=12.10.0'} + + '@grpc/proto-loader@0.7.15': + resolution: {integrity: sha512-tMXdRCfYVixjuFK+Hk0Q1s38gV9zDiDJfWL3h1rv4Qc39oILCu1TRTDt7+fGUI8K4G1Fj125Hx/ru3azECWTyQ==} + engines: {node: '>=6'} + hasBin: true + '@heroicons/react@2.2.0': resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==} peerDependencies: react: '>= 16 || ^19.0.0-rc' + '@hiero-ledger/cryptography@1.16.0-beta.3': + resolution: {integrity: sha512-7+R/HKGq6LiqUZ1agn52sQS6J3+VXBWvqIMUCIU1EVdbEPQDPoVPJYEd7dDreBCLIcjBRcHVjDc9wbi+ar2rsA==} + engines: {node: '>=12.0.0'} + peerDependencies: + expo-crypto: '*' + peerDependenciesMeta: + expo-crypto: + optional: true + + '@hiero-ledger/proto@2.26.0-beta.3': + resolution: {integrity: sha512-2UhTKX2RbL2LC8XcgetFa4iS5d8cELY/8PmFolj750z4CoQu2YOchZTqNTdI431qR9uAx3aBVSf+mx/YBYIUNA==} + engines: {node: '>=10.0.0'} + peerDependencies: + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + debug: 4.4.1 + protobufjs: 7.5.4 + strip-ansi: 7.1.2 + + '@hiero-ledger/sdk@2.80.0': + resolution: {integrity: sha512-9FHNPduWl27eNI2Gns0O6GJTqcEJ11lBTML84A7D8albCErVXaUVsnRrASafH+Xfq1dqK5dwsNHRwu8WtM3zVQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + bn.js: 5.2.1 + '@hono/node-server@1.19.1': resolution: {integrity: sha512-h44e5s+ByUriaRIbeS/C74O8v90m0A95luyYQGMF7KEn96KkYMXO7bZAwombzTpjQTU4e0TkU8U1WBIXlwuwtA==} engines: {node: '>=18.14.1'} @@ -2597,89 +2980,105 @@ packages: resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-arm@1.2.4': resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-ppc64@1.2.4': resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-riscv64@1.2.4': resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-s390x@1.2.4': resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-libvips-linux-x64@1.2.4': resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-libvips-linuxmusl-arm64@1.2.4': resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-libvips-linuxmusl-x64@1.2.4': resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-linux-arm64@0.34.5': resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [glibc] '@img/sharp-linux-arm@0.34.5': resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm] os: [linux] + libc: [glibc] '@img/sharp-linux-ppc64@0.34.5': resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [ppc64] os: [linux] + libc: [glibc] '@img/sharp-linux-riscv64@0.34.5': resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [riscv64] os: [linux] + libc: [glibc] '@img/sharp-linux-s390x@0.34.5': resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [s390x] os: [linux] + libc: [glibc] '@img/sharp-linux-x64@0.34.5': resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [glibc] '@img/sharp-linuxmusl-arm64@0.34.5': resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [arm64] os: [linux] + libc: [musl] '@img/sharp-linuxmusl-x64@0.34.5': resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} cpu: [x64] os: [linux] + libc: [musl] '@img/sharp-wasm32@0.34.5': resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} @@ -2717,6 +3116,18 @@ packages: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} + '@isaacs/ttlcache@1.4.1': + resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} + engines: {node: '>=12'} + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} @@ -2727,12 +3138,21 @@ packages: resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} '@jridgewell/trace-mapping@0.3.30': resolution: {integrity: sha512-GQ7Nw5G2lTu/BtHTKfXhKHok2WGetd4XYcVKGx00SjAk8GMwgJM3zr6zORiPGuOE+/vkc90KtTosSSvaCjKb2Q==} + '@js-sdsl/ordered-map@4.4.2': + resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} + + '@likecoin/qr-code-styling@1.6.6': + resolution: {integrity: sha512-RbGK/+20bJhFZR70r8MeDvfyz3W7U5zXpykSTYOYxZGyo6wC+Y4QnbUpL+YdAtzT2ZIFeCNOcRs2W2FNrKPoaA==} + '@lit-labs/ssr-dom-shim@1.4.0': resolution: {integrity: sha512-ficsEARKnmmW5njugNYKipTm4SFnbik7CXtoencDZzmzo/dQ+2Q0bgkzJuoJP20Aj0F+izzJjOqsnkd6F/o1bw==} @@ -2789,9 +3209,11 @@ packages: '@metamask/sdk-analytics@0.0.5': resolution: {integrity: sha512-fDah+keS1RjSUlC8GmYXvx6Y26s3Ax1U9hGpWb6GSY5SAdmTSIqp2CvYy6yW0WgLhnYhW+6xERuD0eVqV63QIQ==} + deprecated: No longer maintained, superseded by @metamask/connect-analytics '@metamask/sdk-communication-layer@0.32.0': resolution: {integrity: sha512-dmj/KFjMi1fsdZGIOtbhxdg3amxhKL/A5BqSU4uh/SyDKPub/OT+x5pX8bGjpTL1WPWY/Q0OIlvFyX3VWnT06Q==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect peerDependencies: cross-fetch: ^4.0.0 eciesjs: '*' @@ -2801,6 +3223,7 @@ packages: '@metamask/sdk-communication-layer@0.33.1': resolution: {integrity: sha512-0bI9hkysxcfbZ/lk0T2+aKVo1j0ynQVTuB3sJ5ssPWlz+Z3VwveCkP1O7EVu1tsVVCb0YV5WxK9zmURu2FIiaA==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect peerDependencies: cross-fetch: ^4.0.0 eciesjs: '*' @@ -2810,15 +3233,19 @@ packages: '@metamask/sdk-install-modal-web@0.32.0': resolution: {integrity: sha512-TFoktj0JgfWnQaL3yFkApqNwcaqJ+dw4xcnrJueMP3aXkSNev2Ido+WVNOg4IIMxnmOrfAC9t0UJ0u/dC9MjOQ==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect '@metamask/sdk-install-modal-web@0.32.1': resolution: {integrity: sha512-MGmAo6qSjf1tuYXhCu2EZLftq+DSt5Z7fsIKr2P+lDgdTPWgLfZB1tJKzNcwKKOdf6q9Qmmxn7lJuI/gq5LrKw==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect '@metamask/sdk@0.32.0': resolution: {integrity: sha512-WmGAlP1oBuD9hk4CsdlG1WJFuPtYJY+dnTHJMeCyohTWD2GgkcLMUUuvu9lO1/NVzuOoSi1OrnjbuY1O/1NZ1g==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect '@metamask/sdk@0.33.1': resolution: {integrity: sha512-1mcOQVGr9rSrVcbKPNVzbZ8eCl1K0FATsYH3WJ/MH4WcZDWGECWrXJPNMZoEAkLxWiMe8jOQBumg2pmcDa9zpQ==} + deprecated: No longer maintained, superseded by https://docs.metamask.io/metamask-connect '@metamask/superstruct@3.2.1': resolution: {integrity: sha512-fLgJnDOXFmuVlB38rUN5SmU7hAFQcCjrg3Vrxz67KTY7YHFnSNEKvX4avmEBdOI0yTCxZjwMCFEqsC8k2+Wd3g==} @@ -2850,6 +3277,10 @@ packages: '@cfworker/json-schema': optional: true + '@msgpack/msgpack@3.1.3': + resolution: {integrity: sha512-47XIizs9XZXvuJgoaJUIE2lFoID8ugvc0jzSHP+Ptfk8nTbnR8g788wv48N03Kx0UkAv559HWRQ3yzOgzlRNUA==} + engines: {node: '>= 18'} + '@napi-rs/wasm-runtime@0.2.12': resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} @@ -2876,24 +3307,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@next/swc-linux-arm64-musl@16.0.10': resolution: {integrity: sha512-llA+hiDTrYvyWI21Z0L1GiXwjQaanPVQQwru5peOgtooeJ8qx3tlqRV2P7uH2pKQaUfHxI/WVarvI5oYgGxaTw==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@next/swc-linux-x64-gnu@16.0.10': resolution: {integrity: sha512-AK2q5H0+a9nsXbeZ3FZdMtbtu9jxW4R/NgzZ6+lrTm3d6Zb7jYrWcgjcpM1k8uuqlSy4xIyPR2YiuUr+wXsavA==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@next/swc-linux-x64-musl@16.0.10': resolution: {integrity: sha512-1TDG9PDKivNw5550S111gsO4RGennLVl9cipPhtkXIFVwo31YZ73nEbLjNC8qG3SgTz/QZyYyaFYMeY4BKZR/g==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@next/swc-win32-arm64-msvc@16.0.10': resolution: {integrity: sha512-aEZIS4Hh32xdJQbHz121pyuVZniSNoqDVx1yIr2hy+ZwJGipeqnMZBJHyMxv2tiuAXGx6/xpTcQJ6btIiBjgmg==} @@ -2907,6 +3342,10 @@ packages: cpu: [x64] os: [win32] + '@noble/ciphers@1.2.0': + resolution: {integrity: sha512-YGdEUzYEd+82jeaVbSKKVp1jFZb8LwaNMIIzHFkihGvYdd/KKAr7KaJHdEdSYGredE3ssSravXIa0Jxg28Sv5w==} + engines: {node: ^14.21.3 || >=16} + '@noble/ciphers@1.2.1': resolution: {integrity: sha512-rONPWMC7PeExE077uLE4oqWrZ1IvAfz3oH9LibVAcVCopJiA9R62uavnbEzdkVmJYI6M6Zgkbeb07+tWjlq2XA==} engines: {node: ^14.21.3 || >=16} @@ -2915,8 +3354,9 @@ packages: resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} engines: {node: ^14.21.3 || >=16} - '@noble/curves@1.2.0': - resolution: {integrity: sha512-oYclrNgRaM9SsBUBVbb8M6DTV7ZHRTKugureoYEncY5c65HOmRzvSiTE3y5CYaPYJA/GVkrhXEoF0M3Ya9PMnw==} + '@noble/ciphers@2.1.1': + resolution: {integrity: sha512-bysYuiVfhxNJuldNXlFEitTVdNnYUc+XNJZd7Qm2a5j1vZHgY+fazadNFWFaMK/2vye0JVlxV3gHmC0WDfAOQw==} + engines: {node: '>= 20.19.0'} '@noble/curves@1.4.2': resolution: {integrity: sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw==} @@ -2937,9 +3377,12 @@ packages: resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} engines: {node: ^14.21.3 || >=16} - '@noble/hashes@1.3.2': - resolution: {integrity: sha512-MVC8EAQp7MvEcm30KWENFjgR+Mkmf+D189XJTkFIlwohU5hcBbn1ZkKq7KVTi2Hme3PMGF390DaL52beVrIihQ==} - engines: {node: '>= 16'} + '@noble/curves@2.0.1': + resolution: {integrity: sha512-vs1Az2OOTBiP4q0pwjW5aF0xp9n4MxVrmkFBxc6EKZc6ddYx5gaZiAsZoq0uRRXWbi3AT/sBqn05eRPtn1JCPw==} + engines: {node: '>= 20.19.0'} + + '@noble/ed25519@3.0.0': + resolution: {integrity: sha512-QyteqMNm0GLqfa5SoYbSC3+Pvykwpn95Zgth4MFVSMKBB75ELl9tX1LAVsN4c3HXOrakHsF2gL4zWDAYCcsnzg==} '@noble/hashes@1.4.0': resolution: {integrity: sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg==} @@ -2957,6 +3400,10 @@ packages: resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} engines: {node: ^14.21.3 || >=16} + '@noble/hashes@2.0.1': + resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} + engines: {node: '>= 20.19.0'} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -2977,6 +3424,11 @@ packages: resolution: {integrity: sha512-IHnV6A+zxU7XwmKFinmYjUcwlyK9+xkG3/s9KcQhI9BjQKycrJ1JRO+FbNYPwZiPKW3je/DR0k7w8/gLa5eaxQ==} deprecated: 'The package is now available as "qr": npm install qr' + '@perawallet/connect@1.5.2': + resolution: {integrity: sha512-Lq4nLaQBisZUkBIWirhRn4b9MjrKWvlMxfrU6On5al/14E5mm3dlnwGHhpJ88IGlnGs7JyL625LVMgUK1TOTrg==} + peerDependencies: + algosdk: ^3.5.2 + '@pinojs/redact@0.4.0': resolution: {integrity: sha512-k2ENnmBugE/rzQfEcdWHcCY+/FM3VLzH9cYEsbdsoqrvzAKRhUZeRNhAZvB8OitQJ1TBed3yqWtdjzS6wJKBwg==} @@ -2988,6 +3440,92 @@ packages: resolution: {integrity: sha512-QNqXyfVS2wm9hweSYD2O7F0G06uurj9kZ96TRQE5Y9hU7+tgdZwIkbAKc5Ocy1HxEY2kuDQa6cQ1WRs/O5LFKA==} engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + '@protobufjs/aspromise@1.1.2': + resolution: {integrity: sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==} + + '@protobufjs/base64@1.1.2': + resolution: {integrity: sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==} + + '@protobufjs/codegen@2.0.4': + resolution: {integrity: sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==} + + '@protobufjs/eventemitter@1.1.0': + resolution: {integrity: sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==} + + '@protobufjs/fetch@1.1.0': + resolution: {integrity: sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==} + + '@protobufjs/float@1.0.2': + resolution: {integrity: sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==} + + '@protobufjs/inquire@1.1.0': + resolution: {integrity: sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==} + + '@protobufjs/path@1.1.2': + resolution: {integrity: sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==} + + '@protobufjs/pool@1.1.0': + resolution: {integrity: sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==} + + '@protobufjs/utf8@1.1.0': + resolution: {integrity: sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==} + + '@react-native/assets-registry@0.85.0': + resolution: {integrity: sha512-zfVwcEunuywcDR6EYSOcyPKzWMR/HXuByjfS4m7//Hs+Qh5r1j5yfDFNeqansNs3LKv+7EFnEEYFCfpLhYTIew==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/codegen@0.85.0': + resolution: {integrity: sha512-5CHJkC9UpBxQokGju7gD6W615RO1zR17INuB1PB4kcXNy3rre7tyy6ufct+sllDD6ildRC9A//cyh6TI03+jxA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@babel/core': '*' + + '@react-native/community-cli-plugin@0.85.0': + resolution: {integrity: sha512-OtNdU8xpZxnYmT17gik10eDO47MKYoy8wNlPigxL3lxv/+Hn2cxlvuBHIwoML6PJMgGXpuootOwEyj6MPl7WQQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@react-native-community/cli': '*' + '@react-native/metro-config': 0.85.0 + peerDependenciesMeta: + '@react-native-community/cli': + optional: true + '@react-native/metro-config': + optional: true + + '@react-native/debugger-frontend@0.85.0': + resolution: {integrity: sha512-57m1QfNlusZBV8C8dGx2JXdp0lXz8IWB44E5/NagM3AchMYPXBzWy+unlE/tPfvr7otOSdhRyyPC8Rw2NJuGiw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/debugger-shell@0.85.0': + resolution: {integrity: sha512-bL4JJwlTt4wwUgjOIjkdxyu0pMD9p6OLUJ/VWeG+/T6QhIu4x75mECgzodjOPvhgQ/TwsY4uRe7o2wMEjwShjA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/dev-middleware@0.85.0': + resolution: {integrity: sha512-jmiktFPyAZjzMTcyyr1+gnmaCrZH0lrjbbUsRk20p60XPTQ1eQtDLUGG4NQUlt8FzdKDmX7VlwAj8FuVl3Su4g==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/gradle-plugin@0.85.0': + resolution: {integrity: sha512-C9+krvr9XtylwPrDUzVjlWh+DrILVYkSHDcWiAnHBaCvyRl8nbaSvzdaapuhOPT76395j0Aj83ENlLaExuhGXQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/js-polyfills@0.85.0': + resolution: {integrity: sha512-h2nfIqNEA72Ebdcq5scJg1kyZ01B9xI+NJ2AA8ZpGN8SbxOBNAiZtWEqxzAUe6v5Iu7LE3+1WFBWcMQGtT4zLQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/normalize-colors@0.85.0': + resolution: {integrity: sha512-pULHg7h5ogY78oKvbyZM93UucljB3Tvo85o1h4mrfn/G2oQAruLbCWAiVdaI00G2EVdUke3wlOtrlaTez3vZ1A==} + + '@react-native/virtualized-lists@0.85.0': + resolution: {integrity: sha512-QpomR0B/LX/jUNKO3ptjQo0NM+JfBHXbKGRe45LaFpl2Wr6r031CKp5UJ4XAAWq148Do01SI4bFDGAScb0IdpA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@types/react': ^19.2.0 + react: '*' + react-native: 0.85.0 + peerDependenciesMeta: + '@types/react': + optional: true + '@reown/appkit-common@1.7.8': resolution: {integrity: sha512-ridIhc/x6JOp7KbDdwGKY4zwf8/iK8EYBl+HtWrruutSLwZyVi5P8WaZa+8iajL6LcDcDF7LoyLwMTym7SRuwQ==} @@ -3051,56 +3589,67 @@ packages: resolution: {integrity: sha512-u72Mzc6jyJwKjJbZZcIYmd9bumJu7KNmHYdue43vT1rXPm2rITwmPWF0mmPzLm9/vJWxIRbao/jrQmxTO0Sm9w==} cpu: [arm] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm-musleabihf@4.50.0': resolution: {integrity: sha512-S4UefYdV0tnynDJV1mdkNawp0E5Qm2MtSs330IyHgaccOFrwqsvgigUD29uT+B/70PDY1eQ3t40+xf6wIvXJyg==} cpu: [arm] os: [linux] + libc: [musl] '@rollup/rollup-linux-arm64-gnu@4.50.0': resolution: {integrity: sha512-1EhkSvUQXJsIhk4msxP5nNAUWoB4MFDHhtc4gAYvnqoHlaL9V3F37pNHabndawsfy/Tp7BPiy/aSa6XBYbaD1g==} cpu: [arm64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-arm64-musl@4.50.0': resolution: {integrity: sha512-EtBDIZuDtVg75xIPIK1l5vCXNNCIRM0OBPUG+tbApDuJAy9mKago6QxX+tfMzbCI6tXEhMuZuN1+CU8iDW+0UQ==} cpu: [arm64] os: [linux] + libc: [musl] '@rollup/rollup-linux-loongarch64-gnu@4.50.0': resolution: {integrity: sha512-BGYSwJdMP0hT5CCmljuSNx7+k+0upweM2M4YGfFBjnFSZMHOLYR0gEEj/dxyYJ6Zc6AiSeaBY8dWOa11GF/ppQ==} cpu: [loong64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-ppc64-gnu@4.50.0': resolution: {integrity: sha512-I1gSMzkVe1KzAxKAroCJL30hA4DqSi+wGc5gviD0y3IL/VkvcnAqwBf4RHXHyvH66YVHxpKO8ojrgc4SrWAnLg==} cpu: [ppc64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-gnu@4.50.0': resolution: {integrity: sha512-bSbWlY3jZo7molh4tc5dKfeSxkqnf48UsLqYbUhnkdnfgZjgufLS/NTA8PcP/dnvct5CCdNkABJ56CbclMRYCA==} cpu: [riscv64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-riscv64-musl@4.50.0': resolution: {integrity: sha512-LSXSGumSURzEQLT2e4sFqFOv3LWZsEF8FK7AAv9zHZNDdMnUPYH3t8ZlaeYYZyTXnsob3htwTKeWtBIkPV27iQ==} cpu: [riscv64] os: [linux] + libc: [musl] '@rollup/rollup-linux-s390x-gnu@4.50.0': resolution: {integrity: sha512-CxRKyakfDrsLXiCyucVfVWVoaPA4oFSpPpDwlMcDFQvrv3XY6KEzMtMZrA+e/goC8xxp2WSOxHQubP8fPmmjOQ==} cpu: [s390x] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-gnu@4.50.0': resolution: {integrity: sha512-8PrJJA7/VU8ToHVEPu14FzuSAqVKyo5gg/J8xUerMbyNkWkO9j2ExBho/68RnJsMGNJq4zH114iAttgm7BZVkA==} cpu: [x64] os: [linux] + libc: [glibc] '@rollup/rollup-linux-x64-musl@4.50.0': resolution: {integrity: sha512-SkE6YQp+CzpyOrbw7Oc4MgXFvTw2UIBElvAvLCo230pyxOLmYwRPwZ/L5lBe/VW/qT1ZgND9wJfOsdy0XptRvw==} cpu: [x64] os: [linux] + libc: [musl] '@rollup/rollup-openharmony-arm64@4.50.0': resolution: {integrity: sha512-PZkNLPfvXeIOgJWA804zjSFH7fARBBCpCXxgkGDRjjAhRLOR8o0IGS01ykh5GYfod4c2yiiREuDM8iZ+pVsT+Q==} @@ -3159,6 +3708,23 @@ packages: '@scure/bip39@1.6.0': resolution: {integrity: sha512-+lF0BbLiJNwVlev4eKelw1WWLaiKXw7sSl8T6FvBlWkdX+94aGJ4o8XjUdlyhTCjd8c+B3KT3JfS8P0bLRNU6A==} + '@signinwithethereum/siwe-parser@4.1.0': + resolution: {integrity: sha512-aS+bU5QpTQgMpC6HjQHuKJpltUrkyGUVNuhuBLARa39wF1B+m05/4bgnf2qrEcgQONfU36A2Nbn3ibmwhHkc2Q==} + + '@signinwithethereum/siwe@4.1.0': + resolution: {integrity: sha512-NT56M82i+A2uBU++F9PSBvEYPcjUV3BdClRVojWt3cbe7WizIVH1wi2qKJJR570RLHZvr8q1gUf0E90WymlMeA==} + peerDependencies: + ethers: ^5.7.0 || ^6.13.0 + viem: ^2.7.0 + peerDependenciesMeta: + ethers: + optional: true + viem: + optional: true + + '@sinclair/typebox@0.27.10': + resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} + '@sindresorhus/is@4.6.0': resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -4280,21 +4846,6 @@ packages: '@solana/web3.js@1.98.4': resolution: {integrity: sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==} - '@spruceid/siwe-parser@2.1.2': - resolution: {integrity: sha512-d/r3S1LwJyMaRAKQ0awmo9whfXeE88Qt00vRj91q5uv5ATtWIQEGJ67Yr5eSZw5zp1/fZCXZYuEckt8lSkereQ==} - - '@stablelib/binary@1.0.1': - resolution: {integrity: sha512-ClJWvmL6UBM/wjkvv/7m5VP3GMr9t0osr4yVgLZsLCOz4hGN9gIAFEqnJ0TsSMAN+n840nf2cHZnA5/KFqHC7Q==} - - '@stablelib/int@1.0.1': - resolution: {integrity: sha512-byr69X/sDtDiIjIV6m4roLVWnNNlRGzsvxw+agj8CIEazqWGOQp2dTYgQhtyVXV9wpO6WyXRQUzLV/JRNumT2w==} - - '@stablelib/random@1.0.2': - resolution: {integrity: sha512-rIsE83Xpb7clHPVRlBj8qNe5L8ISQOzjghYQm/dZ7VaM2KHYwMW5adjQjrzTZCchFnNCNhkwtnOBa9HTMJCI8w==} - - '@stablelib/wipe@1.0.1': - resolution: {integrity: sha512-WfqfX/eXGiAd3RJe4VU2snh/ZPwtSjLG4ynQ/vYzvghTh7dHFcI1wl+nrkWG6lGhukOxOsUHfv8dUXr58D0ayg==} - '@stellar/js-xdr@3.1.2': resolution: {integrity: sha512-VVolPL5goVEIsvuGqDc5uiKxV03lzfWdvYg1KikvwheDmTBO68CKDji3bAZ/kppZrx5iTA8z3Ld5yuytcvhvOQ==} @@ -4433,24 +4984,28 @@ packages: engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-arm64-musl@4.1.17': resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] + libc: [musl] '@tailwindcss/oxide-linux-x64-gnu@4.1.17': resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [glibc] '@tailwindcss/oxide-linux-x64-musl@4.1.17': resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] + libc: [musl] '@tailwindcss/oxide-wasm32-wasi@4.1.17': resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} @@ -4491,10 +5046,49 @@ packages: peerDependencies: react: ^18 || ^19 + '@tanstack/store@0.8.0': + resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + '@trysound/sax@0.2.0': resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==} engines: {node: '>=10.13.0'} + '@txnlab/use-wallet@4.6.0': + resolution: {integrity: sha512-niAookAa8cpkrZsGDwQUaeLTODSd5gxSiUHaiPDiHiF/4oGKx/X/KJOFwAA/8iXOI8CTe60fbwEiKRXNIa1RvQ==} + peerDependencies: + '@agoralabs-sh/avm-web-provider': ^1.7.0 + '@blockshake/defly-connect': ^1.2.1 + '@perawallet/connect': ^1.4.1 + '@walletconnect/modal': ^2.7.0 + '@walletconnect/sign-client': ^2.23.4 + '@web3auth/base': ^9.0.0 + '@web3auth/base-provider': ^9.0.0 + '@web3auth/modal': ^9.0.0 + '@web3auth/single-factor-auth': ^9.0.0 + algosdk: ^3.0.0 + lute-connect: ^1.6.3 + peerDependenciesMeta: + '@agoralabs-sh/avm-web-provider': + optional: true + '@blockshake/defly-connect': + optional: true + '@perawallet/connect': + optional: true + '@walletconnect/modal': + optional: true + '@walletconnect/sign-client': + optional: true + '@web3auth/base': + optional: true + '@web3auth/base-provider': + optional: true + '@web3auth/modal': + optional: true + '@web3auth/single-factor-auth': + optional: true + lute-connect: + optional: true + '@tybys/wasm-util@0.10.0': resolution: {integrity: sha512-VyyPYFlOMNylG45GoAe0xDoLwWuowvf92F9kySqzYh8vmYm7D2u4iUJKa1tOUpS70Ku13ASrOkS4ScXFsTaCNQ==} @@ -4510,8 +5104,8 @@ packages: '@types/connect@3.4.38': resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - '@types/debug@4.1.12': - resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} + '@types/debug@4.1.13': + resolution: {integrity: sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==} '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} @@ -4531,6 +5125,15 @@ packages: '@types/http-errors@2.0.5': resolution: {integrity: sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==} + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} @@ -4555,8 +5158,8 @@ packages: '@types/node@22.18.0': resolution: {integrity: sha512-m5ObIqwsUp6BZzyiy4RdZpzWGub9bqLJMvZDD0QMXhxjqMHMENlj+SqF5QxoUwaQNFe+8kz8XM8ZQhqkQPTgMQ==} - '@types/node@22.7.5': - resolution: {integrity: sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ==} + '@types/node@22.19.17': + resolution: {integrity: sha512-wGdMcf+vPYM6jikpS/qhg6WiqSV/OhG+jeeHT/KlVqxYfD40iYJf9/AE1uQxVWFvU7MipKRkRv8NSHiCGgPr8Q==} '@types/qs@6.14.0': resolution: {integrity: sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==} @@ -4593,6 +5196,12 @@ packages: '@types/ws@8.18.1': resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + '@typescript-eslint/eslint-plugin@8.42.0': resolution: {integrity: sha512-Aq2dPqsQkxHOLfb2OPv43RnIvfj05nw8v/6n3B2NABIPpHnjQnaLo9QGMTvml+tv4korl/Cjfrb/BYhoL8UUTQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -4750,41 +5359,49 @@ packages: resolution: {integrity: sha512-34gw7PjDGB9JgePJEmhEqBhWvCiiWCuXsL9hYphDF7crW7UgI05gyBAi6MF58uGcMOiOqSJ2ybEeCvHcq0BCmQ==} cpu: [arm64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-arm64-musl@1.11.1': resolution: {integrity: sha512-RyMIx6Uf53hhOtJDIamSbTskA99sPHS96wxVE/bJtePJJtpdKGXO1wY90oRdXuYOGOTuqjT8ACccMc4K6QmT3w==} cpu: [arm64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-ppc64-gnu@1.11.1': resolution: {integrity: sha512-D8Vae74A4/a+mZH0FbOkFJL9DSK2R6TFPC9M+jCWYia/q2einCubX10pecpDiTmkJVUH+y8K3BZClycD8nCShA==} cpu: [ppc64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-gnu@1.11.1': resolution: {integrity: sha512-frxL4OrzOWVVsOc96+V3aqTIQl1O2TjgExV4EKgRY09AJ9leZpEg8Ak9phadbuX0BA4k8U5qtvMSQQGGmaJqcQ==} cpu: [riscv64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-riscv64-musl@1.11.1': resolution: {integrity: sha512-mJ5vuDaIZ+l/acv01sHoXfpnyrNKOk/3aDoEdLO/Xtn9HuZlDD6jKxHlkN8ZhWyLJsRBxfv9GYM2utQ1SChKew==} cpu: [riscv64] os: [linux] + libc: [musl] '@unrs/resolver-binding-linux-s390x-gnu@1.11.1': resolution: {integrity: sha512-kELo8ebBVtb9sA7rMe1Cph4QHreByhaZ2QEADd9NzIQsYNQpt9UkM9iqr2lhGr5afh885d/cB5QeTXSbZHTYPg==} cpu: [s390x] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-gnu@1.11.1': resolution: {integrity: sha512-C3ZAHugKgovV5YvAMsxhq0gtXuwESUKc5MhEtjBpLoHPLYM+iuwSj3lflFwK3DPm68660rZ7G8BMcwSro7hD5w==} cpu: [x64] os: [linux] + libc: [glibc] '@unrs/resolver-binding-linux-x64-musl@1.11.1': resolution: {integrity: sha512-rV0YSoyhK2nZ4vEswT/QwqzqQXw5I6CjoaYMOX0TqBlWhojUf8P94mvI7nuJTeaCkkds3QE4+zS8Ko+GdXuZtA==} cpu: [x64] os: [linux] + libc: [musl] '@unrs/resolver-binding-wasm32-wasi@1.11.1': resolution: {integrity: sha512-5u4RkfxJm+Ng7IWgkzi3qrFOvLvQYnPBmjmZQ8+szTK/b31fQCnleNl1GgEt7nIsZRIf5PLhPwT0WM+q45x/UQ==} @@ -4904,6 +5521,16 @@ packages: resolution: {integrity: sha512-hiEivWNztx73s+7iLxsuD1sOJ28xtRix58W7Xnz4XzzA/pF0+aicnWgjOdA10doVDEDZdUuZCIIqG96SFNlDUg==} engines: {node: '>=16'} + '@walletconnect/browser-utils@1.8.0': + resolution: {integrity: sha512-Wcqqx+wjxIo9fv6eBUFHPsW1y/bGWWRboni5dfD8PtOmrihrEpOCmvRJe4rfl7xgJW8Ea9UqKEaq0bIRLHlK4A==} + + '@walletconnect/client@1.8.0': + resolution: {integrity: sha512-svyBQ14NHx6Cs2j4TpkQaBI/2AF4+LXz64FojTjMtV4VMMhl81jSO1vNeg+yYhQzvjcGH/GpSwixjyCW0xFBOQ==} + deprecated: 'WalletConnect''s v1 SDKs are now deprecated. Please upgrade to a v2 SDK. For details see: https://docs.walletconnect.com/' + + '@walletconnect/core@1.8.0': + resolution: {integrity: sha512-aFTHvEEbXcZ8XdWBw6rpQDte41Rxwnuk3SgTD8/iKGSRTni50gI9S3YEzMj05jozSiOBxQci4pJDMVhIUMtarw==} + '@walletconnect/core@2.21.0': resolution: {integrity: sha512-o6R7Ua4myxR8aRUAJ1z3gT9nM+jd2B2mfamu6arzy1Cc6vi10fIwFWb6vg3bC8xJ6o9H3n/cN5TOW3aA9Y1XVw==} engines: {node: '>=18'} @@ -4912,6 +5539,16 @@ packages: resolution: {integrity: sha512-Tp4MHJYcdWD846PH//2r+Mu4wz1/ZU/fr9av1UWFiaYQ2t2TPLDiZxjLw54AAEpMqlEHemwCgiRiAmjR1NDdTQ==} engines: {node: '>=18'} + '@walletconnect/core@2.23.9': + resolution: {integrity: sha512-ws4WG8LeagUo2ERRo02HryXRcpwIRmCQ3pHLW5gWbVReLXXIpgk6ZAfID3fEGHevIwwnHSGww+nNhNpdXyiq0g==} + engines: {node: '>=18.20.8'} + + '@walletconnect/crypto@1.1.0': + resolution: {integrity: sha512-yZO8BBTQt7BcaemjDgwN56OmSv0OO4QjIpvtfj5OxZfL6IQZQWHOhwC6pJg+BmZPbDlJlWFqFuCZRtiPwRmsoA==} + + '@walletconnect/encoding@1.0.2': + resolution: {integrity: sha512-CrwSBrjqJ7rpGQcTL3kU+Ief+Bcuu9PH6JLOb+wM6NITX1GTxR/MfNwnQfhLKK6xpRAyj2/nM04OOH6wS8Imag==} + '@walletconnect/environment@1.0.1': resolution: {integrity: sha512-T426LLZtHj8e8rYnKfzsw1aG6+M0BT1ZxayMdv/p8yM0MU+eJDISqNY3/bccxRr4LrF9csq02Rhqt08Ibl0VRg==} @@ -4925,6 +5562,9 @@ packages: '@walletconnect/heartbeat@1.2.2': resolution: {integrity: sha512-uASiRmC5MwhuRuf05vq4AT48Pq8RMi876zV8rr8cV969uTOzWdB/k+Lj5yI2PBtB1bGQisGen7MM1GcZlQTBXw==} + '@walletconnect/iso-crypto@1.8.0': + resolution: {integrity: sha512-pWy19KCyitpfXb70hA73r9FcvklS+FvO9QUIttp3c2mfW8frxgYeRXfxLRCIQTkaYueRKvdqPjbyhPLam508XQ==} + '@walletconnect/jsonrpc-http-connection@1.0.8': resolution: {integrity: sha512-+B7cRuaxijLeFDJUq5hAzNyef3e3tBDIxyaCNmFtjwnod5AGis3RToNqzFU33vpVcxFhofkpE7Cx+5MYejbMGw==} @@ -4951,12 +5591,21 @@ packages: '@walletconnect/logger@2.1.2': resolution: {integrity: sha512-aAb28I3S6pYXZHQm5ESB+V6rDqIYfsnHaQyzFbwUUBFY4H0OXx/YtTl8lvhUNhMMfb9UxbwEBS253TlXUYJWSw==} + '@walletconnect/logger@3.0.2': + resolution: {integrity: sha512-7wR3wAwJTOmX4gbcUZcFMov8fjftY05+5cO/d4cpDD8wDzJ+cIlKdYOXaXfxHLSYeDazMXIsxMYjHYVDfkx+nA==} + + '@walletconnect/randombytes@1.1.0': + resolution: {integrity: sha512-X+LO/9ClnXX2Q/1+u83qMnohVaxC4qsXByM/gMSwGMrUObxEiqEWS+b9Upg9oNl6mTr85dTCRF8W17KVcKKXQw==} + '@walletconnect/relay-api@1.0.11': resolution: {integrity: sha512-tLPErkze/HmC9aCmdZOhtVmYZq1wKfWTJtygQHoWtgg722Jd4homo54Cs4ak2RUFUZIGO2RsOpIcWipaua5D5Q==} '@walletconnect/relay-auth@1.1.0': resolution: {integrity: sha512-qFw+a9uRz26jRCDgL7Q5TA9qYIgcNY8jpJzI1zAWNZ8i7mQjaijRnWFKsCHAU9CyGjvt6RKrRXyFtFOpWTVmCQ==} + '@walletconnect/safe-json@1.0.0': + resolution: {integrity: sha512-QJzp/S/86sUAgWY6eh5MKYmSfZaRpIlmCJdi5uG4DJlKkZrHEF7ye7gA+VtbVzvTtpM/gRwO2plQuiooIeXjfg==} + '@walletconnect/safe-json@1.0.2': resolution: {integrity: sha512-Ogb7I27kZ3LPC3ibn8ldyUr5544t3/STow9+lzz7Sfo808YD7SBWk7SAsdBFlYgP2zDRy2hS3sKRcuSRM0OTmA==} @@ -4968,15 +5617,28 @@ packages: resolution: {integrity: sha512-QaXzmPsMnKGV6tc4UcdnQVNOz4zyXgarvdIQibJ4L3EmLat73r5ZVl4c0cCOcoaV7rgM9Wbphgu5E/7jNcd3Zg==} deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' + '@walletconnect/sign-client@2.23.9': + resolution: {integrity: sha512-Xj+hw4E6mGRyhCdVOT/RMgnG+up/Y3v0ho5PlkVozvXWeVSqHNh9DmjLuU97a7OACoGd/oHBF6g3NVqD7MgCMQ==} + + '@walletconnect/socket-transport@1.8.0': + resolution: {integrity: sha512-5DyIyWrzHXTcVp0Vd93zJ5XMW61iDM6bcWT4p8DTRfFsOtW46JquruMhxOLeCOieM4D73kcr3U7WtyR4JUsGuQ==} + '@walletconnect/time@1.0.2': resolution: {integrity: sha512-uzdd9woDcJ1AaBZRhqy5rNC9laqWGErfc4dxA9a87mPdKOgWMD85mcFo9dIYIts/Jwocfwn07EC6EzclKubk/g==} + '@walletconnect/types@1.8.0': + resolution: {integrity: sha512-Cn+3I0V0vT9ghMuzh1KzZvCkiAxTq+1TR2eSqw5E5AVWfmCtECFkVZBP6uUJZ8YjwLqXheI+rnjqPy7sVM4Fyg==} + deprecated: 'WalletConnect''s v1 SDKs are now deprecated. Please upgrade to a v2 SDK. For details see: https://docs.walletconnect.com/' + '@walletconnect/types@2.21.0': resolution: {integrity: sha512-ll+9upzqt95ZBWcfkOszXZkfnpbJJ2CmxMfGgE5GmhdxxxCcO5bGhXkI+x8OpiS555RJ/v/sXJYMSOLkmu4fFw==} '@walletconnect/types@2.21.1': resolution: {integrity: sha512-UeefNadqP6IyfwWC1Yi7ux+ljbP2R66PLfDrDm8izmvlPmYlqRerJWJvYO4t0Vvr9wrG4Ko7E0c4M7FaPKT/sQ==} + '@walletconnect/types@2.23.9': + resolution: {integrity: sha512-IUl1PpD/Dig8IE2OZ9XtjbPohEyOZJ73xs92EDUzoIyzRtfm36g2D340pY3iu3AAdLv1yFiaZafB8Hf8RFze8A==} + '@walletconnect/universal-provider@2.21.0': resolution: {integrity: sha512-mtUQvewt+X0VBQay/xOJBvxsB3Xsm1lTwFjZ6WUwSOTR1X+FNb71hSApnV5kbsdDIpYPXeQUbGt2se1n5E5UBg==} deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' @@ -4985,15 +5647,27 @@ packages: resolution: {integrity: sha512-Wjx9G8gUHVMnYfxtasC9poGm8QMiPCpXpbbLFT+iPoQskDDly8BwueWnqKs4Mx2SdIAWAwuXeZ5ojk5qQOxJJg==} deprecated: 'Reliability and performance improvements. See: https://github.com/WalletConnect/walletconnect-monorepo/releases' + '@walletconnect/utils@1.8.0': + resolution: {integrity: sha512-zExzp8Mj1YiAIBfKNm5u622oNw44WOESzo6hj+Q3apSMIb0Jph9X3GDIdbZmvVZsNPxWDL7uodKgZcCInZv2vA==} + '@walletconnect/utils@2.21.0': resolution: {integrity: sha512-zfHLiUoBrQ8rP57HTPXW7rQMnYxYI4gT9yTACxVW6LhIFROTF6/ytm5SKNoIvi4a5nX5dfXG4D9XwQUCu8Ilig==} '@walletconnect/utils@2.21.1': resolution: {integrity: sha512-VPZvTcrNQCkbGOjFRbC24mm/pzbRMUq2DSQoiHlhh0X1U7ZhuIrzVtAoKsrzu6rqjz0EEtGxCr3K1TGRqDG4NA==} + '@walletconnect/utils@2.23.9': + resolution: {integrity: sha512-C5TltCs8UPypNiteYnKSv8+ZDK2EjVDyXCxN6kA9bkA+j6KGsNIV7l9MUA8WBAvE5Gi5EcBdhD3R9Hpo/1HHqQ==} + + '@walletconnect/window-getters@1.0.0': + resolution: {integrity: sha512-xB0SQsLaleIYIkSsl43vm8EwETpBzJ2gnzk7e0wMF3ktqiTGS6TFHxcprMl5R44KKh4tCcHCJwolMCaDSwtAaA==} + '@walletconnect/window-getters@1.0.1': resolution: {integrity: sha512-vHp+HqzGxORPAN8gY03qnbTMnhqIwjeRJNOMOAzePRg4xVEEE2WvYsI9G2NMjOknA8hnuYbU3/hwLcKbjhc8+Q==} + '@walletconnect/window-metadata@1.0.0': + resolution: {integrity: sha512-9eFvmJxIKCC3YWOL97SgRkKhlyGXkrHwamfechmqszbypFspaSk+t2jQXAEU7YClHF6Qjw5eYOmy1//zFi9/GA==} + '@walletconnect/window-metadata@1.0.1': resolution: {integrity: sha512-9koTqyGrM2cqFRW517BPY/iEtUDx2r1+Pwwu5m7sJ7ka79wi3EyqhqcICk/yDmv6jAS1rjKgTKXlEhanYjijcA==} @@ -5019,17 +5693,6 @@ packages: zod: optional: true - abitype@1.1.0: - resolution: {integrity: sha512-6Vh4HcRxNMLA0puzPjM5GBgT4aAcFGKZzSgAXvuZ27shJP6NEpielTuqbBmZILR5/xd0PizkBGy5hReKz9jl5A==} - peerDependencies: - typescript: '>=5.0.4' - zod: ^3.22.0 || ^4.0.0 - peerDependenciesMeta: - typescript: - optional: true - zod: - optional: true - abitype@1.2.3: resolution: {integrity: sha512-Ofer5QUnuUdTFsBRwARMoWKOH1ND5ehwYhJ3OJ/BQO+StkwQjHw0XyVh4vDttzHB7QOFhPHa/o413PJ82gU/Tg==} peerDependencies: @@ -5041,6 +5704,10 @@ packages: zod: optional: true + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + abstract-logging@2.0.1: resolution: {integrity: sha512-2BjRTZxTPvheOvGbBslFSYOUkr+SjPtOnrLP33f+VIWLzezQpZcqVg7ja3L4dBXmzzgwT+a029jRx5PCi3JuiA==} @@ -5062,9 +5729,6 @@ packages: engines: {node: '>=0.4.0'} hasBin: true - aes-js@4.0.0-beta.5: - resolution: {integrity: sha512-G965FqalsNyrPqgEGON7nIx1e/OVENSgiEIzyC63haUMuvNnwIgIjMs52hlTCKhkBny7A2ORNlfY9Zu+jmGk1Q==} - agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} @@ -5087,6 +5751,21 @@ packages: ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + algo-msgpack-with-bigint@2.1.1: + resolution: {integrity: sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==} + engines: {node: '>= 10'} + + algorand-msgpack@1.1.0: + resolution: {integrity: sha512-08k7pBQnkaUB5p+jL7f1TRaUIlTSDE0cesFu1mD7llLao+1cAhtvvZmGE3OnisTd0xOn118QMw74SRqddqaYvw==} + engines: {node: '>= 14'} + + algosdk@3.5.2: + resolution: {integrity: sha512-frhGtZl1JvfrLRKmMvUm880wj4OiWsWo2FhbreNWh7pdFsKuWPj60fV682wt/CYefLI70iwHavPOwGBkTVt0VA==} + engines: {node: '>=18.0.0'} + + anser@1.4.10: + resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} @@ -5099,14 +5778,26 @@ packages: resolution: {integrity: sha512-TKY5pyBkHyADOPYlRT9Lx6F544mPl0vS5Ew7BJ45hA08Q+t3GjbueLliBWN3sMICk6+y7HdyxSzC4bWS8baBdg==} engines: {node: '>=12'} + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + ansi-styles@6.2.1: resolution: {integrity: sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==} engines: {node: '>=12'} + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} @@ -5170,6 +5861,13 @@ packages: resolution: {integrity: sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==} engines: {node: '>= 0.4'} + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + + asn1js@3.0.6: + resolution: {integrity: sha512-UOCGPYbl0tv8+006qks/dTgV9ajs97X2p0FAbyS2iyCRrmLSRolDaHdp+v/CLgnzHc3fVB+CwYiUmei7ndFcgA==} + engines: {node: '>=12.0.0'} + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} @@ -5232,6 +5930,9 @@ packages: peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 + babel-plugin-syntax-hermes-parser@0.33.3: + resolution: {integrity: sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA==} + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} @@ -5252,9 +5953,6 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - big.js@6.2.2: resolution: {integrity: sha512-y/ie+Faknx7sZA5MfGA2xKlu0GDv8RWrXGsmlteyJQ2lvoKv9GBK/fpRMc2qlSoBAgNxrixICFCBefIq8WCQpQ==} @@ -5262,14 +5960,29 @@ packages: resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} engines: {node: '>= 10.0.0'} + bignumber.js@9.1.1: + resolution: {integrity: sha512-pHm4LsMJ6lzgNGVfZHjMoO8sdoRhOzOH4MLmY65Jg70bpxCKu5iOHNJyfF6OyvYw7t8Fpf35RuzUyqnQsj8Vig==} + bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - bn.js@5.2.2: - resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} + blakejs@1.2.1: + resolution: {integrity: sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==} + + bn.js@4.11.8: + resolution: {integrity: sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==} + + bn.js@4.12.3: + resolution: {integrity: sha512-fGTi3gxV/23FTYdAoUtLYp6qySe2KE3teyZitipKNRuVYcBkoP/bB3guXN/XVKUe9mxCHXnc9C4ocyz8OmgN0g==} + + bn.js@5.2.1: + resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + + bn.js@5.2.3: + resolution: {integrity: sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==} body-parser@1.20.3: resolution: {integrity: sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==} @@ -5285,6 +5998,9 @@ packages: borsh@0.7.0: resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} + bowser@2.11.0: + resolution: {integrity: sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==} + bowser@2.12.1: resolution: {integrity: sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==} @@ -5298,6 +6014,9 @@ packages: resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} engines: {node: '>=8'} + brorand@1.1.0: + resolution: {integrity: sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==} + browserslist@4.25.4: resolution: {integrity: sha512-4jYpcjabC606xJ3kw2QwGEZKX0Aw7sgQdZCvIK9dhVSPh76BKo+C+btT1RRofH7B+8iNpEbgGNVWiLki5q93yg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -5309,6 +6028,12 @@ packages: bs58@6.0.0: resolution: {integrity: sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==} + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} @@ -5391,6 +6116,17 @@ packages: resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} engines: {node: '>= 14.16.0'} + chrome-launcher@0.15.2: + resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} + engines: {node: '>=12.13.0'} + hasBin: true + + chromium-edge-launcher@0.3.0: + resolution: {integrity: sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==} + + ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + ci-info@3.9.0: resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} engines: {node: '>=8'} @@ -5401,6 +6137,10 @@ packages: cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + clone-response@1.0.3: resolution: {integrity: sha512-ROoL94jJH2dUVML2Y/5PEDNaSHgeOdSDicUyS7izcF63G6sTc/FTjLub4b8Il9S8S0beOfYt0TaA5qvFK+w0wA==} @@ -5419,6 +6159,9 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + colorette@2.0.20: + resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} @@ -5463,6 +6206,10 @@ packages: confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} + consola@3.4.2: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} @@ -5540,6 +6287,9 @@ packages: crypt@0.0.2: resolution: {integrity: sha512-mCxBlsHFYh9C+HVpiEacem8FEBnMXgU9gy4zmNC+SXAZNB/1idgp/aulFJ4FgCi7GPEVbfyng092GqL2k2rmow==} + crypto-js@4.2.0: + resolution: {integrity: sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==} + css-select@5.2.2: resolution: {integrity: sha512-TizTzUddG/xYLA3NXodFM0fSbNizXjOKhqiQQwvhlspadZokn1KDy0NZFS0wuEubIYAV5/c1/lAr0TaaFXEXzw==} @@ -5577,10 +6327,6 @@ packages: resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} engines: {node: '>=18'} - data-urls@6.0.0: - resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} - engines: {node: '>=20'} - data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} @@ -5600,6 +6346,9 @@ packages: resolution: {integrity: sha512-fnULvOpxnC5/Vg3NCiWelDsLiUc9bRwAPs/+LfTLNvetFCtCTN+yQz15C/fs4AwX1R9K5GLtLfn8QW+dWisaAw==} engines: {node: '>=0.11'} + dateformat@4.6.3: + resolution: {integrity: sha512-2P0p0pFGzHS5EMnhdxQi7aJN+iMheud0UhG4dlE1DLAlvL8JHjJJTX/CSm4JXwV0Ka5nGk3zC5mcb5bUQUxxMA==} + dayjs@1.11.13: resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} @@ -5724,6 +6473,9 @@ packages: resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + detect-browser@5.2.0: + resolution: {integrity: sha512-tr7XntDAu50BVENgQfajMLzacmSe34D+qZc4zjnniz0ZVuw/TZcLcyxHQjYpJTM36sGEkZZlYLnIM1hH7alTMA==} + detect-browser@5.3.0: resolution: {integrity: sha512-53rsFbGdwMwlF7qvCt0ypLM5V5/Mbl0szB7GPN8y9NCcbknYOeVVXdrXEq+90IwAfrrzt6Hd+u2E2ntakICU8w==} @@ -5762,6 +6514,10 @@ packages: dot-case@3.0.4: resolution: {integrity: sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==} + dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} + engines: {node: '>=12'} + dotenv@8.6.0: resolution: {integrity: sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g==} engines: {node: '>=10'} @@ -5786,6 +6542,9 @@ packages: electron-to-chromium@1.5.214: resolution: {integrity: sha512-TpvUNdha+X3ybfU78NoQatKvQEm1oq3lf2QbnmCEdw+Bd9RuIAY+hJTvq1avzHM0f7EJfnH3vbCnbzKzisc/9Q==} + elliptic@6.6.1: + resolution: {integrity: sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==} + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -5832,6 +6591,9 @@ packages: error-ex@1.3.2: resolution: {integrity: sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==} + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + es-abstract@1.24.0: resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} engines: {node: '>= 0.4'} @@ -5870,14 +6632,22 @@ packages: es-toolkit@1.33.0: resolution: {integrity: sha512-X13Q/ZSc+vsO1q600bvNK4bxgXMkHcf//RxCmYDaRY5DAcT+eoXjY5hoAPGMdRnWQjvyLEcyauG3b6hz76LNqg==} + es-toolkit@1.44.0: + resolution: {integrity: sha512-6penXeZalaV88MM3cGkFZZfOoLGWshWWfdy0tWw/RlVVyhvMaWSBTOvXNeiW3e5FwdS5ePW0LGEu17zT139ktg==} + es6-promise@4.2.8: resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} es6-promisify@5.0.0: resolution: {integrity: sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==} - esbuild@0.25.9: - resolution: {integrity: sha512-CRbODhYyQx3qp7ZEwzxOk4JBqmD/seJrzPa/cGjY1VtIn5E09Oi9/dB4JwctnfZ8Q8iT7rioVv5k/FNT/uf54g==} + esbuild@0.25.12: + resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} engines: {node: '>=18'} hasBin: true @@ -6057,9 +6827,9 @@ packages: ethereum-cryptography@2.2.1: resolution: {integrity: sha512-r/W8lkHSiTLxUxW8Rf3u4HGB0xQweG2RyETjywylKZSzLWoWAijRz8WCuOtJ6wah+avllXBqZuk29HCCvhEIRg==} - ethers@6.16.0: - resolution: {integrity: sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==} - engines: {node: '>=14.0.0'} + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} eventemitter2@6.4.9: resolution: {integrity: sha512-JEPTiaOt9f04oa6NOkc4aH+nVp5I3wEjpHbIPqfgCdD5v5bUzy7xQqwcVO2aDQgOWhI28da57HksMrzK9HlRxg==} @@ -6067,6 +6837,9 @@ packages: eventemitter3@5.0.1: resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} + events@3.3.0: resolution: {integrity: sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==} engines: {node: '>=0.8.x'} @@ -6087,6 +6860,9 @@ packages: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + express-rate-limit@8.2.1: resolution: {integrity: sha512-PCZEIEIxqwhzw4KF0n7QF4QqruVTcF73O5kFKUnGOyjbCCgizBBiFaYpd/fnBLUMPw/BWw9OsiN7GgrNYr7j6g==} engines: {node: '>= 16'} @@ -6112,6 +6888,12 @@ packages: resolution: {integrity: sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==} engines: {node: '> 0.1.90'} + fast-base64-decode@1.0.0: + resolution: {integrity: sha512-qwaScUgUGBYeDNRnbc/KyllVU88Jk1pRHPStuF/lO7B0/RTRLj7U0lkdTAutlBblY08rwZDff6tNU9cjv6j//Q==} + + fast-copy@3.0.2: + resolution: {integrity: sha512-dl0O9Vhju8IrcLndv2eU4ldt1ftXMqqfgN4H1cpmGV7P6jeB9FwpN9a2c8DPGE1Ys88rNUJVYDHq73CGAGOPfQ==} + fast-decode-uri-component@1.0.1: resolution: {integrity: sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==} @@ -6157,12 +6939,20 @@ packages: fastestsmallesttextencoderdecoder@1.0.22: resolution: {integrity: sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==} - fastify@5.8.2: - resolution: {integrity: sha512-lZmt3navvZG915IE+f7/TIVamxIwmBd+OMB+O9WBzcpIwOo6F0LTh0sluoMFk5VkrKTvvrwIaoJPkir4Z+jtAg==} + fastify@5.8.4: + resolution: {integrity: sha512-sa42J1xylbBAYUWALSBoyXKPDUvM3OoNOibIefA+Oha57FryXKKCZarA1iDntOCWp3O35voZLuDg2mdODXtPzQ==} fastq@1.19.1: resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fb-dotslash@0.5.8: + resolution: {integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==} + engines: {node: '>=20'} + hasBin: true + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} @@ -6190,6 +6980,10 @@ packages: resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==} engines: {node: '>=0.10.0'} + finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + finalhandler@1.3.1: resolution: {integrity: sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==} engines: {node: '>= 0.8'} @@ -6220,6 +7014,9 @@ packages: flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flow-enums-runtime@0.0.6: + resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + follow-redirects@1.15.11: resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} engines: {node: '>=4.0'} @@ -6237,6 +7034,10 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} + forge-light@1.1.4: + resolution: {integrity: sha512-Nr0xdu93LJawgBZVU/tC+A+4pbKqigdY5PRBz8CXNm4e5saAZIqU2Qe9+nVFtVO5TWCHSgvI0LaZZuatgE5J1g==} + engines: {node: '>= 6.13.0'} + form-data@4.0.4: resolution: {integrity: sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==} engines: {node: '>= 6'} @@ -6398,16 +7199,37 @@ packages: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} + hash.js@1.1.7: + resolution: {integrity: sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==} + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} + help-me@5.0.0: + resolution: {integrity: sha512-7xgomUX6ADmcYzFik0HzAxh/73YlKR9bmFzf51CZwR+b6YtzU2m0u49hQCqV6SvlqIqsaxovfwdvbnsw3b/zpg==} + + hermes-compiler@250829098.0.10: + resolution: {integrity: sha512-TcRlZ0/TlyfJqquRFAWoyElVNnkdYRi/sEp4/Qy8/GYxjg8j2cS9D4MjuaQ+qimkmLN7AmO+44IznRf06mAr0w==} + hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + hermes-estree@0.33.3: + resolution: {integrity: sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==} + hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + hermes-parser@0.33.3: + resolution: {integrity: sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==} + + hi-base32@0.5.1: + resolution: {integrity: sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==} + + hmac-drbg@1.0.1: + resolution: {integrity: sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==} + hono@4.10.7: resolution: {integrity: sha512-icXIITfw/07Q88nLSkB9aiUrd8rYzSweK681Kjo/TSggaGbOX4RRyxxm71v+3PC8C/j+4rlxGeoTRxQDkaJkUw==} engines: {node: '>=16.9.0'} @@ -6420,10 +7242,6 @@ packages: resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} engines: {node: '>=18'} - html-encoding-sniffer@6.0.0: - resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - http-cache-semantics@4.2.0: resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} @@ -6483,6 +7301,11 @@ packages: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} + image-size@1.2.1: + resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} + engines: {node: '>=16.x'} + hasBin: true + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} @@ -6498,6 +7321,9 @@ packages: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + ip-address@10.0.1: resolution: {integrity: sha512-NWv9YLW4PoW2B7xtzaS3NCot75m6nK7Icdv0o3lfMceJVRfSoQwqD4wEH5rLwoKJwUiZ/rfpiVBhnaF0FK4HoA==} engines: {node: '>= 12'} @@ -6558,6 +7384,11 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -6640,6 +7471,9 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} + is-typedarray@1.0.0: + resolution: {integrity: sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -6656,6 +7490,10 @@ packages: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + isarray@1.0.0: resolution: {integrity: sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==} @@ -6692,6 +7530,22 @@ packages: engines: {node: '>=8'} hasBin: true + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true @@ -6699,9 +7553,6 @@ packages: jose@5.10.0: resolution: {integrity: sha512-s+3Al/p9g32Iq+oqXxkW//7jk2Vig6FF1CFqzVXoTUXt2qz89YWbL+OwS17NFYEvxC35n0FKeGO2LGYSxeM2Gg==} - jose@6.1.0: - resolution: {integrity: sha512-TTQJyoEoKcC1lscpVDCSsVgYzUDg/0Bt3WE//WiTPK6uOCQC2KZS4MpugbMWt/zyjkopgZoXhZuCi00gLudfUA==} - jose@6.1.3: resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} @@ -6709,9 +7560,24 @@ packages: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} + js-base64@3.7.4: + resolution: {integrity: sha512-wpM/wi20Tl+3ifTyi0RdDckS4YTD4Lf953mBRrpG8547T7hInHNPEj8+ck4gB8VDcGyeAWFK++Wb/fU1BeavKQ==} + + js-base64@3.7.7: + resolution: {integrity: sha512-7rCnleh0z2CkXhH67J8K1Ytz0b2Y+yxTPL+/KOJoa20hfnVQ/3/T6W/KflYI4bRHRagNeXeU2bkNGI3v1oS/lw==} + js-base64@3.7.8: resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} + js-sha256@0.9.0: + resolution: {integrity: sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==} + + js-sha3@0.8.0: + resolution: {integrity: sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==} + + js-sha512@0.8.0: + resolution: {integrity: sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} @@ -6730,6 +7596,9 @@ packages: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true + jsc-safe-url@0.2.4: + resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==} + jsdoc-type-pratt-parser@4.1.0: resolution: {integrity: sha512-Hicd6JK5Njt2QB6XYFS7ok9e37O8AYk3jTcppG4YVQnYjOemymvTcmc7OWsmq/Qqj5TdRFO5/x/tIPmBeRtGHg==} engines: {node: '>=12.0.0'} @@ -6743,15 +7612,6 @@ packages: canvas: optional: true - jsdom@27.4.0: - resolution: {integrity: sha512-mjzqwWRD9Y1J1KUi7W97Gja1bwOOM5Ug0EZ6UDK3xS7j7mndrkwozHtSblfomlzyB4NepioNt+B2sOSzczVgtQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - peerDependencies: - canvas: ^3.0.0 - peerDependenciesMeta: - canvas: - optional: true - jsesc@3.0.2: resolution: {integrity: sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==} engines: {node: '>=6'} @@ -6762,6 +7622,9 @@ packages: engines: {node: '>=6'} hasBin: true + json-bigint@1.0.0: + resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} @@ -6830,6 +7693,10 @@ packages: resolution: {integrity: sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==} engines: {node: '>=0.10'} + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} @@ -6837,6 +7704,9 @@ packages: light-my-request@6.6.0: resolution: {integrity: sha512-CHYbu8RtboSIoVsHZ6Ye4cj4Aw/yg2oAFimlF7mNvfDV192LR7nDiKtSIfCuLT7KokPSTn/9kfVLm5OGN0A28A==} + lighthouse-logger@1.4.2: + resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} + lightningcss-android-arm64@1.30.2: resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} engines: {node: '>= 12.0.0'} @@ -6872,24 +7742,28 @@ packages: engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [glibc] lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [glibc] lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} @@ -6935,6 +7809,9 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + lodash.camelcase@4.3.0: + resolution: {integrity: sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==} + lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} @@ -6947,9 +7824,15 @@ packages: lodash.startcase@4.4.0: resolution: {integrity: sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==} + lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + lodash@4.17.21: resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + long@5.3.1: + resolution: {integrity: sha512-ka87Jz3gcx/I7Hal94xaN2tZEOPoUOEVftkQqZx2EeQRN7LGdfLlI3FvZ+7WDplm+vK2Urx9ULrvSowtdCieng==} + loose-envify@1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -6983,12 +7866,21 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lute-connect@1.7.0: + resolution: {integrity: sha512-/eXb2/c/xltKyVEVWchd1QZB6F0fvgXwVIqXDQWeJ9unPo0kMMbtuLkeb1v4Kr1lffxX8uGnb+8kAMYjczUASg==} + magic-string@0.30.18: resolution: {integrity: sha512-yi8swmWbO17qHhwIBNeeZxTceJMeBvWJaId6dyvTSOwTipqeHhMhOrz6513r1sOKnpvQ7zkhlG8tPrpilwTxHQ==} magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + marky@1.3.0: + resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -7013,6 +7905,9 @@ packages: resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} engines: {node: '>= 0.8'} + memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} + merge-descriptors@1.0.3: resolution: {integrity: sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==} @@ -7020,6 +7915,9 @@ packages: resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} engines: {node: '>=18'} + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -7028,11 +7926,69 @@ packages: resolution: {integrity: sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==} engines: {node: '>= 0.6'} - micro-ftch@0.3.1: - resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} + metro-babel-transformer@0.84.2: + resolution: {integrity: sha512-UZqjh1VMRDm0WasifM0aN+JreCn3CW0BaPoZgDXb0xOMFSF9dKZJsKhcrpzkjL1+qwmHFYjlhGiQ+tvXdSx+OQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} - micromatch@4.0.8: - resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + metro-cache-key@0.84.2: + resolution: {integrity: sha512-+yJxLYu5nhKp7jZD6wtx4dMoSqLzK6MeYVkjMaUgjuh2Lu8DwGrxRnbmIVnn5Z9AQOs/K4eOWmuD7N2p64UCMw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-cache@0.84.2: + resolution: {integrity: sha512-jPX2fwOc/MmP2KRScSg2jFtVN9BTd+QN6j/3qZ+HIbEAsePLONozbKR2kCIBGvVeBTe7js48WXziI4+AdfwfFQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-config@0.84.2: + resolution: {integrity: sha512-ze7IgJwLJoXoTxeXW86xqqKoxXjE0gZg5w8kW2mawaWLSfuvI0KgVaaERXgoVuWl+DQU2q22tIeAEdsCyUZvBQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-core@0.84.2: + resolution: {integrity: sha512-s9Ko372nzfbu5Y2uhWDlB/g3E6mba3Es95QzF/8IwNM4ynZgqM9rfnU0PR54onGvDGDfj44jbooSxaA1D09rDA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-file-map@0.84.2: + resolution: {integrity: sha512-ZgX1lXO9YJCgTY6OSuwvRcHdhXjAFd1DdYC4g2B+d7yAtLUW1/OqwTLpW6ixl1zqZDDQSDSYZXDsN7DL2IumBw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-minify-terser@0.84.2: + resolution: {integrity: sha512-1TNGPN4oUose+XSHsdDUvcvPHQxKP5lZNbiS6UteTXX+6zFNu+IzxqSokyrDoj9BSjVbdClrB3okuI+Fpls3LA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-resolver@0.84.2: + resolution: {integrity: sha512-2i6OQJIv18+olvLnmcM20uhi1T729+25izZozqOugSaV0YGzMV/EXkYFqxkXC9iNsantGcI/w9PgaI89wLK6JQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-runtime@0.84.2: + resolution: {integrity: sha512-NzzORY2+mmN3tLhsZ7N4GDOBERusalyM1o1k36euulUIEe8UkDhwzcsRexvxKaSkrGLiRQ9PYDLp9uxPkQ+A0Q==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-source-map@0.84.2: + resolution: {integrity: sha512-m6rRVBefzaAyn6dBk5GOabVchCQ3VIS1/MhCj61dJB5cqLOOx34BV3DRFwnDBkuPw2RR/LUoul0U1sixlS9VQg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-symbolicate@0.84.2: + resolution: {integrity: sha512-o0RY49012YcGE1E4GsZtgzFCBPeoxlASzIsD5CNOTmAoKDIroHfTFFiYCGPLCGwRwQjMaCChhoH0TZCjAyyCKA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + + metro-transform-plugins@0.84.2: + resolution: {integrity: sha512-/821YLQv4PgD1NOruzPkr0r3HDALXqwCEECewyEQZ5hmSb8jzf1VdEpf3F8fx8zI4/5dHY/rARDVVuHCEb/Xrg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-transform-worker@0.84.2: + resolution: {integrity: sha512-aR09svo3WC7OTYk5YB0VY0iSXOGrPdfmQWIxG8ADD2cKf/B95VR+y4GgVUbqB31buNvgtU+iCx9186i/YaNGlw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro@0.84.2: + resolution: {integrity: sha512-Qw7sl+e34cf/0LYEvDfVPiWvXmkvpuVgFqjzhPCc9Mw30NsvRFYZEH6I9zEHlpjugIveV+Jzdqt3YSPMU+Hx/w==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + + micro-ftch@0.3.1: + resolution: {integrity: sha512-/0LLxhzP0tfiR5hcQebtudP56gUurs2CLkGarnCiB/OqEyUFQ6U3paQi/tgLv0hBJYt2rnr9MNpxz4fiiugstg==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} engines: {node: '>=8.6'} mime-db@1.52.0: @@ -7064,6 +8020,12 @@ packages: resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} engines: {node: '>=10'} + minimalistic-assert@1.0.1: + resolution: {integrity: sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==} + + minimalistic-crypto-utils@1.0.1: + resolution: {integrity: sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==} + minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} @@ -7086,6 +8048,11 @@ packages: typescript: optional: true + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + mlly@1.8.0: resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} @@ -7192,6 +8159,9 @@ packages: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + node-mock-http@1.0.2: resolution: {integrity: sha512-zWaamgDUdo9SSLw47we78+zYw/bDr5gH8pH7oRRs8V3KmBtu8GLgGIbV2p/gRPd3LWpEOpjQj7X1FOU3VFMJ8g==} @@ -7209,9 +8179,16 @@ packages: nth-check@2.1.1: resolution: {integrity: sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==} + nullthrows@1.1.1: + resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} + nwsapi@2.2.21: resolution: {integrity: sha512-o6nIY3qwiSXl7/LuOU0Dmuctd34Yay0yeuZRLFmDPrrdHpXKFndPj3hM+YEPVHYC5fx2otBx4Ilc/gyYSAUaIA==} + ob1@0.84.2: + resolution: {integrity: sha512-JID0ti8tDRQZJdQ3l+UeVAsKP+dW5Ucmktes/J9FwqP5KarafoTMqWvw4LRKrMtA7yWT3r/+E2w5wapd89GToA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + obj-multiplex@1.0.0: resolution: {integrity: sha512-0GNJAOsHoBHeNTvl5Vt6IWnpUEcc3uSRxzBri7EDyIcMgYvnY2JL2qdeV5zTMjWQX5OHcD5amcW2HFfDh0gjIA==} @@ -7257,6 +8234,10 @@ packages: resolution: {integrity: sha512-0eJJY6hXLGf1udHwfNftBqH+g73EU4B504nZeKpz1sYRKafAghwxEJunB2O7rDZkL4PGfsMVnTXZ2EjibbqcsA==} engines: {node: '>=14.0.0'} + on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -7264,6 +8245,10 @@ packages: once@1.4.0: resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + open@7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} + openapi-fetch@0.13.8: resolution: {integrity: sha512-yJ4QKRyNxE44baQ9mY5+r/kAzZ8yXMemtNAOFwOzRXJscdjSxxzWSNlyBAr+o5JjkUw9Lc3W7OIoca0cY3PYnQ==} @@ -7281,8 +8266,8 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} - ox@0.11.3: - resolution: {integrity: sha512-1bWYGk/xZel3xro3l8WGg6eq4YEKlaqvyMtVhfMFpbJzK2F6rj4EDRtqDCWVEJMkzcmEi9uW2QxsqELokOlarw==} + ox@0.14.20: + resolution: {integrity: sha512-rby38C3nDn8eQkf29Zgw4hkCZJ64Qqi0zRPWL8ENUQ7JVuoITqrVtwWQgM/He19SCMUEc7hS/Sjw0jIOSLJhOw==} peerDependencies: typescript: '>=5.4.0' peerDependenciesMeta: @@ -7329,14 +8314,6 @@ packages: typescript: optional: true - ox@0.9.6: - resolution: {integrity: sha512-8SuCbHPvv2eZLYXrNmC0EC12rdzXQLdhnOMlHDW2wiCPLxBrOOJwX5L5E61by+UjTPOryqQiRSnjIKCI+GykKg==} - peerDependencies: - typescript: '>=5.4.0' - peerDependenciesMeta: - typescript: - optional: true - p-cancelable@2.1.1: resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==} engines: {node: '>=8'} @@ -7392,9 +8369,6 @@ packages: parse5@7.3.0: resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - parse5@8.0.0: - resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} - parseurl@1.3.3: resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} engines: {node: '>= 0.8'} @@ -7457,15 +8431,30 @@ packages: pino-abstract-transport@0.5.0: resolution: {integrity: sha512-+KAgmVeqXYbTtU2FScx1XS3kNyfZ5TrXY07V96QnUSFqo2gAqlvmaxH67Lj7SWazqsMabf+58ctdTcBgnOLUOQ==} + pino-abstract-transport@2.0.0: + resolution: {integrity: sha512-F63x5tizV6WCh4R6RHyi2Ml+M70DNRXt/+HANowMflpgGFMAym/VKm6G7ZOQRjqN7XbGxK1Lg9t6ZrtzOaivMw==} + pino-abstract-transport@3.0.0: resolution: {integrity: sha512-wlfUczU+n7Hy/Ha5j9a/gZNy7We5+cXp8YL+X+PG8S0KXxw7n/JXA3c46Y0zQznIJ83URJiwy7Lh56WLokNuxg==} + pino-pretty@13.0.0: + resolution: {integrity: sha512-cQBBIVG3YajgoUjo1FdKVRX6t9XPxwB9lcNJVD5GCnNM4Y6T12YYx8c6zEejxQsU0wrg9TwmDulcE9LR7qcJqA==} + hasBin: true + pino-std-serializers@4.0.0: resolution: {integrity: sha512-cK0pekc1Kjy5w9V2/n+8MkZwusa6EyyxfeQCB799CQRhRt/CqYKiWs5adeu8Shve2ZNffvfC/7J64A2PJo1W/Q==} pino-std-serializers@7.1.0: resolution: {integrity: sha512-BndPH67/JxGExRgiX1dX0w1FvZck5Wa4aal9198SrRhZjH3GxKQUKIBnYJTdj2HDN3UQAS06HlfcSbQj2OHmaw==} + pino@10.0.0: + resolution: {integrity: sha512-eI9pKwWEix40kfvSzqEP6ldqOoBIN7dwD/o91TY5z8vQI12sAffpR/pOqAD1IVVwIVHDpHjkq0joBPdJD0rafA==} + hasBin: true + + pino@10.1.0: + resolution: {integrity: sha512-0zZC2ygfdqvqK8zJIr1e+wT1T/L+LF6qvqvbzEQ6tiMAoTqEVK9a1K3YRu8HEUvGEvNqZyPJTtb2sNIoTkB83w==} + hasBin: true + pino@10.3.1: resolution: {integrity: sha512-r34yH/GlQpKZbU1BvFFqOjhISRo1MNx1tWYsYvmj6KIRHSPMT2+yHOEb1SG6NMvRoHRF0a07kCOox/9yakl1vg==} hasBin: true @@ -7561,8 +8550,8 @@ packages: preact@10.24.2: resolution: {integrity: sha512-1cSoF0aCC8uaARATfrlz4VCBqE8LwZwRfLgkxJOQwAlQt6ayTmi0D9OF7nXid1POI5SZidFuG9CnlXbDfLqY/Q==} - preact@10.27.2: - resolution: {integrity: sha512-5SYSgFKSyhCbk6SrXyMpqjb5+MQBgfvEKE/OC+PujcY34sOpqtr+0AZQtPYx5IA6VxynQ7rUPCtKzyovpj9Bpg==} + preact@10.29.1: + resolution: {integrity: sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} @@ -7582,6 +8571,10 @@ packages: engines: {node: '>=14'} hasBin: true + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + process-nextick-args@2.0.1: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} @@ -7594,9 +8587,16 @@ packages: process-warning@5.0.0: resolution: {integrity: sha512-a39t9ApHNx2L4+HBnQKqxxHNs1r7KF+Intd8Q/g1bUh6q0WIp9voPXJ/x0j+ZL45KF1pJd9+q2jLIRMfvEshkA==} + promise@8.3.0: + resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + prop-types@15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} + protobufjs@7.5.4: + resolution: {integrity: sha512-CvexbZtbov6jW2eXAvLukXjXUW1TzFaivC46BpWc/3BpcCysb5Vffu+B3XHMm8lVEuy2Mm4XGex8hBSg1yapPg==} + engines: {node: '>=12.0.0'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -7610,10 +8610,26 @@ packages: pump@3.0.3: resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} + pump@3.0.4: + resolution: {integrity: sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pvtsutils@1.3.6: + resolution: {integrity: sha512-PLgQXQ6H2FWCaeRak8vvk1GW462lMxB5s3Jm673N82zI4vqtVUPuZdffdZbPDFRoU8kAhItWFtPCWiPpp4/EDg==} + + pvutils@1.1.5: + resolution: {integrity: sha512-KTqnxsgGiQ6ZAzZCVlJH5eOjSnvlyEgx1m8bkRJfOhmGRqfo5KLvmAlACQkrjEtOQ4B7wF9TdSLIs9O90MX9xA==} + engines: {node: '>=16.0.0'} + + qr-code-styling@1.6.0-rc.1: + resolution: {integrity: sha512-ModRIiW6oUnsP18QzrRYZSc/CFKFKIdj7pUs57AEVH20ajlglRpN3HukjHk0UbNMTlKGuaYl7Gt6/O5Gg2NU2Q==} + + qrcode-generator@1.5.2: + resolution: {integrity: sha512-pItrW0Z9HnDBnFmgiNrY1uxRdri32Uh9EjNYLPVC2zZ3ZRIIEqBoDgm4DkvDwNNDHTK7FNkmr8zAa77BYc9xNw==} + qrcode@1.5.3: resolution: {integrity: sha512-puyri6ApkEHYiVl4CFzo1tDkAZ+ATcnbJrJ6RiBM1Fhctdn/ix9MTE3hRph33omisEbC/2fcfemsseiKgBPKZg==} engines: {node: '>=10.13.0'} @@ -7635,6 +8651,10 @@ packages: quansync@0.2.11: resolution: {integrity: sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==} + query-string@6.13.5: + resolution: {integrity: sha512-svk3xg9qHR39P3JlHuD7g3nRnyay5mHbrPctEBDUxUkHRifPHXJDhBUycdCC0NBjXoDf44Gb+IsOZL1Uwn8M/Q==} + engines: {node: '>=6'} + query-string@7.1.3: resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==} engines: {node: '>=6'} @@ -7642,6 +8662,9 @@ packages: queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + quick-format-unescaped@4.0.4: resolution: {integrity: sha512-tYC1Q1hgyRuHgloV/YXs2w15unPVh8qfu/qCTfhTYamaw7fyhumKa2yGpdSo87vY32rIclj+4fWYQXUMs9EHvg==} @@ -7667,6 +8690,9 @@ packages: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} + react-devtools-core@6.1.5: + resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} + react-dom@19.2.1: resolution: {integrity: sha512-ibrK8llX2a4eOskq1mXKu/TGZj9qzomO+sNfO98M6d9zIPOEhlBkMkBUBLd1vgS0gQsLDBzA+8jJBVXDnfHmJg==} peerDependencies: @@ -7680,6 +8706,32 @@ packages: react-is@16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-native-get-random-values@1.11.0: + resolution: {integrity: sha512-4BTbDbRmS7iPdhYLRcz3PGFIpFJBwNZg9g42iwa2P6FOv9vZj/xJc678RZXnLNZzd0qd7Q3CCF6Yd+CU2eoXKQ==} + peerDependencies: + react-native: '>=0.56' + + react-native@0.85.0: + resolution: {integrity: sha512-z2ltUAS9xzdL4HQeG7wpsYMv2o35R4D8qZwbXu0SbeamZ4+ZIBxc84Ay4Vb6fRExBpsT06aZFV+W030W9JxDFQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + peerDependencies: + '@react-native/jest-preset': 0.85.0 + '@types/react': ^19.1.1 + react: ^19.2.3 + peerDependenciesMeta: + '@react-native/jest-preset': + optional: true + '@types/react': + optional: true + + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + react@19.2.1: resolution: {integrity: sha512-DGrYcCWK7tvYMnWh79yrPHt+vdx9tY+1gPZa7nJQtO/p8bLTDaHp4dzwEhQB7pZ4Xe3ok4XKuEPrVuc+wlpkmw==} engines: {node: '>=0.10.0'} @@ -7722,6 +8774,9 @@ packages: regenerate@1.4.2: resolution: {integrity: sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==} + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} @@ -7782,6 +8837,9 @@ packages: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + rfc4648@1.5.3: + resolution: {integrity: sha512-MjOWxM065+WswwnmNONOT+bD1nXzY9Km6u3kzvnx8F8/HXGZdz3T6e6vZJ8Q/RIMUSp/nxqjH3GwvJDy8ijeQQ==} + rfdc@1.4.1: resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} @@ -7821,8 +8879,9 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} - safe-regex2@5.0.0: - resolution: {integrity: sha512-YwJwe5a51WlK7KbOJREPdjNrpViQBI3p4T50lfwPuDhZnE3XGVTlGvi+aolc5+RvxDD6bnUmjVsU9n1eboLUYw==} + safe-regex2@5.1.0: + resolution: {integrity: sha512-pNHAuBW7TrcleFHsxBr5QMi/Iyp0ENjUKz7GCcX1UO7cMh+NmVK6HxQckNL1tJp1XAJVjG6B8OKIPqodqj9rtw==} + hasBin: true safe-stable-stringify@2.5.0: resolution: {integrity: sha512-b3rppTKm9T+PsVCBEOUR46GWI7fdOs00VKZ1+9c1EWDaDMvjQc6tUwuFyIprgGgTcWoVHSKrU8H31ZHA2e0RHA==} @@ -7838,6 +8897,9 @@ packages: scheduler@0.27.0: resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + secure-json-parse@2.7.0: + resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} + secure-json-parse@4.1.0: resolution: {integrity: sha512-l4KnYfEyqYJxDwlNVyRfO2E4NTHfMKAWdUuA8J0yve2Dz/E/PdBepY03RvyJpssIpRFwJoCD55wA+mEDs6ByWA==} @@ -7855,6 +8917,11 @@ packages: engines: {node: '>=10'} hasBin: true + semver@7.7.4: + resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} + engines: {node: '>=10'} + hasBin: true + send@0.19.0: resolution: {integrity: sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==} engines: {node: '>= 0.8.0'} @@ -7863,6 +8930,10 @@ packages: resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} + serialize-error@2.1.0: + resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} + engines: {node: '>=0.10.0'} + serve-static@1.16.2: resolution: {integrity: sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==} engines: {node: '>= 0.8.0'} @@ -7909,6 +8980,10 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + side-channel-list@1.0.0: resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} engines: {node: '>= 0.4'} @@ -7932,15 +9007,13 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - siwe@2.3.2: - resolution: {integrity: sha512-aSf+6+Latyttbj5nMu6GF3doMfv2UYj83hhwZgUF20ky6fTS83uVhkQABdIVnEuS8y1bBdk7p6ltb9SmlhTTlA==} - peerDependencies: - ethers: ^5.6.8 || ^6.0.8 - slash@3.0.0: resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} engines: {node: '>=8'} + slow-redact@0.3.2: + resolution: {integrity: sha512-MseHyi2+E/hBRqdOi5COy6wZ7j7DxXRz9NkseavNYSvvWC06D8a5cidVZX3tcG5eCW3NIyVU4zT63hw0Q486jw==} + snake-case@3.0.4: resolution: {integrity: sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==} @@ -7962,11 +9035,25 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + source-map@0.8.0-beta.0: resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} engines: {node: '>= 8'} deprecated: The work that was done in this beta branch won't be included in future versions + spark-md5@3.0.2: + resolution: {integrity: sha512-wcFzz9cDfbuqe0FZzfi2or1sgyIrsDwmPwfZC4hiNidPdPINjeUwNfv5kldczoEAcjl9Y1L3SM7Uz2PUEQzxQw==} + spawndamnit@3.0.1: resolution: {integrity: sha512-MmnduQUuHCoFckZoWnXsTg7JaiLBJrKFj9UI2MbRPGaJeVpsLcVBu6P/IGZovziM/YBsellCmsprgNA+w0CzVg==} @@ -7996,6 +9083,17 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + + stacktrace-parser@0.1.11: + resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} + engines: {node: '>=6'} + + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} @@ -8069,6 +9167,10 @@ packages: resolution: {integrity: sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==} engines: {node: '>=12'} + strip-ansi@7.1.2: + resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + engines: {node: '>=12'} + strip-bom@3.0.0: resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} engines: {node: '>=4'} @@ -8110,6 +9212,10 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -8143,6 +9249,11 @@ packages: resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==} engines: {node: '>=8'} + terser@5.46.1: + resolution: {integrity: sha512-vzCjQO/rgUuK9sf8VJZvjqiqiHFaZLnOiimmUuOKODxWL8mm/xua7viT7aqX7dgPY60otQjUotzFMmCB4VdmqQ==} + engines: {node: '>=10'} + hasBin: true + text-encoding-utf-8@1.0.2: resolution: {integrity: sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==} @@ -8156,10 +9267,16 @@ packages: thread-stream@0.15.2: resolution: {integrity: sha512-UkEhKIg2pD+fjkHQKyJO3yoIvAP3N6RlNFt2dUhcS1FGvCD1cQa1M/PGknCLFIyZdtJOWQjejp7bdNqmN7zwdA==} + thread-stream@3.1.0: + resolution: {integrity: sha512-OqyPZ9u96VohAyMfJykzmivOrY2wfMSf3C5TtFJVgN+Hm6aj+voFhlK+kZEIv2FBh1X6Xp3DlnCOfEQ3B2J86A==} + thread-stream@4.0.0: resolution: {integrity: sha512-4iMVL6HAINXWf1ZKZjIPcz5wYaOdPhtO8ATvZ+Xqp3BTdaqtAwQkNmKORqcIo5YkQqGXq5cwfswDwMqqQNrpJA==} engines: {node: '>=20'} + throat@5.0.0: + resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + tinybench@2.9.0: resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} @@ -8189,19 +9306,15 @@ packages: tldts-core@6.1.86: resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} - tldts-core@7.0.19: - resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} - tldts@6.1.86: resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} hasBin: true - tldts@7.0.19: - resolution: {integrity: sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==} - hasBin: true + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} - to-buffer@1.2.1: - resolution: {integrity: sha512-tB82LpAIWjhLYbqjx3X4zEeHN6M8CiuOEy2JY8SEQVdYRe3CCHOFaqrBW1doLDrfpWhplcW7BL+bO3/6S3pcDQ==} + to-buffer@1.2.2: + resolution: {integrity: sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==} engines: {node: '>= 0.4'} to-regex-range@5.0.1: @@ -8223,10 +9336,6 @@ packages: resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} engines: {node: '>=16'} - tough-cookie@6.0.0: - resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} - engines: {node: '>=16'} - tr46@0.0.3: resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} @@ -8237,10 +9346,6 @@ packages: resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} engines: {node: '>=18'} - tr46@6.0.0: - resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} - engines: {node: '>=20'} - tree-kill@1.2.2: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true @@ -8270,9 +9375,6 @@ packages: tslib@1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} - tslib@2.7.0: - resolution: {integrity: sha512-gLXCKdN1/j47AiHiOkJN69hJmcbGTHI0ImLmbYLHykhgeN0jVGola9yVjFgzCUklsZQMW55o+dW7IXv3RCXDzA==} - tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -8295,8 +9397,8 @@ packages: typescript: optional: true - tsx@4.20.5: - resolution: {integrity: sha512-+wKjMNU9w/EaQayHXb7WA7ZaHY6hN8WgfvHNQ3t1PnU91/7O8TcTnIhCDYTZwnt8JsO9IBqZ30Ln1r7pPF52Aw==} + tsx@4.21.0: + resolution: {integrity: sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw==} engines: {node: '>=18.0.0'} hasBin: true @@ -8334,6 +9436,9 @@ packages: resolution: {integrity: sha512-gxToHmi9oTBNB05UjUsrWf0OyN5ZXtD0apOarC1KIx232Vp3WimRNy3810QzeNSgyD5rsaIDXlxlbnOzlouo+w==} hasBin: true + tweetnacl-ts@1.0.3: + resolution: {integrity: sha512-C5I/dWf6xjAXaCDlf84T4HvozU/8ycAlq5WRllF1hAeeq5390tfXD+bNas5bhEV0HMSOx8bsQYpLjPl8wfnEeQ==} + tweetnacl@1.0.3: resolution: {integrity: sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==} @@ -8341,6 +9446,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + type-is@1.6.18: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} @@ -8365,6 +9474,9 @@ packages: resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} engines: {node: '>= 0.4'} + typedarray-to-buffer@3.1.5: + resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} + typescript-eslint@8.49.0: resolution: {integrity: sha512-zRSVH1WXD0uXczCXw+nsdjGPUdx4dfrs5VQoHnUWmv1U3oNlAKv4FUNdLDhVUg+gYn+a5hUESqch//Rv5wVhrg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -8383,6 +9495,9 @@ packages: uint8arrays@3.1.0: resolution: {integrity: sha512-ei5rfKtoRO8OyOIor2Rz5fhzjThwIHJZ3uyDPnDHTXbP0aMQ1RN/6AI5B5d9dBxJOU+BvOAk7ZQ1xphsX8Lrog==} + uint8arrays@3.1.1: + resolution: {integrity: sha512-+QJa8QRnbdXVpHYjLoTpJIdCTiw9Ir62nocClWuXIq2JIh4Uta0cQsTSpFL678p2CN8B+XSApwcU+pQEqVpKWg==} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -8390,15 +9505,9 @@ packages: uncrypto@0.1.3: resolution: {integrity: sha512-Ql87qFHB3s/De2ClA9e0gsnS6zXG27SkTiSJwjCc9MebbfapQfuPzumMIUMi38ezPZVNFcHI9sUIepeQfw8J8Q==} - undici-types@6.19.8: - resolution: {integrity: sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==} - undici-types@6.21.0: resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} - undici-types@7.22.0: resolution: {integrity: sha512-RKZvifiL60xdsIuC80UY0dq8Z7DbJUV8/l2hOVbyZAxBzEeQU4Z58+4ZzJ6WN2Lidi9KzT5EbiGX+PI/UGYuRw==} @@ -8517,6 +9626,9 @@ packages: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} + utf8@3.0.0: + resolution: {integrity: sha512-E8VjFIQ/TyQgp+TZfS6l8yp/xWppSAHzidGiRrqe4bK4XP9pTRyKFgGJpO3SN7zdX4DeomTrwaseCHovfpFcqQ==} + util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} @@ -8535,9 +9647,6 @@ packages: resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==} hasBin: true - valid-url@1.0.9: - resolution: {integrity: sha512-QQDsV8OnSf5Uc30CKSwG9lnhMPe6exHtTXLRYX8uMwKENy640pU+2BgBL0LRbDh/eYRahNCS7aewCx0wf3NYVA==} - valtio@1.13.2: resolution: {integrity: sha512-Qik0o+DSy741TmkqmRfjq+0xpZBXi/Y6+fXZLn0xNF1z/waFMbE3rkivv5Zcf9RrMUp6zswf2J7sbh2KBlba5A==} engines: {node: '>=12.20.0'} @@ -8562,24 +9671,8 @@ packages: typescript: optional: true - viem@2.37.3: - resolution: {integrity: sha512-hwoZqkFSy13GCFzIftgfIH8hNENvdlcHIvtLt73w91tL6rKmZjQisXWTahi1Vn5of8/JQ1FBKfwUus3YkDXwbw==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - - viem@2.40.3: - resolution: {integrity: sha512-feYfEpbgjRkZYQpwcgxqkWzjxHI5LSDAjcGetHHwDRuX9BRQHUdV8ohrCosCYpdEhus/RknD3/bOd4qLYVPPuA==} - peerDependencies: - typescript: '>=5.0.4' - peerDependenciesMeta: - typescript: - optional: true - - viem@2.45.1: - resolution: {integrity: sha512-LN6Pp7vSfv50LgwhkfSbIXftAM5J89lP9x8TeDa8QM7o41IxlHrDh0F9X+FfnCWtsz11pEVV5sn+yBUoOHNqYA==} + viem@2.48.11: + resolution: {integrity: sha512-+WZ5E0dBS6GtKb+1wEk5DeYRRRW42+pFnXCo67Ydodf42sBwO+hu3wnQy66lc4MKmHz+llPVdbyehYr9oTE2iw==} peerDependencies: typescript: '>=5.0.4' peerDependenciesMeta: @@ -8667,6 +9760,12 @@ packages: jsdom: optional: true + vlq@1.0.1: + resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + + vlq@2.0.4: + resolution: {integrity: sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==} + w3c-xmlserializer@5.0.0: resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} engines: {node: '>=18'} @@ -8693,6 +9792,9 @@ packages: typescript: optional: true + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + webextension-polyfill@0.10.0: resolution: {integrity: sha512-c5s35LgVa5tFaHhrZDnr3FpQpjj1BB+RXhLTYUxGqBVN460HkbM8TBtEqdXWbpTKfzwCcjAZVF7zXCYSKtcp9g==} @@ -8706,15 +9808,14 @@ packages: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} - webidl-conversions@8.0.1: - resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} - engines: {node: '>=20'} - whatwg-encoding@3.1.1: resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} engines: {node: '>=18'} deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation + whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + whatwg-mimetype@4.0.0: resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} engines: {node: '>=18'} @@ -8723,10 +9824,6 @@ packages: resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} engines: {node: '>=18'} - whatwg-url@15.1.0: - resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} - engines: {node: '>=20'} - whatwg-url@5.0.0: resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} @@ -8793,6 +9890,18 @@ packages: utf-8-validate: optional: true + ws@7.5.3: + resolution: {integrity: sha512-kQ/dHIzuLrS6Je9+uv81ueZomEwH0qVYstcAQ4/Z93K8zeko9gtAbttJWzoC5ukqXY1PpoouV3+VSOqEAFt5wg==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + ws@8.17.1: resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} engines: {node: '>=10.0.0'} @@ -8829,8 +9938,8 @@ packages: utf-8-validate: optional: true - ws@8.19.0: - resolution: {integrity: sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg==} + ws@8.20.0: + resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -8862,6 +9971,10 @@ packages: y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} @@ -8874,10 +9987,18 @@ packages: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + yargs@15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} engines: {node: '>=8'} + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} @@ -8940,12 +10061,30 @@ packages: snapshots: - '@acemir/cssom@0.9.30': - optional: true + '@adraffy/ens-normalize@1.11.1': {} - '@adraffy/ens-normalize@1.10.1': {} + '@algorandfoundation/algokit-utils@10.0.0-alpha.46': + dependencies: + '@algorandfoundation/xhd-wallet-api': 2.0.0-canary.1 + '@noble/curves': 2.0.1 + '@noble/ed25519': 3.0.0 + '@noble/hashes': 2.0.1 + algorand-msgpack: 1.1.0 + buffer: 6.0.3 + dotenv: 16.6.1 + hi-base32: 0.5.1 + json-bigint: 1.0.0 + tweetnacl: 1.0.3 + vlq: 2.0.4 - '@adraffy/ens-normalize@1.11.0': {} + '@algorandfoundation/xhd-wallet-api@2.0.0-canary.1': + dependencies: + '@noble/ciphers': 2.1.1 + '@noble/curves': 2.0.1 + '@noble/hashes': 2.0.1 + ajv: 8.17.1 + algo-msgpack-with-bigint: 2.1.1 + bn.js: 5.2.3 '@alloc/quick-lru@5.2.0': {} @@ -8985,24 +10124,18 @@ snapshots: '@csstools/css-tokenizer': 3.0.4 lru-cache: 11.2.4 - '@asamuzakjp/dom-selector@6.7.6': - dependencies: - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.1.0 - is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.4 - optional: true - - '@asamuzakjp/nwsapi@2.3.9': - optional: true - '@babel/code-frame@7.27.1': dependencies: '@babel/helper-validator-identifier': 7.27.1 js-tokens: 4.0.0 picocolors: 1.1.1 + '@babel/code-frame@7.29.0': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + '@babel/compat-data@7.28.0': {} '@babel/core@7.28.3': @@ -9033,6 +10166,14 @@ snapshots: '@jridgewell/trace-mapping': 0.3.30 jsesc: 3.1.0 + '@babel/generator@7.29.1': + dependencies: + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.27.3': dependencies: '@babel/types': 7.28.2 @@ -9136,6 +10277,8 @@ snapshots: '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.27.1': {} '@babel/helper-wrap-function@7.28.3': @@ -9155,6 +10298,10 @@ snapshots: dependencies: '@babel/types': 7.28.2 + '@babel/parser@7.29.2': + dependencies: + '@babel/types': 7.29.0 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.3)': dependencies: '@babel/core': 7.28.3 @@ -9712,6 +10859,12 @@ snapshots: '@babel/parser': 7.28.3 '@babel/types': 7.28.2 + '@babel/template@7.28.6': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + '@babel/traverse@7.28.3': dependencies: '@babel/code-frame': 7.27.1 @@ -9724,11 +10877,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.29.0': + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/generator': 7.29.1 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/types': 7.29.0 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@babel/types@7.28.2': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@babel/types@7.29.0': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@base-org/account@1.1.1(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@noble/hashes': 1.4.0 @@ -9737,7 +10907,27 @@ snapshots: idb-keyval: 6.2.1 ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) preact: 10.24.2 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + + '@base-org/account@1.1.1(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.9.2)(zod@4.1.13) + preact: 10.24.2 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) zustand: 5.0.3(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) transitivePeerDependencies: - '@types/react' @@ -9757,7 +10947,7 @@ snapshots: idb-keyval: 6.2.1 ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) preact: 10.24.2 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zustand: 5.0.3(@types/react@19.1.12)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) transitivePeerDependencies: - '@types/react' @@ -9778,7 +10968,31 @@ snapshots: idb-keyval: 6.2.1 ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) preact: 10.24.2 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - debug + - encoding + - fastestsmallesttextencoderdecoder + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + + '@base-org/account@2.4.0(@types/react@19.1.12)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + '@coinbase/cdp-sdk': 1.36.1(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.9.2)(zod@4.1.13) + preact: 10.24.2 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) zustand: 5.0.3(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) transitivePeerDependencies: - '@types/react' @@ -9793,6 +11007,19 @@ snapshots: - utf-8-validate - zod + '@blockshake/defly-connect@1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@likecoin/qr-code-styling': 1.6.6 + '@walletconnect/client': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/types': 1.8.0 + algosdk: 3.5.2 + bowser: 2.11.0 + buffer: 6.0.3 + lottie-web: 5.13.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@changesets/apply-release-plan@7.0.14': dependencies: '@changesets/config': 3.1.2 @@ -9830,7 +11057,7 @@ snapshots: transitivePeerDependencies: - encoding - '@changesets/cli@2.29.8(@types/node@22.18.0)': + '@changesets/cli@2.29.8(@types/node@22.19.17)': dependencies: '@changesets/apply-release-plan': 7.0.14 '@changesets/assemble-release-plan': 6.0.9 @@ -9846,7 +11073,7 @@ snapshots: '@changesets/should-skip-package': 0.1.2 '@changesets/types': 6.1.0 '@changesets/write': 0.4.0 - '@inquirer/external-editor': 1.0.3(@types/node@22.18.0) + '@inquirer/external-editor': 1.0.3(@types/node@22.19.17) '@manypkg/get-packages': 1.1.3 ansi-colors: 4.1.3 ci-info: 3.9.0 @@ -9959,10 +11186,10 @@ snapshots: abitype: 1.0.6(typescript@5.9.2)(zod@3.25.76) axios: 1.11.0 axios-retry: 4.5.0(axios@1.11.0) - jose: 6.1.0 + jose: 6.1.3 md5: 2.3.0 uncrypto: 0.1.3 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zod: 3.25.76 transitivePeerDependencies: - bufferutil @@ -9972,12 +11199,12 @@ snapshots: - typescript - utf-8-validate - '@coinbase/onchainkit@0.38.19(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.1(react@19.2.1))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76)': + '@coinbase/onchainkit@0.38.19(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-dom@19.2.1(react@19.2.1))(react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@farcaster/frame-sdk': 0.1.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@farcaster/miniapp-wagmi-connector': 1.0.0(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@farcaster/miniapp-wagmi-connector': 1.0.0(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@tanstack/react-query': 5.90.11(react@19.2.1) - '@wagmi/core': 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/core': 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) clsx: 2.1.1 graphql: 16.11.0 graphql-request: 6.1.0(graphql@16.11.0) @@ -9985,8 +11212,8 @@ snapshots: react: 19.2.1 react-dom: 19.2.1(react@19.2.1) tailwind-merge: 2.6.0 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10))(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -10027,14 +11254,14 @@ snapshots: '@coinbase/wallet-sdk@3.9.3': dependencies: - bn.js: 5.2.2 + bn.js: 5.2.3 buffer: 6.0.3 clsx: 1.2.1 eth-block-tracker: 7.1.0 eth-json-rpc-filters: 6.0.1 - eventemitter3: 5.0.1 + eventemitter3: 5.0.4 keccak: 3.0.4 - preact: 10.27.2 + preact: 10.29.1 sha.js: 2.4.12 transitivePeerDependencies: - supports-color @@ -10047,7 +11274,7 @@ snapshots: idb-keyval: 6.2.1 ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) preact: 10.24.2 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zustand: 5.0.3(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) transitivePeerDependencies: - '@types/react' @@ -10059,16 +11286,16 @@ snapshots: - utf-8-validate - zod - '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@3.25.76)': + '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@noble/hashes': 1.4.0 clsx: 1.2.1 eventemitter3: 5.0.1 idb-keyval: 6.2.1 - ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) + ox: 0.6.9(typescript@5.9.2)(zod@4.1.13) preact: 10.24.2 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - zustand: 5.0.3(@types/react@19.1.12)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + zustand: 5.0.3(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) transitivePeerDependencies: - '@types/react' - bufferutil @@ -10079,11 +11306,31 @@ snapshots: - utf-8-validate - zod - '@craftamap/esbuild-plugin-html@0.9.0(bufferutil@4.0.9)(esbuild@0.25.9)(utf-8-validate@5.0.10)': + '@coinbase/wallet-sdk@4.3.6(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - esbuild: 0.25.9 - jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - lodash: 4.17.21 + '@noble/hashes': 1.4.0 + clsx: 1.2.1 + eventemitter3: 5.0.1 + idb-keyval: 6.2.1 + ox: 0.6.9(typescript@5.9.2)(zod@3.25.76) + preact: 10.24.2 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + zustand: 5.0.3(@types/react@19.1.12)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) + transitivePeerDependencies: + - '@types/react' + - bufferutil + - immer + - react + - typescript + - use-sync-external-store + - utf-8-validate + - zod + + '@craftamap/esbuild-plugin-html@0.9.0(bufferutil@4.0.9)(esbuild@0.27.7)(utf-8-validate@5.0.10)': + dependencies: + esbuild: 0.27.7 + jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + lodash: 4.17.21 transitivePeerDependencies: - bufferutil - canvas @@ -10140,87 +11387,165 @@ snapshots: '@es-joy/jsdoccomment@0.50.2': dependencies: '@types/estree': 1.0.8 - '@typescript-eslint/types': 8.49.0 + '@typescript-eslint/types': 8.42.0 comment-parser: 1.4.1 esquery: 1.6.0 jsdoc-type-pratt-parser: 4.1.0 - '@esbuild/aix-ppc64@0.25.9': + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.25.12': optional: true - '@esbuild/android-arm64@0.25.9': + '@esbuild/linux-ppc64@0.27.7': optional: true - '@esbuild/android-arm@0.25.9': + '@esbuild/linux-riscv64@0.25.12': optional: true - '@esbuild/android-x64@0.25.9': + '@esbuild/linux-riscv64@0.27.7': optional: true - '@esbuild/darwin-arm64@0.25.9': + '@esbuild/linux-s390x@0.25.12': optional: true - '@esbuild/darwin-x64@0.25.9': + '@esbuild/linux-s390x@0.27.7': optional: true - '@esbuild/freebsd-arm64@0.25.9': + '@esbuild/linux-x64@0.25.12': optional: true - '@esbuild/freebsd-x64@0.25.9': + '@esbuild/linux-x64@0.27.7': optional: true - '@esbuild/linux-arm64@0.25.9': + '@esbuild/netbsd-arm64@0.25.12': optional: true - '@esbuild/linux-arm@0.25.9': + '@esbuild/netbsd-arm64@0.27.7': optional: true - '@esbuild/linux-ia32@0.25.9': + '@esbuild/netbsd-x64@0.25.12': optional: true - '@esbuild/linux-loong64@0.25.9': + '@esbuild/netbsd-x64@0.27.7': optional: true - '@esbuild/linux-mips64el@0.25.9': + '@esbuild/openbsd-arm64@0.25.12': optional: true - '@esbuild/linux-ppc64@0.25.9': + '@esbuild/openbsd-arm64@0.27.7': optional: true - '@esbuild/linux-riscv64@0.25.9': + '@esbuild/openbsd-x64@0.25.12': optional: true - '@esbuild/linux-s390x@0.25.9': + '@esbuild/openbsd-x64@0.27.7': optional: true - '@esbuild/linux-x64@0.25.9': + '@esbuild/openharmony-arm64@0.25.12': optional: true - '@esbuild/netbsd-arm64@0.25.9': + '@esbuild/openharmony-arm64@0.27.7': optional: true - '@esbuild/netbsd-x64@0.25.9': + '@esbuild/sunos-x64@0.25.12': optional: true - '@esbuild/openbsd-arm64@0.25.9': + '@esbuild/sunos-x64@0.27.7': optional: true - '@esbuild/openbsd-x64@0.25.9': + '@esbuild/win32-arm64@0.25.12': optional: true - '@esbuild/openharmony-arm64@0.25.9': + '@esbuild/win32-arm64@0.27.7': optional: true - '@esbuild/sunos-x64@0.25.9': + '@esbuild/win32-ia32@0.25.12': optional: true - '@esbuild/win32-arm64@0.25.9': + '@esbuild/win32-ia32@0.27.7': optional: true - '@esbuild/win32-ia32@0.25.9': + '@esbuild/win32-x64@0.25.12': optional: true - '@esbuild/win32-x64@0.25.9': + '@esbuild/win32-x64@0.27.7': optional: true '@eslint-community/eslint-utils@4.8.0(eslint@9.34.0(jiti@2.6.1))': @@ -10233,7 +11558,7 @@ snapshots: '@eslint/config-array@0.21.0': dependencies: '@eslint/object-schema': 2.1.6 - debug: 4.4.3 + debug: 4.4.1 minimatch: 3.1.2 transitivePeerDependencies: - supports-color @@ -10287,8 +11612,130 @@ snapshots: ethereum-cryptography: 2.2.1 micro-ftch: 0.3.1 - '@exodus/bytes@1.8.0': - optional: true + '@ethersproject/abi@5.8.0': + dependencies: + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/hash': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/abstract-provider@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/networks': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/transactions': 5.8.0 + '@ethersproject/web': 5.8.0 + + '@ethersproject/abstract-signer@5.8.0': + dependencies: + '@ethersproject/abstract-provider': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + + '@ethersproject/address@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/rlp': 5.8.0 + + '@ethersproject/base64@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + + '@ethersproject/bignumber@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + bn.js: 5.2.3 + + '@ethersproject/bytes@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/constants@5.8.0': + dependencies: + '@ethersproject/bignumber': 5.8.0 + + '@ethersproject/hash@5.8.0': + dependencies: + '@ethersproject/abstract-signer': 5.8.0 + '@ethersproject/address': 5.8.0 + '@ethersproject/base64': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@ethersproject/keccak256@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + js-sha3: 0.8.0 + + '@ethersproject/logger@5.8.0': {} + + '@ethersproject/networks@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/properties@5.8.0': + dependencies: + '@ethersproject/logger': 5.8.0 + + '@ethersproject/rlp@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/signing-key@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + bn.js: 5.2.3 + elliptic: 6.6.1 + hash.js: 1.1.7 + + '@ethersproject/strings@5.8.0': + dependencies: + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/logger': 5.8.0 + + '@ethersproject/transactions@5.8.0': + dependencies: + '@ethersproject/address': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/constants': 5.8.0 + '@ethersproject/keccak256': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@ethersproject/signing-key': 5.8.0 + + '@ethersproject/web@5.8.0': + dependencies: + '@ethersproject/base64': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/logger': 5.8.0 + '@ethersproject/properties': 5.8.0 + '@ethersproject/strings': 5.8.0 + + '@evanhahn/lottie-web-light@5.8.1': {} '@farcaster/frame-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: @@ -10320,7 +11767,7 @@ snapshots: '@farcaster/miniapp-core': 0.3.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) '@farcaster/quick-auth': 0.0.6(typescript@5.9.2) comlink: 4.4.2 - eventemitter3: 5.0.1 + eventemitter3: 5.0.4 ox: 0.4.4(typescript@5.9.2)(zod@3.25.76) transitivePeerDependencies: - bufferutil @@ -10329,11 +11776,11 @@ snapshots: - utf-8-validate - zod - '@farcaster/miniapp-wagmi-connector@1.0.0(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@farcaster/miniapp-wagmi-connector@1.0.0(@farcaster/miniapp-sdk@0.1.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: '@farcaster/miniapp-sdk': 0.1.9(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@wagmi/core': 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@farcaster/quick-auth@0.0.6(typescript@5.9.2)': dependencies: @@ -10364,35 +11811,35 @@ snapshots: '@fastify/forwarded': 3.0.1 ipaddr.js: 2.3.0 - '@gemini-wallet/core@0.2.0(viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@gemini-wallet/core@0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: '@metamask/rpc-errors': 7.0.2 eventemitter3: 5.0.1 - viem: 2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - supports-color - '@gemini-wallet/core@0.2.0(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@gemini-wallet/core@0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': dependencies: '@metamask/rpc-errors': 7.0.2 eventemitter3: 5.0.1 - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - supports-color - '@gemini-wallet/core@0.3.2(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@gemini-wallet/core@0.3.2(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: '@metamask/rpc-errors': 7.0.2 eventemitter3: 5.0.1 - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - supports-color - '@gemini-wallet/core@0.3.2(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@gemini-wallet/core@0.3.2(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': dependencies: '@metamask/rpc-errors': 7.0.2 eventemitter3: 5.0.1 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - supports-color @@ -10400,10 +11847,81 @@ snapshots: dependencies: graphql: 16.11.0 + '@grpc/grpc-js@1.12.6': + dependencies: + '@grpc/proto-loader': 0.7.15 + '@js-sdsl/ordered-map': 4.4.2 + + '@grpc/proto-loader@0.7.15': + dependencies: + lodash.camelcase: 4.3.0 + long: 5.3.1 + protobufjs: 7.5.4 + yargs: 17.7.2 + '@heroicons/react@2.2.0(react@19.2.3)': dependencies: react: 19.2.3 + '@hiero-ledger/cryptography@1.16.0-beta.3(react-native@0.85.0(@babel/core@7.28.3)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))': + dependencies: + '@noble/curves': 1.8.1 + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + asn1js: 3.0.6 + bignumber.js: 9.1.1 + bn.js: 5.2.1 + buffer: 6.0.3 + crypto-js: 4.2.0 + debug: 4.4.1 + forge-light: 1.1.4 + js-base64: 3.7.7 + react-native-get-random-values: 1.11.0(react-native@0.85.0(@babel/core@7.28.3)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)) + spark-md5: 3.0.2 + strip-ansi: 7.1.2 + tweetnacl: 1.0.3 + utf8: 3.0.0 + transitivePeerDependencies: + - react-native + - supports-color + + '@hiero-ledger/proto@2.26.0-beta.3(ansi-regex@6.2.2)(ansi-styles@6.2.3)(debug@4.4.1)(protobufjs@7.5.4)(strip-ansi@7.1.2)': + dependencies: + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + debug: 4.4.1 + long: 5.3.1 + protobufjs: 7.5.4 + strip-ansi: 7.1.2 + + '@hiero-ledger/sdk@2.80.0(bn.js@5.2.1)(react-native@0.85.0(@babel/core@7.28.3)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))': + dependencies: + '@ethersproject/abi': 5.8.0 + '@ethersproject/bignumber': 5.8.0 + '@ethersproject/bytes': 5.8.0 + '@ethersproject/rlp': 5.8.0 + '@grpc/grpc-js': 1.12.6 + '@hiero-ledger/cryptography': 1.16.0-beta.3(react-native@0.85.0(@babel/core@7.28.3)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)) + '@hiero-ledger/proto': 2.26.0-beta.3(ansi-regex@6.2.2)(ansi-styles@6.2.3)(debug@4.4.1)(protobufjs@7.5.4)(strip-ansi@7.1.2) + ansi-regex: 6.2.2 + ansi-styles: 6.2.3 + bignumber.js: 9.1.1 + bn.js: 5.2.1 + crypto-js: 4.2.0 + debug: 4.4.1 + js-base64: 3.7.4 + long: 5.3.1 + pino: 10.1.0 + pino-pretty: 13.0.0 + protobufjs: 7.5.4 + rfc4648: 1.5.3 + strip-ansi: 7.1.2 + utf8: 3.0.0 + transitivePeerDependencies: + - expo-crypto + - react-native + - supports-color + '@hono/node-server@1.19.1(hono@4.10.7)': dependencies: hono: 4.10.7 @@ -10520,12 +12038,12 @@ snapshots: '@img/sharp-win32-x64@0.34.5': optional: true - '@inquirer/external-editor@1.0.3(@types/node@22.18.0)': + '@inquirer/external-editor@1.0.3(@types/node@22.19.17)': dependencies: chardet: 2.1.1 iconv-lite: 0.7.2 optionalDependencies: - '@types/node': 22.18.0 + '@types/node': 22.19.17 '@isaacs/cliui@8.0.2': dependencies: @@ -10536,6 +12054,21 @@ snapshots: wrap-ansi: 8.1.0 wrap-ansi-cjs: wrap-ansi@7.0.0 + '@isaacs/ttlcache@1.4.1': {} + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.10 + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 22.19.17 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + '@jridgewell/gen-mapping@0.3.13': dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -10548,6 +12081,11 @@ snapshots: '@jridgewell/resolve-uri@3.1.2': {} + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.30 + '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.30': @@ -10555,6 +12093,12 @@ snapshots: '@jridgewell/resolve-uri': 3.1.2 '@jridgewell/sourcemap-codec': 1.5.5 + '@js-sdsl/ordered-map@4.4.2': {} + + '@likecoin/qr-code-styling@1.6.6': + dependencies: + qrcode-generator: 1.5.2 + '@lit-labs/ssr-dom-shim@1.4.0': {} '@lit/reactive-element@2.1.1': @@ -10760,12 +12304,12 @@ snapshots: '@metamask/superstruct': 3.2.1 '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 - '@types/debug': 4.1.12 + '@types/debug': 4.1.13 '@types/lodash': 4.17.20 debug: 4.4.3 lodash: 4.17.21 pony-cause: 2.1.11 - semver: 7.7.3 + semver: 7.7.4 uuid: 9.0.1 transitivePeerDependencies: - supports-color @@ -10773,9 +12317,9 @@ snapshots: '@metamask/utils@5.0.2': dependencies: '@ethereumjs/tx': 4.2.0 - '@types/debug': 4.1.12 + '@types/debug': 4.1.13 debug: 4.4.3 - semver: 7.7.3 + semver: 7.7.4 superstruct: 1.0.4 transitivePeerDependencies: - supports-color @@ -10786,10 +12330,10 @@ snapshots: '@metamask/superstruct': 3.2.1 '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 - '@types/debug': 4.1.12 + '@types/debug': 4.1.13 debug: 4.4.3 pony-cause: 2.1.11 - semver: 7.7.3 + semver: 7.7.4 uuid: 9.0.1 transitivePeerDependencies: - supports-color @@ -10800,10 +12344,10 @@ snapshots: '@metamask/superstruct': 3.2.1 '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 - '@types/debug': 4.1.12 + '@types/debug': 4.1.13 debug: 4.4.3 pony-cause: 2.1.11 - semver: 7.7.3 + semver: 7.7.4 uuid: 9.0.1 transitivePeerDependencies: - supports-color @@ -10830,6 +12374,8 @@ snapshots: transitivePeerDependencies: - supports-color + '@msgpack/msgpack@3.1.3': {} + '@napi-rs/wasm-runtime@0.2.12': dependencies: '@emnapi/core': 1.5.0 @@ -10867,13 +12413,13 @@ snapshots: '@next/swc-win32-x64-msvc@16.0.10': optional: true + '@noble/ciphers@1.2.0': {} + '@noble/ciphers@1.2.1': {} '@noble/ciphers@1.3.0': {} - '@noble/curves@1.2.0': - dependencies: - '@noble/hashes': 1.3.2 + '@noble/ciphers@2.1.1': {} '@noble/curves@1.4.2': dependencies: @@ -10895,7 +12441,11 @@ snapshots: dependencies: '@noble/hashes': 1.8.0 - '@noble/hashes@1.3.2': {} + '@noble/curves@2.0.1': + dependencies: + '@noble/hashes': 2.0.1 + + '@noble/ed25519@3.0.0': {} '@noble/hashes@1.4.0': {} @@ -10905,6 +12455,8 @@ snapshots: '@noble/hashes@1.8.0': {} + '@noble/hashes@2.0.1': {} + '@nodelib/fs.scandir@2.1.5': dependencies: '@nodelib/fs.stat': 2.0.5 @@ -10921,6 +12473,20 @@ snapshots: '@paulmillr/qr@0.2.1': {} + '@perawallet/connect@1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@evanhahn/lottie-web-light': 5.8.1 + '@walletconnect/client': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/types': 1.8.0 + algosdk: 3.5.2 + bowser: 2.11.0 + buffer: 6.0.3 + qr-code-styling: 1.6.0-rc.1 + tweetnacl-ts: 1.0.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@pinojs/redact@0.4.0': {} '@pkgjs/parseargs@0.11.0': @@ -10928,11 +12494,112 @@ snapshots: '@pkgr/core@0.2.9': {} + '@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': + dependencies: + '@protobufjs/aspromise': 1.1.2 + '@protobufjs/inquire': 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': {} + + '@react-native/assets-registry@0.85.0': {} + + '@react-native/codegen@0.85.0(@babel/core@7.28.3)': + dependencies: + '@babel/core': 7.28.3 + '@babel/parser': 7.29.2 + hermes-parser: 0.33.3 + invariant: 2.2.4 + nullthrows: 1.1.1 + tinyglobby: 0.2.15 + yargs: 17.7.2 + + '@react-native/community-cli-plugin@0.85.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@react-native/dev-middleware': 0.85.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + debug: 4.4.3 + invariant: 2.2.4 + metro: 0.84.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-config: 0.84.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-core: 0.84.2 + semver: 7.7.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/debugger-frontend@0.85.0': {} + + '@react-native/debugger-shell@0.85.0': + dependencies: + cross-spawn: 7.0.6 + debug: 4.4.3 + fb-dotslash: 0.5.8 + transitivePeerDependencies: + - supports-color + + '@react-native/dev-middleware@0.85.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.85.0 + '@react-native/debugger-shell': 0.85.0 + chrome-launcher: 0.15.2 + chromium-edge-launcher: 0.3.0 + connect: 3.7.0 + debug: 4.4.3 + invariant: 2.2.4 + nullthrows: 1.1.1 + open: 7.4.2 + serve-static: 1.16.2 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/gradle-plugin@0.85.0': {} + + '@react-native/js-polyfills@0.85.0': {} + + '@react-native/normalize-colors@0.85.0': {} + + '@react-native/virtualized-lists@0.85.0(@types/react@19.1.12)(react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10))(react@19.2.1)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.2.1 + react-native: 0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10) + optionalDependencies: + '@types/react': 19.1.12 + optional: true + + '@react-native/virtualized-lists@0.85.0(react-native@0.85.0(@babel/core@7.28.3)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.2.3 + react-native: 0.85.0(@babel/core@7.28.3)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10) + '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4)': dependencies: big.js: 6.2.2 dayjs: 1.11.13 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4) transitivePeerDependencies: - bufferutil - typescript @@ -10943,7 +12610,18 @@ snapshots: dependencies: big.js: 6.2.2 dayjs: 1.11.13 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@reown/appkit-common@1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + big.js: 6.2.2 + dayjs: 1.11.13 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - bufferutil - typescript @@ -10956,7 +12634,7 @@ snapshots: '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) '@walletconnect/universal-provider': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) valtio: 1.13.2(@types/react@19.1.12)(react@19.2.1) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -10985,13 +12663,13 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-controllers@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-controllers@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@walletconnect/universal-provider': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - valtio: 1.13.2(@types/react@19.1.12)(react@19.2.3) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/universal-provider': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + valtio: 1.13.2(@types/react@19.1.12)(react@19.2.1) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11020,14 +12698,13 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-pay@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-controllers@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@3.25.76) - lit: 3.3.0 - valtio: 1.13.2(@types/react@19.1.12)(react@19.2.1) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) + '@walletconnect/universal-provider': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + valtio: 1.13.2(@types/react@19.1.12)(react@19.2.3) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11056,14 +12733,14 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-pay@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@reown/appkit-pay@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.3))(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@3.25.76) lit: 3.3.0 - valtio: 1.13.2(@types/react@19.1.12)(react@19.2.3) + valtio: 1.13.2(@types/react@19.1.12)(react@19.2.1) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11092,18 +12769,14 @@ snapshots: - utf-8-validate - zod - '@reown/appkit-polyfills@1.7.8': - dependencies: - buffer: 6.0.3 - - '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@3.25.76)': + '@reown/appkit-pay@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-ui': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@reown/appkit-utils': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@4.1.13) lit: 3.3.0 + valtio: 1.13.2(@types/react@19.1.12)(react@19.2.1) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11130,16 +12803,129 @@ snapshots: - typescript - uploadthing - utf-8-validate - - valtio - zod - '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.3))(zod@3.25.76)': + '@reown/appkit-pay@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-ui': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@reown/appkit-utils': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.3))(zod@3.25.76) - '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) + lit: 3.3.0 + valtio: 1.13.2(@types/react@19.1.12)(react@19.2.3) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-polyfills@1.7.8': + dependencies: + buffer: 6.0.3 + + '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@3.25.76) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) + lit: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - valtio + - zod + + '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@4.1.13)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@4.1.13) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) + lit: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - valtio + - zod + + '@reown/appkit-scaffold-ui@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.3))(zod@3.25.76)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.3))(zod@3.25.76) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) lit: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -11205,6 +12991,41 @@ snapshots: - utf-8-validate - zod + '@reown/appkit-ui@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) + lit: 3.3.0 + qrcode: 1.5.3 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + '@reown/appkit-ui@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) @@ -11249,7 +13070,45 @@ snapshots: '@walletconnect/logger': 2.1.2 '@walletconnect/universal-provider': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) valtio: 1.13.2(@types/react@19.1.12)(react@19.2.1) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit-utils@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@4.1.13)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-polyfills': 1.7.8 + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) + '@walletconnect/logger': 2.1.2 + '@walletconnect/universal-provider': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + valtio: 1.13.2(@types/react@19.1.12)(react@19.2.1) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11287,7 +13146,7 @@ snapshots: '@walletconnect/logger': 2.1.2 '@walletconnect/universal-provider': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) valtio: 1.13.2(@types/react@19.1.12)(react@19.2.3) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11341,7 +13200,50 @@ snapshots: '@walletconnect/universal-provider': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) bs58: 6.0.0 valtio: 1.13.2(@types/react@19.1.12)(react@19.2.1) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@reown/appkit@1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + '@reown/appkit-common': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-controllers': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-pay': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-polyfills': 1.7.8 + '@reown/appkit-scaffold-ui': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@4.1.13) + '@reown/appkit-ui': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@reown/appkit-utils': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1))(zod@4.1.13) + '@reown/appkit-wallet': 1.7.8(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10) + '@walletconnect/types': 2.21.0(@vercel/functions@2.2.13) + '@walletconnect/universal-provider': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + bs58: 6.0.0 + valtio: 1.13.2(@types/react@19.1.12)(react@19.2.1) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11384,7 +13286,7 @@ snapshots: '@walletconnect/universal-provider': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) bs58: 6.0.0 valtio: 1.13.2(@types/react@19.1.12)(react@19.2.3) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -11488,10 +13390,30 @@ snapshots: - utf-8-validate - zod + '@safe-global/safe-apps-provider@0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + events: 3.3.0 + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@safe-global/safe-gateway-typescript-sdk': 3.23.1 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + transitivePeerDependencies: + - bufferutil + - typescript + - utf-8-validate + - zod + + '@safe-global/safe-apps-sdk@9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + '@safe-global/safe-gateway-typescript-sdk': 3.23.1 + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - bufferutil - typescript @@ -11537,17 +13459,30 @@ snapshots: '@noble/hashes': 1.8.0 '@scure/base': 1.2.6 + '@signinwithethereum/siwe-parser@4.1.0': + dependencies: + '@noble/hashes': 1.8.0 + apg-js: 4.4.0 + + '@signinwithethereum/siwe@4.1.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + dependencies: + '@signinwithethereum/siwe-parser': 4.1.0 + optionalDependencies: + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + + '@sinclair/typebox@0.27.10': {} + '@sindresorhus/is@4.6.0': {} '@socket.io/component-emitter@3.1.2': {} - '@solana-program/compute-budget@0.11.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + '@solana-program/compute-budget@0.11.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: - '@solana/kit': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/compute-budget@0.11.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + '@solana-program/compute-budget@0.11.0(@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10))': dependencies: - '@solana/kit': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) '@solana-program/compute-budget@0.8.0(@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10))': dependencies: @@ -11558,27 +13493,27 @@ snapshots: '@solana/kit': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) '@solana/sysvars': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana-program/token-2022@0.6.1(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2))': + '@solana-program/token-2022@0.6.1(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2))': dependencies: - '@solana/kit': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/sysvars': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana-program/token-2022@0.6.1(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2))': + '@solana-program/token-2022@0.6.1(@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10))(@solana/sysvars@6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2))': dependencies: - '@solana/kit': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) '@solana/sysvars': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana-program/token@0.5.1(@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10))': dependencies: '@solana/kit': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) - '@solana-program/token@0.9.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + '@solana-program/token@0.9.0(@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': dependencies: - '@solana/kit': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana-program/token@0.9.0(@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)))': + '@solana-program/token@0.9.0(@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10))': dependencies: - '@solana/kit': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/kit': 6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10) '@solana/accounts@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)': dependencies: @@ -12048,7 +13983,7 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/kit@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/accounts': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -12062,11 +13997,11 @@ snapshots: '@solana/rpc': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/rpc-parsed-types': 5.0.0(typescript@5.9.2) '@solana/rpc-spec-types': 5.0.0(typescript@5.9.2) - '@solana/rpc-subscriptions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/signers': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/sysvars': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-confirmation': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/transaction-confirmation': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/transaction-messages': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/transactions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) typescript: 5.9.2 @@ -12101,34 +14036,7 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/kit@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/accounts': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.1.0(typescript@5.9.2) - '@solana/functional': 5.1.0(typescript@5.9.2) - '@solana/instruction-plans': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/instructions': 5.1.0(typescript@5.9.2) - '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/offchain-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/programs': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-parsed-types': 5.1.0(typescript@5.9.2) - '@solana/rpc-spec-types': 5.1.0(typescript@5.9.2) - '@solana/rpc-subscriptions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/signers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/sysvars': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-confirmation': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - ws - - '@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)': + '@solana/kit@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)': dependencies: '@solana/accounts': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -12505,23 +14413,23 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/rpc-subscriptions-channel-websocket@2.3.0(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions-channel-websocket@2.3.0(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.3.0(typescript@5.9.2) '@solana/functional': 2.3.0(typescript@5.9.2) '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.9.2) '@solana/subscribable': 2.3.0(typescript@5.9.2) typescript: 5.9.2 - ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@solana/rpc-subscriptions-channel-websocket@5.0.0(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions-channel-websocket@5.0.0(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 5.0.0(typescript@5.9.2) '@solana/functional': 5.0.0(typescript@5.9.2) '@solana/rpc-subscriptions-spec': 5.0.0(typescript@5.9.2) '@solana/subscribable': 5.0.0(typescript@5.9.2) typescript: 5.9.2 - ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@solana/rpc-subscriptions-channel-websocket@5.1.0(typescript@5.9.2)(ws@7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: @@ -12533,23 +14441,13 @@ snapshots: optionalDependencies: ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@solana/rpc-subscriptions-channel-websocket@5.1.0(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/errors': 5.1.0(typescript@5.9.2) - '@solana/functional': 5.1.0(typescript@5.9.2) - '@solana/rpc-subscriptions-spec': 5.1.0(typescript@5.9.2) - '@solana/subscribable': 5.1.0(typescript@5.9.2) - typescript: 5.9.2 - optionalDependencies: - ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@solana/rpc-subscriptions-channel-websocket@6.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) '@solana/functional': 6.1.0(typescript@5.9.2) '@solana/rpc-subscriptions-spec': 6.1.0(typescript@5.9.2) '@solana/subscribable': 6.1.0(typescript@5.9.2) - ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -12589,7 +14487,7 @@ snapshots: optionalDependencies: typescript: 5.9.2 - '@solana/rpc-subscriptions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 2.3.0(typescript@5.9.2) '@solana/fast-stable-stringify': 2.3.0(typescript@5.9.2) @@ -12597,7 +14495,7 @@ snapshots: '@solana/promises': 2.3.0(typescript@5.9.2) '@solana/rpc-spec-types': 2.3.0(typescript@5.9.2) '@solana/rpc-subscriptions-api': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions-channel-websocket': 2.3.0(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-channel-websocket': 2.3.0(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/rpc-subscriptions-spec': 2.3.0(typescript@5.9.2) '@solana/rpc-transformers': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -12607,7 +14505,7 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/rpc-subscriptions@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/rpc-subscriptions@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/errors': 5.0.0(typescript@5.9.2) '@solana/fast-stable-stringify': 5.0.0(typescript@5.9.2) @@ -12615,7 +14513,7 @@ snapshots: '@solana/promises': 5.0.0(typescript@5.9.2) '@solana/rpc-spec-types': 5.0.0(typescript@5.9.2) '@solana/rpc-subscriptions-api': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions-channel-websocket': 5.0.0(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions-channel-websocket': 5.0.0(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/rpc-subscriptions-spec': 5.0.0(typescript@5.9.2) '@solana/rpc-transformers': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -12643,24 +14541,6 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/rpc-subscriptions@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/errors': 5.1.0(typescript@5.9.2) - '@solana/fast-stable-stringify': 5.1.0(typescript@5.9.2) - '@solana/functional': 5.1.0(typescript@5.9.2) - '@solana/promises': 5.1.0(typescript@5.9.2) - '@solana/rpc-spec-types': 5.1.0(typescript@5.9.2) - '@solana/rpc-subscriptions-api': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions-channel-websocket': 5.1.0(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-subscriptions-spec': 5.1.0(typescript@5.9.2) - '@solana/rpc-transformers': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/subscribable': 5.1.0(typescript@5.9.2) - typescript: 5.9.2 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - ws - '@solana/rpc-subscriptions@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)': dependencies: '@solana/errors': 6.1.0(typescript@5.9.2) @@ -12732,7 +14612,7 @@ snapshots: '@solana/rpc-spec': 2.3.0(typescript@5.9.2) '@solana/rpc-spec-types': 2.3.0(typescript@5.9.2) typescript: 5.9.2 - undici-types: 7.16.0 + undici-types: 7.22.0 '@solana/rpc-transport-http@5.0.0(typescript@5.9.2)': dependencies: @@ -12740,7 +14620,7 @@ snapshots: '@solana/rpc-spec': 5.0.0(typescript@5.9.2) '@solana/rpc-spec-types': 5.0.0(typescript@5.9.2) typescript: 5.9.2 - undici-types: 7.16.0 + undici-types: 7.22.0 '@solana/rpc-transport-http@5.1.0(typescript@5.9.2)': dependencies: @@ -12748,7 +14628,7 @@ snapshots: '@solana/rpc-spec': 5.1.0(typescript@5.9.2) '@solana/rpc-spec-types': 5.1.0(typescript@5.9.2) typescript: 5.9.2 - undici-types: 7.16.0 + undici-types: 7.22.0 '@solana/rpc-transport-http@6.1.0(typescript@5.9.2)': dependencies: @@ -12997,7 +14877,7 @@ snapshots: transitivePeerDependencies: - fastestsmallesttextencoderdecoder - '@solana/transaction-confirmation@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/transaction-confirmation@2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/addresses': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/codecs-strings': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -13005,7 +14885,7 @@ snapshots: '@solana/keys': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/promises': 2.3.0(typescript@5.9.2) '@solana/rpc': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/rpc-types': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/transaction-messages': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/transactions': 2.3.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -13014,7 +14894,7 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/transaction-confirmation@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': + '@solana/transaction-confirmation@5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': dependencies: '@solana/addresses': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/codecs-strings': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -13022,7 +14902,7 @@ snapshots: '@solana/keys': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/promises': 5.0.0(typescript@5.9.2) '@solana/rpc': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + '@solana/rpc-subscriptions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) '@solana/rpc-types': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/transaction-messages': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) '@solana/transactions': 5.0.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -13048,23 +14928,6 @@ snapshots: - fastestsmallesttextencoderdecoder - ws - '@solana/transaction-confirmation@5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))': - dependencies: - '@solana/addresses': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/codecs-strings': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/errors': 5.1.0(typescript@5.9.2) - '@solana/keys': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/promises': 5.1.0(typescript@5.9.2) - '@solana/rpc': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/rpc-subscriptions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - '@solana/rpc-types': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transaction-messages': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - '@solana/transactions': 5.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) - typescript: 5.9.2 - transitivePeerDependencies: - - fastestsmallesttextencoderdecoder - - ws - '@solana/transaction-confirmation@6.1.0(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2)(utf-8-validate@5.0.10)': dependencies: '@solana/addresses': 6.1.0(fastestsmallesttextencoderdecoder@1.0.22)(typescript@5.9.2) @@ -13231,7 +15094,7 @@ snapshots: '@solana/buffer-layout': 4.0.1 '@solana/codecs-numbers': 2.3.0(typescript@5.9.2) agentkeepalive: 4.6.0 - bn.js: 5.2.2 + bn.js: 5.2.3 borsh: 0.7.0 bs58: 4.0.1 buffer: 6.0.3 @@ -13246,26 +15109,6 @@ snapshots: - typescript - utf-8-validate - '@spruceid/siwe-parser@2.1.2': - dependencies: - '@noble/hashes': 1.8.0 - apg-js: 4.4.0 - uri-js: 4.4.1 - valid-url: 1.0.9 - - '@stablelib/binary@1.0.1': - dependencies: - '@stablelib/int': 1.0.1 - - '@stablelib/int@1.0.1': {} - - '@stablelib/random@1.0.2': - dependencies: - '@stablelib/binary': 1.0.1 - '@stablelib/wipe': 1.0.1 - - '@stablelib/wipe@1.0.1': {} - '@stellar/js-xdr@3.1.2': {} '@stellar/stellar-base@14.1.0': @@ -13477,8 +15320,20 @@ snapshots: '@tanstack/query-core': 5.90.11 react: 19.2.3 + '@tanstack/store@0.8.0': {} + '@trysound/sax@0.2.0': {} + '@txnlab/use-wallet@4.6.0(@blockshake/defly-connect@1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@perawallet/connect@1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10))(@walletconnect/sign-client@2.23.9(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(algosdk@3.5.2)(lute-connect@1.7.0)': + dependencies: + '@tanstack/store': 0.8.0 + algosdk: 3.5.2 + optionalDependencies: + '@blockshake/defly-connect': 1.2.1(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@perawallet/connect': 1.5.2(algosdk@3.5.2)(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/sign-client': 2.23.9(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + lute-connect: 1.7.0 + '@tybys/wasm-util@0.10.0': dependencies: tslib: 2.8.1 @@ -13487,13 +15342,13 @@ snapshots: '@types/body-parser@1.19.6': dependencies: '@types/connect': 3.4.38 - '@types/node': 22.18.0 + '@types/node': 22.19.17 '@types/cacheable-request@6.0.3': dependencies: '@types/http-cache-semantics': 4.2.0 '@types/keyv': 3.1.4 - '@types/node': 22.18.0 + '@types/node': 22.19.17 '@types/responselike': 1.0.3 '@types/chai@5.2.2': @@ -13502,9 +15357,9 @@ snapshots: '@types/connect@3.4.38': dependencies: - '@types/node': 22.18.0 + '@types/node': 22.19.17 - '@types/debug@4.1.12': + '@types/debug@4.1.13': dependencies: '@types/ms': 2.1.0 @@ -13514,7 +15369,7 @@ snapshots: '@types/express-serve-static-core@5.0.7': dependencies: - '@types/node': 22.18.0 + '@types/node': 22.19.17 '@types/qs': 6.14.0 '@types/range-parser': 1.2.7 '@types/send': 0.17.5 @@ -13529,13 +15384,23 @@ snapshots: '@types/http-errors@2.0.5': {} + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + '@types/json-schema@7.0.15': {} '@types/json5@0.0.29': {} '@types/keyv@3.1.4': dependencies: - '@types/node': 22.18.0 + '@types/node': 22.19.17 '@types/lodash@4.17.20': {} @@ -13549,9 +15414,9 @@ snapshots: dependencies: undici-types: 6.21.0 - '@types/node@22.7.5': + '@types/node@22.19.17': dependencies: - undici-types: 6.19.8 + undici-types: 6.21.0 '@types/qs@6.14.0': {} @@ -13567,17 +15432,17 @@ snapshots: '@types/responselike@1.0.3': dependencies: - '@types/node': 22.18.0 + '@types/node': 22.19.17 '@types/send@0.17.5': dependencies: '@types/mime': 1.3.5 - '@types/node': 22.18.0 + '@types/node': 22.19.17 '@types/serve-static@1.15.8': dependencies: '@types/http-errors': 2.0.5 - '@types/node': 22.18.0 + '@types/node': 22.19.17 '@types/send': 0.17.5 '@types/trusted-types@2.0.7': {} @@ -13586,11 +15451,17 @@ snapshots: '@types/ws@7.4.7': dependencies: - '@types/node': 22.18.0 + '@types/node': 22.19.17 '@types/ws@8.18.1': dependencies: - '@types/node': 22.18.0 + '@types/node': 22.19.17 + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 '@typescript-eslint/eslint-plugin@8.42.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2)': dependencies: @@ -13690,7 +15561,7 @@ snapshots: '@typescript-eslint/types': 8.42.0 '@typescript-eslint/typescript-estree': 8.42.0(typescript@5.9.2) '@typescript-eslint/utils': 8.42.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2) - debug: 4.4.3 + debug: 4.4.1 eslint: 9.34.0(jiti@2.6.1) ts-api-utils: 2.1.0(typescript@5.9.2) typescript: 5.9.2 @@ -13852,13 +15723,21 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1))': + '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.21 + magic-string: 0.30.18 + optionalDependencies: + vite: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) + + '@vitest/mocker@3.2.4(vite@6.3.5(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.18 optionalDependencies: - vite: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + vite: 6.3.5(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) '@vitest/pretty-format@3.2.4': dependencies: @@ -13873,7 +15752,7 @@ snapshots: '@vitest/snapshot@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.21 + magic-string: 0.30.18 pathe: 2.0.3 '@vitest/spy@3.2.4': @@ -13886,18 +15765,62 @@ snapshots: loupe: 3.2.1 tinyrainbow: 2.0.0 - '@wagmi/connectors@5.9.9(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': + '@wagmi/connectors@5.9.9(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: '@base-org/account': 1.1.1(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@gemini-wallet/core': 0.2.0(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@gemini-wallet/core': 0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@metamask/sdk': 0.32.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/core': 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - immer + - ioredis + - react + - supports-color + - uploadthing + - use-sync-external-store + - utf-8-validate + - zod + + '@wagmi/connectors@5.9.9(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)))(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(zod@4.1.13)': + dependencies: + '@base-org/account': 1.1.1(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@4.1.13) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@4.1.13) + '@gemini-wallet/core': 0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) + '@metamask/sdk': 0.32.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@wagmi/core': 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + cbw-sdk: '@coinbase/wallet-sdk@3.9.3' + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -13930,18 +15853,18 @@ snapshots: - utf-8-validate - zod - '@wagmi/connectors@5.9.9(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': + '@wagmi/connectors@5.9.9(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)': dependencies: '@base-org/account': 1.1.1(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@3.25.76) '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(zod@3.25.76) - '@gemini-wallet/core': 0.2.0(viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@gemini-wallet/core': 0.2.0(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@metamask/sdk': 0.32.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/core': 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - viem: 2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -13974,19 +15897,19 @@ snapshots: - utf-8-validate - zod - '@wagmi/connectors@6.2.0(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76))(zod@3.25.76)': + '@wagmi/connectors@6.2.0(8ca0b565c60a9a741f268dc26c5db471)': dependencies: - '@base-org/account': 2.4.0(@types/react@19.1.12)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@gemini-wallet/core': 0.3.2(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@base-org/account': 2.4.0(@types/react@19.1.12)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@4.1.13) + '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@4.1.13) + '@gemini-wallet/core': 0.3.2(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) - '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) + '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + porto: 0.2.35(22b2b0b9fc59e99960931a8cc4834246) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -14027,19 +15950,19 @@ snapshots: - wagmi - zod - '@wagmi/connectors@6.2.0(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76))(zod@3.25.76)': + '@wagmi/connectors@6.2.0(b93a2b74079d10fd55412ca63eb44a93)': dependencies: '@base-org/account': 2.4.0(@types/react@19.1.12)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) '@coinbase/wallet-sdk': 4.3.6(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(zod@3.25.76) - '@gemini-wallet/core': 0.3.2(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@gemini-wallet/core': 0.3.2(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@metamask/sdk': 0.33.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@safe-global/safe-apps-provider': 0.18.6(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@safe-global/safe-apps-sdk': 9.1.0(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) '@walletconnect/ethereum-provider': 2.21.1(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) cbw-sdk: '@coinbase/wallet-sdk@3.9.3' - porto: 0.2.35(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + porto: 0.2.35(8943dcca3736e121a930ece2db280a96) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -14080,11 +16003,11 @@ snapshots: - wagmi - zod - '@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: eventemitter3: 5.0.1 mipd: 0.0.7(typescript@5.9.2) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zustand: 5.0.0(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) optionalDependencies: '@tanstack/query-core': 5.90.11 @@ -14095,11 +16018,11 @@ snapshots: - react - use-sync-external-store - '@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': dependencies: eventemitter3: 5.0.1 mipd: 0.0.7(typescript@5.9.2) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) zustand: 5.0.0(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) optionalDependencies: '@tanstack/query-core': 5.90.11 @@ -14110,11 +16033,11 @@ snapshots: - react - use-sync-external-store - '@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: eventemitter3: 5.0.1 mipd: 0.0.7(typescript@5.9.2) - viem: 2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zustand: 5.0.0(@types/react@19.1.12)(react@19.2.3)(use-sync-external-store@1.4.0(react@19.2.3)) optionalDependencies: '@tanstack/query-core': 5.90.11 @@ -14125,11 +16048,11 @@ snapshots: - react - use-sync-external-store - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': dependencies: eventemitter3: 5.0.1 mipd: 0.0.7(typescript@5.9.2) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zustand: 5.0.0(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) optionalDependencies: '@tanstack/query-core': 5.90.11 @@ -14140,11 +16063,11 @@ snapshots: - react - use-sync-external-store - '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))': + '@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))': dependencies: eventemitter3: 5.0.1 mipd: 0.0.7(typescript@5.9.2) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) zustand: 5.0.0(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) optionalDependencies: '@tanstack/query-core': 5.90.11 @@ -14165,6 +16088,33 @@ snapshots: dependencies: '@wallet-standard/base': 1.1.0 + '@walletconnect/browser-utils@1.8.0': + dependencies: + '@walletconnect/safe-json': 1.0.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/window-getters': 1.0.0 + '@walletconnect/window-metadata': 1.0.0 + detect-browser: 5.2.0 + + '@walletconnect/client@1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@walletconnect/core': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/iso-crypto': 1.8.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@walletconnect/core@1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@walletconnect/socket-transport': 1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + '@walletconnect/core@2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/heartbeat': 1.2.2 @@ -14209,7 +16159,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/core@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/core@2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 @@ -14222,8 +16172,8 @@ snapshots: '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) - '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.0(@vercel/functions@2.2.13) + '@walletconnect/utils': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) '@walletconnect/window-getters': 1.0.1 es-toolkit: 1.33.0 events: 3.3.0 @@ -14253,23 +16203,25 @@ snapshots: - utf-8-validate - zod - '@walletconnect/environment@1.0.1': - dependencies: - tslib: 1.14.1 - - '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/core@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@reown/appkit': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) - '@walletconnect/sign-client': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) - '@walletconnect/universal-provider': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.33.0 events: 3.3.0 + uint8arrays: 3.1.0 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -14282,7 +16234,6 @@ snapshots: - '@netlify/blobs' - '@planetscale/database' - '@react-native-async-storage/async-storage' - - '@types/react' - '@upstash/redis' - '@vercel/blob' - '@vercel/functions' @@ -14290,27 +16241,31 @@ snapshots: - aws4fetch - bufferutil - db0 - - encoding - ioredis - - react - typescript - uploadthing - utf-8-validate - zod - '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/core@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@reown/appkit': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/heartbeat': 1.2.2 '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) - '@walletconnect/sign-client': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/logger': 2.1.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) - '@walletconnect/universal-provider': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.33.0 events: 3.3.0 + uint8arrays: 3.1.0 transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -14323,7 +16278,6 @@ snapshots: - '@netlify/blobs' - '@planetscale/database' - '@react-native-async-storage/async-storage' - - '@types/react' - '@upstash/redis' - '@vercel/blob' - '@vercel/functions' @@ -14331,52 +16285,242 @@ snapshots: - aws4fetch - bufferutil - db0 - - encoding - ioredis - - react - typescript - uploadthing - utf-8-validate - zod - '@walletconnect/events@1.0.1': - dependencies: - keyvaluestorage-interface: 1.0.0 - tslib: 1.14.1 - - '@walletconnect/heartbeat@1.2.2': - dependencies: - '@walletconnect/events': 1.0.1 - '@walletconnect/time': 1.0.2 - events: 3.3.0 - - '@walletconnect/jsonrpc-http-connection@1.0.8': + '@walletconnect/core@2.23.9(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/jsonrpc-ws-connection': 1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) + '@walletconnect/logger': 3.0.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 - cross-fetch: 3.2.0 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.23.9(@vercel/functions@2.2.13) + '@walletconnect/utils': 2.23.9(@vercel/functions@2.2.13)(typescript@5.9.2)(zod@4.1.13) + '@walletconnect/window-getters': 1.0.1 + es-toolkit: 1.44.0 events: 3.3.0 + uint8arrays: 3.1.1 transitivePeerDependencies: - - encoding + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod - '@walletconnect/jsonrpc-provider@1.0.14': + '@walletconnect/crypto@1.1.0': dependencies: - '@walletconnect/jsonrpc-utils': 1.0.8 - '@walletconnect/safe-json': 1.0.2 - events: 3.3.0 + '@noble/ciphers': 1.2.0 + '@noble/hashes': 1.7.0 + '@walletconnect/encoding': 1.0.2 + '@walletconnect/environment': 1.0.1 + '@walletconnect/randombytes': 1.1.0 + tslib: 1.14.1 - '@walletconnect/jsonrpc-types@1.0.4': + '@walletconnect/encoding@1.0.2': dependencies: - events: 3.3.0 - keyvaluestorage-interface: 1.0.0 + is-typedarray: 1.0.0 + tslib: 1.14.1 + typedarray-to-buffer: 3.1.5 - '@walletconnect/jsonrpc-utils@1.0.8': + '@walletconnect/environment@1.0.1': dependencies: - '@walletconnect/environment': 1.0.1 - '@walletconnect/jsonrpc-types': 1.0.4 tslib: 1.14.1 - '@walletconnect/jsonrpc-ws-connection@1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) + '@walletconnect/sign-client': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) + '@walletconnect/universal-provider': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + '@reown/appkit': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) + '@walletconnect/sign-client': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) + '@walletconnect/universal-provider': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/ethereum-provider@2.21.1(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@reown/appkit': 1.7.8(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) + '@walletconnect/sign-client': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) + '@walletconnect/universal-provider': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@types/react' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - encoding + - ioredis + - react + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/events@1.0.1': + dependencies: + keyvaluestorage-interface: 1.0.0 + tslib: 1.14.1 + + '@walletconnect/heartbeat@1.2.2': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/time': 1.0.2 + events: 3.3.0 + + '@walletconnect/iso-crypto@1.8.0': + dependencies: + '@walletconnect/crypto': 1.1.0 + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + + '@walletconnect/jsonrpc-http-connection@1.0.8': + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + cross-fetch: 3.2.0 + events: 3.3.0 + transitivePeerDependencies: + - encoding + + '@walletconnect/jsonrpc-provider@1.0.14': + dependencies: + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/safe-json': 1.0.2 + events: 3.3.0 + + '@walletconnect/jsonrpc-types@1.0.4': + dependencies: + events: 3.3.0 + keyvaluestorage-interface: 1.0.0 + + '@walletconnect/jsonrpc-utils@1.0.8': + dependencies: + '@walletconnect/environment': 1.0.1 + '@walletconnect/jsonrpc-types': 1.0.4 + tslib: 1.14.1 + + '@walletconnect/jsonrpc-ws-connection@1.0.16(bufferutil@4.0.9)(utf-8-validate@5.0.10)': dependencies: '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/safe-json': 1.0.2 @@ -14411,37 +16555,336 @@ snapshots: - ioredis - uploadthing - '@walletconnect/logger@2.1.2': - dependencies: - '@walletconnect/safe-json': 1.0.2 - pino: 7.11.0 - - '@walletconnect/relay-api@1.0.11': - dependencies: - '@walletconnect/jsonrpc-types': 1.0.4 - - '@walletconnect/relay-auth@1.1.0': - dependencies: - '@noble/curves': 1.8.0 - '@noble/hashes': 1.7.0 - '@walletconnect/safe-json': 1.0.2 - '@walletconnect/time': 1.0.2 - uint8arrays: 3.1.0 - - '@walletconnect/safe-json@1.0.2': - dependencies: - tslib: 1.14.1 - - '@walletconnect/sign-client@2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/logger@2.1.2': + dependencies: + '@walletconnect/safe-json': 1.0.2 + pino: 7.11.0 + + '@walletconnect/logger@3.0.2': + dependencies: + '@walletconnect/safe-json': 1.0.2 + pino: 10.0.0 + + '@walletconnect/randombytes@1.1.0': + dependencies: + '@noble/hashes': 1.7.0 + '@walletconnect/encoding': 1.0.2 + '@walletconnect/environment': 1.0.1 + tslib: 1.14.1 + + '@walletconnect/relay-api@1.0.11': + dependencies: + '@walletconnect/jsonrpc-types': 1.0.4 + + '@walletconnect/relay-auth@1.1.0': + dependencies: + '@noble/curves': 1.8.0 + '@noble/hashes': 1.7.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + uint8arrays: 3.1.1 + + '@walletconnect/safe-json@1.0.0': {} + + '@walletconnect/safe-json@1.0.2': + dependencies: + tslib: 1.14.1 + + '@walletconnect/sign-client@2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/core': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0(@vercel/functions@2.2.13) + '@walletconnect/utils': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/sign-client@2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + '@walletconnect/core': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0(@vercel/functions@2.2.13) + '@walletconnect/utils': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/sign-client@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@walletconnect/core': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) + '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/sign-client@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + '@walletconnect/core': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 2.1.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) + '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/sign-client@2.23.9(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': + dependencies: + '@walletconnect/core': 2.23.9(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/logger': 3.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.23.9(@vercel/functions@2.2.13) + '@walletconnect/utils': 2.23.9(@vercel/functions@2.2.13)(typescript@5.9.2)(zod@4.1.13) + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - bufferutil + - db0 + - ioredis + - typescript + - uploadthing + - utf-8-validate + - zod + + '@walletconnect/socket-transport@1.8.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)': + dependencies: + '@walletconnect/types': 1.8.0 + '@walletconnect/utils': 1.8.0 + ws: 7.5.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@walletconnect/time@1.0.2': + dependencies: + tslib: 1.14.1 + + '@walletconnect/types@1.8.0': {} + + '@walletconnect/types@2.21.0(@vercel/functions@2.2.13)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) + '@walletconnect/logger': 2.1.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/types@2.21.1(@vercel/functions@2.2.13)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) + '@walletconnect/logger': 2.1.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/types@2.23.9(@vercel/functions@2.2.13)': + dependencies: + '@walletconnect/events': 1.0.1 + '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) + '@walletconnect/logger': 3.0.2 + events: 3.3.0 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - uploadthing + + '@walletconnect/universal-provider@2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: - '@walletconnect/core': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) '@walletconnect/logger': 2.1.2 - '@walletconnect/time': 1.0.2 + '@walletconnect/sign-client': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/types': 2.21.0(@vercel/functions@2.2.13) '@walletconnect/utils': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -14462,22 +16905,26 @@ snapshots: - aws4fetch - bufferutil - db0 + - encoding - ioredis - typescript - uploadthing - utf-8-validate - zod - '@walletconnect/sign-client@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/universal-provider@2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@walletconnect/core': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 + '@walletconnect/jsonrpc-types': 1.0.4 '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) '@walletconnect/logger': 2.1.2 - '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) - '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/sign-client': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.0(@vercel/functions@2.2.13) + '@walletconnect/utils': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -14498,23 +16945,26 @@ snapshots: - aws4fetch - bufferutil - db0 + - encoding - ioredis - typescript - uploadthing - utf-8-validate - zod - '@walletconnect/time@1.0.2': - dependencies: - tslib: 1.14.1 - - '@walletconnect/types@2.21.0(@vercel/functions@2.2.13)': + '@walletconnect/universal-provider@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) + '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -14533,17 +16983,28 @@ snapshots: - '@vercel/functions' - '@vercel/kv' - aws4fetch + - bufferutil - db0 + - encoding - ioredis + - typescript - uploadthing + - utf-8-validate + - zod - '@walletconnect/types@2.21.1(@vercel/functions@2.2.13)': + '@walletconnect/universal-provider@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@walletconnect/events': 1.0.1 - '@walletconnect/heartbeat': 1.2.2 + '@walletconnect/jsonrpc-http-connection': 1.0.8 + '@walletconnect/jsonrpc-provider': 1.0.14 '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) '@walletconnect/logger': 2.1.2 + '@walletconnect/sign-client': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) + '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) + es-toolkit: 1.33.0 events: 3.3.0 transitivePeerDependencies: - '@azure/app-configuration' @@ -14562,24 +17023,44 @@ snapshots: - '@vercel/functions' - '@vercel/kv' - aws4fetch + - bufferutil - db0 + - encoding - ioredis + - typescript - uploadthing + - utf-8-validate + - zod - '@walletconnect/universal-provider@2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/utils@1.8.0': dependencies: - '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8 - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 + '@walletconnect/browser-utils': 1.8.0 + '@walletconnect/encoding': 1.0.2 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/types': 1.8.0 + bn.js: 4.11.8 + js-sha3: 0.8.0 + query-string: 6.13.5 + + '@walletconnect/utils@2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + dependencies: + '@noble/ciphers': 1.2.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) - '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 '@walletconnect/types': 2.21.0(@vercel/functions@2.2.13) - '@walletconnect/utils': 2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - es-toolkit: 1.33.0 - events: 3.3.0 + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -14599,27 +17080,31 @@ snapshots: - aws4fetch - bufferutil - db0 - - encoding - ioredis - typescript - uploadthing - utf-8-validate - zod - '@walletconnect/universal-provider@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/utils@2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: - '@walletconnect/events': 1.0.1 - '@walletconnect/jsonrpc-http-connection': 1.0.8 - '@walletconnect/jsonrpc-provider': 1.0.14 - '@walletconnect/jsonrpc-types': 1.0.4 + '@noble/ciphers': 1.2.1 + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 '@walletconnect/jsonrpc-utils': 1.0.8 '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) - '@walletconnect/logger': 2.1.2 - '@walletconnect/sign-client': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) - '@walletconnect/utils': 2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) - es-toolkit: 1.33.0 - events: 3.3.0 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.21.0(@vercel/functions@2.2.13) + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + bs58: 6.0.0 + detect-browser: 5.3.0 + query-string: 7.1.3 + uint8arrays: 3.1.0 + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -14639,14 +17124,13 @@ snapshots: - aws4fetch - bufferutil - db0 - - encoding - ioredis - typescript - uploadthing - utf-8-validate - zod - '@walletconnect/utils@2.21.0(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/utils@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': dependencies: '@noble/ciphers': 1.2.1 '@noble/curves': 1.8.1 @@ -14657,7 +17141,7 @@ snapshots: '@walletconnect/relay-auth': 1.1.0 '@walletconnect/safe-json': 1.0.2 '@walletconnect/time': 1.0.2 - '@walletconnect/types': 2.21.0(@vercel/functions@2.2.13) + '@walletconnect/types': 2.21.1(@vercel/functions@2.2.13) '@walletconnect/window-getters': 1.0.1 '@walletconnect/window-metadata': 1.0.1 bs58: 6.0.0 @@ -14690,7 +17174,7 @@ snapshots: - utf-8-validate - zod - '@walletconnect/utils@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)': + '@walletconnect/utils@2.21.1(@vercel/functions@2.2.13)(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)': dependencies: '@noble/ciphers': 1.2.1 '@noble/curves': 1.8.1 @@ -14708,7 +17192,7 @@ snapshots: detect-browser: 5.3.0 query-string: 7.1.3 uint8arrays: 3.1.0 - viem: 2.23.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.23.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) transitivePeerDependencies: - '@azure/app-configuration' - '@azure/cosmos' @@ -14734,10 +17218,60 @@ snapshots: - utf-8-validate - zod + '@walletconnect/utils@2.23.9(@vercel/functions@2.2.13)(typescript@5.9.2)(zod@4.1.13)': + dependencies: + '@msgpack/msgpack': 3.1.3 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/base': 1.2.6 + '@walletconnect/jsonrpc-utils': 1.0.8 + '@walletconnect/keyvaluestorage': 1.1.1(@vercel/functions@2.2.13) + '@walletconnect/logger': 3.0.2 + '@walletconnect/relay-api': 1.0.11 + '@walletconnect/relay-auth': 1.1.0 + '@walletconnect/safe-json': 1.0.2 + '@walletconnect/time': 1.0.2 + '@walletconnect/types': 2.23.9(@vercel/functions@2.2.13) + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata': 1.0.1 + blakejs: 1.2.1 + detect-browser: 5.3.0 + ox: 0.9.3(typescript@5.9.2)(zod@4.1.13) + uint8arrays: 3.1.1 + transitivePeerDependencies: + - '@azure/app-configuration' + - '@azure/cosmos' + - '@azure/data-tables' + - '@azure/identity' + - '@azure/keyvault-secrets' + - '@azure/storage-blob' + - '@capacitor/preferences' + - '@deno/kv' + - '@netlify/blobs' + - '@planetscale/database' + - '@react-native-async-storage/async-storage' + - '@upstash/redis' + - '@vercel/blob' + - '@vercel/functions' + - '@vercel/kv' + - aws4fetch + - db0 + - ioredis + - typescript + - uploadthing + - zod + + '@walletconnect/window-getters@1.0.0': {} + '@walletconnect/window-getters@1.0.1': dependencies: tslib: 1.14.1 + '@walletconnect/window-metadata@1.0.0': + dependencies: + '@walletconnect/window-getters': 1.0.1 + '@walletconnect/window-metadata@1.0.1': dependencies: '@walletconnect/window-getters': 1.0.1 @@ -14753,12 +17287,7 @@ snapshots: typescript: 5.9.2 zod: 3.25.76 - abitype@1.1.0(typescript@5.9.2)(zod@3.25.76): - optionalDependencies: - typescript: 5.9.2 - zod: 3.25.76 - - abitype@1.1.0(typescript@5.9.2)(zod@4.1.13): + abitype@1.0.8(typescript@5.9.2)(zod@4.1.13): optionalDependencies: typescript: 5.9.2 zod: 4.1.13 @@ -14773,6 +17302,15 @@ snapshots: typescript: 5.9.2 zod: 3.25.76 + abitype@1.2.3(typescript@5.9.2)(zod@4.1.13): + optionalDependencies: + typescript: 5.9.2 + zod: 4.1.13 + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + abstract-logging@2.0.1: {} accepts@1.3.8: @@ -14791,8 +17329,6 @@ snapshots: acorn@8.15.0: {} - aes-js@4.0.0-beta.5: {} - agent-base@7.1.4: {} agentkeepalive@4.6.0: @@ -14817,18 +17353,41 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + algo-msgpack-with-bigint@2.1.1: {} + + algorand-msgpack@1.1.0: {} + + algosdk@3.5.2: + dependencies: + algorand-msgpack: 1.1.0 + hi-base32: 0.5.1 + js-sha256: 0.9.0 + js-sha3: 0.8.0 + js-sha512: 0.8.0 + json-bigint: 1.0.0 + tweetnacl: 1.0.3 + vlq: 2.0.4 + + anser@1.4.10: {} + ansi-colors@4.1.3: {} ansi-regex@5.0.1: {} ansi-regex@6.2.0: {} + ansi-regex@6.2.2: {} + ansi-styles@4.3.0: dependencies: color-convert: 2.0.1 + ansi-styles@5.2.0: {} + ansi-styles@6.2.1: {} + ansi-styles@6.2.3: {} + any-promise@1.3.0: {} anymatch@3.1.3: @@ -14919,6 +17478,14 @@ snapshots: get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 + asap@2.0.6: {} + + asn1js@3.0.6: + dependencies: + pvtsutils: 1.3.6 + pvutils: 1.1.5 + tslib: 2.8.1 + assertion-error@2.0.1: {} ast-types-flow@0.0.8: {} @@ -14991,6 +17558,10 @@ snapshots: transitivePeerDependencies: - supports-color + babel-plugin-syntax-hermes-parser@0.33.3: + dependencies: + hermes-parser: 0.33.3 + balanced-match@1.0.2: {} base-x@3.0.11: @@ -15007,24 +17578,29 @@ snapshots: dependencies: is-windows: 1.0.2 - bidi-js@1.0.3: - dependencies: - require-from-string: 2.0.2 - optional: true - big.js@6.2.2: {} bigint-buffer@1.1.5: dependencies: bindings: 1.5.0 + bignumber.js@9.1.1: {} + bignumber.js@9.3.1: {} bindings@1.5.0: dependencies: file-uri-to-path: 1.0.0 - bn.js@5.2.2: {} + blakejs@1.2.1: {} + + bn.js@4.11.8: {} + + bn.js@4.12.3: {} + + bn.js@5.2.1: {} + + bn.js@5.2.3: {} body-parser@1.20.3: dependencies: @@ -15061,10 +17637,12 @@ snapshots: borsh@0.7.0: dependencies: - bn.js: 5.2.2 + bn.js: 5.2.3 bs58: 4.0.1 text-encoding-utf-8: 1.0.2 + bowser@2.11.0: {} + bowser@2.12.1: {} brace-expansion@1.1.12: @@ -15080,6 +17658,8 @@ snapshots: dependencies: fill-range: 7.1.1 + brorand@1.1.0: {} + browserslist@4.25.4: dependencies: caniuse-lite: 1.0.30001739 @@ -15095,6 +17675,12 @@ snapshots: dependencies: base-x: 5.0.1 + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + buffer@6.0.3: dependencies: base64-js: 1.5.1 @@ -15104,9 +17690,9 @@ snapshots: dependencies: node-gyp-build: 4.8.4 - bundle-require@5.1.0(esbuild@0.25.9): + bundle-require@5.1.0(esbuild@0.25.12): dependencies: - esbuild: 0.25.9 + esbuild: 0.25.12 load-tsconfig: 0.2.5 bytes@3.1.2: {} @@ -15175,6 +17761,27 @@ snapshots: dependencies: readdirp: 4.1.2 + chrome-launcher@0.15.2: + dependencies: + '@types/node': 22.19.17 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + transitivePeerDependencies: + - supports-color + + chromium-edge-launcher@0.3.0: + dependencies: + '@types/node': 22.19.17 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + mkdirp: 1.0.4 + transitivePeerDependencies: + - supports-color + + ci-info@2.0.0: {} + ci-info@3.9.0: {} client-only@0.0.1: {} @@ -15185,6 +17792,12 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 6.2.0 + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + clone-response@1.0.3: dependencies: mimic-response: 1.0.1 @@ -15199,6 +17812,8 @@ snapshots: color-name@1.1.4: {} + colorette@2.0.20: {} + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 @@ -15225,6 +17840,15 @@ snapshots: confbox@0.1.8: {} + connect@3.7.0: + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color + consola@3.4.2: {} content-disposition@0.5.4: @@ -15293,6 +17917,8 @@ snapshots: crypt@0.0.2: {} + crypto-js@4.2.0: {} + css-select@5.2.2: dependencies: boolbase: 1.0.0 @@ -15338,12 +17964,6 @@ snapshots: whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - data-urls@6.0.0: - dependencies: - whatwg-mimetype: 4.0.0 - whatwg-url: 15.1.0 - optional: true - data-view-buffer@1.0.2: dependencies: call-bound: 1.0.4 @@ -15368,6 +17988,8 @@ snapshots: dependencies: '@babel/runtime': 7.28.3 + dateformat@4.6.3: {} + dayjs@1.11.13: {} debug@2.6.9: @@ -15446,6 +18068,8 @@ snapshots: destroy@1.2.0: {} + detect-browser@5.2.0: {} + detect-browser@5.3.0: {} detect-indent@6.1.0: {} @@ -15485,6 +18109,8 @@ snapshots: no-case: 3.0.4 tslib: 2.8.1 + dotenv@16.6.1: {} + dotenv@8.6.0: {} dunder-proto@1.0.1: @@ -15513,6 +18139,16 @@ snapshots: electron-to-chromium@1.5.214: {} + elliptic@6.6.1: + dependencies: + bn.js: 4.12.3 + brorand: 1.1.0 + hash.js: 1.1.7 + hmac-drbg: 1.0.1 + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + emoji-regex@8.0.0: {} emoji-regex@9.2.2: {} @@ -15559,6 +18195,10 @@ snapshots: dependencies: is-arrayish: 0.2.1 + error-stack-parser@2.1.4: + dependencies: + stackframe: 1.3.4 + es-abstract@1.24.0: dependencies: array-buffer-byte-length: 1.0.2 @@ -15664,40 +18304,71 @@ snapshots: es-toolkit@1.33.0: {} + es-toolkit@1.44.0: {} + es6-promise@4.2.8: {} es6-promisify@5.0.0: dependencies: es6-promise: 4.2.8 - esbuild@0.25.9: + esbuild@0.25.12: optionalDependencies: - '@esbuild/aix-ppc64': 0.25.9 - '@esbuild/android-arm': 0.25.9 - '@esbuild/android-arm64': 0.25.9 - '@esbuild/android-x64': 0.25.9 - '@esbuild/darwin-arm64': 0.25.9 - '@esbuild/darwin-x64': 0.25.9 - '@esbuild/freebsd-arm64': 0.25.9 - '@esbuild/freebsd-x64': 0.25.9 - '@esbuild/linux-arm': 0.25.9 - '@esbuild/linux-arm64': 0.25.9 - '@esbuild/linux-ia32': 0.25.9 - '@esbuild/linux-loong64': 0.25.9 - '@esbuild/linux-mips64el': 0.25.9 - '@esbuild/linux-ppc64': 0.25.9 - '@esbuild/linux-riscv64': 0.25.9 - '@esbuild/linux-s390x': 0.25.9 - '@esbuild/linux-x64': 0.25.9 - '@esbuild/netbsd-arm64': 0.25.9 - '@esbuild/netbsd-x64': 0.25.9 - '@esbuild/openbsd-arm64': 0.25.9 - '@esbuild/openbsd-x64': 0.25.9 - '@esbuild/openharmony-arm64': 0.25.9 - '@esbuild/sunos-x64': 0.25.9 - '@esbuild/win32-arm64': 0.25.9 - '@esbuild/win32-ia32': 0.25.9 - '@esbuild/win32-x64': 0.25.9 + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 escalade@3.2.0: {} @@ -15741,7 +18412,7 @@ snapshots: get-tsconfig: 4.10.1 is-bun-module: 2.0.0 stable-hash: 0.0.5 - tinyglobby: 0.2.15 + tinyglobby: 0.2.14 unrs-resolver: 1.11.1 optionalDependencies: eslint-plugin-import: 2.32.0(@typescript-eslint/parser@8.42.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2))(eslint-import-resolver-typescript@3.10.1)(eslint@9.34.0(jiti@2.6.1)) @@ -15832,13 +18503,13 @@ snapshots: '@es-joy/jsdoccomment': 0.50.2 are-docs-informative: 0.0.2 comment-parser: 1.4.1 - debug: 4.4.3 + debug: 4.4.1 escape-string-regexp: 4.0.0 eslint: 9.34.0(jiti@2.6.1) espree: 10.4.0 esquery: 1.6.0 parse-imports-exports: 0.2.4 - semver: 7.7.3 + semver: 7.7.2 spdx-expression-parse: 4.0.0 transitivePeerDependencies: - supports-color @@ -15929,7 +18600,7 @@ snapshots: ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.1 escape-string-regexp: 4.0.0 eslint-scope: 8.4.0 eslint-visitor-keys: 4.2.1 @@ -16013,23 +18684,14 @@ snapshots: '@scure/bip32': 1.4.0 '@scure/bip39': 1.3.0 - ethers@6.16.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): - dependencies: - '@adraffy/ens-normalize': 1.10.1 - '@noble/curves': 1.2.0 - '@noble/hashes': 1.3.2 - '@types/node': 22.7.5 - aes-js: 4.0.0-beta.5 - tslib: 2.7.0 - ws: 8.17.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) - transitivePeerDependencies: - - bufferutil - - utf-8-validate + event-target-shim@5.0.1: {} eventemitter2@6.4.9: {} eventemitter3@5.0.1: {} + eventemitter3@5.0.4: {} + events@3.3.0: {} eventsource-parser@3.0.6: {} @@ -16042,6 +18704,8 @@ snapshots: expect-type@1.2.2: {} + exponential-backoff@3.1.3: {} + express-rate-limit@8.2.1(express@5.2.1): dependencies: express: 5.2.1 @@ -16125,6 +18789,10 @@ snapshots: eyes@0.1.8: {} + fast-base64-decode@1.0.0: {} + + fast-copy@3.0.2: {} + fast-decode-uri-component@1.0.1: {} fast-deep-equal@3.1.3: {} @@ -16174,7 +18842,7 @@ snapshots: fastestsmallesttextencoderdecoder@1.0.22: {} - fastify@5.8.2: + fastify@5.8.4: dependencies: '@fastify/ajv-compiler': 4.0.5 '@fastify/error': 4.2.0 @@ -16196,6 +18864,12 @@ snapshots: dependencies: reusify: 1.1.0 + fb-dotslash@0.5.8: {} + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + fdir@6.5.0(picomatch@4.0.3): optionalDependencies: picomatch: 4.0.3 @@ -16216,6 +18890,18 @@ snapshots: filter-obj@1.1.0: {} + finalhandler@1.1.2: + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + finalhandler@1.3.1: dependencies: debug: 2.6.9 @@ -16243,7 +18929,7 @@ snapshots: dependencies: fast-deep-equal: 3.1.3 fast-querystring: 1.1.2 - safe-regex2: 5.0.0 + safe-regex2: 5.1.0 find-up@4.1.0: dependencies: @@ -16268,6 +18954,8 @@ snapshots: flatted@3.3.3: {} + flow-enums-runtime@0.0.6: {} + follow-redirects@1.15.11: {} for-each@0.3.5: @@ -16279,6 +18967,8 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 + forge-light@1.1.4: {} + form-data@4.0.4: dependencies: asynckit: 0.4.0 @@ -16354,7 +19044,7 @@ snapshots: get-stream@5.2.0: dependencies: - pump: 3.0.3 + pump: 3.0.4 get-symbol-description@1.1.0: dependencies: @@ -16463,16 +19153,39 @@ snapshots: dependencies: has-symbols: 1.1.0 + hash.js@1.1.7: + dependencies: + inherits: 2.0.4 + minimalistic-assert: 1.0.1 + hasown@2.0.2: dependencies: function-bind: 1.1.2 + help-me@5.0.0: {} + + hermes-compiler@250829098.0.10: {} + hermes-estree@0.25.1: {} + hermes-estree@0.33.3: {} + hermes-parser@0.25.1: dependencies: hermes-estree: 0.25.1 + hermes-parser@0.33.3: + dependencies: + hermes-estree: 0.33.3 + + hi-base32@0.5.1: {} + + hmac-drbg@1.0.1: + dependencies: + hash.js: 1.1.7 + minimalistic-assert: 1.0.1 + minimalistic-crypto-utils: 1.0.1 + hono@4.10.7: {} hono@4.11.7: {} @@ -16481,13 +19194,6 @@ snapshots: dependencies: whatwg-encoding: 3.1.1 - html-encoding-sniffer@6.0.0: - dependencies: - '@exodus/bytes': 1.8.0 - transitivePeerDependencies: - - '@exodus/crypto' - optional: true - http-cache-semantics@4.2.0: {} http-errors@2.0.0: @@ -16553,6 +19259,10 @@ snapshots: ignore@7.0.5: {} + image-size@1.2.1: + dependencies: + queue: 6.0.2 + import-fresh@3.3.1: dependencies: parent-module: 1.0.1 @@ -16568,6 +19278,10 @@ snapshots: hasown: 2.0.2 side-channel: 1.1.0 + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + ip-address@10.0.1: {} ipaddr.js@1.9.1: {} @@ -16610,7 +19324,7 @@ snapshots: is-bun-module@2.0.0: dependencies: - semver: 7.7.3 + semver: 7.7.4 is-callable@1.2.7: {} @@ -16629,6 +19343,8 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-docker@2.2.1: {} + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -16701,6 +19417,8 @@ snapshots: dependencies: which-typed-array: 1.1.19 + is-typedarray@1.0.0: {} + is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -16714,6 +19432,10 @@ snapshots: is-windows@1.0.2: {} + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + isarray@1.0.0: {} isarray@2.0.5: {} @@ -16765,18 +19487,53 @@ snapshots: - bufferutil - utf-8-validate + jest-get-type@29.6.3: {} + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 22.19.17 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 2.3.1 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-worker@29.7.0: + dependencies: + '@types/node': 22.19.17 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + jiti@2.6.1: {} jose@5.10.0: {} - jose@6.1.0: {} - jose@6.1.3: {} joycon@3.1.1: {} + js-base64@3.7.4: {} + + js-base64@3.7.7: {} + js-base64@3.7.8: {} + js-sha256@0.9.0: {} + + js-sha3@0.8.0: {} + + js-sha512@0.8.0: {} + js-tokens@4.0.0: {} js-tokens@9.0.1: {} @@ -16794,6 +19551,8 @@ snapshots: dependencies: argparse: 2.0.1 + jsc-safe-url@0.2.4: {} + jsdoc-type-pratt-parser@4.1.0: {} jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): @@ -16816,46 +19575,21 @@ snapshots: whatwg-encoding: 3.1.1 whatwg-mimetype: 4.0.0 whatwg-url: 14.2.0 - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) - xml-name-validator: 5.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): - dependencies: - '@acemir/cssom': 0.9.30 - '@asamuzakjp/dom-selector': 6.7.6 - '@exodus/bytes': 1.8.0 - cssstyle: 5.3.6 - data-urls: 6.0.0 - decimal.js: 10.6.0 - html-encoding-sniffer: 6.0.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 - is-potential-custom-element-name: 1.0.1 - parse5: 8.0.0 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 6.0.0 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 8.0.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 15.1.0 - ws: 8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) xml-name-validator: 5.0.0 transitivePeerDependencies: - - '@exodus/crypto' - bufferutil - supports-color - utf-8-validate - optional: true jsesc@3.0.2: {} jsesc@3.1.0: {} + json-bigint@1.0.0: + dependencies: + bignumber.js: 9.3.1 + json-buffer@3.0.1: {} json-parse-even-better-errors@2.3.1: {} @@ -16918,6 +19652,8 @@ snapshots: dependencies: language-subtag-registry: 0.3.23 + leven@3.1.0: {} + levn@0.4.1: dependencies: prelude-ls: 1.2.1 @@ -16929,6 +19665,13 @@ snapshots: process-warning: 4.0.1 set-cookie-parser: 2.7.2 + lighthouse-logger@1.4.2: + dependencies: + debug: 2.6.9 + marky: 1.3.0 + transitivePeerDependencies: + - supports-color + lightningcss-android-arm64@1.30.2: optional: true @@ -17008,6 +19751,8 @@ snapshots: dependencies: p-locate: 5.0.0 + lodash.camelcase@4.3.0: {} + lodash.debounce@4.0.8: {} lodash.merge@4.6.2: {} @@ -17016,8 +19761,12 @@ snapshots: lodash.startcase@4.4.0: {} + lodash.throttle@4.1.1: {} + lodash@4.17.21: {} + long@5.3.1: {} + loose-envify@1.4.0: dependencies: js-tokens: 4.0.0 @@ -17046,6 +19795,8 @@ snapshots: dependencies: yallist: 3.1.1 + lute-connect@1.7.0: {} + magic-string@0.30.18: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -17054,6 +19805,12 @@ snapshots: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + marky@1.3.0: {} + math-intrinsics@1.1.0: {} md5@2.3.0: @@ -17072,14 +19829,192 @@ snapshots: media-typer@1.1.0: {} + memoize-one@5.2.1: {} + merge-descriptors@1.0.3: {} merge-descriptors@2.0.0: {} + merge-stream@2.0.0: {} + merge2@1.4.1: {} methods@1.1.2: {} + metro-babel-transformer@0.84.2: + dependencies: + '@babel/core': 7.28.3 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.33.3 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-cache-key@0.84.2: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-cache@0.84.2: + dependencies: + exponential-backoff: 3.1.3 + flow-enums-runtime: 0.0.6 + https-proxy-agent: 7.0.6 + metro-core: 0.84.2 + transitivePeerDependencies: + - supports-color + + metro-config@0.84.2(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + connect: 3.7.0 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.84.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-cache: 0.84.2 + metro-core: 0.84.2 + metro-runtime: 0.84.2 + yaml: 2.8.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro-core@0.84.2: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.84.2 + + metro-file-map@0.84.2: + dependencies: + debug: 4.4.3 + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + nullthrows: 1.1.1 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color + + metro-minify-terser@0.84.2: + dependencies: + flow-enums-runtime: 0.0.6 + terser: 5.46.1 + + metro-resolver@0.84.2: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-runtime@0.84.2: + dependencies: + '@babel/runtime': 7.28.3 + flow-enums-runtime: 0.0.6 + + metro-source-map@0.84.2: + dependencies: + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.84.2 + nullthrows: 1.1.1 + ob1: 0.84.2 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-symbolicate@0.84.2: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.84.2 + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-transform-plugins@0.84.2: + dependencies: + '@babel/core': 7.28.3 + '@babel/generator': 7.29.1 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-transform-worker@0.84.2(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + '@babel/core': 7.28.3 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/types': 7.29.0 + flow-enums-runtime: 0.0.6 + metro: 0.84.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-babel-transformer: 0.84.2 + metro-cache: 0.84.2 + metro-cache-key: 0.84.2 + metro-minify-terser: 0.84.2 + metro-source-map: 0.84.2 + metro-transform-plugins: 0.84.2 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro@0.84.2(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + '@babel/code-frame': 7.29.0 + '@babel/core': 7.28.3 + '@babel/generator': 7.29.1 + '@babel/parser': 7.29.2 + '@babel/template': 7.28.6 + '@babel/traverse': 7.29.0 + '@babel/types': 7.29.0 + accepts: 2.0.0 + chalk: 4.1.2 + ci-info: 2.0.0 + connect: 3.7.0 + debug: 4.4.3 + error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + hermes-parser: 0.33.3 + image-size: 1.2.1 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.84.2 + metro-cache: 0.84.2 + metro-cache-key: 0.84.2 + metro-config: 0.84.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + metro-core: 0.84.2 + metro-file-map: 0.84.2 + metro-resolver: 0.84.2 + metro-runtime: 0.84.2 + metro-source-map: 0.84.2 + metro-symbolicate: 0.84.2 + metro-transform-plugins: 0.84.2 + metro-transform-worker: 0.84.2(bufferutil@4.0.9)(utf-8-validate@5.0.10) + mime-types: 3.0.2 + nullthrows: 1.1.1 + serialize-error: 2.1.0 + source-map: 0.5.7 + throat: 5.0.0 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + micro-ftch@0.3.1: {} micromatch@4.0.8: @@ -17105,6 +20040,10 @@ snapshots: mimic-response@3.1.0: {} + minimalistic-assert@1.0.1: {} + + minimalistic-crypto-utils@1.0.1: {} + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 @@ -17121,6 +20060,8 @@ snapshots: optionalDependencies: typescript: 5.9.2 + mkdirp@1.0.4: {} + mlly@1.8.0: dependencies: acorn: 8.15.0 @@ -17206,6 +20147,8 @@ snapshots: node-gyp-build@4.8.4: {} + node-int64@0.4.0: {} + node-mock-http@1.0.2: {} node-releases@2.0.19: {} @@ -17218,8 +20161,14 @@ snapshots: dependencies: boolbase: 1.0.0 + nullthrows@1.1.1: {} + nwsapi@2.2.21: {} + ob1@0.84.2: + dependencies: + flow-enums-runtime: 0.0.6 + obj-multiplex@1.0.0: dependencies: end-of-stream: 1.4.5 @@ -17278,6 +20227,10 @@ snapshots: on-exit-leak-free@2.1.2: {} + on-finished@2.3.0: + dependencies: + ee-first: 1.1.1 + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -17286,6 +20239,11 @@ snapshots: dependencies: wrappy: 1.0.2 + open@7.4.2: + dependencies: + is-docker: 2.2.1 + is-wsl: 2.2.0 + openapi-fetch@0.13.8: dependencies: openapi-typescript-helpers: 0.0.15 @@ -17309,9 +20267,9 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 - ox@0.11.3(typescript@5.9.2)(zod@3.22.4): + ox@0.14.20(typescript@5.9.2)(zod@3.22.4): dependencies: - '@adraffy/ens-normalize': 1.11.0 + '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 @@ -17324,9 +20282,9 @@ snapshots: transitivePeerDependencies: - zod - ox@0.11.3(typescript@5.9.2)(zod@3.25.76): + ox@0.14.20(typescript@5.9.2)(zod@3.25.76): dependencies: - '@adraffy/ens-normalize': 1.11.0 + '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 @@ -17339,14 +20297,29 @@ snapshots: transitivePeerDependencies: - zod + ox@0.14.20(typescript@5.9.2)(zod@4.1.13): + dependencies: + '@adraffy/ens-normalize': 1.11.1 + '@noble/ciphers': 1.3.0 + '@noble/curves': 1.9.1 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - zod + ox@0.4.4(typescript@5.9.2)(zod@3.25.76): dependencies: - '@adraffy/ens-normalize': 1.11.0 + '@adraffy/ens-normalize': 1.11.1 '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.9.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.9.2)(zod@3.25.76) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.2 @@ -17355,12 +20328,26 @@ snapshots: ox@0.6.7(typescript@5.9.2)(zod@3.25.76): dependencies: - '@adraffy/ens-normalize': 1.11.0 + '@adraffy/ens-normalize': 1.11.1 + '@noble/curves': 1.9.7 + '@noble/hashes': 1.8.0 + '@scure/bip32': 1.7.0 + '@scure/bip39': 1.6.0 + abitype: 1.2.3(typescript@5.9.2)(zod@3.25.76) + eventemitter3: 5.0.1 + optionalDependencies: + typescript: 5.9.2 + transitivePeerDependencies: + - zod + + ox@0.6.7(typescript@5.9.2)(zod@4.1.13): + dependencies: + '@adraffy/ens-normalize': 1.11.1 '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.9.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.2 @@ -17369,57 +20356,56 @@ snapshots: ox@0.6.9(typescript@5.9.2)(zod@3.25.76): dependencies: - '@adraffy/ens-normalize': 1.11.0 + '@adraffy/ens-normalize': 1.11.1 '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.9.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.9.2)(zod@3.25.76) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: - zod - ox@0.9.17(typescript@5.9.2)(zod@4.1.13): + ox@0.6.9(typescript@5.9.2)(zod@4.1.13): dependencies: - '@adraffy/ens-normalize': 1.11.0 - '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.1 + '@adraffy/ens-normalize': 1.11.1 + '@noble/curves': 1.9.7 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.9.2)(zod@4.1.13) + abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: - zod - ox@0.9.3(typescript@5.9.2)(zod@3.25.76): + ox@0.9.17(typescript@5.9.2)(zod@4.1.13): dependencies: - '@adraffy/ens-normalize': 1.11.0 + '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.9.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: - zod - ox@0.9.6(typescript@5.9.2)(zod@3.25.76): + ox@0.9.3(typescript@5.9.2)(zod@4.1.13): dependencies: - '@adraffy/ens-normalize': 1.11.0 + '@adraffy/ens-normalize': 1.11.1 '@noble/ciphers': 1.3.0 '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.9.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) eventemitter3: 5.0.1 optionalDependencies: typescript: 5.9.2 @@ -17479,11 +20465,6 @@ snapshots: dependencies: entities: 6.0.1 - parse5@8.0.0: - dependencies: - entities: 6.0.1 - optional: true - parseurl@1.3.3: {} path-exists@4.0.0: {} @@ -17524,14 +20505,62 @@ snapshots: duplexify: 4.1.3 split2: 4.2.0 + pino-abstract-transport@2.0.0: + dependencies: + split2: 4.2.0 + pino-abstract-transport@3.0.0: dependencies: split2: 4.2.0 + pino-pretty@13.0.0: + dependencies: + colorette: 2.0.20 + dateformat: 4.6.3 + fast-copy: 3.0.2 + fast-safe-stringify: 2.1.1 + help-me: 5.0.0 + joycon: 3.1.1 + minimist: 1.2.8 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pump: 3.0.4 + secure-json-parse: 2.7.0 + sonic-boom: 4.2.1 + strip-json-comments: 3.1.1 + pino-std-serializers@4.0.0: {} pino-std-serializers@7.1.0: {} + pino@10.0.0: + dependencies: + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + slow-redact: 0.3.2 + sonic-boom: 4.2.1 + thread-stream: 3.1.0 + + pino@10.1.0: + dependencies: + '@pinojs/redact': 0.4.0 + atomic-sleep: 1.0.0 + on-exit-leak-free: 2.1.2 + pino-abstract-transport: 2.0.0 + pino-std-serializers: 7.1.0 + process-warning: 5.0.0 + quick-format-unescaped: 4.0.4 + real-require: 0.2.0 + safe-stable-stringify: 2.5.0 + sonic-boom: 4.2.1 + thread-stream: 3.1.0 + pino@10.3.1: dependencies: '@pinojs/redact': 0.4.0 @@ -17574,41 +20603,43 @@ snapshots: pony-cause@2.1.11: {} - porto@0.2.35(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)): + porto@0.2.35(22b2b0b9fc59e99960931a8cc4834246): dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) hono: 4.10.7 idb-keyval: 6.2.2 mipd: 0.0.7(typescript@5.9.2) ox: 0.9.17(typescript@5.9.2)(zod@4.1.13) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) zod: 4.1.13 zustand: 5.0.3(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) optionalDependencies: '@tanstack/react-query': 5.90.11(react@19.2.1) react: 19.2.1 + react-native: 0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10) typescript: 5.9.2 - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10))(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(zod@4.1.13) transitivePeerDependencies: - '@types/react' - immer - use-sync-external-store - porto@0.2.35(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76)): + porto@0.2.35(8943dcca3736e121a930ece2db280a96): dependencies: - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) hono: 4.10.7 idb-keyval: 6.2.2 mipd: 0.0.7(typescript@5.9.2) ox: 0.9.17(typescript@5.9.2)(zod@4.1.13) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zod: 4.1.13 zustand: 5.0.3(@types/react@19.1.12)(react@19.2.1)(use-sync-external-store@1.4.0(react@19.2.1)) optionalDependencies: '@tanstack/react-query': 5.90.11(react@19.2.1) react: 19.2.1 + react-native: 0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10) typescript: 5.9.2 - wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + wagmi: 2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10))(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) transitivePeerDependencies: - '@types/react' - immer @@ -17618,13 +20649,13 @@ snapshots: possible-typed-array-names@1.1.0: {} - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(yaml@2.8.1): + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.1): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.6.1 postcss: 8.5.6 - tsx: 4.20.5 + tsx: 4.21.0 yaml: 2.8.1 postcss@8.4.31: @@ -17641,7 +20672,7 @@ snapshots: preact@10.24.2: {} - preact@10.27.2: {} + preact@10.29.1: {} prelude-ls@1.2.1: {} @@ -17653,6 +20684,12 @@ snapshots: prettier@3.5.2: {} + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + process-nextick-args@2.0.1: {} process-warning@1.0.0: {} @@ -17661,12 +20698,31 @@ snapshots: process-warning@5.0.0: {} + promise@8.3.0: + dependencies: + asap: 2.0.6 + prop-types@15.8.1: dependencies: loose-envify: 1.4.0 object-assign: 4.1.1 react-is: 16.13.1 + protobufjs@7.5.4: + 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': 22.19.17 + long: 5.3.1 + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -17681,8 +20737,25 @@ snapshots: end-of-stream: 1.4.5 once: 1.4.0 + pump@3.0.4: + dependencies: + end-of-stream: 1.4.5 + once: 1.4.0 + punycode@2.3.1: {} + pvtsutils@1.3.6: + dependencies: + tslib: 2.8.1 + + pvutils@1.1.5: {} + + qr-code-styling@1.6.0-rc.1: + dependencies: + qrcode-generator: 1.5.2 + + qrcode-generator@1.5.2: {} + qrcode@1.5.3: dependencies: dijkstrajs: 1.0.3 @@ -17706,6 +20779,12 @@ snapshots: quansync@0.2.11: {} + query-string@6.13.5: + dependencies: + decode-uri-component: 0.2.2 + split-on-first: 1.1.0 + strict-uri-encode: 2.0.0 + query-string@7.1.3: dependencies: decode-uri-component: 0.2.2 @@ -17715,6 +20794,10 @@ snapshots: queue-microtask@1.2.3: {} + queue@6.0.2: + dependencies: + inherits: 2.0.4 + quick-format-unescaped@4.0.4: {} quick-lru@5.1.1: {} @@ -17741,6 +20824,14 @@ snapshots: iconv-lite: 0.7.2 unpipe: 1.0.0 + react-devtools-core@6.1.5(bufferutil@4.0.9)(utf-8-validate@5.0.10): + dependencies: + shell-quote: 1.8.3 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - bufferutil + - utf-8-validate + react-dom@19.2.1(react@19.2.1): dependencies: react: 19.2.1 @@ -17753,6 +20844,104 @@ snapshots: react-is@16.13.1: {} + react-is@18.3.1: {} + + react-native-get-random-values@1.11.0(react-native@0.85.0(@babel/core@7.28.3)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10)): + dependencies: + fast-base64-decode: 1.0.0 + react-native: 0.85.0(@babel/core@7.28.3)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10) + + react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10): + dependencies: + '@react-native/assets-registry': 0.85.0 + '@react-native/codegen': 0.85.0(@babel/core@7.28.3) + '@react-native/community-cli-plugin': 0.85.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@react-native/gradle-plugin': 0.85.0 + '@react-native/js-polyfills': 0.85.0 + '@react-native/normalize-colors': 0.85.0 + '@react-native/virtualized-lists': 0.85.0(@types/react@19.1.12)(react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10))(react@19.2.1) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + babel-plugin-syntax-hermes-parser: 0.33.3 + base64-js: 1.5.1 + commander: 12.1.0 + flow-enums-runtime: 0.0.6 + hermes-compiler: 250829098.0.10 + invariant: 2.2.4 + memoize-one: 5.2.1 + metro-runtime: 0.84.2 + metro-source-map: 0.84.2 + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 + react: 19.2.1 + react-devtools-core: 6.1.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) + react-refresh: 0.14.2 + regenerator-runtime: 0.13.11 + scheduler: 0.27.0 + semver: 7.7.4 + stacktrace-parser: 0.1.11 + tinyglobby: 0.2.15 + whatwg-fetch: 3.6.20 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + yargs: 17.7.2 + optionalDependencies: + '@types/react': 19.1.12 + transitivePeerDependencies: + - '@babel/core' + - '@react-native-community/cli' + - '@react-native/metro-config' + - bufferutil + - supports-color + - utf-8-validate + optional: true + + react-native@0.85.0(@babel/core@7.28.3)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10): + dependencies: + '@react-native/assets-registry': 0.85.0 + '@react-native/codegen': 0.85.0(@babel/core@7.28.3) + '@react-native/community-cli-plugin': 0.85.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@react-native/gradle-plugin': 0.85.0 + '@react-native/js-polyfills': 0.85.0 + '@react-native/normalize-colors': 0.85.0 + '@react-native/virtualized-lists': 0.85.0(react-native@0.85.0(@babel/core@7.28.3)(bufferutil@4.0.9)(react@19.2.3)(utf-8-validate@5.0.10))(react@19.2.3) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + babel-plugin-syntax-hermes-parser: 0.33.3 + base64-js: 1.5.1 + commander: 12.1.0 + flow-enums-runtime: 0.0.6 + hermes-compiler: 250829098.0.10 + invariant: 2.2.4 + memoize-one: 5.2.1 + metro-runtime: 0.84.2 + metro-source-map: 0.84.2 + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 + react: 19.2.3 + react-devtools-core: 6.1.5(bufferutil@4.0.9)(utf-8-validate@5.0.10) + react-refresh: 0.14.2 + regenerator-runtime: 0.13.11 + scheduler: 0.27.0 + semver: 7.7.4 + stacktrace-parser: 0.1.11 + tinyglobby: 0.2.15 + whatwg-fetch: 3.6.20 + ws: 7.5.10(bufferutil@4.0.9)(utf-8-validate@5.0.10) + yargs: 17.7.2 + transitivePeerDependencies: + - '@babel/core' + - '@react-native-community/cli' + - '@react-native/metro-config' + - bufferutil + - supports-color + - utf-8-validate + + react-refresh@0.14.2: {} + react@19.2.1: {} react@19.2.3: {} @@ -17803,6 +20992,8 @@ snapshots: regenerate@1.4.2: {} + regenerator-runtime@0.13.11: {} + regexp.prototype.flags@1.5.4: dependencies: call-bind: 1.0.8 @@ -17861,6 +21052,8 @@ snapshots: reusify@1.1.0: {} + rfc4648@1.5.3: {} + rfdc@1.4.1: {} rollup@4.50.0: @@ -17906,9 +21099,9 @@ snapshots: '@types/uuid': 8.3.4 '@types/ws': 8.18.1 buffer: 6.0.3 - eventemitter3: 5.0.1 + eventemitter3: 5.0.4 uuid: 8.3.2 - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 @@ -17942,7 +21135,7 @@ snapshots: es-errors: 1.3.0 is-regex: 1.2.1 - safe-regex2@5.0.0: + safe-regex2@5.1.0: dependencies: ret: 0.5.0 @@ -17956,6 +21149,8 @@ snapshots: scheduler@0.27.0: {} + secure-json-parse@2.7.0: {} + secure-json-parse@4.1.0: {} semver@6.3.1: {} @@ -17964,6 +21159,8 @@ snapshots: semver@7.7.3: {} + semver@7.7.4: {} + send@0.19.0: dependencies: debug: 2.6.9 @@ -17998,6 +21195,8 @@ snapshots: transitivePeerDependencies: - supports-color + serialize-error@2.1.0: {} + serve-static@1.16.2: dependencies: encodeurl: 2.0.0 @@ -18048,7 +21247,7 @@ snapshots: dependencies: inherits: 2.0.4 safe-buffer: 5.2.1 - to-buffer: 1.2.1 + to-buffer: 1.2.2 sharp@0.34.5: dependencies: @@ -18088,6 +21287,8 @@ snapshots: shebang-regex@3.0.0: {} + shell-quote@1.8.3: {} + side-channel-list@1.0.0: dependencies: es-errors: 1.3.0 @@ -18120,16 +21321,10 @@ snapshots: signal-exit@4.1.0: {} - siwe@2.3.2(ethers@6.16.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)): - dependencies: - '@spruceid/siwe-parser': 2.1.2 - '@stablelib/random': 1.0.2 - ethers: 6.16.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) - uri-js: 4.4.1 - valid-url: 1.0.9 - slash@3.0.0: {} + slow-redact@0.3.2: {} + snake-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -18163,10 +21358,21 @@ snapshots: source-map-js@1.2.1: {} + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.5.7: {} + + source-map@0.6.1: {} + source-map@0.8.0-beta.0: dependencies: whatwg-url: 7.1.0 + spark-md5@3.0.2: {} + spawndamnit@3.0.1: dependencies: cross-spawn: 7.0.6 @@ -18191,6 +21397,14 @@ snapshots: stackback@0.0.2: {} + stackframe@1.3.4: {} + + stacktrace-parser@0.1.11: + dependencies: + type-fest: 0.7.1 + + statuses@1.5.0: {} + statuses@2.0.1: {} statuses@2.0.2: {} @@ -18290,6 +21504,10 @@ snapshots: dependencies: ansi-regex: 6.2.0 + strip-ansi@7.1.2: + dependencies: + ansi-regex: 6.2.2 + strip-bom@3.0.0: {} strip-json-comments@3.1.1: {} @@ -18323,6 +21541,10 @@ snapshots: dependencies: has-flag: 4.0.0 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} svg-parser@2.0.4: {} @@ -18351,6 +21573,13 @@ snapshots: term-size@2.2.1: {} + terser@5.46.1: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + text-encoding-utf-8@1.0.2: {} thenify-all@1.6.0: @@ -18365,10 +21594,16 @@ snapshots: dependencies: real-require: 0.1.0 + thread-stream@3.1.0: + dependencies: + real-require: 0.2.0 + thread-stream@4.0.0: dependencies: real-require: 0.2.0 + throat@5.0.0: {} + tinybench@2.9.0: {} tinyexec@0.3.2: {} @@ -18391,19 +21626,13 @@ snapshots: tldts-core@6.1.86: {} - tldts-core@7.0.19: - optional: true - tldts@6.1.86: dependencies: tldts-core: 6.1.86 - tldts@7.0.19: - dependencies: - tldts-core: 7.0.19 - optional: true + tmpl@1.0.5: {} - to-buffer@1.2.1: + to-buffer@1.2.2: dependencies: isarray: 2.0.5 safe-buffer: 5.2.1 @@ -18423,11 +21652,6 @@ snapshots: dependencies: tldts: 6.1.86 - tough-cookie@6.0.0: - dependencies: - tldts: 7.0.19 - optional: true - tr46@0.0.3: {} tr46@1.0.1: @@ -18438,11 +21662,6 @@ snapshots: dependencies: punycode: 2.3.1 - tr46@6.0.0: - dependencies: - punycode: 2.3.1 - optional: true - tree-kill@1.2.2: {} ts-api-utils@2.1.0(typescript@5.9.2): @@ -18464,22 +21683,20 @@ snapshots: tslib@1.14.1: {} - tslib@2.7.0: {} - tslib@2.8.1: {} - tsup@8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(typescript@5.9.2)(yaml@2.8.1): + tsup@8.5.0(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(typescript@5.9.2)(yaml@2.8.1): dependencies: - bundle-require: 5.1.0(esbuild@0.25.9) + bundle-require: 5.1.0(esbuild@0.25.12) cac: 6.7.14 chokidar: 4.0.3 consola: 3.4.2 debug: 4.4.1 - esbuild: 0.25.9 + esbuild: 0.25.12 fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.5)(yaml@2.8.1) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.21.0)(yaml@2.8.1) resolve-from: 5.0.0 rollup: 4.50.0 source-map: 0.8.0-beta.0 @@ -18496,9 +21713,9 @@ snapshots: - tsx - yaml - tsx@4.20.5: + tsx@4.21.0: dependencies: - esbuild: 0.25.9 + esbuild: 0.27.7 get-tsconfig: 4.10.1 optionalDependencies: fsevents: 2.3.3 @@ -18530,12 +21747,18 @@ snapshots: turbo-windows-64: 2.5.6 turbo-windows-arm64: 2.5.6 + tweetnacl-ts@1.0.3: + dependencies: + tslib: 1.14.1 + tweetnacl@1.0.3: {} type-check@0.4.0: dependencies: prelude-ls: 1.2.1 + type-fest@0.7.1: {} + type-is@1.6.18: dependencies: media-typer: 0.3.0 @@ -18580,6 +21803,10 @@ snapshots: possible-typed-array-names: 1.1.0 reflect.getprototypeof: 1.0.10 + typedarray-to-buffer@3.1.5: + dependencies: + is-typedarray: 1.0.0 + typescript-eslint@8.49.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2): dependencies: '@typescript-eslint/eslint-plugin': 8.49.0(@typescript-eslint/parser@8.49.0(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2))(eslint@9.34.0(jiti@2.6.1))(typescript@5.9.2) @@ -18599,6 +21826,10 @@ snapshots: dependencies: multiformats: 9.9.0 + uint8arrays@3.1.1: + dependencies: + multiformats: 9.9.0 + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -18608,12 +21839,8 @@ snapshots: uncrypto@0.1.3: {} - undici-types@6.19.8: {} - undici-types@6.21.0: {} - undici-types@7.16.0: {} - undici-types@7.22.0: {} unicode-canonical-property-names-ecmascript@2.0.1: {} @@ -18701,6 +21928,8 @@ snapshots: dependencies: node-gyp-build: 4.8.4 + utf8@3.0.0: {} + util-deprecate@1.0.2: {} util@0.12.5: @@ -18717,8 +21946,6 @@ snapshots: uuid@9.0.1: {} - valid-url@1.0.9: {} - valtio@1.13.2(@types/react@19.1.12)(react@19.2.1): dependencies: derive-valtio: 0.1.0(valtio@1.13.2(@types/react@19.1.12)(react@19.2.1)) @@ -18756,16 +21983,16 @@ snapshots: - utf-8-validate - zod - viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76): + viem@2.23.2(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13): dependencies: - '@noble/curves': 1.9.1 - '@noble/hashes': 1.8.0 - '@scure/bip32': 1.7.0 - '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.9.2)(zod@3.25.76) - isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.9.3(typescript@5.9.2)(zod@3.25.76) - ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) + '@noble/curves': 1.8.1 + '@noble/hashes': 1.7.1 + '@scure/bip32': 1.6.2 + '@scure/bip39': 1.5.4 + abitype: 1.0.8(typescript@5.9.2)(zod@4.1.13) + isows: 1.0.6(ws@8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10)) + ox: 0.6.7(typescript@5.9.2)(zod@4.1.13) + ws: 8.18.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -18773,15 +22000,15 @@ snapshots: - utf-8-validate - zod - viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76): + viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.1.0(typescript@5.9.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.9.2)(zod@3.22.4) isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.9.6(typescript@5.9.2)(zod@3.25.76) + ox: 0.14.20(typescript@5.9.2)(zod@3.22.4) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.9.2 @@ -18790,15 +22017,15 @@ snapshots: - utf-8-validate - zod - viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.22.4): + viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.2)(zod@3.22.4) + abitype: 1.2.3(typescript@5.9.2)(zod@3.25.76) isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.11.3(typescript@5.9.2)(zod@3.22.4) + ox: 0.14.20(typescript@5.9.2)(zod@3.25.76) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.9.2 @@ -18807,15 +22034,15 @@ snapshots: - utf-8-validate - zod - viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76): + viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13): dependencies: '@noble/curves': 1.9.1 '@noble/hashes': 1.8.0 '@scure/bip32': 1.7.0 '@scure/bip39': 1.6.0 - abitype: 1.2.3(typescript@5.9.2)(zod@3.25.76) + abitype: 1.2.3(typescript@5.9.2)(zod@4.1.13) isows: 1.0.7(ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10)) - ox: 0.11.3(typescript@5.9.2)(zod@3.25.76) + ox: 0.14.20(typescript@5.9.2)(zod@4.1.13) ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: typescript: 5.9.2 @@ -18824,13 +22051,34 @@ snapshots: - utf-8-validate - zod - vite-node@3.2.4(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1): + vite-node@3.2.4(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1): dependencies: cac: 6.7.14 - debug: 4.4.3 + debug: 4.4.1 + es-module-lexer: 1.7.0 + pathe: 2.0.3 + vite: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) + transitivePeerDependencies: + - '@types/node' + - jiti + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vite-node@3.2.4(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1): + dependencies: + cac: 6.7.14 + debug: 4.4.1 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + vite: 6.3.5(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - '@types/node' - jiti @@ -18845,62 +22093,134 @@ snapshots: - tsx - yaml - vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)): + vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)): + dependencies: + debug: 4.4.1 + globrex: 0.1.2 + tsconfck: 3.1.6(typescript@5.9.2) + optionalDependencies: + vite: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) + transitivePeerDependencies: + - supports-color + - typescript + + vite-tsconfig-paths@5.1.4(typescript@5.9.2)(vite@6.3.5(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)): dependencies: debug: 4.4.1 globrex: 0.1.2 tsconfck: 3.1.6(typescript@5.9.2) optionalDependencies: - vite: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + vite: 6.3.5(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) transitivePeerDependencies: - supports-color - typescript - vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1): + vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1): dependencies: - esbuild: 0.25.9 + esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 rollup: 4.50.0 - tinyglobby: 0.2.15 + tinyglobby: 0.2.14 optionalDependencies: '@types/node': 22.18.0 fsevents: 2.3.3 jiti: 2.6.1 lightningcss: 1.30.2 - tsx: 4.20.5 + terser: 5.46.1 + tsx: 4.21.0 yaml: 2.8.1 - vitest@3.2.4(@types/debug@4.1.12)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1): + vite@6.3.5(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1): + dependencies: + esbuild: 0.25.12 + fdir: 6.5.0(picomatch@4.0.3) + picomatch: 4.0.3 + postcss: 8.5.6 + rollup: 4.50.0 + tinyglobby: 0.2.14 + optionalDependencies: + '@types/node': 22.19.17 + fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + terser: 5.46.1 + tsx: 4.21.0 + yaml: 2.8.1 + + vitest@3.2.4(@types/debug@4.1.13)(@types/node@22.18.0)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1)) + '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 '@vitest/spy': 3.2.4 '@vitest/utils': 3.2.4 chai: 5.3.3 - debug: 4.4.3 + debug: 4.4.1 expect-type: 1.2.2 - magic-string: 0.30.21 + magic-string: 0.30.18 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.15 + tinyglobby: 0.2.14 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) - vite-node: 3.2.4(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(tsx@4.20.5)(yaml@2.8.1) + vite: 6.3.5(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@22.18.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) why-is-node-running: 2.3.0 optionalDependencies: - '@types/debug': 4.1.12 + '@types/debug': 4.1.13 '@types/node': 22.18.0 - jsdom: 27.4.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) + transitivePeerDependencies: + - jiti + - less + - lightningcss + - msw + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - tsx + - yaml + + vitest@3.2.4(@types/debug@4.1.13)(@types/node@22.19.17)(jiti@2.6.1)(jsdom@26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10))(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1): + dependencies: + '@types/chai': 5.2.2 + '@vitest/expect': 3.2.4 + '@vitest/mocker': 3.2.4(vite@6.3.5(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1)) + '@vitest/pretty-format': 3.2.4 + '@vitest/runner': 3.2.4 + '@vitest/snapshot': 3.2.4 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + debug: 4.4.1 + expect-type: 1.2.2 + magic-string: 0.30.18 + pathe: 2.0.3 + picomatch: 4.0.3 + std-env: 3.9.0 + tinybench: 2.9.0 + tinyexec: 0.3.2 + tinyglobby: 0.2.14 + tinypool: 1.1.1 + tinyrainbow: 2.0.0 + vite: 6.3.5(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) + vite-node: 3.2.4(@types/node@22.19.17)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.46.1)(tsx@4.21.0)(yaml@2.8.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@types/debug': 4.1.13 + '@types/node': 22.19.17 + jsdom: 26.1.0(bufferutil@4.0.9)(utf-8-validate@5.0.10) transitivePeerDependencies: - jiti - less @@ -18915,18 +22235,22 @@ snapshots: - tsx - yaml + vlq@1.0.1: {} + + vlq@2.0.4: {} + w3c-xmlserializer@5.0.0: dependencies: xml-name-validator: 5.0.0 - wagmi@2.16.9(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76): + wagmi@2.16.9(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.3))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76): dependencies: '@tanstack/react-query': 5.90.11(react@19.2.3) - '@wagmi/connectors': 5.9.9(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) - '@wagmi/core': 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/connectors': 5.9.9(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76) + '@wagmi/core': 2.20.3(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.3)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.3))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) react: 19.2.3 use-sync-external-store: 1.4.0(react@19.2.3) - viem: 2.37.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -18958,14 +22282,14 @@ snapshots: - utf-8-validate - zod - wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76): + wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10))(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76): dependencies: '@tanstack/react-query': 5.90.11(react@19.2.1) - '@wagmi/connectors': 6.2.0(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76))(zod@3.25.76) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/connectors': 6.2.0(b93a2b74079d10fd55412ca63eb44a93) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) react: 19.2.1 use-sync-external-store: 1.4.0(react@19.2.1) - viem: 2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -19003,14 +22327,14 @@ snapshots: - utf-8-validate - zod - wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76): + wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react-native@0.85.0(@babel/core@7.28.3)(@types/react@19.1.12)(bufferutil@4.0.9)(react@19.2.1)(utf-8-validate@5.0.10))(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13))(zod@4.1.13): dependencies: '@tanstack/react-query': 5.90.11(react@19.2.1) - '@wagmi/connectors': 6.2.0(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(@wagmi/core@2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)))(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(utf-8-validate@5.0.10)(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(wagmi@2.19.5(@tanstack/query-core@5.90.11)(@tanstack/react-query@5.90.11(react@19.2.1))(@types/react@19.1.12)(@vercel/functions@2.2.13)(bufferutil@4.0.9)(fastestsmallesttextencoderdecoder@1.0.22)(react@19.2.1)(typescript@5.9.2)(utf-8-validate@5.0.10)(viem@2.40.3(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76))(zod@3.25.76))(zod@3.25.76) - '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76)) + '@wagmi/connectors': 6.2.0(8ca0b565c60a9a741f268dc26c5db471) + '@wagmi/core': 2.22.1(@tanstack/query-core@5.90.11)(@types/react@19.1.12)(react@19.2.1)(typescript@5.9.2)(use-sync-external-store@1.4.0(react@19.2.1))(viem@2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13)) react: 19.2.1 use-sync-external-store: 1.4.0(react@19.2.1) - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@4.1.13) optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: @@ -19048,6 +22372,10 @@ snapshots: - utf-8-validate - zod + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + webextension-polyfill@0.10.0: {} webidl-conversions@3.0.1: {} @@ -19056,13 +22384,12 @@ snapshots: webidl-conversions@7.0.0: {} - webidl-conversions@8.0.1: - optional: true - whatwg-encoding@3.1.1: dependencies: iconv-lite: 0.6.3 + whatwg-fetch@3.6.20: {} + whatwg-mimetype@4.0.0: {} whatwg-url@14.2.0: @@ -19070,12 +22397,6 @@ snapshots: tr46: 5.1.1 webidl-conversions: 7.0.0 - whatwg-url@15.1.0: - dependencies: - tr46: 6.0.0 - webidl-conversions: 8.0.1 - optional: true - whatwg-url@5.0.0: dependencies: tr46: 0.0.3 @@ -19166,6 +22487,11 @@ snapshots: bufferutil: 4.0.9 utf-8-validate: 5.0.10 + ws@7.5.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): + optionalDependencies: + bufferutil: 4.0.9 + utf-8-validate: 5.0.10 + ws@8.17.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.9 @@ -19181,7 +22507,7 @@ snapshots: bufferutil: 4.0.9 utf-8-validate: 5.0.10 - ws@8.19.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): + ws@8.20.0(bufferutil@4.0.9)(utf-8-validate@5.0.10): optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 @@ -19192,7 +22518,7 @@ snapshots: axios: 1.11.0 express: 4.21.2 hono: 4.10.7 - viem: 2.45.1(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) + viem: 2.48.11(bufferutil@4.0.9)(typescript@5.9.2)(utf-8-validate@5.0.10)(zod@3.25.76) zod: 3.25.76 transitivePeerDependencies: - bufferutil @@ -19211,16 +22537,19 @@ snapshots: y18n@4.0.3: {} + y18n@5.0.8: {} + yallist@3.1.1: {} - yaml@2.8.1: - optional: true + yaml@2.8.1: {} yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 decamelize: 1.2.0 + yargs-parser@21.1.1: {} + yargs@15.4.1: dependencies: cliui: 6.0.0 @@ -19235,6 +22564,16 @@ snapshots: y18n: 4.0.3 yargs-parser: 18.1.3 + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + yocto-queue@0.1.0: {} zod-to-json-schema@3.25.1(zod@3.25.76): diff --git a/typescript/pnpm-workspace.yaml b/typescript/pnpm-workspace.yaml index d46c0d7901..29f4a25852 100644 --- a/typescript/pnpm-workspace.yaml +++ b/typescript/pnpm-workspace.yaml @@ -5,8 +5,18 @@ packages: - packages/http/* - packages/mechanisms/* - packages/legacy/* - - examples/facilitator - examples/**/* - site -ignoredBuiltDependencies: - - esbuild +overrides: + cssstyle: 5.3.6 +minimumReleaseAge: 4320 # Only install package versions that have been published for at least 3 days. +minimumReleaseAgeStrict: true +allowBuilds: + bigint-buffer: true + bufferutil: true + esbuild: true + keccak: true + protobufjs: true + sharp: true + unrs-resolver: true + utf-8-validate: true diff --git a/typescript/site/README.md b/typescript/site/README.md index 0a25a2157b..48b24541ff 100644 --- a/typescript/site/README.md +++ b/typescript/site/README.md @@ -9,7 +9,7 @@ x402 is an open protocol for internet-native payments built around the HTTP 402 - Payment-gated content access - Real-time payment verification - Payment settlement -- Integration with EVM-compatible blockchains +- Integration with EVM, SVM, and AVM blockchains ## Features @@ -38,8 +38,10 @@ x402 is an open protocol for internet-native payments built around the HTTP 402 FACILITATOR_URL=your_facilitator_url RESOURCE_EVM_ADDRESS=your_evm_wallet_address RESOURCE_SVM_ADDRESS=your_solana_wallet_address + RESOURCE_AVM_ADDRESS=your_algorand_wallet_address FACILITATOR_EVM_PRIVATE_KEY=your_evm_private_key FACILITATOR_SVM_PRIVATE_KEY=your_solana_private_key + FACILITATOR_AVM_PRIVATE_KEY=your_algorand_private_key ``` ### Running the Development Server @@ -151,7 +153,7 @@ We welcome projects that are building with x402! To add your project to our ecos To learn more about the technologies used in this project: - [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API -- [x402 Protocol Documentation](https://github.com/coinbase/x402) - learn about the x402 payment protocol +- [x402 Protocol Documentation](https://github.com/x402-foundation/x402) - learn about the x402 payment protocol - [EVM Documentation](https://ethereum.org/en/developers/docs/) - learn about Ethereum Virtual Machine ## Deploy on Vercel @@ -162,8 +164,8 @@ Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/bui ## Contributing -We welcome contributions! Please see our [Contributing Guidelines](https://github.com/coinbase/x402/blob/main/CONTRIBUTING.md) for details. +We welcome contributions! Please see our [Contributing Guidelines](https://github.com/x402-foundation/x402/blob/main/CONTRIBUTING.md) for details. ## License -This project is licensed under the MIT License - see the [LICENSE](https://github.com/coinbase/x402/blob/main/LICENSE) file for details. +This project is licensed under the MIT License - see the [LICENSE](https://github.com/x402-foundation/x402/blob/main/LICENSE) file for details. diff --git a/typescript/site/app/api/well-known/api-catalog/route.ts b/typescript/site/app/api/well-known/api-catalog/route.ts new file mode 100644 index 0000000000..20fa6a2741 --- /dev/null +++ b/typescript/site/app/api/well-known/api-catalog/route.ts @@ -0,0 +1,43 @@ +/** + * Returns the API catalog in application/linkset+json format per RFC 9727. + * + * @returns API catalog response with linkset entries for x402 services + */ +export function GET() { + const catalog = { + linkset: [ + { + anchor: "https://x402.org/facilitator", + links: [ + { + rel: "service-desc", + href: "https://github.com/coinbase/x402", + }, + { + rel: "service-doc", + href: "https://x402.org/writing", + }, + ], + }, + { + anchor: "https://x402.org/protected", + links: [ + { + rel: "payment-required", + href: "https://x402.org/protected", + }, + { + rel: "service-desc", + href: "https://github.com/coinbase/x402", + }, + ], + }, + ], + }; + + return new Response(JSON.stringify(catalog), { + headers: { + "Content-Type": "application/linkset+json", + }, + }); +} diff --git a/typescript/site/app/components/CodeSnippet.tsx b/typescript/site/app/components/CodeSnippet.tsx index 36311eb12f..c09684c659 100644 --- a/typescript/site/app/components/CodeSnippet.tsx +++ b/typescript/site/app/components/CodeSnippet.tsx @@ -4,15 +4,18 @@ import { useState } from "react"; interface CodeSnippetProps { code: string; + /** If provided, this value is copied to clipboard instead of `code`. Use to + * show a compact display version while preserving properly-formatted copy. */ + copyCode?: string; title?: string; description?: string; } -export function CodeSnippet({ code, title, description }: CodeSnippetProps) { +export function CodeSnippet({ code, copyCode, title, description }: CodeSnippetProps) { const [copied, setCopied] = useState(false); const handleCopy = () => { - navigator.clipboard.writeText(code); + navigator.clipboard.writeText(copyCode ?? code); setCopied(true); setTimeout(() => setCopied(false), 2000); }; @@ -39,26 +42,58 @@ export function CodeSnippet({ code, title, description }: CodeSnippetProps) { fill="black" /> -

- {title} -

+

{title}

)} -
+
@@ -69,7 +104,7 @@ export function CodeSnippet({ code, title, description }: CodeSnippetProps) { fontFamily: '"DM Mono", monospace', fontStyle: "normal", fontWeight: 400, - lineHeight: "20px", + lineHeight: "18px", letterSpacing: "-0.7px", }} > @@ -79,9 +114,7 @@ export function CodeSnippet({ code, title, description }: CodeSnippetProps) {
{description && ( -

- {description} -

+

{description}

)}
diff --git a/typescript/site/app/components/Footer.tsx b/typescript/site/app/components/Footer.tsx index b3d9e526a4..84a84c2e82 100644 --- a/typescript/site/app/components/Footer.tsx +++ b/typescript/site/app/components/Footer.tsx @@ -52,7 +52,7 @@ export function Footer() { Ecosystem Writing @@ -65,6 +65,14 @@ export function Footer() { > Whitepaper + + Contact +
@@ -72,7 +80,7 @@ export function Footer() { {/* Social icons */}

- While x402 is an open and neutral standard, this website is maintained by - {" "}Coinbase Developer Platform. By using this site, you agree to be bound by the{" "} - - CDP Terms of Service - {" "} - and{" "} + Copyright © x402 a Series of LF Projects, LLC +
+ For web site terms of use, trademark policy and other project policies please see{" "} - Global Privacy Policy + https://lfprojects.org .

@@ -128,7 +128,7 @@ export function Footer() { alt="" aria-hidden="true" className="w-full h-auto" - style={{ filter: 'brightness(0.75)' }} + style={{ filter: "brightness(0.75)" }} />
diff --git a/typescript/site/app/components/HeroIllustration.tsx b/typescript/site/app/components/HeroIllustration.tsx index 49a8d24ae0..db17b48e16 100644 --- a/typescript/site/app/components/HeroIllustration.tsx +++ b/typescript/site/app/components/HeroIllustration.tsx @@ -18,7 +18,7 @@ export function HeroIllustration() { href="https://www.x402.org/protected" target="_blank" rel="noopener noreferrer" - className="absolute bottom-[260px] right-[190px] z-10" + className="absolute bottom-[300px] right-[190px] z-10" > -
+
+
{/* Animated left column */} x402 is an open, neutral standard for internet-native payments. It absolves the Internet's original sin by natively making payments possible between clients and @@ -44,20 +47,43 @@ export function HeroSection({ codeSnippet }: HeroSectionProps) { + + + +

+ Trusted by +

+
+
+ {Array.from({ length: 4 }).map((_, i) => ( + + ))} +
+
+ +
+ + {/* Stats pinned to the bottom of the left column — desktop only */} +
+

+ Last 30 days +

+
+ + + + +
+
- {/* Animated right column - only show at xl (1280px+) where there's room */} - +
- +
); diff --git a/typescript/site/app/components/NavBar.tsx b/typescript/site/app/components/NavBar.tsx index 390fdf95b2..acdc194caf 100644 --- a/typescript/site/app/components/NavBar.tsx +++ b/typescript/site/app/components/NavBar.tsx @@ -44,13 +44,7 @@ export function NavBar({ animateLogo = false }: NavBarProps): React.ReactElement {mobileMenuOpen ? ( ) : ( - + )} @@ -63,7 +57,7 @@ export function NavBar({ animateLogo = false }: NavBarProps): React.ReactElement Ecosystem Writing @@ -87,67 +81,73 @@ export function NavBar({ animateLogo = false }: NavBarProps): React.ReactElement {/* Desktop: Right side actions */}
- {/* Docs button */} - - + + + - - Docs - + xmlns="http://www.w3.org/2000/svg" + aria-hidden="true" + > + + + +
- {/* Build with us button */} - - - Contact - + + Get Started + +
{/* Mobile: Spacer to balance hamburger */} @@ -169,7 +169,7 @@ export function NavBar({ animateLogo = false }: NavBarProps): React.ReactElement Ecosystem setMobileMenuOpen(false)} > @@ -192,22 +192,13 @@ export function NavBar({ animateLogo = false }: NavBarProps): React.ReactElement {/* CTA buttons */}
setMobileMenuOpen(false)} - > - Docs - - setMobileMenuOpen(false)} > - Contact + Get Started
diff --git a/typescript/site/app/components/StatsSection.tsx b/typescript/site/app/components/StatsSection.tsx index d9ff43ab03..a8125690e5 100644 --- a/typescript/site/app/components/StatsSection.tsx +++ b/typescript/site/app/components/StatsSection.tsx @@ -10,7 +10,7 @@ interface StatsData { sellers: string; } -const STATIC_STATS: StatsData = { +export const STATIC_STATS: StatsData = { transactions: "75.41M", volume: "$24.24M", buyers: "94.06K", @@ -22,7 +22,7 @@ interface StatItemProps { label: string; } -function StatItem({ value, label }: StatItemProps) { +export function StatItem({ value, label }: StatItemProps) { return (
@@ -33,7 +33,7 @@ function StatItem({ value, label }: StatItemProps) { ); } -const brands = [ +export const brands = [ { name: "Stripe", logo: "/logos/stripe-mono.svg" }, { name: "AWS", logo: "/logos/aws.-mono.svg", className: "h-8" }, { name: "Messari", logo: "/logos/messari-mono.svg" }, @@ -42,12 +42,13 @@ const brands = [ { name: "Vercel", logo: "/logos/vercel-mono.svg" }, { name: "Cloudflare", logo: "/logos/cloudflare-mono.svg", className: "h-7" }, { name: "World", logo: "/logos/world-mono.svg" }, + { name: "Quicknode", logo: "/logos/quicknode-mono.svg", className: "h-7" }, ]; -function BrandSet() { +export function BrandSet() { return (
- {brands.map((brand) => ( + {brands.map(brand => ( +

Last 30 days

@@ -71,19 +75,6 @@ export function StatsSection() {
- -
- -

Adopted by

-
-
- {Array.from({ length: 4 }).map((_, i) => ( - - ))} -
-
- -
); } diff --git a/typescript/site/app/ecosystem/partners-data/alchemy/metadata.json b/typescript/site/app/ecosystem/partners-data/alchemy/metadata.json index 908c8f5327..af3d9187e8 100644 --- a/typescript/site/app/ecosystem/partners-data/alchemy/metadata.json +++ b/typescript/site/app/ecosystem/partners-data/alchemy/metadata.json @@ -3,6 +3,5 @@ "description": "Alchemy integrates x402 to enable monetized access to their blockchain developer platform, allowing AI agents and applications to pay for RPC calls and web3 APIs using stablecoins.", "logoUrl": "/logos/alchemy.png", "websiteUrl": "https://agents.alchemy.com/?utm_source=x&utm_medium=social&utm_campaign=x402", - "category": "Infrastructure & Tooling", - "top_section": true + "category": "Infrastructure & Tooling" } diff --git a/typescript/site/app/ecosystem/partners-data/axios-fetch-clients/metadata.json b/typescript/site/app/ecosystem/partners-data/axios-fetch-clients/metadata.json index d0a882bf0c..38ed27d1bc 100644 --- a/typescript/site/app/ecosystem/partners-data/axios-fetch-clients/metadata.json +++ b/typescript/site/app/ecosystem/partners-data/axios-fetch-clients/metadata.json @@ -3,5 +3,5 @@ "category": "Client-Side Integrations", "logoUrl": "/logos/axios-fetch-clients.png", "description": "Reference TypeScript clients for x402 using both Axios and Fetch. Easily integrate x402 payments into your own applications.", - "websiteUrl": "https://github.com/coinbase/x402/tree/main/examples/typescript/clients" + "websiteUrl": "https://github.com/x402-foundation/x402/tree/main/examples/typescript/clients" } \ No newline at end of file diff --git a/typescript/site/app/ecosystem/partners-data/exa/metadata.json b/typescript/site/app/ecosystem/partners-data/exa/metadata.json new file mode 100644 index 0000000000..3b157d7f84 --- /dev/null +++ b/typescript/site/app/ecosystem/partners-data/exa/metadata.json @@ -0,0 +1,8 @@ +{ + "name": "Exa", + "description": "Exa is an AI-native search engine that provides high-quality web data through its API, enabling AI agents and applications to search and retrieve content from the web.", + "logoUrl": "/logos/exa-ai.svg", + "websiteUrl": "https://exa.ai/", + "category": "Services/Endpoints", + "top_section": true +} diff --git a/typescript/site/app/ecosystem/partners-data/mcp-example/metadata.json b/typescript/site/app/ecosystem/partners-data/mcp-example/metadata.json index e79718aa9e..dd22fbddb8 100644 --- a/typescript/site/app/ecosystem/partners-data/mcp-example/metadata.json +++ b/typescript/site/app/ecosystem/partners-data/mcp-example/metadata.json @@ -3,5 +3,5 @@ "category": "Infrastructure & Tooling", "logoUrl": "/logos/mcp-example.png", "description": "A reference implementation MCP server and wallet to call x402 endpoints. Explore the code and run your own server.", - "websiteUrl": "https://github.com/coinbase/x402/tree/main/examples/typescript/mcp" + "websiteUrl": "https://github.com/x402-foundation/x402/tree/main/examples/typescript/mcp" } \ No newline at end of file diff --git a/typescript/site/app/ecosystem/partners-data/messari/metadata.json b/typescript/site/app/ecosystem/partners-data/messari/metadata.json index fd55780f5f..280bebc6a1 100644 --- a/typescript/site/app/ecosystem/partners-data/messari/metadata.json +++ b/typescript/site/app/ecosystem/partners-data/messari/metadata.json @@ -3,6 +3,5 @@ "description": "Messari leverages x402 to gate access to their professional-grade crypto intelligence and research APIs, enabling pay-per-use access to on-chain data and market analytics.", "logoUrl": "/logos/messari.png", "websiteUrl": "https://messari.io/x402", - "category": "Infrastructure & Tooling", - "top_section": true + "category": "Infrastructure & Tooling" } diff --git a/typescript/site/app/ecosystem/partners-data/node-servers/metadata.json b/typescript/site/app/ecosystem/partners-data/node-servers/metadata.json index a20272d495..5ec0d11c78 100644 --- a/typescript/site/app/ecosystem/partners-data/node-servers/metadata.json +++ b/typescript/site/app/ecosystem/partners-data/node-servers/metadata.json @@ -3,5 +3,5 @@ "category": "Infrastructure & Tooling", "logoUrl": "/logos/node-servers.png", "description": "Reference x402 server implementations in Node.js using Hono and Express, plus an advanced example with dynamic pricing and complex logic.", - "websiteUrl": "https://github.com/coinbase/x402/tree/main/examples/typescript/servers" + "websiteUrl": "https://github.com/x402-foundation/x402/tree/main/examples/typescript/servers" } \ No newline at end of file diff --git a/typescript/site/app/ecosystem/partners-data/openpayment/metadata.json b/typescript/site/app/ecosystem/partners-data/openpayment/metadata.json new file mode 100644 index 0000000000..6fe45f5234 --- /dev/null +++ b/typescript/site/app/ecosystem/partners-data/openpayment/metadata.json @@ -0,0 +1,7 @@ +{ + "name": "OpenPayment", + "description": "OpenPayment is a stablecoin payment link platform for sales, subscriptions, donations, paywalls, and agent-driven payments, with wallet-native checkout and direct USDC settlement powered by x402.", + "logoUrl": "/logos/openpayment.png", + "websiteUrl": "https://openpayment.link", + "category": "Client-Side Integrations" +} diff --git a/typescript/site/app/ecosystem/partners-data/polygon-facilitator/metadata.json b/typescript/site/app/ecosystem/partners-data/polygon-facilitator/metadata.json new file mode 100644 index 0000000000..a39188796c --- /dev/null +++ b/typescript/site/app/ecosystem/partners-data/polygon-facilitator/metadata.json @@ -0,0 +1,19 @@ +{ + "name": "Polygon Facilitator", + "description": "Production-grade x402 facilitator for Polygon networks. Supports EIP-3009 USDC payments with verify and settle capabilities on Polygon Mainnet and Polygon Amoy testnet.", + "logoUrl": "/logos/polygon.png", + "websiteUrl": "https://docs.polygon.technology/payment-services/agentic-payments/x402/intro/", + "category": "Facilitators", + "facilitator": { + "baseUrl": "https://x402.polygon.technology", + "networks": ["polygon", "polygon-amoy"], + "schemes": ["exact"], + "assets": ["EIP-3009"], + "supports": { + "verify": true, + "settle": true, + "supported": true, + "list": false + } + } +} diff --git a/typescript/site/app/ecosystem/partners-data/ultravioleta-dao/metadata.json b/typescript/site/app/ecosystem/partners-data/ultravioleta-dao/metadata.json new file mode 100644 index 0000000000..309daf51e5 --- /dev/null +++ b/typescript/site/app/ecosystem/partners-data/ultravioleta-dao/metadata.json @@ -0,0 +1,54 @@ +{ + "name": "Ultravioleta DAO", + "description": "Production-grade multi-chain facilitator in Rust supporting 19 mainnets across 7 blockchain families with 5 stablecoins, commerce settlements, and ERC-8004 reputation.", + "logoUrl": "/logos/ultravioleta-dao.png", + "websiteUrl": "https://facilitator.ultravioletadao.xyz", + "category": "Facilitators", + "facilitator": { + "baseUrl": "https://facilitator.ultravioletadao.xyz", + "networks": [ + "base", + "base-sepolia", + "ethereum", + "arbitrum", + "arbitrum-sepolia", + "avalanche", + "avalanche-fuji", + "polygon", + "polygon-amoy", + "optimism", + "optimism-sepolia", + "celo", + "celo-sepolia", + "bsc", + "unichain", + "unichain-sepolia", + "monad", + "hyperevm", + "hyperevm-testnet", + "scroll", + "skale-base", + "skale-base-sepolia", + "solana", + "solana-devnet", + "sui", + "sui-testnet", + "fogo", + "fogo-testnet", + "near", + "near-testnet", + "stellar", + "stellar-testnet", + "algorand", + "algorand-testnet" + ], + "schemes": ["exact", "commerce", "upto"], + "assets": ["EIP-3009", "SPL", "Sui::Coin", "NEAR", "Stellar", "Algorand"], + "supports": { + "verify": true, + "settle": true, + "supported": true, + "list": false + } + } +} diff --git a/typescript/site/app/ecosystem/partners-data/venice/metadata.json b/typescript/site/app/ecosystem/partners-data/venice/metadata.json new file mode 100644 index 0000000000..77bb610f6b --- /dev/null +++ b/typescript/site/app/ecosystem/partners-data/venice/metadata.json @@ -0,0 +1,8 @@ +{ + "name": "Venice", + "description": "Venice is a private and permissionless AI platform that provides access to open-source AI models, enabling uncensored inference, image generation, and code assistance without data retention.", + "logoUrl": "/logos/venice.svg", + "websiteUrl": "https://venice.ai/", + "category": "Services/Endpoints", + "top_section": true +} diff --git a/typescript/site/app/ecosystem/partners-data/vercel/metadata.json b/typescript/site/app/ecosystem/partners-data/vercel/metadata.json index 61b101aa19..00498edc5d 100644 --- a/typescript/site/app/ecosystem/partners-data/vercel/metadata.json +++ b/typescript/site/app/ecosystem/partners-data/vercel/metadata.json @@ -1,7 +1,7 @@ { "name": "Vercel", "description": "Vercel supports x402 as an open protocol for payments in MCP tools, enabling developers to monetize AI-powered applications and serverless functions.", - "logoUrl": "/logos/vercel.png", + "logoUrl": "/logos/vercel-l.svg", "websiteUrl": "https://vercel.com/blog/introducing-x402-mcp-open-protocol-payments-for-mcp-tools", "category": "Infrastructure & Tooling", "top_section": true diff --git a/typescript/site/app/ecosystem/partners-data/x402-examples/metadata.json b/typescript/site/app/ecosystem/partners-data/x402-examples/metadata.json index 9a3ac0725b..ce196ab858 100644 --- a/typescript/site/app/ecosystem/partners-data/x402-examples/metadata.json +++ b/typescript/site/app/ecosystem/partners-data/x402-examples/metadata.json @@ -3,5 +3,5 @@ "category": "Learning & Community Resources", "logoUrl": "/logos/x402-examples.png", "description": "A collection of x402 examples including Next.js integration, Go Proxy, agent use-cases, authentication flows, and more. Explore practical code samples to accelerate your x402 journey.", - "websiteUrl": "https://github.com/coinbase/x402/tree/main/examples/typescript" + "websiteUrl": "https://github.com/x402-foundation/x402/tree/main/examples/typescript" } \ No newline at end of file diff --git a/typescript/site/app/ecosystem/partners-data/xrpl-x402-facilitator/metadata.json b/typescript/site/app/ecosystem/partners-data/xrpl-x402-facilitator/metadata.json new file mode 100644 index 0000000000..86bf25f416 --- /dev/null +++ b/typescript/site/app/ecosystem/partners-data/xrpl-x402-facilitator/metadata.json @@ -0,0 +1,19 @@ +{ + "name": "T54 XRPL x402 Facilitator", + "description": "First x402 facilitator on XRPL, providing reliable settlement for XRP and RLUSD payments.", + "logoUrl": "/logos/t54-x402-secure.jpg", + "websiteUrl": "https://xrpl-x402.t54.ai/", + "category": "Facilitators", + "facilitator": { + "baseUrl": "https://xrpl-facilitator-mainnet.t54.ai", + "networks": ["xrpl:0"], + "schemes": ["exact"], + "assets": ["XRP", "RLUSD"], + "supports": { + "verify": true, + "settle": true, + "supported": true, + "list": false + } + } +} diff --git a/typescript/site/app/facilitator/index.ts b/typescript/site/app/facilitator/index.ts index 82f039d85d..93e6c93616 100644 --- a/typescript/site/app/facilitator/index.ts +++ b/typescript/site/app/facilitator/index.ts @@ -5,9 +5,11 @@ import { toFacilitatorAptosSigner } from "@x402/aptos"; import { ExactAptosScheme } from "@x402/aptos/exact/facilitator"; import { x402Facilitator } from "@x402/core/facilitator"; import { Network } from "@x402/core/types"; -import { toFacilitatorEvmSigner } from "@x402/evm"; +import { type AuthorizerSigner, toFacilitatorEvmSigner } from "@x402/evm"; +import { BatchSettlementEvmScheme } from "@x402/evm/batch-settlement/facilitator"; import { ExactEvmScheme } from "@x402/evm/exact/facilitator"; import { ExactEvmSchemeV1 } from "@x402/evm/exact/v1/facilitator"; +import { UptoEvmScheme } from "@x402/evm/upto/facilitator"; import { EIP2612_GAS_SPONSORING, createErc20ApprovalGasSponsoringExtension, @@ -17,12 +19,14 @@ import { ExactStellarScheme } from "@x402/stellar/exact/facilitator"; import { toFacilitatorSvmSigner } from "@x402/svm"; import { ExactSvmScheme } from "@x402/svm/exact/facilitator"; import { ExactSvmSchemeV1 } from "@x402/svm/exact/v1/facilitator"; +import { toFacilitatorAvmSigner } from "@x402/avm"; +import { ExactAvmScheme } from "@x402/avm/exact/facilitator"; import { createWalletClient, http, publicActions } from "viem"; import { privateKeyToAccount } from "viem/accounts"; import { baseSepolia } from "viem/chains"; /** - * Initialize and configure the x402 facilitator with EVM, SVM, Aptos, and Stellar support + * Initialize and configure the x402 facilitator with EVM, SVM, AVM, Aptos, and Stellar support * This is called lazily on first use to support Next.js module loading * * @returns A configured x402Facilitator instance @@ -37,6 +41,8 @@ async function createFacilitator(): Promise { throw new Error("❌ FACILITATOR_SVM_PRIVATE_KEY environment variable is required"); } + const avmPrivateKey = process.env.FACILITATOR_AVM_PRIVATE_KEY; + // Initialize the EVM account from private key const evmAccount = privateKeyToAccount(process.env.FACILITATOR_EVM_PRIVATE_KEY as `0x${string}`); @@ -89,6 +95,12 @@ async function createFacilitator(): Promise { getCode: (args: { address: `0x${string}` }) => viemClient.getCode(args), }); + const receiverAuthorizerSigner: AuthorizerSigner = { + address: evmAccount.address, + signTypedData: params => + evmAccount.signTypedData(params as Parameters[0]), + }; + // Initialize the SVM account from private key const svmAccount = await createKeyPairSignerFromBytes( base58.decode(process.env.FACILITATOR_SVM_PRIVATE_KEY as string), @@ -97,13 +109,24 @@ async function createFacilitator(): Promise { // Initialize SVM signer - handles all Solana networks with automatic RPC creation const svmSigner = toFacilitatorSvmSigner(svmAccount); - // Create and configure the facilitator with EVM and SVM + // Create and configure the facilitator with all networks const facilitator = new x402Facilitator() .register("eip155:84532", new ExactEvmScheme(evmSigner)) .registerV1("base-sepolia" as Network, new ExactEvmSchemeV1(evmSigner)) + .register("eip155:84532", new UptoEvmScheme(evmSigner)) + .register("eip155:84532", new BatchSettlementEvmScheme(evmSigner, receiverAuthorizerSigner)) .register("solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1", new ExactSvmScheme(svmSigner)) .registerV1("solana-devnet" as Network, new ExactSvmSchemeV1(svmSigner)); + // Optionally register Algorand if configured + if (avmPrivateKey) { + const avmSigner = toFacilitatorAvmSigner(avmPrivateKey); + facilitator.register( + "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=", + new ExactAvmScheme(avmSigner), + ); + } + // Optionally register Aptos if configured if (process.env.FACILITATOR_APTOS_PRIVATE_KEY) { const formattedAptosKey = PrivateKey.formatPrivateKey( diff --git a/typescript/site/app/globals.css b/typescript/site/app/globals.css index 1bccf82f88..fd0137c538 100644 --- a/typescript/site/app/globals.css +++ b/typescript/site/app/globals.css @@ -70,3 +70,40 @@ body { @utility animate-marquee { animation: marquee var(--duration, 40s) linear infinite reverse; } + +/* Hero section — explicit media queries for xl layout */ +.hero-illustration-col { + display: none; +} + +@media (min-width: 1024px) { + /* At lg, layout is flex-row — align columns to top */ + .hero-flex-row { + align-items: flex-start; + } +} + +@media (min-width: 1280px) { + /* Remove section top padding — illustration fills from nav bottom */ + .hero-section { + padding-top: 0; + } + + /* Restore top padding on left column only */ + .hero-left-col { + padding-top: 2.5rem; /* 40px = pt-10 */ + } + + /* Stretch both columns to illustration height at xl */ + .hero-flex-row { + align-items: stretch; + } + + /* Show illustration column */ + .hero-illustration-col { + display: block; + position: relative; + flex-shrink: 0; + width: 720px; + } +} diff --git a/typescript/site/app/layout.tsx b/typescript/site/app/layout.tsx index f79d07c6b4..fd7a3f7368 100644 --- a/typescript/site/app/layout.tsx +++ b/typescript/site/app/layout.tsx @@ -1,5 +1,6 @@ import type { Metadata, Viewport } from "next"; import { Inter, DM_Mono, Inconsolata, Instrument_Serif } from "next/font/google"; +import Script from "next/script"; import "./globals.css"; const inter = Inter({ @@ -68,6 +69,64 @@ export default function RootLayout({ Skip to main content
{children}
+ ); diff --git a/typescript/site/app/page.tsx b/typescript/site/app/page.tsx index e023a240f6..4e619b504e 100644 --- a/typescript/site/app/page.tsx +++ b/typescript/site/app/page.tsx @@ -1,5 +1,6 @@ import Link from "next/link"; import Image from "next/image"; + import { NavBar } from "./components/NavBar"; import { Footer } from "./components/Footer"; import { @@ -87,7 +88,13 @@ const x402Steps = [ ]; const heroCodeSnippet = { - code: `app.use( + code: `app.use(paymentMiddleware({ + "GET /weather": { + accepts: [...], // As many networks / schemes as you want to support + description: "Weather data", // What your endpoint does + }, +}));`, + copyCode: `app.use( paymentMiddleware( { "GET /weather": { @@ -98,7 +105,8 @@ const heroCodeSnippet = { ) );`, title: "Accept payments with a single line of code", - description: "That's it. Add one line of code to require payment for each incoming request. If a request arrives without payment, the server responds with HTTP 402, prompting the client to pay and retry.", + description: + "That's it. Add one line of code to require payment for each incoming request. If a request arrives without payment, the server responds with HTTP 402, prompting the client to pay and retry.", }; export default function HomePage() { @@ -108,8 +116,10 @@ export default function HomePage() { - {/* Stats & Social Proof */} - + {/* Stats & Social Proof — hidden on xl where stats live inside HeroSection */} +
+ +
{/* What's x402? */} @@ -165,10 +175,7 @@ export default function HomePage() { descriptionSize="small" /> - +
@@ -182,7 +189,10 @@ export default function HomePage() { />
-
+

- Join a global community of thousands of builders contributing to an - open codebase, faster financial system, and freer internet. + Join a global community of thousands of builders contributing to an open codebase, + faster financial system, and freer internet.

({ + url: `https://x402.org/writing/${post.slug}`, + lastModified: new Date(post.sortDate), + changeFrequency: "monthly" as const, + priority: 0.7, + })), + { + url: "https://x402.org/protected", + lastModified: new Date("2026-04-23"), + changeFrequency: "monthly", + priority: 0.5, + }, + ]; +} diff --git a/typescript/site/app/writing/page.tsx b/typescript/site/app/writing/page.tsx new file mode 100644 index 0000000000..a8a27da4ae --- /dev/null +++ b/typescript/site/app/writing/page.tsx @@ -0,0 +1,80 @@ +import Image from "next/image"; +import type { Metadata } from "next"; +import Link from "next/link"; +import { NavBar } from "../components/NavBar"; +import { Footer } from "../components/Footer"; +import { getWritingPostsSorted } from "./posts"; + +const pageTitle = "Writing | x402"; +const pageDescription = "Articles and updates on the x402 internet-native payments protocol."; + +export const metadata: Metadata = { + title: pageTitle, + description: pageDescription, + openGraph: { + title: pageTitle, + description: pageDescription, + url: "/writing", + type: "website", + }, + twitter: { + card: "summary_large_image", + title: pageTitle, + description: pageDescription, + }, +}; + +export default function WritingIndexPage() { + const posts = getWritingPostsSorted(); + + return ( +
+ + +
+
+
+

Writing

+

+ Protocol announcements, deep dives, and ecosystem updates from the x402 team. +

+
+ +
    + {posts.map((post) => ( +
  • + +
    + {post.title} +
    +
    +

    + {post.title} +

    +

    {post.displayDate}

    +

    By: {post.authors}

    +

    {post.excerpt}

    + + Read article + +
    + +
  • + ))} +
+
+
+ +
+
+ ); +} \ No newline at end of file diff --git a/typescript/site/app/writing/posts.tsx b/typescript/site/app/writing/posts.tsx new file mode 100644 index 0000000000..dedf185d9f --- /dev/null +++ b/typescript/site/app/writing/posts.tsx @@ -0,0 +1,44 @@ +export interface WritingPost { + slug: string; + title: string; + displayDate: string; + /** ISO date string for sorting (newest first) */ + sortDate: string; + authors: string; + heroSrc: string; + excerpt: string; +} + +export const writingPosts: WritingPost[] = [ + { + slug: "x402-batch-settlement", + title: "Introducing x402 Batch Settlement: High-velocity Agentic Commerce", + displayDate: "May 11, 2026", + sortDate: "2026-05-11", + authors: "Philippe d'Argent, Carson Roscoe, Conner Swenberg, Josh Nickerson", + heroSrc: "/images/x402-batch-settlement-hero.png", + excerpt: + "Batch settlement enables agents to transact at extremely low latency and fractions of a cent, with cryptographic vouchers and bulk onchain redemption.", + }, + { + slug: "x402-v2-launch", + title: "Introducing x402 V2: Evolving the Standard for Internet-native Payments", + displayDate: "December 11, 2025", + sortDate: "2025-12-11", + authors: "Erik Reppel, Carson Roscoe, Josh Nickerson", + heroSrc: "/images/blog_intro.png", + excerpt: + "x402 V2 expands the protocol beyond single-call, exact payments: wallet-based identity, discovery, dynamic recipients, and a modular SDK.", + }, +]; + +/** + * Returns writing posts sorted newest first by `sortDate`. + * + * @returns Ordered copy of {@link writingPosts} + */ +export function getWritingPostsSorted(): WritingPost[] { + return [...writingPosts].sort((a, b) => + a.sortDate < b.sortDate ? 1 : a.sortDate > b.sortDate ? -1 : 0, + ); +} \ No newline at end of file diff --git a/typescript/site/app/writing/x402-batch-settlement/page.tsx b/typescript/site/app/writing/x402-batch-settlement/page.tsx new file mode 100644 index 0000000000..c1a975454a --- /dev/null +++ b/typescript/site/app/writing/x402-batch-settlement/page.tsx @@ -0,0 +1,227 @@ +import Image from "next/image"; +import type { Metadata } from "next"; +import Link from "next/link"; +import { NavBar } from "../../components/NavBar"; +import { Footer } from "../../components/Footer"; + +const pageTitle = "Introducing x402 Batch Settlement: High-velocity Agentic Commerce"; +const pageDescription = + "The x402 protocol is introducing batch settlement, enabling agents to transact at extremely low latency and fractions of a cent."; + +export const metadata: Metadata = { + title: pageTitle, + description: pageDescription, + openGraph: { + title: pageTitle, + description: pageDescription, + url: "/writing/x402-batch-settlement", + type: "article", + images: [ + { + url: "/images/x402-batch-settlement-hero.png", + width: 2730, + height: 1536, + alt: "x402 batch settlement announcement hero", + }, + ], + }, + twitter: { + card: "summary_large_image", + title: pageTitle, + description: pageDescription, + images: ["/images/x402-batch-settlement-hero.png"], + }, +}; + +export default function X402BatchSettlementPage() { + return ( +
+ + +
+
+
+

+ + Back to Writing + +

+

+ Introducing x402 Batch Settlement: High-velocity Agentic Commerce +

+

May 11, 2026

+

+ By: Philippe d'Argent, Carson Roscoe, Conner Swenberg, Josh Nickerson +

+
+ +
+
+ x402 batch settlement hero illustration +
+
+ +
+
+

+ TL;DR: The x402 protocol is introducing batch settlement, enabling agents to + transact at extremely low latency and fractions of a cent. Agents provide cryptographic vouchers + that enable sellers to settle in bulk, reducing overhead. Batch settlement lets agents perform + thousands of granular interactions while maintaining the economic efficiency of a single + transaction. It brings the speed of HTTP to x402 payments, creating a scalable foundation for the + agentic economy. +

+
+ +
+

The Evolution: Beyond One-to-One Settlement

+

+ x402 was built to make HTTP-native payments a standard: pay for an API using the 402 Payment + Required status code and a structured envelope. It's the ideal architecture for autonomous + agents: no UIs, no silos, just machine-to-machine value transfer. +

+

+ However, as we move toward high-frequency interactions per tool call, per token, or per kilobyte, + the unit economics require a more sophisticated approach. While blockchains charge per transaction, + the internet thrives on per-request agility. To bridge this gap, x402 is introducing batch + settlement. +

+
+ +
+

+ Efficiency by Design: Decoupling Authorization from Settlement +

+

+ Batch settlement separates the intent to pay from the onchain finality: +

+
    +
  • + At request time: The buyer provides a proof of authorization that is + near-instant to verify. +
  • +
  • + At scale: Value moves onchain only when it is economically optimal, amortized + across hundreds or thousands of interactions. +
  • +
+

+ This is a core protocol scheme, not a vendor-specific feature. It brings the efficiency of payment + channels directly into the x402 envelope. +

+
+ +
+

How Batch Settlement Works

+

+ Batch settlement is optimized for high-volume micro-transactions: +

+
    +
  • + Capital commitment: The buyer opens a session by committing funds (for example + an EVM escrow or channel). +
  • +
  • + The hot path: Every HTTP interaction includes a cryptographic voucher, a + cumulative "I owe you" that increments with usage. +
  • +
  • + Cheap verification: The seller verifies these vouchers via simple signature math, + with no chain lookups required during the request, and serves the resource immediately. +
  • +
  • + Amortized redemption: The seller settles onchain in bulk. Many logical payments + are compressed into a single transaction. +
  • +
+

+ The result? You keep the granularity of per-request pricing without the friction of per-request gas + or Facilitator fees. +

+
+ +
+

Dynamic Pricing, Static Overhead

+

+ Real-world APIs aren't always flat-rate. Inference, data processing, and compute vary based on + LLM tokens, data sizes, and milliseconds. Batch settlement handles this natively by building on the + "up to" mental model: +

+
    +
  • The 402 header can advertise a ceiling for each interaction in a batch.
  • +
  • The seller captures only the actual usage against the batch's escrow.
  • +
+

+ Unlike standard "up to" payments, which typically settle individually, batch settlement lets + these "up to" authorizations accumulate silently until it's time to finalize the + batch. +

+
+ +
+

Why This is the "Agent" Tier

+

+ Agents are loops: Plan → Act → Pay → Observe. If every "Act" requires an onchain + settlement, the overhead grows linearly with the agent's complexity. +

+

+ Batch settlement shifts that cost. The dominant expense moves toward the session or the day, rather + than the individual call. This keeps the seller protected with signed commitments while allowing the + agent to spin through loops at the speed of HTTP. +

+
+ +
+

Trust Without Hand-Waving

+

+ Efficiency doesn't mean sacrificing sovereignty. The x402 batch-settlement spec (and its EVM + implementations) defines clear exit ramps. Escrow is explicit, limits are cryptographically signed, + and buyers retain defined refund and withdrawal semantics. It's a trust-minimized architecture + designed for a permissionless web. +

+
+ +
+

Getting Started

+

+ The protocol remains open and neutral. Support for the batch-settlement machinery is currently + available in the TypeScript and Go SDKs, with Python support in development. For more detail, check + out the docs:{" "} + + docs.x402.org/schemes/batch-settlement + + . +

+
+ +
+

The Bottom Line

+

+ x402's mission is to make internet-native commerce "boring": standardized, reliable, + and predictable. While the exact and "up to" schemes cover immediate, discrete transfers, + batch settlement provides the economic rails for the next generation of high-density agentic markets. + It tackles the fundamental trade-off of the machine economy: maximizing the integrity of the promise + while minimizing the cost of the proof. +

+
+
+
+
+ +
+
+ ); +} \ No newline at end of file diff --git a/typescript/site/app/writing/x402-v2-launch/page.tsx b/typescript/site/app/writing/x402-v2-launch/page.tsx index 65d0bbcd35..71aa192ca7 100644 --- a/typescript/site/app/writing/x402-v2-launch/page.tsx +++ b/typescript/site/app/writing/x402-v2-launch/page.tsx @@ -41,6 +41,11 @@ export default function X402V2LaunchPage() {
{/* Header */}
+

+ + Back to Writing + +

Introducing x402 V2: Evolving the Standard for Internet-native Payments

@@ -240,7 +245,7 @@ export default function X402V2LaunchPage() {

You can check out the repo{" "} - + here {" "} or{" "} diff --git a/typescript/site/next.config.ts b/typescript/site/next.config.ts index a4e3b3d305..72422a3946 100644 --- a/typescript/site/next.config.ts +++ b/typescript/site/next.config.ts @@ -24,6 +24,20 @@ const nextConfig: NextConfig = { }, ], }, + { + source: "/", + headers: [ + { + key: "Link", + value: + '; rel="api-catalog", ; rel="service-doc", ; rel="payment-required"', + }, + { + key: "X-X402-Supported", + value: "true", + }, + ], + }, ]; }, async rewrites() { @@ -32,6 +46,10 @@ const nextConfig: NextConfig = { source: "/build", destination: "/build-with-us", }, + { + source: "/.well-known/api-catalog", + destination: "/api/well-known/api-catalog", + }, ]; }, async redirects() { diff --git a/typescript/site/package.json b/typescript/site/package.json index 7fb2786f95..71c6657b8d 100644 --- a/typescript/site/package.json +++ b/typescript/site/package.json @@ -3,7 +3,7 @@ "version": "0.1.0", "private": true, "type": "module", - "packageManager": "pnpm@10.7.0", + "packageManager": "pnpm@11.1.1", "scripts": { "dev": "next dev", "build": "next build", @@ -22,6 +22,7 @@ "@solana/kit": "^6.1.0", "@vercel/functions": "^2.2.8", "@x402/aptos": "workspace:*", + "@x402/avm": "workspace:*", "@x402/core": "workspace:*", "@x402/evm": "workspace:*", "@x402/extensions": "workspace:*", @@ -29,12 +30,13 @@ "@x402/paywall": "workspace:*", "@x402/stellar": "workspace:*", "@x402/svm": "workspace:*", + "@algorandfoundation/algokit-utils": "10.0.0-alpha.46", "lottie-react": "^2.4.1", "motion": "^11.18.0", "next": "^16.0.10", "react": "^19.2.3", "react-dom": "^19.2.3", - "viem": "^2.21.26", + "viem": "^2.48.11", "wagmi": "^2.15.6", "x402-legacy": "npm:x402@0.1.2" }, @@ -55,6 +57,6 @@ "eslint-plugin-prettier": "^5.2.6", "prettier": "3.5.2", "tailwindcss": "^4.0.0", - "typescript": "^5" + "typescript": "^5.7.3" } } diff --git a/typescript/site/proxy.ts b/typescript/site/proxy.ts index 578e0d0546..48cac5e0ce 100644 --- a/typescript/site/proxy.ts +++ b/typescript/site/proxy.ts @@ -2,17 +2,21 @@ import { paymentProxyFromConfig } from "@x402/next"; import { HTTPFacilitatorClient } from "@x402/core/server"; import { ExactEvmScheme } from "@x402/evm/exact/server"; import { ExactSvmScheme } from "@x402/svm/exact/server"; +import { ExactAvmScheme } from "@x402/avm/exact/server"; import { NextRequest, NextResponse } from "next/server"; import { createPaywall } from "@x402/paywall"; import { evmPaywall } from "@x402/paywall/evm"; import { svmPaywall } from "@x402/paywall/svm"; +import { avmPaywall } from "@x402/paywall/avm"; const evmPayeeAddress = process.env.RESOURCE_EVM_ADDRESS as `0x${string}`; const svmPayeeAddress = process.env.RESOURCE_SVM_ADDRESS as string; +const avmPayeeAddress = process.env.RESOURCE_AVM_ADDRESS; const facilitatorUrl = process.env.FACILITATOR_URL as string; const EVM_NETWORK = "eip155:84532" as const; // Base Sepolia const SVM_NETWORK = "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" as const; // Solana Devnet +const AVM_NETWORK = "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=" as const; // Algorand Testnet // List of blocked countries and regions const BLOCKED_COUNTRIES = [ @@ -36,9 +40,11 @@ if (!facilitatorUrl) { const facilitatorClient = new HTTPFacilitatorClient({ url: facilitatorUrl }); // Build the paywall provider -const paywall = createPaywall() - .withNetwork(evmPaywall) - .withNetwork(svmPaywall) +const paywallBuilder = createPaywall().withNetwork(evmPaywall).withNetwork(svmPaywall); +if (avmPayeeAddress) { + paywallBuilder.withNetwork(avmPaywall); +} +const paywall = paywallBuilder .withConfig({ appName: "x402 Demo", appLogo: "/logos/x402-examples.png", @@ -61,6 +67,16 @@ const x402PaymentProxy = paymentProxyFromConfig( price: "$0.01", network: SVM_NETWORK, }, + ...(avmPayeeAddress + ? [ + { + payTo: avmPayeeAddress, + scheme: "exact" as const, + price: "$0.01", + network: AVM_NETWORK, + }, + ] + : []), ], description: "Access to protected content", }, @@ -69,6 +85,7 @@ const x402PaymentProxy = paymentProxyFromConfig( [ { network: EVM_NETWORK, server: new ExactEvmScheme() }, { network: SVM_NETWORK, server: new ExactSvmScheme() }, + ...(avmPayeeAddress ? [{ network: AVM_NETWORK, server: new ExactAvmScheme() }] : []), ], undefined, // paywallConfig paywall, // paywall provider @@ -95,7 +112,75 @@ const geolocationProxy = async (req: NextRequest) => { return null; }; +const homepageMarkdown = `# x402 — Payment Required | Internet-Native Payments Standard + +x402 is the internet's payment standard. An open standard for internet-native payments that empowers agentic payments at scale. Build a more free and fair internet. + +## Accept payments with a single line of code + +\`\`\`javascript +app.use( + paymentMiddleware( + { + "GET /weather": { + accepts: [...], + description: "Weather data", + }, + }, + ) +); +\`\`\` + +Add one line of code to require payment for each incoming request. If a request arrives without payment, the server responds with HTTP 402, prompting the client to pay and retry. + +## Key Features + +- **Zero protocol fees** — x402 is free for the customer and the merchant—just pay nominal payment network fees +- **Zero wait** — Money moves at the speed of the internet +- **Zero friction** — No accounts or personal information needed +- **Zero centralization** — Anyone on the internet can build on or extend x402 +- **Zero restrictions** — x402 is a neutral standard, not tied to any specific network + +## How x402 Works vs Traditional Payments + +### Traditional (5 steps) + +1. Create account with new API provider +2. Add payment method (KYC required) +3. Buy credits or subscription +4. Manage API key +5. Make payment + +### x402 (3 steps) + +1. AI agent sends HTTP request and receives 402: Payment Required +2. AI agent pays instantly with stablecoins +3. API access granted + +## x402 is HTTP-native + +x402 uses the HTTP 402 status code — a status code reserved since the beginning of HTTP for exactly this purpose. No proprietary protocols, no walled gardens — just the web, working as intended. + +## Links + +- [Ecosystem](https://x402.org/ecosystem) — Explore the x402 ecosystem of partners and integrations +- [GitHub](https://github.com/coinbase/x402) — Open source repository +- [Writing](https://x402.org/writing) — Protocol articles and updates +- [Whitepaper](https://x402.org/x402-whitepaper.pdf) — Technical specification +`; + export const proxy = async (req: NextRequest) => { + const pathname = new URL(req.url).pathname; + const accept = req.headers.get("accept") || ""; + + if (pathname === "/" && accept.includes("text/markdown")) { + return new NextResponse(homepageMarkdown, { + headers: { + "Content-Type": "text/markdown; charset=utf-8", + }, + }); + } + const geolocationResponse = await geolocationProxy(req); if (geolocationResponse) { return geolocationResponse; diff --git a/typescript/site/public/.well-known/agent-skills/index.json b/typescript/site/public/.well-known/agent-skills/index.json new file mode 100644 index 0000000000..e15fa574e7 --- /dev/null +++ b/typescript/site/public/.well-known/agent-skills/index.json @@ -0,0 +1,12 @@ +{ + "$schema": "https://schemas.agentskills.io/discovery/0.2.0/schema.json", + "skills": [ + { + "name": "x402-payment", + "type": "skill-md", + "description": "Make HTTP payments using the x402 protocol with stablecoins", + "url": "https://x402.org/.well-known/agent-skills/x402-payment/SKILL.md", + "digest": "sha256:010ead99436b33470888a4df05c2a379b9a942d2ba9c6e4e22ac0dfe05256885" + } + ] +} diff --git a/typescript/site/public/.well-known/agent-skills/x402-payment/SKILL.md b/typescript/site/public/.well-known/agent-skills/x402-payment/SKILL.md new file mode 100644 index 0000000000..ace4e58a60 --- /dev/null +++ b/typescript/site/public/.well-known/agent-skills/x402-payment/SKILL.md @@ -0,0 +1,55 @@ +# x402 Payment Skill + +Make HTTP payments using the x402 protocol with stablecoins. + +## Overview + +x402 is an open standard for internet-native payments. When an API endpoint requires payment, it responds with HTTP 402 Payment Required, including payment details in the response. The client then makes a stablecoin payment and retries the request with proof of payment. + +## How to Use + +1. Send an HTTP request to the target endpoint +2. If you receive a **402 Payment Required** response, parse the payment requirements from the response body +3. The response includes: price, payment network, token address, and recipient +4. Create a stablecoin payment transaction on the specified network +5. Resend the original request with the payment proof in the `X-PAYMENT` header + +## Supported Networks + +- Base: `eip155:8453` +- Ethereum: `eip155:1` +- Arbitrum: `eip155:42161` +- Solana: `solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp` + +## Supported Tokens + +- USDC +- EURC + +## Integration + +```javascript +import { paymentMiddleware } from "@x402/express"; + +app.use( + paymentMiddleware({ + "GET /api/data": { + accepts: [ + { + scheme: "exact", + network: "eip155:84532", + maxAmountRequired: "100000", + resource: "https://api.example.com/data", + }, + ], + description: "Access to data API", + }, + }) +); +``` + +## Resources + +- [GitHub Repository](https://github.com/coinbase/x402) +- [Documentation](https://x402.org/writing/x402-v2-launch) +- [Ecosystem](https://x402.org/ecosystem) diff --git a/typescript/site/public/.well-known/mcp/server-card.json b/typescript/site/public/.well-known/mcp/server-card.json new file mode 100644 index 0000000000..4d7d5b3a82 --- /dev/null +++ b/typescript/site/public/.well-known/mcp/server-card.json @@ -0,0 +1,11 @@ +{ + "serverInfo": { + "name": "x402", + "version": "2.0.0" + }, + "capabilities": { + "tools": false, + "resources": true, + "prompts": false + } +} diff --git a/typescript/site/public/images/x402-batch-settlement-hero.png b/typescript/site/public/images/x402-batch-settlement-hero.png new file mode 100644 index 0000000000..73a839c7cd Binary files /dev/null and b/typescript/site/public/images/x402-batch-settlement-hero.png differ diff --git a/typescript/site/public/logos/exa-ai.svg b/typescript/site/public/logos/exa-ai.svg new file mode 100644 index 0000000000..e800a68d30 --- /dev/null +++ b/typescript/site/public/logos/exa-ai.svg @@ -0,0 +1,18 @@ + + + + + + + + + + \ No newline at end of file diff --git a/typescript/site/public/logos/openpayment.png b/typescript/site/public/logos/openpayment.png new file mode 100644 index 0000000000..f2a8a8868e Binary files /dev/null and b/typescript/site/public/logos/openpayment.png differ diff --git a/typescript/site/public/logos/polygon.png b/typescript/site/public/logos/polygon.png new file mode 100644 index 0000000000..19d38897a0 Binary files /dev/null and b/typescript/site/public/logos/polygon.png differ diff --git a/typescript/site/public/logos/quicknode-mono.svg b/typescript/site/public/logos/quicknode-mono.svg new file mode 100644 index 0000000000..38bcc00aa0 --- /dev/null +++ b/typescript/site/public/logos/quicknode-mono.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/typescript/site/public/logos/ultravioleta-dao.png b/typescript/site/public/logos/ultravioleta-dao.png new file mode 100755 index 0000000000..360a43c9f8 Binary files /dev/null and b/typescript/site/public/logos/ultravioleta-dao.png differ diff --git a/typescript/site/public/logos/venice.svg b/typescript/site/public/logos/venice.svg new file mode 100644 index 0000000000..98f4aacef9 --- /dev/null +++ b/typescript/site/public/logos/venice.svg @@ -0,0 +1,19 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/typescript/site/public/logos/vercel-l.svg b/typescript/site/public/logos/vercel-l.svg new file mode 100644 index 0000000000..36fe7b0695 --- /dev/null +++ b/typescript/site/public/logos/vercel-l.svg @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/typescript/site/public/logos/vercel.svg b/typescript/site/public/logos/vercel.svg new file mode 100644 index 0000000000..032dc16ad4 --- /dev/null +++ b/typescript/site/public/logos/vercel.svg @@ -0,0 +1,14 @@ + + + + + + + + + + \ No newline at end of file diff --git a/typescript/site/public/robots.txt b/typescript/site/public/robots.txt new file mode 100644 index 0000000000..97d333da8c --- /dev/null +++ b/typescript/site/public/robots.txt @@ -0,0 +1,30 @@ +User-agent: * +Allow: / + +User-agent: GPTBot +Allow: / + +User-agent: OAI-SearchBot +Allow: / + +User-agent: Claude-Web +Allow: / + +User-agent: Google-Extended +Allow: / + +User-agent: Anthropic-AI +Allow: / + +User-agent: CCBot +Allow: / + +User-agent: PerplexityBot +Allow: / + +User-agent: Bytespider +Allow: / + +Sitemap: https://x402.org/sitemap.xml + +Content-Signal: ai-train=yes, search=yes, ai-input=yes